From 9ffa0d3972dc6386e7f78f6ba49647aee129cda6 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Fri, 10 Mar 2023 13:22:15 +0100 Subject: [PATCH 01/52] Add more inverters to user manual --- User_Manual.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/User_Manual.md b/User_Manual.md index 0a0caaed..242f5152 100644 --- a/User_Manual.md +++ b/User_Manual.md @@ -310,6 +310,8 @@ To get the information open the URL `/api/record/info` on your AhoyDTU. The info | tomquist | TSOL-M1600 | | 1.0.12 | 2020 | 06-24 | 100 | | | | rejoe2 | MI-600 | | 236 | 2018 | 11-27 | 17 | | | | rejoe2 | MI-1500 | | 1.0.12 | 2020 | 06-24 | 100 | | | +| dragricola | HM-1200 | | 1.0.16 | 2021 | 10-12 | 100 | | | +| dragricola | MI-300 | | 230 | 2017 | 08-08 | 1 | | | | | | | | | | | | | ## Developer Information about Command Queue From 0cc6e0938330f3c2d25e135c4f66bad766e481be Mon Sep 17 00:00:00 2001 From: lumapu Date: Fri, 10 Mar 2023 18:00:26 +0100 Subject: [PATCH 02/52] fix SH1106 rotation and turn off during night #756 --- src/CHANGES.md | 3 +++ src/plugins/Display/Display.h | 2 +- src/plugins/Display/Display_Mono.cpp | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 26b2c09d..dd8607ca 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -2,6 +2,9 @@ (starting from release version `0.5.66`) +## 0.5.98 +* fix SH1106 rotation and turn off during night #756 + ## 0.5.97 * Attention: re-ordered display types, check your settings! #746 * improved saving settings of display #747, #746 diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index 5b572219..1081c4fa 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -42,7 +42,7 @@ class Display { } void tickerSecond() { - loop(); + mMono.loop(); if (mNewPayload || ((++mLoopCnt % 10) == 0)) { mNewPayload = false; mLoopCnt = 0; diff --git a/src/plugins/Display/Display_Mono.cpp b/src/plugins/Display/Display_Mono.cpp index ad27ebcc..5af864f6 100644 --- a/src/plugins/Display/Display_Mono.cpp +++ b/src/plugins/Display/Display_Mono.cpp @@ -27,9 +27,9 @@ DisplayMono::DisplayMono() { -void DisplayMono::init(uint8_t type, uint8_t rot, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t *utcTs, const char* version) { +void DisplayMono::init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t *utcTs, const char* version) { if ((0 < type) && (type < 4)) { - u8g2_cb_t *rot = (u8g2_cb_t *)((rot != 0x00) ? U8G2_R2 : U8G2_R0); + u8g2_cb_t *rot = (u8g2_cb_t *)((rotation != 0x00) ? U8G2_R2 : U8G2_R0); mType = type; switch(type) { case 1: From 3e919b4d10b800f1c1c976f18adfd1952f708f90 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 11 Mar 2023 00:12:57 +0100 Subject: [PATCH 03/52] removed MQTT subscription `sync_ntp`, `set_time` with a value of `0` does the same #696 simplified MQTT subscription for `limit`. Check User-Manual.md for new syntax #696, #713 repaired inverter wise limit control, #713 --- User_Manual.md | 57 +++++++++---------------------- src/CHANGES.md | 3 ++ src/LICENSE | 7 ---- src/app.cpp | 2 +- src/app.h | 2 +- src/appInterface.h | 2 +- src/defines.h | 4 +-- src/main.cpp | 4 +-- src/publisher/pubMqtt.h | 38 ++++++++++++++------- src/publisher/pubMqttDefs.h | 16 ++------- src/web/html/includes/footer.html | 2 +- 11 files changed, 56 insertions(+), 81 deletions(-) delete mode 100644 src/LICENSE diff --git a/User_Manual.md b/User_Manual.md index 0a0caaed..15247155 100644 --- a/User_Manual.md +++ b/User_Manual.md @@ -91,9 +91,6 @@ The AhoyDTU will publish on the following topics ## Active Power Limit via Serial / Control Page URL: `/serial` -If you leave the field "Active Power Limit" empty during the setup and reboot the ahoy-dtu will set a value of 65535 in the setup. -That is the value you have to fill in case you want to operate the inverter without a active power limit. -If the value is 65535 or -1 after another reboot the value will be set automatically to "100" and in the drop-down menu "relative in percent persistent" will be set. Of course you can do this also by your self. You can change the setting in the following manner. Decide if you want to set @@ -115,24 +112,17 @@ Also an absolute active power limit below approx. 30 Watt seems to be not meanfu ### Generic Information -The AhoyDTU subscribes on three topics `/ctrl/#`, `/setup` and `/status`. +The AhoyDTU subscribes on following topics: + +- `/ctrl/limit/` +- `/ctrl/restart/` +- `/setup/set_time` 👆 `` can be set on setup page, default is `inverter`. 👆 `` is the number of the specific inverter in the setup page. -### Inverter Power (On / Off) -```mqtt -/ctrl/power/ -``` -with payload `1` = `ON` and `0` = `OFF` - -Example: -```mqtt -inverter/ctrl/power/0 1 -``` - ### Inverter restart ```mqtt /ctrl/restart/ @@ -142,50 +132,35 @@ Example: inverter/ctrl/restart/0 ``` -### Power Limit relative persistent [%] +### Power Limit relative (non persistent) [%] ```mqtt -/ctrl/limit_persistent_relative/ +/ctrl/limit/ ``` with a payload `[2 .. 100]` +**NOTE: optional a `%` can be sent as last character** + Example: ```mqtt -inverter/ctrl/limit_persistent_relative/0 70 +inverter/ctrl/limit/0 70 ``` -### Power Limit absolute persistent [Watts] +### Power Limit absolute (non persistent) [Watts] ```mqtt -/ctrl/limit_persistent_absolute/ +/ctrl/limit/ ``` with a payload `[0 .. 65535]` -Example: -```mqtt -inverter/ctrl/limit_persistent_absolute/0 600 -``` - -### Power Limit relative non persistent [%] -```mqtt -/ctrl/limit_nonpersistent_relative/ -``` -with a payload `[2 .. 100]` +**NOTE: the unit `W` is necessary to determine an absolute limit** Example: ```mqtt -inverter/ctrl/limit_nonpersistent_relative/0 70 -``` - -### Power Limit absolute non persistent [Watts] -```mqtt -/ctrl/limit_nonpersistent_absolute/ +inverter/ctrl/limit_nonpersistent_absolute/0 600W ``` -with a payload `[0 .. 65535]` -Example: -```mqtt -inverter/ctrl/limit_nonpersistent_absolute/0 600 -``` +### Power Limit persistent +This feature was removed. The persisten limit should not be modified cyclic by a script because of potential wearout of the flash inside the inverter. ## Control via REST API diff --git a/src/CHANGES.md b/src/CHANGES.md index dd8607ca..45179967 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -4,6 +4,9 @@ ## 0.5.98 * fix SH1106 rotation and turn off during night #756 +* removed MQTT subscription `sync_ntp`, `set_time` with a value of `0` does the same #696 +* simplified MQTT subscription for `limit`. Check [User-Manual.md](../User-Manual.md) for new syntax #696, #713 +* repaired inverter wise limit control ## 0.5.97 * Attention: re-ordered display types, check your settings! #746 diff --git a/src/LICENSE b/src/LICENSE deleted file mode 100644 index 057d1565..00000000 --- a/src/LICENSE +++ /dev/null @@ -1,7 +0,0 @@ -License - -CC-CY-NC-SA 3.0 - -https://creativecommons.org/licenses/by-nc-sa/3.0/de - -This project is for non-commercial use only! diff --git a/src/app.cpp b/src/app.cpp index d65dbe1d..a65d1f09 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- // 2023 Ahoy, https://ahoydtu.de -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- #include "app.h" diff --git a/src/app.h b/src/app.h index b68dc0c4..41a77c07 100644 --- a/src/app.h +++ b/src/app.h @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- // 2023 Ahoy, https://ahoydtu.de -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- #ifndef __APP_H__ diff --git a/src/appInterface.h b/src/appInterface.h index 83a4f769..f9a13b03 100644 --- a/src/appInterface.h +++ b/src/appInterface.h @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- // 2022 Ahoy, https://ahoydtu.de -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- #ifndef __IAPP_H__ diff --git a/src/defines.h b/src/defines.h index 13e525bc..6888f8a9 100644 --- a/src/defines.h +++ b/src/defines.h @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- // 2023 Ahoy, https://www.mikrocontroller.net/topic/525778 -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- #ifndef __DEFINES_H__ @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 5 -#define VERSION_PATCH 97 +#define VERSION_PATCH 98 //------------------------------------- typedef struct { diff --git a/src/main.cpp b/src/main.cpp index c585d0f2..af10abce 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- -// 2022 Ahoy, https://www.mikrocontroller.net/topic/525778 -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +// 2023 Ahoy, https://ahoydtu.de +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- #include "utils/dbg.h" diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 4ec4c3f5..d9063c77 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- // 2023 Ahoy, https://ahoydtu.de -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- // https://bert.emelis.net/espMqttClient/ @@ -312,13 +312,14 @@ class PubMqtt { tickerMinute(); publish(mLwtTopic, mqttStr[MQTT_STR_LWT_CONN], true, false); - subscribe(subscr[MQTT_SUBS_LMT_PERI_REL]); - subscribe(subscr[MQTT_SUBS_LMT_PERI_ABS]); - subscribe(subscr[MQTT_SUBS_LMT_NONPERI_REL]); - subscribe(subscr[MQTT_SUBS_LMT_NONPERI_ABS]); + char sub[20]; + for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { + snprintf(sub, 20, "ctrl/limit/%d", i); + subscribe(sub); + snprintf(sub, 20, "ctrl/restart/%d", i); + subscribe(sub); + } subscribe(subscr[MQTT_SUBS_SET_TIME]); - subscribe(subscr[MQTT_SUBS_SYNC_NTP]); - //subscribe("status/#"); } void onDisconnect(espMqttClientTypes::DisconnectReason reason) { @@ -358,11 +359,15 @@ class PubMqtt { DynamicJsonDocument json(128); JsonObject root = json.to(); + bool limitAbs = false; if(len > 0) { char *pyld = new char[len + 1]; strncpy(pyld, (const char*)payload, len); pyld[len] = '\0'; - root["val"] = atoi(pyld); + root[F("val")] = atoi(pyld); + DPRINTLN(DBG_INFO, String(pyld) + " " + String(len)); + if(pyld[len-1] == 'W') + limitAbs = true; delete[] pyld; } @@ -377,8 +382,17 @@ class PubMqtt { tmp[pos] = '\0'; switch(elm++) { case 1: root[F("path")] = String(tmp); break; - case 2: root[F("cmd")] = String(tmp); break; - case 3: root[F("id")] = atoi(tmp); break; + case 2: + if(strncmp("limit", tmp, 5) == 0) { + if(limitAbs) + root[F("cmd")] = F("limit_nonpersistent_absolute"); + else + root[F("cmd")] = F("limit_nonpersistent_relative"); + } + else + root[F("cmd")] = String(tmp); + break; + case 3: root[F("id")] = atoi(tmp); break; default: break; } if('\0' == p[pos]) @@ -389,9 +403,9 @@ class PubMqtt { pos++; } - /*char out[128]; + char out[128]; serializeJson(root, out, 128); - DPRINTLN(DBG_INFO, "json: " + String(out));*/ + DPRINTLN(DBG_INFO, "json: " + String(out)); (mSubscriptionCb)(root); mRxCnt++; diff --git a/src/publisher/pubMqttDefs.h b/src/publisher/pubMqttDefs.h index 64309b18..9633e2d4 100644 --- a/src/publisher/pubMqttDefs.h +++ b/src/publisher/pubMqttDefs.h @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- // 2023 Ahoy, https://ahoydtu.de -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- #ifndef __PUB_MQTT_DEFS_H__ @@ -84,21 +84,11 @@ const char* const subtopics[] PROGMEM = { }; enum { - MQTT_SUBS_LMT_PERI_REL, - MQTT_SUBS_LMT_PERI_ABS, - MQTT_SUBS_LMT_NONPERI_REL, - MQTT_SUBS_LMT_NONPERI_ABS, - MQTT_SUBS_SET_TIME, - MQTT_SUBS_SYNC_NTP + MQTT_SUBS_SET_TIME }; const char* const subscr[] PROGMEM = { - "ctrl/limit_persistent_relative", - "ctrl/limit_persistent_absolute", - "ctrl/limit_nonpersistent_relative", - "ctrl/limit_nonpersistent_absolute", - "setup/set_time", - "setup/sync_ntp" + "setup/set_time" }; #endif /*__PUB_MQTT_DEFS_H__*/ diff --git a/src/web/html/includes/footer.html b/src/web/html/includes/footer.html index 5a2b705b..bbc4c6ce 100644 --- a/src/web/html/includes/footer.html +++ b/src/web/html/includes/footer.html @@ -10,7 +10,7 @@ From 499e1e44f52a094e8facc4dafbf262745d3b0b53 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 11 Mar 2023 00:54:10 +0100 Subject: [PATCH 04/52] 0.5.98 removed debug outputs --- src/publisher/pubMqtt.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index d9063c77..2b2b298e 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -365,7 +365,6 @@ class PubMqtt { strncpy(pyld, (const char*)payload, len); pyld[len] = '\0'; root[F("val")] = atoi(pyld); - DPRINTLN(DBG_INFO, String(pyld) + " " + String(len)); if(pyld[len-1] == 'W') limitAbs = true; delete[] pyld; @@ -403,9 +402,9 @@ class PubMqtt { pos++; } - char out[128]; + /*char out[128]; serializeJson(root, out, 128); - DPRINTLN(DBG_INFO, "json: " + String(out)); + DPRINTLN(DBG_INFO, "json: " + String(out));*/ (mSubscriptionCb)(root); mRxCnt++; From 2d9f53c941fb627fd05059f3bfaf223f0597758c Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 11 Mar 2023 02:10:18 +0100 Subject: [PATCH 05/52] fix upload settings #686 --- src/CHANGES.md | 1 + src/app.h | 6 +-- src/appInterface.h | 2 +- src/config/settings.h | 14 +++++-- src/web/html/setup.html | 37 +++++++++++------- src/web/web.h | 83 +++++------------------------------------ 6 files changed, 49 insertions(+), 94 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 45179967..c28d4c6b 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -7,6 +7,7 @@ * removed MQTT subscription `sync_ntp`, `set_time` with a value of `0` does the same #696 * simplified MQTT subscription for `limit`. Check [User-Manual.md](../User-Manual.md) for new syntax #696, #713 * repaired inverter wise limit control +* fix upload settings #686 ## 0.5.97 * Attention: re-ordered display types, check your settings! #746 diff --git a/src/app.h b/src/app.h index 41a77c07..64510eef 100644 --- a/src/app.h +++ b/src/app.h @@ -68,9 +68,9 @@ class app : public IApp, public ah::Scheduler { return Scheduler::getTimestamp(); } - bool saveSettings() { - mShowRebootRequest = true; - return mSettings.saveSettings(); + bool saveSettings(bool stopFs = false) { + mShowRebootRequest = true; // only message on index, no reboot + return mSettings.saveSettings(stopFs); } bool readSettings(const char *path) { diff --git a/src/appInterface.h b/src/appInterface.h index f9a13b03..4c7d6042 100644 --- a/src/appInterface.h +++ b/src/appInterface.h @@ -14,7 +14,7 @@ class IApp { public: virtual ~IApp() {} - virtual bool saveSettings() = 0; + virtual bool saveSettings(bool stopFs) = 0; virtual bool readSettings(const char *path) = 0; virtual bool eraseSettings(bool eraseWifi) = 0; virtual void setOnUpdate() = 0; diff --git a/src/config/settings.h b/src/config/settings.h index 9dcca1c4..fab8327e 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- // 2023 Ahoy, https://ahoydtu.de -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- #ifndef __SETTINGS_H__ @@ -247,7 +247,7 @@ class settings { return mCfg.valid; } - bool saveSettings(void) { + bool saveSettings(bool stopFs = false) { DPRINTLN(DBG_DEBUG, F("save settings")); File fp = LittleFS.open("/settings.json", "w"); if(!fp) { @@ -273,6 +273,9 @@ class settings { } fp.close(); + if(stopFs) + stop(); + return true; } @@ -280,7 +283,7 @@ class settings { if(true == eraseWifi) return LittleFS.format(); loadDefaults(!eraseWifi); - return saveSettings(); + return saveSettings(true); } private: @@ -403,6 +406,11 @@ class settings { mCfg.nrf.pinCe = obj[F("ce")]; mCfg.nrf.pinIrq = obj[F("irq")]; mCfg.nrf.amplifierPower = obj[F("pwr")]; + if((obj[F("cs")] == obj[F("ce")])) { + mCfg.nrf.pinCs = DEF_CS_PIN; + mCfg.nrf.pinCe = DEF_CE_PIN; + mCfg.nrf.pinIrq = DEF_IRQ_PIN; + } } } diff --git a/src/web/html/setup.html b/src/web/html/setup.html index e3188f05..588fd51b 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -279,25 +279,34 @@
Reboot device after successful save
-
+
- -
-
- ERASE SETTINGS (not WiFi) -
- Upload / Store JSON Settings -
- - -
-
- Download settings (JSON file) (only saved values, passwords will be removed!) -
+
+
+ ERASE SETTINGS (not WiFi) +
+ Import / Export JSON Settings +
+
Import
+
+
+ + +
+
+
+
+
Export
+
+ Download settings (JSON file) (only values, passwords will be removed!) +
+
+
+
{#HTML_FOOTER} diff --git a/src/web/web.h b/src/web/web.h index fe4a53e6..1b8833bf 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- // 2022 Ahoy, https://www.mikrocontroller.net/topic/525778 -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed //----------------------------------------------------------------------------- #ifndef __WEB_H__ @@ -170,11 +170,15 @@ class Web { if (!fp) mUploadFail = true; else { + char pwd[PWD_LEN]; + strncpy(pwd, mConfig->sys.stationPwd, PWD_LEN); // backup WiFi PWD if (!mApp->readSettings("tmp.json")) { mUploadFail = true; DPRINTLN(DBG_ERROR, F("upload JSON error!")); - } else - mApp->saveSettings(); + } else { + strncpy(mConfig->sys.stationPwd, pwd, PWD_LEN); // restore WiFi PWD + mApp->saveSettings(true); + } } DPRINTLN(DBG_INFO, F("upload finished!")); } @@ -414,10 +418,8 @@ class Web { refresh = 120; } request->send(200, F("text/html; charset=UTF-8"), F("Factory Reset") + content + F("")); - if (refresh == 10) { - delay(1000); - ESP.restart(); - } + if (refresh == 10) + onReboot(request); } void onSetup(AsyncWebServerRequest *request) { @@ -590,7 +592,7 @@ class Web { mConfig->plugin.display.disp_dc = (mConfig->plugin.display.type < 3) ? DEF_PIN_OFF : request->arg("disp_dc").toInt(); mConfig->plugin.display.disp_busy = (mConfig->plugin.display.type < 10) ? DEF_PIN_OFF : request->arg("disp_bsy").toInt(); - mApp->saveSettings(); + mApp->saveSettings((request->arg("reboot") == "on")); if (request->arg("reboot") == "on") onReboot(request); @@ -618,71 +620,6 @@ class Web { request->send(response); } - /*void showWebApi(AsyncWebServerRequest *request) { - // TODO: remove - DPRINTLN(DBG_VERBOSE, F("web::showWebApi")); - DPRINTLN(DBG_DEBUG, request->arg("plain")); - const size_t capacity = 200; // Use arduinojson.org/assistant to compute the capacity. - DynamicJsonDocument response(capacity); - - // Parse JSON object - deserializeJson(response, request->arg("plain")); - // ToDo: error handling for payload - uint8_t iv_id = response["inverter"]; - uint8_t cmd = response["cmd"]; - Inverter<> *iv = mSys->getInverterByPos(iv_id); - if (NULL != iv) { - if (response["tx_request"] == (uint8_t)TX_REQ_INFO) { - // if the AlarmData is requested set the Alarm Index to the requested one - if (cmd == AlarmData || cmd == AlarmUpdate) { - // set the AlarmMesIndex for the request from user input - iv->alarmMesIndex = response["payload"]; - } - DPRINTLN(DBG_INFO, F("Will make tx-request 0x15 with subcmd ") + String(cmd) + F(" and payload ") + String((uint16_t) response["payload"])); - // process payload from web request corresponding to the cmd - iv->enqueCommand(cmd); - } - - - if (response["tx_request"] == (uint8_t)TX_REQ_DEVCONTROL) { - if (response["cmd"] == (uint8_t)ActivePowerContr) { - uint16_t webapiPayload = response["payload"]; - uint16_t webapiPayload2 = response["payload2"]; - if (webapiPayload > 0 && webapiPayload < 10000) { - iv->devControlCmd = ActivePowerContr; - iv->powerLimit[0] = webapiPayload; - if (webapiPayload2 > 0) - iv->powerLimit[1] = webapiPayload2; // dev option, no sanity check - else // if not set, set it to 0x0000 default - iv->powerLimit[1] = AbsolutNonPersistent; // payload will be seted temporary in Watt absolut - if (iv->powerLimit[1] & 0x0001) - DPRINTLN(DBG_INFO, F("Power limit for inverter ") + String(iv->id) + F(" set to ") + String(iv->powerLimit[0]) + F("% via REST API")); - else - DPRINTLN(DBG_INFO, F("Power limit for inverter ") + String(iv->id) + F(" set to ") + String(iv->powerLimit[0]) + F("W via REST API")); - iv->devControlRequest = true; // queue it in the request loop - } - } - if (response["cmd"] == (uint8_t)TurnOff) { - iv->devControlCmd = TurnOff; - iv->devControlRequest = true; // queue it in the request loop - } - if (response["cmd"] == (uint8_t)TurnOn) { - iv->devControlCmd = TurnOn; - iv->devControlRequest = true; // queue it in the request loop - } - if (response["cmd"] == (uint8_t)CleanState_LockAndAlarm) { - iv->devControlCmd = CleanState_LockAndAlarm; - iv->devControlRequest = true; // queue it in the request loop - } - if (response["cmd"] == (uint8_t)Restart) { - iv->devControlCmd = Restart; - iv->devControlRequest = true; // queue it in the request loop - } - } - } - request->send(200, "text/json", "{success:true}"); - }*/ - void onDebug(AsyncWebServerRequest *request) { mApp->getSchedulerNames(); AsyncWebServerResponse *response = request->beginResponse(200, F("text/html; charset=UTF-8"), "ok"); From 116a1e6a93583e60aa2f70e26b0d19ce7fa22fce Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 11 Mar 2023 23:52:12 +0100 Subject: [PATCH 06/52] 0.5.99 fix limit in [User_Manual.md](../User_Manual.md) changed `contrast` to `luminance` in `setup.html` try to fix SSD1306 display #759 only show necessary display pins depending on setting --- User_Manual.md | 2 +- src/CHANGES.md | 8 ++++++- src/app.cpp | 2 +- src/defines.h | 2 +- src/plugins/Display/Display.h | 4 ++-- src/web/html/setup.html | 39 ++++++++++++++++++++++++++++------- src/web/web.h | 6 +++--- 7 files changed, 47 insertions(+), 16 deletions(-) diff --git a/User_Manual.md b/User_Manual.md index 15247155..f0b24ef1 100644 --- a/User_Manual.md +++ b/User_Manual.md @@ -156,7 +156,7 @@ with a payload `[0 .. 65535]` Example: ```mqtt -inverter/ctrl/limit_nonpersistent_absolute/0 600W +inverter/ctrl/limit/0 600W ``` ### Power Limit persistent diff --git a/src/CHANGES.md b/src/CHANGES.md index c28d4c6b..65c67bb8 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -2,10 +2,16 @@ (starting from release version `0.5.66`) +## 0.5.99 +* fix limit in [User_Manual.md](../User_Manual.md) +* changed `contrast` to `luminance` in `setup.html` +* try to fix SSD1306 display #759 +* only show necessary display pins depending on setting + ## 0.5.98 * fix SH1106 rotation and turn off during night #756 * removed MQTT subscription `sync_ntp`, `set_time` with a value of `0` does the same #696 -* simplified MQTT subscription for `limit`. Check [User-Manual.md](../User-Manual.md) for new syntax #696, #713 +* simplified MQTT subscription for `limit`. Check [User_Manual.md](../User_Manual.md) for new syntax #696, #713 * repaired inverter wise limit control * fix upload settings #686 diff --git a/src/app.cpp b/src/app.cpp index a65d1f09..a69d73a1 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -78,7 +78,7 @@ void app::setup() { // Plugins if (mConfig->plugin.display.type != 0) - mDisplay.setup(&mConfig->plugin.display, &mSys, &mTimestamp, 0xff, mVersion); + mDisplay.setup(&mConfig->plugin.display, &mSys, &mTimestamp, mVersion); mPubSerial.setup(mConfig, &mSys, &mTimestamp); diff --git a/src/defines.h b/src/defines.h index 6888f8a9..228f7388 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 5 -#define VERSION_PATCH 98 +#define VERSION_PATCH 99 //------------------------------------- typedef struct { diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index 1081c4fa..6e492e44 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -14,7 +14,7 @@ class Display { public: Display() {} - void setup(display_t *cfg, HMSYSTEM *sys, uint32_t *utcTs, uint8_t disp_reset, const char *version) { + void setup(display_t *cfg, HMSYSTEM *sys, uint32_t *utcTs, const char *version) { mCfg = cfg; mSys = sys; mUtcTs = utcTs; @@ -27,7 +27,7 @@ class Display { if ((1 < mCfg->type) && (mCfg->type < 10)) { mMono.config(mCfg->pwrSaveAtIvOffline, mCfg->pxShift, mCfg->contrast); - mMono.init(mCfg->type, mCfg->rot, mCfg->disp_cs, mCfg->disp_dc, mCfg->disp_reset, mCfg->disp_clk, mCfg->disp_data, mUtcTs, mVersion); + mMono.init(mCfg->type, mCfg->rot, mCfg->disp_cs, mCfg->disp_dc, 0xff, mCfg->disp_clk, mCfg->disp_data, mUtcTs, mVersion); } else if (mCfg->type >= 10) { #if defined(ESP32) mRefreshCycle = 0; diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 588fd51b..ad8506dd 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -265,11 +265,11 @@
-
Enable Screensaver (pixel shifting)
+
Enable Screensaver (pixel shifting, OLED only)
-
Contrast
+
Luminance

Pinout

@@ -647,12 +647,12 @@ document.getElementsByName(i)[0].checked = obj[i]; var e = document.getElementById("dispPins"); - pins = [['clock', 'disp_clk'], ['data', 'disp_data'], ['cs', 'disp_cs'], ['dc', 'disp_dc'], ['reset', 'disp_rst'], ['busy', 'disp_bsy']]; + var pins = [['clock', 'disp_clk'], ['data', 'disp_data'], ['cs', 'disp_cs'], ['dc', 'disp_dc'], ['reset', 'disp_rst']]; + if("ESP32" == type) + pins.push(['busy', 'disp_bsy']); for(p of pins) { - if(("ESP8266" == type) && p[0] == "busy") - break; e.append( - ml("div", {class: "row mb-3"}, [ + ml("div", {class: "row mb-3", id: "row_" + p[1]}, [ ml("div", {class: "col-12 col-sm-3 my-2"}, p[0].toUpperCase()), ml("div", {class: "col-12 col-sm-9"}, sel(p[1], ("ESP8266" == type) ? esp8266pins : esp32pins, obj[p[1]]) @@ -664,12 +664,16 @@ var opts = [[0, "None"], [1, "SSD1306 0.96\""], [2, "SH1106 1.3\""], [3, "Nokia5110"]]; if("ESP32" == type) opts.push([10, "ePaper"]); + var dispType = sel("disp_typ", opts, obj["disp_typ"]); document.getElementById("dispType").append( ml("div", {class: "row mb-3"}, [ ml("div", {class: "col-12 col-sm-3 my-2"}, "Type"), - ml("div", {class: "col-12 col-sm-9"}, sel("disp_typ", opts, obj["disp_typ"])) + ml("div", {class: "col-12 col-sm-9"}, dispType) ]) ); + dispType.addEventListener('change', (e) => { + hideDispPins(pins, e.target.value) + }); opts = [[0, "0°"], [2, "180°"]]; if("ESP32" == type) { @@ -684,6 +688,27 @@ ); document.getElementsByName("disp_cont")[0].value = obj["disp_cont"]; + hideDispPins(pins, obj.disp_typ); + } + + function hideDispPins(pins, dispType) { + if(0 == dispType) { + for(p of pins) { + document.getElementById("row_" + p[1]).classList.add("hide"); + } + } else if(2 >= dispType) { + for(var i = 0; i < pins.length; i++) { + var cl = document.getElementById("row_" + pins[i][1]).classList; + if(i < 2) + cl.remove("hide"); + else + cl.add("hide"); + } + } else { + for(p of pins) { + document.getElementById("row_" + p[1]).classList.remove("hide"); + } + } } function parse(root) { diff --git a/src/web/web.h b/src/web/web.h index 1b8833bf..098ed7ed 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -587,9 +587,9 @@ class Web { mConfig->plugin.display.contrast = (mConfig->plugin.display.type == 0) ? 60 : request->arg("disp_cont").toInt(); mConfig->plugin.display.disp_data = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : request->arg("disp_data").toInt(); mConfig->plugin.display.disp_clk = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : request->arg("disp_clk").toInt(); - mConfig->plugin.display.disp_cs = (mConfig->plugin.display.type < 3) ? DEF_PIN_OFF : request->arg("disp_cs").toInt(); - mConfig->plugin.display.disp_reset = (mConfig->plugin.display.type < 3) ? DEF_PIN_OFF : request->arg("disp_rst").toInt(); - mConfig->plugin.display.disp_dc = (mConfig->plugin.display.type < 3) ? DEF_PIN_OFF : request->arg("disp_dc").toInt(); + mConfig->plugin.display.disp_cs = (mConfig->plugin.display.type < 4) ? DEF_PIN_OFF : request->arg("disp_cs").toInt(); + mConfig->plugin.display.disp_reset = (mConfig->plugin.display.type < 4) ? DEF_PIN_OFF : request->arg("disp_rst").toInt(); + mConfig->plugin.display.disp_dc = (mConfig->plugin.display.type < 4) ? DEF_PIN_OFF : request->arg("disp_dc").toInt(); mConfig->plugin.display.disp_busy = (mConfig->plugin.display.type < 10) ? DEF_PIN_OFF : request->arg("disp_bsy").toInt(); mApp->saveSettings((request->arg("reboot") == "on")); From f6d9cd6142403cd27032084b25f38e358b7e2695 Mon Sep 17 00:00:00 2001 From: DM6JM Date: Sun, 12 Mar 2023 17:39:36 +0100 Subject: [PATCH 07/52] Update: RPi documentation --- tools/rpi/README.md | 18 +++++++++++++-- tools/rpi/ahoy_system.service | 42 +++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 tools/rpi/ahoy_system.service diff --git a/tools/rpi/README.md b/tools/rpi/README.md index d1829706..79bc5cbb 100644 --- a/tools/rpi/README.md +++ b/tools/rpi/README.md @@ -21,14 +21,22 @@ Required Hardware Setup `ahoy.py` has been successfully tested with the following setup -- RaspberryPi Model 2B (any model should work) +- RaspberryPi Model 2B, 4B (any model should work) - NRF24L01+ Radio Module connected as described, e.g., in [2] (Instructions at [3] should work identically, but [2] has more pretty pictures.) +- or the [PaHoy board](https://github.com/DM6JM/PaHoy/) - TMRh20's 'Optimized High Speed nRF24L01+ Driver' [3], installed as per the instructions given in [4] - Python Library Wrapper, as per [5] +- or the easy way, using [pyRF24](https://github.com/nRF24/pyRF24)[6] +How to talk to the nRF24L01+ in Python? +--------------------------------------- +Either you make use of the way proposed in the following, using the NRF24 Python Wrapper and the 'Optimized High Speed nRF24L01+ Driver' OR you just use pip and let it install pyRF24. + +- If you go with pyRF24, all that needs to be done is installing pyRF24 as described in [6]. Please be aware that not all examples provided in this repo are prepared to use pyRF24. It might be nescessary to adjust the imports from RF24 to pyRF24 to get them running. Once you installed pyRF24, go on at 'Required python modules' +- If you go with the RF24 wrapper, do the following steps Building the NRF24 Python Wrapper --------------------------------- @@ -220,7 +228,12 @@ Example injects exactly the same as we normally use to poll data This allows for even faster hacking during runtime - +Running it as a service +----------------------- +If you want to run directly from the start, you might want to install it as a service. +Depending on if you want to run it once a user is logged in or as soon as the system is booted, two service examples are included. +ahoy.service allows you to start it as a user service upon login. +ahoy_system.service allows you to start it as a system service already before login without user interaction. Analysing the Logs ------------------ @@ -263,3 +276,4 @@ References - [3] https://nrf24.github.io/RF24/index.html - [4] https://nrf24.github.io/RF24/md_docs_linux_install.html - [5] https://nrf24.github.io/RF24/md_docs_python_wrapper.html +- [6] https://github.com/nRF24/pyRF24 diff --git a/tools/rpi/ahoy_system.service b/tools/rpi/ahoy_system.service new file mode 100644 index 00000000..df8f4b13 --- /dev/null +++ b/tools/rpi/ahoy_system.service @@ -0,0 +1,42 @@ +###################################################################### +# systemd.service configuration for ahoy (lumapu) +# users can modify the lines: +# Description +# ExecStart (example: name of config file) +# WorkingDirectory (absolute path to your private ahoy dir) +# To change other config parameter, please consult systemd documentation +# +# To activate this service, enable and start ahoy.service: +# - Create folder ahoy in /home/ and set owner to the user that the +# service should be executed for (e.g. pi) +# - Copy folder contents to new folder +# - Adjust the user that this service should be executed as, avoid root +# - Execute commands to setup, check and start/stop as wanted +# $ sudo systemctl enable /home/ahoy/tools/rpi/ahoy.service +# $ sudo systemctl status ahoy +# $ sudo systemctl start ahoy +# $ sudo systemctl stop ahoy +# +# 2023.01 +# 2023.03 +###################################################################### + +[Unit] + +Description=ahoy (lumapu) as Service +After=network.target local-fs.target time-sync.target + +[Service] +ExecStart=/usr/bin/env python3 -um hoymiles --log-transactions --verbose --config ahoy.yml +RestartSec=10 +Restart=on-failure +Type=simple +User=pi + +# WorkingDirectory must be an absolute path - not relative path +WorkingDirectory=/home/ahoy/tools/rpi +EnvironmentFile=/etc/environment + +[Install] +WantedBy=default.target + From 6da58e3505ed1ef79238cc707a335f31527a3fa8 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 13 Mar 2023 21:58:48 +0100 Subject: [PATCH 08/52] 0.5.100 fix add inverter `setup.html` #766 fix MQTT retained flag for total values #726 renamed buttons for import and export `setup.html` added serial message `settings saved` --- src/CHANGES.md | 6 ++++++ src/app.h | 1 + src/config/settings.h | 1 + src/defines.h | 2 +- src/publisher/pubMqtt.h | 6 +++--- src/web/html/setup.html | 6 +++--- 6 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 65c67bb8..9ec5f85b 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -2,6 +2,12 @@ (starting from release version `0.5.66`) +## 0.5.100 +* fix add inverter `setup.html` #766 +* fix MQTT retained flag for total values #726 +* renamed buttons for import and export `setup.html` +* added serial message `settings saved` + ## 0.5.99 * fix limit in [User_Manual.md](../User_Manual.md) * changed `contrast` to `luminance` in `setup.html` diff --git a/src/app.h b/src/app.h index 64510eef..a792ffe8 100644 --- a/src/app.h +++ b/src/app.h @@ -210,6 +210,7 @@ class app : public IApp, public ah::Scheduler { onWifi(false); ah::Scheduler::resetTicker(); WiFi.disconnect(); + delay(200); ESP.restart(); } diff --git a/src/config/settings.h b/src/config/settings.h index fab8327e..77bc7a26 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -273,6 +273,7 @@ class settings { } fp.close(); + DPRINTLN(DBG_INFO, F("settings saved")); if(stopFs) stop(); diff --git a/src/defines.h b/src/defines.h index 228f7388..b800aaa0 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 5 -#define VERSION_PATCH 99 +#define VERSION_PATCH 100 //------------------------------------- typedef struct { diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 2b2b298e..7922b2e8 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -59,7 +59,7 @@ class PubMqtt { if((strlen(mCfgMqtt->user) > 0) && (strlen(mCfgMqtt->pwd) > 0)) mClient.setCredentials(mCfgMqtt->user, mCfgMqtt->pwd); - snprintf(mClientId, 26, "%s-", mDevName); + snprintf(mClientId, 24, "%s-", mDevName); uint8_t pos = strlen(mClientId); mClientId[pos++] = WiFi.macAddress().substring( 9, 10).c_str()[0]; mClientId[pos++] = WiFi.macAddress().substring(10, 11).c_str()[0]; @@ -582,8 +582,8 @@ class PubMqtt { if (sendTotals) { uint8_t fieldId; - bool retained = true; for (uint8_t i = 0; i < 4; i++) { + bool retained = true; switch (i) { default: case 0: @@ -635,7 +635,7 @@ class PubMqtt { // last will topic and payload must be available trough lifetime of 'espMqttClient' char mLwtTopic[MQTT_TOPIC_LEN+5]; const char *mDevName, *mVersion; - char mClientId[26]; // number of chars is limited to 23 up to v3.1 of MQTT + char mClientId[24]; // number of chars is limited to 23 up to v3.1 of MQTT }; #endif /*__PUB_MQTT_H__*/ diff --git a/src/web/html/setup.html b/src/web/html/setup.html index ad8506dd..967cccd6 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -295,14 +295,14 @@
- +
Export
- Download settings (JSON file) (only values, passwords will be removed!) + Export settings (JSON file) (only values, passwords will be removed!)
@@ -368,7 +368,7 @@ document.getElementById("btnAdd").addEventListener("click", function() { if(highestId <= (maxInv-1)) { - ivHtml(JSON.parse('{"enabled":true,"name":"","serial":"","channels":4,"ch_max_power":[0,0,0,0],"ch_name":["","","",""],"ch_yield_cor":[0,0,0,0]}'), highestId); + ivHtml(JSON.parse('{"enabled":true,"name":"","serial":"","channels":4,"ch_max_pwr":[0,0,0,0],"ch_name":["","","",""],"ch_yield_cor":[0,0,0,0]}'), highestId); } }); From 20688b207ab6ff70f7f8b6658fc5e642625e4ead Mon Sep 17 00:00:00 2001 From: dAjaY85 Date: Tue, 14 Mar 2023 09:13:18 +0100 Subject: [PATCH 09/52] Korrektur, damit SSD wieder funktioniert. --- src/plugins/Display/Display.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index 6e492e44..566a1395 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -25,7 +25,7 @@ class Display { if (mCfg->type == 0) return; - if ((1 < mCfg->type) && (mCfg->type < 10)) { + if ((0 < mCfg->type) && (mCfg->type < 10)) { mMono.config(mCfg->pwrSaveAtIvOffline, mCfg->pxShift, mCfg->contrast); mMono.init(mCfg->type, mCfg->rot, mCfg->disp_cs, mCfg->disp_dc, 0xff, mCfg->disp_clk, mCfg->disp_data, mUtcTs, mVersion); } else if (mCfg->type >= 10) { From 237d45f19aada8f53d9d193ece04d32303c395d1 Mon Sep 17 00:00:00 2001 From: dAjaY85 Date: Tue, 14 Mar 2023 09:15:04 +0100 Subject: [PATCH 10/52] Version 101 --- src/defines.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/defines.h b/src/defines.h index b800aaa0..997981a3 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 5 -#define VERSION_PATCH 100 +#define VERSION_PATCH 101 //------------------------------------- typedef struct { From 58d992c7713d761ceacf54656d3fd477b9595162 Mon Sep 17 00:00:00 2001 From: argafal Date: Tue, 14 Mar 2023 18:28:05 +0100 Subject: [PATCH 11/52] Two improvements to heap fragmentation See https://github.com/lumapu/ahoy/issues/768. --- src/publisher/pubMqtt.h | 22 +++++++++++++--------- src/publisher/pubMqttDefs.h | 2 ++ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 2b2b298e..3acbef1b 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -111,6 +111,7 @@ class PubMqtt { publish(subtopics[MQTT_UPTIME], val); publish(subtopics[MQTT_RSSI], String(WiFi.RSSI()).c_str()); publish(subtopics[MQTT_FREE_HEAP], String(ESP.getFreeHeap()).c_str()); + publish(subtopics[MQTT_HEAP_FRAG], String(ESP.getHeapFragmentation()).c_str()); } bool tickerSun(uint32_t sunrise, uint32_t sunset, uint32_t offs, bool disNightCom) { @@ -162,14 +163,16 @@ class PubMqtt { if(!mClient.connected()) return; - String topic = ""; - if(addTopic) - topic = String(mCfgMqtt->topic) + "/"; - topic += String(subTopic); + memset(mTopic, 0, MQTT_TOPIC_LEN+5); + if(addTopic){ + snprintf(mTopic, MQTT_TOPIC_LEN+5, "%s/%s", mCfgMqtt->topic, subTopic); + } else { + snprintf(mTopic, MQTT_TOPIC_LEN+5, "%s", subTopic); + } do { - if(0 != mClient.publish(topic.c_str(), QOS_0, retained, payload)) - break; + if(0 != mClient.publish(mTopic, QOS_0, retained, payload)) + break; if(!mClient.connected()) break; #if defined(ESP8266) @@ -207,7 +210,7 @@ class PubMqtt { DPRINTLN(DBG_VERBOSE, F("sendMqttDiscoveryConfig")); char topic[64], name[32], uniq_id[32]; - DynamicJsonDocument doc(256); + StaticJsonDocument<256> doc; uint8_t fldTotal[4] = {FLD_PAC, FLD_YT, FLD_YD, FLD_PDC}; const char* unitTotal[4] = {"W", "kWh", "Wh", "W"}; @@ -264,7 +267,7 @@ class PubMqtt { stateCls = getFieldStateClass(fldTotal[i]); } - DynamicJsonDocument doc2(512); + StaticJsonDocument<512> doc2; doc2[F("name")] = name; doc2[F("stat_t")] = String(mCfgMqtt->topic) + "/" + ((!total) ? String(iv->config->name) : "total" ) + String(topic); doc2[F("unit_of_meas")] = ((!total) ? (iv->getUnit(i,rec)) : (unitTotal[i])); @@ -356,7 +359,7 @@ class PubMqtt { if(NULL == mSubscriptionCb) return; - DynamicJsonDocument json(128); + StaticJsonDocument<128> json; JsonObject root = json.to(); bool limitAbs = false; @@ -636,6 +639,7 @@ class PubMqtt { char mLwtTopic[MQTT_TOPIC_LEN+5]; const char *mDevName, *mVersion; char mClientId[26]; // number of chars is limited to 23 up to v3.1 of MQTT + char mTopic[MQTT_TOPIC_LEN+5]; }; #endif /*__PUB_MQTT_H__*/ diff --git a/src/publisher/pubMqttDefs.h b/src/publisher/pubMqttDefs.h index 9633e2d4..088023b7 100644 --- a/src/publisher/pubMqttDefs.h +++ b/src/publisher/pubMqttDefs.h @@ -41,6 +41,7 @@ enum { MQTT_UPTIME = 0, MQTT_RSSI, MQTT_FREE_HEAP, + MQTT_HEAP_FRAG, MQTT_SUNRISE, MQTT_SUNSET, MQTT_COMM_START, @@ -64,6 +65,7 @@ const char* const subtopics[] PROGMEM = { "uptime", "wifi_rssi", "free_heap", + "heap_frag", "sunrise", "sunset", "comm_start", From 73032663c421c41d3b6355fc308820b5296974c8 Mon Sep 17 00:00:00 2001 From: argafal Date: Tue, 14 Mar 2023 18:31:03 +0100 Subject: [PATCH 12/52] Resolve conflict, accept upstream --- src/publisher/pubMqtt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 3acbef1b..633ec912 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -638,7 +638,7 @@ class PubMqtt { // last will topic and payload must be available trough lifetime of 'espMqttClient' char mLwtTopic[MQTT_TOPIC_LEN+5]; const char *mDevName, *mVersion; - char mClientId[26]; // number of chars is limited to 23 up to v3.1 of MQTT + char mClientId[24]; // number of chars is limited to 23 up to v3.1 of MQTT char mTopic[MQTT_TOPIC_LEN+5]; }; From 108ab3ecfa18070ee774cb1e40ea227c14f393b4 Mon Sep 17 00:00:00 2001 From: dAjaY85 Date: Tue, 14 Mar 2023 22:12:34 +0100 Subject: [PATCH 13/52] 1306 Fehlerkorrektur --- src/plugins/Display/Display.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index 566a1395..1a0222b2 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -79,7 +79,7 @@ class Display { totalYieldTotal += iv->getChannelFieldValue(CH0, FLD_YT, rec); } - if ((1 < mCfg->type) && (mCfg->type < 10)) { + if ((0 < mCfg->type) && (mCfg->type < 10)) { mMono.disp(totalPower, totalYieldDay, totalYieldTotal, isprod); } else if (mCfg->type >= 10) { #if defined(ESP32) From 44faa0316c9bf89ffe6e5579bfa04177bb1ad27f Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Wed, 15 Mar 2023 08:19:24 +0100 Subject: [PATCH 14/52] MI - reviw ac calculation (#2) * Update: RPi documentation * Update miPayload.h * Update README.md * MI - remarks to user manual * MI - getting started * MI - user manual typos * MI - fix AC calc * MI - fix status msg. analysis --------- Co-authored-by: DM6JM Co-authored-by: Lukas Pusch --- Getting_Started.md | 4 ++++ README.md | 2 +- User_Manual.md | 8 +++++++ src/hm/miPayload.h | 38 +++++++++++++------------------ tools/rpi/README.md | 18 +++++++++++++-- tools/rpi/ahoy_system.service | 42 +++++++++++++++++++++++++++++++++++ 6 files changed, 87 insertions(+), 25 deletions(-) create mode 100644 tools/rpi/ahoy_system.service diff --git a/Getting_Started.md b/Getting_Started.md index b595da77..ff592f8b 100644 --- a/Getting_Started.md +++ b/Getting_Started.md @@ -53,6 +53,10 @@ Hoymiles Inverters - HM1000? - HM1200 - HM1500 +- MI-300* [For MI inverters see remarks here](User_Manual.md#mi-inverters) +- MI-600* +- MI-700* +- MI-1500* (2nd gen. still untested) TSUN Inverters: diff --git a/README.md b/README.md index 43b31dfe..b7e2aa9e 100644 --- a/README.md +++ b/README.md @@ -48,4 +48,4 @@ Please try to describe your issues as precise as possible and think about if thi - [OpenDTU](https://github.com/tbnobody/OpenDTU) <- Our sister project ✨ for Hoymiles HM-300, HM-600, HM-1200 (for ESP32 only!) - [DTU Simulator](https://github.com/Ziyatoe/DTUsimMI1x00-Hoymiles) - <- Go here ✨ for Hoymiles MI-300, MI-600, MI-1200 Software + <- Go here ✨ for Hoymiles MI-300, MI-600, MI-1200 Software (single inverter only) diff --git a/User_Manual.md b/User_Manual.md index b605f3c9..242a2809 100644 --- a/User_Manual.md +++ b/User_Manual.md @@ -321,3 +321,11 @@ Send Power Limit: - A persistent limit is only needed if you want to throttle your inverter permanently or you can use it to set a start value on the battery, which is then always the switch-on limit when switching on, otherwise it would ramp up to 100% without regulation, which is continuous load is not healthy. - You can set a new limit in the turn-off state, which is then used for on (switching on again), otherwise the last limit from before the turn-off is used, but of course this only applies if DC voltage is applied the whole time. - If the DC voltage is missing for a few seconds, the microcontroller in the inverter goes off and forgets everything that was temporary/non-persistent in the RAM: YieldDay, error memory, non-persistent limit. + +## Additional Notes +### MI Inverters +- AhoyDTU supports MI type inverters as well, since dev. version 0.5.70. +- MI inverters are known to be delivered with two different generations of firmwares: inverters with serial numbers 10x2 already use the 3rd generation protocol and behave just like the newer HM models, *the follwoing remarks do not apply to these*. +- Older MI inverters (#sn 10x1) use a different rf protocol and thus do not deliver exactly the same data. E.g. the AC power value will therefore be calculated by AhoyDTU itself, while other values might not be available at all. +- Single and dual channel 2nd gen. devices seem not to accept power limiting commands at all, the lower limit for 4-channel MI is 10% (instead of 2% for newer models) +- 4-channel MI type inverters might work, but code still is untested. diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index c4fc2a2a..62e7450e 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -118,7 +118,7 @@ class MiPayload { //DPRINTLN(DBG_INFO, F("MI got data [0]=") + String(p->packet[0], HEX)); if (p->packet[0] == (0x08 + ALL_FRAMES)) { // 0x88; MI status response to 0x09 - miStsDecode(iv, p); + miStsDecode(iv, p), CH1; } else if (p->packet[0] == (0x11 + SINGLE_FRAME)) { // 0x92; MI status response to 0x11 @@ -361,6 +361,7 @@ const byteAssign_t InfoAssignment[] = { if (!mPayload[iv->id].stsAB[CH2] || !mPayload[iv->id].dataAB[CH2] ) { cmd = 0x11; change = true; + mPayload[iv->id].retransmits = 0; //reset counter } } } else if ( cmd == 0x11) { @@ -468,15 +469,16 @@ const byteAssign_t InfoAssignment[] = { (mCbMiPayload)(val); } - void miStsDecode(Inverter<> *iv, packet_t *p, uint8_t chan = CH1) { + void miStsDecode(Inverter<> *iv, packet_t *p, uint8_t stschan = CH1) { DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") status msg 0x") + String(p->packet[0], HEX)); record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); // choose the record structure rec->ts = mPayload[iv->id].ts; mPayload[iv->id].gotFragment = true; mPayload[iv->id].txId = p->packet[0]; - uint8_t status = (p->packet[11] << 8) + p->packet[12]; - uint8_t stschan = p->packet[0] == 0x88 ? CH1 : CH2; + //uint8_t status = (p->packet[11] << 8) + p->packet[12]; + uint8_t status = (p->packet[9] << 8) + p->packet[10]; + //uint8_t stschan = p->packet[0] == 0x88 ? CH1 : CH2; mPayload[iv->id].sts[stschan] = status; mPayload[iv->id].stsAB[stschan] = true; if (mPayload[iv->id].stsAB[CH1] && mPayload[iv->id].stsAB[CH2]) @@ -495,20 +497,6 @@ const byteAssign_t InfoAssignment[] = { //mPayload[iv->id].skipfirstrepeat = 1; if (mPayload[iv->id].stsAB[CH0] && mPayload[iv->id].dataAB[CH0] && !mPayload[iv->id].complete) { miComplete(iv); - /*mPayload[iv->id].complete = true; - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") got all msgs")); - iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0)); - //preliminary AC calculation... - uint8_t ac_pow = 0; - //if (mPayload[iv->id].sts[0] == 3) { - ac_pow = calcPowerDcCh0(iv, 0)*9.5; - //} - iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) (ac_pow/10)); - iv->setQueuedCmdFinished(); - iv->doCalculations(); - mPayload[iv->id].skipfirstrepeat = 0; - notify(mPayload[iv->id].txCmd); - yield();*/ } } @@ -632,10 +620,16 @@ const byteAssign_t InfoAssignment[] = { record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0)); //preliminary AC calculation... + uint8_t ac_pow = 0; - //if (mPayload[iv->id].sts[0] == 3) { - ac_pow = calcPowerDcCh0(iv, 0)*9.5; - //} + for(uint8_t i = 1; i <= iv->channels; i++) { + if (mPayload[iv->id].sts[i] == 3) { + uint8_t pos = iv->getPosByChFld(i, FLD_PDC, rec); + ac_pow += iv->getValue(pos, rec); + } + } + ac_pow = ac_pow*9.5; + iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) (ac_pow/10)); iv->doCalculations(); iv->setQueuedCmdFinished(); @@ -693,7 +687,7 @@ const byteAssign_t InfoAssignment[] = { mPayload[id].skipfirstrepeat = 0; mPayload[id].requested = false; mPayload[id].ts = *mTimestamp; - mPayload[id].sts[0] = 0; //disable this in case gotFragment is not working + mPayload[id].sts[0] = 0; mPayload[id].sts[CH1] = 0; mPayload[id].sts[CH2] = 0; mPayload[id].sts[CH3] = 0; diff --git a/tools/rpi/README.md b/tools/rpi/README.md index d1829706..79bc5cbb 100644 --- a/tools/rpi/README.md +++ b/tools/rpi/README.md @@ -21,14 +21,22 @@ Required Hardware Setup `ahoy.py` has been successfully tested with the following setup -- RaspberryPi Model 2B (any model should work) +- RaspberryPi Model 2B, 4B (any model should work) - NRF24L01+ Radio Module connected as described, e.g., in [2] (Instructions at [3] should work identically, but [2] has more pretty pictures.) +- or the [PaHoy board](https://github.com/DM6JM/PaHoy/) - TMRh20's 'Optimized High Speed nRF24L01+ Driver' [3], installed as per the instructions given in [4] - Python Library Wrapper, as per [5] +- or the easy way, using [pyRF24](https://github.com/nRF24/pyRF24)[6] +How to talk to the nRF24L01+ in Python? +--------------------------------------- +Either you make use of the way proposed in the following, using the NRF24 Python Wrapper and the 'Optimized High Speed nRF24L01+ Driver' OR you just use pip and let it install pyRF24. + +- If you go with pyRF24, all that needs to be done is installing pyRF24 as described in [6]. Please be aware that not all examples provided in this repo are prepared to use pyRF24. It might be nescessary to adjust the imports from RF24 to pyRF24 to get them running. Once you installed pyRF24, go on at 'Required python modules' +- If you go with the RF24 wrapper, do the following steps Building the NRF24 Python Wrapper --------------------------------- @@ -220,7 +228,12 @@ Example injects exactly the same as we normally use to poll data This allows for even faster hacking during runtime - +Running it as a service +----------------------- +If you want to run directly from the start, you might want to install it as a service. +Depending on if you want to run it once a user is logged in or as soon as the system is booted, two service examples are included. +ahoy.service allows you to start it as a user service upon login. +ahoy_system.service allows you to start it as a system service already before login without user interaction. Analysing the Logs ------------------ @@ -263,3 +276,4 @@ References - [3] https://nrf24.github.io/RF24/index.html - [4] https://nrf24.github.io/RF24/md_docs_linux_install.html - [5] https://nrf24.github.io/RF24/md_docs_python_wrapper.html +- [6] https://github.com/nRF24/pyRF24 diff --git a/tools/rpi/ahoy_system.service b/tools/rpi/ahoy_system.service new file mode 100644 index 00000000..df8f4b13 --- /dev/null +++ b/tools/rpi/ahoy_system.service @@ -0,0 +1,42 @@ +###################################################################### +# systemd.service configuration for ahoy (lumapu) +# users can modify the lines: +# Description +# ExecStart (example: name of config file) +# WorkingDirectory (absolute path to your private ahoy dir) +# To change other config parameter, please consult systemd documentation +# +# To activate this service, enable and start ahoy.service: +# - Create folder ahoy in /home/ and set owner to the user that the +# service should be executed for (e.g. pi) +# - Copy folder contents to new folder +# - Adjust the user that this service should be executed as, avoid root +# - Execute commands to setup, check and start/stop as wanted +# $ sudo systemctl enable /home/ahoy/tools/rpi/ahoy.service +# $ sudo systemctl status ahoy +# $ sudo systemctl start ahoy +# $ sudo systemctl stop ahoy +# +# 2023.01 +# 2023.03 +###################################################################### + +[Unit] + +Description=ahoy (lumapu) as Service +After=network.target local-fs.target time-sync.target + +[Service] +ExecStart=/usr/bin/env python3 -um hoymiles --log-transactions --verbose --config ahoy.yml +RestartSec=10 +Restart=on-failure +Type=simple +User=pi + +# WorkingDirectory must be an absolute path - not relative path +WorkingDirectory=/home/ahoy/tools/rpi +EnvironmentFile=/etc/environment + +[Install] +WantedBy=default.target + From 3b661b050fcf738b86b6ab5b008401356eee9546 Mon Sep 17 00:00:00 2001 From: argafal Date: Wed, 15 Mar 2023 10:12:49 +0100 Subject: [PATCH 15/52] Increase the MQTT topic buffer size See https://github.com/lumapu/ahoy/issues/768#issuecomment-1468692140 --- src/publisher/pubMqtt.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 2fdb77ba..d66f5899 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -163,11 +163,11 @@ class PubMqtt { if(!mClient.connected()) return; - memset(mTopic, 0, MQTT_TOPIC_LEN+5); + memset(mTopic, 0, MQTT_TOPIC_LEN + 32 + MAX_NAME_LENGTH + 1); if(addTopic){ - snprintf(mTopic, MQTT_TOPIC_LEN+5, "%s/%s", mCfgMqtt->topic, subTopic); + snprintf(mTopic, MQTT_TOPIC_LEN + 32 + MAX_NAME_LENGTH + 1, "%s/%s", mCfgMqtt->topic, subTopic); } else { - snprintf(mTopic, MQTT_TOPIC_LEN+5, "%s", subTopic); + snprintf(mTopic, MQTT_TOPIC_LEN + 32 + MAX_NAME_LENGTH + 1, "%s", subTopic); } do { @@ -639,7 +639,8 @@ class PubMqtt { char mLwtTopic[MQTT_TOPIC_LEN+5]; const char *mDevName, *mVersion; char mClientId[24]; // number of chars is limited to 23 up to v3.1 of MQTT - char mTopic[MQTT_TOPIC_LEN+5]; + // global buffer for mqtt topic. Used when publishing mqtt messages. + char mTopic[MQTT_TOPIC_LEN + 32 + MAX_NAME_LENGTH + 1]; }; #endif /*__PUB_MQTT_H__*/ From 53ae7fe7f5e6e98793972eb21e1c6db1e6fb9bb1 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 16 Mar 2023 08:02:36 +0100 Subject: [PATCH 16/52] Mi dev control (#3) * MI - add devControl path to ivSend() * MI - review AC calc II Additionally code restructured to prepare for dev control (limitation, not working yet) --- src/hm/miPayload.h | 131 +++++++++++++++++++++++++++------------------ 1 file changed, 79 insertions(+), 52 deletions(-) diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index 62e7450e..a90b845d 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -68,49 +68,93 @@ class MiPayload { } void loop() { - /*if(NULL != mHighPrioIv) { - iv->ivSend(mHighPrioIv, true); // should request firmware version etc.? + if(NULL != mHighPrioIv) { + ivSend(mHighPrioIv, true); // for devcontrol commands? mHighPrioIv = NULL; - }*/ + } } void ivSendHighPrio(Inverter<> *iv) { mHighPrioIv = iv; } - void ivSend(Inverter<> *iv) { + void ivSend(Inverter<> *iv, bool highPrio = false) { + if(!highPrio) { + if (mPayload[iv->id].requested) { + if (!mPayload[iv->id].complete) + process(false); // no retransmit + + if (!mPayload[iv->id].complete) { + if (!mPayload[iv->id].gotFragment) + mStat->rxFailNoAnser++; // got nothing + else + mStat->rxFail++; // got fragments but not complete response + + iv->setQueuedCmdFinished(); // command failed + if (mSerialDebug) + DPRINTLN(DBG_INFO, F("enqueued cmd failed/timeout")); + if (mSerialDebug) { + DPRINT(DBG_INFO, F("(#")); + DBGPRINT(String(iv->id)); + DBGPRINT(F(") no Payload received! (retransmits: ")); + DBGPRINT(String(mPayload[iv->id].retransmits)); + DBGPRINTLN(F(")")); + } + } + } + } + reset(iv->id); mPayload[iv->id].requested = true; yield(); - if (mSerialDebug) - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") Requesting Inv SN ") + String(iv->config->serial.u64, HEX)); - - uint8_t cmd = iv->getQueuedCmd(); - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(") prepareDevInformCmd 0x")); - DBGPRINTLN(String(cmd, HEX)); - uint8_t cmd2 = cmd; - if (cmd == 0x1 ) { //0x1 - cmd = 0x0f; - cmd2 = 0x00; - mSys->Radio.sendCmdPacket(iv->radioId.u64, cmd, cmd2, false); - } else { - mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd2, mPayload[iv->id].ts, iv->alarmMesIndex, false, cmd); - }; - - mPayload[iv->id].txCmd = cmd; - if (iv->type == INV_TYPE_1CH || iv->type == INV_TYPE_2CH) { - mPayload[iv->id].dataAB[CH1] = false; - mPayload[iv->id].stsAB[CH1] = false; - mPayload[iv->id].dataAB[CH0] = false; - mPayload[iv->id].stsAB[CH0] = false; + if (mSerialDebug){ + DPRINT(DBG_INFO, F("(#")); + DBGPRINT(String(iv->id)); + DBGPRINT(F(") Requesting Inv SN ")); + DBGPRINTLN(String(iv->config->serial.u64, HEX)); } - if (iv->type == INV_TYPE_2CH) { - mPayload[iv->id].dataAB[CH2] = false; - mPayload[iv->id].stsAB[CH2] = false; + if (iv->getDevControlRequest()) { + if (mSerialDebug) { + DPRINT(DBG_INFO, F("(#")); + DBGPRINT(String(iv->id)); + DBGPRINT(F(") Devcontrol request 0x")); + DBGPRINT(String(iv->devControlCmd, HEX)); + DBGPRINT(F(" power limit ")); + DBGPRINTLN(String(iv->powerLimit[0])); + } + mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, false); + mPayload[iv->id].txCmd = iv->devControlCmd; + //iv->clearCmdQueue(); + //iv->enqueCommand(SystemConfigPara); // read back power limit + } else { + uint8_t cmd = iv->getQueuedCmd(); + DPRINT(DBG_INFO, F("(#")); + DBGPRINT(String(iv->id)); + DBGPRINT(F(") prepareDevInformCmd 0x")); + DBGPRINTLN(String(cmd, HEX)); + uint8_t cmd2 = cmd; + if (cmd == 0x1 ) { //0x1 + cmd = 0x0f; + cmd2 = 0x00; + mSys->Radio.sendCmdPacket(iv->radioId.u64, cmd, cmd2, false); + } else { + mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd2, mPayload[iv->id].ts, iv->alarmMesIndex, false, cmd); + }; + + mPayload[iv->id].txCmd = cmd; + if (iv->type == INV_TYPE_1CH || iv->type == INV_TYPE_2CH) { + mPayload[iv->id].dataAB[CH1] = false; + mPayload[iv->id].stsAB[CH1] = false; + mPayload[iv->id].dataAB[CH0] = false; + mPayload[iv->id].stsAB[CH0] = false; + } + + if (iv->type == INV_TYPE_2CH) { + mPayload[iv->id].dataAB[CH2] = false; + mPayload[iv->id].stsAB[CH2] = false; + } } } @@ -118,7 +162,7 @@ class MiPayload { //DPRINTLN(DBG_INFO, F("MI got data [0]=") + String(p->packet[0], HEX)); if (p->packet[0] == (0x08 + ALL_FRAMES)) { // 0x88; MI status response to 0x09 - miStsDecode(iv, p), CH1; + miStsDecode(iv, p); } else if (p->packet[0] == (0x11 + SINGLE_FRAME)) { // 0x92; MI status response to 0x11 @@ -573,27 +617,11 @@ const byteAssign_t InfoAssignment[] = { } - - if ( mPayload[iv->id].complete || //4ch device (iv->type != INV_TYPE_4CH //other devices && mPayload[iv->id].dataAB[CH0] && mPayload[iv->id].stsAB[CH0])) { miComplete(iv); - /*mPayload[iv->id].complete = true; // For 2 CH devices, this might be too short... - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") got all msgs")); - iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0)); - //preliminary AC calculation... - uint8_t ac_pow = 0; - //if (mPayload[iv->id].sts[0] == 3) { - ac_pow = calcPowerDcCh0(iv, 0)*9.5; - //} - iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) (ac_pow/10)); - iv->doCalculations(); - iv->setQueuedCmdFinished(); - mStat->rxSuccess++; - yield(); - notify(mPayload[iv->id].txCmd);*/ } @@ -619,18 +647,18 @@ const byteAssign_t InfoAssignment[] = { DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") got all msgs")); record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0)); - //preliminary AC calculation... - uint8_t ac_pow = 0; + //preliminary AC calculation... + float ac_pow = 0; for(uint8_t i = 1; i <= iv->channels; i++) { if (mPayload[iv->id].sts[i] == 3) { uint8_t pos = iv->getPosByChFld(i, FLD_PDC, rec); ac_pow += iv->getValue(pos, rec); } } - ac_pow = ac_pow*9.5; + ac_pow = (int) (ac_pow*9.5); + iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) ac_pow/10); - iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) (ac_pow/10)); iv->doCalculations(); iv->setQueuedCmdFinished(); mStat->rxSuccess++; @@ -695,7 +723,6 @@ const byteAssign_t InfoAssignment[] = { } - IApp *mApp; HMSYSTEM *mSys; statistics_t *mStat; From 12f37c2cb08129259036362cea216b7109bb314f Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 16 Mar 2023 09:35:42 +0100 Subject: [PATCH 17/52] MI - add some multiframe handling --- src/hm/hmRadio.h | 5 ++++- src/hm/miPayload.h | 9 ++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index f0236362..8f528784 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -253,7 +253,10 @@ class HmRadio { mBufCtrl.push(p); if (p.packet[0] == (TX_REQ_INFO + ALL_FRAMES)) // response from get information command isLastPackage = (p.packet[9] > 0x81); // > 0x81 indicates last packet received - else if (p.packet[0] != 0x00) // ignore fragment number zero + else if (p.packet[0] == ( 0x0f + ALL_FRAMES) ) // response from MI get information command + isLastPackage = (p.packet[9] > 0x11); // > 0x11 indicates last packet received + else if (p.packet[0] != 0x00 && p.packet[0] != 0x88 && p.packet[0] != 0x92) + // ignore fragment number zero and MI status messages isLastPackage = true; // response from dev control command yield(); } diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index a90b845d..931c9657 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -221,14 +221,16 @@ const byteAssign_t InfoAssignment[] = { for (uint8_t i = 0; i < 5; i++) { iv->setValue(i, rec, (float) ((p->packet[(12+2*i)] << 8) + p->packet[(13+2*i)])/1); } - iv->setQueuedCmdFinished(); + /*iv->setQueuedCmdFinished(); mStat->rxSuccess++; - mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x01, false); + mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x01, false);*/ } else if ( p->packet[9] == 0x01 ) {//second frame DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") got 2nd frame (hw info)")); - mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x12, false); + //mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x12, false); } else if ( p->packet[9] == 0x12 ) {//3rd frame DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") got 3rd frame (hw info)")); + iv->setQueuedCmdFinished(); + mStat->rxSuccess++; } } else if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command @@ -723,6 +725,7 @@ const byteAssign_t InfoAssignment[] = { } + IApp *mApp; HMSYSTEM *mSys; statistics_t *mStat; From 3317265783e6a308c46cb4b46849892532caea88 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 16 Mar 2023 16:48:57 +0100 Subject: [PATCH 18/52] MI - optimize serial output and resending logic --- hmRadio.h | 335 +++++++++++++++++++++++ miPayload.h | 757 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1092 insertions(+) create mode 100644 hmRadio.h create mode 100644 miPayload.h diff --git a/hmRadio.h b/hmRadio.h new file mode 100644 index 00000000..8f528784 --- /dev/null +++ b/hmRadio.h @@ -0,0 +1,335 @@ +//----------------------------------------------------------------------------- +// 2023 Ahoy, https://github.com/lumpapu/ahoy +// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +//----------------------------------------------------------------------------- + +#ifndef __RADIO_H__ +#define __RADIO_H__ + +#include "../utils/dbg.h" +#include +#include "../utils/crc.h" +#include "../config/config.h" + +#define SPI_SPEED 1000000 + +#define RF_CHANNELS 5 + +#define TX_REQ_INFO 0x15 +#define TX_REQ_DEVCONTROL 0x51 +#define ALL_FRAMES 0x80 +#define SINGLE_FRAME 0x81 + +const char* const rf24AmpPowerNames[] = {"MIN", "LOW", "HIGH", "MAX"}; + + +//----------------------------------------------------------------------------- +// MACROS +//----------------------------------------------------------------------------- +#define CP_U32_LittleEndian(buf, v) ({ \ + uint8_t *b = buf; \ + b[0] = ((v >> 24) & 0xff); \ + b[1] = ((v >> 16) & 0xff); \ + b[2] = ((v >> 8) & 0xff); \ + b[3] = ((v ) & 0xff); \ +}) + +#define CP_U32_BigEndian(buf, v) ({ \ + uint8_t *b = buf; \ + b[3] = ((v >> 24) & 0xff); \ + b[2] = ((v >> 16) & 0xff); \ + b[1] = ((v >> 8) & 0xff); \ + b[0] = ((v ) & 0xff); \ +}) + +#define BIT_CNT(x) ((x)<<3) + +//----------------------------------------------------------------------------- +// HM Radio class +//----------------------------------------------------------------------------- +template +class HmRadio { + public: + HmRadio() : mNrf24(CE_PIN, CS_PIN, SPI_SPEED) { + DPRINT(DBG_VERBOSE, F("hmRadio.h : HmRadio():mNrf24(CE_PIN: ")); + DPRINT(DBG_VERBOSE, String(CE_PIN)); + DPRINT(DBG_VERBOSE, F(", CS_PIN: ")); + DPRINT(DBG_VERBOSE, String(CS_PIN)); + DPRINT(DBG_VERBOSE, F(", SPI_SPEED: ")); + DPRINTLN(DBG_VERBOSE, String(SPI_SPEED) + ")"); + + // Depending on the program, the module can work on 2403, 2423, 2440, 2461 or 2475MHz. + // Channel List 2403, 2423, 2440, 2461, 2475MHz + mRfChLst[0] = 03; + mRfChLst[1] = 23; + mRfChLst[2] = 40; + mRfChLst[3] = 61; + mRfChLst[4] = 75; + + // default channels + mTxChIdx = 2; // Start TX with 40 + mRxChIdx = 0; // Start RX with 03 + + mSendCnt = 0; + mRetransmits = 0; + + mSerialDebug = false; + mIrqRcvd = false; + } + ~HmRadio() {} + + void setup(uint8_t ampPwr = RF24_PA_LOW, uint8_t irq = IRQ_PIN, uint8_t ce = CE_PIN, uint8_t cs = CS_PIN) { + DPRINTLN(DBG_VERBOSE, F("hmRadio.h:setup")); + pinMode(irq, INPUT_PULLUP); + + uint32_t dtuSn = 0x87654321; + uint32_t chipID = 0; // will be filled with last 3 bytes of MAC + #ifdef ESP32 + uint64_t MAC = ESP.getEfuseMac(); + chipID = ((MAC >> 8) & 0xFF0000) | ((MAC >> 24) & 0xFF00) | ((MAC >> 40) & 0xFF); + #else + chipID = ESP.getChipId(); + #endif + if(chipID) { + dtuSn = 0x80000000; // the first digit is an 8 for DTU production year 2022, the rest is filled with the ESP chipID in decimal + for(int i = 0; i < 7; i++) { + dtuSn |= (chipID % 10) << (i * 4); + chipID /= 10; + } + } + // change the byte order of the DTU serial number and append the required 0x01 at the end + DTU_RADIO_ID = ((uint64_t)(((dtuSn >> 24) & 0xFF) | ((dtuSn >> 8) & 0xFF00) | ((dtuSn << 8) & 0xFF0000) | ((dtuSn << 24) & 0xFF000000)) << 8) | 0x01; + + mNrf24.begin(ce, cs); + mNrf24.setRetries(3, 15); // 3*250us + 250us and 15 loops -> 15ms + + mNrf24.setChannel(mRfChLst[mRxChIdx]); + mNrf24.startListening(); + mNrf24.setDataRate(RF24_250KBPS); + mNrf24.setAutoAck(true); + mNrf24.enableDynamicPayloads(); + mNrf24.setCRCLength(RF24_CRC_16); + mNrf24.setAddressWidth(5); + mNrf24.openReadingPipe(1, DTU_RADIO_ID); + + // enable all receiving interrupts + mNrf24.maskIRQ(false, false, false); + + DPRINT(DBG_INFO, F("RF24 Amp Pwr: RF24_PA_")); + DPRINTLN(DBG_INFO, String(rf24AmpPowerNames[ampPwr])); + mNrf24.setPALevel(ampPwr & 0x03); + + if(mNrf24.isChipConnected()) { + DPRINTLN(DBG_INFO, F("Radio Config:")); + mNrf24.printPrettyDetails(); + } + else + DPRINTLN(DBG_WARN, F("WARNING! your NRF24 module can't be reached, check the wiring")); + } + + bool loop(void) { + if (!mIrqRcvd) + return false; // nothing to do + mIrqRcvd = false; + bool tx_ok, tx_fail, rx_ready; + mNrf24.whatHappened(tx_ok, tx_fail, rx_ready); // resets the IRQ pin to HIGH + mNrf24.flush_tx(); // empty TX FIFO + //DBGPRINTLN("TX whatHappened Ch" + String(mRfChLst[mTxChIdx]) + " " + String(tx_ok) + String(tx_fail) + String(rx_ready)); + + // start listening on the default RX channel + mRxChIdx = 0; + mNrf24.setChannel(mRfChLst[mRxChIdx]); + mNrf24.startListening(); + + //uint32_t debug_ms = millis(); + uint16_t cnt = 300; // that is 60 times 5 channels + while (0 < cnt--) { + uint32_t startMillis = millis(); + while (millis()-startMillis < 4) { // listen 4ms to each channel + if (mIrqRcvd) { + mIrqRcvd = false; + if (getReceived()) { // everything received + //DBGPRINTLN("RX finished Cnt: " + String(300-cnt) + " time used: " + String(millis()-debug_ms)+ " ms"); + return true; + } + } + yield(); + } + switchRxCh(); // switch to next RX channel + yield(); + } + // not finished but time is over + //DBGPRINTLN("RX not finished: 300 time used: " + String(millis()-debug_ms)+ " ms"); + return true; + } + + void handleIntr(void) { + mIrqRcvd = true; + } + + bool isChipConnected(void) { + //DPRINTLN(DBG_VERBOSE, F("hmRadio.h:isChipConnected")); + return mNrf24.isChipConnected(); + } + void enableDebug() { + mSerialDebug = true; + } + + void sendControlPacket(uint64_t invId, uint8_t cmd, uint16_t *data, bool isRetransmit) { + DPRINT(DBG_INFO, F("sendControlPacket cmd: 0x")); + DBGPRINTLN(String(cmd, HEX)); + initPacket(invId, TX_REQ_DEVCONTROL, SINGLE_FRAME); + uint8_t cnt = 10; + mTxBuf[cnt++] = cmd; // cmd -> 0 on, 1 off, 2 restart, 11 active power, 12 reactive power, 13 power factor + mTxBuf[cnt++] = 0x00; + if(cmd >= ActivePowerContr && cmd <= PFSet) { // ActivePowerContr, ReactivePowerContr, PFSet + mTxBuf[cnt++] = ((data[0] * 10) >> 8) & 0xff; // power limit + mTxBuf[cnt++] = ((data[0] * 10) ) & 0xff; // power limit + mTxBuf[cnt++] = ((data[1] ) >> 8) & 0xff; // setting for persistens handlings + mTxBuf[cnt++] = ((data[1] ) ) & 0xff; // setting for persistens handling + } + sendPacket(invId, cnt, isRetransmit, true); + } + + void prepareDevInformCmd(uint64_t invId, uint8_t cmd, uint32_t ts, uint16_t alarmMesId, bool isRetransmit, uint8_t reqfld=TX_REQ_INFO) { // might not be necessary to add additional arg. + DPRINTLN(DBG_DEBUG, F("prepareDevInformCmd 0x") + String(cmd, HEX)); + initPacket(invId, reqfld, ALL_FRAMES); + mTxBuf[10] = cmd; // cid + mTxBuf[11] = 0x00; + CP_U32_LittleEndian(&mTxBuf[12], ts); + if (cmd == RealTimeRunData_Debug || cmd == AlarmData ) { + mTxBuf[18] = (alarmMesId >> 8) & 0xff; + mTxBuf[19] = (alarmMesId ) & 0xff; + } + sendPacket(invId, 24, isRetransmit, true); + } + + void sendCmdPacket(uint64_t invId, uint8_t mid, uint8_t pid, bool isRetransmit) { + initPacket(invId, mid, pid); + sendPacket(invId, 10, isRetransmit, false); + } + + void dumpBuf(uint8_t buf[], uint8_t len) { + //DPRINTLN(DBG_VERBOSE, F("hmRadio.h:dumpBuf")); + for(uint8_t i = 0; i < len; i++) { + DHEX(buf[i]); + DBGPRINT(" "); + } + DBGPRINTLN(""); + } + + uint8_t getDataRate(void) { + if(!mNrf24.isChipConnected()) + return 3; // unkown + return mNrf24.getDataRate(); + } + + bool isPVariant(void) { + return mNrf24.isPVariant(); + } + + std::queue mBufCtrl; + + uint32_t mSendCnt; + uint32_t mRetransmits; + + bool mSerialDebug; + + private: + bool getReceived(void) { + bool tx_ok, tx_fail, rx_ready; + mNrf24.whatHappened(tx_ok, tx_fail, rx_ready); // resets the IRQ pin to HIGH + //DBGPRINTLN("RX whatHappened Ch" + String(mRfChLst[mRxChIdx]) + " " + String(tx_ok) + String(tx_fail) + String(rx_ready)); + + bool isLastPackage = false; + while(mNrf24.available()) { + uint8_t len; + len = mNrf24.getDynamicPayloadSize(); // if payload size > 32, corrupt payload has been flushed + if (len > 0) { + packet_t p; + p.ch = mRfChLst[mRxChIdx]; + p.len = len; + mNrf24.read(p.packet, len); + mBufCtrl.push(p); + if (p.packet[0] == (TX_REQ_INFO + ALL_FRAMES)) // response from get information command + isLastPackage = (p.packet[9] > 0x81); // > 0x81 indicates last packet received + else if (p.packet[0] == ( 0x0f + ALL_FRAMES) ) // response from MI get information command + isLastPackage = (p.packet[9] > 0x11); // > 0x11 indicates last packet received + else if (p.packet[0] != 0x00 && p.packet[0] != 0x88 && p.packet[0] != 0x92) + // ignore fragment number zero and MI status messages + isLastPackage = true; // response from dev control command + yield(); + } + } + return isLastPackage; + } + + void switchRxCh() { + mNrf24.stopListening(); + // get next channel index + if(++mRxChIdx >= RF_CHANNELS) + mRxChIdx = 0; + mNrf24.setChannel(mRfChLst[mRxChIdx]); + mNrf24.startListening(); + } + + void initPacket(uint64_t invId, uint8_t mid, uint8_t pid) { + DPRINTLN(DBG_VERBOSE, F("initPacket, mid: ") + String(mid, HEX) + F(" pid: ") + String(pid, HEX)); + memset(mTxBuf, 0, MAX_RF_PAYLOAD_SIZE); + mTxBuf[0] = mid; // message id + CP_U32_BigEndian(&mTxBuf[1], (invId >> 8)); + CP_U32_BigEndian(&mTxBuf[5], (DTU_RADIO_ID >> 8)); + mTxBuf[9] = pid; + } + + void sendPacket(uint64_t invId, uint8_t len, bool isRetransmit, bool clear=false) { + //DPRINTLN(DBG_VERBOSE, F("hmRadio.h:sendPacket")); + //DPRINTLN(DBG_VERBOSE, "sent packet: #" + String(mSendCnt)); + + // append crc's + if (len > 10) { + // crc control data + uint16_t crc = ah::crc16(&mTxBuf[10], len - 10); + mTxBuf[len++] = (crc >> 8) & 0xff; + mTxBuf[len++] = (crc ) & 0xff; + } + // crc over all + mTxBuf[len] = ah::crc8(mTxBuf, len); + len++; + + if(mSerialDebug) { + DPRINT(DBG_INFO, F("TX ")); + DBGPRINT(String(len)); + DBGPRINT("B Ch"); + DBGPRINT(String(mRfChLst[mTxChIdx])); + DBGPRINT(F(" | ")); + dumpBuf(mTxBuf, len); + } + + mNrf24.stopListening(); + mNrf24.setChannel(mRfChLst[mTxChIdx]); + mNrf24.openWritingPipe(reinterpret_cast(&invId)); + mNrf24.startWrite(mTxBuf, len, false); // false = request ACK response + + // switch TX channel for next packet + if(++mTxChIdx >= RF_CHANNELS) + mTxChIdx = 0; + + if(isRetransmit) + mRetransmits++; + else + mSendCnt++; + } + + volatile bool mIrqRcvd; + uint64_t DTU_RADIO_ID; + + uint8_t mRfChLst[RF_CHANNELS]; + uint8_t mTxChIdx; + uint8_t mRxChIdx; + + RF24 mNrf24; + uint8_t mTxBuf[MAX_RF_PAYLOAD_SIZE]; +}; + +#endif /*__RADIO_H__*/ diff --git a/miPayload.h b/miPayload.h new file mode 100644 index 00000000..7e32ea92 --- /dev/null +++ b/miPayload.h @@ -0,0 +1,757 @@ +//----------------------------------------------------------------------------- +// 2023 Ahoy, https://ahoydtu.de +// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +//----------------------------------------------------------------------------- + +#ifndef __MI_PAYLOAD_H__ +#define __MI_PAYLOAD_H__ + +//#include "hmInverter.h" +#include "../utils/dbg.h" +#include "../utils/crc.h" +#include "../config/config.h" +#include + +typedef struct { + uint32_t ts; + bool requested; + uint8_t txCmd; + uint8_t len[MAX_PAYLOAD_ENTRIES]; + bool complete; + bool dataAB[3]; + bool stsAB[3]; + uint8_t sts[5]; + uint8_t txId; + uint8_t invId; + uint8_t retransmits; + uint8_t skipfirstrepeat; + bool gotFragment; + /* + uint8_t data[MAX_PAYLOAD_ENTRIES][MAX_RF_PAYLOAD_SIZE]; + uint8_t maxPackId; + bool lastFound;*/ +} miPayload_t; + + +typedef std::function miPayloadListenerType; + + +template +class MiPayload { + public: + MiPayload() {} + + void setup(IApp *app, HMSYSTEM *sys, statistics_t *stat, uint8_t maxRetransmits, uint32_t *timestamp) { + mApp = app; + mSys = sys; + mStat = stat; + mMaxRetrans = maxRetransmits; + mTimestamp = timestamp; + for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { + reset(i); + } + mSerialDebug = false; + mHighPrioIv = NULL; + mCbMiPayload = NULL; + } + + void enableSerialDebug(bool enable) { + mSerialDebug = enable; + } + + void addPayloadListener(miPayloadListenerType cb) { + mCbMiPayload = cb; + } + + void addAlarmListener(alarmListenerType cb) { + mCbMiAlarm = cb; + } + + void loop() { + if(NULL != mHighPrioIv) { + ivSend(mHighPrioIv, true); // for devcontrol commands? + mHighPrioIv = NULL; + } + } + + void ivSendHighPrio(Inverter<> *iv) { + mHighPrioIv = iv; + } + + void ivSend(Inverter<> *iv, bool highPrio = false) { + if(!highPrio) { + if (mPayload[iv->id].requested) { + if (!mPayload[iv->id].complete) + process(false); // no retransmit + + if (!mPayload[iv->id].complete) { + if (!mPayload[iv->id].gotFragment) + mStat->rxFailNoAnser++; // got nothing + else + mStat->rxFail++; // got fragments but not complete response + + iv->setQueuedCmdFinished(); // command failed + if (mSerialDebug) + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("enqueued cmd failed/timeout")); + if (mSerialDebug) { + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINT(F("no Payload received! (retransmits: ")); + DBGPRINT(String(mPayload[iv->id].retransmits)); + DBGPRINTLN(F(")")); + } + } + } + } + + reset(iv->id); + mPayload[iv->id].requested = true; + + yield(); + if (mSerialDebug){ + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINT(F("Requesting Inv SN ")); + DBGPRINTLN(String(iv->config->serial.u64, HEX)); + } + + if (iv->getDevControlRequest()) { + if (mSerialDebug) { + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINT(F("Devcontrol request 0x")); + DBGPRINT(String(iv->devControlCmd, HEX)); + DBGPRINT(F(" power limit ")); + DBGPRINTLN(String(iv->powerLimit[0])); + } + mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, false); + mPayload[iv->id].txCmd = iv->devControlCmd; + //iv->clearCmdQueue(); + //iv->enqueCommand(SystemConfigPara); // read back power limit + } else { + uint8_t cmd = iv->getQueuedCmd(); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINT(F("prepareDevInformCmd 0x")); + DBGPRINTLN(String(cmd, HEX)); + uint8_t cmd2 = cmd; + if (cmd == 0x1 ) { //0x1 + cmd = 0x0f; + cmd2 = 0x00; + mSys->Radio.sendCmdPacket(iv->radioId.u64, cmd, cmd2, false); + } else { + mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd2, mPayload[iv->id].ts, iv->alarmMesIndex, false, cmd); + }; + + mPayload[iv->id].txCmd = cmd; + if (iv->type == INV_TYPE_1CH || iv->type == INV_TYPE_2CH) { + mPayload[iv->id].dataAB[CH1] = false; + mPayload[iv->id].stsAB[CH1] = false; + mPayload[iv->id].dataAB[CH0] = false; + mPayload[iv->id].stsAB[CH0] = false; + } + + if (iv->type == INV_TYPE_2CH) { + mPayload[iv->id].dataAB[CH2] = false; + mPayload[iv->id].stsAB[CH2] = false; + } + } + } + + void add(Inverter<> *iv, packet_t *p) { + //DPRINTLN(DBG_INFO, F("MI got data [0]=") + String(p->packet[0], HEX)); + + if (p->packet[0] == (0x08 + ALL_FRAMES)) { // 0x88; MI status response to 0x09 + miStsDecode(iv, p); + } + + else if (p->packet[0] == (0x11 + SINGLE_FRAME)) { // 0x92; MI status response to 0x11 + miStsDecode(iv, p, CH2); + } + + else if ( p->packet[0] == 0x09 + ALL_FRAMES || + p->packet[0] == 0x11 + ALL_FRAMES || + ( p->packet[0] >= (0x36 + ALL_FRAMES) && p->packet[0] < (0x39 + SINGLE_FRAME) ) ) { // small MI or MI 1500 data responses to 0x09, 0x11, 0x36, 0x37, 0x38 and 0x39 + mPayload[iv->id].txId = p->packet[0]; + miDataDecode(iv,p); + } + + else if (p->packet[0] == ( 0x0f + ALL_FRAMES)) { + // MI response from get hardware information request + record_t<> *rec = iv->getRecordStruct(InverterDevInform_All); // choose the record structure + rec->ts = mPayload[iv->id].ts; + mPayload[iv->id].gotFragment = true; + +/* + Polling the device software and hardware version number command + start byte Command word routing address target address User data check end byte + byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7] byte[8] byte[9] byte[10] byte[11] byte[12] + 0x7e 0x0f xx xx xx xx YY YY YY YY 0x00 CRC 0x7f + Command Receipt - First Frame + start byte Command word target address routing address Multi-frame marking User data User data User data User data User data User data User data User data User data User data User data User data User data User data User data User data check end byte + byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7] byte[8] byte[9] byte[10] byte[11] byte[12] byte[13] byte[14] byte[15] byte[16] byte[17] byte[18] byte[19] byte[20] byte[21] byte[22] byte[23] byte[24] byte[25] byte[26] byte[27] byte[28] + 0x7e 0x8f YY YY YY YY xx xx xx xx 0x00 USFWBuild_VER APPFWBuild_VER APPFWBuild_YYYY APPFWBuild_MMDD APPFWBuild_HHMM APPFW_PN HW_VER CRC 0x7f + Command Receipt - Second Frame + start byte Command word target address routing address Multi-frame marking User data User data User data User data User data User data User data User data User data User data User data User data User data User data User data User data check end byte + byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7] byte[8] byte[9] byte[10] byte[11] byte[12] byte[13] byte[14] byte[15] byte[16] byte[17] byte[18] byte[19] byte[20] byte[21] byte[22] byte[23] byte[24] byte[25] byte[26] byte[27] byte[28] + 0x7e 0x8f YY YY YY YY xx xx xx xx 0x01 HW_PN HW_FB_TLmValue HW_FB_ReSPRT HW_GridSamp_ResValule HW_ECapValue Matching_APPFW_PN CRC 0x7f + Command receipt - third frame + start byte Command word target address routing address Multi-frame marking User data User data User data User data User data User data User data User data check end byte + byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7] byte[8] byte[9] byte[10] byte[11] byte[12] byte[13] byte[14] byte[15] byte[16] byte[15] byte[16] byte[17] byte[18] + 0x7e 0x8f YY YY YY YY xx xx xx xx 0x12 APPFW_MINVER HWInfoAddr PNInfoCRC_gusv PNInfoCRC_gusv CRC 0x7f +*/ + +/* +case InverterDevInform_All: + rec->length = (uint8_t)(HMINFO_LIST_LEN); + rec->assign = (byteAssign_t *)InfoAssignment; + rec->pyldLen = HMINFO_PAYLOAD_LEN; + break; +const byteAssign_t InfoAssignment[] = { + { FLD_FW_VERSION, UNIT_NONE, CH0, 0, 2, 1 }, + { FLD_FW_BUILD_YEAR, UNIT_NONE, CH0, 2, 2, 1 }, + { FLD_FW_BUILD_MONTH_DAY, UNIT_NONE, CH0, 4, 2, 1 }, + { FLD_FW_BUILD_HOUR_MINUTE, UNIT_NONE, CH0, 6, 2, 1 }, + { FLD_HW_ID, UNIT_NONE, CH0, 8, 2, 1 } +}; +*/ + + if ( p->packet[9] == 0x00 ) {//first frame + //FLD_FW_VERSION + for (uint8_t i = 0; i < 5; i++) { + iv->setValue(i, rec, (float) ((p->packet[(12+2*i)] << 8) + p->packet[(13+2*i)])/1); + } + /*iv->setQueuedCmdFinished(); + mStat->rxSuccess++; + mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x01, false);*/ + } else if ( p->packet[9] == 0x01 ) {//second frame + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("got 2nd frame (hw info)")); + //mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x12, false); + } else if ( p->packet[9] == 0x12 ) {//3rd frame + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("got 3rd frame (hw info)")); + iv->setQueuedCmdFinished(); + mStat->rxSuccess++; + } + + } else if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command + // atm, we just do nothing else than print out what we got... + // for decoding see xls- Data collection instructions - #147ff + mPayload[iv->id].txId = p->packet[0]; + DPRINTLN(DBG_DEBUG, F("Response from info request received")); + uint8_t *pid = &p->packet[9]; + if (*pid == 0x00) { + DPRINT(DBG_DEBUG, F("fragment number zero received")); + + iv->setQueuedCmdFinished(); + } //else { + DPRINTLN(DBG_DEBUG, "PID: 0x" + String(*pid, HEX)); + /* + if ((*pid & 0x7F) < MAX_PAYLOAD_ENTRIES) { + memcpy(mPayload[iv->id].data[(*pid & 0x7F) - 1], &p->packet[10], p->len - 11); + mPayload[iv->id].len[(*pid & 0x7F) - 1] = p->len - 11; + mPayload[iv->id].gotFragment = true; + } + if ((*pid & ALL_FRAMES) == ALL_FRAMES) { + // Last packet + if (((*pid & 0x7f) > mPayload[iv->id].maxPackId) || (MAX_PAYLOAD_ENTRIES == mPayload[iv->id].maxPackId)) { + mPayload[iv->id].maxPackId = (*pid & 0x7f); + if (*pid > 0x81) + mPayload[iv->id].lastFound = true; + } + } + } + } */ + } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command + miDPRINTHead(DBG_DEBUG, iv->id); + DBGPRINTLN(F("Response from devcontrol request received")); + + mPayload[iv->id].txId = p->packet[0]; + iv->clearDevControlRequest(); + + if ((p->packet[12] == ActivePowerContr) && (p->packet[13] == 0x00)) { + String msg = ""; + if((p->packet[10] == 0x00) && (p->packet[11] == 0x00)) + mApp->setMqttPowerLimitAck(iv); + else + msg = "NOT "; + //DPRINTLN(DBG_INFO, F("Inverter ") + String(iv->id) + F(" has ") + msg + F("accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1])); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("has ") + msg + F("accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1])); + + iv->clearCmdQueue(); + iv->enqueCommand(SystemConfigPara); // read back power limit + } + iv->devControlCmd = Init; + } else { // some other response; copied from hmPayload:process; might not be correct to do that here!!! + DPRINTLN(DBG_INFO, F("procPyld: cmd: 0x") + String(mPayload[iv->id].txCmd, HEX)); + DPRINTLN(DBG_INFO, F("procPyld: txid: 0x") + String(mPayload[iv->id].txId, HEX)); + //DPRINTLN(DBG_DEBUG, F("procPyld: max: ") + String(mPayload[iv->id].maxPackId)); + record_t<> *rec = iv->getRecordStruct(mPayload[iv->id].txCmd); // choose the parser + mPayload[iv->id].complete = true; + + uint8_t payload[128]; + uint8_t payloadLen = 0; + + memset(payload, 0, 128); + + /*for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId); i++) { + memcpy(&payload[payloadLen], mPayload[iv->id].data[i], (mPayload[iv->id].len[i])); + payloadLen += (mPayload[iv->id].len[i]); + yield(); + }*/ + payloadLen -= 2; + + if (mSerialDebug) { + DPRINT(DBG_INFO, F("Payload (") + String(payloadLen) + "): "); + mSys->Radio.dumpBuf(payload, payloadLen); + } + + if (NULL == rec) { + DPRINTLN(DBG_ERROR, F("record is NULL!")); + } else if ((rec->pyldLen == payloadLen) || (0 == rec->pyldLen)) { + if (mPayload[iv->id].txId == (TX_REQ_INFO + ALL_FRAMES)) + mStat->rxSuccess++; + + rec->ts = mPayload[iv->id].ts; + for (uint8_t i = 0; i < rec->length; i++) { + iv->addValue(i, payload, rec); + yield(); + } + iv->doCalculations(); + notify(mPayload[iv->id].txCmd); + + if(AlarmData == mPayload[iv->id].txCmd) { + uint8_t i = 0; + uint16_t code; + uint32_t start, end; + while(1) { + code = iv->parseAlarmLog(i++, payload, payloadLen, &start, &end); + if(0 == code) + break; + if (NULL != mCbMiAlarm) + (mCbMiAlarm)(code, start, end); + yield(); + } + } + } else { + DPRINTLN(DBG_ERROR, F("plausibility check failed, expected ") + String(rec->pyldLen) + F(" bytes")); + mStat->rxFail++; + } + + iv->setQueuedCmdFinished(); + } + } + + void process(bool retransmit) { + for (uint8_t id = 0; id < mSys->getNumInverters(); id++) { + Inverter<> *iv = mSys->getInverterByPos(id); + if (NULL == iv) + continue; // skip to next inverter + + if (IV_HM == iv->ivGen) // only process MI inverters + continue; // skip to next inverter + + if ( !mPayload[iv->id].complete && + (mPayload[iv->id].txId != (TX_REQ_INFO + ALL_FRAMES)) && + (mPayload[iv->id].txId < (0x36 + ALL_FRAMES)) && + (mPayload[iv->id].txId > (0x39 + ALL_FRAMES)) && + (mPayload[iv->id].txId != (0x09 + ALL_FRAMES)) && + (mPayload[iv->id].txId != (0x11 + ALL_FRAMES)) && + (mPayload[iv->id].txId != (0x88)) && + (mPayload[iv->id].txId != (0x92)) && + (mPayload[iv->id].txId != 0 )) { + // no processing needed if txId is not one of 0x95, 0x88, 0x89, 0x91, 0x92 or resonse to 0x36ff + mPayload[iv->id].complete = true; + continue; // skip to next inverter + } + + //delayed next message? + //mPayload[iv->id].skipfirstrepeat++; + if (mPayload[iv->id].skipfirstrepeat) { + mPayload[iv->id].skipfirstrepeat = 0; //reset counter*/ + continue; // skip to next inverter + } + + if (!mPayload[iv->id].complete) { + //DPRINTLN(DBG_INFO, F("Pyld incompl code")); //info for testing only + bool crcPass, pyldComplete; + crcPass = build(iv->id, &pyldComplete); + if (!crcPass && !pyldComplete) { // payload not complete + if ((mPayload[iv->id].requested) && (retransmit)) { + if (iv->devControlCmd == Restart || iv->devControlCmd == CleanState_LockAndAlarm) { + // This is required to prevent retransmissions without answer. + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); + mPayload[iv->id].retransmits = mMaxRetrans; + } else if(iv->devControlCmd == ActivePowerContr) { + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("retransmit power limit")); + mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true); + } else { + uint8_t cmd = mPayload[iv->id].txCmd; + if (mPayload[iv->id].retransmits < mMaxRetrans) { + mPayload[iv->id].retransmits++; + if( !mPayload[iv->id].gotFragment ) { + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("nothing received")); + mPayload[iv->id].retransmits = mMaxRetrans; + } else if ( cmd == 0x0f ) { + //hard/firmware request + mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x00, true); + //iv->setQueuedCmdFinished(); + //cmd = iv->getQueuedCmd(); + } else { + bool change = false; + if ( cmd >= 0x36 && cmd < 0x39 ) { // MI-1500 Data command + cmd++; // just request the next channel + change = true; + } else if ( cmd == 0x09 ) {//MI single or dual channel device + if ( mPayload[iv->id].dataAB[CH1] && iv->type == INV_TYPE_2CH ) { + if (!mPayload[iv->id].stsAB[CH1] && mPayload[iv->id].retransmits<2) {} + //first try to get missing sts for first channel a second time + else if (!mPayload[iv->id].stsAB[CH2] || !mPayload[iv->id].dataAB[CH2] ) { + cmd = 0x11; + change = true; + mPayload[iv->id].retransmits = 0; //reset counter + } + } + } else if ( cmd == 0x11) { + if ( mPayload[iv->id].dataAB[CH2] ) { // data + status ch2 are there? + if (mPayload[iv->id].stsAB[CH2] && (!mPayload[iv->id].stsAB[CH1] || !mPayload[iv->id].dataAB[CH1])) { + cmd = 0x09; + change = true; + } + } + } + miDPRINTHead(DBG_INFO, iv->id); + if (change) { + DBGPRINT(F("next request is 0x")); + } else { + DBGPRINT(F("not complete: Request Retransmit 0x")); + } + DBGPRINTLN(String(cmd, HEX)); + //mSys->Radio.sendCmdPacket(iv->radioId.u64, cmd, cmd, true); + mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex, true, cmd); + mPayload[iv->id].txCmd = cmd; + yield(); + } + } + } + } + } else if(!crcPass && pyldComplete) { // crc error on complete Payload + if (mPayload[iv->id].retransmits < mMaxRetrans) { + mPayload[iv->id].retransmits++; + miDPRINTHead(DBG_WARN, iv->id); + DBGPRINTLN(F("CRC Error: Request Complete Retransmit")); + mPayload[iv->id].txCmd = iv->getQueuedCmd(); + miDPRINTHead(DBG_INFO, iv->id); + + DBGPRINTLN(F("prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX)); + mSys->Radio.prepareDevInformCmd(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); + } + } + /*else { // payload complete + //This tree is not really tested, most likely it's not truly complete.... + DPRINTLN(DBG_INFO, F("procPyld: cmd: 0x") + String(mPayload[iv->id].txCmd, HEX)); + DPRINTLN(DBG_INFO, F("procPyld: txid: 0x") + String(mPayload[iv->id].txId, HEX)); + //DPRINTLN(DBG_DEBUG, F("procPyld: max: ") + String(mPayload[iv->id].maxPackId)); + //record_t<> *rec = iv->getRecordStruct(mPayload[iv->id].txCmd); // choose the parser + mPayload[iv->id].complete = true; + uint8_t ac_pow = 0; + //if (mPayload[iv->id].sts[0] == 3) { + ac_pow = calcPowerDcCh0(iv, 0)*9.5; + //} + record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); // choose the parser + iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) (ac_pow/10)); + DPRINTLN(DBG_INFO, F("process: compl. set of msgs detected")); + iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0)); + iv->doCalculations(); + //uint8_t payload[128]; + //uint8_t payloadLen = 0; + //memset(payload, 0, 128); + //for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId); i++) { + // memcpy(&payload[payloadLen], mPayload[iv->id].data[i], (mPayload[iv->id].len[i])); + // payloadLen += (mPayload[iv->id].len[i]); + // yield(); + //} + //payloadLen -= 2; + //if (mSerialDebug) { + // DPRINT(DBG_INFO, F("Payload (") + String(payloadLen) + "): "); + // mSys->Radio.dumpBuf(payload, payloadLen); + //} + //if (NULL == rec) { + // DPRINTLN(DBG_ERROR, F("record is NULL!")); + //} else if ((rec->pyldLen == payloadLen) || (0 == rec->pyldLen)) { + // if (mPayload[iv->id].txId == (TX_REQ_INFO + ALL_FRAMES)) + // mStat->rxSuccess++; + // rec->ts = mPayload[iv->id].ts; + // for (uint8_t i = 0; i < rec->length; i++) { + // iv->addValue(i, payload, rec); + // yield(); + // } + // iv->doCalculations(); + // notify(mPayload[iv->id].txCmd); + // if(AlarmData == mPayload[iv->id].txCmd) { + // uint8_t i = 0; + // uint16_t code; + // uint32_t start, end; + // while(1) { + // code = iv->parseAlarmLog(i++, payload, payloadLen, &start, &end); + // if(0 == code) + // break; + // if (NULL != mCbAlarm) + // (mCbAlarm)(code, start, end); + // yield(); + // } + // } + //} else { + // DPRINTLN(DBG_ERROR, F("plausibility check failed, expected ") + String(rec->pyldLen) + F(" bytes")); + // mStat->rxFail++; + //} + //iv->setQueuedCmdFinished(); + //}*/ + } + yield(); + } + } + + private: + void notify(uint8_t val) { + if(NULL != mCbMiPayload) + (mCbMiPayload)(val); + } + + void miStsDecode(Inverter<> *iv, packet_t *p, uint8_t stschan = CH1) { + //DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") status msg 0x") + String(p->packet[0], HEX)); + record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); // choose the record structure + rec->ts = mPayload[iv->id].ts; + mPayload[iv->id].gotFragment = true; + mPayload[iv->id].txId = p->packet[0]; + + //uint8_t status = (p->packet[11] << 8) + p->packet[12]; + uint8_t status = (p->packet[9] << 8) + p->packet[10]; + //uint8_t stschan = p->packet[0] == 0x88 ? CH1 : CH2; + mPayload[iv->id].sts[stschan] = status; + mPayload[iv->id].stsAB[stschan] = true; + if (mPayload[iv->id].stsAB[CH1] && mPayload[iv->id].stsAB[CH2]) + mPayload[iv->id].stsAB[CH0] = true; + if ( !mPayload[iv->id].sts[0] || status < mPayload[iv->id].sts[0]) { + mPayload[iv->id].sts[0] = status; + iv->setValue(iv->getPosByChFld(0, FLD_EVT, rec), rec, status); + } + + if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){ + iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]; // seems there's no status per channel in 3rd gen. models?!? + + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("alarm ID incremented to ") + String(iv->alarmMesIndex)); + iv->enqueCommand(AlarmData); + } + //mPayload[iv->id].skipfirstrepeat = 1; + if (mPayload[iv->id].stsAB[CH0] && mPayload[iv->id].dataAB[CH0] && !mPayload[iv->id].complete) { + miComplete(iv); + } + } + + void miDataDecode(Inverter<> *iv, packet_t *p) { + record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); // choose the parser + rec->ts = mPayload[iv->id].ts; + mPayload[iv->id].gotFragment = true; + + uint8_t datachan = ( p->packet[0] == 0x89 || p->packet[0] == (0x36 + ALL_FRAMES) ) ? CH1 : + ( p->packet[0] == 0x91 || p->packet[0] == (0x37 + ALL_FRAMES) ) ? CH2 : + p->packet[0] == (0x38 + ALL_FRAMES) ? CH3 : + CH4; + //DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") data msg 0x") + String(p->packet[0], HEX) + F(" channel ") + datachan); + // count in RF_communication_protocol.xlsx is with offset = -1 + iv->setValue(iv->getPosByChFld(datachan, FLD_UDC, rec), rec, (float)((p->packet[9] << 8) + p->packet[10])/10); + yield(); + iv->setValue(iv->getPosByChFld(datachan, FLD_IDC, rec), rec, (float)((p->packet[11] << 8) + p->packet[12])/10); + yield(); + iv->setValue(iv->getPosByChFld(0, FLD_UAC, rec), rec, (float)((p->packet[13] << 8) + p->packet[14])/10); + yield(); + iv->setValue(iv->getPosByChFld(0, FLD_F, rec), rec, (float) ((p->packet[15] << 8) + p->packet[16])/100); + iv->setValue(iv->getPosByChFld(datachan, FLD_PDC, rec), rec, (float)((p->packet[17] << 8) + p->packet[18])/10); + yield(); + iv->setValue(iv->getPosByChFld(datachan, FLD_YD, rec), rec, (float)((p->packet[19] << 8) + p->packet[20])/1); + yield(); + iv->setValue(iv->getPosByChFld(0, FLD_T, rec), rec, (float) ((int16_t)(p->packet[21] << 8) + p->packet[22])/10); + iv->setValue(iv->getPosByChFld(0, FLD_IRR, rec), rec, (float) (calcIrradiation(iv, datachan))); + //AC Power is missing; we may have to calculate, as no respective data is in payload + + if ( datachan < 3 ) { + mPayload[iv->id].dataAB[datachan] = true; + } + if ( !mPayload[iv->id].dataAB[CH0] && mPayload[iv->id].dataAB[CH2] && mPayload[iv->id].dataAB[CH2] ) { + mPayload[iv->id].dataAB[CH0] = true; + } + + if (p->packet[0] >= (0x36 + ALL_FRAMES) ) { + + /*For MI1500: + if (MI1500) { + STAT = (uint8_t)(p->packet[25] ); + FCNT = (uint8_t)(p->packet[26]); + FCODE = (uint8_t)(p->packet[27]); + }*/ + + uint8_t status = (uint8_t)(p->packet[23]); + mPayload[iv->id].sts[datachan] = status; + if ( !mPayload[iv->id].sts[0] || status < mPayload[iv->id].sts[0]) { + mPayload[iv->id].sts[0] = status; + iv->setValue(iv->getPosByChFld(0, FLD_EVT, rec), rec, status); + } + + if (p->packet[0] < (0x39 + ALL_FRAMES) ) { + /*uint8_t cmd = p->packet[0] - ALL_FRAMES + 1; + mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex, false, cmd); + mPayload[iv->id].txCmd = cmd;*/ + mPayload[iv->id].complete = false; + } + + else if (p->packet[0] == (0x39 + ALL_FRAMES) ) { + /*uint8_t cmd = p->packet[0] - ALL_FRAMES + 1; + mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex, false, cmd); + mPayload[iv->id].txCmd = cmd;*/ + mPayload[iv->id].complete = true; + } + + //iv->setValue(iv->getPosByChFld(0, FLD_EVT, rec), rec, calcMiSts(iv));yield(); + if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){ + iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]; + + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("alarm ID incremented to ") + String(iv->alarmMesIndex)); + //iv->enqueCommand(AlarmData); + } + + } + + if ( mPayload[iv->id].complete || //4ch device + (iv->type != INV_TYPE_4CH //other devices + && mPayload[iv->id].dataAB[CH0] + && mPayload[iv->id].stsAB[CH0])) { + miComplete(iv); + } + + + +/* + if(AlarmData == mPayload[iv->id].txCmd) { + uint8_t i = 0; + uint16_t code; + uint32_t start, end; + while(1) { + code = iv->parseAlarmLog(i++, payload, payloadLen, &start, &end); + if(0 == code) + break; + if (NULL != mCbMiAlarm) + (mCbAlarm)(code, start, end); + yield(); + } + }*/ + } + + void miComplete(Inverter<> *iv) { + mPayload[iv->id].complete = true; // For 2 CH devices, this might be too short... + DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") got all msgs")); + record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); + iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0)); + + //preliminary AC calculation... + float ac_pow = 0; + for(uint8_t i = 1; i <= iv->channels; i++) { + if (mPayload[iv->id].sts[i] == 3) { + uint8_t pos = iv->getPosByChFld(i, FLD_PDC, rec); + ac_pow += iv->getValue(pos, rec); + } + } + ac_pow = (int) (ac_pow*9.5); + iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) ac_pow/10); + + iv->doCalculations(); + iv->setQueuedCmdFinished(); + mStat->rxSuccess++; + yield(); + notify(mPayload[iv->id].txCmd); + } + + bool build(uint8_t id, bool *complete) { + DPRINTLN(DBG_VERBOSE, F("build")); + /*uint16_t crc = 0xffff, crcRcv = 0x0000; + if (mPayload[id].maxPackId > MAX_PAYLOAD_ENTRIES) + mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; + */ + // check if all messages are there + + *complete = mPayload[id].complete; + uint8_t txCmd = mPayload[id].txCmd; + //uint8_t cmd = getQueuedCmd(); + if(!*complete) { + DPRINTLN(DBG_VERBOSE, F("incomlete, txCmd is 0x") + String(txCmd, HEX)); // + F("cmd is 0x") + String(cmd, HEX)); + if (txCmd == 0x09 || txCmd == 0x11 || (txCmd >= 0x36 && txCmd <= 0x39)) + return false; + } + + /*for (uint8_t i = 0; i < mPayload[id].maxPackId; i++) { + if (mPayload[id].len[i] > 0) { + if (i == (mPayload[id].maxPackId - 1)) { + crc = ah::crc16(mPayload[id].data[i], mPayload[id].len[i] - 2, crc); + crcRcv = (mPayload[id].data[i][mPayload[id].len[i] - 2] << 8) | (mPayload[id].data[i][mPayload[id].len[i] - 1]); + } else + crc = ah::crc16(mPayload[id].data[i], mPayload[id].len[i], crc); + } + yield(); + } + return (crc == crcRcv) ? true : false;*/ + return true; + } + + void miDPRINTHead(uint8_t lvl, uint8_t id) { + DPRINT(lvl, F("(#")); + DBGPRINT(String(id)); + DBGPRINT(F(") ")); + } + + void reset(uint8_t id) { + //DPRINTLN(DBG_INFO, F("resetPayload: id: ") + String(id)); + miDPRINTHead(DBG_INFO, id); + DBGPRINTLN(F("resetPayload")); + memset(mPayload[id].len, 0, MAX_PAYLOAD_ENTRIES); + mPayload[id].gotFragment = false; + /*mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; + mPayload[id].lastFound = false;*/ + mPayload[id].retransmits = 0; + mPayload[id].complete = false; + mPayload[id].dataAB[CH0] = true; //required for 1CH and 2CH devices + mPayload[id].dataAB[CH1] = true; //required for 1CH and 2CH devices + mPayload[id].dataAB[CH2] = true; //only required for 2CH devices + mPayload[id].stsAB[CH0] = true; //required for 1CH and 2CH devices + mPayload[id].stsAB[CH1] = true; //required for 1CH and 2CH devices + mPayload[id].stsAB[CH2] = true; //only required for 2CH devices + mPayload[id].txCmd = 0; + mPayload[id].skipfirstrepeat = 0; + mPayload[id].requested = false; + mPayload[id].ts = *mTimestamp; + mPayload[id].sts[0] = 0; + mPayload[id].sts[CH1] = 0; + mPayload[id].sts[CH2] = 0; + mPayload[id].sts[CH3] = 0; + mPayload[id].sts[CH4] = 0; + } + + + + IApp *mApp; + HMSYSTEM *mSys; + statistics_t *mStat; + uint8_t mMaxRetrans; + uint32_t *mTimestamp; + miPayload_t mPayload[MAX_NUM_INVERTERS]; + bool mSerialDebug; + + Inverter<> *mHighPrioIv; + alarmListenerType mCbMiAlarm; + payloadListenerType mCbMiPayload; +}; + +#endif /*__MI_PAYLOAD_H__*/ From a2f559d91eba5628e09a7260d27b0305656f7246 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 16 Mar 2023 16:50:20 +0100 Subject: [PATCH 19/52] Delete miPayload.h wrong place... --- miPayload.h | 757 ---------------------------------------------------- 1 file changed, 757 deletions(-) delete mode 100644 miPayload.h diff --git a/miPayload.h b/miPayload.h deleted file mode 100644 index 7e32ea92..00000000 --- a/miPayload.h +++ /dev/null @@ -1,757 +0,0 @@ -//----------------------------------------------------------------------------- -// 2023 Ahoy, https://ahoydtu.de -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ -//----------------------------------------------------------------------------- - -#ifndef __MI_PAYLOAD_H__ -#define __MI_PAYLOAD_H__ - -//#include "hmInverter.h" -#include "../utils/dbg.h" -#include "../utils/crc.h" -#include "../config/config.h" -#include - -typedef struct { - uint32_t ts; - bool requested; - uint8_t txCmd; - uint8_t len[MAX_PAYLOAD_ENTRIES]; - bool complete; - bool dataAB[3]; - bool stsAB[3]; - uint8_t sts[5]; - uint8_t txId; - uint8_t invId; - uint8_t retransmits; - uint8_t skipfirstrepeat; - bool gotFragment; - /* - uint8_t data[MAX_PAYLOAD_ENTRIES][MAX_RF_PAYLOAD_SIZE]; - uint8_t maxPackId; - bool lastFound;*/ -} miPayload_t; - - -typedef std::function miPayloadListenerType; - - -template -class MiPayload { - public: - MiPayload() {} - - void setup(IApp *app, HMSYSTEM *sys, statistics_t *stat, uint8_t maxRetransmits, uint32_t *timestamp) { - mApp = app; - mSys = sys; - mStat = stat; - mMaxRetrans = maxRetransmits; - mTimestamp = timestamp; - for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { - reset(i); - } - mSerialDebug = false; - mHighPrioIv = NULL; - mCbMiPayload = NULL; - } - - void enableSerialDebug(bool enable) { - mSerialDebug = enable; - } - - void addPayloadListener(miPayloadListenerType cb) { - mCbMiPayload = cb; - } - - void addAlarmListener(alarmListenerType cb) { - mCbMiAlarm = cb; - } - - void loop() { - if(NULL != mHighPrioIv) { - ivSend(mHighPrioIv, true); // for devcontrol commands? - mHighPrioIv = NULL; - } - } - - void ivSendHighPrio(Inverter<> *iv) { - mHighPrioIv = iv; - } - - void ivSend(Inverter<> *iv, bool highPrio = false) { - if(!highPrio) { - if (mPayload[iv->id].requested) { - if (!mPayload[iv->id].complete) - process(false); // no retransmit - - if (!mPayload[iv->id].complete) { - if (!mPayload[iv->id].gotFragment) - mStat->rxFailNoAnser++; // got nothing - else - mStat->rxFail++; // got fragments but not complete response - - iv->setQueuedCmdFinished(); // command failed - if (mSerialDebug) - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINTLN(F("enqueued cmd failed/timeout")); - if (mSerialDebug) { - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINT(F("no Payload received! (retransmits: ")); - DBGPRINT(String(mPayload[iv->id].retransmits)); - DBGPRINTLN(F(")")); - } - } - } - } - - reset(iv->id); - mPayload[iv->id].requested = true; - - yield(); - if (mSerialDebug){ - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINT(F("Requesting Inv SN ")); - DBGPRINTLN(String(iv->config->serial.u64, HEX)); - } - - if (iv->getDevControlRequest()) { - if (mSerialDebug) { - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINT(F("Devcontrol request 0x")); - DBGPRINT(String(iv->devControlCmd, HEX)); - DBGPRINT(F(" power limit ")); - DBGPRINTLN(String(iv->powerLimit[0])); - } - mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, false); - mPayload[iv->id].txCmd = iv->devControlCmd; - //iv->clearCmdQueue(); - //iv->enqueCommand(SystemConfigPara); // read back power limit - } else { - uint8_t cmd = iv->getQueuedCmd(); - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINT(F("prepareDevInformCmd 0x")); - DBGPRINTLN(String(cmd, HEX)); - uint8_t cmd2 = cmd; - if (cmd == 0x1 ) { //0x1 - cmd = 0x0f; - cmd2 = 0x00; - mSys->Radio.sendCmdPacket(iv->radioId.u64, cmd, cmd2, false); - } else { - mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd2, mPayload[iv->id].ts, iv->alarmMesIndex, false, cmd); - }; - - mPayload[iv->id].txCmd = cmd; - if (iv->type == INV_TYPE_1CH || iv->type == INV_TYPE_2CH) { - mPayload[iv->id].dataAB[CH1] = false; - mPayload[iv->id].stsAB[CH1] = false; - mPayload[iv->id].dataAB[CH0] = false; - mPayload[iv->id].stsAB[CH0] = false; - } - - if (iv->type == INV_TYPE_2CH) { - mPayload[iv->id].dataAB[CH2] = false; - mPayload[iv->id].stsAB[CH2] = false; - } - } - } - - void add(Inverter<> *iv, packet_t *p) { - //DPRINTLN(DBG_INFO, F("MI got data [0]=") + String(p->packet[0], HEX)); - - if (p->packet[0] == (0x08 + ALL_FRAMES)) { // 0x88; MI status response to 0x09 - miStsDecode(iv, p); - } - - else if (p->packet[0] == (0x11 + SINGLE_FRAME)) { // 0x92; MI status response to 0x11 - miStsDecode(iv, p, CH2); - } - - else if ( p->packet[0] == 0x09 + ALL_FRAMES || - p->packet[0] == 0x11 + ALL_FRAMES || - ( p->packet[0] >= (0x36 + ALL_FRAMES) && p->packet[0] < (0x39 + SINGLE_FRAME) ) ) { // small MI or MI 1500 data responses to 0x09, 0x11, 0x36, 0x37, 0x38 and 0x39 - mPayload[iv->id].txId = p->packet[0]; - miDataDecode(iv,p); - } - - else if (p->packet[0] == ( 0x0f + ALL_FRAMES)) { - // MI response from get hardware information request - record_t<> *rec = iv->getRecordStruct(InverterDevInform_All); // choose the record structure - rec->ts = mPayload[iv->id].ts; - mPayload[iv->id].gotFragment = true; - -/* - Polling the device software and hardware version number command - start byte Command word routing address target address User data check end byte - byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7] byte[8] byte[9] byte[10] byte[11] byte[12] - 0x7e 0x0f xx xx xx xx YY YY YY YY 0x00 CRC 0x7f - Command Receipt - First Frame - start byte Command word target address routing address Multi-frame marking User data User data User data User data User data User data User data User data User data User data User data User data User data User data User data User data check end byte - byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7] byte[8] byte[9] byte[10] byte[11] byte[12] byte[13] byte[14] byte[15] byte[16] byte[17] byte[18] byte[19] byte[20] byte[21] byte[22] byte[23] byte[24] byte[25] byte[26] byte[27] byte[28] - 0x7e 0x8f YY YY YY YY xx xx xx xx 0x00 USFWBuild_VER APPFWBuild_VER APPFWBuild_YYYY APPFWBuild_MMDD APPFWBuild_HHMM APPFW_PN HW_VER CRC 0x7f - Command Receipt - Second Frame - start byte Command word target address routing address Multi-frame marking User data User data User data User data User data User data User data User data User data User data User data User data User data User data User data User data check end byte - byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7] byte[8] byte[9] byte[10] byte[11] byte[12] byte[13] byte[14] byte[15] byte[16] byte[17] byte[18] byte[19] byte[20] byte[21] byte[22] byte[23] byte[24] byte[25] byte[26] byte[27] byte[28] - 0x7e 0x8f YY YY YY YY xx xx xx xx 0x01 HW_PN HW_FB_TLmValue HW_FB_ReSPRT HW_GridSamp_ResValule HW_ECapValue Matching_APPFW_PN CRC 0x7f - Command receipt - third frame - start byte Command word target address routing address Multi-frame marking User data User data User data User data User data User data User data User data check end byte - byte[0] byte[1] byte[2] byte[3] byte[4] byte[5] byte[6] byte[7] byte[8] byte[9] byte[10] byte[11] byte[12] byte[13] byte[14] byte[15] byte[16] byte[15] byte[16] byte[17] byte[18] - 0x7e 0x8f YY YY YY YY xx xx xx xx 0x12 APPFW_MINVER HWInfoAddr PNInfoCRC_gusv PNInfoCRC_gusv CRC 0x7f -*/ - -/* -case InverterDevInform_All: - rec->length = (uint8_t)(HMINFO_LIST_LEN); - rec->assign = (byteAssign_t *)InfoAssignment; - rec->pyldLen = HMINFO_PAYLOAD_LEN; - break; -const byteAssign_t InfoAssignment[] = { - { FLD_FW_VERSION, UNIT_NONE, CH0, 0, 2, 1 }, - { FLD_FW_BUILD_YEAR, UNIT_NONE, CH0, 2, 2, 1 }, - { FLD_FW_BUILD_MONTH_DAY, UNIT_NONE, CH0, 4, 2, 1 }, - { FLD_FW_BUILD_HOUR_MINUTE, UNIT_NONE, CH0, 6, 2, 1 }, - { FLD_HW_ID, UNIT_NONE, CH0, 8, 2, 1 } -}; -*/ - - if ( p->packet[9] == 0x00 ) {//first frame - //FLD_FW_VERSION - for (uint8_t i = 0; i < 5; i++) { - iv->setValue(i, rec, (float) ((p->packet[(12+2*i)] << 8) + p->packet[(13+2*i)])/1); - } - /*iv->setQueuedCmdFinished(); - mStat->rxSuccess++; - mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x01, false);*/ - } else if ( p->packet[9] == 0x01 ) {//second frame - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINTLN(F("got 2nd frame (hw info)")); - //mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x12, false); - } else if ( p->packet[9] == 0x12 ) {//3rd frame - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINTLN(F("got 3rd frame (hw info)")); - iv->setQueuedCmdFinished(); - mStat->rxSuccess++; - } - - } else if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command - // atm, we just do nothing else than print out what we got... - // for decoding see xls- Data collection instructions - #147ff - mPayload[iv->id].txId = p->packet[0]; - DPRINTLN(DBG_DEBUG, F("Response from info request received")); - uint8_t *pid = &p->packet[9]; - if (*pid == 0x00) { - DPRINT(DBG_DEBUG, F("fragment number zero received")); - - iv->setQueuedCmdFinished(); - } //else { - DPRINTLN(DBG_DEBUG, "PID: 0x" + String(*pid, HEX)); - /* - if ((*pid & 0x7F) < MAX_PAYLOAD_ENTRIES) { - memcpy(mPayload[iv->id].data[(*pid & 0x7F) - 1], &p->packet[10], p->len - 11); - mPayload[iv->id].len[(*pid & 0x7F) - 1] = p->len - 11; - mPayload[iv->id].gotFragment = true; - } - if ((*pid & ALL_FRAMES) == ALL_FRAMES) { - // Last packet - if (((*pid & 0x7f) > mPayload[iv->id].maxPackId) || (MAX_PAYLOAD_ENTRIES == mPayload[iv->id].maxPackId)) { - mPayload[iv->id].maxPackId = (*pid & 0x7f); - if (*pid > 0x81) - mPayload[iv->id].lastFound = true; - } - } - } - } */ - } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command - miDPRINTHead(DBG_DEBUG, iv->id); - DBGPRINTLN(F("Response from devcontrol request received")); - - mPayload[iv->id].txId = p->packet[0]; - iv->clearDevControlRequest(); - - if ((p->packet[12] == ActivePowerContr) && (p->packet[13] == 0x00)) { - String msg = ""; - if((p->packet[10] == 0x00) && (p->packet[11] == 0x00)) - mApp->setMqttPowerLimitAck(iv); - else - msg = "NOT "; - //DPRINTLN(DBG_INFO, F("Inverter ") + String(iv->id) + F(" has ") + msg + F("accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1])); - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINTLN(F("has ") + msg + F("accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1])); - - iv->clearCmdQueue(); - iv->enqueCommand(SystemConfigPara); // read back power limit - } - iv->devControlCmd = Init; - } else { // some other response; copied from hmPayload:process; might not be correct to do that here!!! - DPRINTLN(DBG_INFO, F("procPyld: cmd: 0x") + String(mPayload[iv->id].txCmd, HEX)); - DPRINTLN(DBG_INFO, F("procPyld: txid: 0x") + String(mPayload[iv->id].txId, HEX)); - //DPRINTLN(DBG_DEBUG, F("procPyld: max: ") + String(mPayload[iv->id].maxPackId)); - record_t<> *rec = iv->getRecordStruct(mPayload[iv->id].txCmd); // choose the parser - mPayload[iv->id].complete = true; - - uint8_t payload[128]; - uint8_t payloadLen = 0; - - memset(payload, 0, 128); - - /*for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId); i++) { - memcpy(&payload[payloadLen], mPayload[iv->id].data[i], (mPayload[iv->id].len[i])); - payloadLen += (mPayload[iv->id].len[i]); - yield(); - }*/ - payloadLen -= 2; - - if (mSerialDebug) { - DPRINT(DBG_INFO, F("Payload (") + String(payloadLen) + "): "); - mSys->Radio.dumpBuf(payload, payloadLen); - } - - if (NULL == rec) { - DPRINTLN(DBG_ERROR, F("record is NULL!")); - } else if ((rec->pyldLen == payloadLen) || (0 == rec->pyldLen)) { - if (mPayload[iv->id].txId == (TX_REQ_INFO + ALL_FRAMES)) - mStat->rxSuccess++; - - rec->ts = mPayload[iv->id].ts; - for (uint8_t i = 0; i < rec->length; i++) { - iv->addValue(i, payload, rec); - yield(); - } - iv->doCalculations(); - notify(mPayload[iv->id].txCmd); - - if(AlarmData == mPayload[iv->id].txCmd) { - uint8_t i = 0; - uint16_t code; - uint32_t start, end; - while(1) { - code = iv->parseAlarmLog(i++, payload, payloadLen, &start, &end); - if(0 == code) - break; - if (NULL != mCbMiAlarm) - (mCbMiAlarm)(code, start, end); - yield(); - } - } - } else { - DPRINTLN(DBG_ERROR, F("plausibility check failed, expected ") + String(rec->pyldLen) + F(" bytes")); - mStat->rxFail++; - } - - iv->setQueuedCmdFinished(); - } - } - - void process(bool retransmit) { - for (uint8_t id = 0; id < mSys->getNumInverters(); id++) { - Inverter<> *iv = mSys->getInverterByPos(id); - if (NULL == iv) - continue; // skip to next inverter - - if (IV_HM == iv->ivGen) // only process MI inverters - continue; // skip to next inverter - - if ( !mPayload[iv->id].complete && - (mPayload[iv->id].txId != (TX_REQ_INFO + ALL_FRAMES)) && - (mPayload[iv->id].txId < (0x36 + ALL_FRAMES)) && - (mPayload[iv->id].txId > (0x39 + ALL_FRAMES)) && - (mPayload[iv->id].txId != (0x09 + ALL_FRAMES)) && - (mPayload[iv->id].txId != (0x11 + ALL_FRAMES)) && - (mPayload[iv->id].txId != (0x88)) && - (mPayload[iv->id].txId != (0x92)) && - (mPayload[iv->id].txId != 0 )) { - // no processing needed if txId is not one of 0x95, 0x88, 0x89, 0x91, 0x92 or resonse to 0x36ff - mPayload[iv->id].complete = true; - continue; // skip to next inverter - } - - //delayed next message? - //mPayload[iv->id].skipfirstrepeat++; - if (mPayload[iv->id].skipfirstrepeat) { - mPayload[iv->id].skipfirstrepeat = 0; //reset counter*/ - continue; // skip to next inverter - } - - if (!mPayload[iv->id].complete) { - //DPRINTLN(DBG_INFO, F("Pyld incompl code")); //info for testing only - bool crcPass, pyldComplete; - crcPass = build(iv->id, &pyldComplete); - if (!crcPass && !pyldComplete) { // payload not complete - if ((mPayload[iv->id].requested) && (retransmit)) { - if (iv->devControlCmd == Restart || iv->devControlCmd == CleanState_LockAndAlarm) { - // This is required to prevent retransmissions without answer. - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINTLN(F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); - mPayload[iv->id].retransmits = mMaxRetrans; - } else if(iv->devControlCmd == ActivePowerContr) { - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINTLN(F("retransmit power limit")); - mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true); - } else { - uint8_t cmd = mPayload[iv->id].txCmd; - if (mPayload[iv->id].retransmits < mMaxRetrans) { - mPayload[iv->id].retransmits++; - if( !mPayload[iv->id].gotFragment ) { - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINTLN(F("nothing received")); - mPayload[iv->id].retransmits = mMaxRetrans; - } else if ( cmd == 0x0f ) { - //hard/firmware request - mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x00, true); - //iv->setQueuedCmdFinished(); - //cmd = iv->getQueuedCmd(); - } else { - bool change = false; - if ( cmd >= 0x36 && cmd < 0x39 ) { // MI-1500 Data command - cmd++; // just request the next channel - change = true; - } else if ( cmd == 0x09 ) {//MI single or dual channel device - if ( mPayload[iv->id].dataAB[CH1] && iv->type == INV_TYPE_2CH ) { - if (!mPayload[iv->id].stsAB[CH1] && mPayload[iv->id].retransmits<2) {} - //first try to get missing sts for first channel a second time - else if (!mPayload[iv->id].stsAB[CH2] || !mPayload[iv->id].dataAB[CH2] ) { - cmd = 0x11; - change = true; - mPayload[iv->id].retransmits = 0; //reset counter - } - } - } else if ( cmd == 0x11) { - if ( mPayload[iv->id].dataAB[CH2] ) { // data + status ch2 are there? - if (mPayload[iv->id].stsAB[CH2] && (!mPayload[iv->id].stsAB[CH1] || !mPayload[iv->id].dataAB[CH1])) { - cmd = 0x09; - change = true; - } - } - } - miDPRINTHead(DBG_INFO, iv->id); - if (change) { - DBGPRINT(F("next request is 0x")); - } else { - DBGPRINT(F("not complete: Request Retransmit 0x")); - } - DBGPRINTLN(String(cmd, HEX)); - //mSys->Radio.sendCmdPacket(iv->radioId.u64, cmd, cmd, true); - mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex, true, cmd); - mPayload[iv->id].txCmd = cmd; - yield(); - } - } - } - } - } else if(!crcPass && pyldComplete) { // crc error on complete Payload - if (mPayload[iv->id].retransmits < mMaxRetrans) { - mPayload[iv->id].retransmits++; - miDPRINTHead(DBG_WARN, iv->id); - DBGPRINTLN(F("CRC Error: Request Complete Retransmit")); - mPayload[iv->id].txCmd = iv->getQueuedCmd(); - miDPRINTHead(DBG_INFO, iv->id); - - DBGPRINTLN(F("prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX)); - mSys->Radio.prepareDevInformCmd(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); - } - } - /*else { // payload complete - //This tree is not really tested, most likely it's not truly complete.... - DPRINTLN(DBG_INFO, F("procPyld: cmd: 0x") + String(mPayload[iv->id].txCmd, HEX)); - DPRINTLN(DBG_INFO, F("procPyld: txid: 0x") + String(mPayload[iv->id].txId, HEX)); - //DPRINTLN(DBG_DEBUG, F("procPyld: max: ") + String(mPayload[iv->id].maxPackId)); - //record_t<> *rec = iv->getRecordStruct(mPayload[iv->id].txCmd); // choose the parser - mPayload[iv->id].complete = true; - uint8_t ac_pow = 0; - //if (mPayload[iv->id].sts[0] == 3) { - ac_pow = calcPowerDcCh0(iv, 0)*9.5; - //} - record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); // choose the parser - iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) (ac_pow/10)); - DPRINTLN(DBG_INFO, F("process: compl. set of msgs detected")); - iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0)); - iv->doCalculations(); - //uint8_t payload[128]; - //uint8_t payloadLen = 0; - //memset(payload, 0, 128); - //for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId); i++) { - // memcpy(&payload[payloadLen], mPayload[iv->id].data[i], (mPayload[iv->id].len[i])); - // payloadLen += (mPayload[iv->id].len[i]); - // yield(); - //} - //payloadLen -= 2; - //if (mSerialDebug) { - // DPRINT(DBG_INFO, F("Payload (") + String(payloadLen) + "): "); - // mSys->Radio.dumpBuf(payload, payloadLen); - //} - //if (NULL == rec) { - // DPRINTLN(DBG_ERROR, F("record is NULL!")); - //} else if ((rec->pyldLen == payloadLen) || (0 == rec->pyldLen)) { - // if (mPayload[iv->id].txId == (TX_REQ_INFO + ALL_FRAMES)) - // mStat->rxSuccess++; - // rec->ts = mPayload[iv->id].ts; - // for (uint8_t i = 0; i < rec->length; i++) { - // iv->addValue(i, payload, rec); - // yield(); - // } - // iv->doCalculations(); - // notify(mPayload[iv->id].txCmd); - // if(AlarmData == mPayload[iv->id].txCmd) { - // uint8_t i = 0; - // uint16_t code; - // uint32_t start, end; - // while(1) { - // code = iv->parseAlarmLog(i++, payload, payloadLen, &start, &end); - // if(0 == code) - // break; - // if (NULL != mCbAlarm) - // (mCbAlarm)(code, start, end); - // yield(); - // } - // } - //} else { - // DPRINTLN(DBG_ERROR, F("plausibility check failed, expected ") + String(rec->pyldLen) + F(" bytes")); - // mStat->rxFail++; - //} - //iv->setQueuedCmdFinished(); - //}*/ - } - yield(); - } - } - - private: - void notify(uint8_t val) { - if(NULL != mCbMiPayload) - (mCbMiPayload)(val); - } - - void miStsDecode(Inverter<> *iv, packet_t *p, uint8_t stschan = CH1) { - //DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") status msg 0x") + String(p->packet[0], HEX)); - record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); // choose the record structure - rec->ts = mPayload[iv->id].ts; - mPayload[iv->id].gotFragment = true; - mPayload[iv->id].txId = p->packet[0]; - - //uint8_t status = (p->packet[11] << 8) + p->packet[12]; - uint8_t status = (p->packet[9] << 8) + p->packet[10]; - //uint8_t stschan = p->packet[0] == 0x88 ? CH1 : CH2; - mPayload[iv->id].sts[stschan] = status; - mPayload[iv->id].stsAB[stschan] = true; - if (mPayload[iv->id].stsAB[CH1] && mPayload[iv->id].stsAB[CH2]) - mPayload[iv->id].stsAB[CH0] = true; - if ( !mPayload[iv->id].sts[0] || status < mPayload[iv->id].sts[0]) { - mPayload[iv->id].sts[0] = status; - iv->setValue(iv->getPosByChFld(0, FLD_EVT, rec), rec, status); - } - - if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){ - iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]; // seems there's no status per channel in 3rd gen. models?!? - - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINTLN(F("alarm ID incremented to ") + String(iv->alarmMesIndex)); - iv->enqueCommand(AlarmData); - } - //mPayload[iv->id].skipfirstrepeat = 1; - if (mPayload[iv->id].stsAB[CH0] && mPayload[iv->id].dataAB[CH0] && !mPayload[iv->id].complete) { - miComplete(iv); - } - } - - void miDataDecode(Inverter<> *iv, packet_t *p) { - record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); // choose the parser - rec->ts = mPayload[iv->id].ts; - mPayload[iv->id].gotFragment = true; - - uint8_t datachan = ( p->packet[0] == 0x89 || p->packet[0] == (0x36 + ALL_FRAMES) ) ? CH1 : - ( p->packet[0] == 0x91 || p->packet[0] == (0x37 + ALL_FRAMES) ) ? CH2 : - p->packet[0] == (0x38 + ALL_FRAMES) ? CH3 : - CH4; - //DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") data msg 0x") + String(p->packet[0], HEX) + F(" channel ") + datachan); - // count in RF_communication_protocol.xlsx is with offset = -1 - iv->setValue(iv->getPosByChFld(datachan, FLD_UDC, rec), rec, (float)((p->packet[9] << 8) + p->packet[10])/10); - yield(); - iv->setValue(iv->getPosByChFld(datachan, FLD_IDC, rec), rec, (float)((p->packet[11] << 8) + p->packet[12])/10); - yield(); - iv->setValue(iv->getPosByChFld(0, FLD_UAC, rec), rec, (float)((p->packet[13] << 8) + p->packet[14])/10); - yield(); - iv->setValue(iv->getPosByChFld(0, FLD_F, rec), rec, (float) ((p->packet[15] << 8) + p->packet[16])/100); - iv->setValue(iv->getPosByChFld(datachan, FLD_PDC, rec), rec, (float)((p->packet[17] << 8) + p->packet[18])/10); - yield(); - iv->setValue(iv->getPosByChFld(datachan, FLD_YD, rec), rec, (float)((p->packet[19] << 8) + p->packet[20])/1); - yield(); - iv->setValue(iv->getPosByChFld(0, FLD_T, rec), rec, (float) ((int16_t)(p->packet[21] << 8) + p->packet[22])/10); - iv->setValue(iv->getPosByChFld(0, FLD_IRR, rec), rec, (float) (calcIrradiation(iv, datachan))); - //AC Power is missing; we may have to calculate, as no respective data is in payload - - if ( datachan < 3 ) { - mPayload[iv->id].dataAB[datachan] = true; - } - if ( !mPayload[iv->id].dataAB[CH0] && mPayload[iv->id].dataAB[CH2] && mPayload[iv->id].dataAB[CH2] ) { - mPayload[iv->id].dataAB[CH0] = true; - } - - if (p->packet[0] >= (0x36 + ALL_FRAMES) ) { - - /*For MI1500: - if (MI1500) { - STAT = (uint8_t)(p->packet[25] ); - FCNT = (uint8_t)(p->packet[26]); - FCODE = (uint8_t)(p->packet[27]); - }*/ - - uint8_t status = (uint8_t)(p->packet[23]); - mPayload[iv->id].sts[datachan] = status; - if ( !mPayload[iv->id].sts[0] || status < mPayload[iv->id].sts[0]) { - mPayload[iv->id].sts[0] = status; - iv->setValue(iv->getPosByChFld(0, FLD_EVT, rec), rec, status); - } - - if (p->packet[0] < (0x39 + ALL_FRAMES) ) { - /*uint8_t cmd = p->packet[0] - ALL_FRAMES + 1; - mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex, false, cmd); - mPayload[iv->id].txCmd = cmd;*/ - mPayload[iv->id].complete = false; - } - - else if (p->packet[0] == (0x39 + ALL_FRAMES) ) { - /*uint8_t cmd = p->packet[0] - ALL_FRAMES + 1; - mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex, false, cmd); - mPayload[iv->id].txCmd = cmd;*/ - mPayload[iv->id].complete = true; - } - - //iv->setValue(iv->getPosByChFld(0, FLD_EVT, rec), rec, calcMiSts(iv));yield(); - if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){ - iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]; - - miDPRINTHead(DBG_INFO, iv->id); - DBGPRINTLN(F("alarm ID incremented to ") + String(iv->alarmMesIndex)); - //iv->enqueCommand(AlarmData); - } - - } - - if ( mPayload[iv->id].complete || //4ch device - (iv->type != INV_TYPE_4CH //other devices - && mPayload[iv->id].dataAB[CH0] - && mPayload[iv->id].stsAB[CH0])) { - miComplete(iv); - } - - - -/* - if(AlarmData == mPayload[iv->id].txCmd) { - uint8_t i = 0; - uint16_t code; - uint32_t start, end; - while(1) { - code = iv->parseAlarmLog(i++, payload, payloadLen, &start, &end); - if(0 == code) - break; - if (NULL != mCbMiAlarm) - (mCbAlarm)(code, start, end); - yield(); - } - }*/ - } - - void miComplete(Inverter<> *iv) { - mPayload[iv->id].complete = true; // For 2 CH devices, this might be too short... - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") got all msgs")); - record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); - iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0)); - - //preliminary AC calculation... - float ac_pow = 0; - for(uint8_t i = 1; i <= iv->channels; i++) { - if (mPayload[iv->id].sts[i] == 3) { - uint8_t pos = iv->getPosByChFld(i, FLD_PDC, rec); - ac_pow += iv->getValue(pos, rec); - } - } - ac_pow = (int) (ac_pow*9.5); - iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) ac_pow/10); - - iv->doCalculations(); - iv->setQueuedCmdFinished(); - mStat->rxSuccess++; - yield(); - notify(mPayload[iv->id].txCmd); - } - - bool build(uint8_t id, bool *complete) { - DPRINTLN(DBG_VERBOSE, F("build")); - /*uint16_t crc = 0xffff, crcRcv = 0x0000; - if (mPayload[id].maxPackId > MAX_PAYLOAD_ENTRIES) - mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; - */ - // check if all messages are there - - *complete = mPayload[id].complete; - uint8_t txCmd = mPayload[id].txCmd; - //uint8_t cmd = getQueuedCmd(); - if(!*complete) { - DPRINTLN(DBG_VERBOSE, F("incomlete, txCmd is 0x") + String(txCmd, HEX)); // + F("cmd is 0x") + String(cmd, HEX)); - if (txCmd == 0x09 || txCmd == 0x11 || (txCmd >= 0x36 && txCmd <= 0x39)) - return false; - } - - /*for (uint8_t i = 0; i < mPayload[id].maxPackId; i++) { - if (mPayload[id].len[i] > 0) { - if (i == (mPayload[id].maxPackId - 1)) { - crc = ah::crc16(mPayload[id].data[i], mPayload[id].len[i] - 2, crc); - crcRcv = (mPayload[id].data[i][mPayload[id].len[i] - 2] << 8) | (mPayload[id].data[i][mPayload[id].len[i] - 1]); - } else - crc = ah::crc16(mPayload[id].data[i], mPayload[id].len[i], crc); - } - yield(); - } - return (crc == crcRcv) ? true : false;*/ - return true; - } - - void miDPRINTHead(uint8_t lvl, uint8_t id) { - DPRINT(lvl, F("(#")); - DBGPRINT(String(id)); - DBGPRINT(F(") ")); - } - - void reset(uint8_t id) { - //DPRINTLN(DBG_INFO, F("resetPayload: id: ") + String(id)); - miDPRINTHead(DBG_INFO, id); - DBGPRINTLN(F("resetPayload")); - memset(mPayload[id].len, 0, MAX_PAYLOAD_ENTRIES); - mPayload[id].gotFragment = false; - /*mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; - mPayload[id].lastFound = false;*/ - mPayload[id].retransmits = 0; - mPayload[id].complete = false; - mPayload[id].dataAB[CH0] = true; //required for 1CH and 2CH devices - mPayload[id].dataAB[CH1] = true; //required for 1CH and 2CH devices - mPayload[id].dataAB[CH2] = true; //only required for 2CH devices - mPayload[id].stsAB[CH0] = true; //required for 1CH and 2CH devices - mPayload[id].stsAB[CH1] = true; //required for 1CH and 2CH devices - mPayload[id].stsAB[CH2] = true; //only required for 2CH devices - mPayload[id].txCmd = 0; - mPayload[id].skipfirstrepeat = 0; - mPayload[id].requested = false; - mPayload[id].ts = *mTimestamp; - mPayload[id].sts[0] = 0; - mPayload[id].sts[CH1] = 0; - mPayload[id].sts[CH2] = 0; - mPayload[id].sts[CH3] = 0; - mPayload[id].sts[CH4] = 0; - } - - - - IApp *mApp; - HMSYSTEM *mSys; - statistics_t *mStat; - uint8_t mMaxRetrans; - uint32_t *mTimestamp; - miPayload_t mPayload[MAX_NUM_INVERTERS]; - bool mSerialDebug; - - Inverter<> *mHighPrioIv; - alarmListenerType mCbMiAlarm; - payloadListenerType mCbMiPayload; -}; - -#endif /*__MI_PAYLOAD_H__*/ From 95420e35de44492a8c7d0bf944b252519f70719d Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 16 Mar 2023 16:50:37 +0100 Subject: [PATCH 20/52] Delete hmRadio.h wrong place... --- hmRadio.h | 335 ------------------------------------------------------ 1 file changed, 335 deletions(-) delete mode 100644 hmRadio.h diff --git a/hmRadio.h b/hmRadio.h deleted file mode 100644 index 8f528784..00000000 --- a/hmRadio.h +++ /dev/null @@ -1,335 +0,0 @@ -//----------------------------------------------------------------------------- -// 2023 Ahoy, https://github.com/lumpapu/ahoy -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ -//----------------------------------------------------------------------------- - -#ifndef __RADIO_H__ -#define __RADIO_H__ - -#include "../utils/dbg.h" -#include -#include "../utils/crc.h" -#include "../config/config.h" - -#define SPI_SPEED 1000000 - -#define RF_CHANNELS 5 - -#define TX_REQ_INFO 0x15 -#define TX_REQ_DEVCONTROL 0x51 -#define ALL_FRAMES 0x80 -#define SINGLE_FRAME 0x81 - -const char* const rf24AmpPowerNames[] = {"MIN", "LOW", "HIGH", "MAX"}; - - -//----------------------------------------------------------------------------- -// MACROS -//----------------------------------------------------------------------------- -#define CP_U32_LittleEndian(buf, v) ({ \ - uint8_t *b = buf; \ - b[0] = ((v >> 24) & 0xff); \ - b[1] = ((v >> 16) & 0xff); \ - b[2] = ((v >> 8) & 0xff); \ - b[3] = ((v ) & 0xff); \ -}) - -#define CP_U32_BigEndian(buf, v) ({ \ - uint8_t *b = buf; \ - b[3] = ((v >> 24) & 0xff); \ - b[2] = ((v >> 16) & 0xff); \ - b[1] = ((v >> 8) & 0xff); \ - b[0] = ((v ) & 0xff); \ -}) - -#define BIT_CNT(x) ((x)<<3) - -//----------------------------------------------------------------------------- -// HM Radio class -//----------------------------------------------------------------------------- -template -class HmRadio { - public: - HmRadio() : mNrf24(CE_PIN, CS_PIN, SPI_SPEED) { - DPRINT(DBG_VERBOSE, F("hmRadio.h : HmRadio():mNrf24(CE_PIN: ")); - DPRINT(DBG_VERBOSE, String(CE_PIN)); - DPRINT(DBG_VERBOSE, F(", CS_PIN: ")); - DPRINT(DBG_VERBOSE, String(CS_PIN)); - DPRINT(DBG_VERBOSE, F(", SPI_SPEED: ")); - DPRINTLN(DBG_VERBOSE, String(SPI_SPEED) + ")"); - - // Depending on the program, the module can work on 2403, 2423, 2440, 2461 or 2475MHz. - // Channel List 2403, 2423, 2440, 2461, 2475MHz - mRfChLst[0] = 03; - mRfChLst[1] = 23; - mRfChLst[2] = 40; - mRfChLst[3] = 61; - mRfChLst[4] = 75; - - // default channels - mTxChIdx = 2; // Start TX with 40 - mRxChIdx = 0; // Start RX with 03 - - mSendCnt = 0; - mRetransmits = 0; - - mSerialDebug = false; - mIrqRcvd = false; - } - ~HmRadio() {} - - void setup(uint8_t ampPwr = RF24_PA_LOW, uint8_t irq = IRQ_PIN, uint8_t ce = CE_PIN, uint8_t cs = CS_PIN) { - DPRINTLN(DBG_VERBOSE, F("hmRadio.h:setup")); - pinMode(irq, INPUT_PULLUP); - - uint32_t dtuSn = 0x87654321; - uint32_t chipID = 0; // will be filled with last 3 bytes of MAC - #ifdef ESP32 - uint64_t MAC = ESP.getEfuseMac(); - chipID = ((MAC >> 8) & 0xFF0000) | ((MAC >> 24) & 0xFF00) | ((MAC >> 40) & 0xFF); - #else - chipID = ESP.getChipId(); - #endif - if(chipID) { - dtuSn = 0x80000000; // the first digit is an 8 for DTU production year 2022, the rest is filled with the ESP chipID in decimal - for(int i = 0; i < 7; i++) { - dtuSn |= (chipID % 10) << (i * 4); - chipID /= 10; - } - } - // change the byte order of the DTU serial number and append the required 0x01 at the end - DTU_RADIO_ID = ((uint64_t)(((dtuSn >> 24) & 0xFF) | ((dtuSn >> 8) & 0xFF00) | ((dtuSn << 8) & 0xFF0000) | ((dtuSn << 24) & 0xFF000000)) << 8) | 0x01; - - mNrf24.begin(ce, cs); - mNrf24.setRetries(3, 15); // 3*250us + 250us and 15 loops -> 15ms - - mNrf24.setChannel(mRfChLst[mRxChIdx]); - mNrf24.startListening(); - mNrf24.setDataRate(RF24_250KBPS); - mNrf24.setAutoAck(true); - mNrf24.enableDynamicPayloads(); - mNrf24.setCRCLength(RF24_CRC_16); - mNrf24.setAddressWidth(5); - mNrf24.openReadingPipe(1, DTU_RADIO_ID); - - // enable all receiving interrupts - mNrf24.maskIRQ(false, false, false); - - DPRINT(DBG_INFO, F("RF24 Amp Pwr: RF24_PA_")); - DPRINTLN(DBG_INFO, String(rf24AmpPowerNames[ampPwr])); - mNrf24.setPALevel(ampPwr & 0x03); - - if(mNrf24.isChipConnected()) { - DPRINTLN(DBG_INFO, F("Radio Config:")); - mNrf24.printPrettyDetails(); - } - else - DPRINTLN(DBG_WARN, F("WARNING! your NRF24 module can't be reached, check the wiring")); - } - - bool loop(void) { - if (!mIrqRcvd) - return false; // nothing to do - mIrqRcvd = false; - bool tx_ok, tx_fail, rx_ready; - mNrf24.whatHappened(tx_ok, tx_fail, rx_ready); // resets the IRQ pin to HIGH - mNrf24.flush_tx(); // empty TX FIFO - //DBGPRINTLN("TX whatHappened Ch" + String(mRfChLst[mTxChIdx]) + " " + String(tx_ok) + String(tx_fail) + String(rx_ready)); - - // start listening on the default RX channel - mRxChIdx = 0; - mNrf24.setChannel(mRfChLst[mRxChIdx]); - mNrf24.startListening(); - - //uint32_t debug_ms = millis(); - uint16_t cnt = 300; // that is 60 times 5 channels - while (0 < cnt--) { - uint32_t startMillis = millis(); - while (millis()-startMillis < 4) { // listen 4ms to each channel - if (mIrqRcvd) { - mIrqRcvd = false; - if (getReceived()) { // everything received - //DBGPRINTLN("RX finished Cnt: " + String(300-cnt) + " time used: " + String(millis()-debug_ms)+ " ms"); - return true; - } - } - yield(); - } - switchRxCh(); // switch to next RX channel - yield(); - } - // not finished but time is over - //DBGPRINTLN("RX not finished: 300 time used: " + String(millis()-debug_ms)+ " ms"); - return true; - } - - void handleIntr(void) { - mIrqRcvd = true; - } - - bool isChipConnected(void) { - //DPRINTLN(DBG_VERBOSE, F("hmRadio.h:isChipConnected")); - return mNrf24.isChipConnected(); - } - void enableDebug() { - mSerialDebug = true; - } - - void sendControlPacket(uint64_t invId, uint8_t cmd, uint16_t *data, bool isRetransmit) { - DPRINT(DBG_INFO, F("sendControlPacket cmd: 0x")); - DBGPRINTLN(String(cmd, HEX)); - initPacket(invId, TX_REQ_DEVCONTROL, SINGLE_FRAME); - uint8_t cnt = 10; - mTxBuf[cnt++] = cmd; // cmd -> 0 on, 1 off, 2 restart, 11 active power, 12 reactive power, 13 power factor - mTxBuf[cnt++] = 0x00; - if(cmd >= ActivePowerContr && cmd <= PFSet) { // ActivePowerContr, ReactivePowerContr, PFSet - mTxBuf[cnt++] = ((data[0] * 10) >> 8) & 0xff; // power limit - mTxBuf[cnt++] = ((data[0] * 10) ) & 0xff; // power limit - mTxBuf[cnt++] = ((data[1] ) >> 8) & 0xff; // setting for persistens handlings - mTxBuf[cnt++] = ((data[1] ) ) & 0xff; // setting for persistens handling - } - sendPacket(invId, cnt, isRetransmit, true); - } - - void prepareDevInformCmd(uint64_t invId, uint8_t cmd, uint32_t ts, uint16_t alarmMesId, bool isRetransmit, uint8_t reqfld=TX_REQ_INFO) { // might not be necessary to add additional arg. - DPRINTLN(DBG_DEBUG, F("prepareDevInformCmd 0x") + String(cmd, HEX)); - initPacket(invId, reqfld, ALL_FRAMES); - mTxBuf[10] = cmd; // cid - mTxBuf[11] = 0x00; - CP_U32_LittleEndian(&mTxBuf[12], ts); - if (cmd == RealTimeRunData_Debug || cmd == AlarmData ) { - mTxBuf[18] = (alarmMesId >> 8) & 0xff; - mTxBuf[19] = (alarmMesId ) & 0xff; - } - sendPacket(invId, 24, isRetransmit, true); - } - - void sendCmdPacket(uint64_t invId, uint8_t mid, uint8_t pid, bool isRetransmit) { - initPacket(invId, mid, pid); - sendPacket(invId, 10, isRetransmit, false); - } - - void dumpBuf(uint8_t buf[], uint8_t len) { - //DPRINTLN(DBG_VERBOSE, F("hmRadio.h:dumpBuf")); - for(uint8_t i = 0; i < len; i++) { - DHEX(buf[i]); - DBGPRINT(" "); - } - DBGPRINTLN(""); - } - - uint8_t getDataRate(void) { - if(!mNrf24.isChipConnected()) - return 3; // unkown - return mNrf24.getDataRate(); - } - - bool isPVariant(void) { - return mNrf24.isPVariant(); - } - - std::queue mBufCtrl; - - uint32_t mSendCnt; - uint32_t mRetransmits; - - bool mSerialDebug; - - private: - bool getReceived(void) { - bool tx_ok, tx_fail, rx_ready; - mNrf24.whatHappened(tx_ok, tx_fail, rx_ready); // resets the IRQ pin to HIGH - //DBGPRINTLN("RX whatHappened Ch" + String(mRfChLst[mRxChIdx]) + " " + String(tx_ok) + String(tx_fail) + String(rx_ready)); - - bool isLastPackage = false; - while(mNrf24.available()) { - uint8_t len; - len = mNrf24.getDynamicPayloadSize(); // if payload size > 32, corrupt payload has been flushed - if (len > 0) { - packet_t p; - p.ch = mRfChLst[mRxChIdx]; - p.len = len; - mNrf24.read(p.packet, len); - mBufCtrl.push(p); - if (p.packet[0] == (TX_REQ_INFO + ALL_FRAMES)) // response from get information command - isLastPackage = (p.packet[9] > 0x81); // > 0x81 indicates last packet received - else if (p.packet[0] == ( 0x0f + ALL_FRAMES) ) // response from MI get information command - isLastPackage = (p.packet[9] > 0x11); // > 0x11 indicates last packet received - else if (p.packet[0] != 0x00 && p.packet[0] != 0x88 && p.packet[0] != 0x92) - // ignore fragment number zero and MI status messages - isLastPackage = true; // response from dev control command - yield(); - } - } - return isLastPackage; - } - - void switchRxCh() { - mNrf24.stopListening(); - // get next channel index - if(++mRxChIdx >= RF_CHANNELS) - mRxChIdx = 0; - mNrf24.setChannel(mRfChLst[mRxChIdx]); - mNrf24.startListening(); - } - - void initPacket(uint64_t invId, uint8_t mid, uint8_t pid) { - DPRINTLN(DBG_VERBOSE, F("initPacket, mid: ") + String(mid, HEX) + F(" pid: ") + String(pid, HEX)); - memset(mTxBuf, 0, MAX_RF_PAYLOAD_SIZE); - mTxBuf[0] = mid; // message id - CP_U32_BigEndian(&mTxBuf[1], (invId >> 8)); - CP_U32_BigEndian(&mTxBuf[5], (DTU_RADIO_ID >> 8)); - mTxBuf[9] = pid; - } - - void sendPacket(uint64_t invId, uint8_t len, bool isRetransmit, bool clear=false) { - //DPRINTLN(DBG_VERBOSE, F("hmRadio.h:sendPacket")); - //DPRINTLN(DBG_VERBOSE, "sent packet: #" + String(mSendCnt)); - - // append crc's - if (len > 10) { - // crc control data - uint16_t crc = ah::crc16(&mTxBuf[10], len - 10); - mTxBuf[len++] = (crc >> 8) & 0xff; - mTxBuf[len++] = (crc ) & 0xff; - } - // crc over all - mTxBuf[len] = ah::crc8(mTxBuf, len); - len++; - - if(mSerialDebug) { - DPRINT(DBG_INFO, F("TX ")); - DBGPRINT(String(len)); - DBGPRINT("B Ch"); - DBGPRINT(String(mRfChLst[mTxChIdx])); - DBGPRINT(F(" | ")); - dumpBuf(mTxBuf, len); - } - - mNrf24.stopListening(); - mNrf24.setChannel(mRfChLst[mTxChIdx]); - mNrf24.openWritingPipe(reinterpret_cast(&invId)); - mNrf24.startWrite(mTxBuf, len, false); // false = request ACK response - - // switch TX channel for next packet - if(++mTxChIdx >= RF_CHANNELS) - mTxChIdx = 0; - - if(isRetransmit) - mRetransmits++; - else - mSendCnt++; - } - - volatile bool mIrqRcvd; - uint64_t DTU_RADIO_ID; - - uint8_t mRfChLst[RF_CHANNELS]; - uint8_t mTxChIdx; - uint8_t mRxChIdx; - - RF24 mNrf24; - uint8_t mTxBuf[MAX_RF_PAYLOAD_SIZE]; -}; - -#endif /*__RADIO_H__*/ From c3fce0af243b70b30f664f8be76986226d5d9a02 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 16 Mar 2023 16:51:28 +0100 Subject: [PATCH 21/52] MI - optimize debug output and resending logic --- src/hm/miPayload.h | 89 +++++++++++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 37 deletions(-) diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index 931c9657..7e32ea92 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -92,11 +92,11 @@ class MiPayload { iv->setQueuedCmdFinished(); // command failed if (mSerialDebug) - DPRINTLN(DBG_INFO, F("enqueued cmd failed/timeout")); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("enqueued cmd failed/timeout")); if (mSerialDebug) { - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(") no Payload received! (retransmits: ")); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINT(F("no Payload received! (retransmits: ")); DBGPRINT(String(mPayload[iv->id].retransmits)); DBGPRINTLN(F(")")); } @@ -109,17 +109,15 @@ class MiPayload { yield(); if (mSerialDebug){ - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(") Requesting Inv SN ")); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINT(F("Requesting Inv SN ")); DBGPRINTLN(String(iv->config->serial.u64, HEX)); } if (iv->getDevControlRequest()) { if (mSerialDebug) { - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(") Devcontrol request 0x")); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINT(F("Devcontrol request 0x")); DBGPRINT(String(iv->devControlCmd, HEX)); DBGPRINT(F(" power limit ")); DBGPRINTLN(String(iv->powerLimit[0])); @@ -130,9 +128,8 @@ class MiPayload { //iv->enqueCommand(SystemConfigPara); // read back power limit } else { uint8_t cmd = iv->getQueuedCmd(); - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(") prepareDevInformCmd 0x")); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINT(F("prepareDevInformCmd 0x")); DBGPRINTLN(String(cmd, HEX)); uint8_t cmd2 = cmd; if (cmd == 0x1 ) { //0x1 @@ -225,10 +222,12 @@ const byteAssign_t InfoAssignment[] = { mStat->rxSuccess++; mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x01, false);*/ } else if ( p->packet[9] == 0x01 ) {//second frame - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") got 2nd frame (hw info)")); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("got 2nd frame (hw info)")); //mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x12, false); } else if ( p->packet[9] == 0x12 ) {//3rd frame - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") got 3rd frame (hw info)")); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("got 3rd frame (hw info)")); iv->setQueuedCmdFinished(); mStat->rxSuccess++; } @@ -262,7 +261,8 @@ const byteAssign_t InfoAssignment[] = { } } */ } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command - DPRINTLN(DBG_DEBUG, F("Response from devcontrol request received")); + miDPRINTHead(DBG_DEBUG, iv->id); + DBGPRINTLN(F("Response from devcontrol request received")); mPayload[iv->id].txId = p->packet[0]; iv->clearDevControlRequest(); @@ -273,7 +273,10 @@ const byteAssign_t InfoAssignment[] = { mApp->setMqttPowerLimitAck(iv); else msg = "NOT "; - DPRINTLN(DBG_INFO, F("Inverter ") + String(iv->id) + F(" has ") + msg + F("accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1])); + //DPRINTLN(DBG_INFO, F("Inverter ") + String(iv->id) + F(" has ") + msg + F("accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1])); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("has ") + msg + F("accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1])); + iv->clearCmdQueue(); iv->enqueCommand(SystemConfigPara); // read back power limit } @@ -376,21 +379,20 @@ const byteAssign_t InfoAssignment[] = { if ((mPayload[iv->id].requested) && (retransmit)) { if (iv->devControlCmd == Restart || iv->devControlCmd == CleanState_LockAndAlarm) { // This is required to prevent retransmissions without answer. - DPRINTLN(DBG_INFO, F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); mPayload[iv->id].retransmits = mMaxRetrans; } else if(iv->devControlCmd == ActivePowerContr) { - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINTLN(F(") retransmit power limit")); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("retransmit power limit")); mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true); } else { uint8_t cmd = mPayload[iv->id].txCmd; if (mPayload[iv->id].retransmits < mMaxRetrans) { mPayload[iv->id].retransmits++; if( !mPayload[iv->id].gotFragment ) { - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINTLN(F(") nothing received")); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("nothing received")); mPayload[iv->id].retransmits = mMaxRetrans; } else if ( cmd == 0x0f ) { //hard/firmware request @@ -404,23 +406,23 @@ const byteAssign_t InfoAssignment[] = { change = true; } else if ( cmd == 0x09 ) {//MI single or dual channel device if ( mPayload[iv->id].dataAB[CH1] && iv->type == INV_TYPE_2CH ) { - if (!mPayload[iv->id].stsAB[CH2] || !mPayload[iv->id].dataAB[CH2] ) { + if (!mPayload[iv->id].stsAB[CH1] && mPayload[iv->id].retransmits<2) {} + //first try to get missing sts for first channel a second time + else if (!mPayload[iv->id].stsAB[CH2] || !mPayload[iv->id].dataAB[CH2] ) { cmd = 0x11; change = true; mPayload[iv->id].retransmits = 0; //reset counter } } } else if ( cmd == 0x11) { - if ( mPayload[iv->id].dataAB[CH2] ) { // data is there, but no status - if (!mPayload[iv->id].stsAB[CH1] || !mPayload[iv->id].dataAB[CH1] ) { + if ( mPayload[iv->id].dataAB[CH2] ) { // data + status ch2 are there? + if (mPayload[iv->id].stsAB[CH2] && (!mPayload[iv->id].stsAB[CH1] || !mPayload[iv->id].dataAB[CH1])) { cmd = 0x09; change = true; } } } - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(") ")); + miDPRINTHead(DBG_INFO, iv->id); if (change) { DBGPRINT(F("next request is 0x")); } else { @@ -438,9 +440,12 @@ const byteAssign_t InfoAssignment[] = { } else if(!crcPass && pyldComplete) { // crc error on complete Payload if (mPayload[iv->id].retransmits < mMaxRetrans) { mPayload[iv->id].retransmits++; - DPRINTLN(DBG_WARN, F("CRC Error: Request Complete Retransmit")); + miDPRINTHead(DBG_WARN, iv->id); + DBGPRINTLN(F("CRC Error: Request Complete Retransmit")); mPayload[iv->id].txCmd = iv->getQueuedCmd(); - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX)); + miDPRINTHead(DBG_INFO, iv->id); + + DBGPRINTLN(F("prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX)); mSys->Radio.prepareDevInformCmd(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); } } @@ -516,7 +521,7 @@ const byteAssign_t InfoAssignment[] = { } void miStsDecode(Inverter<> *iv, packet_t *p, uint8_t stschan = CH1) { - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") status msg 0x") + String(p->packet[0], HEX)); + //DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") status msg 0x") + String(p->packet[0], HEX)); record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); // choose the record structure rec->ts = mPayload[iv->id].ts; mPayload[iv->id].gotFragment = true; @@ -537,7 +542,8 @@ const byteAssign_t InfoAssignment[] = { if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){ iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]; // seems there's no status per channel in 3rd gen. models?!? - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") alarm ID incremented to ") + String(iv->alarmMesIndex)); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("alarm ID incremented to ") + String(iv->alarmMesIndex)); iv->enqueCommand(AlarmData); } //mPayload[iv->id].skipfirstrepeat = 1; @@ -555,7 +561,7 @@ const byteAssign_t InfoAssignment[] = { ( p->packet[0] == 0x91 || p->packet[0] == (0x37 + ALL_FRAMES) ) ? CH2 : p->packet[0] == (0x38 + ALL_FRAMES) ? CH3 : CH4; - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") data msg 0x") + String(p->packet[0], HEX) + F(" channel ") + datachan); + //DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") data msg 0x") + String(p->packet[0], HEX) + F(" channel ") + datachan); // count in RF_communication_protocol.xlsx is with offset = -1 iv->setValue(iv->getPosByChFld(datachan, FLD_UDC, rec), rec, (float)((p->packet[9] << 8) + p->packet[10])/10); yield(); @@ -613,7 +619,8 @@ const byteAssign_t InfoAssignment[] = { if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){ iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]; - DPRINTLN(DBG_INFO, F("alarm ID incremented to ") + String(iv->alarmMesIndex)); + miDPRINTHead(DBG_INFO, iv->id); + DBGPRINTLN(F("alarm ID incremented to ") + String(iv->alarmMesIndex)); //iv->enqueCommand(AlarmData); } @@ -699,8 +706,16 @@ const byteAssign_t InfoAssignment[] = { return true; } + void miDPRINTHead(uint8_t lvl, uint8_t id) { + DPRINT(lvl, F("(#")); + DBGPRINT(String(id)); + DBGPRINT(F(") ")); + } + void reset(uint8_t id) { - DPRINTLN(DBG_INFO, F("resetPayload: id: ") + String(id)); + //DPRINTLN(DBG_INFO, F("resetPayload: id: ") + String(id)); + miDPRINTHead(DBG_INFO, id); + DBGPRINTLN(F("resetPayload")); memset(mPayload[id].len, 0, MAX_PAYLOAD_ENTRIES); mPayload[id].gotFragment = false; /*mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; From d01b527eb4977316bd340e4d0306a7e0ab60edca Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 16 Mar 2023 17:31:42 +0100 Subject: [PATCH 22/52] Debug: introduce DPRINTHEAD function --- src/utils/dbg.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/utils/dbg.h b/src/utils/dbg.h index bdfa2b15..b5cc57c6 100644 --- a/src/utils/dbg.h +++ b/src/utils/dbg.h @@ -146,6 +146,10 @@ }\ }) +#define DPRINTHEAD(level, id) ({\ + DPRINT(level, F("(#")); DBGPRINT(String(id)); DBGPRINT(F(") "));\ +}) + #define DPRINTLN(level, str) ({\ switch(level) {\ case DBG_ERROR: PERRLN(str); break; \ @@ -155,7 +159,6 @@ default: PVERBLN(str); break; \ }\ }) - /*class ahoyLog { public: ahoyLog() {} From ff93954612680399b7343901b8a9170e9d29bec0 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 16 Mar 2023 17:32:56 +0100 Subject: [PATCH 23/52] use DPRINTHEAD for MI saves ~2+% of flash mem --- src/hm/miPayload.h | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index 7e32ea92..64a345c4 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -92,10 +92,10 @@ class MiPayload { iv->setQueuedCmdFinished(); // command failed if (mSerialDebug) - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINTLN(F("enqueued cmd failed/timeout")); if (mSerialDebug) { - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINT(F("no Payload received! (retransmits: ")); DBGPRINT(String(mPayload[iv->id].retransmits)); DBGPRINTLN(F(")")); @@ -109,14 +109,14 @@ class MiPayload { yield(); if (mSerialDebug){ - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINT(F("Requesting Inv SN ")); DBGPRINTLN(String(iv->config->serial.u64, HEX)); } if (iv->getDevControlRequest()) { if (mSerialDebug) { - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINT(F("Devcontrol request 0x")); DBGPRINT(String(iv->devControlCmd, HEX)); DBGPRINT(F(" power limit ")); @@ -128,7 +128,7 @@ class MiPayload { //iv->enqueCommand(SystemConfigPara); // read back power limit } else { uint8_t cmd = iv->getQueuedCmd(); - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINT(F("prepareDevInformCmd 0x")); DBGPRINTLN(String(cmd, HEX)); uint8_t cmd2 = cmd; @@ -222,11 +222,11 @@ const byteAssign_t InfoAssignment[] = { mStat->rxSuccess++; mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x01, false);*/ } else if ( p->packet[9] == 0x01 ) {//second frame - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINTLN(F("got 2nd frame (hw info)")); //mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x12, false); } else if ( p->packet[9] == 0x12 ) {//3rd frame - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINTLN(F("got 3rd frame (hw info)")); iv->setQueuedCmdFinished(); mStat->rxSuccess++; @@ -261,7 +261,7 @@ const byteAssign_t InfoAssignment[] = { } } */ } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command - miDPRINTHead(DBG_DEBUG, iv->id); + DPRINTHEAD(DBG_DEBUG, iv->id); DBGPRINTLN(F("Response from devcontrol request received")); mPayload[iv->id].txId = p->packet[0]; @@ -274,7 +274,7 @@ const byteAssign_t InfoAssignment[] = { else msg = "NOT "; //DPRINTLN(DBG_INFO, F("Inverter ") + String(iv->id) + F(" has ") + msg + F("accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1])); - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINTLN(F("has ") + msg + F("accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1])); iv->clearCmdQueue(); @@ -379,11 +379,11 @@ const byteAssign_t InfoAssignment[] = { if ((mPayload[iv->id].requested) && (retransmit)) { if (iv->devControlCmd == Restart || iv->devControlCmd == CleanState_LockAndAlarm) { // This is required to prevent retransmissions without answer. - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINTLN(F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); mPayload[iv->id].retransmits = mMaxRetrans; } else if(iv->devControlCmd == ActivePowerContr) { - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINTLN(F("retransmit power limit")); mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true); } else { @@ -391,7 +391,7 @@ const byteAssign_t InfoAssignment[] = { if (mPayload[iv->id].retransmits < mMaxRetrans) { mPayload[iv->id].retransmits++; if( !mPayload[iv->id].gotFragment ) { - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINTLN(F("nothing received")); mPayload[iv->id].retransmits = mMaxRetrans; } else if ( cmd == 0x0f ) { @@ -422,7 +422,7 @@ const byteAssign_t InfoAssignment[] = { } } } - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); if (change) { DBGPRINT(F("next request is 0x")); } else { @@ -440,10 +440,10 @@ const byteAssign_t InfoAssignment[] = { } else if(!crcPass && pyldComplete) { // crc error on complete Payload if (mPayload[iv->id].retransmits < mMaxRetrans) { mPayload[iv->id].retransmits++; - miDPRINTHead(DBG_WARN, iv->id); + DPRINTHEAD(DBG_WARN, iv->id); DBGPRINTLN(F("CRC Error: Request Complete Retransmit")); mPayload[iv->id].txCmd = iv->getQueuedCmd(); - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINTLN(F("prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX)); mSys->Radio.prepareDevInformCmd(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); @@ -542,7 +542,7 @@ const byteAssign_t InfoAssignment[] = { if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){ iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]; // seems there's no status per channel in 3rd gen. models?!? - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINTLN(F("alarm ID incremented to ") + String(iv->alarmMesIndex)); iv->enqueCommand(AlarmData); } @@ -619,7 +619,7 @@ const byteAssign_t InfoAssignment[] = { if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){ iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]; - miDPRINTHead(DBG_INFO, iv->id); + DPRINTHEAD(DBG_INFO, iv->id); DBGPRINTLN(F("alarm ID incremented to ") + String(iv->alarmMesIndex)); //iv->enqueCommand(AlarmData); } @@ -706,15 +706,15 @@ const byteAssign_t InfoAssignment[] = { return true; } - void miDPRINTHead(uint8_t lvl, uint8_t id) { +/* void miDPRINTHead(uint8_t lvl, uint8_t id) { DPRINT(lvl, F("(#")); DBGPRINT(String(id)); DBGPRINT(F(") ")); - } + }*/ void reset(uint8_t id) { //DPRINTLN(DBG_INFO, F("resetPayload: id: ") + String(id)); - miDPRINTHead(DBG_INFO, id); + DPRINTHEAD(DBG_INFO, id); DBGPRINTLN(F("resetPayload")); memset(mPayload[id].len, 0, MAX_PAYLOAD_ENTRIES); mPayload[id].gotFragment = false; From a2f4807f5a4902fe4a188cb197fb8b9560b74589 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Fri, 17 Mar 2023 07:35:12 +0100 Subject: [PATCH 24/52] Move some fix texts to debug.h Add * DBGPRINT_TXT * DBGPRINTLN_TXT --- src/utils/dbg.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/utils/dbg.h b/src/utils/dbg.h index b5cc57c6..56623cf8 100644 --- a/src/utils/dbg.h +++ b/src/utils/dbg.h @@ -159,6 +159,38 @@ default: PVERBLN(str); break; \ }\ }) + +// available text variables +#define TXT_NOPYLD 1 +#define TXT_INVSERNO 2 +#define TXT_GDEVINF 3 +#define TXT_DEVCTRL 4 +#define TXT_INCRALM 5 + + +#define DBGPRINT_TXT(text) ({\ + switch(text) {\ + case TXT_NOPYLD: DBGPRINT(F("no Payload received! (retransmits: ")); break; \ + case TXT_INVSERNO: DBGPRINT(F("Requesting Inv SN ")); break; \ + case TXT_GDEVINF: DBGPRINT(F("prepareDevInformCmd 0x")); break; \ + case TXT_DEVCTRL: DBGPRINT(F("Devcontrol request 0x")); break; \ + case TXT_INCRALM: DBGPRINT(F("alarm ID incremented to ")); break; \ + default: ; break; \ + }\ +}) + +// available text variables w. lf +#define TXT_TIMEOUT 1 +#define TXT_NOPYLD2 2 + +#define DBGPRINTLN_TXT(text) ({\ + switch(text) {\ + case TXT_TIMEOUT: DBGPRINT(F("enqueued cmd failed/timeout\r\n")); break; \ + case TXT_NOPYLD2: DBGPRINT(F("nothing received\r\n")); break; \ + default: ; break; \ + }\ +}) + /*class ahoyLog { public: ahoyLog() {} From e1326698b98d2e07775d3e70b9fed4af2f6a9547 Mon Sep 17 00:00:00 2001 From: lumapu Date: Fri, 17 Mar 2023 23:14:38 +0100 Subject: [PATCH 25/52] 0.5.102 fix JSON import #775 fix save settings, at least already stored settings are not lost #771 --- src/.vscode/settings.json | 1 + src/CHANGES.md | 13 +++++++++++++ src/config/settings.h | 31 ++++++++++++++++++++++++------- src/defines.h | 2 +- src/hm/miPayload.h | 2 +- src/web/html/setup.html | 2 +- src/web/web.h | 24 +++++++++++------------- 7 files changed, 52 insertions(+), 23 deletions(-) diff --git a/src/.vscode/settings.json b/src/.vscode/settings.json index 85de73f4..c0becfd1 100644 --- a/src/.vscode/settings.json +++ b/src/.vscode/settings.json @@ -85,4 +85,5 @@ "stop_token": "cpp", "thread": "cpp" }, + "cmake.configureOnOpen": false, } \ No newline at end of file diff --git a/src/CHANGES.md b/src/CHANGES.md index 9ec5f85b..131e891d 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -2,6 +2,19 @@ (starting from release version `0.5.66`) +## 0.5.102 +* fix JSON import #775 +* fix save settings, at least already stored settings are not lost #771 + +## 0.5.101 +* fix SSD1306 +* update documentation +* Update miPayload.h +* Update README.md +* MI - remarks to user manual +* MI - fix AC calc +* MI - fix status msg. analysis + ## 0.5.100 * fix add inverter `setup.html` #766 * fix MQTT retained flag for total values #726 diff --git a/src/config/settings.h b/src/config/settings.h index 77bc7a26..29974862 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -14,6 +14,12 @@ #include "../utils/dbg.h" #include "../utils/helper.h" +#if defined(ESP32) + #define MAX_ALLOWED_BUF_SIZE ESP.getMaxAllocHeap() - 2048 +#else + #define MAX_ALLOWED_BUF_SIZE ESP.getMaxFreeBlockSize() - 2048 +#endif + /** * More info: * https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html#flash-layout @@ -224,8 +230,9 @@ class settings { else { //DPRINTLN(DBG_INFO, fp.readString()); //fp.seek(0, SeekSet); - DynamicJsonDocument root(5500); + DynamicJsonDocument root(MAX_ALLOWED_BUF_SIZE); DeserializationError err = deserializeJson(root, fp); + root.shrinkToFit(); if(!err && (root.size() > 0)) { mCfg.valid = true; jsonWifi(root[F("wifi")]); @@ -249,13 +256,8 @@ class settings { bool saveSettings(bool stopFs = false) { DPRINTLN(DBG_DEBUG, F("save settings")); - File fp = LittleFS.open("/settings.json", "w"); - if(!fp) { - DPRINTLN(DBG_ERROR, F("can't open settings file!")); - return false; - } - DynamicJsonDocument json(6500); + DynamicJsonDocument json(MAX_ALLOWED_BUF_SIZE); JsonObject root = json.to(); jsonWifi(root.createNestedObject(F("wifi")), true); jsonNrf(root.createNestedObject(F("nrf")), true); @@ -267,12 +269,27 @@ class settings { jsonPlugin(root.createNestedObject(F("plugin")), true); jsonInst(root.createNestedObject(F("inst")), true); + DPRINT(DBG_INFO, "memory usage: "); + DBGPRINTLN(String(json.memoryUsage())); + + if(json.overflowed()) { + DPRINTLN(DBG_ERROR, F("buffer too small!")); + return false; + } + + File fp = LittleFS.open("/settings.json", "w"); + if(!fp) { + DPRINTLN(DBG_ERROR, F("can't open settings file!")); + return false; + } + if(0 == serializeJson(root, fp)) { DPRINTLN(DBG_ERROR, F("can't write settings file!")); return false; } fp.close(); + DPRINTLN(DBG_INFO, F("settings saved")); if(stopFs) stop(); diff --git a/src/defines.h b/src/defines.h index 997981a3..e6206a96 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 5 -#define VERSION_PATCH 101 +#define VERSION_PATCH 102 //------------------------------------- typedef struct { diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index 62e7450e..554e57c8 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -118,7 +118,7 @@ class MiPayload { //DPRINTLN(DBG_INFO, F("MI got data [0]=") + String(p->packet[0], HEX)); if (p->packet[0] == (0x08 + ALL_FRAMES)) { // 0x88; MI status response to 0x09 - miStsDecode(iv, p), CH1; + miStsDecode(iv, p, CH1); } else if (p->packet[0] == (0x11 + SINGLE_FRAME)) { // 0x92; MI status response to 0x11 diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 967cccd6..58144219 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -270,7 +270,7 @@
Luminance
-
+

Pinout

diff --git a/src/web/web.h b/src/web/web.h index 098ed7ed..814259b8 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -161,26 +161,24 @@ class Web { DPRINTLN(DBG_ERROR, F("can't open file!")); mUploadFail = true; mUploadFp.close(); + return; } } mUploadFp.write(data, len); if (final) { mUploadFp.close(); - File fp = LittleFS.open("/tmp.json", "r"); - if (!fp) + char pwd[PWD_LEN]; + strncpy(pwd, mConfig->sys.stationPwd, PWD_LEN); // backup WiFi PWD + if (!mApp->readSettings("/tmp.json")) { mUploadFail = true; - else { - char pwd[PWD_LEN]; - strncpy(pwd, mConfig->sys.stationPwd, PWD_LEN); // backup WiFi PWD - if (!mApp->readSettings("tmp.json")) { - mUploadFail = true; - DPRINTLN(DBG_ERROR, F("upload JSON error!")); - } else { - strncpy(mConfig->sys.stationPwd, pwd, PWD_LEN); // restore WiFi PWD - mApp->saveSettings(true); - } + DPRINTLN(DBG_ERROR, F("upload JSON error!")); + } else { + LittleFS.remove("/tmp.json"); + strncpy(mConfig->sys.stationPwd, pwd, PWD_LEN); // restore WiFi PWD + mApp->saveSettings(true); } - DPRINTLN(DBG_INFO, F("upload finished!")); + if (!mUploadFail) + DPRINTLN(DBG_INFO, F("upload finished!")); } } From 57bda044e59580bcdc95351ac3fb5fb73112f353 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 18 Mar 2023 01:37:59 +0100 Subject: [PATCH 26/52] 0.5.102 Warning: old exports are not compatible any more! further save settings improvements (only store inverters which are existing) improved display of settings save return value made save settings asynchronous (more heap memory is free) --- src/CHANGES.md | 4 +++ src/app.cpp | 2 ++ src/app.h | 25 ++++++++++++++++-- src/appInterface.h | 2 ++ src/config/settings.h | 57 ++++++++++++++++++++++++++--------------- src/web/RestApi.h | 17 +++++++++--- src/web/html/index.html | 4 +-- src/web/html/setup.html | 12 ++++----- src/web/web.h | 17 +++++++----- 9 files changed, 99 insertions(+), 41 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 131e891d..4c1346cb 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -3,8 +3,12 @@ (starting from release version `0.5.66`) ## 0.5.102 +* Warning: old exports are not compatible any more! * fix JSON import #775 * fix save settings, at least already stored settings are not lost #771 +* further save settings improvements (only store inverters which are existing) +* improved display of settings save return value +* made save settings asynchronous (more heap memory is free) ## 0.5.101 * fix SSD1306 diff --git a/src/app.cpp b/src/app.cpp index a69d73a1..23030d76 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -374,6 +374,8 @@ void app::resetSystem(void) { mSendLastIvId = 0; mShowRebootRequest = false; mIVCommunicationOn = true; + mSavePending = false; + mSaveReboot = false; memset(&mStat, 0, sizeof(statistics_t)); } diff --git a/src/app.h b/src/app.h index a792ffe8..afd90565 100644 --- a/src/app.h +++ b/src/app.h @@ -68,9 +68,12 @@ class app : public IApp, public ah::Scheduler { return Scheduler::getTimestamp(); } - bool saveSettings(bool stopFs = false) { + bool saveSettings(bool reboot) { mShowRebootRequest = true; // only message on index, no reboot - return mSettings.saveSettings(stopFs); + mSavePending = true; + mSaveReboot = reboot; + once(std::bind(&app::tickSave, this), 2, "save"); + return true; } bool readSettings(const char *path) { @@ -81,6 +84,14 @@ class app : public IApp, public ah::Scheduler { return mSettings.eraseSettings(eraseWifi); } + bool getSavePending() { + return mSavePending; + } + + bool getLastSaveSucceed() { + return mSettings.getLastSaveSucceed(); + } + statistics_t *getStatistics() { return &mStat; } @@ -214,6 +225,14 @@ class app : public IApp, public ah::Scheduler { ESP.restart(); } + void tickSave(void) { + mSettings.saveSettings(); + mSavePending = false; + + if(mSaveReboot) + once(std::bind(&app::tickReboot, this), 2, "rboot"); + } + void tickNtpUpdate(void); void tickCalcSunrise(void); void tickIVCommunication(void); @@ -253,6 +272,8 @@ class app : public IApp, public ah::Scheduler { char mVersion[12]; settings mSettings; settings_t *mConfig; + bool mSavePending; + bool mSaveReboot; uint8_t mSendLastIvId; bool mSendFirst; diff --git a/src/appInterface.h b/src/appInterface.h index 4c7d6042..a79dcdb1 100644 --- a/src/appInterface.h +++ b/src/appInterface.h @@ -17,6 +17,8 @@ class IApp { virtual bool saveSettings(bool stopFs) = 0; virtual bool readSettings(const char *path) = 0; virtual bool eraseSettings(bool eraseWifi) = 0; + virtual bool getSavePending() = 0; + virtual bool getLastSaveSucceed() = 0; virtual void setOnUpdate() = 0; virtual void setRebootFlag() = 0; virtual const char *getVersion() = 0; diff --git a/src/config/settings.h b/src/config/settings.h index 29974862..24bb6a9e 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -15,9 +15,9 @@ #include "../utils/helper.h" #if defined(ESP32) - #define MAX_ALLOWED_BUF_SIZE ESP.getMaxAllocHeap() - 2048 + #define MAX_ALLOWED_BUF_SIZE ESP.getMaxAllocHeap() - 1024 #else - #define MAX_ALLOWED_BUF_SIZE ESP.getMaxFreeBlockSize() - 2048 + #define MAX_ALLOWED_BUF_SIZE ESP.getMaxFreeBlockSize() - 1024 #endif /** @@ -161,7 +161,9 @@ typedef struct { class settings { public: - settings() {} + settings() { + mLastSaveSucceed = false; + } void setup() { DPRINTLN(DBG_INFO, F("Initializing FS ..")); @@ -208,6 +210,10 @@ class settings { return mCfg.valid; } + inline bool getLastSaveSucceed() { + return mLastSaveSucceed; + } + void getInfo(uint32_t *used, uint32_t *size) { #if !defined(ESP32) FSInfo info; @@ -254,7 +260,7 @@ class settings { return mCfg.valid; } - bool saveSettings(bool stopFs = false) { + bool saveSettings() { DPRINTLN(DBG_DEBUG, F("save settings")); DynamicJsonDocument json(MAX_ALLOWED_BUF_SIZE); @@ -269,31 +275,35 @@ class settings { jsonPlugin(root.createNestedObject(F("plugin")), true); jsonInst(root.createNestedObject(F("inst")), true); - DPRINT(DBG_INFO, "memory usage: "); + DPRINT(DBG_INFO, F("memory usage: ")); DBGPRINTLN(String(json.memoryUsage())); + DPRINT(DBG_INFO, F("capacity: ")); + DBGPRINTLN(String(json.capacity())); + DPRINT(DBG_INFO, F("max alloc: ")); + DBGPRINTLN(String(MAX_ALLOWED_BUF_SIZE)); if(json.overflowed()) { DPRINTLN(DBG_ERROR, F("buffer too small!")); + mLastSaveSucceed = false; return false; } File fp = LittleFS.open("/settings.json", "w"); if(!fp) { DPRINTLN(DBG_ERROR, F("can't open settings file!")); + mLastSaveSucceed = false; return false; } if(0 == serializeJson(root, fp)) { DPRINTLN(DBG_ERROR, F("can't write settings file!")); + mLastSaveSucceed = false; return false; } fp.close(); - DPRINTLN(DBG_INFO, F("settings saved")); - if(stopFs) - stop(); - + mLastSaveSucceed = true; return true; } @@ -301,7 +311,7 @@ class settings { if(true == eraseWifi) return LittleFS.format(); loadDefaults(!eraseWifi); - return saveSettings(true); + return saveSettings(); } private: @@ -549,36 +559,41 @@ class settings { if(set) ivArr = obj.createNestedArray(F("iv")); for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { - if(set) - jsonIv(ivArr.createNestedObject(), &mCfg.inst.iv[i], true); - else - jsonIv(obj[F("iv")][i], &mCfg.inst.iv[i]); + if(set) { + if(mCfg.inst.iv[i].serial.u64 != 0ULL) + jsonIv(ivArr.createNestedObject(), &mCfg.inst.iv[i], true); + } + else { + if(!obj[F("iv")][i].isNull()) + jsonIv(obj[F("iv")][i], &mCfg.inst.iv[i]); + } } } void jsonIv(JsonObject obj, cfgIv_t *cfg, bool set = false) { if(set) { - obj[F("en")] = (bool)cfg->enabled; - obj[F("name")] = cfg->name; - obj[F("sn")] = cfg->serial.u64; + obj[F("en")] = (bool)cfg->enabled; + obj[F("name")] = cfg->name; + obj[F("sn")] = cfg->serial.u64; for(uint8_t i = 0; i < 4; i++) { - obj[F("yield")][i] = cfg->yieldCor[i]; + obj[F("yc")][i] = cfg->yieldCor[i]; obj[F("pwr")][i] = cfg->chMaxPwr[i]; - obj[F("chName")][i] = cfg->chName[i]; + obj[F("chn")][i] = cfg->chName[i]; } } else { cfg->enabled = (bool)obj[F("en")]; snprintf(cfg->name, MAX_NAME_LENGTH, "%s", obj[F("name")].as()); cfg->serial.u64 = obj[F("sn")]; for(uint8_t i = 0; i < 4; i++) { - cfg->yieldCor[i] = obj[F("yield")][i]; + cfg->yieldCor[i] = obj[F("yc")][i]; cfg->chMaxPwr[i] = obj[F("pwr")][i]; - snprintf(cfg->chName[i], MAX_NAME_LENGTH, "%s", obj[F("chName")][i].as()); + snprintf(cfg->chName[i], MAX_NAME_LENGTH, "%s", obj[F("chn")][i].as()); } } } settings_t mCfg; + bool mLastSaveSucceed; }; #endif /*__SETTINGS_H__*/ diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 9b14e439..ecabd1f4 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -80,6 +80,7 @@ class RestApi { if(path == "html/system") getHtmlSystem(root); else if(path == "html/logout") getHtmlLogout(root); else if(path == "html/save") getHtmlSave(root); + else if(path == "html/chk_save") getHtmlChkSave(root); else if(path == "system") getSysInfo(root); else if(path == "generic") getGeneric(root); else if(path == "reboot") getReboot(root); @@ -266,9 +267,19 @@ class RestApi { void getHtmlSave(JsonObject obj) { getGeneric(obj.createNestedObject(F("generic"))); - obj[F("refresh")] = 2; - obj[F("refresh_url")] = "/setup"; - obj[F("html")] = F("settings succesfully save"); + obj[F("refresh")] = 1; + obj[F("refresh_url")] = F("/chk_save"); + obj[F("html")] = F("saving settings ..."); + } + + void getHtmlChkSave(JsonObject obj) { + getGeneric(obj.createNestedObject(F("generic"))); + obj[F("refresh")] = (mApp->getLastSaveSucceed()) ? 10 : 1; + obj[F("refresh_url")] = mApp->getSavePending() ? F("/chk_save") : F("/setup"); + if(mApp->getSavePending()) + obj[F("html")] = F("saving settings ..."); + else + obj[F("html")] = mApp->getLastSaveSucceed() ? F("settings succesfully saved") : F("failed saving settings"); } void getReboot(JsonObject obj) { diff --git a/src/web/html/index.html b/src/web/html/index.html index 27a46a9c..72537e5e 100644 --- a/src/web/html/index.html +++ b/src/web/html/index.html @@ -102,12 +102,12 @@ if(obj["disNightComm"]) { if(((obj["ts_sunrise"] - obj["ts_offset"]) < obj["ts_now"]) && ((obj["ts_sunset"] + obj["ts_offset"]) > obj["ts_now"])) { - commInfo = "Polling inverter(s), will stop at sunset " + (new Date((obj["ts_sunset"] + obj["ts_offset"]) * 1000).toLocaleString('de-DE')); + commInfo = "Polling inverter(s), will pause at sunset " + (new Date((obj["ts_sunset"] + obj["ts_offset"]) * 1000).toLocaleString('de-DE')); } else { commInfo = "Night time, inverter polling disabled, "; if(obj["ts_now"] > (obj["ts_sunrise"] - obj["ts_offset"])) { - commInfo += "stopped at " + (new Date((obj["ts_sunset"] + obj["ts_offset"]) * 1000).toLocaleString('de-DE')); + commInfo += "paused at " + (new Date((obj["ts_sunset"] + obj["ts_offset"]) * 1000).toLocaleString('de-DE')); } else { commInfo += "will start polling at " + (new Date((obj["ts_sunrise"] - obj["ts_offset"]) * 1000).toLocaleString('de-DE')); diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 58144219..93841461 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -157,7 +157,7 @@
-
Reset values when inverter polling stops at sunset
+
Reset values when inverter polling pauses at sunset
@@ -209,7 +209,7 @@
-
Stop polling inverters during night
+
Pause polling inverters during night
@@ -291,8 +291,8 @@
Import / Export JSON Settings
-
Import
-
+
Import
+
@@ -300,8 +300,8 @@
-
Export
-
+
Export
+
Export settings (JSON file) (only values, passwords will be removed!)
diff --git a/src/web/web.h b/src/web/web.h index 814259b8..c1726f87 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -68,6 +68,7 @@ class Web { mWeb.on("/setup", HTTP_GET, std::bind(&Web::onSetup, this, std::placeholders::_1)); mWeb.on("/save", HTTP_ANY, std::bind(&Web::showSave, this, std::placeholders::_1)); + mWeb.on("/chk_save", HTTP_ANY, std::bind(&Web::onCheckSave, this, std::placeholders::_1)); mWeb.on("/live", HTTP_ANY, std::bind(&Web::onLive, this, std::placeholders::_1)); //mWeb.on("/api1", HTTP_POST, std::bind(&Web::showWebApi, this, std::placeholders::_1)); @@ -592,13 +593,15 @@ class Web { mApp->saveSettings((request->arg("reboot") == "on")); - if (request->arg("reboot") == "on") - onReboot(request); - else { - AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), system_html, system_html_len); - response->addHeader(F("Content-Encoding"), "gzip"); - request->send(response); - } + AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), system_html, system_html_len); + response->addHeader(F("Content-Encoding"), "gzip"); + request->send(response); + } + + void onCheckSave(AsyncWebServerRequest *request) { + AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), system_html, system_html_len); + response->addHeader(F("Content-Encoding"), "gzip"); + request->send(response); } void onLive(AsyncWebServerRequest *request) { From d7c06fd5d895f3d10e2c62efeb9ac885e097a2b2 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 18 Mar 2023 02:12:12 +0100 Subject: [PATCH 27/52] 0.5.102 small fixes (save settings) --- src/app.h | 7 ++++--- src/config/settings.h | 8 ++++---- src/web/RestApi.h | 9 +-------- src/web/web.h | 4 ++-- 4 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/app.h b/src/app.h index afd90565..cbf7e6a1 100644 --- a/src/app.h +++ b/src/app.h @@ -72,7 +72,7 @@ class app : public IApp, public ah::Scheduler { mShowRebootRequest = true; // only message on index, no reboot mSavePending = true; mSaveReboot = reboot; - once(std::bind(&app::tickSave, this), 2, "save"); + once(std::bind(&app::tickSave, this), 3, "save"); return true; } @@ -226,11 +226,12 @@ class app : public IApp, public ah::Scheduler { } void tickSave(void) { - mSettings.saveSettings(); + if(!mSettings.saveSettings()) + mSaveReboot = false; mSavePending = false; if(mSaveReboot) - once(std::bind(&app::tickReboot, this), 2, "rboot"); + setRebootFlag(); } void tickNtpUpdate(void); diff --git a/src/config/settings.h b/src/config/settings.h index 24bb6a9e..a1c5a85f 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -576,18 +576,18 @@ class settings { obj[F("name")] = cfg->name; obj[F("sn")] = cfg->serial.u64; for(uint8_t i = 0; i < 4; i++) { - obj[F("yc")][i] = cfg->yieldCor[i]; + obj[F("yield")][i] = cfg->yieldCor[i]; obj[F("pwr")][i] = cfg->chMaxPwr[i]; - obj[F("chn")][i] = cfg->chName[i]; + obj[F("chName")][i] = cfg->chName[i]; } } else { cfg->enabled = (bool)obj[F("en")]; snprintf(cfg->name, MAX_NAME_LENGTH, "%s", obj[F("name")].as()); cfg->serial.u64 = obj[F("sn")]; for(uint8_t i = 0; i < 4; i++) { - cfg->yieldCor[i] = obj[F("yc")][i]; + cfg->yieldCor[i] = obj[F("yield")][i]; cfg->chMaxPwr[i] = obj[F("pwr")][i]; - snprintf(cfg->chName[i], MAX_NAME_LENGTH, "%s", obj[F("chn")][i].as()); + snprintf(cfg->chName[i], MAX_NAME_LENGTH, "%s", obj[F("chName")][i].as()); } } } diff --git a/src/web/RestApi.h b/src/web/RestApi.h index ecabd1f4..2d61c623 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -80,7 +80,7 @@ class RestApi { if(path == "html/system") getHtmlSystem(root); else if(path == "html/logout") getHtmlLogout(root); else if(path == "html/save") getHtmlSave(root); - else if(path == "html/chk_save") getHtmlChkSave(root); + else if(path == "html/chk_save") getHtmlSave(root); else if(path == "system") getSysInfo(root); else if(path == "generic") getGeneric(root); else if(path == "reboot") getReboot(root); @@ -268,13 +268,6 @@ class RestApi { void getHtmlSave(JsonObject obj) { getGeneric(obj.createNestedObject(F("generic"))); obj[F("refresh")] = 1; - obj[F("refresh_url")] = F("/chk_save"); - obj[F("html")] = F("saving settings ..."); - } - - void getHtmlChkSave(JsonObject obj) { - getGeneric(obj.createNestedObject(F("generic"))); - obj[F("refresh")] = (mApp->getLastSaveSucceed()) ? 10 : 1; obj[F("refresh_url")] = mApp->getSavePending() ? F("/chk_save") : F("/setup"); if(mApp->getSavePending()) obj[F("html")] = F("saving settings ..."); diff --git a/src/web/web.h b/src/web/web.h index c1726f87..6ba495af 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -67,8 +67,8 @@ class Web { mWeb.on("/factory", HTTP_ANY, std::bind(&Web::showFactoryRst, this, std::placeholders::_1)); mWeb.on("/setup", HTTP_GET, std::bind(&Web::onSetup, this, std::placeholders::_1)); - mWeb.on("/save", HTTP_ANY, std::bind(&Web::showSave, this, std::placeholders::_1)); - mWeb.on("/chk_save", HTTP_ANY, std::bind(&Web::onCheckSave, this, std::placeholders::_1)); + mWeb.on("/save", HTTP_POST, std::bind(&Web::showSave, this, std::placeholders::_1)); + mWeb.on("/chk_save", HTTP_GET, std::bind(&Web::onCheckSave, this, std::placeholders::_1)); mWeb.on("/live", HTTP_ANY, std::bind(&Web::onLive, this, std::placeholders::_1)); //mWeb.on("/api1", HTTP_POST, std::bind(&Web::showWebApi, this, std::placeholders::_1)); From 159b78c326f1f70d6eb72bdddee0bddc05571997 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 19 Mar 2023 13:13:27 +0100 Subject: [PATCH 28/52] 0.5.103 merged MI improvements, thx @rejoe2 #778 changed display inverter online message --- src/CHANGES.md | 4 + src/defines.h | 2 +- src/hm/hmRadio.h | 5 +- src/hm/miPayload.h | 201 ++++++++++++++++----------- src/plugins/Display/Display_Mono.cpp | 2 +- src/utils/dbg.h | 35 +++++ 6 files changed, 168 insertions(+), 81 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 4c1346cb..cf72d38f 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -2,6 +2,10 @@ (starting from release version `0.5.66`) +## 0.5.103 +* merged MI improvements, thx @rejoe2 #778 +* changed display inverter online message + ## 0.5.102 * Warning: old exports are not compatible any more! * fix JSON import #775 diff --git a/src/defines.h b/src/defines.h index e6206a96..56a05970 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 5 -#define VERSION_PATCH 102 +#define VERSION_PATCH 103 //------------------------------------- typedef struct { diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index f0236362..8f528784 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -253,7 +253,10 @@ class HmRadio { mBufCtrl.push(p); if (p.packet[0] == (TX_REQ_INFO + ALL_FRAMES)) // response from get information command isLastPackage = (p.packet[9] > 0x81); // > 0x81 indicates last packet received - else if (p.packet[0] != 0x00) // ignore fragment number zero + else if (p.packet[0] == ( 0x0f + ALL_FRAMES) ) // response from MI get information command + isLastPackage = (p.packet[9] > 0x11); // > 0x11 indicates last packet received + else if (p.packet[0] != 0x00 && p.packet[0] != 0x88 && p.packet[0] != 0x92) + // ignore fragment number zero and MI status messages isLastPackage = true; // response from dev control command yield(); } diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index 554e57c8..64a345c4 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -68,49 +68,90 @@ class MiPayload { } void loop() { - /*if(NULL != mHighPrioIv) { - iv->ivSend(mHighPrioIv, true); // should request firmware version etc.? + if(NULL != mHighPrioIv) { + ivSend(mHighPrioIv, true); // for devcontrol commands? mHighPrioIv = NULL; - }*/ + } } void ivSendHighPrio(Inverter<> *iv) { mHighPrioIv = iv; } - void ivSend(Inverter<> *iv) { + void ivSend(Inverter<> *iv, bool highPrio = false) { + if(!highPrio) { + if (mPayload[iv->id].requested) { + if (!mPayload[iv->id].complete) + process(false); // no retransmit + + if (!mPayload[iv->id].complete) { + if (!mPayload[iv->id].gotFragment) + mStat->rxFailNoAnser++; // got nothing + else + mStat->rxFail++; // got fragments but not complete response + + iv->setQueuedCmdFinished(); // command failed + if (mSerialDebug) + DPRINTHEAD(DBG_INFO, iv->id); + DBGPRINTLN(F("enqueued cmd failed/timeout")); + if (mSerialDebug) { + DPRINTHEAD(DBG_INFO, iv->id); + DBGPRINT(F("no Payload received! (retransmits: ")); + DBGPRINT(String(mPayload[iv->id].retransmits)); + DBGPRINTLN(F(")")); + } + } + } + } + reset(iv->id); mPayload[iv->id].requested = true; yield(); - if (mSerialDebug) - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") Requesting Inv SN ") + String(iv->config->serial.u64, HEX)); - - uint8_t cmd = iv->getQueuedCmd(); - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(") prepareDevInformCmd 0x")); - DBGPRINTLN(String(cmd, HEX)); - uint8_t cmd2 = cmd; - if (cmd == 0x1 ) { //0x1 - cmd = 0x0f; - cmd2 = 0x00; - mSys->Radio.sendCmdPacket(iv->radioId.u64, cmd, cmd2, false); - } else { - mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd2, mPayload[iv->id].ts, iv->alarmMesIndex, false, cmd); - }; - - mPayload[iv->id].txCmd = cmd; - if (iv->type == INV_TYPE_1CH || iv->type == INV_TYPE_2CH) { - mPayload[iv->id].dataAB[CH1] = false; - mPayload[iv->id].stsAB[CH1] = false; - mPayload[iv->id].dataAB[CH0] = false; - mPayload[iv->id].stsAB[CH0] = false; + if (mSerialDebug){ + DPRINTHEAD(DBG_INFO, iv->id); + DBGPRINT(F("Requesting Inv SN ")); + DBGPRINTLN(String(iv->config->serial.u64, HEX)); } - if (iv->type == INV_TYPE_2CH) { - mPayload[iv->id].dataAB[CH2] = false; - mPayload[iv->id].stsAB[CH2] = false; + if (iv->getDevControlRequest()) { + if (mSerialDebug) { + DPRINTHEAD(DBG_INFO, iv->id); + DBGPRINT(F("Devcontrol request 0x")); + DBGPRINT(String(iv->devControlCmd, HEX)); + DBGPRINT(F(" power limit ")); + DBGPRINTLN(String(iv->powerLimit[0])); + } + mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, false); + mPayload[iv->id].txCmd = iv->devControlCmd; + //iv->clearCmdQueue(); + //iv->enqueCommand(SystemConfigPara); // read back power limit + } else { + uint8_t cmd = iv->getQueuedCmd(); + DPRINTHEAD(DBG_INFO, iv->id); + DBGPRINT(F("prepareDevInformCmd 0x")); + DBGPRINTLN(String(cmd, HEX)); + uint8_t cmd2 = cmd; + if (cmd == 0x1 ) { //0x1 + cmd = 0x0f; + cmd2 = 0x00; + mSys->Radio.sendCmdPacket(iv->radioId.u64, cmd, cmd2, false); + } else { + mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd2, mPayload[iv->id].ts, iv->alarmMesIndex, false, cmd); + }; + + mPayload[iv->id].txCmd = cmd; + if (iv->type == INV_TYPE_1CH || iv->type == INV_TYPE_2CH) { + mPayload[iv->id].dataAB[CH1] = false; + mPayload[iv->id].stsAB[CH1] = false; + mPayload[iv->id].dataAB[CH0] = false; + mPayload[iv->id].stsAB[CH0] = false; + } + + if (iv->type == INV_TYPE_2CH) { + mPayload[iv->id].dataAB[CH2] = false; + mPayload[iv->id].stsAB[CH2] = false; + } } } @@ -118,7 +159,7 @@ class MiPayload { //DPRINTLN(DBG_INFO, F("MI got data [0]=") + String(p->packet[0], HEX)); if (p->packet[0] == (0x08 + ALL_FRAMES)) { // 0x88; MI status response to 0x09 - miStsDecode(iv, p, CH1); + miStsDecode(iv, p); } else if (p->packet[0] == (0x11 + SINGLE_FRAME)) { // 0x92; MI status response to 0x11 @@ -177,14 +218,18 @@ const byteAssign_t InfoAssignment[] = { for (uint8_t i = 0; i < 5; i++) { iv->setValue(i, rec, (float) ((p->packet[(12+2*i)] << 8) + p->packet[(13+2*i)])/1); } - iv->setQueuedCmdFinished(); + /*iv->setQueuedCmdFinished(); mStat->rxSuccess++; - mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x01, false); + mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x01, false);*/ } else if ( p->packet[9] == 0x01 ) {//second frame - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") got 2nd frame (hw info)")); - mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x12, false); + DPRINTHEAD(DBG_INFO, iv->id); + DBGPRINTLN(F("got 2nd frame (hw info)")); + //mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x12, false); } else if ( p->packet[9] == 0x12 ) {//3rd frame - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") got 3rd frame (hw info)")); + DPRINTHEAD(DBG_INFO, iv->id); + DBGPRINTLN(F("got 3rd frame (hw info)")); + iv->setQueuedCmdFinished(); + mStat->rxSuccess++; } } else if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command @@ -216,7 +261,8 @@ const byteAssign_t InfoAssignment[] = { } } */ } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command - DPRINTLN(DBG_DEBUG, F("Response from devcontrol request received")); + DPRINTHEAD(DBG_DEBUG, iv->id); + DBGPRINTLN(F("Response from devcontrol request received")); mPayload[iv->id].txId = p->packet[0]; iv->clearDevControlRequest(); @@ -227,7 +273,10 @@ const byteAssign_t InfoAssignment[] = { mApp->setMqttPowerLimitAck(iv); else msg = "NOT "; - DPRINTLN(DBG_INFO, F("Inverter ") + String(iv->id) + F(" has ") + msg + F("accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1])); + //DPRINTLN(DBG_INFO, F("Inverter ") + String(iv->id) + F(" has ") + msg + F("accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1])); + DPRINTHEAD(DBG_INFO, iv->id); + DBGPRINTLN(F("has ") + msg + F("accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1])); + iv->clearCmdQueue(); iv->enqueCommand(SystemConfigPara); // read back power limit } @@ -330,21 +379,20 @@ const byteAssign_t InfoAssignment[] = { if ((mPayload[iv->id].requested) && (retransmit)) { if (iv->devControlCmd == Restart || iv->devControlCmd == CleanState_LockAndAlarm) { // This is required to prevent retransmissions without answer. - DPRINTLN(DBG_INFO, F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); + DPRINTHEAD(DBG_INFO, iv->id); + DBGPRINTLN(F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); mPayload[iv->id].retransmits = mMaxRetrans; } else if(iv->devControlCmd == ActivePowerContr) { - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINTLN(F(") retransmit power limit")); + DPRINTHEAD(DBG_INFO, iv->id); + DBGPRINTLN(F("retransmit power limit")); mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true); } else { uint8_t cmd = mPayload[iv->id].txCmd; if (mPayload[iv->id].retransmits < mMaxRetrans) { mPayload[iv->id].retransmits++; if( !mPayload[iv->id].gotFragment ) { - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINTLN(F(") nothing received")); + DPRINTHEAD(DBG_INFO, iv->id); + DBGPRINTLN(F("nothing received")); mPayload[iv->id].retransmits = mMaxRetrans; } else if ( cmd == 0x0f ) { //hard/firmware request @@ -358,23 +406,23 @@ const byteAssign_t InfoAssignment[] = { change = true; } else if ( cmd == 0x09 ) {//MI single or dual channel device if ( mPayload[iv->id].dataAB[CH1] && iv->type == INV_TYPE_2CH ) { - if (!mPayload[iv->id].stsAB[CH2] || !mPayload[iv->id].dataAB[CH2] ) { + if (!mPayload[iv->id].stsAB[CH1] && mPayload[iv->id].retransmits<2) {} + //first try to get missing sts for first channel a second time + else if (!mPayload[iv->id].stsAB[CH2] || !mPayload[iv->id].dataAB[CH2] ) { cmd = 0x11; change = true; mPayload[iv->id].retransmits = 0; //reset counter } } } else if ( cmd == 0x11) { - if ( mPayload[iv->id].dataAB[CH2] ) { // data is there, but no status - if (!mPayload[iv->id].stsAB[CH1] || !mPayload[iv->id].dataAB[CH1] ) { + if ( mPayload[iv->id].dataAB[CH2] ) { // data + status ch2 are there? + if (mPayload[iv->id].stsAB[CH2] && (!mPayload[iv->id].stsAB[CH1] || !mPayload[iv->id].dataAB[CH1])) { cmd = 0x09; change = true; } } } - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(") ")); + DPRINTHEAD(DBG_INFO, iv->id); if (change) { DBGPRINT(F("next request is 0x")); } else { @@ -392,9 +440,12 @@ const byteAssign_t InfoAssignment[] = { } else if(!crcPass && pyldComplete) { // crc error on complete Payload if (mPayload[iv->id].retransmits < mMaxRetrans) { mPayload[iv->id].retransmits++; - DPRINTLN(DBG_WARN, F("CRC Error: Request Complete Retransmit")); + DPRINTHEAD(DBG_WARN, iv->id); + DBGPRINTLN(F("CRC Error: Request Complete Retransmit")); mPayload[iv->id].txCmd = iv->getQueuedCmd(); - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX)); + DPRINTHEAD(DBG_INFO, iv->id); + + DBGPRINTLN(F("prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX)); mSys->Radio.prepareDevInformCmd(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); } } @@ -470,7 +521,7 @@ const byteAssign_t InfoAssignment[] = { } void miStsDecode(Inverter<> *iv, packet_t *p, uint8_t stschan = CH1) { - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") status msg 0x") + String(p->packet[0], HEX)); + //DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") status msg 0x") + String(p->packet[0], HEX)); record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); // choose the record structure rec->ts = mPayload[iv->id].ts; mPayload[iv->id].gotFragment = true; @@ -491,7 +542,8 @@ const byteAssign_t InfoAssignment[] = { if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){ iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]; // seems there's no status per channel in 3rd gen. models?!? - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") alarm ID incremented to ") + String(iv->alarmMesIndex)); + DPRINTHEAD(DBG_INFO, iv->id); + DBGPRINTLN(F("alarm ID incremented to ") + String(iv->alarmMesIndex)); iv->enqueCommand(AlarmData); } //mPayload[iv->id].skipfirstrepeat = 1; @@ -509,7 +561,7 @@ const byteAssign_t InfoAssignment[] = { ( p->packet[0] == 0x91 || p->packet[0] == (0x37 + ALL_FRAMES) ) ? CH2 : p->packet[0] == (0x38 + ALL_FRAMES) ? CH3 : CH4; - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") data msg 0x") + String(p->packet[0], HEX) + F(" channel ") + datachan); + //DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") data msg 0x") + String(p->packet[0], HEX) + F(" channel ") + datachan); // count in RF_communication_protocol.xlsx is with offset = -1 iv->setValue(iv->getPosByChFld(datachan, FLD_UDC, rec), rec, (float)((p->packet[9] << 8) + p->packet[10])/10); yield(); @@ -567,33 +619,18 @@ const byteAssign_t InfoAssignment[] = { if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){ iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]; - DPRINTLN(DBG_INFO, F("alarm ID incremented to ") + String(iv->alarmMesIndex)); + DPRINTHEAD(DBG_INFO, iv->id); + DBGPRINTLN(F("alarm ID incremented to ") + String(iv->alarmMesIndex)); //iv->enqueCommand(AlarmData); } } - - if ( mPayload[iv->id].complete || //4ch device (iv->type != INV_TYPE_4CH //other devices && mPayload[iv->id].dataAB[CH0] && mPayload[iv->id].stsAB[CH0])) { miComplete(iv); - /*mPayload[iv->id].complete = true; // For 2 CH devices, this might be too short... - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") got all msgs")); - iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0)); - //preliminary AC calculation... - uint8_t ac_pow = 0; - //if (mPayload[iv->id].sts[0] == 3) { - ac_pow = calcPowerDcCh0(iv, 0)*9.5; - //} - iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) (ac_pow/10)); - iv->doCalculations(); - iv->setQueuedCmdFinished(); - mStat->rxSuccess++; - yield(); - notify(mPayload[iv->id].txCmd);*/ } @@ -619,18 +656,18 @@ const byteAssign_t InfoAssignment[] = { DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") got all msgs")); record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0)); - //preliminary AC calculation... - uint8_t ac_pow = 0; + //preliminary AC calculation... + float ac_pow = 0; for(uint8_t i = 1; i <= iv->channels; i++) { if (mPayload[iv->id].sts[i] == 3) { uint8_t pos = iv->getPosByChFld(i, FLD_PDC, rec); ac_pow += iv->getValue(pos, rec); } } - ac_pow = ac_pow*9.5; + ac_pow = (int) (ac_pow*9.5); + iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) ac_pow/10); - iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) (ac_pow/10)); iv->doCalculations(); iv->setQueuedCmdFinished(); mStat->rxSuccess++; @@ -669,8 +706,16 @@ const byteAssign_t InfoAssignment[] = { return true; } +/* void miDPRINTHead(uint8_t lvl, uint8_t id) { + DPRINT(lvl, F("(#")); + DBGPRINT(String(id)); + DBGPRINT(F(") ")); + }*/ + void reset(uint8_t id) { - DPRINTLN(DBG_INFO, F("resetPayload: id: ") + String(id)); + //DPRINTLN(DBG_INFO, F("resetPayload: id: ") + String(id)); + DPRINTHEAD(DBG_INFO, id); + DBGPRINTLN(F("resetPayload")); memset(mPayload[id].len, 0, MAX_PAYLOAD_ENTRIES); mPayload[id].gotFragment = false; /*mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; diff --git a/src/plugins/Display/Display_Mono.cpp b/src/plugins/Display/Display_Mono.cpp index 5af864f6..d55b6061 100644 --- a/src/plugins/Display/Display_Mono.cpp +++ b/src/plugins/Display/Display_Mono.cpp @@ -108,7 +108,7 @@ void DisplayMono::disp(float totalPower, float totalYieldDay, float totalYieldTo if (!(_mExtra % 10) && (ip)) { printText(ip.toString().c_str(), 3); } else if (!(_mExtra % 5)) { - snprintf(_fmtText, DISP_FMT_TEXT_LEN, "#%d Inverter online", isprod); + snprintf(_fmtText, DISP_FMT_TEXT_LEN, "%d Inverter on", isprod); printText(_fmtText, 3); } else { if(mIsLarge && (NULL != mUtcTs)) diff --git a/src/utils/dbg.h b/src/utils/dbg.h index bdfa2b15..56623cf8 100644 --- a/src/utils/dbg.h +++ b/src/utils/dbg.h @@ -146,6 +146,10 @@ }\ }) +#define DPRINTHEAD(level, id) ({\ + DPRINT(level, F("(#")); DBGPRINT(String(id)); DBGPRINT(F(") "));\ +}) + #define DPRINTLN(level, str) ({\ switch(level) {\ case DBG_ERROR: PERRLN(str); break; \ @@ -156,6 +160,37 @@ }\ }) +// available text variables +#define TXT_NOPYLD 1 +#define TXT_INVSERNO 2 +#define TXT_GDEVINF 3 +#define TXT_DEVCTRL 4 +#define TXT_INCRALM 5 + + +#define DBGPRINT_TXT(text) ({\ + switch(text) {\ + case TXT_NOPYLD: DBGPRINT(F("no Payload received! (retransmits: ")); break; \ + case TXT_INVSERNO: DBGPRINT(F("Requesting Inv SN ")); break; \ + case TXT_GDEVINF: DBGPRINT(F("prepareDevInformCmd 0x")); break; \ + case TXT_DEVCTRL: DBGPRINT(F("Devcontrol request 0x")); break; \ + case TXT_INCRALM: DBGPRINT(F("alarm ID incremented to ")); break; \ + default: ; break; \ + }\ +}) + +// available text variables w. lf +#define TXT_TIMEOUT 1 +#define TXT_NOPYLD2 2 + +#define DBGPRINTLN_TXT(text) ({\ + switch(text) {\ + case TXT_TIMEOUT: DBGPRINT(F("enqueued cmd failed/timeout\r\n")); break; \ + case TXT_NOPYLD2: DBGPRINT(F("nothing received\r\n")); break; \ + default: ; break; \ + }\ +}) + /*class ahoyLog { public: ahoyLog() {} From 96eb32ca63b2a6d5163f3950d440b00ed5494526 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 19 Mar 2023 13:16:39 +0100 Subject: [PATCH 29/52] 0.5.103 merged heap improvements #772 --- src/CHANGES.md | 1 + src/publisher/pubMqtt.h | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index cf72d38f..dd5f3e5f 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -5,6 +5,7 @@ ## 0.5.103 * merged MI improvements, thx @rejoe2 #778 * changed display inverter online message +* merged heap improvements #772 ## 0.5.102 * Warning: old exports are not compatible any more! diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index d66f5899..e98b1978 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -210,7 +210,7 @@ class PubMqtt { DPRINTLN(DBG_VERBOSE, F("sendMqttDiscoveryConfig")); char topic[64], name[32], uniq_id[32]; - StaticJsonDocument<256> doc; + DynamicJsonDocument doc(256); uint8_t fldTotal[4] = {FLD_PAC, FLD_YT, FLD_YD, FLD_PDC}; const char* unitTotal[4] = {"W", "kWh", "Wh", "W"}; @@ -267,7 +267,7 @@ class PubMqtt { stateCls = getFieldStateClass(fldTotal[i]); } - StaticJsonDocument<512> doc2; + DynamicJsonDocument doc2(512); doc2[F("name")] = name; doc2[F("stat_t")] = String(mCfgMqtt->topic) + "/" + ((!total) ? String(iv->config->name) : "total" ) + String(topic); doc2[F("unit_of_meas")] = ((!total) ? (iv->getUnit(i,rec)) : (unitTotal[i])); @@ -359,7 +359,7 @@ class PubMqtt { if(NULL == mSubscriptionCb) return; - StaticJsonDocument<128> json; + DynamicJsonDocument json(128); JsonObject root = json.to(); bool limitAbs = false; From 296597a589246b1b753438139ec34484728642b3 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 19 Mar 2023 13:23:42 +0100 Subject: [PATCH 30/52] 0.5.103 fix ESP32 build --- src/publisher/pubMqtt.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index e98b1978..73196918 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -111,7 +111,9 @@ class PubMqtt { publish(subtopics[MQTT_UPTIME], val); publish(subtopics[MQTT_RSSI], String(WiFi.RSSI()).c_str()); publish(subtopics[MQTT_FREE_HEAP], String(ESP.getFreeHeap()).c_str()); + #ifndef ESP32 publish(subtopics[MQTT_HEAP_FRAG], String(ESP.getHeapFragmentation()).c_str()); + #endif } bool tickerSun(uint32_t sunrise, uint32_t sunset, uint32_t offs, bool disNightCom) { From a7bacf1f111f084e50e85e501c6b0ba3a30b9656 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Sun, 19 Mar 2023 13:49:07 +0100 Subject: [PATCH 31/52] MI - dec control plus debug (#4) * restructure serial debug output (partly) + MI - more code review * fix debug output for power control cmds * MI - limitation commands answered * Debug - add more macros and texts Might as well help for https://github.com/lumapu/ahoy/pull/478 Unfortunately, this atm doesn't really lower used flash memory * MI - limit command - now seems to work for MI-600 (to be verified) - debug - more use of macros (wrt. to real effect see last remark) --- src/hm/hmInverter.h | 5 +- src/hm/hmPayload.h | 94 +++++++++++++++++----------- src/hm/hmRadio.h | 37 ++++++++--- src/hm/miPayload.h | 149 +++++++++++++++++++++++++++----------------- src/utils/dbg.h | 67 ++++++++++++++++++-- 5 files changed, 243 insertions(+), 109 deletions(-) diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 18512812..8bb046bb 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -143,7 +143,10 @@ class Inverter { template void enqueCommand(uint8_t cmd) { _commandQueue.push(std::make_shared(cmd)); - DPRINTLN(DBG_INFO, F("(#") + String(id) + F(") enqueuedCmd: 0x") + String(cmd, HEX)); + DPRINTHEAD(DBG_INFO, id); + //DBGPRINTLN(F("enqueuedCmd: 0x") + String(cmd, HEX)); + DBGPRINT_TXT(TXT_ENQUCMD); + DBGHEXLN(cmd); } void setQueuedCmdFinished() { diff --git a/src/hm/hmPayload.h b/src/hm/hmPayload.h index 245a769e..8b75cf47 100644 --- a/src/hm/hmPayload.h +++ b/src/hm/hmPayload.h @@ -117,11 +117,13 @@ class HmPayload { iv->setQueuedCmdFinished(); // command failed if (mSerialDebug) - DPRINTLN(DBG_INFO, F("enqueued cmd failed/timeout")); + DPRINTHEAD(DBG_INFO, iv->id); + DBGPRINTLN_TXT(TXT_TIMEOUT); + //DBGPRINTLN(F("enqueued cmd failed/timeout")); if (mSerialDebug) { - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(") no Payload received! (retransmits: ")); + DPRINTHEAD(DBG_INFO, iv->id); + //DBGPRINT(F("no Payload received! (retransmits: ")); + DBGPRINT_TXT(TXT_NOPYLD); DBGPRINT(String(mPayload[iv->id].retransmits)); DBGPRINTLN(F(")")); } @@ -134,17 +136,17 @@ class HmPayload { yield(); if (mSerialDebug) { - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(") Requesting Inv SN ")); + DPRINTHEAD(DBG_INFO, iv->id); + //DBGPRINT(F("Requesting Inv SN ")); + DBGPRINT_TXT(TXT_INVSERNO); DBGPRINTLN(String(iv->config->serial.u64, HEX)); } if (iv->getDevControlRequest()) { if (mSerialDebug) { - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(") Devcontrol request 0x")); + DPRINTHEAD(DBG_INFO, iv->id); + //DBGPRINT(F("Devcontrol request 0x")); + DBGPRINT_TXT(TXT_DEVCTRL); DBGPRINT(String(iv->devControlCmd, HEX)); DBGPRINT(F(" power limit ")); DBGPRINTLN(String(iv->powerLimit[0])); @@ -155,9 +157,9 @@ class HmPayload { //iv->enqueCommand(SystemConfigPara); // read back power limit } else { uint8_t cmd = iv->getQueuedCmd(); - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(") prepareDevInformCmd 0x")); + DPRINTHEAD(DBG_INFO, iv->id); + //DBGPRINT(F("prepareDevInformCmd 0x")); + DBGPRINT_TXT(TXT_GDEVINF); DBGPRINTLN(String(cmd, HEX)); mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex, false); mPayload[iv->id].txCmd = cmd; @@ -200,14 +202,13 @@ class HmPayload { mApp->setMqttPowerLimitAck(iv); else ok = false; - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(" has ")); + DPRINTHEAD(DBG_INFO,iv->id); + DBGPRINT(F("has ")); if(!ok) DBGPRINT(F("not ")); DBGPRINT(F("accepted power limit set point ")); DBGPRINT(String(iv->powerLimit[0])); DBGPRINT(F(" with PowerLimitControl ")); - DBGPRINT(String(iv->powerLimit[1])); + DBGPRINTLN(String(iv->powerLimit[1])); iv->clearCmdQueue(); iv->enqueCommand(SystemConfigPara); // read back power limit @@ -240,10 +241,14 @@ class HmPayload { mPayload[iv->id].retransmits++; if (iv->devControlCmd == Restart || iv->devControlCmd == CleanState_LockAndAlarm) { // This is required to prevent retransmissions without answer. - DPRINTLN(DBG_INFO, F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); + //DPRINTLN(DBG_INFO, F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); + DPRINTHEAD(DBG_INFO, iv->id); + DBGPRINTLN_TXT(TXT_PREVSND); mPayload[iv->id].retransmits = mMaxRetrans; } else if(iv->devControlCmd == ActivePowerContr) { - DPRINTLN(DBG_INFO, F("retransmit power limit")); + //DPRINTLN(DBG_INFO, F("retransmit power limit")); + DPRINTHEAD(DBG_INFO, iv->id); + DBGPRINTLN_TXT(TXT_RESPLIM); mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true); } else { if(false == mPayload[iv->id].gotFragment) { @@ -253,16 +258,18 @@ class HmPayload { DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX)); mSys->Radio.prepareDevInformCmd(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); */ - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINTLN(F(") nothing received")); + DPRINTHEAD(DBG_INFO, iv->id); + DBGPRINTLN_TXT(TXT_NOPYLD2); mPayload[iv->id].retransmits = mMaxRetrans; } else { for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId - 1); i++) { if (mPayload[iv->id].len[i] == 0) { - DPRINT(DBG_WARN, F("Frame ")); + DPRINTHEAD(DBG_WARN,iv->id); + DBGPRINT(F("Frame ")); DBGPRINT(String(i + 1)); - DBGPRINTLN(F(" missing: Request Retransmit")); + //DBGPRINTLN(F(" missing: Request Retransmit")); + DBGPRINT_TXT(TXT_REQRETR); + DBGPRINT(F("\r\n")); mSys->Radio.sendCmdPacket(iv->radioId.u64, TX_REQ_INFO, (SINGLE_FRAME + i), true); break; // only request retransmit one frame per loop } @@ -275,20 +282,29 @@ class HmPayload { } else if(!crcPass && pyldComplete) { // crc error on complete Payload if (mPayload[iv->id].retransmits < mMaxRetrans) { mPayload[iv->id].retransmits++; - DPRINTLN(DBG_WARN, F("CRC Error: Request Complete Retransmit")); + DPRINTHEAD(DBG_WARN,iv->id); + DBGPRINTLN_TXT(TXT_CRCERR); mPayload[iv->id].txCmd = iv->getQueuedCmd(); - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(") prepareDevInformCmd 0x")); - DBGPRINTLN(String(mPayload[iv->id].txCmd, HEX)); + DPRINTHEAD(DBG_INFO,iv->id); + DBGPRINT_TXT(TXT_GDEVINF); + //DBGPRINTLN(String(mPayload[iv->id].txCmd, HEX)); + DBGHEXLN(mPayload[iv->id].txCmd); mSys->Radio.prepareDevInformCmd(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); } } else { // payload complete - DPRINT(DBG_INFO, F("procPyld: cmd: 0x")); - DBGPRINTLN(String(mPayload[iv->id].txCmd, HEX)); - DPRINT(DBG_INFO, F("procPyld: txid: 0x")); - DBGPRINTLN(String(mPayload[iv->id].txId, HEX)); - DPRINTLN(DBG_DEBUG, F("procPyld: max: ") + String(mPayload[iv->id].maxPackId)); + //DPRINT(DBG_INFO, F("procPyld: cmd: 0x")); + //DBGPRINTLN(String(mPayload[iv->id].txCmd, HEX)); + DPRINT_INIT(DBG_INFO,TXT_PPYDCMD); + DBGHEXLN(mPayload[iv->id].txCmd); + //DPRINT(DBG_INFO, F("procPyld: txid: 0x")); + DPRINT_INIT(DBG_INFO,TXT_PPYDTXI); + //DBGPRINTLN(String(mPayload[iv->id].txId, HEX)); + DBGHEXLN(mPayload[iv->id].txId); + DPRINT_INIT(DBG_DEBUG,TXT_PPYDMAX); + DBGPRINTLN(String(mPayload[iv->id].maxPackId)); + //DPRINT(DBG_DEBUG, F("procPyld: max: ");// + String(mPayload[iv->id].maxPackId)); + //DBGHEXLN(mPayload[iv->id].maxPackId); + record_t<> *rec = iv->getRecordStruct(mPayload[iv->id].txCmd); // choose the parser mPayload[iv->id].complete = true; @@ -312,7 +328,7 @@ class HmPayload { } if (NULL == rec) { - DPRINTLN(DBG_ERROR, F("record is NULL!")); + DPRINTLN_TXT(DBG_ERROR, TXT_NULLREC); } else if ((rec->pyldLen == payloadLen) || (0 == rec->pyldLen)) { if (mPayload[iv->id].txId == (TX_REQ_INFO + ALL_FRAMES)) mStat->rxSuccess++; @@ -364,7 +380,9 @@ class HmPayload { } bool build(uint8_t id, bool *complete) { - DPRINTLN(DBG_VERBOSE, F("build")); + //DPRINTLN(DBG_VERBOSE, F("build")); + DPRINTLN_TXT(DBG_VERBOSE, TXT_BUILD); + uint16_t crc = 0xffff, crcRcv = 0x0000; if (mPayload[id].maxPackId > MAX_PAYLOAD_ENTRIES) mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; @@ -393,8 +411,8 @@ class HmPayload { } void reset(uint8_t id) { - DPRINT(DBG_INFO, "resetPayload: id: "); - DBGPRINTLN(String(id)); + DPRINTHEAD(DBG_INFO,id); + DBGPRINTLN_TXT(TXT_RSTPYLD); memset(mPayload[id].len, 0, MAX_PAYLOAD_ENTRIES); mPayload[id].txCmd = 0; mPayload[id].gotFragment = false; diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 8f528784..40c92889 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -175,18 +175,39 @@ class HmRadio { mSerialDebug = true; } - void sendControlPacket(uint64_t invId, uint8_t cmd, uint16_t *data, bool isRetransmit) { + void sendControlPacket(uint64_t invId, uint8_t cmd, uint16_t *data, bool isRetransmit, bool isNoMI = true) { DPRINT(DBG_INFO, F("sendControlPacket cmd: 0x")); DBGPRINTLN(String(cmd, HEX)); initPacket(invId, TX_REQ_DEVCONTROL, SINGLE_FRAME); uint8_t cnt = 10; - mTxBuf[cnt++] = cmd; // cmd -> 0 on, 1 off, 2 restart, 11 active power, 12 reactive power, 13 power factor - mTxBuf[cnt++] = 0x00; - if(cmd >= ActivePowerContr && cmd <= PFSet) { // ActivePowerContr, ReactivePowerContr, PFSet - mTxBuf[cnt++] = ((data[0] * 10) >> 8) & 0xff; // power limit - mTxBuf[cnt++] = ((data[0] * 10) ) & 0xff; // power limit - mTxBuf[cnt++] = ((data[1] ) >> 8) & 0xff; // setting for persistens handlings - mTxBuf[cnt++] = ((data[1] ) ) & 0xff; // setting for persistens handling + if (isNoMI) { + mTxBuf[cnt++] = cmd; // cmd -> 0 on, 1 off, 2 restart, 11 active power, 12 reactive power, 13 power factor + mTxBuf[cnt++] = 0x00; + if(cmd >= ActivePowerContr && cmd <= PFSet) { // ActivePowerContr, ReactivePowerContr, PFSet + mTxBuf[cnt++] = ((data[0] * 10) >> 8) & 0xff; // power limit + mTxBuf[cnt++] = ((data[0] * 10) ) & 0xff; // power limit + mTxBuf[cnt++] = ((data[1] ) >> 8) & 0xff; // setting for persistens handlings + mTxBuf[cnt++] = ((data[1] ) ) & 0xff; // setting for persistens handling + } + } else { //MI 2nd gen. specific + switch (cmd) { + case TurnOn: + mTxBuf[9] = 0x55; + mTxBuf[10] = 0xaa; + break; + case TurnOff: + mTxBuf[9] = 0xaa; + mTxBuf[10] = 0x55; + break; + case ActivePowerContr: + cnt++; + mTxBuf[9] = 0x5a; + mTxBuf[10] = 0x5a; + mTxBuf[11] = data[0]; // power limit + break; + default: + return; + } } sendPacket(invId, cnt, isRetransmit, true); } diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index 64a345c4..2be3b032 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -15,6 +15,7 @@ typedef struct { uint32_t ts; bool requested; + bool limitrequested; uint8_t txCmd; uint8_t len[MAX_PAYLOAD_ENTRIES]; bool complete; @@ -24,7 +25,7 @@ typedef struct { uint8_t txId; uint8_t invId; uint8_t retransmits; - uint8_t skipfirstrepeat; + //uint8_t skipfirstrepeat; bool gotFragment; /* uint8_t data[MAX_PAYLOAD_ENTRIES][MAX_RF_PAYLOAD_SIZE]; @@ -49,6 +50,7 @@ class MiPayload { mTimestamp = timestamp; for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { reset(i); + mPayload[i].limitrequested = true; } mSerialDebug = false; mHighPrioIv = NULL; @@ -68,7 +70,7 @@ class MiPayload { } void loop() { - if(NULL != mHighPrioIv) { + if(NULL != mHighPrioIv) { // && mHighPrioIv->ivGen == IV_MI) { ivSend(mHighPrioIv, true); // for devcontrol commands? mHighPrioIv = NULL; } @@ -93,10 +95,12 @@ class MiPayload { iv->setQueuedCmdFinished(); // command failed if (mSerialDebug) DPRINTHEAD(DBG_INFO, iv->id); - DBGPRINTLN(F("enqueued cmd failed/timeout")); + //DBGPRINTLN(F("enqueued cmd failed/timeout")); + DBGPRINTLN_TXT(TXT_TIMEOUT); if (mSerialDebug) { DPRINTHEAD(DBG_INFO, iv->id); - DBGPRINT(F("no Payload received! (retransmits: ")); + //DBGPRINT(F("no Payload received! (retransmits: ")); + DBGPRINT_TXT(TXT_NOPYLD); DBGPRINT(String(mPayload[iv->id].retransmits)); DBGPRINTLN(F(")")); } @@ -110,31 +114,44 @@ class MiPayload { yield(); if (mSerialDebug){ DPRINTHEAD(DBG_INFO, iv->id); - DBGPRINT(F("Requesting Inv SN ")); + //DBGPRINT(F("Requesting Inv SN ")); + DBGPRINT_TXT(TXT_INVSERNO); DBGPRINTLN(String(iv->config->serial.u64, HEX)); } if (iv->getDevControlRequest()) { if (mSerialDebug) { DPRINTHEAD(DBG_INFO, iv->id); - DBGPRINT(F("Devcontrol request 0x")); - DBGPRINT(String(iv->devControlCmd, HEX)); + //DBGPRINT(F("Devcontrol request 0x")); + DBGPRINT_TXT(TXT_DEVCTRL); + DHEX(iv->devControlCmd); DBGPRINT(F(" power limit ")); DBGPRINTLN(String(iv->powerLimit[0])); } - mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, false); + mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, false, false); mPayload[iv->id].txCmd = iv->devControlCmd; - //iv->clearCmdQueue(); - //iv->enqueCommand(SystemConfigPara); // read back power limit + mPayload[iv->id].limitrequested = true; + + iv->clearCmdQueue(); + iv->enqueCommand(SystemConfigPara); // try to read back power limit } else { uint8_t cmd = iv->getQueuedCmd(); DPRINTHEAD(DBG_INFO, iv->id); - DBGPRINT(F("prepareDevInformCmd 0x")); - DBGPRINTLN(String(cmd, HEX)); + DBGPRINT_TXT(TXT_GDEVINF); + DBGHEXLN(cmd); uint8_t cmd2 = cmd; - if (cmd == 0x1 ) { //0x1 - cmd = 0x0f; - cmd2 = 0x00; + if ( cmd == SystemConfigPara ) { //0x05 for HM-types + if (!mPayload[iv->id].limitrequested) { // only do once at startup + iv->setQueuedCmdFinished(); + cmd = iv->getQueuedCmd(); + } else { + mPayload[iv->id].limitrequested = false; + } + } + + if (cmd == 0x1 || cmd == SystemConfigPara ) { //0x1 and 0x05 for HM-types + cmd = 0x0f; // for MI, these seem to make part of the Polling the device software and hardware version number command + cmd2 = cmd == SystemConfigPara ? 0x01 : 0x00; //perhaps we can only try to get second frame? mSys->Radio.sendCmdPacket(iv->radioId.u64, cmd, cmd2, false); } else { mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd2, mPayload[iv->id].ts, iv->alarmMesIndex, false, cmd); @@ -218,13 +235,25 @@ const byteAssign_t InfoAssignment[] = { for (uint8_t i = 0; i < 5; i++) { iv->setValue(i, rec, (float) ((p->packet[(12+2*i)] << 8) + p->packet[(13+2*i)])/1); } + iv->isConnected = true; + DPRINTHEAD(DBG_INFO, iv->id); + DPRINT(DBG_INFO,F("HW_VER is ")); + DBGPRINTLN(String((p->packet[24] << 8) + p->packet[25])); /*iv->setQueuedCmdFinished(); - mStat->rxSuccess++; mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x01, false);*/ } else if ( p->packet[9] == 0x01 ) {//second frame DPRINTHEAD(DBG_INFO, iv->id); DBGPRINTLN(F("got 2nd frame (hw info)")); - //mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x12, false); + // xlsx: HW_ECapValue is total energy?!? (data coll. inst. #154) + DPRINT(DBG_INFO,F("HW_ECapValue ")); + DBGPRINTLN(String((p->packet[20] << 8) + p->packet[21])); + iv->setValue(iv->getPosByChFld(0, FLD_YT, rec), rec, (float) ((p->packet[20] << 8) + p->packet[21])/1); + DPRINT(DBG_INFO,F("HW_FB_TLmValue ")); + DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15])); + DPRINT(DBG_INFO,F("HW_FB_ReSPRT ")); + DBGPRINTLN(String((p->packet[16] << 8) + p->packet[17])); + DPRINT(DBG_INFO,F("HW_GridSamp_ResValule ")); + DBGPRINTLN(String((p->packet[18] << 8) + p->packet[19])); } else if ( p->packet[9] == 0x12 ) {//3rd frame DPRINTHEAD(DBG_INFO, iv->id); DBGPRINTLN(F("got 3rd frame (hw info)")); @@ -260,31 +289,34 @@ const byteAssign_t InfoAssignment[] = { } } } */ - } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command + } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES ) // response from dev control command + || p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES -1)) { // response from DRED instruction DPRINTHEAD(DBG_DEBUG, iv->id); DBGPRINTLN(F("Response from devcontrol request received")); mPayload[iv->id].txId = p->packet[0]; iv->clearDevControlRequest(); - if ((p->packet[12] == ActivePowerContr) && (p->packet[13] == 0x00)) { - String msg = ""; - if((p->packet[10] == 0x00) && (p->packet[11] == 0x00)) - mApp->setMqttPowerLimitAck(iv); - else - msg = "NOT "; - //DPRINTLN(DBG_INFO, F("Inverter ") + String(iv->id) + F(" has ") + msg + F("accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1])); + if ((p->packet[9] == 0x5a) && (p->packet[10] == 0x5a)) { + mApp->setMqttPowerLimitAck(iv); DPRINTHEAD(DBG_INFO, iv->id); - DBGPRINTLN(F("has ") + msg + F("accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1])); + DBGPRINT(F("has accepted power limit set point ")); + DBGPRINT(String(iv->powerLimit[0])); + DBGPRINT(F(" with PowerLimitControl ")); + DBGPRINTLN(String(iv->powerLimit[1])); iv->clearCmdQueue(); iv->enqueCommand(SystemConfigPara); // read back power limit } iv->devControlCmd = Init; } else { // some other response; copied from hmPayload:process; might not be correct to do that here!!! - DPRINTLN(DBG_INFO, F("procPyld: cmd: 0x") + String(mPayload[iv->id].txCmd, HEX)); - DPRINTLN(DBG_INFO, F("procPyld: txid: 0x") + String(mPayload[iv->id].txId, HEX)); + //DPRINTLN(DBG_INFO, F("procPyld: cmd: 0x") + String(mPayload[iv->id].txCmd, HEX)); + //DPRINTLN(DBG_INFO, F("procPyld: txid: 0x") + String(mPayload[iv->id].txId, HEX)); //DPRINTLN(DBG_DEBUG, F("procPyld: max: ") + String(mPayload[iv->id].maxPackId)); + DPRINT_INIT(DBG_INFO,TXT_PPYDCMD); + DBGHEXLN(mPayload[iv->id].txCmd); + DBGPRINT_TXT(TXT_PPYDTXI); + DBGHEXLN(mPayload[iv->id].txId); record_t<> *rec = iv->getRecordStruct(mPayload[iv->id].txCmd); // choose the parser mPayload[iv->id].complete = true; @@ -306,7 +338,7 @@ const byteAssign_t InfoAssignment[] = { } if (NULL == rec) { - DPRINTLN(DBG_ERROR, F("record is NULL!")); + DPRINTLN_TXT(DBG_ERROR, TXT_NULLREC); } else if ((rec->pyldLen == payloadLen) || (0 == rec->pyldLen)) { if (mPayload[iv->id].txId == (TX_REQ_INFO + ALL_FRAMES)) mStat->rxSuccess++; @@ -366,10 +398,10 @@ const byteAssign_t InfoAssignment[] = { //delayed next message? //mPayload[iv->id].skipfirstrepeat++; - if (mPayload[iv->id].skipfirstrepeat) { - mPayload[iv->id].skipfirstrepeat = 0; //reset counter*/ + /*if (mPayload[iv->id].skipfirstrepeat) { + mPayload[iv->id].skipfirstrepeat = 0; //reset counter continue; // skip to next inverter - } + }*/ if (!mPayload[iv->id].complete) { //DPRINTLN(DBG_INFO, F("Pyld incompl code")); //info for testing only @@ -380,19 +412,19 @@ const byteAssign_t InfoAssignment[] = { if (iv->devControlCmd == Restart || iv->devControlCmd == CleanState_LockAndAlarm) { // This is required to prevent retransmissions without answer. DPRINTHEAD(DBG_INFO, iv->id); - DBGPRINTLN(F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); + DBGPRINTLN_TXT(TXT_PREVSND); mPayload[iv->id].retransmits = mMaxRetrans; } else if(iv->devControlCmd == ActivePowerContr) { DPRINTHEAD(DBG_INFO, iv->id); - DBGPRINTLN(F("retransmit power limit")); - mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true); + DBGPRINTLN_TXT(TXT_RESPLIM); + mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true, false); } else { uint8_t cmd = mPayload[iv->id].txCmd; if (mPayload[iv->id].retransmits < mMaxRetrans) { mPayload[iv->id].retransmits++; if( !mPayload[iv->id].gotFragment ) { DPRINTHEAD(DBG_INFO, iv->id); - DBGPRINTLN(F("nothing received")); + DBGPRINTLN_TXT(TXT_NOPYLD2); mPayload[iv->id].retransmits = mMaxRetrans; } else if ( cmd == 0x0f ) { //hard/firmware request @@ -424,11 +456,15 @@ const byteAssign_t InfoAssignment[] = { } DPRINTHEAD(DBG_INFO, iv->id); if (change) { - DBGPRINT(F("next request is 0x")); + DBGPRINT(F("next request is")); + //mPayload[iv->id].skipfirstrepeat = 0; } else { - DBGPRINT(F("not complete: Request Retransmit 0x")); + DBGPRINT(F("sth.")); + DBGPRINT_TXT(TXT_REQRETR); } - DBGPRINTLN(String(cmd, HEX)); + //DBGPRINTLN(String(cmd, HEX)); + DBGPRINT(F(" 0x")); + DBGHEXLN(cmd); //mSys->Radio.sendCmdPacket(iv->radioId.u64, cmd, cmd, true); mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex, true, cmd); mPayload[iv->id].txCmd = cmd; @@ -441,11 +477,14 @@ const byteAssign_t InfoAssignment[] = { if (mPayload[iv->id].retransmits < mMaxRetrans) { mPayload[iv->id].retransmits++; DPRINTHEAD(DBG_WARN, iv->id); - DBGPRINTLN(F("CRC Error: Request Complete Retransmit")); + DBGPRINTLN_TXT(TXT_CRCERR); + //DBGPRINTLN(F("CRC Error: Request Complete Retransmit")); mPayload[iv->id].txCmd = iv->getQueuedCmd(); DPRINTHEAD(DBG_INFO, iv->id); - DBGPRINTLN(F("prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX)); + DBGPRINT_TXT(TXT_GDEVINF); + //DBGPRINTLN(F("prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX)); + DBGPRINTLN(String(mPayload[iv->id].txCmd, HEX)); mSys->Radio.prepareDevInformCmd(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); } } @@ -543,8 +582,9 @@ const byteAssign_t InfoAssignment[] = { iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]; // seems there's no status per channel in 3rd gen. models?!? DPRINTHEAD(DBG_INFO, iv->id); - DBGPRINTLN(F("alarm ID incremented to ") + String(iv->alarmMesIndex)); - iv->enqueCommand(AlarmData); + DBGPRINT_TXT(TXT_INCRALM); + DBGPRINTLN(String(iv->alarmMesIndex)); + //iv->enqueCommand(AlarmData); Would just start with second channel request 0x11... } //mPayload[iv->id].skipfirstrepeat = 1; if (mPayload[iv->id].stsAB[CH0] && mPayload[iv->id].dataAB[CH0] && !mPayload[iv->id].complete) { @@ -615,13 +655,12 @@ const byteAssign_t InfoAssignment[] = { mPayload[iv->id].complete = true; } - //iv->setValue(iv->getPosByChFld(0, FLD_EVT, rec), rec, calcMiSts(iv));yield(); if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){ iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]; DPRINTHEAD(DBG_INFO, iv->id); - DBGPRINTLN(F("alarm ID incremented to ") + String(iv->alarmMesIndex)); - //iv->enqueCommand(AlarmData); + DBGPRINT_TXT(TXT_INCRALM); + DBGPRINTLN(String(iv->alarmMesIndex)); } } @@ -652,8 +691,11 @@ const byteAssign_t InfoAssignment[] = { } void miComplete(Inverter<> *iv) { + if (mPayload[iv->id].complete) + return; //if we got second message as well in repreated attempt mPayload[iv->id].complete = true; // For 2 CH devices, this might be too short... - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") got all msgs")); + DPRINTHEAD(DBG_INFO, iv->id); + DBGPRINTLN(F("got all msgs")); record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0)); @@ -676,7 +718,7 @@ const byteAssign_t InfoAssignment[] = { } bool build(uint8_t id, bool *complete) { - DPRINTLN(DBG_VERBOSE, F("build")); + DPRINTLN_TXT(DBG_VERBOSE, TXT_BUILD); /*uint16_t crc = 0xffff, crcRcv = 0x0000; if (mPayload[id].maxPackId > MAX_PAYLOAD_ENTRIES) mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; @@ -706,16 +748,9 @@ const byteAssign_t InfoAssignment[] = { return true; } -/* void miDPRINTHead(uint8_t lvl, uint8_t id) { - DPRINT(lvl, F("(#")); - DBGPRINT(String(id)); - DBGPRINT(F(") ")); - }*/ - void reset(uint8_t id) { - //DPRINTLN(DBG_INFO, F("resetPayload: id: ") + String(id)); DPRINTHEAD(DBG_INFO, id); - DBGPRINTLN(F("resetPayload")); + DBGPRINTLN_TXT(TXT_RSTPYLD); memset(mPayload[id].len, 0, MAX_PAYLOAD_ENTRIES); mPayload[id].gotFragment = false; /*mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; @@ -729,7 +764,7 @@ const byteAssign_t InfoAssignment[] = { mPayload[id].stsAB[CH1] = true; //required for 1CH and 2CH devices mPayload[id].stsAB[CH2] = true; //only required for 2CH devices mPayload[id].txCmd = 0; - mPayload[id].skipfirstrepeat = 0; + //mPayload[id].skipfirstrepeat = 0; mPayload[id].requested = false; mPayload[id].ts = *mTimestamp; mPayload[id].sts[0] = 0; diff --git a/src/utils/dbg.h b/src/utils/dbg.h index 56623cf8..97450cd8 100644 --- a/src/utils/dbg.h +++ b/src/utils/dbg.h @@ -60,6 +60,11 @@ mCb(String(b, HEX)); } } + + inline void DBGHEXLN(uint8_t b) { + DHEX(b); + DBGPRINT(F("\r\n")); + } /*inline void DHEX(uint16_t b) { if( b<0x10 ) DSERIAL.print(F("000")); else if( b<0x100 ) DSERIAL.print(F("00")); @@ -146,6 +151,16 @@ }\ }) +#define DPRINT_INIT(level,text) ({\ + DPRINT(level,F(""));\ + DBGPRINT_TXT(text);\ +}) + +#define DPRINTLN_TXT(level,text) ({\ + DPRINT(level,F(""));\ + DBGPRINTLN_TXT(text);\ +}) + #define DPRINTHEAD(level, id) ({\ DPRINT(level, F("(#")); DBGPRINT(String(id)); DBGPRINT(F(") "));\ }) @@ -160,12 +175,34 @@ }\ }) + // available text variables -#define TXT_NOPYLD 1 +#define TXT_ENQUCMD 6 #define TXT_INVSERNO 2 +#define TXT_REQRETR 7 +#define TXT_PPYDMAX 10 +#define TXT_NOPYLD 1 + #define TXT_GDEVINF 3 #define TXT_DEVCTRL 4 #define TXT_INCRALM 5 +#define TXT_PPYDCMD 8 +#define TXT_PPYDTXI 9 + + +/* DBGPRINT(F(" power limit ")); +DPRINTLN(DBG_DEBUG, F("Response from info request received")); + +DBGPRINTLN(F("Response from devcontrol request received")); + DPRINT(DBG_DEBUG, F("fragment number zero received")); + DBGPRINT(F("has accepted power limit set point ")); + DBGPRINT(F(" with PowerLimitControl ")); + DPRINT(DBG_INFO, F("Payload (") + String(payloadLen) + "): "); + DPRINTLN(DBG_ERROR, F("plausibility check failed, expected ") + String(rec->pyldLen) + F(" bytes")); + + DPRINTLN(DBG_VERBOSE, F("incomlete, txCmd is 0x") + String(txCmd, HEX)); // + F("cmd is 0x") + String(cmd, HEX)); +*/ + #define DBGPRINT_TXT(text) ({\ @@ -175,18 +212,38 @@ case TXT_GDEVINF: DBGPRINT(F("prepareDevInformCmd 0x")); break; \ case TXT_DEVCTRL: DBGPRINT(F("Devcontrol request 0x")); break; \ case TXT_INCRALM: DBGPRINT(F("alarm ID incremented to ")); break; \ + case TXT_ENQUCMD: DBGPRINT(F("enqueuedCmd: 0x")); break; \ + case TXT_REQRETR: DBGPRINT(F(" missing: Request Retransmit")); break; \ + case TXT_PPYDCMD: DBGPRINT(F("procPyld: cmd: 0x")); break; \ + case TXT_PPYDTXI: DBGPRINT(F("procPyld: txid: 0x")); break; \ + case TXT_PPYDMAX: DBGPRINT(F("procPyld: max: ")); break; \ default: ; break; \ }\ }) + // available text variables w. lf -#define TXT_TIMEOUT 1 -#define TXT_NOPYLD2 2 +#define TXT_BUILD 1 +#define TXT_TIMEOUT 2 +#define TXT_NOPYLD2 3 +#define TXT_CRCERR 4 +#define TXT_RSTPYLD 5 +#define TXT_NULLREC 7 +#define TXT_PREVSND 8 +#define TXT_RESPLIM 9 + +//resetPayload #define DBGPRINTLN_TXT(text) ({\ switch(text) {\ - case TXT_TIMEOUT: DBGPRINT(F("enqueued cmd failed/timeout\r\n")); break; \ - case TXT_NOPYLD2: DBGPRINT(F("nothing received\r\n")); break; \ + case TXT_TIMEOUT: DBGPRINTLN(F("enqueued cmd failed/timeout")); break; \ + case TXT_BUILD: DBGPRINTLN(F("build")); break; \ + case TXT_NOPYLD2: DBGPRINTLN(F("nothing received")); break; \ + case TXT_RSTPYLD: DBGPRINTLN(F("resetPayload"));break; \ + case TXT_CRCERR: DBGPRINTLN(F("CRC Error: Request Complete Retransmit")); break; \ + case TXT_NULLREC: DBGPRINTLN(F("record is NULL!")); break; \ + case TXT_PREVSND: DBGPRINTLN(F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); break; \ + case TXT_RESPLIM: DBGPRINTLN(F("retransmit power limit")); break; \ default: ; break; \ }\ }) From a6b8794855ad5f912255d9a44199807528acc9ce Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 19 Mar 2023 21:49:39 +0100 Subject: [PATCH 32/52] 0.5.104 * further improved save settings * removed `#` character from ePaper * fixed saving pinout for `Nokia-Display` * removed `Reset` Pin for monochrome displays --- src/CHANGES.md | 6 +++ src/defines.h | 2 +- src/plugins/Display/Display_ePaper.cpp | 2 +- src/web/RestApi.h | 64 +++----------------------- src/web/html/save.html | 51 ++++++++++++++++++++ src/web/html/setup.html | 25 +++++----- src/web/web.h | 20 +++----- 7 files changed, 85 insertions(+), 85 deletions(-) create mode 100644 src/web/html/save.html diff --git a/src/CHANGES.md b/src/CHANGES.md index dd5f3e5f..fd855e3c 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -2,6 +2,12 @@ (starting from release version `0.5.66`) +## 0.5.104 +* further improved save settings +* removed `#` character from ePaper +* fixed saving pinout for `Nokia-Display` +* removed `Reset` Pin for monochrome displays + ## 0.5.103 * merged MI improvements, thx @rejoe2 #778 * changed display inverter online message diff --git a/src/defines.h b/src/defines.h index 56a05970..f29f6ea5 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 5 -#define VERSION_PATCH 103 +#define VERSION_PATCH 104 //------------------------------------- typedef struct { diff --git a/src/plugins/Display/Display_ePaper.cpp b/src/plugins/Display/Display_ePaper.cpp index fea372cd..a2254b8d 100644 --- a/src/plugins/Display/Display_ePaper.cpp +++ b/src/plugins/Display/Display_ePaper.cpp @@ -168,7 +168,7 @@ void DisplayEPaper::actualPowerPaged(float _totalPower, float _totalYieldDay, fl _display->println("kWh"); _display->setCursor(0, _display->height() - (mHeadFootPadding + 10)); - snprintf(_fmtText, sizeof(_fmtText), "#%d Inverter online", _isprod); + snprintf(_fmtText, sizeof(_fmtText), "%d Inverter online", _isprod); _display->println(_fmtText); } while (_display->nextPage()); diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 2d61c623..01c1726e 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -80,7 +80,6 @@ class RestApi { if(path == "html/system") getHtmlSystem(root); else if(path == "html/logout") getHtmlLogout(root); else if(path == "html/save") getHtmlSave(root); - else if(path == "html/chk_save") getHtmlSave(root); else if(path == "system") getSysInfo(root); else if(path == "generic") getGeneric(root); else if(path == "reboot") getReboot(root); @@ -267,12 +266,8 @@ class RestApi { void getHtmlSave(JsonObject obj) { getGeneric(obj.createNestedObject(F("generic"))); - obj[F("refresh")] = 1; - obj[F("refresh_url")] = mApp->getSavePending() ? F("/chk_save") : F("/setup"); - if(mApp->getSavePending()) - obj[F("html")] = F("saving settings ..."); - else - obj[F("html")] = mApp->getLastSaveSucceed() ? F("settings succesfully saved") : F("failed saving settings"); + obj["pending"] = (bool)mApp->getSavePending(); + obj["success"] = (bool)mApp->getLastSaveSucceed(); } void getReboot(JsonObject obj) { @@ -417,10 +412,10 @@ class RestApi { obj[F("disp_cont")] = (uint8_t)mConfig->plugin.display.contrast; obj[F("disp_clk")] = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : mConfig->plugin.display.disp_clk; obj[F("disp_data")] = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : mConfig->plugin.display.disp_data; - obj[F("disp_cs")] = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : mConfig->plugin.display.disp_cs; - obj[F("disp_dc")] = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : mConfig->plugin.display.disp_dc; - obj[F("disp_rst")] = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : mConfig->plugin.display.disp_reset; - obj[F("disp_bsy")] = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : mConfig->plugin.display.disp_busy; + obj[F("disp_cs")] = (mConfig->plugin.display.type < 3) ? DEF_PIN_OFF : mConfig->plugin.display.disp_cs; + obj[F("disp_dc")] = (mConfig->plugin.display.type < 3) ? DEF_PIN_OFF : mConfig->plugin.display.disp_dc; + obj[F("disp_rst")] = (mConfig->plugin.display.type < 3) ? DEF_PIN_OFF : mConfig->plugin.display.disp_reset; + obj[F("disp_bsy")] = (mConfig->plugin.display.type < 10) ? DEF_PIN_OFF : mConfig->plugin.display.disp_busy; } void getIndex(JsonObject obj) { @@ -492,7 +487,6 @@ class RestApi { void getLive(JsonObject obj) { getGeneric(obj.createNestedObject(F("generic"))); - //JsonArray invArr = obj.createNestedArray(F("inverter")); obj[F("refresh")] = mConfig->nrf.sendInterval; for (uint8_t fld = 0; fld < sizeof(acList); fld++) { @@ -512,52 +506,6 @@ class RestApi { parse = iv->config->enabled; obj[F("iv")][i] = parse; } - - /*Inverter<> *iv; - uint8_t pos; - for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) { - iv = mSys->getInverterByPos(i); - if(NULL != iv) { - record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); - JsonObject obj2 = invArr.createNestedObject(); - obj2[F("enabled")] = (bool)iv->config->enabled; - obj2[F("name")] = String(iv->config->name); - obj2[F("channels")] = iv->channels; - obj2[F("power_limit_read")] = ah::round3(iv->actPowerLimit); - //obj2[F("last_alarm")] = String(iv->lastAlarmMsg); - obj2[F("ts_last_success")] = rec->ts; - - JsonArray ch = obj2.createNestedArray("ch"); - JsonArray ch0 = ch.createNestedArray(); - obj2[F("ch_names")][0] = "AC"; - for (uint8_t fld = 0; fld < sizeof(list); fld++) { - pos = (iv->getPosByChFld(CH0, list[fld], rec)); - ch0[fld] = (0xff != pos) ? ah::round3(iv->getValue(pos, rec)) : 0.0; - obj[F("ch0_fld_units")][fld] = (0xff != pos) ? String(iv->getUnit(pos, rec)) : notAvail; - obj[F("ch0_fld_names")][fld] = (0xff != pos) ? String(iv->getFieldName(pos, rec)) : notAvail; - } - - for(uint8_t j = 1; j <= iv->channels; j ++) { - obj2[F("ch_names")][j] = String(iv->config->chName[j-1]); - JsonArray cur = ch.createNestedArray(); - for (uint8_t k = 0; k < 6; k++) { - switch(k) { - default: pos = (iv->getPosByChFld(j, FLD_UDC, rec)); break; - case 1: pos = (iv->getPosByChFld(j, FLD_IDC, rec)); break; - case 2: pos = (iv->getPosByChFld(j, FLD_PDC, rec)); break; - case 3: pos = (iv->getPosByChFld(j, FLD_YD, rec)); break; - case 4: pos = (iv->getPosByChFld(j, FLD_YT, rec)); break; - case 5: pos = (iv->getPosByChFld(j, FLD_IRR, rec)); break; - } - cur[k] = (0xff != pos) ? ah::round3(iv->getValue(pos, rec)) : 0.0; - if(1 == j) { - obj[F("fld_units")][k] = (0xff != pos) ? String(iv->getUnit(pos, rec)) : notAvail; - obj[F("fld_names")][k] = (0xff != pos) ? String(iv->getFieldName(pos, rec)) : notAvail; - } - } - } - } - }*/ } void getRecord(JsonObject obj, uint8_t recType) { diff --git a/src/web/html/save.html b/src/web/html/save.html new file mode 100644 index 00000000..54d43d7f --- /dev/null +++ b/src/web/html/save.html @@ -0,0 +1,51 @@ + + + + Save + {#HTML_HEADER} + + + {#HTML_NAV} +
+
+
+
+
+ {#HTML_FOOTER} + + + diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 93841461..a335f76f 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -692,22 +692,23 @@ } function hideDispPins(pins, dispType) { - if(0 == dispType) { - for(p of pins) { - document.getElementById("row_" + p[1]).classList.add("hide"); - } - } else if(2 >= dispType) { - for(var i = 0; i < pins.length; i++) { - var cl = document.getElementById("row_" + pins[i][1]).classList; + for(var i = 0; i < pins.length; i++) { + var cl = document.getElementById("row_" + pins[i][1]).classList; + + if(0 == dispType) + cl.add("hide"); + else if(dispType <= 2) { // OLED if(i < 2) cl.remove("hide"); else cl.add("hide"); - } - } else { - for(p of pins) { - document.getElementById("row_" + p[1]).classList.remove("hide"); - } + } else if(dispType == 3) { // Nokia + if(i < 4) + cl.remove("hide"); + else + cl.add("hide"); + } else // ePaper + cl.remove("hide"); } } diff --git a/src/web/web.h b/src/web/web.h index 6ba495af..91818b96 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -27,6 +27,7 @@ #include "html/h/setup_html.h" #include "html/h/style_css.h" #include "html/h/system_html.h" +#include "html/h/save_html.h" #include "html/h/update_html.h" #include "html/h/visualization_html.h" @@ -68,7 +69,6 @@ class Web { mWeb.on("/setup", HTTP_GET, std::bind(&Web::onSetup, this, std::placeholders::_1)); mWeb.on("/save", HTTP_POST, std::bind(&Web::showSave, this, std::placeholders::_1)); - mWeb.on("/chk_save", HTTP_GET, std::bind(&Web::onCheckSave, this, std::placeholders::_1)); mWeb.on("/live", HTTP_ANY, std::bind(&Web::onLive, this, std::placeholders::_1)); //mWeb.on("/api1", HTTP_POST, std::bind(&Web::showWebApi, this, std::placeholders::_1)); @@ -327,7 +327,7 @@ class Web { mProtected = true; - AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), system_html, system_html_len); + AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), save_html, save_html_len); response->addHeader(F("Content-Encoding"), "gzip"); request->send(response); } @@ -375,7 +375,7 @@ class Web { void onReboot(AsyncWebServerRequest *request) { mApp->setRebootFlag(); - AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), system_html, system_html_len); + AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), save_html, save_html_len); response->addHeader(F("Content-Encoding"), "gzip"); request->send(response); } @@ -586,20 +586,14 @@ class Web { mConfig->plugin.display.contrast = (mConfig->plugin.display.type == 0) ? 60 : request->arg("disp_cont").toInt(); mConfig->plugin.display.disp_data = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : request->arg("disp_data").toInt(); mConfig->plugin.display.disp_clk = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : request->arg("disp_clk").toInt(); - mConfig->plugin.display.disp_cs = (mConfig->plugin.display.type < 4) ? DEF_PIN_OFF : request->arg("disp_cs").toInt(); - mConfig->plugin.display.disp_reset = (mConfig->plugin.display.type < 4) ? DEF_PIN_OFF : request->arg("disp_rst").toInt(); - mConfig->plugin.display.disp_dc = (mConfig->plugin.display.type < 4) ? DEF_PIN_OFF : request->arg("disp_dc").toInt(); + mConfig->plugin.display.disp_cs = (mConfig->plugin.display.type < 3) ? DEF_PIN_OFF : request->arg("disp_cs").toInt(); + mConfig->plugin.display.disp_reset = (mConfig->plugin.display.type < 3) ? DEF_PIN_OFF : request->arg("disp_rst").toInt(); + mConfig->plugin.display.disp_dc = (mConfig->plugin.display.type < 3) ? DEF_PIN_OFF : request->arg("disp_dc").toInt(); mConfig->plugin.display.disp_busy = (mConfig->plugin.display.type < 10) ? DEF_PIN_OFF : request->arg("disp_bsy").toInt(); mApp->saveSettings((request->arg("reboot") == "on")); - AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), system_html, system_html_len); - response->addHeader(F("Content-Encoding"), "gzip"); - request->send(response); - } - - void onCheckSave(AsyncWebServerRequest *request) { - AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), system_html, system_html_len); + AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), save_html, save_html_len); response->addHeader(F("Content-Encoding"), "gzip"); request->send(response); } From 25695fc30a1d5e31345b5f6772270c79da9e3711 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 19 Mar 2023 22:11:21 +0100 Subject: [PATCH 33/52] 0.5.104 * improved wifi connection #652 --- src/CHANGES.md | 1 + src/wifi/ahoywifi.cpp | 14 ++++++++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index fd855e3c..0af4746b 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -7,6 +7,7 @@ * removed `#` character from ePaper * fixed saving pinout for `Nokia-Display` * removed `Reset` Pin for monochrome displays +* improved wifi connection #652 ## 0.5.103 * merged MI improvements, thx @rejoe2 #778 diff --git a/src/wifi/ahoywifi.cpp b/src/wifi/ahoywifi.cpp index 9109c831..0acdf9e2 100644 --- a/src/wifi/ahoywifi.cpp +++ b/src/wifi/ahoywifi.cpp @@ -88,12 +88,11 @@ void ahoywifi::tickWifiLoop() { } mCnt++; - uint8_t timeout = 10; // seconds + uint8_t timeout = (mStaConn == DISCONNECTED) ? 10 : 20; // seconds if (mStaConn == CONNECTED) // connected but no ip timeout = 20; - - if(!mScanActive && mBSSIDList.empty() && ((mCnt % timeout) == 0)) { // start scanning APs with the given SSID + if(!mScanActive && mBSSIDList.empty() && (mStaConn == DISCONNECTED)) { // start scanning APs with the given SSID DBGPRINT(F("scanning APs with SSID ")); DBGPRINTLN(String(mConfig->sys.stationSsid)); mScanCnt = 0; @@ -115,8 +114,9 @@ void ahoywifi::tickWifiLoop() { mCnt = timeout - 2; } if((mCnt % timeout) == 0) { // try to reconnect after x sec without connection - if(mStaConn != CONNECTED) - mStaConn = CONNECTING; + mStaConn = CONNECTING; + WiFi.disconnect(); + if(mBSSIDList.size() > 0) { // get first BSSID in list DBGPRINT(F("try to connect to AP with BSSID:")); uint8_t bssid[6]; @@ -126,9 +126,11 @@ void ahoywifi::tickWifiLoop() { DBGPRINT(" " + String(bssid[j], HEX)); } DBGPRINTLN(""); - WiFi.disconnect(); WiFi.begin(mConfig->sys.stationSsid, mConfig->sys.stationPwd, 0, &bssid[0]); } + else + mStaConn = DISCONNECTED; + mCnt = 0; } } From 0526a5191af34efcfeef59627309c66ccc81db5f Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 20 Mar 2023 14:05:35 +0100 Subject: [PATCH 34/52] Create Dockerfile --- tools/rpi/Dockerfile | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tools/rpi/Dockerfile diff --git a/tools/rpi/Dockerfile b/tools/rpi/Dockerfile new file mode 100644 index 00000000..8fa89661 --- /dev/null +++ b/tools/rpi/Dockerfile @@ -0,0 +1,15 @@ +############################ +# build executable binary +############################ + +FROM python:slim-bullseye + +COPY . /hoymiles +WORKDIR /hoymiles + +RUN python3 -m pip install pyrf24 +RUN python3 -m pip list #watch for RF24 module - if its there its installed + +RUN pip install crcmod pyyaml paho-mqtt SunTimes + +CMD python3 -um hoymiles --log-transactions --verbose --config /etc/ahoy.yml From 0535117a47c3ab3b092e17c78a5fb50e0b1efd27 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Wed, 22 Mar 2023 13:38:20 +0100 Subject: [PATCH 35/52] MI - some small fixes (#5) --- src/hm/hmInverter.h | 3 ++- src/hm/miPayload.h | 40 ++++++++++++++++++++++++---------------- src/utils/dbg.h | 22 ++++++++++++++-------- 3 files changed, 40 insertions(+), 25 deletions(-) diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 8bb046bb..65f5678b 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -157,7 +157,8 @@ class Inverter { } void clearCmdQueue() { - DPRINTLN(DBG_INFO, F("clearCmdQueue")); + DPRINTHEAD(DBG_INFO, id); + DBGPRINTLN_TXT(TXT_CLRQUE); while (!_commandQueue.empty()) { // Will destroy CommandAbstract Class Object (?) _commandQueue.pop(); diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index 2be3b032..289c0342 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -174,7 +174,6 @@ class MiPayload { void add(Inverter<> *iv, packet_t *p) { //DPRINTLN(DBG_INFO, F("MI got data [0]=") + String(p->packet[0], HEX)); - if (p->packet[0] == (0x08 + ALL_FRAMES)) { // 0x88; MI status response to 0x09 miStsDecode(iv, p); } @@ -261,20 +260,26 @@ const byteAssign_t InfoAssignment[] = { mStat->rxSuccess++; } - } else if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command + } else if ( p->packet[0] == (TX_REQ_INFO + ALL_FRAMES) || p->packet[0] == 0xB6 ) { // response from get information command // atm, we just do nothing else than print out what we got... // for decoding see xls- Data collection instructions - #147ff - mPayload[iv->id].txId = p->packet[0]; - DPRINTLN(DBG_DEBUG, F("Response from info request received")); + //mPayload[iv->id].txId = p->packet[0]; + //DPRINTLN(DBG_DEBUG, F("Response from info request received")); + DBGPRINTLN_TXT(TXT_RXDIREQ); uint8_t *pid = &p->packet[9]; if (*pid == 0x00) { - DPRINT(DBG_DEBUG, F("fragment number zero received")); - + //DPRINT(DBG_DEBUG, F("fragment number zero received")); + DBGPRINTLN_TXT(TXT_FRAGM0); + iv->setQueuedCmdFinished(); + } else if (p->packet[9] == 0x81) { + DPRINTHEAD(DBG_WARN, iv->id); + DBGPRINTLN_TXT(TXT_NO2NDG); + iv->ivGen = IV_HM; iv->setQueuedCmdFinished(); - } //else { - DPRINTLN(DBG_DEBUG, "PID: 0x" + String(*pid, HEX)); - /* - if ((*pid & 0x7F) < MAX_PAYLOAD_ENTRIES) { + iv->clearCmdQueue(); + //DPRINTLN(DBG_DEBUG, "PID: 0x" + String(*pid, HEX)); + /* (old else-tree) + if ((*pid & 0x7F) < MAX_PAYLOAD_ENTRIES) {^ memcpy(mPayload[iv->id].data[(*pid & 0x7F) - 1], &p->packet[10], p->len - 11); mPayload[iv->id].len[(*pid & 0x7F) - 1] = p->len - 11; mPayload[iv->id].gotFragment = true; @@ -286,13 +291,14 @@ const byteAssign_t InfoAssignment[] = { if (*pid > 0x81) mPayload[iv->id].lastFound = true; } - } + }*/ } - } */ + //} } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES ) // response from dev control command - || p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES -1)) { // response from DRED instruction + || p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES -1)) { // response from DRED instruction DPRINTHEAD(DBG_DEBUG, iv->id); - DBGPRINTLN(F("Response from devcontrol request received")); + DBGPRINTLN_TXT(TXT_RXCTRREQ); + //DBGPRINTLN(F("Response from devcontrol request received")); mPayload[iv->id].txId = p->packet[0]; iv->clearDevControlRequest(); @@ -313,7 +319,8 @@ const byteAssign_t InfoAssignment[] = { //DPRINTLN(DBG_INFO, F("procPyld: cmd: 0x") + String(mPayload[iv->id].txCmd, HEX)); //DPRINTLN(DBG_INFO, F("procPyld: txid: 0x") + String(mPayload[iv->id].txId, HEX)); //DPRINTLN(DBG_DEBUG, F("procPyld: max: ") + String(mPayload[iv->id].maxPackId)); - DPRINT_INIT(DBG_INFO,TXT_PPYDCMD); + DPRINTHEAD(DBG_INFO, iv->id); + DBGPRINT_TXT(TXT_PPYDCMD); DBGHEXLN(mPayload[iv->id].txCmd); DBGPRINT_TXT(TXT_PPYDTXI); DBGHEXLN(mPayload[iv->id].txId); @@ -718,7 +725,8 @@ const byteAssign_t InfoAssignment[] = { } bool build(uint8_t id, bool *complete) { - DPRINTLN_TXT(DBG_VERBOSE, TXT_BUILD); + DPRINTLN(DBG_VERBOSE, F("build")); + //DPRINTLN_TXT(DBG_VERBOSE, TXT_BUILD); /*uint16_t crc = 0xffff, crcRcv = 0x0000; if (mPayload[id].maxPackId > MAX_PAYLOAD_ENTRIES) mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; diff --git a/src/utils/dbg.h b/src/utils/dbg.h index 97450cd8..eee9c7c9 100644 --- a/src/utils/dbg.h +++ b/src/utils/dbg.h @@ -182,7 +182,6 @@ #define TXT_REQRETR 7 #define TXT_PPYDMAX 10 #define TXT_NOPYLD 1 - #define TXT_GDEVINF 3 #define TXT_DEVCTRL 4 #define TXT_INCRALM 5 @@ -194,7 +193,6 @@ DPRINTLN(DBG_DEBUG, F("Response from info request received")); DBGPRINTLN(F("Response from devcontrol request received")); - DPRINT(DBG_DEBUG, F("fragment number zero received")); DBGPRINT(F("has accepted power limit set point ")); DBGPRINT(F(" with PowerLimitControl ")); DPRINT(DBG_INFO, F("Payload (") + String(payloadLen) + "): "); @@ -228,22 +226,30 @@ DBGPRINTLN(F("Response from devcontrol request received")); #define TXT_NOPYLD2 3 #define TXT_CRCERR 4 #define TXT_RSTPYLD 5 -#define TXT_NULLREC 7 -#define TXT_PREVSND 8 -#define TXT_RESPLIM 9 - -//resetPayload +#define TXT_RXDIREQ 6 +#define TXT_CLRQUE 7 +#define TXT_RXCTRREQ 8 +#define TXT_NULLREC 9 +#define TXT_PREVSND 10 +#define TXT_RESPLIM 11 +#define TXT_FRAGM0 20 +#define TXT_NO2NDG 100 #define DBGPRINTLN_TXT(text) ({\ switch(text) {\ case TXT_TIMEOUT: DBGPRINTLN(F("enqueued cmd failed/timeout")); break; \ case TXT_BUILD: DBGPRINTLN(F("build")); break; \ case TXT_NOPYLD2: DBGPRINTLN(F("nothing received")); break; \ - case TXT_RSTPYLD: DBGPRINTLN(F("resetPayload"));break; \ case TXT_CRCERR: DBGPRINTLN(F("CRC Error: Request Complete Retransmit")); break; \ + case TXT_RSTPYLD: DBGPRINTLN(F("resetPayload"));break; \ + case TXT_RXDIREQ: DBGPRINTLN(F("Response from info request received")); break; \ + case TXT_CLRQUE: DBGPRINTLN(F("clearCmdQueue")); break; \ + case TXT_RXCTRREQ: DBGPRINTLN(F("Response from devcontrol request received")); break; \ case TXT_NULLREC: DBGPRINTLN(F("record is NULL!")); break; \ case TXT_PREVSND: DBGPRINTLN(F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); break; \ case TXT_RESPLIM: DBGPRINTLN(F("retransmit power limit")); break; \ + case TXT_FRAGM0: DBGPRINTLN(F("fragment number zero received")); break; \ + case TXT_NO2NDG: DBGPRINTLN(F("seems to use 3rd gen. protocol - switching ivGen!")); break; \ default: ; break; \ }\ }) From 250d3f9fb1b44fbf921500d13ea738fa5aa95fbc Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 23 Mar 2023 07:17:27 +0100 Subject: [PATCH 36/52] MI - debug output for error calculation --- src/hm/hmPayload.h | 20 ++++++++++---------- src/hm/miPayload.h | 30 +++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/hm/hmPayload.h b/src/hm/hmPayload.h index 8b75cf47..e653b2ad 100644 --- a/src/hm/hmPayload.h +++ b/src/hm/hmPayload.h @@ -292,18 +292,18 @@ class HmPayload { mSys->Radio.prepareDevInformCmd(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); } } else { // payload complete - //DPRINT(DBG_INFO, F("procPyld: cmd: 0x")); + DPRINT(DBG_INFO, F("procPyld: cmd: 0x")); //DBGPRINTLN(String(mPayload[iv->id].txCmd, HEX)); - DPRINT_INIT(DBG_INFO,TXT_PPYDCMD); + //DPRINT_INIT(DBG_INFO,TXT_PPYDCMD); DBGHEXLN(mPayload[iv->id].txCmd); - //DPRINT(DBG_INFO, F("procPyld: txid: 0x")); - DPRINT_INIT(DBG_INFO,TXT_PPYDTXI); + DPRINT(DBG_INFO, F("procPyld: txid: 0x")); + //DPRINT_INIT(DBG_INFO,TXT_PPYDTXI); //DBGPRINTLN(String(mPayload[iv->id].txId, HEX)); DBGHEXLN(mPayload[iv->id].txId); - DPRINT_INIT(DBG_DEBUG,TXT_PPYDMAX); - DBGPRINTLN(String(mPayload[iv->id].maxPackId)); - //DPRINT(DBG_DEBUG, F("procPyld: max: ");// + String(mPayload[iv->id].maxPackId)); - //DBGHEXLN(mPayload[iv->id].maxPackId); + //DPRINT_INIT(DBG_DEBUG,TXT_PPYDMAX); + //DBGPRINTLN(String(mPayload[iv->id].maxPackId)); + DPRINT(DBG_DEBUG, F("procPyld: max: ") + String(mPayload[iv->id].maxPackId)); + record_t<> *rec = iv->getRecordStruct(mPayload[iv->id].txCmd); // choose the parser mPayload[iv->id].complete = true; @@ -380,8 +380,8 @@ class HmPayload { } bool build(uint8_t id, bool *complete) { - //DPRINTLN(DBG_VERBOSE, F("build")); - DPRINTLN_TXT(DBG_VERBOSE, TXT_BUILD); + DPRINTLN(DBG_VERBOSE, F("build")); + //DPRINTLN_TXT(DBG_VERBOSE, TXT_BUILD); uint16_t crc = 0xffff, crcRcv = 0x0000; if (mPayload[id].maxPackId > MAX_PAYLOAD_ENTRIES) diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index 289c0342..5badb0ec 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -21,7 +21,7 @@ typedef struct { bool complete; bool dataAB[3]; bool stsAB[3]; - uint8_t sts[5]; + uint16_t sts[5]; uint8_t txId; uint8_t invId; uint8_t retransmits; @@ -260,9 +260,10 @@ const byteAssign_t InfoAssignment[] = { mStat->rxSuccess++; } - } else if ( p->packet[0] == (TX_REQ_INFO + ALL_FRAMES) || p->packet[0] == 0xB6 ) { // response from get information command - // atm, we just do nothing else than print out what we got... - // for decoding see xls- Data collection instructions - #147ff + } else if ( p->packet[0] == (TX_REQ_INFO + ALL_FRAMES) // response from get information command + || p->packet[0] == 0xB6 ) { // strange short response from MI-1500 3rd gen; might be missleading! + // atm, we just do nothing else than print out what we got... + // for decoding see xls- Data collection instructions - #147ff //mPayload[iv->id].txId = p->packet[0]; //DPRINTLN(DBG_DEBUG, F("Response from info request received")); DBGPRINTLN_TXT(TXT_RXDIREQ); @@ -271,7 +272,7 @@ const byteAssign_t InfoAssignment[] = { //DPRINT(DBG_DEBUG, F("fragment number zero received")); DBGPRINTLN_TXT(TXT_FRAGM0); iv->setQueuedCmdFinished(); - } else if (p->packet[9] == 0x81) { + } else if (p->packet[9] == 0x81) { // might need some additional check, as this is only ment for short answers! DPRINTHEAD(DBG_WARN, iv->id); DBGPRINTLN_TXT(TXT_NO2NDG); iv->ivGen = IV_HM; @@ -574,13 +575,24 @@ const byteAssign_t InfoAssignment[] = { mPayload[iv->id].txId = p->packet[0]; //uint8_t status = (p->packet[11] << 8) + p->packet[12]; - uint8_t status = (p->packet[9] << 8) + p->packet[10]; - //uint8_t stschan = p->packet[0] == 0x88 ? CH1 : CH2; + uint16_t status = 3; // regular status for MI, change to 1 later? + if ( p->packet[10] < 3 ) { + status = p->packet[10]*100 + p->packet[9]*10 + stschan; //first approach, needs review! + } else if ( p->packet[10] > 3 ) { + status = p->packet[10]*1000 + p->packet[9]*100 + p->packet[12]*10 + p->packet[11]; + if (p->packet[12] < 6) { + status += stschan; + } + } + if ( status != 3 ) { + DPRINTLN(DBG_WARN, F("Error code ") + String(status)); + } + mPayload[iv->id].sts[stschan] = status; mPayload[iv->id].stsAB[stschan] = true; if (mPayload[iv->id].stsAB[CH1] && mPayload[iv->id].stsAB[CH2]) mPayload[iv->id].stsAB[CH0] = true; - if ( !mPayload[iv->id].sts[0] || status < mPayload[iv->id].sts[0]) { + if ( !mPayload[iv->id].sts[0] || status < mPayload[iv->id].sts[0] ) { mPayload[iv->id].sts[0] = status; iv->setValue(iv->getPosByChFld(0, FLD_EVT, rec), rec, status); } @@ -641,7 +653,7 @@ const byteAssign_t InfoAssignment[] = { FCODE = (uint8_t)(p->packet[27]); }*/ - uint8_t status = (uint8_t)(p->packet[23]); + uint16_t status = (uint8_t)(p->packet[23]); mPayload[iv->id].sts[datachan] = status; if ( !mPayload[iv->id].sts[0] || status < mPayload[iv->id].sts[0]) { mPayload[iv->id].sts[0] = status; From 7d2efd794393e2a3e19963bed7a6c15634962c9b Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 23 Mar 2023 14:06:25 +0100 Subject: [PATCH 37/52] Update Dockerfile added Influx Client Pip --- tools/rpi/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/rpi/Dockerfile b/tools/rpi/Dockerfile index 8fa89661..1a62b01b 100644 --- a/tools/rpi/Dockerfile +++ b/tools/rpi/Dockerfile @@ -7,8 +7,8 @@ FROM python:slim-bullseye COPY . /hoymiles WORKDIR /hoymiles -RUN python3 -m pip install pyrf24 -RUN python3 -m pip list #watch for RF24 module - if its there its installed +RUN python3 -m pip install pyrf24 influxdb_client && \ +python3 -m pip list #watch for RF24 module - if its there its installed RUN pip install crcmod pyyaml paho-mqtt SunTimes From b498ea619f8b3087ce4a57d39ef51eceadf8b534 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 23 Mar 2023 18:43:10 +0100 Subject: [PATCH 38/52] MI - restructure error calculation --- src/hm/miPayload.h | 135 +++++++++++++++++++++++++++------------------ 1 file changed, 82 insertions(+), 53 deletions(-) diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index 5badb0ec..61e6b174 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -21,7 +21,7 @@ typedef struct { bool complete; bool dataAB[3]; bool stsAB[3]; - uint16_t sts[5]; + uint16_t sts[6]; uint8_t txId; uint8_t invId; uint8_t retransmits; @@ -49,7 +49,7 @@ class MiPayload { mMaxRetrans = maxRetransmits; mTimestamp = timestamp; for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { - reset(i); + reset(i, true); mPayload[i].limitrequested = true; } mSerialDebug = false; @@ -240,19 +240,28 @@ const byteAssign_t InfoAssignment[] = { DBGPRINTLN(String((p->packet[24] << 8) + p->packet[25])); /*iv->setQueuedCmdFinished(); mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x01, false);*/ - } else if ( p->packet[9] == 0x01 ) {//second frame + } else if ( p->packet[9] == 0x01 || p->packet[9] == 0x10 ) {//second frame for MI, 3rd gen. answers in 0x10 DPRINTHEAD(DBG_INFO, iv->id); - DBGPRINTLN(F("got 2nd frame (hw info)")); + if ( p->packet[9] == 0x01 ) { + DBGPRINTLN(F("got 2nd frame (hw info)")); + } else { + DBGPRINTLN(F("3rd gen. inverter!")); // see table in OpenDTU code, DevInfoParser.cpp devInfo[] + } // xlsx: HW_ECapValue is total energy?!? (data coll. inst. #154) - DPRINT(DBG_INFO,F("HW_ECapValue ")); - DBGPRINTLN(String((p->packet[20] << 8) + p->packet[21])); - iv->setValue(iv->getPosByChFld(0, FLD_YT, rec), rec, (float) ((p->packet[20] << 8) + p->packet[21])/1); - DPRINT(DBG_INFO,F("HW_FB_TLmValue ")); - DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15])); - DPRINT(DBG_INFO,F("HW_FB_ReSPRT ")); - DBGPRINTLN(String((p->packet[16] << 8) + p->packet[17])); - DPRINT(DBG_INFO,F("HW_GridSamp_ResValule ")); - DBGPRINTLN(String((p->packet[18] << 8) + p->packet[19])); + DPRINT(DBG_INFO,F("HW_PartNo ")); + DBGPRINTLN(String((uint32_t) (((p->packet[10] << 8) | p->packet[11]) << 8 | p->packet[12]) << 8 | p->packet[13])); + //DBGPRINTLN(String((p->packet[12] << 8) + p->packet[13])); + if ( p->packet[9] == 0x01 ) { + DPRINT(DBG_INFO,F("HW_ECapValue ")); + DBGPRINTLN(String((p->packet[20] << 8) + p->packet[21])); + iv->setValue(iv->getPosByChFld(0, FLD_YT, rec), rec, (float) ((p->packet[20] << 8) + p->packet[21])/1); + DPRINT(DBG_INFO,F("HW_FB_TLmValue ")); + DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15])); + DPRINT(DBG_INFO,F("HW_FB_ReSPRT ")); + DBGPRINTLN(String((p->packet[16] << 8) + p->packet[17])); + DPRINT(DBG_INFO,F("HW_GridSamp_ResValule ")); + DBGPRINTLN(String((p->packet[18] << 8) + p->packet[19])); + } } else if ( p->packet[9] == 0x12 ) {//3rd frame DPRINTHEAD(DBG_INFO, iv->id); DBGPRINTLN(F("got 3rd frame (hw info)")); @@ -261,7 +270,7 @@ const byteAssign_t InfoAssignment[] = { } } else if ( p->packet[0] == (TX_REQ_INFO + ALL_FRAMES) // response from get information command - || p->packet[0] == 0xB6 ) { // strange short response from MI-1500 3rd gen; might be missleading! + || p->packet[0] == 0xB6 && mPayload[iv->id].txCmd != 0x36) { // strange short response from MI-1500 3rd gen; might be missleading! // atm, we just do nothing else than print out what we got... // for decoding see xls- Data collection instructions - #147ff //mPayload[iv->id].txId = p->packet[0]; @@ -502,16 +511,6 @@ const byteAssign_t InfoAssignment[] = { DPRINTLN(DBG_INFO, F("procPyld: txid: 0x") + String(mPayload[iv->id].txId, HEX)); //DPRINTLN(DBG_DEBUG, F("procPyld: max: ") + String(mPayload[iv->id].maxPackId)); //record_t<> *rec = iv->getRecordStruct(mPayload[iv->id].txCmd); // choose the parser - mPayload[iv->id].complete = true; - uint8_t ac_pow = 0; - //if (mPayload[iv->id].sts[0] == 3) { - ac_pow = calcPowerDcCh0(iv, 0)*9.5; - //} - record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); // choose the parser - iv->setValue(iv->getPosByChFld(0, FLD_PAC, rec), rec, (float) (ac_pow/10)); - DPRINTLN(DBG_INFO, F("process: compl. set of msgs detected")); - iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0)); - iv->doCalculations(); //uint8_t payload[128]; //uint8_t payloadLen = 0; //memset(payload, 0, 128); @@ -573,28 +572,45 @@ const byteAssign_t InfoAssignment[] = { rec->ts = mPayload[iv->id].ts; mPayload[iv->id].gotFragment = true; mPayload[iv->id].txId = p->packet[0]; + miStsConsolidate(iv, stschan, rec, p->packet[10], p->packet[12], p->packet[9], p->packet[11]); + mPayload[iv->id].stsAB[stschan] = true; + if (mPayload[iv->id].stsAB[CH1] && mPayload[iv->id].stsAB[CH2]) + mPayload[iv->id].stsAB[CH0] = true; + //mPayload[iv->id].skipfirstrepeat = 1; + if (mPayload[iv->id].stsAB[CH0] && mPayload[iv->id].dataAB[CH0] && !mPayload[iv->id].complete) { + miComplete(iv); + } + } + void miStsConsolidate(Inverter<> *iv, uint8_t stschan, record_t<> *rec, uint8_t uState, uint8_t uEnum, uint8_t lState = 0, uint8_t lEnum = 0) { //uint8_t status = (p->packet[11] << 8) + p->packet[12]; uint16_t status = 3; // regular status for MI, change to 1 later? - if ( p->packet[10] < 3 ) { - status = p->packet[10]*100 + p->packet[9]*10 + stschan; //first approach, needs review! - } else if ( p->packet[10] > 3 ) { - status = p->packet[10]*1000 + p->packet[9]*100 + p->packet[12]*10 + p->packet[11]; - if (p->packet[12] < 6) { + if ( uState < 3 ) { + status = uState*100 + stschan; //first approach, needs review! + if (lState) + status += lState*10; + } else if ( uState > 3 ) { + status = uState*1000 + uEnum*10; + if (lState) + status += lState*100; //needs review, esp. for 4ch-8310 state! + //if (lEnum) + status += lEnum; + if (uEnum < 6) { status += stschan; } } - if ( status != 3 ) { - DPRINTLN(DBG_WARN, F("Error code ") + String(status)); + + uint16_t prntsts = status == 3 ? 1 : status; + if ( status != mPayload[iv->id].sts[stschan] ) { //sth.'s changed? + mPayload[iv->id].sts[stschan] = status; + DPRINT(DBG_WARN, F("Status change for CH")); + DBGPRINT(String(stschan)); DBGPRINT(F(": ")); + DBGPRINTLN(iv->getAlarmStr(prntsts)); } - mPayload[iv->id].sts[stschan] = status; - mPayload[iv->id].stsAB[stschan] = true; - if (mPayload[iv->id].stsAB[CH1] && mPayload[iv->id].stsAB[CH2]) - mPayload[iv->id].stsAB[CH0] = true; - if ( !mPayload[iv->id].sts[0] || status < mPayload[iv->id].sts[0] ) { - mPayload[iv->id].sts[0] = status; - iv->setValue(iv->getPosByChFld(0, FLD_EVT, rec), rec, status); + if ( !mPayload[iv->id].sts[0] || prntsts < mPayload[iv->id].sts[0] ) { + mPayload[iv->id].sts[0] = prntsts; + iv->setValue(iv->getPosByChFld(0, FLD_EVT, rec), rec, prntsts); } if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){ @@ -603,12 +619,20 @@ const byteAssign_t InfoAssignment[] = { DPRINTHEAD(DBG_INFO, iv->id); DBGPRINT_TXT(TXT_INCRALM); DBGPRINTLN(String(iv->alarmMesIndex)); - //iv->enqueCommand(AlarmData); Would just start with second channel request 0x11... - } - //mPayload[iv->id].skipfirstrepeat = 1; - if (mPayload[iv->id].stsAB[CH0] && mPayload[iv->id].dataAB[CH0] && !mPayload[iv->id].complete) { - miComplete(iv); } + /*if(AlarmData == mPayload[iv->id].txCmd) { + uint8_t i = 0; + uint16_t code; + uint32_t start, end; + while(1) { + code = iv->parseAlarmLog(i++, payload, payloadLen, &start, &end); + if(0 == code) + break; + if (NULL != mCbAlarm) + (mCbAlarm)(code, start, end); + yield(); + } + }*/ } void miDataDecode(Inverter<> *iv, packet_t *p) { @@ -653,12 +677,14 @@ const byteAssign_t InfoAssignment[] = { FCODE = (uint8_t)(p->packet[27]); }*/ - uint16_t status = (uint8_t)(p->packet[23]); + /*uint16_t status = (uint8_t)(p->packet[23]); mPayload[iv->id].sts[datachan] = status; if ( !mPayload[iv->id].sts[0] || status < mPayload[iv->id].sts[0]) { mPayload[iv->id].sts[0] = status; iv->setValue(iv->getPosByChFld(0, FLD_EVT, rec), rec, status); - } + }*/ + miStsConsolidate(iv, datachan, rec, p->packet[23], p->packet[24]); + if (p->packet[0] < (0x39 + ALL_FRAMES) ) { /*uint8_t cmd = p->packet[0] - ALL_FRAMES + 1; @@ -674,17 +700,17 @@ const byteAssign_t InfoAssignment[] = { mPayload[iv->id].complete = true; } - if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){ + /*if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){ iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]; DPRINTHEAD(DBG_INFO, iv->id); DBGPRINT_TXT(TXT_INCRALM); DBGPRINTLN(String(iv->alarmMesIndex)); - } + }*/ } - if ( mPayload[iv->id].complete || //4ch device + if ( mPayload[iv->id].complete || //4ch device (iv->type != INV_TYPE_4CH //other devices && mPayload[iv->id].dataAB[CH0] && mPayload[iv->id].stsAB[CH0])) { @@ -768,7 +794,7 @@ const byteAssign_t InfoAssignment[] = { return true; } - void reset(uint8_t id) { + void reset(uint8_t id, bool clrSts = false) { DPRINTHEAD(DBG_INFO, id); DBGPRINTLN_TXT(TXT_RSTPYLD); memset(mPayload[id].len, 0, MAX_PAYLOAD_ENTRIES); @@ -788,10 +814,13 @@ const byteAssign_t InfoAssignment[] = { mPayload[id].requested = false; mPayload[id].ts = *mTimestamp; mPayload[id].sts[0] = 0; - mPayload[id].sts[CH1] = 0; - mPayload[id].sts[CH2] = 0; - mPayload[id].sts[CH3] = 0; - mPayload[id].sts[CH4] = 0; + if (clrSts) { // only clear channel states at startup + mPayload[id].sts[CH1] = 0; + mPayload[id].sts[CH2] = 0; + mPayload[id].sts[CH3] = 0; + mPayload[id].sts[CH4] = 0; + mPayload[id].sts[5] = 0; //remember last summarized state + } } From 3ed76324d531d6794f06edeb794a80123b7e2a31 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 23 Mar 2023 22:08:26 +0100 Subject: [PATCH 39/52] clean up pull request --- src/hm/hmInverter.h | 11 +++--- src/hm/hmPayload.h | 91 +++++++++++++++++++-------------------------- src/hm/miPayload.h | 73 +++++++++++++++--------------------- src/utils/dbg.h | 90 +------------------------------------------- 4 files changed, 76 insertions(+), 189 deletions(-) diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 65f5678b..6f6efe38 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -143,10 +143,10 @@ class Inverter { template void enqueCommand(uint8_t cmd) { _commandQueue.push(std::make_shared(cmd)); - DPRINTHEAD(DBG_INFO, id); - //DBGPRINTLN(F("enqueuedCmd: 0x") + String(cmd, HEX)); - DBGPRINT_TXT(TXT_ENQUCMD); - DBGHEXLN(cmd); + DPRINT(DBG_INFO, F("(#")); + DBGPRINT(String(id)); + DBGPRINT(F(") enqueCommand: 0x")); + DHEX(cmd); } void setQueuedCmdFinished() { @@ -157,8 +157,7 @@ class Inverter { } void clearCmdQueue() { - DPRINTHEAD(DBG_INFO, id); - DBGPRINTLN_TXT(TXT_CLRQUE); + DPRINTLN(DBG_INFO, F("clearCmdQueue")); while (!_commandQueue.empty()) { // Will destroy CommandAbstract Class Object (?) _commandQueue.pop(); diff --git a/src/hm/hmPayload.h b/src/hm/hmPayload.h index e653b2ad..7660c46b 100644 --- a/src/hm/hmPayload.h +++ b/src/hm/hmPayload.h @@ -117,13 +117,11 @@ class HmPayload { iv->setQueuedCmdFinished(); // command failed if (mSerialDebug) - DPRINTHEAD(DBG_INFO, iv->id); - DBGPRINTLN_TXT(TXT_TIMEOUT); - //DBGPRINTLN(F("enqueued cmd failed/timeout")); + DPRINTLN(DBG_INFO, F("enqueued cmd failed/timeout")); if (mSerialDebug) { - DPRINTHEAD(DBG_INFO, iv->id); - //DBGPRINT(F("no Payload received! (retransmits: ")); - DBGPRINT_TXT(TXT_NOPYLD); + DPRINT(DBG_INFO, F("(#")); + DBGPRINT(String(iv->id)); + DBGPRINT(F(") no Payload received! (retransmits: ")); DBGPRINT(String(mPayload[iv->id].retransmits)); DBGPRINTLN(F(")")); } @@ -136,17 +134,17 @@ class HmPayload { yield(); if (mSerialDebug) { - DPRINTHEAD(DBG_INFO, iv->id); - //DBGPRINT(F("Requesting Inv SN ")); - DBGPRINT_TXT(TXT_INVSERNO); + DPRINT(DBG_INFO, F("(#")); + DBGPRINT(String(iv->id)); + DBGPRINT(F(") Requesting Inv SN ")); DBGPRINTLN(String(iv->config->serial.u64, HEX)); } if (iv->getDevControlRequest()) { if (mSerialDebug) { - DPRINTHEAD(DBG_INFO, iv->id); - //DBGPRINT(F("Devcontrol request 0x")); - DBGPRINT_TXT(TXT_DEVCTRL); + DPRINT(DBG_INFO, F("(#")); + DBGPRINT(String(iv->id)); + DBGPRINT(F(") Devcontrol request 0x")); DBGPRINT(String(iv->devControlCmd, HEX)); DBGPRINT(F(" power limit ")); DBGPRINTLN(String(iv->powerLimit[0])); @@ -157,9 +155,9 @@ class HmPayload { //iv->enqueCommand(SystemConfigPara); // read back power limit } else { uint8_t cmd = iv->getQueuedCmd(); - DPRINTHEAD(DBG_INFO, iv->id); - //DBGPRINT(F("prepareDevInformCmd 0x")); - DBGPRINT_TXT(TXT_GDEVINF); + DPRINT(DBG_INFO, F("(#")); + DBGPRINT(String(iv->id)); + DBGPRINT(F(") prepareDevInformCmd 0x")); DBGPRINTLN(String(cmd, HEX)); mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex, false); mPayload[iv->id].txCmd = cmd; @@ -202,8 +200,9 @@ class HmPayload { mApp->setMqttPowerLimitAck(iv); else ok = false; - DPRINTHEAD(DBG_INFO,iv->id); - DBGPRINT(F("has ")); + DPRINT(DBG_INFO, F("(#")); + DBGPRINT(String(iv->id)); + DBGPRINT(F(" has ")); if(!ok) DBGPRINT(F("not ")); DBGPRINT(F("accepted power limit set point ")); DBGPRINT(String(iv->powerLimit[0])); @@ -241,14 +240,12 @@ class HmPayload { mPayload[iv->id].retransmits++; if (iv->devControlCmd == Restart || iv->devControlCmd == CleanState_LockAndAlarm) { // This is required to prevent retransmissions without answer. - //DPRINTLN(DBG_INFO, F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); - DPRINTHEAD(DBG_INFO, iv->id); - DBGPRINTLN_TXT(TXT_PREVSND); + DPRINTLN(DBG_INFO, F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); mPayload[iv->id].retransmits = mMaxRetrans; } else if(iv->devControlCmd == ActivePowerContr) { - //DPRINTLN(DBG_INFO, F("retransmit power limit")); - DPRINTHEAD(DBG_INFO, iv->id); - DBGPRINTLN_TXT(TXT_RESPLIM); + DPRINT(DBG_INFO, F("(#")); + DBGPRINT(String(iv->id)); + DPRINTLN(DBG_INFO, F(") retransmit power limit")); mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true); } else { if(false == mPayload[iv->id].gotFragment) { @@ -258,18 +255,18 @@ class HmPayload { DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX)); mSys->Radio.prepareDevInformCmd(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); */ - DPRINTHEAD(DBG_INFO, iv->id); - DBGPRINTLN_TXT(TXT_NOPYLD2); + DPRINT(DBG_INFO, F("(#")); + DBGPRINT(String(iv->id)); + DBGPRINTLN(F(") nothing received")); mPayload[iv->id].retransmits = mMaxRetrans; } else { for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId - 1); i++) { if (mPayload[iv->id].len[i] == 0) { - DPRINTHEAD(DBG_WARN,iv->id); - DBGPRINT(F("Frame ")); + DPRINT(DBG_WARN, F("(#")); + DBGPRINT(String(iv->id)); + DBGPRINT(F(") Frame ")); DBGPRINT(String(i + 1)); - //DBGPRINTLN(F(" missing: Request Retransmit")); - DBGPRINT_TXT(TXT_REQRETR); - DBGPRINT(F("\r\n")); + DBGPRINTLN(F(" missing: Request Retransmit")); mSys->Radio.sendCmdPacket(iv->radioId.u64, TX_REQ_INFO, (SINGLE_FRAME + i), true); break; // only request retransmit one frame per loop } @@ -282,29 +279,21 @@ class HmPayload { } else if(!crcPass && pyldComplete) { // crc error on complete Payload if (mPayload[iv->id].retransmits < mMaxRetrans) { mPayload[iv->id].retransmits++; - DPRINTHEAD(DBG_WARN,iv->id); - DBGPRINTLN_TXT(TXT_CRCERR); + DPRINTLN(DBG_WARN, F("CRC Error: Request Complete Retransmit")); mPayload[iv->id].txCmd = iv->getQueuedCmd(); - DPRINTHEAD(DBG_INFO,iv->id); - DBGPRINT_TXT(TXT_GDEVINF); - //DBGPRINTLN(String(mPayload[iv->id].txCmd, HEX)); - DBGHEXLN(mPayload[iv->id].txCmd); + DPRINT(DBG_INFO, F("(#")); + DBGPRINT(String(iv->id)); + DBGPRINT(F(") prepareDevInformCmd 0x")); + DHEXLN(mPayload[iv->id].txCmd); mSys->Radio.prepareDevInformCmd(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); } } else { // payload complete DPRINT(DBG_INFO, F("procPyld: cmd: 0x")); - //DBGPRINTLN(String(mPayload[iv->id].txCmd, HEX)); - //DPRINT_INIT(DBG_INFO,TXT_PPYDCMD); - DBGHEXLN(mPayload[iv->id].txCmd); + DHEXLN(mPayload[iv->id].txCmd); DPRINT(DBG_INFO, F("procPyld: txid: 0x")); - //DPRINT_INIT(DBG_INFO,TXT_PPYDTXI); - //DBGPRINTLN(String(mPayload[iv->id].txId, HEX)); - DBGHEXLN(mPayload[iv->id].txId); - //DPRINT_INIT(DBG_DEBUG,TXT_PPYDMAX); - //DBGPRINTLN(String(mPayload[iv->id].maxPackId)); - DPRINT(DBG_DEBUG, F("procPyld: max: ") + String(mPayload[iv->id].maxPackId)); - - + DHEXLN(mPayload[iv->id].txId); + DPRINTLN(DBG_DEBUG, F("procPyld: max: ")); + DBGPRINT(String(mPayload[iv->id].maxPackId)); record_t<> *rec = iv->getRecordStruct(mPayload[iv->id].txCmd); // choose the parser mPayload[iv->id].complete = true; @@ -328,7 +317,7 @@ class HmPayload { } if (NULL == rec) { - DPRINTLN_TXT(DBG_ERROR, TXT_NULLREC); + DPRINTLN(DBG_ERROR, F("record is NULL!")); } else if ((rec->pyldLen == payloadLen) || (0 == rec->pyldLen)) { if (mPayload[iv->id].txId == (TX_REQ_INFO + ALL_FRAMES)) mStat->rxSuccess++; @@ -381,8 +370,6 @@ class HmPayload { bool build(uint8_t id, bool *complete) { DPRINTLN(DBG_VERBOSE, F("build")); - //DPRINTLN_TXT(DBG_VERBOSE, TXT_BUILD); - uint16_t crc = 0xffff, crcRcv = 0x0000; if (mPayload[id].maxPackId > MAX_PAYLOAD_ENTRIES) mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; @@ -411,8 +398,8 @@ class HmPayload { } void reset(uint8_t id) { - DPRINTHEAD(DBG_INFO,id); - DBGPRINTLN_TXT(TXT_RSTPYLD); + DPRINT(DBG_INFO, "resetPayload: id: "); + DBGPRINTLN(String(id)); memset(mPayload[id].len, 0, MAX_PAYLOAD_ENTRIES); mPayload[id].txCmd = 0; mPayload[id].gotFragment = false; diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index 61e6b174..c5a6eb9a 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -95,12 +95,10 @@ class MiPayload { iv->setQueuedCmdFinished(); // command failed if (mSerialDebug) DPRINTHEAD(DBG_INFO, iv->id); - //DBGPRINTLN(F("enqueued cmd failed/timeout")); - DBGPRINTLN_TXT(TXT_TIMEOUT); + DBGPRINTLN(F("enqueued cmd failed/timeout")); if (mSerialDebug) { DPRINTHEAD(DBG_INFO, iv->id); - //DBGPRINT(F("no Payload received! (retransmits: ")); - DBGPRINT_TXT(TXT_NOPYLD); + DBGPRINT(F("no Payload received! (retransmits: ")); DBGPRINT(String(mPayload[iv->id].retransmits)); DBGPRINTLN(F(")")); } @@ -114,16 +112,14 @@ class MiPayload { yield(); if (mSerialDebug){ DPRINTHEAD(DBG_INFO, iv->id); - //DBGPRINT(F("Requesting Inv SN ")); - DBGPRINT_TXT(TXT_INVSERNO); + DBGPRINT(F("Requesting Inv SN ")); DBGPRINTLN(String(iv->config->serial.u64, HEX)); } if (iv->getDevControlRequest()) { if (mSerialDebug) { DPRINTHEAD(DBG_INFO, iv->id); - //DBGPRINT(F("Devcontrol request 0x")); - DBGPRINT_TXT(TXT_DEVCTRL); + DBGPRINT(F("Devcontrol request 0x")); DHEX(iv->devControlCmd); DBGPRINT(F(" power limit ")); DBGPRINTLN(String(iv->powerLimit[0])); @@ -137,8 +133,8 @@ class MiPayload { } else { uint8_t cmd = iv->getQueuedCmd(); DPRINTHEAD(DBG_INFO, iv->id); - DBGPRINT_TXT(TXT_GDEVINF); - DBGHEXLN(cmd); + DBGPRINT(F("prepareDevInformCmd 0x")); + DHEXLN(cmd); uint8_t cmd2 = cmd; if ( cmd == SystemConfigPara ) { //0x05 for HM-types if (!mPayload[iv->id].limitrequested) { // only do once at startup @@ -149,7 +145,7 @@ class MiPayload { } } - if (cmd == 0x1 || cmd == SystemConfigPara ) { //0x1 and 0x05 for HM-types + if (cmd == 0x01 || cmd == SystemConfigPara ) { //0x1 and 0x05 for HM-types cmd = 0x0f; // for MI, these seem to make part of the Polling the device software and hardware version number command cmd2 = cmd == SystemConfigPara ? 0x01 : 0x00; //perhaps we can only try to get second frame? mSys->Radio.sendCmdPacket(iv->radioId.u64, cmd, cmd2, false); @@ -270,20 +266,19 @@ const byteAssign_t InfoAssignment[] = { } } else if ( p->packet[0] == (TX_REQ_INFO + ALL_FRAMES) // response from get information command - || p->packet[0] == 0xB6 && mPayload[iv->id].txCmd != 0x36) { // strange short response from MI-1500 3rd gen; might be missleading! + || (p->packet[0] == 0xB6 && mPayload[iv->id].txCmd != 0x36)) { // strange short response from MI-1500 3rd gen; might be missleading! // atm, we just do nothing else than print out what we got... // for decoding see xls- Data collection instructions - #147ff //mPayload[iv->id].txId = p->packet[0]; - //DPRINTLN(DBG_DEBUG, F("Response from info request received")); - DBGPRINTLN_TXT(TXT_RXDIREQ); + DPRINTLN(DBG_DEBUG, F("Response from info request received")); uint8_t *pid = &p->packet[9]; if (*pid == 0x00) { - //DPRINT(DBG_DEBUG, F("fragment number zero received")); - DBGPRINTLN_TXT(TXT_FRAGM0); + DPRINT(DBG_DEBUG, F("fragment number zero received")); iv->setQueuedCmdFinished(); } else if (p->packet[9] == 0x81) { // might need some additional check, as this is only ment for short answers! - DPRINTHEAD(DBG_WARN, iv->id); - DBGPRINTLN_TXT(TXT_NO2NDG); + DPRINT(DBG_WARN, F("(#")); + DBGPRINT(String(iv->id)); + DBGPRINTLN(F(") seems to use 3rd gen. protocol - switching ivGen!")); iv->ivGen = IV_HM; iv->setQueuedCmdFinished(); iv->clearCmdQueue(); @@ -307,8 +302,7 @@ const byteAssign_t InfoAssignment[] = { } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES ) // response from dev control command || p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES -1)) { // response from DRED instruction DPRINTHEAD(DBG_DEBUG, iv->id); - DBGPRINTLN_TXT(TXT_RXCTRREQ); - //DBGPRINTLN(F("Response from devcontrol request received")); + DBGPRINTLN(F("Response from devcontrol request received")); mPayload[iv->id].txId = p->packet[0]; iv->clearDevControlRequest(); @@ -326,14 +320,12 @@ const byteAssign_t InfoAssignment[] = { } iv->devControlCmd = Init; } else { // some other response; copied from hmPayload:process; might not be correct to do that here!!! - //DPRINTLN(DBG_INFO, F("procPyld: cmd: 0x") + String(mPayload[iv->id].txCmd, HEX)); - //DPRINTLN(DBG_INFO, F("procPyld: txid: 0x") + String(mPayload[iv->id].txId, HEX)); - //DPRINTLN(DBG_DEBUG, F("procPyld: max: ") + String(mPayload[iv->id].maxPackId)); - DPRINTHEAD(DBG_INFO, iv->id); - DBGPRINT_TXT(TXT_PPYDCMD); - DBGHEXLN(mPayload[iv->id].txCmd); - DBGPRINT_TXT(TXT_PPYDTXI); - DBGHEXLN(mPayload[iv->id].txId); + DPRINT(DBG_INFO, F("procPyld: cmd: 0x")); + DHEXLN(mPayload[iv->id].txCmd); + DPRINT(DBG_INFO, F("procPyld: txid: 0x")); + DHEXLN(mPayload[iv->id].txId); + //DPRINT(DBG_DEBUG, F("procPyld: max: ")); + //DBGPRINTLN(String(mPayload[iv->id].maxPackId)); record_t<> *rec = iv->getRecordStruct(mPayload[iv->id].txCmd); // choose the parser mPayload[iv->id].complete = true; @@ -355,7 +347,7 @@ const byteAssign_t InfoAssignment[] = { } if (NULL == rec) { - DPRINTLN_TXT(DBG_ERROR, TXT_NULLREC); + DPRINTLN(DBG_ERROR, F("record is NULL!")); } else if ((rec->pyldLen == payloadLen) || (0 == rec->pyldLen)) { if (mPayload[iv->id].txId == (TX_REQ_INFO + ALL_FRAMES)) mStat->rxSuccess++; @@ -429,11 +421,11 @@ const byteAssign_t InfoAssignment[] = { if (iv->devControlCmd == Restart || iv->devControlCmd == CleanState_LockAndAlarm) { // This is required to prevent retransmissions without answer. DPRINTHEAD(DBG_INFO, iv->id); - DBGPRINTLN_TXT(TXT_PREVSND); + DBGPRINTLN(F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); mPayload[iv->id].retransmits = mMaxRetrans; } else if(iv->devControlCmd == ActivePowerContr) { DPRINTHEAD(DBG_INFO, iv->id); - DBGPRINTLN_TXT(TXT_RESPLIM); + DBGPRINTLN(F("retransmit power limit")); mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true, false); } else { uint8_t cmd = mPayload[iv->id].txCmd; @@ -441,7 +433,7 @@ const byteAssign_t InfoAssignment[] = { mPayload[iv->id].retransmits++; if( !mPayload[iv->id].gotFragment ) { DPRINTHEAD(DBG_INFO, iv->id); - DBGPRINTLN_TXT(TXT_NOPYLD2); + DBGPRINTLN(F("nothing received")); mPayload[iv->id].retransmits = mMaxRetrans; } else if ( cmd == 0x0f ) { //hard/firmware request @@ -477,11 +469,10 @@ const byteAssign_t InfoAssignment[] = { //mPayload[iv->id].skipfirstrepeat = 0; } else { DBGPRINT(F("sth.")); - DBGPRINT_TXT(TXT_REQRETR); + DBGPRINT(F(" missing: Request Retransmit")); } - //DBGPRINTLN(String(cmd, HEX)); DBGPRINT(F(" 0x")); - DBGHEXLN(cmd); + DHEXLN(cmd); //mSys->Radio.sendCmdPacket(iv->radioId.u64, cmd, cmd, true); mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex, true, cmd); mPayload[iv->id].txCmd = cmd; @@ -494,14 +485,12 @@ const byteAssign_t InfoAssignment[] = { if (mPayload[iv->id].retransmits < mMaxRetrans) { mPayload[iv->id].retransmits++; DPRINTHEAD(DBG_WARN, iv->id); - DBGPRINTLN_TXT(TXT_CRCERR); - //DBGPRINTLN(F("CRC Error: Request Complete Retransmit")); + DBGPRINTLN(F("CRC Error: Request Complete Retransmit")); mPayload[iv->id].txCmd = iv->getQueuedCmd(); DPRINTHEAD(DBG_INFO, iv->id); - DBGPRINT_TXT(TXT_GDEVINF); - //DBGPRINTLN(F("prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX)); - DBGPRINTLN(String(mPayload[iv->id].txCmd, HEX)); + DBGPRINT(F("prepareDevInformCmd 0x")); + DHEXLN(mPayload[iv->id].txCmd); mSys->Radio.prepareDevInformCmd(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); } } @@ -617,7 +606,7 @@ const byteAssign_t InfoAssignment[] = { iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]; // seems there's no status per channel in 3rd gen. models?!? DPRINTHEAD(DBG_INFO, iv->id); - DBGPRINT_TXT(TXT_INCRALM); + DBGPRINT(F("alarm ID incremented to ")); DBGPRINTLN(String(iv->alarmMesIndex)); } /*if(AlarmData == mPayload[iv->id].txCmd) { @@ -796,7 +785,7 @@ const byteAssign_t InfoAssignment[] = { void reset(uint8_t id, bool clrSts = false) { DPRINTHEAD(DBG_INFO, id); - DBGPRINTLN_TXT(TXT_RSTPYLD); + DBGPRINTLN(F("resetPayload")); memset(mPayload[id].len, 0, MAX_PAYLOAD_ENTRIES); mPayload[id].gotFragment = false; /*mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; diff --git a/src/utils/dbg.h b/src/utils/dbg.h index eee9c7c9..cae96447 100644 --- a/src/utils/dbg.h +++ b/src/utils/dbg.h @@ -61,7 +61,7 @@ } } - inline void DBGHEXLN(uint8_t b) { + inline void DHEXLN(uint8_t b) { DHEX(b); DBGPRINT(F("\r\n")); } @@ -151,16 +151,6 @@ }\ }) -#define DPRINT_INIT(level,text) ({\ - DPRINT(level,F(""));\ - DBGPRINT_TXT(text);\ -}) - -#define DPRINTLN_TXT(level,text) ({\ - DPRINT(level,F(""));\ - DBGPRINTLN_TXT(text);\ -}) - #define DPRINTHEAD(level, id) ({\ DPRINT(level, F("(#")); DBGPRINT(String(id)); DBGPRINT(F(") "));\ }) @@ -176,84 +166,6 @@ }) -// available text variables -#define TXT_ENQUCMD 6 -#define TXT_INVSERNO 2 -#define TXT_REQRETR 7 -#define TXT_PPYDMAX 10 -#define TXT_NOPYLD 1 -#define TXT_GDEVINF 3 -#define TXT_DEVCTRL 4 -#define TXT_INCRALM 5 -#define TXT_PPYDCMD 8 -#define TXT_PPYDTXI 9 - - -/* DBGPRINT(F(" power limit ")); -DPRINTLN(DBG_DEBUG, F("Response from info request received")); - -DBGPRINTLN(F("Response from devcontrol request received")); - DBGPRINT(F("has accepted power limit set point ")); - DBGPRINT(F(" with PowerLimitControl ")); - DPRINT(DBG_INFO, F("Payload (") + String(payloadLen) + "): "); - DPRINTLN(DBG_ERROR, F("plausibility check failed, expected ") + String(rec->pyldLen) + F(" bytes")); - - DPRINTLN(DBG_VERBOSE, F("incomlete, txCmd is 0x") + String(txCmd, HEX)); // + F("cmd is 0x") + String(cmd, HEX)); -*/ - - - -#define DBGPRINT_TXT(text) ({\ - switch(text) {\ - case TXT_NOPYLD: DBGPRINT(F("no Payload received! (retransmits: ")); break; \ - case TXT_INVSERNO: DBGPRINT(F("Requesting Inv SN ")); break; \ - case TXT_GDEVINF: DBGPRINT(F("prepareDevInformCmd 0x")); break; \ - case TXT_DEVCTRL: DBGPRINT(F("Devcontrol request 0x")); break; \ - case TXT_INCRALM: DBGPRINT(F("alarm ID incremented to ")); break; \ - case TXT_ENQUCMD: DBGPRINT(F("enqueuedCmd: 0x")); break; \ - case TXT_REQRETR: DBGPRINT(F(" missing: Request Retransmit")); break; \ - case TXT_PPYDCMD: DBGPRINT(F("procPyld: cmd: 0x")); break; \ - case TXT_PPYDTXI: DBGPRINT(F("procPyld: txid: 0x")); break; \ - case TXT_PPYDMAX: DBGPRINT(F("procPyld: max: ")); break; \ - default: ; break; \ - }\ -}) - - -// available text variables w. lf -#define TXT_BUILD 1 -#define TXT_TIMEOUT 2 -#define TXT_NOPYLD2 3 -#define TXT_CRCERR 4 -#define TXT_RSTPYLD 5 -#define TXT_RXDIREQ 6 -#define TXT_CLRQUE 7 -#define TXT_RXCTRREQ 8 -#define TXT_NULLREC 9 -#define TXT_PREVSND 10 -#define TXT_RESPLIM 11 -#define TXT_FRAGM0 20 -#define TXT_NO2NDG 100 - -#define DBGPRINTLN_TXT(text) ({\ - switch(text) {\ - case TXT_TIMEOUT: DBGPRINTLN(F("enqueued cmd failed/timeout")); break; \ - case TXT_BUILD: DBGPRINTLN(F("build")); break; \ - case TXT_NOPYLD2: DBGPRINTLN(F("nothing received")); break; \ - case TXT_CRCERR: DBGPRINTLN(F("CRC Error: Request Complete Retransmit")); break; \ - case TXT_RSTPYLD: DBGPRINTLN(F("resetPayload"));break; \ - case TXT_RXDIREQ: DBGPRINTLN(F("Response from info request received")); break; \ - case TXT_CLRQUE: DBGPRINTLN(F("clearCmdQueue")); break; \ - case TXT_RXCTRREQ: DBGPRINTLN(F("Response from devcontrol request received")); break; \ - case TXT_NULLREC: DBGPRINTLN(F("record is NULL!")); break; \ - case TXT_PREVSND: DBGPRINTLN(F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); break; \ - case TXT_RESPLIM: DBGPRINTLN(F("retransmit power limit")); break; \ - case TXT_FRAGM0: DBGPRINTLN(F("fragment number zero received")); break; \ - case TXT_NO2NDG: DBGPRINTLN(F("seems to use 3rd gen. protocol - switching ivGen!")); break; \ - default: ; break; \ - }\ -}) - /*class ahoyLog { public: ahoyLog() {} From 5a1a600327c816210f96d83583dec4fb4ec277bc Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 23 Mar 2023 22:41:56 +0100 Subject: [PATCH 40/52] 0.5.105 * merged MI, thx @rejoe2 #788 * fixed reboot message #793 --- src/CHANGES.md | 4 ++++ src/defines.h | 2 +- src/web/RestApi.h | 8 ++++++++ src/web/html/convert.py | 5 ++++- src/web/web.h | 6 +++--- 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 0af4746b..4223ad99 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -2,6 +2,10 @@ (starting from release version `0.5.66`) +## 0.5.105 +* merged MI, thx @rejoe2 #788 +* fixed reboot message #793 + ## 0.5.104 * further improved save settings * removed `#` character from ePaper diff --git a/src/defines.h b/src/defines.h index f29f6ea5..dafcb9ec 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 5 -#define VERSION_PATCH 104 +#define VERSION_PATCH 105 //------------------------------------- typedef struct { diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 01c1726e..15402e7a 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -79,6 +79,7 @@ class RestApi { String path = request->url().substring(5); if(path == "html/system") getHtmlSystem(root); else if(path == "html/logout") getHtmlLogout(root); + else if(path == "html/reboot") getHtmlReboot(root); else if(path == "html/save") getHtmlSave(root); else if(path == "system") getSysInfo(root); else if(path == "generic") getGeneric(root); @@ -264,6 +265,13 @@ class RestApi { obj[F("html")] = F("succesfully logged out"); } + void getHtmlReboot(JsonObject obj) { + getGeneric(obj.createNestedObject(F("generic"))); + obj[F("refresh")] = 20; + obj[F("refresh_url")] = "/"; + obj[F("html")] = F("rebooting ..."); + } + void getHtmlSave(JsonObject obj) { getGeneric(obj.createNestedObject(F("generic"))); obj["pending"] = (bool)mApp->getSavePending(); diff --git a/src/web/html/convert.py b/src/web/html/convert.py index 8b67d701..00f398ac 100644 --- a/src/web/html/convert.py +++ b/src/web/html/convert.py @@ -9,7 +9,10 @@ import subprocess def get_git_sha(): - return subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD']).decode('ascii').strip() + try: + return subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD']).decode('ascii').strip() + except: + return "0000000" def readVersion(path): f = open(path, "r") diff --git a/src/web/web.h b/src/web/web.h index 91818b96..46e5ccb7 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -327,7 +327,7 @@ class Web { mProtected = true; - AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), save_html, save_html_len); + AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), system_html, system_html_len); response->addHeader(F("Content-Encoding"), "gzip"); request->send(response); } @@ -375,7 +375,7 @@ class Web { void onReboot(AsyncWebServerRequest *request) { mApp->setRebootFlag(); - AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), save_html, save_html_len); + AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), system_html, system_html_len); response->addHeader(F("Content-Encoding"), "gzip"); request->send(response); } @@ -593,7 +593,7 @@ class Web { mApp->saveSettings((request->arg("reboot") == "on")); - AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), save_html, save_html_len); + AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), system_html, save_html_len); response->addHeader(F("Content-Encoding"), "gzip"); request->send(response); } From 32092ede0d72c66f8e526b82a1d9a4b7e692d1e4 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Fri, 24 Mar 2023 15:26:14 +0100 Subject: [PATCH 41/52] debug review - DPRINT_IVID - MI: some small changes --- src/hm/hmInverter.h | 14 +++--- src/hm/hmPayload.h | 98 ++++++++++++++++++++++---------------- src/hm/hmRadio.h | 4 +- src/hm/miPayload.h | 113 +++++++++++++++++++++----------------------- src/utils/dbg.h | 7 +-- 5 files changed, 123 insertions(+), 113 deletions(-) diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 6f6efe38..c098a081 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -143,10 +143,11 @@ class Inverter { template void enqueCommand(uint8_t cmd) { _commandQueue.push(std::make_shared(cmd)); - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(id)); - DBGPRINT(F(") enqueCommand: 0x")); - DHEX(cmd); + DPRINT_IVID(DBG_INFO, id); + //DPRINT(DBG_INFO, F("(#")); + //DBGPRINT(String(id)); + DBGPRINTLN(F("enqueCommand: 0x") + String(cmd, HEX)); + //DBGHEXLN(cmd); } void setQueuedCmdFinished() { @@ -289,7 +290,8 @@ class Inverter { alarmMesIndex = rec->record[pos]; //enqueCommand(AlarmUpdate); // What is the function of AlarmUpdate? - DPRINTLN(DBG_INFO, "alarm ID incremented to " + String(alarmMesIndex)); + DPRINT(DBG_INFO, "alarm ID incremented to "); + DBGPRINTLN(String(alarmMesIndex)); enqueCommand(AlarmData); } } @@ -303,7 +305,7 @@ class Inverter { DPRINTLN(DBG_DEBUG, "add config"); if (getPosByChFld(0, FLD_ACT_ACTIVE_PWR_LIMIT, rec) == pos){ actPowerLimit = rec->record[pos]; - DPRINT(DBG_DEBUG, F("Inverter actual power limit: ") + String(actPowerLimit, 1)); + DPRINTLN(DBG_DEBUG, F("Inverter actual power limit: ") + String(actPowerLimit, 1)); } } else if (rec->assign == AlarmDataAssignment) { diff --git a/src/hm/hmPayload.h b/src/hm/hmPayload.h index 7660c46b..7dda7e6f 100644 --- a/src/hm/hmPayload.h +++ b/src/hm/hmPayload.h @@ -116,12 +116,14 @@ class HmPayload { mStat->rxFail++; // got fragments but not complete response iv->setQueuedCmdFinished(); // command failed - if (mSerialDebug) - DPRINTLN(DBG_INFO, F("enqueued cmd failed/timeout")); if (mSerialDebug) { - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(") no Payload received! (retransmits: ")); + DPRINTLN(DBG_INFO, F("enqueued cmd failed/timeout")); + //if (mSerialDebug) { + //DPRINT(DBG_INFO, F("(#")); + //DBGPRINT(String(iv->id)); + //DBGPRINT(F(") no Payload received! (retransmits: ")); + DPRINT_IVID(DBG_INFO, iv->id); + DBGPRINT(F("no Payload received! (retransmits: ")); DBGPRINT(String(mPayload[iv->id].retransmits)); DBGPRINTLN(F(")")); } @@ -134,17 +136,21 @@ class HmPayload { yield(); if (mSerialDebug) { - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(") Requesting Inv SN ")); + DPRINT_IVID(DBG_INFO, iv->id); + //DPRINT(DBG_INFO, F("(#")); + //DBGPRINT(String(iv->id)); + //DBGPRINT(F(") Requesting Inv SN ")); + DBGPRINT(F("Requesting Inv SN ")); DBGPRINTLN(String(iv->config->serial.u64, HEX)); } if (iv->getDevControlRequest()) { if (mSerialDebug) { - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(") Devcontrol request 0x")); + //DPRINT(DBG_INFO, F("(#")); + //DBGPRINT(String(iv->id)); + //DBGPRINT(F(") Devcontrol request 0x")); + DPRINT_IVID(DBG_INFO, iv->id); + DBGPRINT(F("Devcontrol request 0x")); DBGPRINT(String(iv->devControlCmd, HEX)); DBGPRINT(F(" power limit ")); DBGPRINTLN(String(iv->powerLimit[0])); @@ -155,10 +161,12 @@ class HmPayload { //iv->enqueCommand(SystemConfigPara); // read back power limit } else { uint8_t cmd = iv->getQueuedCmd(); - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(") prepareDevInformCmd 0x")); - DBGPRINTLN(String(cmd, HEX)); + //DPRINT(DBG_INFO, F("(#")); + //DBGPRINT(String(iv->id)); + //DBGPRINT(F(") prepareDevInformCmd 0x")); + DPRINT_IVID(DBG_INFO, iv->id); + DBGPRINT(F("prepareDevInformCmd 0x")); + DBGHEXLN(cmd); mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex, false); mPayload[iv->id].txCmd = cmd; } @@ -170,9 +178,9 @@ class HmPayload { DPRINTLN(DBG_DEBUG, F("Response from info request received")); uint8_t *pid = &p->packet[9]; if (*pid == 0x00) { - DPRINT(DBG_DEBUG, F("fragment number zero received and ignored")); + DPRINTLN(DBG_DEBUG, F("fragment number zero received and ignored")); } else { - DPRINTLN(DBG_DEBUG, "PID: 0x" + String(*pid, HEX)); + DPRINTLN(DBG_DEBUG, F("PID: 0x") + String(*pid, HEX)); if ((*pid & 0x7F) < MAX_PAYLOAD_ENTRIES) { memcpy(mPayload[iv->id].data[(*pid & 0x7F) - 1], &p->packet[10], p->len - 11); mPayload[iv->id].len[(*pid & 0x7F) - 1] = p->len - 11; @@ -200,14 +208,17 @@ class HmPayload { mApp->setMqttPowerLimitAck(iv); else ok = false; - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(" has ")); - if(!ok) DBGPRINT(F("not ")); - DBGPRINT(F("accepted power limit set point ")); - DBGPRINT(String(iv->powerLimit[0])); - DBGPRINT(F(" with PowerLimitControl ")); - DBGPRINTLN(String(iv->powerLimit[1])); + //DPRINT(DBG_INFO, F("(#")); + //DBGPRINT(String(iv->id)); + if (mSerialDebug) { + DPRINT_IVID(DBG_INFO, iv->id); + DBGPRINT(F(" has ")); + if(!ok) DBGPRINT(F("not ")); + DBGPRINT(F("accepted power limit set point ")); + DBGPRINT(String(iv->powerLimit[0])); + DBGPRINT(F(" with PowerLimitControl ")); + DBGPRINTLN(String(iv->powerLimit[1])); + } iv->clearCmdQueue(); iv->enqueCommand(SystemConfigPara); // read back power limit @@ -243,9 +254,10 @@ class HmPayload { DPRINTLN(DBG_INFO, F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); mPayload[iv->id].retransmits = mMaxRetrans; } else if(iv->devControlCmd == ActivePowerContr) { - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DPRINTLN(DBG_INFO, F(") retransmit power limit")); + //DPRINT(DBG_INFO, F("(#")); + //DBGPRINT(String(iv->id)); + DPRINT_IVID(DBG_INFO, iv->id); + DPRINTLN(DBG_INFO, F("retransmit power limit")); mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true); } else { if(false == mPayload[iv->id].gotFragment) { @@ -255,16 +267,18 @@ class HmPayload { DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX)); mSys->Radio.prepareDevInformCmd(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); */ - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINTLN(F(") nothing received")); + //DPRINT(DBG_INFO, F("(#")); + //DBGPRINT(String(iv->id)); + DPRINT_IVID(DBG_INFO, iv->id); + DBGPRINTLN(F("nothing received")); mPayload[iv->id].retransmits = mMaxRetrans; } else { for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId - 1); i++) { if (mPayload[iv->id].len[i] == 0) { - DPRINT(DBG_WARN, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(") Frame ")); + //DPRINT(DBG_WARN, F("(#")); + //DBGPRINT(String(iv->id)); + DPRINT_IVID(DBG_WARN, iv->id); + DBGPRINT(F("Frame ")); DBGPRINT(String(i + 1)); DBGPRINTLN(F(" missing: Request Retransmit")); mSys->Radio.sendCmdPacket(iv->radioId.u64, TX_REQ_INFO, (SINGLE_FRAME + i), true); @@ -281,19 +295,19 @@ class HmPayload { mPayload[iv->id].retransmits++; DPRINTLN(DBG_WARN, F("CRC Error: Request Complete Retransmit")); mPayload[iv->id].txCmd = iv->getQueuedCmd(); - DPRINT(DBG_INFO, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINT(F(") prepareDevInformCmd 0x")); - DHEXLN(mPayload[iv->id].txCmd); + //DPRINT(DBG_INFO, F("(#")); + //DBGPRINT(String(iv->id)); + DPRINT_IVID(DBG_INFO, iv->id); + DBGPRINT(F("prepareDevInformCmd 0x")); + DBGHEXLN(mPayload[iv->id].txCmd); mSys->Radio.prepareDevInformCmd(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); } } else { // payload complete DPRINT(DBG_INFO, F("procPyld: cmd: 0x")); - DHEXLN(mPayload[iv->id].txCmd); + DBGHEXLN(mPayload[iv->id].txCmd); DPRINT(DBG_INFO, F("procPyld: txid: 0x")); - DHEXLN(mPayload[iv->id].txId); - DPRINTLN(DBG_DEBUG, F("procPyld: max: ")); - DBGPRINT(String(mPayload[iv->id].maxPackId)); + DBGHEXLN(mPayload[iv->id].txId); + DPRINTLN(DBG_DEBUG, F("procPyld: max: ") + String(mPayload[iv->id].maxPackId)); record_t<> *rec = iv->getRecordStruct(mPayload[iv->id].txCmd); // choose the parser mPayload[iv->id].complete = true; diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 40c92889..ff45a72d 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -177,7 +177,7 @@ class HmRadio { void sendControlPacket(uint64_t invId, uint8_t cmd, uint16_t *data, bool isRetransmit, bool isNoMI = true) { DPRINT(DBG_INFO, F("sendControlPacket cmd: 0x")); - DBGPRINTLN(String(cmd, HEX)); + DBGHEXLN(cmd); initPacket(invId, TX_REQ_DEVCONTROL, SINGLE_FRAME); uint8_t cnt = 10; if (isNoMI) { @@ -295,7 +295,7 @@ class HmRadio { } void initPacket(uint64_t invId, uint8_t mid, uint8_t pid) { - DPRINTLN(DBG_VERBOSE, F("initPacket, mid: ") + String(mid, HEX) + F(" pid: ") + String(pid, HEX)); + DPRINT(DBG_VERBOSE, F("initPacket, mid: ") + String(mid, HEX) + F(" pid: ") + String(pid, HEX)); memset(mTxBuf, 0, MAX_RF_PAYLOAD_SIZE); mTxBuf[0] = mid; // message id CP_U32_BigEndian(&mTxBuf[1], (invId >> 8)); diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index c5a6eb9a..753134d5 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -94,10 +94,10 @@ class MiPayload { iv->setQueuedCmdFinished(); // command failed if (mSerialDebug) - DPRINTHEAD(DBG_INFO, iv->id); + DPRINT_IVID(DBG_INFO, iv->id); DBGPRINTLN(F("enqueued cmd failed/timeout")); if (mSerialDebug) { - DPRINTHEAD(DBG_INFO, iv->id); + DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("no Payload received! (retransmits: ")); DBGPRINT(String(mPayload[iv->id].retransmits)); DBGPRINTLN(F(")")); @@ -111,14 +111,14 @@ class MiPayload { yield(); if (mSerialDebug){ - DPRINTHEAD(DBG_INFO, iv->id); + DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("Requesting Inv SN ")); DBGPRINTLN(String(iv->config->serial.u64, HEX)); } if (iv->getDevControlRequest()) { if (mSerialDebug) { - DPRINTHEAD(DBG_INFO, iv->id); + DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("Devcontrol request 0x")); DHEX(iv->devControlCmd); DBGPRINT(F(" power limit ")); @@ -132,9 +132,9 @@ class MiPayload { iv->enqueCommand(SystemConfigPara); // try to read back power limit } else { uint8_t cmd = iv->getQueuedCmd(); - DPRINTHEAD(DBG_INFO, iv->id); + DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("prepareDevInformCmd 0x")); - DHEXLN(cmd); + DBGHEXLN(cmd); uint8_t cmd2 = cmd; if ( cmd == SystemConfigPara ) { //0x05 for HM-types if (!mPayload[iv->id].limitrequested) { // only do once at startup @@ -180,7 +180,8 @@ class MiPayload { else if ( p->packet[0] == 0x09 + ALL_FRAMES || p->packet[0] == 0x11 + ALL_FRAMES || - ( p->packet[0] >= (0x36 + ALL_FRAMES) && p->packet[0] < (0x39 + SINGLE_FRAME) ) ) { // small MI or MI 1500 data responses to 0x09, 0x11, 0x36, 0x37, 0x38 and 0x39 + ( p->packet[0] >= (0x36 + ALL_FRAMES) && p->packet[0] < (0x39 + SINGLE_FRAME) + && mPayload[iv->id].txCmd != 0x0f) ) { // small MI or MI 1500 data responses to 0x09, 0x11, 0x36, 0x37, 0x38 and 0x39 mPayload[iv->id].txId = p->packet[0]; miDataDecode(iv,p); } @@ -231,13 +232,15 @@ const byteAssign_t InfoAssignment[] = { iv->setValue(i, rec, (float) ((p->packet[(12+2*i)] << 8) + p->packet[(13+2*i)])/1); } iv->isConnected = true; - DPRINTHEAD(DBG_INFO, iv->id); - DPRINT(DBG_INFO,F("HW_VER is ")); - DBGPRINTLN(String((p->packet[24] << 8) + p->packet[25])); + if(mSerialDebug) { + DPRINT_IVID(DBG_INFO, iv->id); + DPRINT(DBG_INFO,F("HW_VER is ")); + DBGPRINTLN(String((p->packet[24] << 8) + p->packet[25])); + } /*iv->setQueuedCmdFinished(); mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x0f, 0x01, false);*/ } else if ( p->packet[9] == 0x01 || p->packet[9] == 0x10 ) {//second frame for MI, 3rd gen. answers in 0x10 - DPRINTHEAD(DBG_INFO, iv->id); + DPRINT_IVID(DBG_INFO, iv->id); if ( p->packet[9] == 0x01 ) { DBGPRINTLN(F("got 2nd frame (hw info)")); } else { @@ -248,18 +251,21 @@ const byteAssign_t InfoAssignment[] = { DBGPRINTLN(String((uint32_t) (((p->packet[10] << 8) | p->packet[11]) << 8 | p->packet[12]) << 8 | p->packet[13])); //DBGPRINTLN(String((p->packet[12] << 8) + p->packet[13])); if ( p->packet[9] == 0x01 ) { - DPRINT(DBG_INFO,F("HW_ECapValue ")); - DBGPRINTLN(String((p->packet[20] << 8) + p->packet[21])); iv->setValue(iv->getPosByChFld(0, FLD_YT, rec), rec, (float) ((p->packet[20] << 8) + p->packet[21])/1); - DPRINT(DBG_INFO,F("HW_FB_TLmValue ")); - DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15])); - DPRINT(DBG_INFO,F("HW_FB_ReSPRT ")); - DBGPRINTLN(String((p->packet[16] << 8) + p->packet[17])); - DPRINT(DBG_INFO,F("HW_GridSamp_ResValule ")); - DBGPRINTLN(String((p->packet[18] << 8) + p->packet[19])); + if(mSerialDebug) { + DPRINT(DBG_INFO,F("HW_ECapValue ")); + DBGPRINTLN(String((p->packet[20] << 8) + p->packet[21])); + + DPRINT(DBG_INFO,F("HW_FB_TLmValue ")); + DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15])); + DPRINT(DBG_INFO,F("HW_FB_ReSPRT ")); + DBGPRINTLN(String((p->packet[16] << 8) + p->packet[17])); + DPRINT(DBG_INFO,F("HW_GridSamp_ResValule ")); + DBGPRINTLN(String((p->packet[18] << 8) + p->packet[19])); + } } } else if ( p->packet[9] == 0x12 ) {//3rd frame - DPRINTHEAD(DBG_INFO, iv->id); + DPRINT_IVID(DBG_INFO, iv->id); DBGPRINTLN(F("got 3rd frame (hw info)")); iv->setQueuedCmdFinished(); mStat->rxSuccess++; @@ -276,9 +282,8 @@ const byteAssign_t InfoAssignment[] = { DPRINT(DBG_DEBUG, F("fragment number zero received")); iv->setQueuedCmdFinished(); } else if (p->packet[9] == 0x81) { // might need some additional check, as this is only ment for short answers! - DPRINT(DBG_WARN, F("(#")); - DBGPRINT(String(iv->id)); - DBGPRINTLN(F(") seems to use 3rd gen. protocol - switching ivGen!")); + DPRINT_IVID(DBG_WARN, iv->id); + DBGPRINTLN(F("seems to use 3rd gen. protocol - switching ivGen!")); iv->ivGen = IV_HM; iv->setQueuedCmdFinished(); iv->clearCmdQueue(); @@ -301,7 +306,7 @@ const byteAssign_t InfoAssignment[] = { //} } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES ) // response from dev control command || p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES -1)) { // response from DRED instruction - DPRINTHEAD(DBG_DEBUG, iv->id); + DPRINT_IVID(DBG_DEBUG, iv->id); DBGPRINTLN(F("Response from devcontrol request received")); mPayload[iv->id].txId = p->packet[0]; @@ -309,7 +314,7 @@ const byteAssign_t InfoAssignment[] = { if ((p->packet[9] == 0x5a) && (p->packet[10] == 0x5a)) { mApp->setMqttPowerLimitAck(iv); - DPRINTHEAD(DBG_INFO, iv->id); + DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("has accepted power limit set point ")); DBGPRINT(String(iv->powerLimit[0])); DBGPRINT(F(" with PowerLimitControl ")); @@ -321,9 +326,9 @@ const byteAssign_t InfoAssignment[] = { iv->devControlCmd = Init; } else { // some other response; copied from hmPayload:process; might not be correct to do that here!!! DPRINT(DBG_INFO, F("procPyld: cmd: 0x")); - DHEXLN(mPayload[iv->id].txCmd); + DBGHEXLN(mPayload[iv->id].txCmd); DPRINT(DBG_INFO, F("procPyld: txid: 0x")); - DHEXLN(mPayload[iv->id].txId); + DBGHEXLN(mPayload[iv->id].txId); //DPRINT(DBG_DEBUG, F("procPyld: max: ")); //DBGPRINTLN(String(mPayload[iv->id].maxPackId)); record_t<> *rec = iv->getRecordStruct(mPayload[iv->id].txCmd); // choose the parser @@ -420,11 +425,11 @@ const byteAssign_t InfoAssignment[] = { if ((mPayload[iv->id].requested) && (retransmit)) { if (iv->devControlCmd == Restart || iv->devControlCmd == CleanState_LockAndAlarm) { // This is required to prevent retransmissions without answer. - DPRINTHEAD(DBG_INFO, iv->id); + DPRINT_IVID(DBG_INFO, iv->id); DBGPRINTLN(F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); mPayload[iv->id].retransmits = mMaxRetrans; } else if(iv->devControlCmd == ActivePowerContr) { - DPRINTHEAD(DBG_INFO, iv->id); + DPRINT_IVID(DBG_INFO, iv->id); DBGPRINTLN(F("retransmit power limit")); mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true, false); } else { @@ -432,7 +437,7 @@ const byteAssign_t InfoAssignment[] = { if (mPayload[iv->id].retransmits < mMaxRetrans) { mPayload[iv->id].retransmits++; if( !mPayload[iv->id].gotFragment ) { - DPRINTHEAD(DBG_INFO, iv->id); + DPRINT_IVID(DBG_INFO, iv->id); DBGPRINTLN(F("nothing received")); mPayload[iv->id].retransmits = mMaxRetrans; } else if ( cmd == 0x0f ) { @@ -463,7 +468,7 @@ const byteAssign_t InfoAssignment[] = { } } } - DPRINTHEAD(DBG_INFO, iv->id); + DPRINT_IVID(DBG_INFO, iv->id); if (change) { DBGPRINT(F("next request is")); //mPayload[iv->id].skipfirstrepeat = 0; @@ -472,7 +477,7 @@ const byteAssign_t InfoAssignment[] = { DBGPRINT(F(" missing: Request Retransmit")); } DBGPRINT(F(" 0x")); - DHEXLN(cmd); + DBGHEXLN(cmd); //mSys->Radio.sendCmdPacket(iv->radioId.u64, cmd, cmd, true); mSys->Radio.prepareDevInformCmd(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex, true, cmd); mPayload[iv->id].txCmd = cmd; @@ -484,13 +489,13 @@ const byteAssign_t InfoAssignment[] = { } else if(!crcPass && pyldComplete) { // crc error on complete Payload if (mPayload[iv->id].retransmits < mMaxRetrans) { mPayload[iv->id].retransmits++; - DPRINTHEAD(DBG_WARN, iv->id); + DPRINT_IVID(DBG_WARN, iv->id); DBGPRINTLN(F("CRC Error: Request Complete Retransmit")); mPayload[iv->id].txCmd = iv->getQueuedCmd(); - DPRINTHEAD(DBG_INFO, iv->id); + DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("prepareDevInformCmd 0x")); - DHEXLN(mPayload[iv->id].txCmd); + DBGHEXLN(mPayload[iv->id].txCmd); mSys->Radio.prepareDevInformCmd(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); } } @@ -574,8 +579,8 @@ const byteAssign_t InfoAssignment[] = { void miStsConsolidate(Inverter<> *iv, uint8_t stschan, record_t<> *rec, uint8_t uState, uint8_t uEnum, uint8_t lState = 0, uint8_t lEnum = 0) { //uint8_t status = (p->packet[11] << 8) + p->packet[12]; uint16_t status = 3; // regular status for MI, change to 1 later? - if ( uState < 3 ) { - status = uState*100 + stschan; //first approach, needs review! + if ( uState == 2 ) { + status = 5050 + stschan; //first approach, needs review! if (lState) status += lState*10; } else if ( uState > 3 ) { @@ -587,13 +592,16 @@ const byteAssign_t InfoAssignment[] = { if (uEnum < 6) { status += stschan; } + if (status == 8000) + status == 8310; //trick? } uint16_t prntsts = status == 3 ? 1 : status; if ( status != mPayload[iv->id].sts[stschan] ) { //sth.'s changed? mPayload[iv->id].sts[stschan] = status; DPRINT(DBG_WARN, F("Status change for CH")); - DBGPRINT(String(stschan)); DBGPRINT(F(": ")); + DBGPRINT(String(stschan)); DBGPRINT(F(" (")); + DBGPRINT(String(prntsts)); DBGPRINT(F("): ")); DBGPRINTLN(iv->getAlarmStr(prntsts)); } @@ -605,7 +613,7 @@ const byteAssign_t InfoAssignment[] = { if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){ iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]; // seems there's no status per channel in 3rd gen. models?!? - DPRINTHEAD(DBG_INFO, iv->id); + DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("alarm ID incremented to ")); DBGPRINTLN(String(iv->alarmMesIndex)); } @@ -692,7 +700,7 @@ const byteAssign_t InfoAssignment[] = { /*if (iv->alarmMesIndex < rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]){ iv->alarmMesIndex = rec->record[iv->getPosByChFld(0, FLD_EVT, rec)]; - DPRINTHEAD(DBG_INFO, iv->id); + DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT_TXT(TXT_INCRALM); DBGPRINTLN(String(iv->alarmMesIndex)); }*/ @@ -728,7 +736,7 @@ const byteAssign_t InfoAssignment[] = { if (mPayload[iv->id].complete) return; //if we got second message as well in repreated attempt mPayload[iv->id].complete = true; // For 2 CH devices, this might be too short... - DPRINTHEAD(DBG_INFO, iv->id); + DPRINT_IVID(DBG_INFO, iv->id); DBGPRINTLN(F("got all msgs")); record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0)); @@ -753,38 +761,23 @@ const byteAssign_t InfoAssignment[] = { bool build(uint8_t id, bool *complete) { DPRINTLN(DBG_VERBOSE, F("build")); - //DPRINTLN_TXT(DBG_VERBOSE, TXT_BUILD); - /*uint16_t crc = 0xffff, crcRcv = 0x0000; - if (mPayload[id].maxPackId > MAX_PAYLOAD_ENTRIES) - mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; - */ // check if all messages are there *complete = mPayload[id].complete; uint8_t txCmd = mPayload[id].txCmd; - //uint8_t cmd = getQueuedCmd(); + if(!*complete) { - DPRINTLN(DBG_VERBOSE, F("incomlete, txCmd is 0x") + String(txCmd, HEX)); // + F("cmd is 0x") + String(cmd, HEX)); + DPRINTLN(DBG_VERBOSE, F("incomlete, txCmd is 0x") + String(txCmd, HEX)); + //DBGHEXLN(txCmd); if (txCmd == 0x09 || txCmd == 0x11 || (txCmd >= 0x36 && txCmd <= 0x39)) return false; } - /*for (uint8_t i = 0; i < mPayload[id].maxPackId; i++) { - if (mPayload[id].len[i] > 0) { - if (i == (mPayload[id].maxPackId - 1)) { - crc = ah::crc16(mPayload[id].data[i], mPayload[id].len[i] - 2, crc); - crcRcv = (mPayload[id].data[i][mPayload[id].len[i] - 2] << 8) | (mPayload[id].data[i][mPayload[id].len[i] - 1]); - } else - crc = ah::crc16(mPayload[id].data[i], mPayload[id].len[i], crc); - } - yield(); - } - return (crc == crcRcv) ? true : false;*/ return true; } void reset(uint8_t id, bool clrSts = false) { - DPRINTHEAD(DBG_INFO, id); + DPRINT_IVID(DBG_INFO, id); DBGPRINTLN(F("resetPayload")); memset(mPayload[id].len, 0, MAX_PAYLOAD_ENTRIES); mPayload[id].gotFragment = false; diff --git a/src/utils/dbg.h b/src/utils/dbg.h index cae96447..c9947dd0 100644 --- a/src/utils/dbg.h +++ b/src/utils/dbg.h @@ -61,8 +61,9 @@ } } - inline void DHEXLN(uint8_t b) { - DHEX(b); + inline void DBGHEXLN(uint8_t b) { + if( b<0x10 ) DBGPRINT(F("0")); + DBGPRINT(String(b, HEX)); DBGPRINT(F("\r\n")); } /*inline void DHEX(uint16_t b) { @@ -151,7 +152,7 @@ }\ }) -#define DPRINTHEAD(level, id) ({\ +#define DPRINT_IVID(level, id) ({\ DPRINT(level, F("(#")); DBGPRINT(String(id)); DBGPRINT(F(") "));\ }) From c1e71288464fba993a82edf7120bfa069f05c4a2 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Fri, 24 Mar 2023 15:33:26 +0100 Subject: [PATCH 42/52] debug review --- src/hm/hmRadio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index ff45a72d..c47d0fec 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -295,7 +295,7 @@ class HmRadio { } void initPacket(uint64_t invId, uint8_t mid, uint8_t pid) { - DPRINT(DBG_VERBOSE, F("initPacket, mid: ") + String(mid, HEX) + F(" pid: ") + String(pid, HEX)); + DPRINTLN(DBG_VERBOSE, F("initPacket, mid: ") + String(mid, HEX) + F(" pid: ") + String(pid, HEX)); memset(mTxBuf, 0, MAX_RF_PAYLOAD_SIZE); mTxBuf[0] = mid; // message id CP_U32_BigEndian(&mTxBuf[1], (invId >> 8)); From 03b1eb126c652045fff35d629ece92dcfb26a765 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Fri, 24 Mar 2023 16:12:21 +0100 Subject: [PATCH 43/52] MI - small bugfix --- src/hm/miPayload.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index 753134d5..44f79e08 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -593,7 +593,7 @@ const byteAssign_t InfoAssignment[] = { status += stschan; } if (status == 8000) - status == 8310; //trick? + status = 8310; //trick? } uint16_t prntsts = status == 3 ? 1 : status; From a1fb4aa911fad7562d62e0481dd6ebfb5ae34b5e Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Fri, 24 Mar 2023 17:01:43 +0100 Subject: [PATCH 44/52] MI - fix length for command packets --- src/hm/hmRadio.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index c47d0fec..a9564196 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -208,6 +208,7 @@ class HmRadio { default: return; } + cnt++; } sendPacket(invId, cnt, isRetransmit, true); } From 3f2e40848ecbbefa2727884cf1038a623783fdb9 Mon Sep 17 00:00:00 2001 From: lumapu Date: Fri, 24 Mar 2023 23:26:35 +0100 Subject: [PATCH 45/52] review #804 --- src/hm/hmInverter.h | 9 ++++----- src/hm/hmPayload.h | 46 ++++++++++++--------------------------------- src/utils/dbg.h | 3 +-- 3 files changed, 17 insertions(+), 41 deletions(-) diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index c098a081..e8c20423 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -144,10 +144,8 @@ class Inverter { void enqueCommand(uint8_t cmd) { _commandQueue.push(std::make_shared(cmd)); DPRINT_IVID(DBG_INFO, id); - //DPRINT(DBG_INFO, F("(#")); - //DBGPRINT(String(id)); - DBGPRINTLN(F("enqueCommand: 0x") + String(cmd, HEX)); - //DBGHEXLN(cmd); + DBGPRINTLN(F("enqueCommand: 0x")); + DBGHEXLN(cmd); } void setQueuedCmdFinished() { @@ -305,7 +303,8 @@ class Inverter { DPRINTLN(DBG_DEBUG, "add config"); if (getPosByChFld(0, FLD_ACT_ACTIVE_PWR_LIMIT, rec) == pos){ actPowerLimit = rec->record[pos]; - DPRINTLN(DBG_DEBUG, F("Inverter actual power limit: ") + String(actPowerLimit, 1)); + DPRINT(DBG_DEBUG, F("Inverter actual power limit: ")); + DBGPRINTLN(String(actPowerLimit, 1)); } } else if (rec->assign == AlarmDataAssignment) { diff --git a/src/hm/hmPayload.h b/src/hm/hmPayload.h index 7dda7e6f..01282b00 100644 --- a/src/hm/hmPayload.h +++ b/src/hm/hmPayload.h @@ -118,10 +118,6 @@ class HmPayload { iv->setQueuedCmdFinished(); // command failed if (mSerialDebug) { DPRINTLN(DBG_INFO, F("enqueued cmd failed/timeout")); - //if (mSerialDebug) { - //DPRINT(DBG_INFO, F("(#")); - //DBGPRINT(String(iv->id)); - //DBGPRINT(F(") no Payload received! (retransmits: ")); DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("no Payload received! (retransmits: ")); DBGPRINT(String(mPayload[iv->id].retransmits)); @@ -137,18 +133,12 @@ class HmPayload { yield(); if (mSerialDebug) { DPRINT_IVID(DBG_INFO, iv->id); - //DPRINT(DBG_INFO, F("(#")); - //DBGPRINT(String(iv->id)); - //DBGPRINT(F(") Requesting Inv SN ")); DBGPRINT(F("Requesting Inv SN ")); DBGPRINTLN(String(iv->config->serial.u64, HEX)); } if (iv->getDevControlRequest()) { if (mSerialDebug) { - //DPRINT(DBG_INFO, F("(#")); - //DBGPRINT(String(iv->id)); - //DBGPRINT(F(") Devcontrol request 0x")); DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("Devcontrol request 0x")); DBGPRINT(String(iv->devControlCmd, HEX)); @@ -161,9 +151,6 @@ class HmPayload { //iv->enqueCommand(SystemConfigPara); // read back power limit } else { uint8_t cmd = iv->getQueuedCmd(); - //DPRINT(DBG_INFO, F("(#")); - //DBGPRINT(String(iv->id)); - //DBGPRINT(F(") prepareDevInformCmd 0x")); DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("prepareDevInformCmd 0x")); DBGHEXLN(cmd); @@ -180,7 +167,8 @@ class HmPayload { if (*pid == 0x00) { DPRINTLN(DBG_DEBUG, F("fragment number zero received and ignored")); } else { - DPRINTLN(DBG_DEBUG, F("PID: 0x") + String(*pid, HEX)); + DPRINT(DBG_DEBUG, F("PID: 0x")); + DBGHEXLN(*pid); if ((*pid & 0x7F) < MAX_PAYLOAD_ENTRIES) { memcpy(mPayload[iv->id].data[(*pid & 0x7F) - 1], &p->packet[10], p->len - 11); mPayload[iv->id].len[(*pid & 0x7F) - 1] = p->len - 11; @@ -208,17 +196,14 @@ class HmPayload { mApp->setMqttPowerLimitAck(iv); else ok = false; - //DPRINT(DBG_INFO, F("(#")); - //DBGPRINT(String(iv->id)); - if (mSerialDebug) { - DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINT(F(" has ")); - if(!ok) DBGPRINT(F("not ")); - DBGPRINT(F("accepted power limit set point ")); - DBGPRINT(String(iv->powerLimit[0])); - DBGPRINT(F(" with PowerLimitControl ")); - DBGPRINTLN(String(iv->powerLimit[1])); - } + + DPRINT_IVID(DBG_INFO, iv->id); + DBGPRINT(F("has ")); + if(!ok) DBGPRINT(F("not ")); + DBGPRINT(F("accepted power limit set point ")); + DBGPRINT(String(iv->powerLimit[0])); + DBGPRINT(F(" with PowerLimitControl ")); + DBGPRINTLN(String(iv->powerLimit[1])); iv->clearCmdQueue(); iv->enqueCommand(SystemConfigPara); // read back power limit @@ -254,8 +239,6 @@ class HmPayload { DPRINTLN(DBG_INFO, F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); mPayload[iv->id].retransmits = mMaxRetrans; } else if(iv->devControlCmd == ActivePowerContr) { - //DPRINT(DBG_INFO, F("(#")); - //DBGPRINT(String(iv->id)); DPRINT_IVID(DBG_INFO, iv->id); DPRINTLN(DBG_INFO, F("retransmit power limit")); mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit, true); @@ -267,16 +250,12 @@ class HmPayload { DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX)); mSys->Radio.prepareDevInformCmd(iv->radioId.u64, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); */ - //DPRINT(DBG_INFO, F("(#")); - //DBGPRINT(String(iv->id)); DPRINT_IVID(DBG_INFO, iv->id); DBGPRINTLN(F("nothing received")); mPayload[iv->id].retransmits = mMaxRetrans; } else { for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId - 1); i++) { if (mPayload[iv->id].len[i] == 0) { - //DPRINT(DBG_WARN, F("(#")); - //DBGPRINT(String(iv->id)); DPRINT_IVID(DBG_WARN, iv->id); DBGPRINT(F("Frame ")); DBGPRINT(String(i + 1)); @@ -295,8 +274,6 @@ class HmPayload { mPayload[iv->id].retransmits++; DPRINTLN(DBG_WARN, F("CRC Error: Request Complete Retransmit")); mPayload[iv->id].txCmd = iv->getQueuedCmd(); - //DPRINT(DBG_INFO, F("(#")); - //DBGPRINT(String(iv->id)); DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("prepareDevInformCmd 0x")); DBGHEXLN(mPayload[iv->id].txCmd); @@ -307,7 +284,8 @@ class HmPayload { DBGHEXLN(mPayload[iv->id].txCmd); DPRINT(DBG_INFO, F("procPyld: txid: 0x")); DBGHEXLN(mPayload[iv->id].txId); - DPRINTLN(DBG_DEBUG, F("procPyld: max: ") + String(mPayload[iv->id].maxPackId)); + DPRINT(DBG_DEBUG, F("procPyld: max: ")); + DBGPRINTLN(String(mPayload[iv->id].maxPackId)); record_t<> *rec = iv->getRecordStruct(mPayload[iv->id].txCmd); // choose the parser mPayload[iv->id].complete = true; diff --git a/src/utils/dbg.h b/src/utils/dbg.h index c9947dd0..4716d7ae 100644 --- a/src/utils/dbg.h +++ b/src/utils/dbg.h @@ -62,8 +62,7 @@ } inline void DBGHEXLN(uint8_t b) { - if( b<0x10 ) DBGPRINT(F("0")); - DBGPRINT(String(b, HEX)); + DHEX(b); DBGPRINT(F("\r\n")); } /*inline void DHEX(uint16_t b) { From 850cda3c384c104fc46f2b29043d4e739e88c2a5 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 25 Mar 2023 02:10:16 +0100 Subject: [PATCH 46/52] 0.5.106 * merged MI and debug message changes #804 * fixed MQTT autodiscover #794, #632 --- src/CHANGES.md | 4 + src/defines.h | 2 +- src/platformio.ini | 19 ++-- src/publisher/pubMqtt.h | 191 ++++++++++++++++++++++------------------ 4 files changed, 117 insertions(+), 99 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 4223ad99..70b87e0f 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -2,6 +2,10 @@ (starting from release version `0.5.66`) +## 0.5.106 +* merged MI and debug message changes #804 +* fixed MQTT autodiscover #794, #632 + ## 0.5.105 * merged MI, thx @rejoe2 #788 * fixed reboot message #793 diff --git a/src/defines.h b/src/defines.h index dafcb9ec..d0c57264 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 5 -#define VERSION_PATCH 105 +#define VERSION_PATCH 106 //------------------------------------- typedef struct { diff --git a/src/platformio.ini b/src/platformio.ini index 6d3f8d23..38e67c95 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -35,25 +35,20 @@ extra_scripts = lib_deps = https://github.com/yubox-node-org/ESPAsyncWebServer - nrf24/RF24 - paulstoffregen/Time + nrf24/RF24 @ ^1.4.5 + paulstoffregen/Time @ ^1.6.1 https://github.com/bertmelis/espMqttClient#v1.4.1 - bblanchon/ArduinoJson - https://github.com/JChristensen/Timezone - olikraus/U8g2 - zinggjm/GxEPD2@^1.5.0 - ;esp8266/DNSServer - ;esp8266/EEPROM - ;esp8266/ESP8266WiFi - ;esp8266/SPI - ;esp8266/Ticker + bblanchon/ArduinoJson @ ^6.21.0 + https://github.com/JChristensen/Timezone @ ^1.2.4 + olikraus/U8g2 @ ^2.34.16 + zinggjm/GxEPD2 @ ^1.5.0 [env:esp8266-release] platform = espressif8266 board = esp12e board_build.f_cpu = 80000000L -build_flags = -D RELEASE +build_flags = -D RELEASE -Wl,-Map,output.map monitor_filters = ;default ; Remove typical terminal control codes from input ;time ; Add timestamp with milliseconds for each new line diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 73196918..a529d1fc 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -34,6 +34,12 @@ struct alarm_t { alarm_t(uint16_t c, uint32_t s, uint32_t e) : code(c), start(s), end(e) {} }; +typedef struct { + bool running; + uint8_t lastIvId; + uint8_t sub; +} discovery_t; + template class PubMqtt { public: @@ -55,6 +61,8 @@ class PubMqtt { mUtcTimestamp = utcTs; mIntervalTimeout = 1; + mDiscovery.running = false; + snprintf(mLwtTopic, MQTT_TOPIC_LEN + 5, "%s/mqtt", mCfgMqtt->topic); if((strlen(mCfgMqtt->user) > 0) && (strlen(mCfgMqtt->pwd) > 0)) @@ -82,6 +90,9 @@ class PubMqtt { mClient.loop(); yield(); #endif + + if(mDiscovery.running) + discoveryConfigLoop(); } @@ -210,92 +221,9 @@ class PubMqtt { void sendDiscoveryConfig(void) { DPRINTLN(DBG_VERBOSE, F("sendMqttDiscoveryConfig")); - - char topic[64], name[32], uniq_id[32]; - DynamicJsonDocument doc(256); - - uint8_t fldTotal[4] = {FLD_PAC, FLD_YT, FLD_YD, FLD_PDC}; - const char* unitTotal[4] = {"W", "kWh", "Wh", "W"}; - - String node_mac = WiFi.macAddress().substring(12,14)+ WiFi.macAddress().substring(15,17); - String node_id = "AHOY_DTU_" + node_mac; - bool total = false; - - for (uint8_t id = 0; id < mSys->getNumInverters() ; id++) { - doc.clear(); - - if (total) // total become true at iv = NULL next cycle - continue; - - Inverter<> *iv = mSys->getInverterByPos(id); - if (NULL == iv) - total = true; - record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); - - if (!total) { - doc[F("name")] = iv->config->name; - doc[F("ids")] = String(iv->config->serial.u64, HEX); - doc[F("mdl")] = iv->config->name; - } - else { - doc[F("name")] = node_id; - doc[F("ids")] = node_id; - doc[F("mdl")] = node_id; - } - - doc[F("cu")] = F("http://") + String(WiFi.localIP().toString()); - doc[F("mf")] = F("Hoymiles"); - JsonObject deviceObj = doc.as(); // deviceObj is only pointer!? - - for (uint8_t i = 0; i < ((!total) ? (rec->length) : (4) ) ; i++) { - const char *devCls, *stateCls; - if (!total) { - if (rec->assign[i].ch == CH0) - snprintf(name, 32, "%s %s", iv->config->name, iv->getFieldName(i, rec)); - else - snprintf(name, 32, "%s CH%d %s", iv->config->name, rec->assign[i].ch, iv->getFieldName(i, rec)); - snprintf(topic, 64, "/ch%d/%s", rec->assign[i].ch, iv->getFieldName(i, rec)); - snprintf(uniq_id, 32, "ch%d_%s", rec->assign[i].ch, iv->getFieldName(i, rec)); - - devCls = getFieldDeviceClass(rec->assign[i].fieldId); - stateCls = getFieldStateClass(rec->assign[i].fieldId); - } - - else { // total values - snprintf(name, 32, "Total %s", fields[fldTotal[i]]); - snprintf(topic, 64, "/%s", fields[fldTotal[i]]); - snprintf(uniq_id, 32, "total_%s", fields[fldTotal[i]]); - devCls = getFieldDeviceClass(fldTotal[i]); - stateCls = getFieldStateClass(fldTotal[i]); - } - - DynamicJsonDocument doc2(512); - doc2[F("name")] = name; - doc2[F("stat_t")] = String(mCfgMqtt->topic) + "/" + ((!total) ? String(iv->config->name) : "total" ) + String(topic); - doc2[F("unit_of_meas")] = ((!total) ? (iv->getUnit(i,rec)) : (unitTotal[i])); - doc2[F("uniq_id")] = ((!total) ? (String(iv->config->serial.u64, HEX)) : (node_id)) + "_" + uniq_id; - doc2[F("dev")] = deviceObj; - if (!(String(stateCls) == String("total_increasing"))) - doc2[F("exp_aft")] = MQTT_INTERVAL + 5; // add 5 sec if connection is bad or ESP too slow @TODO: stimmt das wirklich als expire!? - if (devCls != NULL) - doc2[F("dev_cla")] = String(devCls); - if (stateCls != NULL) - doc2[F("stat_cla")] = String(stateCls); - - if (!total) - snprintf(topic, 64, "%s/sensor/%s/ch%d_%s/config", MQTT_DISCOVERY_PREFIX, iv->config->name, rec->assign[i].ch, iv->getFieldName(i, rec)); - else // total values - snprintf(topic, 64, "%s/sensor/%s/total_%s/config", MQTT_DISCOVERY_PREFIX, node_id.c_str(),fields[fldTotal[i]]); - size_t size = measureJson(doc2) + 1; - char *buf = new char[size]; - memset(buf, 0, size); - serializeJson(doc2, buf, size); - publish(topic, buf, true, false); - delete[] buf; - } - - yield(); - } + mDiscovery.running = true; + mDiscovery.lastIvId = 0; + mDiscovery.sub = 0; } void setPowerLimitAck(Inverter<> *iv) { @@ -415,6 +343,95 @@ class PubMqtt { mRxCnt++; } + void discoveryConfigLoop(void) { + char topic[64], name[32], uniq_id[32], buf[350]; + DynamicJsonDocument doc(256); + + uint8_t fldTotal[4] = {FLD_PAC, FLD_YT, FLD_YD, FLD_PDC}; + const char* unitTotal[4] = {"W", "kWh", "Wh", "W"}; + + String node_mac = WiFi.macAddress().substring(12,14)+ WiFi.macAddress().substring(15,17); + String node_id = "AHOY_DTU_" + node_mac; + bool total = (mDiscovery.lastIvId == MAX_NUM_INVERTERS); + + Inverter<> *iv = mSys->getInverterByPos(mDiscovery.lastIvId); + record_t<> *rec; + if (NULL != iv) + rec = iv->getRecordStruct(RealTimeRunData_Debug); + + if ((NULL != iv) || total) { + if (!total) { + doc[F("name")] = iv->config->name; + doc[F("ids")] = String(iv->config->serial.u64, HEX); + doc[F("mdl")] = iv->config->name; + } + else { + doc[F("name")] = node_id; + doc[F("ids")] = node_id; + doc[F("mdl")] = node_id; + } + + doc[F("cu")] = F("http://") + String(WiFi.localIP().toString()); + doc[F("mf")] = F("Hoymiles"); + JsonObject deviceObj = doc.as(); // deviceObj is only pointer!? + + const char *devCls, *stateCls; + if (!total) { + if (rec->assign[mDiscovery.sub].ch == CH0) + snprintf(name, 32, "%s %s", iv->config->name, iv->getFieldName(mDiscovery.sub, rec)); + else + snprintf(name, 32, "%s CH%d %s", iv->config->name, rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); + snprintf(topic, 64, "/ch%d/%s", rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); + snprintf(uniq_id, 32, "ch%d_%s", rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); + + devCls = getFieldDeviceClass(rec->assign[mDiscovery.sub].fieldId); + stateCls = getFieldStateClass(rec->assign[mDiscovery.sub].fieldId); + } + + else { // total values + snprintf(name, 32, "Total %s", fields[fldTotal[mDiscovery.sub]]); + snprintf(topic, 64, "/%s", fields[fldTotal[mDiscovery.sub]]); + snprintf(uniq_id, 32, "total_%s", fields[fldTotal[mDiscovery.sub]]); + devCls = getFieldDeviceClass(fldTotal[mDiscovery.sub]); + stateCls = getFieldStateClass(fldTotal[mDiscovery.sub]); + } + + DynamicJsonDocument doc2(512); + doc2[F("name")] = name; + doc2[F("stat_t")] = String(mCfgMqtt->topic) + "/" + ((!total) ? String(iv->config->name) : "total" ) + String(topic); + doc2[F("unit_of_meas")] = ((!total) ? (iv->getUnit(mDiscovery.sub, rec)) : (unitTotal[mDiscovery.sub])); + doc2[F("uniq_id")] = ((!total) ? (String(iv->config->serial.u64, HEX)) : (node_id)) + "_" + uniq_id; + doc2[F("dev")] = deviceObj; + if (!(String(stateCls) == String("total_increasing"))) + doc2[F("exp_aft")] = MQTT_INTERVAL + 5; // add 5 sec if connection is bad or ESP too slow @TODO: stimmt das wirklich als expire!? + if (devCls != NULL) + doc2[F("dev_cla")] = String(devCls); + if (stateCls != NULL) + doc2[F("stat_cla")] = String(stateCls); + + if (!total) + snprintf(topic, 64, "%s/sensor/%s/ch%d_%s/config", MQTT_DISCOVERY_PREFIX, iv->config->name, rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); + else // total values + snprintf(topic, 64, "%s/sensor/%s/total_%s/config", MQTT_DISCOVERY_PREFIX, node_id.c_str(),fields[fldTotal[mDiscovery.sub]]); + size_t size = measureJson(doc2) + 1; + memset(buf, 0, size); + serializeJson(doc2, buf, size); + publish(topic, buf, true, false); + + if(++mDiscovery.sub == ((!total) ? (rec->length) : 4)) { + mDiscovery.sub = 0; + if(++mDiscovery.lastIvId == (MAX_NUM_INVERTERS + 1)) + mDiscovery.running = false; + } + } else { + mDiscovery.sub = 0; + if(++mDiscovery.lastIvId == (MAX_NUM_INVERTERS + 1)) + mDiscovery.running = false; + } + + yield(); + } + const char *getFieldDeviceClass(uint8_t fieldId) { uint8_t pos = 0; for (; pos < DEVICE_CLS_ASSIGN_LIST_LEN; pos++) { @@ -643,6 +660,8 @@ class PubMqtt { char mClientId[24]; // number of chars is limited to 23 up to v3.1 of MQTT // global buffer for mqtt topic. Used when publishing mqtt messages. char mTopic[MQTT_TOPIC_LEN + 32 + MAX_NAME_LENGTH + 1]; + + discovery_t mDiscovery; }; #endif /*__PUB_MQTT_H__*/ From ecfefc6041494f5ce6b2ef208ac4361f8ac9ec79 Mon Sep 17 00:00:00 2001 From: Tobias Wolf Date: Sat, 25 Mar 2023 20:23:01 +0100 Subject: [PATCH 47/52] Add uptime to Prometheus metrics --- src/web/web.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/web/web.h b/src/web/web.h index 46e5ccb7..7612b6b9 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -681,8 +681,13 @@ class Web { mApp->getVersion(), mConfig->sys.deviceName); metrics = String(type) + String(topic); - snprintf(topic,sizeof(topic),"# TYPE ahoy_solar_freeheap gauge\nahoy_solar_freeheap{devicename=\"%s\"} %u\n",mConfig->sys.deviceName,ESP.getFreeHeap()); - metrics += String(topic); + snprintf(type,sizeof(type),"# TYPE ahoy_solar_freeheap gauge\n"); + snprintf(topic,sizeof(topic),"ahoy_solar_freeheap{devicename=\"%s\"} %u\n",mConfig->sys.deviceName,ESP.getFreeHeap()); + metrics += String(type) + String(topic); + + snprintf(type,sizeof(type),"# TYPE ahoy_solar_uptime counter\n"); + snprintf(topic,sizeof(topic),"ahoy_solar_uptime{devicename=\"%s\"} %u\n", mApp->getUptime()); + metrics += String(type) + String(topic); // NRF Statistics stat = mApp->getStatistics(); @@ -789,7 +794,7 @@ class Web { String radioStatistic(String statistic, uint32_t value) { char type[60], topic[80], val[25]; - snprintf(type, sizeof(type), "# TYPE ahoy_solar_radio_%s gauge",statistic.c_str()); + snprintf(type, sizeof(type), "# TYPE ahoy_solar_radio_%s counter",statistic.c_str()); snprintf(topic, sizeof(topic), "ahoy_solar_radio_%s",statistic.c_str()); snprintf(val, sizeof(val), "%d", value); return ( String(type) + "\n" + String(topic) + " " + String(val) + "\n"); From 380f86cda1b7ca85621a51dc02109d3bd11ef709 Mon Sep 17 00:00:00 2001 From: Tobias Wolf Date: Sat, 25 Mar 2023 20:42:22 +0100 Subject: [PATCH 48/52] Add missing argument for devicename --- src/web/web.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/web/web.h b/src/web/web.h index 7612b6b9..a7e455b3 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -686,7 +686,7 @@ class Web { metrics += String(type) + String(topic); snprintf(type,sizeof(type),"# TYPE ahoy_solar_uptime counter\n"); - snprintf(topic,sizeof(topic),"ahoy_solar_uptime{devicename=\"%s\"} %u\n", mApp->getUptime()); + snprintf(topic,sizeof(topic),"ahoy_solar_uptime{devicename=\"%s\"} %u\n", mConfig->sys.deviceName, mApp->getUptime()); metrics += String(type) + String(topic); // NRF Statistics From e2f8b7bea3f1f2b7cb769c580c9a59f4e84b19dd Mon Sep 17 00:00:00 2001 From: Tobias Wolf Date: Sat, 25 Mar 2023 21:35:55 +0100 Subject: [PATCH 49/52] Also add RSSI metric --- src/web/web.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/web/web.h b/src/web/web.h index a7e455b3..0d780007 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -689,6 +689,10 @@ class Web { snprintf(topic,sizeof(topic),"ahoy_solar_uptime{devicename=\"%s\"} %u\n", mConfig->sys.deviceName, mApp->getUptime()); metrics += String(type) + String(topic); + snprintf(type,sizeof(type),"# TYPE ahoy_solar_wifi_rssi_db gauge\n"); + snprintf(topic,sizeof(topic),"ahoy_solar_wifi_rssi_db{devicename=\"%s\"} %d\n", mConfig->sys.deviceName, WiFi.RSSI()); + metrics += String(type) + String(topic); + // NRF Statistics stat = mApp->getStatistics(); metrics += radioStatistic(F("rx_success"), stat->rxSuccess); From 7c449b67d4e4793b33533059da04246b16dd4954 Mon Sep 17 00:00:00 2001 From: Tobias Wolf Date: Sat, 25 Mar 2023 23:33:17 +0100 Subject: [PATCH 50/52] Add description for new metrics --- doc/prometheus_ep_description.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/prometheus_ep_description.md b/doc/prometheus_ep_description.md index 9d274f1e..8fb9e002 100644 --- a/doc/prometheus_ep_description.md +++ b/doc/prometheus_ep_description.md @@ -18,6 +18,8 @@ Prometheus metrics provided at `/metrics`. | Metric name | Type | Description | Labels | |----------------------------------------|---------|--------------------------------------------------------|--------------| | `ahoy_solar_info` | Gauge | Information about the AhoyDTU device | version, image, devicename | +| `ahoy_solar_uptime` | Counter | Seconds since boot of the AhoyDTU device | devicename | +| `ahoy_solar_rssi_db` | Gauge | Quality of the Wifi STA connection | devicename | | `ahoy_solar_inverter_info` | Gauge | Information about the configured inverter(s) | name, serial | | `ahoy_solar_inverter_enabled` | Gauge | Is the inverter enabled? | inverter | | `ahoy_solar_inverter_is_available` | Gauge | is the inverter available? | inverter | From 081adeb140a4b74220990b16b935d1fc305fc61b Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 26 Mar 2023 01:03:59 +0100 Subject: [PATCH 51/52] 0.5.107 * fix: show save message * fix: removed serial newline for `enqueueCmd` --- src/CHANGES.md | 4 ++++ src/defines.h | 2 +- src/hm/hmInverter.h | 2 +- src/web/web.h | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 70b87e0f..d4ab8b79 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -2,6 +2,10 @@ (starting from release version `0.5.66`) +## 0.5.107 +* fix: show save message +* fix: removed serial newline for `enqueueCmd` + ## 0.5.106 * merged MI and debug message changes #804 * fixed MQTT autodiscover #794, #632 diff --git a/src/defines.h b/src/defines.h index d0c57264..05cbd23b 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 5 -#define VERSION_PATCH 106 +#define VERSION_PATCH 107 //------------------------------------- typedef struct { diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index e8c20423..d3efd9ac 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -144,7 +144,7 @@ class Inverter { void enqueCommand(uint8_t cmd) { _commandQueue.push(std::make_shared(cmd)); DPRINT_IVID(DBG_INFO, id); - DBGPRINTLN(F("enqueCommand: 0x")); + DBGPRINT(F("enqueCommand: 0x")); DBGHEXLN(cmd); } diff --git a/src/web/web.h b/src/web/web.h index 46e5ccb7..b83e06b5 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -593,7 +593,7 @@ class Web { mApp->saveSettings((request->arg("reboot") == "on")); - AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), system_html, save_html_len); + AsyncWebServerResponse *response = request->beginResponse_P(200, F("text/html; charset=UTF-8"), save_html, save_html_len); response->addHeader(F("Content-Encoding"), "gzip"); request->send(response); } From a95dce51c66350d970dc4c50b34143ad593c6ed7 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 26 Mar 2023 01:27:20 +0100 Subject: [PATCH 52/52] 0.5.107 --- src/CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CHANGES.md b/src/CHANGES.md index d4ab8b79..7c58866a 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -5,6 +5,7 @@ ## 0.5.107 * fix: show save message * fix: removed serial newline for `enqueueCmd` +* Merged improved Prometheus #808 ## 0.5.106 * merged MI and debug message changes #804