Inverter
{INVERTERS}General
- + + +Pinout (Wemos)
{PINOUT} @@ -49,20 +94,20 @@ - - + +Serial Console
- +
- +
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,25 +55,40 @@ 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]; - - // inverter - 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); - if(0ULL != invSerial) { - mSys->addInverter(invName, invSerial, modPwr); - DPRINTLN(F("add inverter: ") + String(invName) + ", SN: " + String(invSerial, HEX)); - } - } 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), name, MAX_NAME_LENGTH); + mEep->read(ADDR_INV_CH_PWR + (i * 2 * 4), modPwr, 4); + if(0ULL != invSerial) { + 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_MAX_RTRY, &mMaxRetransPerPyld); + if(0 == mMaxRetransPerPyld) + mMaxRetransPerPyld = DEF_MAX_RETRANS_PER_PYLD; + // pinout mEep->read(ADDR_PINOUT, &mSys->Radio.pinCs); mEep->read(ADDR_PINOUT+1, &mSys->Radio.pinCe); @@ -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(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); + 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: 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("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 = "Enter the credentials to your prefered WiFi station. After rebooting the device tries to connect with this information.
Enter the credentials to your prefered WiFi station. After rebooting the device tries to connect with this information.
Inverter
{INVERTERS}General
- + + +Pinout (Wemos)
{PINOUT} @@ -49,20 +94,20 @@ - - + +Serial Console
- +