From f148c41a1fb75baa5de06dd527bea725821e387d Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 9 Jun 2022 23:03:38 +0200 Subject: [PATCH] ESP8266 v0.4.16 * request only one inverter per loop (https://github.com/grindylow/ahoy/issues/53#issuecomment-1147042489) * mqtt loop interval calculated by # of inverters and inverter request interval * limit maximum number of retries * added feature request #62 (readable names for channels) * improved setup page, added javascript to hide / show channel fields ** IMORTANT: memory layout change, all configuration will be lost, except WiFI ** --- tools/esp8266/app.cpp | 219 +++++++++++++++++++----------- tools/esp8266/app.h | 4 + tools/esp8266/config.h | 3 + tools/esp8266/defines.h | 22 +-- tools/esp8266/eep.h | 12 +- tools/esp8266/hmInverter.h | 2 + tools/esp8266/html/h/setup_html.h | 2 +- tools/esp8266/html/h/style_css.h | 2 +- tools/esp8266/html/setup.html | 57 +++++++- tools/esp8266/html/style.css | 13 +- tools/esp8266/main.cpp | 7 +- tools/esp8266/main.h | 20 ++- tools/esp8266/mqtt.h | 6 + 13 files changed, 256 insertions(+), 113 deletions(-) diff --git a/tools/esp8266/app.cpp b/tools/esp8266/app.cpp index 917eb7f6..dabcd4d3 100644 --- a/tools/esp8266/app.cpp +++ b/tools/esp8266/app.cpp @@ -19,6 +19,8 @@ app::app() : Main() { mTicker = 0; mRxTicker = 0; + mSendLastIvId = 0; + mShowRebootRequest = false; mSerialValues = true; @@ -53,24 +55,39 @@ void app::setup(uint32_t timeout) { mWeb->on("/livedata", std::bind(&app::showLiveData, this)); if(mSettingsValid) { - uint64_t invSerial; - char invName[MAX_NAME_LENGTH + 1] = {0}; - uint16_t modPwr[4]; + mEep->read(ADDR_INV_INTERVAL, &mSendInterval); + if(mSendInterval < 5) + mSendInterval = 5; + mSendTicker = mSendInterval; // inverter + uint64_t invSerial; + char name[MAX_NAME_LENGTH + 1] = {0}; + uint16_t modPwr[4]; + Inverter<> *iv; for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) { mEep->read(ADDR_INV_ADDR + (i * 8), &invSerial); - mEep->read(ADDR_INV_NAME + (i * MAX_NAME_LENGTH), invName, MAX_NAME_LENGTH); - mEep->read(ADDR_INV_MOD_PWR + (i * 2 * 4), modPwr, 4); + mEep->read(ADDR_INV_NAME + (i * MAX_NAME_LENGTH), name, MAX_NAME_LENGTH); + mEep->read(ADDR_INV_CH_PWR + (i * 2 * 4), modPwr, 4); if(0ULL != invSerial) { - mSys->addInverter(invName, invSerial, modPwr); - DPRINTLN(F("add inverter: ") + String(invName) + ", SN: " + String(invSerial, HEX)); + iv = mSys->addInverter(name, invSerial, modPwr); + if(NULL != iv) { + DPRINTLN(F("add inverter: ") + String(name) + ", SN: " + String(invSerial, HEX)); + + for(uint8_t j = 0; j < 4; j++) { + mEep->read(ADDR_INV_CH_NAME + (i * 4 * MAX_NAME_LENGTH) + j * MAX_NAME_LENGTH, name, MAX_NAME_LENGTH); + snprintf(iv->chName[j], MAX_NAME_LENGTH, "%s", name); + } + } + + + mMqttInterval += mSendInterval; } } - mEep->read(ADDR_INV_INTERVAL, &mSendInterval); - if(mSendInterval < 5) - mSendInterval = 5; - mSendTicker = mSendInterval; + + mEep->read(ADDR_INV_MAX_RTRY, &mMaxRetransPerPyld); + if(0 == mMaxRetransPerPyld) + mMaxRetransPerPyld = DEF_MAX_RETRANS_PER_PYLD; // pinout mEep->read(ADDR_PINOUT, &mSys->Radio.pinCs); @@ -103,7 +120,7 @@ void app::setup(uint32_t timeout) { mEep->read(ADDR_MQTT_USER, mqttUser, MQTT_USER_LEN); mEep->read(ADDR_MQTT_PWD, mqttPwd, MQTT_PWD_LEN); mEep->read(ADDR_MQTT_TOPIC, mqttTopic, MQTT_TOPIC_LEN); - mEep->read(ADDR_MQTT_INTERVAL, &mMqttInterval); + //mEep->read(ADDR_MQTT_INTERVAL, &mMqttInterval); mEep->read(ADDR_MQTT_PORT, &mqttPort); char addr[16] = {0}; @@ -112,18 +129,38 @@ void app::setup(uint32_t timeout) { if(mqttAddr[0] > 0) { mMqttActive = true; if(mMqttInterval < 1) - mMqttInterval = 1; + mMqttInterval = 10; + + snprintf(mqttTopic, MQTT_TOPIC_LEN, "inverter"); } else mMqttInterval = 0xffff; + if(0 == mqttPort) + mqttPort = 1883; + mMqtt.setup(addr, mqttTopic, mqttUser, mqttPwd, mqttPort); mMqttTicker = 0; mSerialTicker = 0; - mMqtt.sendMsg("version", mVersion); + if(mqttAddr[0] > 0) { + char topic[30]; + mMqtt.sendMsg("version", mVersion); + for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) { + iv = mSys->getInverterByPos(i); + if(NULL != iv) { + for(uint8_t i = 0; i < 4; i++) { + if(0 != iv->chName[i][0]) { + snprintf(topic, 30, "%s/ch%d/%s", iv->name, i+1, "name"); + mMqtt.sendMsg(topic, iv->chName[i]); + yield(); + } + } + } + } + } } else { DPRINTLN(F("Settings not valid, erasing ...")); @@ -212,7 +249,7 @@ void app::loop(void) { mMqtt.loop(); if(checkTicker(&mTicker, 1000)) { - if(++mMqttTicker >= mMqttInterval) { + if((++mMqttTicker >= mMqttInterval) && (mMqttInterval != 0xffff)) { mMqttTicker = 0; mMqtt.isConnected(true); char topic[30], val[10]; @@ -258,20 +295,25 @@ void app::loop(void) { if(++mSendTicker >= mSendInterval) { mSendTicker = 0; - if(mSerialDebug) - DPRINTLN(F("Free heap: 0x") + String(ESP.getFreeHeap(), HEX)); - - if(!mSys->BufCtrl.empty()) { + if(0 != mTimestamp) { if(mSerialDebug) - DPRINTLN(F("recbuf not empty! #") + String(mSys->BufCtrl.getFill())); - } - Inverter<> *iv; - for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) { - iv = mSys->getInverterByPos(i); + DPRINTLN(F("Free heap: 0x") + String(ESP.getFreeHeap(), HEX)); + + if(!mSys->BufCtrl.empty()) { + if(mSerialDebug) + DPRINTLN(F("recbuf not empty! #") + String(mSys->BufCtrl.getFill())); + } + + int8_t maxLoop = MAX_NUM_INVERTERS; + Inverter<> *iv = mSys->getInverterByPos(mSendLastIvId); + do { + if(NULL != iv) + mPayload[iv->id].requested = false; + mSendLastIvId = ((MAX_NUM_INVERTERS-1) == mSendLastIvId) ? 0 : mSendLastIvId + 1; + iv = mSys->getInverterByPos(mSendLastIvId); + } while((NULL == iv) && ((maxLoop--) > 0)); + if(NULL != iv) { - // reset payload data - memset(mPayload[iv->id].len, 0, MAX_PAYLOAD_ENTRIES); - mPayload[iv->id].maxPackId = 0; if(!mPayload[iv->id].complete) processPayload(false); @@ -283,7 +325,12 @@ void app::loop(void) { } } - mPayload[iv->id].complete = false; + // reset payload data + memset(mPayload[iv->id].len, 0, MAX_PAYLOAD_ENTRIES); + mPayload[iv->id].retransmits = 0; + mPayload[iv->id].maxPackId = 0; + mPayload[iv->id].complete = false; + mPayload[iv->id].requested = true; mPayload[iv->id].ts = mTimestamp; yield(); @@ -292,8 +339,10 @@ void app::loop(void) { mSys->Radio.sendTimePacket(iv->radioId.u64, mPayload[iv->id].ts); mRxTicker = 0; } - yield(); } + else if(mSerialDebug) + DPRINTLN(F("time not set, can't request inverter!")); + yield(); } } } @@ -340,25 +389,32 @@ void app::processPayload(bool retransmit) { if(NULL != iv) { if(!mPayload[iv->id].complete) { if(!buildPayload(iv->id)) { - if(retransmit) { - if(mPayload[iv->id].maxPackId != 0) { - for(uint8_t i = 0; i < (mPayload[iv->id].maxPackId-1); i ++) { - if(mPayload[iv->id].len[i] == 0) { + if(mPayload[iv->id].requested) { + if(mPayload[iv->id].retransmits < mMaxRetransPerPyld) { + mPayload[iv->id].retransmits++; + if(retransmit) { + if(mPayload[iv->id].maxPackId != 0) { + for(uint8_t i = 0; i < (mPayload[iv->id].maxPackId-1); i ++) { + if(mPayload[iv->id].len[i] == 0) { + if(mSerialDebug) + DPRINTLN(F("Error while retrieving data: Frame ") + String(i+1) + F(" missing: Request Retransmit")); + mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x15, (0x81+i), true); + break; // only retransmit one frame per loop + } + yield(); + } + } + else { if(mSerialDebug) - DPRINTLN(F("Error while retrieving data: Frame ") + String(i+1) + F(" missing: Request Retransmit")); - mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x15, (0x81+i), true); + DPRINTLN(F("Error while retrieving data: last frame missing: Request Retransmit")); + if(0x00 != mLastPacketId) + mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x15, mLastPacketId, true); + else + mSys->Radio.sendTimePacket(iv->radioId.u64, mPayload[iv->id].ts); } + mSys->Radio.switchRxCh(300); } } - else { - if(mSerialDebug) - DPRINTLN(F("Error while retrieving data: last frame missing: Request Retransmit")); - if(0x00 != mLastPacketId) - mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x15, mLastPacketId, true); - else - mSys->Radio.sendTimePacket(iv->radioId.u64, mPayload[iv->id].ts); - } - mSys->Radio.switchRxCh(300); } } else { @@ -423,32 +479,41 @@ void app::showSetup(void) { String inv; uint64_t invSerial; - char invName[MAX_NAME_LENGTH + 1] = {0}; + char name[MAX_NAME_LENGTH + 1] = {0}; uint8_t invType; uint16_t modPwr[4]; for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) { mEep->read(ADDR_INV_ADDR + (i * 8), &invSerial); - mEep->read(ADDR_INV_NAME + (i * MAX_NAME_LENGTH), invName, MAX_NAME_LENGTH); - mEep->read(ADDR_INV_MOD_PWR + (i * 2 * 4), modPwr, 4); + mEep->read(ADDR_INV_NAME + (i * MAX_NAME_LENGTH), name, MAX_NAME_LENGTH); + mEep->read(ADDR_INV_CH_PWR + (i * 2 * 4), modPwr, 4); inv += F("

Inverter ") + String(i) + "

"; inv += F(""); inv += F(""); + inv += F("\"/ maxlength=\"12\" onkeyup=\"checkSerial()\">"); inv += F(""); inv += F(""; - inv += F(""); + inv += F(""); for(uint8_t j = 0; j < 4; j++) { inv += F(""); } + inv += F("
"); + for(uint8_t j = 0; j < 4; j++) { + mEep->read(ADDR_INV_CH_NAME + (i * 4 * MAX_NAME_LENGTH) + j * MAX_NAME_LENGTH, name, MAX_NAME_LENGTH); + inv += F(""; + } } html.replace(F("{INVERTERS}"), String(inv)); @@ -484,13 +549,12 @@ void app::showSetup(void) { if(mSettingsValid) { - mEep->read(ADDR_INV_INTERVAL, &interval); - html.replace(F("{INV_INTVL}"), String(interval)); + html.replace(F("{INV_INTVL}"), String(mSendInterval)); + html.replace(F("{INV_RETRIES}"), String(mMaxRetransPerPyld)); uint8_t tmp; - mEep->read(ADDR_SER_INTERVAL, &interval); mEep->read(ADDR_SER_ENABLE, &tmp); - html.replace(F("{SER_INTVL}"), String(interval)); + html.replace(F("{SER_INTVL}"), String(mSerialInterval)); html.replace(F("{SER_VAL_CB}"), (tmp == 0x01) ? "checked" : ""); mEep->read(ADDR_SER_DEBUG, &tmp); html.replace(F("{SER_DBG_CB}"), (tmp == 0x01) ? "checked" : ""); @@ -498,33 +562,16 @@ void app::showSetup(void) { uint8_t mqttAddr[MQTT_ADDR_LEN] = {0}; uint16_t mqttPort; mEep->read(ADDR_MQTT_ADDR, mqttAddr, MQTT_ADDR_LEN); - mEep->read(ADDR_MQTT_INTERVAL, &interval); mEep->read(ADDR_MQTT_PORT, &mqttPort); char addr[16] = {0}; sprintf(addr, "%d.%d.%d.%d", mqttAddr[0], mqttAddr[1], mqttAddr[2], mqttAddr[3]); html.replace(F("{MQTT_ADDR}"), String(addr)); - html.replace(F("{MQTT_PORT}"), String(mqttPort)); + html.replace(F("{MQTT_PORT}"), String(mMqtt.getPort())); html.replace(F("{MQTT_USER}"), String(mMqtt.getUser())); html.replace(F("{MQTT_PWD}"), String(mMqtt.getPwd())); html.replace(F("{MQTT_TOPIC}"), String(mMqtt.getTopic())); - html.replace(F("{MQTT_INTVL}"), String(interval)); - } - else { - html.replace(F("{INV_INTVL}"), "5"); - - html.replace(F("{SER_VAL_CB}"), "checked"); - html.replace(F("{SER_DBG_CB}"), ""); - html.replace(F("{SER_INTVL}"), "10"); - - html.replace(F("{MQTT_ADDR}"), ""); - html.replace(F("{MQTT_PORT}"), "1883"); - html.replace(F("{MQTT_USER}"), ""); - html.replace(F("{MQTT_PWD}"), ""); - html.replace(F("{MQTT_TOPIC}"), "inverter"); - html.replace(F("{MQTT_INTVL}"), "10"); - - html.replace(F("{SER_INTVL}"), "10"); + html.replace(F("{MQTT_INTVL}"), String(mMqttInterval)); } mWeb->send(200, F("text/html"), html); @@ -584,7 +631,7 @@ void app::showStatistics(void) { content += F("INFO: reboot your ESP to apply all your configuration changes!\n"); if(!mSettingsValid) - content += F("INFO: your settings are invalid, please switch to setup to correct this.\n"); + content += F("INFO: your settings are invalid, please switch to Setup to correct this.\n"); content += F("MQTT: "); if(!mMqtt.isConnected()) @@ -609,7 +656,7 @@ void app::showHoymiles(void) { //----------------------------------------------------------------------------- void app::showLiveData(void) { - DPRINTLN(F("app::showLiveData")); + //DPRINTLN(F("app::showLiveData")); String modHtml; for(uint8_t id = 0; id < mSys->getNumInverters(); id++) { Inverter<> *iv = mSys->getInverterByPos(id); @@ -640,7 +687,12 @@ void app::showLiveData(void) { modHtml += ""; for(uint8_t ch = 1; ch <= modNum; ch ++) { - modHtml += F("
CHANNEL ") + String(ch) + F(""); + modHtml += F("
"); + if(iv->chName[ch-1][0] == 0) + modHtml += F("CHANNEL ") + String(ch); + else + modHtml += String(iv->chName[ch-1]); + modHtml += F(""); for(uint8_t j = 0; j < 6; j++) { switch(j) { default: pos = (iv->getPosByChFld(ch, FLD_UDC)); break; @@ -705,15 +757,20 @@ void app::saveValues(bool webSend = true) { mWeb->arg("inv" + String(i) + "Name").toCharArray(buf, 20); mEep->write(ADDR_INV_NAME + (i * MAX_NAME_LENGTH), buf, MAX_NAME_LENGTH); - // max module power + // max channel power / name for(uint8_t j = 0; j < 4; j++) { uint16_t pwr = mWeb->arg("inv" + String(i) + "ModPwr" + String(j)).toInt(); - mEep->write(ADDR_INV_MOD_PWR + (i * 2 * 4) + (j*2), pwr); + mEep->write(ADDR_INV_CH_PWR + (i * 2 * 4) + (j*2), pwr); + memset(buf, 0, 20); + mWeb->arg("inv" + String(i) + "ModName" + String(j)).toCharArray(buf, 20); + mEep->write(ADDR_INV_CH_NAME + (i * 4 * MAX_NAME_LENGTH) + j * MAX_NAME_LENGTH, buf, MAX_NAME_LENGTH); } } interval = mWeb->arg("invInterval").toInt(); mEep->write(ADDR_INV_INTERVAL, interval); + i = mWeb->arg("invRetry").toInt(); + mEep->write(ADDR_INV_MAX_RTRY, i); // pinout @@ -743,14 +800,14 @@ void app::saveValues(bool webSend = true) { mWeb->arg("mqttUser").toCharArray(mqttUser, MQTT_USER_LEN); mWeb->arg("mqttPwd").toCharArray(mqttPwd, MQTT_PWD_LEN); mWeb->arg("mqttTopic").toCharArray(mqttTopic, MQTT_TOPIC_LEN); - interval = mWeb->arg("mqttIntvl").toInt(); + //interval = mWeb->arg("mqttIntvl").toInt(); mqttPort = mWeb->arg("mqttPort").toInt(); mEep->write(ADDR_MQTT_ADDR, mqttAddr, MQTT_ADDR_LEN); mEep->write(ADDR_MQTT_PORT, mqttPort); mEep->write(ADDR_MQTT_USER, mqttUser, MQTT_USER_LEN); mEep->write(ADDR_MQTT_PWD, mqttPwd, MQTT_PWD_LEN); mEep->write(ADDR_MQTT_TOPIC, mqttTopic, MQTT_TOPIC_LEN); - mEep->write(ADDR_MQTT_INTERVAL, interval); + //mEep->write(ADDR_MQTT_INTERVAL, interval); // serial console @@ -766,6 +823,7 @@ void app::saveValues(bool webSend = true) { mSys->Radio.mSerialDebug = mSerialDebug; updateCrc(); + mEep->commit(); if((mWeb->arg("reboot") == "on")) showReboot(); else { @@ -776,6 +834,7 @@ void app::saveValues(bool webSend = true) { } else { updateCrc(); + mEep->commit(); mWeb->send(200, F("text/html"), F("Error" "

Error while saving

")); } diff --git a/tools/esp8266/app.h b/tools/esp8266/app.h index 30ba1639..3151e404 100644 --- a/tools/esp8266/app.h +++ b/tools/esp8266/app.h @@ -31,6 +31,8 @@ typedef struct { uint8_t len[MAX_PAYLOAD_ENTRIES]; bool complete; uint8_t maxPackId; + uint8_t retransmits; + bool requested; } invPayload_t; @@ -84,11 +86,13 @@ class app : public Main { uint16_t mSendTicker; uint16_t mSendInterval; + uint8_t mSendLastIvId; invPayload_t mPayload[MAX_NUM_INVERTERS]; uint32_t mRxFailed; uint32_t mRxSuccess; uint8_t mLastPacketId; + uint8_t mMaxRetransPerPyld; // timer uint32_t mTicker; diff --git a/tools/esp8266/config.h b/tools/esp8266/config.h index c803bb9c..2c98449c 100644 --- a/tools/esp8266/config.h +++ b/tools/esp8266/config.h @@ -41,6 +41,9 @@ // maximum total payload buffers (must be greater than the number of received frame fragments) #define MAX_PAYLOAD_ENTRIES 4 +// maximum requests for retransmits per payload (per inverter) +#define DEF_MAX_RETRANS_PER_PYLD 5 + // number of seconds since last successful response, before inverter is marked inactive #define INACT_THRES_SEC 300 diff --git a/tools/esp8266/defines.h b/tools/esp8266/defines.h index 90d74e81..7e312e9a 100644 --- a/tools/esp8266/defines.h +++ b/tools/esp8266/defines.h @@ -16,7 +16,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 4 -#define VERSION_PATCH 15 +#define VERSION_PATCH 16 //------------------------------------- @@ -34,10 +34,12 @@ typedef struct { #define DEVNAME_LEN 16 #define CRC_LEN 2 // uint16_t -#define INV_ADDR_LEN MAX_NUM_INVERTERS * 8 // uint64_t -#define INV_NAME_LEN MAX_NUM_INVERTERS * MAX_NAME_LENGTH // char[] -#define INV_CH_MOD_PWR_LEN MAX_NUM_INVERTERS * 2 * 4 // uint16_t (4 channels) -#define INV_INTERVAL_LEN 2 // uint16_t +#define INV_ADDR_LEN MAX_NUM_INVERTERS * 8 // uint64_t +#define INV_NAME_LEN MAX_NUM_INVERTERS * MAX_NAME_LENGTH // char[] +#define INV_CH_CH_PWR_LEN MAX_NUM_INVERTERS * 2 * 4 // uint16_t (4 channels) +#define INV_CH_CH_NAME_LEN MAX_NUM_INVERTERS * MAX_NAME_LENGTH * 4 // (4 channels) +#define INV_INTERVAL_LEN 2 // uint16_t +#define INV_MAX_RTRY_LEN 1 // uint8_t #define PINOUT_LEN 3 // 3 pins: CS, CE, IRQ @@ -68,10 +70,12 @@ typedef struct { #define ADDR_INV_ADDR ADDR_RF24_AMP_PWR + RF24_AMP_PWR_LEN #define ADDR_INV_NAME ADDR_INV_ADDR + INV_ADDR_LEN -#define ADDR_INV_MOD_PWR ADDR_INV_NAME + INV_NAME_LEN -#define ADDR_INV_INTERVAL ADDR_INV_MOD_PWR + INV_CH_MOD_PWR_LEN +#define ADDR_INV_CH_PWR ADDR_INV_NAME + INV_NAME_LEN +#define ADDR_INV_CH_NAME ADDR_INV_CH_PWR + INV_CH_CH_PWR_LEN +#define ADDR_INV_INTERVAL ADDR_INV_CH_NAME + INV_CH_CH_NAME_LEN +#define ADDR_INV_MAX_RTRY ADDR_INV_INTERVAL + INV_INTERVAL_LEN -#define ADDR_MQTT_ADDR ADDR_INV_INTERVAL + INV_INTERVAL_LEN +#define ADDR_MQTT_ADDR ADDR_INV_MAX_RTRY + INV_MAX_RTRY_LEN #define ADDR_MQTT_USER ADDR_MQTT_ADDR + MQTT_ADDR_LEN #define ADDR_MQTT_PWD ADDR_MQTT_USER + MQTT_USER_LEN #define ADDR_MQTT_TOPIC ADDR_MQTT_PWD + MQTT_PWD_LEN @@ -83,7 +87,7 @@ typedef struct { #define ADDR_SER_INTERVAL ADDR_SER_DEBUG + SER_DEBUG_LEN #define ADDR_NEXT ADDR_SER_INTERVAL + SER_INTERVAL_LEN -#define ADDR_SETTINGS_CRC 400 +#define ADDR_SETTINGS_CRC 950 #if(ADDR_SETTINGS_CRC <= ADDR_NEXT) #error address overlap! diff --git a/tools/esp8266/eep.h b/tools/esp8266/eep.h index ca616eb7..21d380d1 100644 --- a/tools/esp8266/eep.h +++ b/tools/esp8266/eep.h @@ -7,7 +7,7 @@ class eep { public: eep() { - EEPROM.begin(500); + EEPROM.begin(1000); } ~eep() { EEPROM.end(); @@ -81,14 +81,12 @@ class eep { for(uint8_t i = 0; i < length; i ++) { EEPROM.write(addr++, str[i]); } - EEPROM.commit(); } void write(uint32_t addr, uint8_t data[], uint16_t length) { for(uint16_t i = 0; i < length; i ++) { EEPROM.write(addr++, data[i]); } - EEPROM.commit(); } void write(uint32_t addr, float value) { @@ -96,24 +94,20 @@ class eep { for(uint8_t i = 0; i < 4; i ++) { EEPROM.write(addr++, p[i]); } - EEPROM.commit(); } void write(uint32_t addr, bool value) { uint8_t intVal = (value) ? 0x01 : 0x00; EEPROM.write(addr++, intVal); - EEPROM.commit(); } void write(uint32_t addr, uint8_t value) { EEPROM.write(addr++, value); - EEPROM.commit(); } void write(uint32_t addr, uint16_t value) { EEPROM.write(addr++, (value >> 8) & 0xff); EEPROM.write(addr++, (value ) & 0xff); - EEPROM.commit(); } @@ -129,7 +123,6 @@ class eep { EEPROM.write(addr++, (value >> 16) & 0xff); EEPROM.write(addr++, (value >> 8) & 0xff); EEPROM.write(addr++, (value ) & 0xff); - EEPROM.commit(); } void write(uint64_t addr, uint64_t value) { @@ -141,6 +134,9 @@ class eep { EEPROM.write(addr++, (value >> 16) & 0xff); EEPROM.write(addr++, (value >> 8) & 0xff); EEPROM.write(addr++, (value ) & 0xff); + } + + void commit(void) { EEPROM.commit(); } }; diff --git a/tools/esp8266/hmInverter.h b/tools/esp8266/hmInverter.h index 349e4e3e..65576dbe 100644 --- a/tools/esp8266/hmInverter.h +++ b/tools/esp8266/hmInverter.h @@ -71,6 +71,7 @@ class Inverter { uint32_t ts; // timestamp of last received payload RECORDTYPE *record; // pointer for values uint16_t chMaxPwr[4]; // maximum power of the modules (Wp) + char chName[4][MAX_NAME_LENGTH]; // human readable name for channel Inverter() { ts = 0; @@ -86,6 +87,7 @@ class Inverter { toRadioId(); record = new RECORDTYPE[listLen]; memset(name, 0, MAX_NAME_LENGTH); + memset(chName, 0, MAX_NAME_LENGTH * 4); memset(record, 0, sizeof(RECORDTYPE) * listLen); } diff --git a/tools/esp8266/html/h/setup_html.h b/tools/esp8266/html/h/setup_html.h index 49f8e9c3..22b557af 100644 --- a/tools/esp8266/html/h/setup_html.h +++ b/tools/esp8266/html/h/setup_html.h @@ -1,4 +1,4 @@ #ifndef __SETUP_HTML_H__ #define __SETUP_HTML_H__ -const char setup_html[] PROGMEM = "Setup - {DEVICE}

Setup

Enter the credentials to your prefered WiFi station. After rebooting the device tries to connect with this information.

WiFi

Device Host Name

ERASE SETTINGS (not WiFi)

Inverter

{INVERTERS}

General

Pinout (Wemos)

{PINOUT}

Radio (NRF24L01+)

MQTT

Serial Console



 

"; +const char setup_html[] PROGMEM = "Setup - {DEVICE}

Setup

Enter the credentials to your prefered WiFi station. After rebooting the device tries to connect with this information.

WiFi

Device Host Name

ERASE SETTINGS (not WiFi)

Inverter

{INVERTERS}

General

Pinout (Wemos)

{PINOUT}

Radio (NRF24L01+)

MQTT

Serial Console



 

"; #endif /*__SETUP_HTML_H__*/ diff --git a/tools/esp8266/html/h/style_css.h b/tools/esp8266/html/h/style_css.h index 5e92f911..848b8607 100644 --- a/tools/esp8266/html/h/style_css.h +++ b/tools/esp8266/html/h/style_css.h @@ -1,4 +1,4 @@ #ifndef __STYLE_CSS_H__ #define __STYLE_CSS_H__ -const char style_css[] PROGMEM = "h1 {margin:0;padding:20pt;font-size:22pt;color:#fff;background-color:#006ec0;display:block;text-transform:uppercase;}html, body {font-family:Arial;margin:0;padding:0;}p {text-align:justify;font-size:13pt;}.des {margin-top:35px;font-size:13pt;color:#006ec0;}.subdes {font-size:12pt;color:#006ec0;margin-left:7px;}a:link, a:visited {text-decoration:none;font-size:13pt;color:#006ec0;}a:hover, a:focus {color:#f00;}a.erase {background-color:#006ec0;color:#fff;padding:7px;display:inline-block;margin-top:30px;float:right;}#content {padding:15px 15px 60px 15px;}#footer {position:fixed;bottom:0px;height:45px;background-color:#006ec0;width:100%;border-top:5px solid #fff;}#footer p, #footer a {color:#fff;padding:0 7px 0 7px;font-size:10pt !important;}div.content {background-color:#fff;padding-bottom:65px;overflow:auto;}input, select {padding:7px;font-size:13pt;}input.text, select {width:70%;box-sizing:border-box;margin-bottom:10px;border:1px solid #ccc;}input.sh {max-width:100px !important;margin-right:10px;}input.btn {background-color:#006ec0;color:#fff;border:0px;float:right;margin:10px 0 30px;text-transform:uppercase;}input.cb {margin-bottom:20px;}label {width:20%;display:inline-block;font-size:12pt;padding-right:10px;margin-left:10px;}.left {float:left;}.right {float:right;}div.ch-iv {width:100%;background-color:#32b004;display:inline-block;margin-bottom:15px;padding-bottom:20px;overflow:auto;}div.ch {width:220px;min-height:350px;background-color:#006ec0;display:inline-block;margin:0 10px 15px 10px;overflow:auto;padding-bottom:20px;}div.ch .value, div.ch .info, div.ch .head, div.ch-iv .value, div.ch-iv .info, div.ch-iv .head {color:#fff;display:block;width:100%;text-align:center;}.subgrp {float:left;width:220px;}div.ch .unit, div.ch-iv .unit {font-size:19px;margin-left:10px;}div.ch .value, div.ch-iv .value {margin-top:20px;font-size:24px;}div.ch .info, div.ch-iv .info {margin-top:3px;font-size:10px;}div.ch .head {background-color:#003c80;padding:10px 0 10px 0;}div.ch-iv .head {background-color:#1c6800;padding:10px 0 10px 0;}div.iv {max-width:960px;margin-bottom:40px;}div.ts {font-size:13px;background-color:#ddd;border-top:7px solid #999;padding:7px;}#note {margin:50px 10px 10px 10px;padding-top:10px;width:100%;border-top:1px solid #bbb;}@media(max-width:500px) {div.ch .unit, div.ch-iv .unit {font-size:18px;}div.ch {width:170px;min-height:100px;}.subgrp {width:180px;}}"; +const char style_css[] PROGMEM = "h1 {margin:0;padding:20pt;font-size:22pt;color:#fff;background-color:#006ec0;display:block;text-transform:uppercase;}html, body {font-family:Arial;margin:0;padding:0;}p {text-align:justify;font-size:13pt;}.des {margin-top:35px;font-size:13pt;color:#006ec0;}.subdes {font-size:12pt;color:#006ec0;margin-left:7px;}.subsubdes {font-size:12pt;color:#006ec0;margin:0 0 7px 12px;}.hide {display:none;}a:link, a:visited {text-decoration:none;font-size:13pt;color:#006ec0;}a:hover, a:focus {color:#f00;}a.erase {background-color:#006ec0;color:#fff;padding:7px;display:inline-block;margin-top:30px;float:right;}#content {padding:15px 15px 60px 15px;}#footer {position:fixed;bottom:0px;height:45px;background-color:#006ec0;width:100%;border-top:5px solid #fff;}#footer p, #footer a {color:#fff;padding:0 7px 0 7px;font-size:10pt !important;}div.content {background-color:#fff;padding-bottom:65px;overflow:auto;}input, select {padding:7px;font-size:13pt;}input.text, select {width:70%;box-sizing:border-box;margin-bottom:10px;border:1px solid #ccc;}input.sh {max-width:150px !important;margin-right:10px;}input.btn {background-color:#006ec0;color:#fff;border:0px;float:right;margin:10px 0 30px;text-transform:uppercase;}input.cb {margin-bottom:20px;}label {width:20%;display:inline-block;font-size:12pt;padding-right:10px;margin-left:15px;}.left {float:left;}.right {float:right;}div.ch-iv {width:100%;background-color:#32b004;display:inline-block;margin-bottom:15px;padding-bottom:20px;overflow:auto;}div.ch {width:220px;min-height:350px;background-color:#006ec0;display:inline-block;margin:0 10px 15px 10px;overflow:auto;padding-bottom:20px;}div.ch .value, div.ch .info, div.ch .head, div.ch-iv .value, div.ch-iv .info, div.ch-iv .head {color:#fff;display:block;width:100%;text-align:center;}.subgrp {float:left;width:220px;}div.ch .unit, div.ch-iv .unit {font-size:19px;margin-left:10px;}div.ch .value, div.ch-iv .value {margin-top:20px;font-size:24px;}div.ch .info, div.ch-iv .info {margin-top:3px;font-size:10px;}div.ch .head {background-color:#003c80;padding:10px 0 10px 0;}div.ch-iv .head {background-color:#1c6800;padding:10px 0 10px 0;}div.iv {max-width:960px;margin-bottom:40px;}div.ts {font-size:13px;background-color:#ddd;border-top:7px solid #999;padding:7px;}#note {margin:50px 10px 10px 10px;padding-top:10px;width:100%;border-top:1px solid #bbb;}@media(max-width:500px) {div.ch .unit, div.ch-iv .unit {font-size:18px;}div.ch {width:170px;min-height:100px;}.subgrp {width:180px;}}"; #endif /*__STYLE_CSS_H__*/ diff --git a/tools/esp8266/html/setup.html b/tools/esp8266/html/setup.html index 0d61eb6f..8988ed3e 100644 --- a/tools/esp8266/html/setup.html +++ b/tools/esp8266/html/setup.html @@ -4,8 +4,51 @@ Setup - {DEVICE} + - +

Setup

@@ -28,8 +71,10 @@

Inverter

{INVERTERS}

General

- + + +

Pinout (Wemos)

{PINOUT} @@ -49,20 +94,20 @@ - - + +

Serial Console



- +

 

- +
diff --git a/tools/esp8266/html/style.css b/tools/esp8266/html/style.css index f1a60820..f6a01e35 100644 --- a/tools/esp8266/html/style.css +++ b/tools/esp8266/html/style.css @@ -31,6 +31,15 @@ p { margin-left: 7px; } +.subsubdes { + font-size:12pt; + color:#006ec0; + margin: 0 0 7px 12px; +} + +.hide { + display: none; +} a:link, a:visited { text-decoration: none; @@ -89,7 +98,7 @@ input.text, select { } input.sh { - max-width: 100px !important; + max-width: 150px !important; margin-right: 10px; } @@ -111,7 +120,7 @@ label { display: inline-block; font-size: 12pt; padding-right: 10px; - margin-left: 10px; + margin-left: 15px; } .left { diff --git a/tools/esp8266/main.cpp b/tools/esp8266/main.cpp index 6ccb10d5..041932fa 100644 --- a/tools/esp8266/main.cpp +++ b/tools/esp8266/main.cpp @@ -267,6 +267,7 @@ void Main::saveValues(bool webSend = true) { memset(mDeviceName, 0, DEVNAME_LEN); mWeb->arg("device").toCharArray(mDeviceName, DEVNAME_LEN); mEep->write(ADDR_DEVNAME, mDeviceName, DEVNAME_LEN); + mEep->commit(); updateCrc(); @@ -288,6 +289,7 @@ void Main::updateCrc(void) { crc = buildEEpCrc(ADDR_START, ADDR_WIFI_CRC); //Serial.println("new CRC: " + String(crc, HEX)); mEep->write(ADDR_WIFI_CRC, crc); + mEep->commit(); } @@ -435,7 +437,10 @@ void Main::sendNTPpacket(IPAddress& address) { String Main::getDateTimeStr(time_t t) { //DPRINTLN(F("Main::getDateTimeStr")); char str[20] = {0}; - sprintf(str, "%04d-%02d-%02d %02d:%02d:%02d", year(t), month(t), day(t), hour(t), minute(t), second(t)); + if(0 == t) + sprintf(str, "n/a"); + else + sprintf(str, "%04d-%02d-%02d %02d:%02d:%02d", year(t), month(t), day(t), hour(t), minute(t), second(t)); return String(str); } diff --git a/tools/esp8266/main.h b/tools/esp8266/main.h index 55f0bd14..6a066bed 100644 --- a/tools/esp8266/main.h +++ b/tools/esp8266/main.h @@ -42,13 +42,22 @@ class Main { inline uint16_t buildEEpCrc(uint32_t start, uint32_t length) { DPRINTLN(F("main.h:buildEEpCrc")); - uint8_t buf[length]; - mEep->read(start, buf, length); - return crc16(buf, length); + uint8_t buf[32]; + uint16_t crc = 0xffff; + uint8_t len; + + while(length > 0) { + len = (length < 32) ? length : 32; + mEep->read(start, buf, len); + crc = crc16(buf, len, crc); + start += len; + length -= len; + } + return crc; } bool checkEEpCrc(uint32_t start, uint32_t length, uint32_t crcPos) { - DPRINTLN(F("main.h:checkEEpCrc")); + //DPRINTLN(F("main.h:checkEEpCrc")); uint16_t crcRd, crcCheck; crcCheck = buildEEpCrc(start, length); mEep->read(crcPos, &crcRd); @@ -57,7 +66,7 @@ class Main { } void eraseSettings(bool all = false) { - DPRINTLN(F("main.h:eraseSettings")); + //DPRINTLN(F("main.h:eraseSettings")); uint8_t buf[64] = {0}; uint16_t addr = (all) ? ADDR_START : ADDR_START_SETTINGS; uint16_t end; @@ -69,6 +78,7 @@ class Main { mEep->write(addr, buf, (end-addr)); addr = end; } while(addr < (ADDR_SETTINGS_CRC + 2)); + mEep->commit(); } inline bool checkTicker(uint32_t *ticker, uint32_t interval) { diff --git a/tools/esp8266/mqtt.h b/tools/esp8266/mqtt.h index a1b3c6ef..df10bdf2 100644 --- a/tools/esp8266/mqtt.h +++ b/tools/esp8266/mqtt.h @@ -25,6 +25,7 @@ class mqtt { mAddressSet = true; mClient->setServer(broker, port); + mPort = port; snprintf(mUser, MQTT_USER_LEN, "%s", user); snprintf(mPwd, MQTT_PWD_LEN, "%s", pwd); snprintf(mTopic, MQTT_TOPIC_LEN, "%s", topic); @@ -65,6 +66,10 @@ class mqtt { return mTopic; } + uint16_t getPort(void) { + return mPort; + } + void loop() { //DPRINT(F("m")); //if(!mClient->connected()) @@ -88,6 +93,7 @@ class mqtt { PubSubClient *mClient; bool mAddressSet; + uint16_t mPort; char mUser[MQTT_USER_LEN]; char mPwd[MQTT_PWD_LEN]; char mTopic[MQTT_TOPIC_LEN];