From 4d19e2dde4cde676347f98733da4dc3a2963511a Mon Sep 17 00:00:00 2001 From: lumapu Date: Fri, 18 Aug 2023 17:31:57 +0200 Subject: [PATCH 001/267] 0.7.37 * fix alarm time on WebGui #1099 * added RSSI info for HMS and HMT inverters (MqTT + REST API) --- src/CHANGES.md | 21 +++++++-------------- src/defines.h | 2 +- src/hm/hmInverter.h | 2 ++ src/hms/hmsPayload.h | 8 ++++++++ src/publisher/pubMqttIvData.h | 6 ++++++ src/web/RestApi.h | 1 + src/web/html/api.js | 4 ++-- src/web/html/visualization.html | 7 +++++-- 8 files changed, 32 insertions(+), 19 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index f788eef3..8b2ca4d6 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,15 +1,8 @@ -Changelog v0.7.36 +# Development Changes -* added Ethernet variant -* fix configuration of ePaper -* fix MI inverter support -* endpoints `/api/record/live`, `/api/record/alarm`, `/api/record/config`, `/api/record/info` are obsolete -* added `/api/inverter/alarm/[ID]` to read inverter alarms -* added Alarms in Live View as modal window -* added MqTT transmission of last 10 alarms -* updated documentation -* changed `ESP8266` default NRF24 pin assignments (`D3` = `CE` and `D4` = `IRQ`) -* changed live view to gray once inverter isn't available -> fast identify if inverters are online -* added information about maximum power (AC and DC) -* updated documentation -* several small fixes +## 0.7.37 - 2023-08-18 +* fix alarm time on WebGui #1099 +* added RSSI info for HMS and HMT inverters (MqTT + REST API) + +## 0.7.36 +* last Release diff --git a/src/defines.h b/src/defines.h index 8b6c0dab..163e22b5 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 7 -#define VERSION_PATCH 36 +#define VERSION_PATCH 37 //------------------------------------- typedef struct { diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 594f4211..cfcd134a 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -151,6 +151,7 @@ class Inverter { std::array lastAlarm; // holds last 10 alarms uint8_t alarmNxtWrPos; // indicates the position in array (rolling buffer) uint16_t alarmCnt; // counts the total number of occured alarms + int8_t rssi; // HMS and HMT inverters only static uint32_t *timestamp; // system timestamp @@ -171,6 +172,7 @@ class Inverter { status = InverterStatus::OFF; alarmNxtWrPos = 0; alarmCnt = 0; + rssi = -127; } ~Inverter() { diff --git a/src/hms/hmsPayload.h b/src/hms/hmsPayload.h index c167fd43..bfa75f1a 100644 --- a/src/hms/hmsPayload.h +++ b/src/hms/hmsPayload.h @@ -19,6 +19,7 @@ typedef struct { //uint8_t invId; uint32_t ts; uint8_t data[MAX_PAYLOAD_ENTRIES][MAX_RF_PAYLOAD_SIZE]; + int8_t rssi[MAX_PAYLOAD_ENTRIES]; uint8_t len[MAX_PAYLOAD_ENTRIES]; bool complete; uint8_t maxPackId; @@ -160,6 +161,7 @@ class HmsPayload { memcpy(mPayload[iv->id].data[(*pid & 0x7F) - 1], &p->data[11], p->data[0] - 11); mPayload[iv->id].len[(*pid & 0x7F) - 1] = p->data[0] -11; mPayload[iv->id].gotFragment = true; + mPayload[iv->id].rssi[(*pid & 0x7F) - 1] = p->rssi; } if ((*pid & ALL_FRAMES) == ALL_FRAMES) { @@ -281,6 +283,8 @@ class HmsPayload { memset(payload, 0, 150); + int8_t rssi = -127; + for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId); i++) { if((mPayload[iv->id].len[i] + payloadLen) > 150) { DPRINTLN(DBG_ERROR, F("payload buffer to small!")); @@ -288,6 +292,9 @@ class HmsPayload { } memcpy(&payload[payloadLen], mPayload[iv->id].data[i], (mPayload[iv->id].len[i])); payloadLen += (mPayload[iv->id].len[i]); + // get worst RSSI + if(mPayload[iv->id].rssi[i] > rssi) + rssi = mPayload[iv->id].rssi[i]; yield(); } payloadLen -= 2; @@ -310,6 +317,7 @@ class HmsPayload { iv->addValue(i, payload, rec); yield(); } + iv->rssi = rssi; iv->doCalculations(); notify(mPayload[iv->id].txCmd, iv); diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h index 57bf5609..22a2626d 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -106,6 +106,12 @@ class PubMqttIvData { snprintf(mVal, 40, "%d", mIv->getLastTs(rec)); mPublish(mSubTopic, mVal, true, QOS_0); + if((mIv->ivGen == IV_HMS) || (mIv->ivGen == IV_HMT)) { + snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/ch0/rssi", mIv->config->name); + snprintf(mVal, 40, "%d", mIv->rssi); + mPublish(mSubTopic, mVal, false, QOS_0); + } + mIv->isProducing(); // recalculate status mState = SEND_DATA; } else if(mSendTotals && mTotalFound) diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 861e8994..ddc16d52 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -367,6 +367,7 @@ class RestApi { obj[F("generation")] = iv->ivGen; obj[F("status")] = (uint8_t)iv->status; obj[F("alarm_cnt")] = iv->alarmCnt; + obj[F("rssi")] = iv->rssi; JsonArray ch = obj.createNestedArray("ch"); diff --git a/src/web/html/api.js b/src/web/html/api.js index 1548190c..93429afc 100644 --- a/src/web/html/api.js +++ b/src/web/html/api.js @@ -126,8 +126,8 @@ function toIsoDateStr(d) { return new Date(d.getTime() + (d.getTimezoneOffset() * -60000)).toISOString().substring(0, 19).replace('T', ', '); } -function toIsoTimeStr(d) { - return new Date(d.getTime() + (d.getTimezoneOffset() * -60000)).toISOString().substring(11, 19).replace('T', ', '); +function toIsoTimeStr(d) { // UTC! + return new Date(d.getTime()).toISOString().substring(11, 19).replace('T', ', '); } function setHide(id, hide) { diff --git a/src/web/html/visualization.html b/src/web/html/visualization.html index cb9b45ef..0194749a 100644 --- a/src/web/html/visualization.html +++ b/src/web/html/visualization.html @@ -166,7 +166,7 @@ ]); } - function tsInfo(ts) { + function tsInfo(ts, gen, rssi) { var ageInfo = "Last received data requested at: "; if(ts > 0) { var date = new Date(ts * 1000); @@ -175,6 +175,9 @@ else ageInfo += "nothing received"; + if((gen >= 2) && (rssi > -127)) + ageInfo += " (RSSI: " + rssi + "dBm)"; + return ml("div", {class: "mb-5"}, [ ml("div", {class: "row p-1 ts-h mx-2"}, ml("div", {class: "col"}, "") @@ -200,7 +203,7 @@ ml("div", {}, [ ivHead(obj), ml("div", {class: "row mb-2"}, chn), - tsInfo(obj.ts_last_success) + tsInfo(obj.ts_last_success, obj.generation, obj.rssi) ]) ); From 9ccdfca9df5992b88612b83f185a1a328ac10ac6 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 19 Aug 2023 01:43:19 +0200 Subject: [PATCH 002/267] test github action --- .github/workflows/compile_development.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/compile_development.yml b/.github/workflows/compile_development.yml index 847495eb..98b91c59 100644 --- a/.github/workflows/compile_development.yml +++ b/.github/workflows/compile_development.yml @@ -47,7 +47,8 @@ jobs: run: python convert.py - name: Run PlatformIO - run: pio run -d src --environment esp8266-release --environment esp8266-release-prometheus --environment esp8285-release --environment esp32-wroom32-release --environment esp32-wroom32-release-prometheus --environment esp32-wroom32-ethernet-release --environment opendtufusionv1-release + run: pio run -d src --environment esp8266-release --environment esp32-wroom32-release + #run: pio run -d src --environment esp8266-release --environment esp8266-release-prometheus --environment esp8285-release --environment esp32-wroom32-release --environment esp32-wroom32-release-prometheus --environment esp32-wroom32-ethernet-release --environment opendtufusionv1-release - name: Copy boot_app0.bin run: cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin src/.pio/build/opendtufusionv1-release/ota.bin @@ -77,3 +78,12 @@ jobs: src/User_Manual.md src/install.html + - name: Deploy + uses: nogsantos/scp-deploy@master + with: + src: src/firmware/ + host: ${{ secrets.SSH_HOST }} + remote: ${{ secrets.SSH_DIR }}/dev + port: ${{ secrets.SSH_PORT }} + user: ${{ secrets.SSH_USER }} + key: ${{ secrets.SSH_KEY }} From cca791a2a2959faf3bff59a8902d19583fd78e9d Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 19 Aug 2023 01:48:13 +0200 Subject: [PATCH 003/267] another github action test --- .github/workflows/compile_development.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/compile_development.yml b/.github/workflows/compile_development.yml index 98b91c59..c5da960d 100644 --- a/.github/workflows/compile_development.yml +++ b/.github/workflows/compile_development.yml @@ -50,8 +50,8 @@ jobs: run: pio run -d src --environment esp8266-release --environment esp32-wroom32-release #run: pio run -d src --environment esp8266-release --environment esp8266-release-prometheus --environment esp8285-release --environment esp32-wroom32-release --environment esp32-wroom32-release-prometheus --environment esp32-wroom32-ethernet-release --environment opendtufusionv1-release - - name: Copy boot_app0.bin - run: cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin src/.pio/build/opendtufusionv1-release/ota.bin + #- name: Copy boot_app0.bin + # run: cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin src/.pio/build/opendtufusionv1-release/ota.bin - name: Rename Binary files id: rename-binary-files From 9dc996e92a75afcde8fd25a39dfa8e14804ce9b2 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 19 Aug 2023 01:53:28 +0200 Subject: [PATCH 004/267] next github action test --- .github/workflows/compile_development.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/compile_development.yml b/.github/workflows/compile_development.yml index c5da960d..242662da 100644 --- a/.github/workflows/compile_development.yml +++ b/.github/workflows/compile_development.yml @@ -47,11 +47,10 @@ jobs: run: python convert.py - name: Run PlatformIO - run: pio run -d src --environment esp8266-release --environment esp32-wroom32-release - #run: pio run -d src --environment esp8266-release --environment esp8266-release-prometheus --environment esp8285-release --environment esp32-wroom32-release --environment esp32-wroom32-release-prometheus --environment esp32-wroom32-ethernet-release --environment opendtufusionv1-release + run: pio run -d src --environment esp8266-release --environment esp8266-release-prometheus --environment esp8285-release --environment esp32-wroom32-release --environment esp32-wroom32-release-prometheus --environment esp32-wroom32-ethernet-release --environment opendtufusionv1-release - #- name: Copy boot_app0.bin - # run: cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin src/.pio/build/opendtufusionv1-release/ota.bin + - name: Copy boot_app0.bin + run: cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin src/.pio/build/opendtufusionv1-release/ota.bin - name: Rename Binary files id: rename-binary-files From 3074b8ca4c8931b3bfbcb713c5e5703a139bea1d Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 19 Aug 2023 02:27:07 +0200 Subject: [PATCH 005/267] next github action test --- .github/workflows/compile_development.yml | 10 +++++----- .github/workflows/compile_release.yml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/compile_development.yml b/.github/workflows/compile_development.yml index 242662da..047bc33d 100644 --- a/.github/workflows/compile_development.yml +++ b/.github/workflows/compile_development.yml @@ -81,8 +81,8 @@ jobs: uses: nogsantos/scp-deploy@master with: src: src/firmware/ - host: ${{ secrets.SSH_HOST }} - remote: ${{ secrets.SSH_DIR }}/dev - port: ${{ secrets.SSH_PORT }} - user: ${{ secrets.SSH_USER }} - key: ${{ secrets.SSH_KEY }} + host: ${{ secrets.FW_SSH_HOST }} + remote: ${{ secrets.FW_SSH_DIR }}/dev + port: ${{ secrets.FW_SSH_PORT }} + user: ${{ secrets.FW_SSH_USER }} + key: ${{ secrets.FW_SSH_KEY }} diff --git a/.github/workflows/compile_release.yml b/.github/workflows/compile_release.yml index 89f6a4bd..a773e574 100644 --- a/.github/workflows/compile_release.yml +++ b/.github/workflows/compile_release.yml @@ -81,7 +81,7 @@ jobs: VERSION: ${{ steps.rename-binary-files.outputs.name }} - name: Create Artifact - run: zip --junk-paths ${{ steps.rename-binary-files.outputs.name }}.zip src/firmware/* User_Manual.md + run: zip --junk-paths ${{ steps.rename-binary-files.outputs.name }}.zip src/firmware/* rc/firmware/s3/* User_Manual.md - name: Upload Release id: upload-release From a91885b5053ce43340d2c27bf19bfe3234cad6f4 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 21 Aug 2023 00:47:27 +0200 Subject: [PATCH 006/267] added hardware info --- src/.vscode/settings.json | 1 + src/defines.h | 2 +- src/hm/hmDefines.h | 67 +++++++++++++++++++++++++++++---- src/hm/hmInverter.h | 50 +++++++++++++++++++----- src/web/RestApi.h | 30 +++++++++++++++ src/web/html/style.css | 14 +++++++ src/web/html/visualization.html | 43 ++++++++++++++++++++- 7 files changed, 189 insertions(+), 18 deletions(-) diff --git a/src/.vscode/settings.json b/src/.vscode/settings.json index e61851fb..fa166086 100644 --- a/src/.vscode/settings.json +++ b/src/.vscode/settings.json @@ -84,4 +84,5 @@ }, "cmake.configureOnOpen": false, "editor.formatOnSave": false, + "cmake.sourceDirectory": "C:/lpusch/github/ahoy/src/.pio/libdeps/esp32-wroom32-release-prometheus/Adafruit BusIO", } \ No newline at end of file diff --git a/src/defines.h b/src/defines.h index 163e22b5..021b4010 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 7 -#define VERSION_PATCH 37 +#define VERSION_PATCH 38 //------------------------------------- typedef struct { diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index 7c814857..a040d01b 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -10,7 +10,8 @@ #include // inverter generations -enum {IV_HM = 0, IV_MI, IV_HMS, IV_HMT}; +enum {IV_MI = 0, IV_HM, IV_HMS, IV_HMT, IV_UNKNOWN}; +const char* const generationNames[] = {"HM", "MI", "HMS", "HMT", "UNKNOWN"}; // units enum {UNIT_V = 0, UNIT_A, UNIT_W, UNIT_WH, UNIT_KWH, UNIT_HZ, UNIT_C, UNIT_PCT, UNIT_VAR, UNIT_NONE}; @@ -21,20 +22,22 @@ enum {FLD_UDC = 0, FLD_IDC, FLD_PDC, FLD_YD, FLD_YW, FLD_YT, FLD_UAC, FLD_UAC_1N, FLD_UAC_2N, FLD_UAC_3N, FLD_UAC_12, FLD_UAC_23, FLD_UAC_31, FLD_IAC, FLD_IAC_1, FLD_IAC_2, FLD_IAC_3, FLD_PAC, FLD_F, FLD_T, FLD_PF, FLD_EFF, FLD_IRR, FLD_Q, FLD_EVT, FLD_FW_VERSION, FLD_FW_BUILD_YEAR, - FLD_FW_BUILD_MONTH_DAY, FLD_FW_BUILD_HOUR_MINUTE, FLD_HW_ID, - FLD_ACT_ACTIVE_PWR_LIMIT, /*FLD_ACT_REACTIVE_PWR_LIMIT, FLD_ACT_PF,*/ FLD_LAST_ALARM_CODE, FLD_MP}; + FLD_FW_BUILD_MONTH_DAY, FLD_FW_BUILD_HOUR_MINUTE, FLD_BOOTLOADER_VER, + FLD_ACT_ACTIVE_PWR_LIMIT, FLD_PART_NUM, FLD_HW_VERSION, FLD_GRID_PROFILE_CODE, + FLD_GRID_PROFILE_VERSION, /*FLD_ACT_REACTIVE_PWR_LIMIT, FLD_ACT_PF,*/ FLD_LAST_ALARM_CODE, FLD_MP}; const char* const fields[] = {"U_DC", "I_DC", "P_DC", "YieldDay", "YieldWeek", "YieldTotal", "U_AC", "U_AC_1N", "U_AC_2N", "U_AC_3N", "UAC_12", "UAC_23", "UAC_31", "I_AC", "IAC_1", "I_AC_2", "I_AC_3", "P_AC", "F_AC", "Temp", "PF_AC", "Efficiency", "Irradiation","Q_AC", - "ALARM_MES_ID","FWVersion","FWBuildYear","FWBuildMonthDay","FWBuildHourMinute","HWPartId", - "active_PowerLimit", /*"reactivePowerLimit","Powerfactor",*/ "LastAlarmCode", "MaxPower"}; + "ALARM_MES_ID","FWVersion","FWBuildYear","FWBuildMonthDay","FWBuildHourMinute","BootloaderVersion", + "active_PowerLimit", "HWPartNumber", "HWVersion", "GridProfileCode", + "GridProfileVersion", /*"reactivePowerLimit","Powerfactor",*/ "LastAlarmCode", "MaxPower"}; const char* const notAvail = "n/a"; const uint8_t fieldUnits[] = {UNIT_V, UNIT_A, UNIT_W, UNIT_WH, UNIT_KWH, UNIT_KWH, UNIT_V, UNIT_V, UNIT_V, UNIT_V, UNIT_V, UNIT_V, UNIT_V, UNIT_A, UNIT_A, UNIT_A, UNIT_A, UNIT_W, UNIT_HZ, UNIT_C, UNIT_NONE, UNIT_PCT, UNIT_PCT, UNIT_VAR, - UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_PCT, UNIT_NONE, UNIT_W}; + UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_PCT, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_NONE, UNIT_W}; // mqtt discovery device classes enum {DEVICE_CLS_NONE = 0, DEVICE_CLS_CURRENT, DEVICE_CLS_ENERGY, DEVICE_CLS_PWR, DEVICE_CLS_VOLTAGE, DEVICE_CLS_FREQ, DEVICE_CLS_TEMP}; @@ -98,11 +101,20 @@ const byteAssign_t InfoAssignment[] = { { 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 } + { FLD_BOOTLOADER_VER, UNIT_NONE, CH0, 8, 2, 1 } }; #define HMINFO_LIST_LEN (sizeof(InfoAssignment) / sizeof(byteAssign_t)) #define HMINFO_PAYLOAD_LEN 14 +const byteAssign_t SimpleInfoAssignment[] = { + { FLD_PART_NUM, UNIT_NONE, CH0, 2, 4, 1 }, + { FLD_HW_VERSION, UNIT_NONE, CH0, 6, 2, 1 }, + { FLD_GRID_PROFILE_CODE, UNIT_NONE, CH0, 8, 2, 1 }, + { FLD_GRID_PROFILE_VERSION, UNIT_NONE, CH0, 10, 2, 1 } +}; +#define HMSIMPLE_INFO_LIST_LEN (sizeof(SimpleInfoAssignment) / sizeof(byteAssign_t)) +#define HMSIMPLE_INFO_PAYLOAD_LEN 14 + const byteAssign_t SystemConfigParaAssignment[] = { { FLD_ACT_ACTIVE_PWR_LIMIT, UNIT_PCT, CH0, 2, 2, 10 }/*, { FLD_ACT_REACTIVE_PWR_LIMIT, UNIT_PCT, CH0, 4, 2, 10 }, @@ -242,4 +254,45 @@ const byteAssign_t hm4chAssignment[] = { #define HM4CH_PAYLOAD_LEN 62 +typedef struct { + uint32_t hwPart; + uint16_t maxPower; +} devInfo_t; + +const devInfo_t devInfo[] = { + // MI 3rd gen + { 0x100230, 1500 }, + + // HM + { 0x101010, 300 }, + { 0x101020, 350 }, + { 0x101030, 400 }, + { 0x101040, 400 }, + { 0x101110, 600 }, + { 0x101120, 700 }, + { 0x101130, 800 }, + { 0x101140, 800 }, + { 0x101210, 1200 }, + { 0x101230, 1500 }, + + // HMS + { 0x102021, 350 }, + { 0x102041, 400 }, + { 0x101051, 450 }, + { 0x101071, 500 }, + { 0x102111, 600 }, + { 0x102141, 800 }, + { 0x101151, 900 }, + { 0x102171, 1000 }, + { 0x102241, 1600 }, + { 0x101251, 1800 }, + { 0x102251, 1800 }, + { 0x101271, 2000 }, + { 0x102271, 2000 }, + + // HMT + { 0x103311, 1800 }, + { 0x103331, 2250 } +}; + #endif /*__HM_DEFINES_H__*/ diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index cfcd134a..d150160c 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -142,6 +142,7 @@ class Inverter { uint8_t channels; // number of PV channels (1-4) record_t recordMeas; // structure for measured values record_t recordInfo; // structure for info values + record_t recordHwInfo; // structure for simple (hardware) info values record_t recordConfig; // structure for system config values record_t recordAlarm; // structure for alarm values //String lastAlarmMsg; @@ -189,7 +190,6 @@ class Inverter { void setQueuedCmdFinished() { if (!_commandQueue.empty()) { - // Will destroy CommandAbstract Class Object (?) _commandQueue.pop(); } } @@ -197,7 +197,6 @@ class Inverter { void clearCmdQueue() { DPRINTLN(DBG_INFO, F("clearCmdQueue")); while (!_commandQueue.empty()) { - // Will destroy CommandAbstract Class Object (?) _commandQueue.pop(); } } @@ -207,6 +206,8 @@ class Inverter { if (ivGen != IV_MI) { if (getFwVersion() == 0) enqueCommand(InverterDevInform_All); // firmware version + else if (getHwVersion() == 0) + enqueCommand(InverterDevInform_Simple); // hardware version enqueCommand(RealTimeRunData_Debug); // live data } else if (ivGen == IV_MI){ if (getFwVersion() == 0) @@ -229,6 +230,7 @@ class Inverter { DPRINTLN(DBG_VERBOSE, F("hmInverter.h:init")); initAssignment(&recordMeas, RealTimeRunData_Debug); initAssignment(&recordInfo, InverterDevInform_All); + initAssignment(&recordHwInfo, InverterDevInform_Simple); initAssignment(&recordConfig, SystemConfigPara); initAssignment(&recordAlarm, AlarmData); toRadioId(); @@ -340,6 +342,10 @@ class Inverter { // eg. fw version ... isConnected = true; } + else if (rec->assign == SimpleInfoAssignment) { + DPRINTLN(DBG_DEBUG, "add simple info"); + // eg. hw version ... + } else if (rec->assign == SystemConfigParaAssignment) { DPRINTLN(DBG_DEBUG, "add config"); if (getPosByChFld(0, FLD_ACT_ACTIVE_PWR_LIMIT, rec) == pos){ @@ -390,6 +396,10 @@ class Inverter { return 0; } + uint32_t getChannelFieldValueInt(uint8_t channel, uint8_t fieldId, record_t<> *rec) { + return (uint32_t) getChannelFieldValue(channel, fieldId, rec); + } + REC_TYP getValue(uint8_t pos, record_t<> *rec) { DPRINTLN(DBG_VERBOSE, F("hmInverter.h:getValue")); if(NULL == rec) @@ -452,8 +462,24 @@ class Inverter { uint16_t getFwVersion() { record_t<> *rec = getRecordStruct(InverterDevInform_All); - uint8_t pos = getPosByChFld(CH0, FLD_FW_VERSION, rec); - return getValue(pos, rec); + return getChannelFieldValue(CH0, FLD_FW_VERSION, rec); + } + + uint16_t getHwVersion() { + record_t<> *rec = getRecordStruct(InverterDevInform_Simple); + return getChannelFieldValue(CH0, FLD_HW_VERSION, rec); + } + + uint16_t getMaxPower() { + record_t<> *rec = getRecordStruct(InverterDevInform_Simple); + if(0 == getChannelFieldValue(CH0, FLD_HW_VERSION, rec)) + return 0; + + for(uint8_t i = 0; i < sizeof(devInfo) / sizeof(devInfo_t); i++) { + if(devInfo[i].hwPart == (getChannelFieldValueInt(CH0, FLD_PART_NUM, rec) >> 8)) + return devInfo[i].maxPower; + } + return 0; } uint32_t getLastTs(record_t<> *rec) { @@ -463,11 +489,12 @@ class Inverter { record_t<> *getRecordStruct(uint8_t cmd) { switch (cmd) { - case RealTimeRunData_Debug: return &recordMeas; // 11 = 0x0b - case InverterDevInform_All: return &recordInfo; // 1 = 0x01 - case SystemConfigPara: return &recordConfig; // 5 = 0x05 - case AlarmData: return &recordAlarm; // 17 = 0x11 - default: break; + case RealTimeRunData_Debug: return &recordMeas; // 11 = 0x0b + case InverterDevInform_Simple: return &recordHwInfo; // 0 = 0x00 + case InverterDevInform_All: return &recordInfo; // 1 = 0x01 + case SystemConfigPara: return &recordConfig; // 5 = 0x05 + case AlarmData: return &recordAlarm; // 17 = 0x11 + default: break; } return NULL; } @@ -535,6 +562,11 @@ class Inverter { rec->assign = (byteAssign_t *)InfoAssignment; rec->pyldLen = HMINFO_PAYLOAD_LEN; break; + case InverterDevInform_Simple: + rec->length = (uint8_t)(HMSIMPLE_INFO_LIST_LEN); + rec->assign = (byteAssign_t *)SimpleInfoAssignment; + rec->pyldLen = HMSIMPLE_INFO_PAYLOAD_LEN; + break; case SystemConfigPara: rec->length = (uint8_t)(HMSYSTEM_LIST_LEN); rec->assign = (byteAssign_t *)SystemConfigParaAssignment; diff --git a/src/web/RestApi.h b/src/web/RestApi.h index ddc16d52..7d08b36b 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -107,6 +107,8 @@ class RestApi { getInverter(root, request->url().substring(17).toInt()); else if(path.substring(0, 15) == "inverter/alarm/") getIvAlarms(root, request->url().substring(20).toInt()); + else if(path.substring(0, 15) == "inverter/version/") + getIvVersion(root, request->url().substring(20).toInt()); else getNotFound(root, F("http://") + request->host() + F("/api/")); } @@ -421,6 +423,34 @@ class RestApi { } } + void getIvVersion(JsonObject obj, uint8_t id) { + Inverter<> *iv = mSys->getInverterByPos(id); + if(NULL == iv) { + obj[F("error")] = F("inverter not found!"); + return; + } + + record_t<> *rec = iv->getRecordStruct(InverterDevInform_Simple); + + obj[F("name")] = String(iv->config->name); + obj[F("generation")] = iv->ivGen; + obj[F("max_pwr")] = iv->getMaxPower(); + obj[F("part_num")] = iv->getChannelFieldValueInt(CH0, FLD_PART_NUM, rec); + obj[F("hw_ver")] = iv->getChannelFieldValueInt(CH0, FLD_HW_VERSION, rec); + obj[F("prod_cw")] = ((iv->radioId.b[3] & 0x0f) * 10 + ((iv->radioId.b[4] & 0x0f))); + obj[F("prod_year")] = ((iv->radioId.b[3] >> 4) & 0x0f) + 2014; + + + rec = iv->getRecordStruct(InverterDevInform_All); + obj[F("fw_ver")] = iv->getChannelFieldValueInt(CH0, FLD_FW_VERSION, rec); + obj[F("fw_date")] = String(iv->getChannelFieldValueInt(CH0, FLD_FW_BUILD_YEAR, rec)) + + "-" + String(iv->getChannelFieldValueInt(CH0, FLD_FW_BUILD_MONTH_DAY, rec) / 100) + + "-" + String(iv->getChannelFieldValueInt(CH0, FLD_FW_BUILD_MONTH_DAY, rec) % 100); + obj[F("fw_time")] = String(iv->getChannelFieldValueInt(CH0, FLD_FW_BUILD_HOUR_MINUTE, rec) / 100) + + ":" + String(iv->getChannelFieldValueInt(CH0, FLD_FW_BUILD_HOUR_MINUTE, rec) % 100); + obj[F("boot_ver")] = iv->getChannelFieldValueInt(CH0, FLD_BOOTLOADER_VER, rec); + } + void getMqtt(JsonObject obj) { obj[F("broker")] = String(mConfig->mqtt.broker); obj[F("clientId")] = String(mConfig->mqtt.clientId); diff --git a/src/web/html/style.css b/src/web/html/style.css index bf84aaa3..f61b1a18 100644 --- a/src/web/html/style.css +++ b/src/web/html/style.css @@ -318,6 +318,20 @@ p { .col-md-12 { width: 100%; } } +table { + border-collapse: collapse; + width: 100%; +} + +th { + text-align: inherit; +} + +.table td, .table th { + padding: .75rem; + border-bottom: 1px solid var(--nav-bg); +} + #wrapper { min-height: 100%; } diff --git a/src/web/html/visualization.html b/src/web/html/visualization.html index 0194749a..a8048eb3 100644 --- a/src/web/html/visualization.html +++ b/src/web/html/visualization.html @@ -102,7 +102,9 @@ ml("div", {class: "col"}, [ ml("div", {class: "p-2 " + clh}, ml("div", {class: "row"}, [ - ml("div", {class: "col mx-2 mx-md-1"}, obj.name), + ml("div", {class: "col mx-2 mx-md-1"}, ml("span", { class: "pointer", onclick: function() { + getAjax("/api/inverter/version/" + obj.id, parseIvVersion); + }}, obj.name)), ml("div", {class: "col a-c"}, "Power limit " + ((obj.power_limit_read == 65535) ? "n/a" : (obj.power_limit_read + " %"))), ml("div", {class: "col a-c"}, ml("span", { class: "pointer", onclick: function() { getAjax("/api/inverter/alarm/" + obj.id, parseIvAlarm); @@ -250,6 +252,45 @@ modal("Alarms of inverter #" + obj.iv_id, ml("div", {}, html)); } + function parseIvVersion(obj) { + var model; + switch(obj.generation) { + case 0: model = "MI-"; break; + case 1: model = "HM-"; break; + case 2: model = "HMS-"; break; + case 3: model = "HMT-"; break; + default: model = "???-"; break; + } + model += String(obj.max_pwr); + + + var html = ml("table", {class: "table"}, [ + ml("tbody", {}, [ + ml("tr", {}, [ + ml("th", {}, "Model"), + ml("td", {}, model) + ]), + ml("tr", {}, [ + ml("th", {}, "Firmware Version / Build"), + ml("td", {}, String(obj.fw_ver) + " (build: " + String(obj.fw_date) + " " + String(obj.fw_time) + ")") + ]), + ml("tr", {}, [ + ml("th", {}, "Hardware Version / Build"), + ml("td", {}, String(obj.hw_ver) + " (build: " + String(obj.prod_cw) + "/" + String(obj.prod_year) + ")") + ]), + ml("tr", {}, [ + ml("th", {}, "Hardware Number"), + ml("td", {}, String(obj.part_num)) + ]), + ml("tr", {}, [ + ml("th", {}, "Bootloader Version"), + ml("td", {}, String(obj.boot_ver)) + ]) + ]) + ]); + modal("Info for inverter " + obj.name, ml("div", {}, html)); + } + function parse(obj) { if(null != obj) { parseGeneric(obj["generic"]); From b01fbe205eb7f10d5a3dd4edd4e43ac33ac27742 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 21 Aug 2023 01:46:13 +0200 Subject: [PATCH 007/267] 0.7.38 * reset alarms at midnight (if inverter is not available) #1105, #1096 * add option to reset 'max' values on midnight #1102 * added default pins for CMT2300A (matching OpenDTU) --- src/CHANGES.md | 5 +++++ src/app.cpp | 40 +++++++++++++++++++++++++++++++--------- src/config/config.h | 4 ++++ src/config/settings.h | 10 +++++++--- src/defines.h | 2 +- src/hm/hmInverter.h | 6 ++++++ src/web/RestApi.h | 3 ++- src/web/html/setup.html | 8 ++++++-- src/web/web.h | 1 + 9 files changed, 63 insertions(+), 16 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 8b2ca4d6..c6daf2ac 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,10 @@ # Development Changes +## 0.7.38 - 2023-08-21 +* reset alarms at midnight (if inverter is not available) #1105, #1096 +* add option to reset 'max' values on midnight #1102 +* added default pins for CMT2300A (matching OpenDTU) + ## 0.7.37 - 2023-08-18 * fix alarm time on WebGui #1099 * added RSSI info for HMS and HMT inverters (MqTT + REST API) diff --git a/src/app.cpp b/src/app.cpp index 179e3ba3..4fd1a6a6 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -276,11 +276,11 @@ void app::updateNtp(void) { if (mMqttReconnect) { // @TODO: mMqttReconnect is variable which scope has changed if (mConfig->inst.rstValsNotAvail) everyMin(std::bind(&app::tickMinute, this), "tMin"); - if (mConfig->inst.rstYieldMidNight) { - uint32_t localTime = gTimezone.toLocal(mTimestamp); - uint32_t midTrig = gTimezone.toUTC(localTime - (localTime % 86400) + 86400); // next midnight local time - onceAt(std::bind(&app::tickMidnight, this), midTrig, "midNi"); - } + + uint32_t localTime = gTimezone.toLocal(mTimestamp); + uint32_t midTrig = gTimezone.toUTC(localTime - (localTime % 86400) + 86400); // next midnight local time + onceAt(std::bind(&app::tickMidnight, this), midTrig, "midNi"); + if (mConfig->sys.schedReboot) { uint32_t localTime = gTimezone.toLocal(mTimestamp); uint32_t rebootTrig = gTimezone.toUTC(localTime - (localTime % 86400) + 86410); // reboot 10 secs after midnght @@ -392,15 +392,37 @@ void app::tickMinute(void) { //----------------------------------------------------------------------------- void app::tickMidnight(void) { - // only triggered if 'reset values at midnight is enabled' uint32_t localTime = gTimezone.toLocal(mTimestamp); uint32_t nxtTrig = gTimezone.toUTC(localTime - (localTime % 86400) + 86400); // next midnight local time onceAt(std::bind(&app::tickMidnight, this), nxtTrig, "mid2"); - zeroIvValues(!CHECK_AVAIL, !SKIP_YIELD_DAY); + Inverter<> *iv; + for (uint8_t id = 0; id < mSys.getNumInverters(); id++) { + iv = mSys.getInverterByPos(id); + if (NULL == iv) + continue; // skip to next inverter + + // reset alarms + if(InverterStatus::OFF == iv->status) + iv->resetAlarms(); - if (mMqttEnabled) - mMqtt.tickerMidnight(); + // clear max values + if(mConfig->inst.rstMaxValsMidNight) { + uint8_t pos; + record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); + for(uint8_t i = 0; i <= iv->channels; i++) { + pos = iv->getPosByChFld(i, FLD_MP, rec); + iv->setValue(pos, rec, 0.0f); + } + } + } + + if (mConfig->inst.rstYieldMidNight) { + zeroIvValues(!CHECK_AVAIL, !SKIP_YIELD_DAY); + + if (mMqttEnabled) + mMqtt.tickerMidnight(); + } } //----------------------------------------------------------------------------- diff --git a/src/config/config.h b/src/config/config.h index c4947ec8..5169edd3 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -66,6 +66,10 @@ #define DEF_MISO_PIN 19 #define DEF_MOSI_PIN 23 #define DEF_SCLK_PIN 18 + + #define DEF_CMT_CSB 27 + #define DEF_CMT_FCSB 26 + #define DEF_CMT_IRQ 34 #else #define DEF_CS_PIN 15 #define DEF_CE_PIN 0 diff --git a/src/config/settings.h b/src/config/settings.h index a7cb6a4c..4581bb6a 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -151,6 +151,7 @@ typedef struct { bool rstYieldMidNight; bool rstValsNotAvail; bool rstValsCommStop; + bool rstMaxValsMidNight; bool startWithoutTime; float yieldEffiency; } cfgInst_t; @@ -394,9 +395,9 @@ class settings { mCfg.nrf.amplifierPower = DEF_AMPLIFIERPOWER & 0x03; mCfg.nrf.enabled = true; - mCfg.cmt.pinCsb = DEF_PIN_OFF; - mCfg.cmt.pinFcsb = DEF_PIN_OFF; - mCfg.cmt.pinIrq = DEF_PIN_OFF; + mCfg.cmt.pinCsb = DEF_CMT_CSB; + mCfg.cmt.pinFcsb = DEF_CMT_FCSB; + mCfg.cmt.pinIrq = DEF_CMT_IRQ; mCfg.cmt.enabled = false; snprintf(mCfg.ntp.addr, NTP_ADDR_LEN, "%s", DEF_NTP_SERVER_NAME); @@ -423,6 +424,7 @@ class settings { mCfg.inst.rstValsNotAvail = false; mCfg.inst.rstValsCommStop = false; mCfg.inst.startWithoutTime = false; + mCfg.inst.rstMaxValsMidNight = false; mCfg.inst.yieldEffiency = 0.955f; mCfg.led.led0 = DEF_PIN_OFF; @@ -651,6 +653,7 @@ class settings { obj[F("rstNotAvail")] = (bool)mCfg.inst.rstValsNotAvail; obj[F("rstComStop")] = (bool)mCfg.inst.rstValsCommStop; obj[F("strtWthtTime")] = (bool)mCfg.inst.startWithoutTime; + obj[F("rstMaxMidNight")] = (bool)mCfg.inst.rstMaxValsMidNight; obj[F("yldEff")] = mCfg.inst.yieldEffiency; } else { @@ -659,6 +662,7 @@ class settings { getVal(obj, F("rstNotAvail"), &mCfg.inst.rstValsNotAvail); getVal(obj, F("rstComStop"), &mCfg.inst.rstValsCommStop); getVal(obj, F("strtWthtTime"), &mCfg.inst.startWithoutTime); + getVal(obj, F("rstMaxMidNight"), &mCfg.inst.rstMaxValsMidNight); getVal(obj, F("yldEff"), &mCfg.inst.yieldEffiency); if(mCfg.inst.yieldEffiency < 0.5) diff --git a/src/defines.h b/src/defines.h index 163e22b5..021b4010 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 7 -#define VERSION_PATCH 37 +#define VERSION_PATCH 38 //------------------------------------- typedef struct { diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index cfcd134a..2ccd7610 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -556,6 +556,12 @@ class Inverter { } } + void resetAlarms() { + lastAlarm.fill({0, 0, 0}); + alarmNxtWrPos = 0; + alarmCnt = 0; + } + uint16_t parseAlarmLog(uint8_t id, uint8_t pyld[], uint8_t len) { uint8_t startOff = 2 + id * ALARM_LOG_ENTRY_SIZE; if((startOff + ALARM_LOG_ENTRY_SIZE) > len) diff --git a/src/web/RestApi.h b/src/web/RestApi.h index ddc16d52..e63ca6f4 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -342,9 +342,10 @@ class RestApi { obj[F("retries")] = String(mConfig->nrf.maxRetransPerPyld); obj[F("max_num_inverters")] = MAX_NUM_INVERTERS; obj[F("rstMid")] = (bool)mConfig->inst.rstYieldMidNight; - obj[F("rstNAvail")] = (bool)mConfig->inst.rstValsNotAvail; + obj[F("rstNotAvail")] = (bool)mConfig->inst.rstValsNotAvail; obj[F("rstComStop")] = (bool)mConfig->inst.rstValsCommStop; obj[F("strtWthtTm")] = (bool)mConfig->inst.startWithoutTime; + obj[F("rstMaxMid")] = (bool)mConfig->inst.rstMaxValsMidNight; obj[F("yldEff")] = mConfig->inst.yieldEffiency; } diff --git a/src/web/html/setup.html b/src/web/html/setup.html index fc855055..536cf2ca 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -172,6 +172,10 @@
Reset values when inverter status is 'not available'
+
+
Reset 'max' values at midnight
+
+
Start without time sync (useful in AP-Only-Mode)
@@ -653,8 +657,8 @@ function ivGlob(obj) { for(var i of [["invInterval", "interval"], ["invRetry", "retries"], ["yldEff", "yldEff"]]) document.getElementsByName(i[0])[0].value = obj[i[1]]; - for(var i of [["Mid", "rstMid"], ["ComStop", "rstComStop"], ["NotAvail", "rstNAvail"]]) - document.getElementsByName("invRst"+i[0])[0].checked = obj[i[1]]; + for(var i of ["Mid", "ComStop", "NotAvail", "MaxMid"]) + document.getElementsByName("invRst"+i)[0].checked = obj["rst" + i]; document.getElementsByName("strtWthtTm")[0].checked = obj["strtWthtTm"]; } diff --git a/src/web/web.h b/src/web/web.h index 4d8ef1e8..ae099656 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -537,6 +537,7 @@ class Web { mConfig->inst.rstValsCommStop = (request->arg("invRstComStop") == "on"); mConfig->inst.rstValsNotAvail = (request->arg("invRstNotAvail") == "on"); mConfig->inst.startWithoutTime = (request->arg("strtWthtTm") == "on"); + mConfig->inst.rstMaxValsMidNight = (request->arg("invRstMaxMid") == "on"); mConfig->inst.yieldEffiency = (request->arg("yldEff")).toFloat(); From fe2a80b71dc27c0c56c8025d6cde17c2ab23467f Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 21 Aug 2023 01:59:58 +0200 Subject: [PATCH 008/267] fix hardware production date --- src/web/RestApi.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/web/RestApi.h b/src/web/RestApi.h index eb87732f..ce06ae6b 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -107,7 +107,7 @@ class RestApi { getInverter(root, request->url().substring(17).toInt()); else if(path.substring(0, 15) == "inverter/alarm/") getIvAlarms(root, request->url().substring(20).toInt()); - else if(path.substring(0, 15) == "inverter/version/") + else if(path.substring(0, 17) == "inverter/version/") getIvVersion(root, request->url().substring(20).toInt()); else getNotFound(root, F("http://") + request->host() + F("/api/")); @@ -438,8 +438,8 @@ class RestApi { obj[F("max_pwr")] = iv->getMaxPower(); obj[F("part_num")] = iv->getChannelFieldValueInt(CH0, FLD_PART_NUM, rec); obj[F("hw_ver")] = iv->getChannelFieldValueInt(CH0, FLD_HW_VERSION, rec); - obj[F("prod_cw")] = ((iv->radioId.b[3] & 0x0f) * 10 + ((iv->radioId.b[4] & 0x0f))); - obj[F("prod_year")] = ((iv->radioId.b[3] >> 4) & 0x0f) + 2014; + obj[F("prod_cw")] = ((iv->config->serial.b[3] & 0x0f) * 10 + ((iv->config->serial.b[2] & 0x0f))); + obj[F("prod_year")] = ((iv->config->serial.b[3] >> 4) & 0x0f) + 2014; rec = iv->getRecordStruct(InverterDevInform_All); From 2130596ae63fa6efaf66367fe12a88e7e8aa52c4 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 21 Aug 2023 02:00:32 +0200 Subject: [PATCH 009/267] 0.7.38 fix pinout --- src/config/settings.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/config/settings.h b/src/config/settings.h index 4581bb6a..fe1be71a 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -395,9 +395,15 @@ class settings { mCfg.nrf.amplifierPower = DEF_AMPLIFIERPOWER & 0x03; mCfg.nrf.enabled = true; + #if defined(ESP32) mCfg.cmt.pinCsb = DEF_CMT_CSB; mCfg.cmt.pinFcsb = DEF_CMT_FCSB; mCfg.cmt.pinIrq = DEF_CMT_IRQ; + #else + mCfg.cmt.pinCsb = DEF_PIN_OFF; + mCfg.cmt.pinFcsb = DEF_PIN_OFF; + mCfg.cmt.pinIrq = DEF_PIN_OFF; + #endif mCfg.cmt.enabled = false; snprintf(mCfg.ntp.addr, NTP_ADDR_LEN, "%s", DEF_NTP_SERVER_NAME); From 3312fe710806e278bad49d3d114783ea6702fefa Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 21 Aug 2023 13:52:06 +0200 Subject: [PATCH 010/267] 0.7.39 * fix background color of invalid inputs * add hardware info (click in `live` on inverter name) --- src/CHANGES.md | 4 ++++ src/defines.h | 2 +- src/web/RestApi.h | 27 +++++++++++++++------------ src/web/html/colorBright.css | 2 ++ src/web/html/colorDark.css | 2 ++ src/web/html/style.css | 2 +- src/web/html/visualization.html | 8 ++++---- 7 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index c6daf2ac..83e4124d 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,9 @@ # Development Changes +## 0.7.39 - 2023-08-21 +* fix background color of invalid inputs +* add hardware info (click in `live` on inverter name) + ## 0.7.38 - 2023-08-21 * reset alarms at midnight (if inverter is not available) #1105, #1096 * add option to reset 'max' values on midnight #1102 diff --git a/src/defines.h b/src/defines.h index 021b4010..ffdcab75 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 7 -#define VERSION_PATCH 38 +#define VERSION_PATCH 39 //------------------------------------- typedef struct { diff --git a/src/web/RestApi.h b/src/web/RestApi.h index ce06ae6b..a0a457d1 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -98,17 +98,13 @@ class RestApi { else if(path == "setup/networks") getNetworks(root); #endif /* !defined(ETHERNET) */ else if(path == "live") getLive(request,root); - /*else if(path == "record/info") getRecord(root, InverterDevInform_All); - else if(path == "record/alarm") getRecord(root, AlarmData); - else if(path == "record/config") getRecord(root, SystemConfigPara); - else if(path == "record/live") getRecord(root, RealTimeRunData_Debug);*/ else { if(path.substring(0, 12) == "inverter/id/") getInverter(root, request->url().substring(17).toInt()); else if(path.substring(0, 15) == "inverter/alarm/") getIvAlarms(root, request->url().substring(20).toInt()); else if(path.substring(0, 17) == "inverter/version/") - getIvVersion(root, request->url().substring(20).toInt()); + getIvVersion(root, request->url().substring(22).toInt()); else getNotFound(root, F("http://") + request->host() + F("/api/")); } @@ -434,21 +430,28 @@ class RestApi { record_t<> *rec = iv->getRecordStruct(InverterDevInform_Simple); obj[F("name")] = String(iv->config->name); + obj[F("serial")] = String(iv->config->serial.u64, HEX); obj[F("generation")] = iv->ivGen; obj[F("max_pwr")] = iv->getMaxPower(); obj[F("part_num")] = iv->getChannelFieldValueInt(CH0, FLD_PART_NUM, rec); obj[F("hw_ver")] = iv->getChannelFieldValueInt(CH0, FLD_HW_VERSION, rec); - obj[F("prod_cw")] = ((iv->config->serial.b[3] & 0x0f) * 10 + ((iv->config->serial.b[2] & 0x0f))); + obj[F("prod_cw")] = ((iv->config->serial.b[3] & 0x0f) * 10 + (((iv->config->serial.b[2] >> 4) & 0x0f))); obj[F("prod_year")] = ((iv->config->serial.b[3] >> 4) & 0x0f) + 2014; rec = iv->getRecordStruct(InverterDevInform_All); - obj[F("fw_ver")] = iv->getChannelFieldValueInt(CH0, FLD_FW_VERSION, rec); - obj[F("fw_date")] = String(iv->getChannelFieldValueInt(CH0, FLD_FW_BUILD_YEAR, rec)) - + "-" + String(iv->getChannelFieldValueInt(CH0, FLD_FW_BUILD_MONTH_DAY, rec) / 100) - + "-" + String(iv->getChannelFieldValueInt(CH0, FLD_FW_BUILD_MONTH_DAY, rec) % 100); - obj[F("fw_time")] = String(iv->getChannelFieldValueInt(CH0, FLD_FW_BUILD_HOUR_MINUTE, rec) / 100) - + ":" + String(iv->getChannelFieldValueInt(CH0, FLD_FW_BUILD_HOUR_MINUTE, rec) % 100); + char buf[10]; + uint16_t val; + + val = iv->getChannelFieldValueInt(CH0, FLD_FW_BUILD_MONTH_DAY, rec); + snprintf(buf, 10, "-%02d-%02d", (val / 100), (val % 100)); + obj[F("fw_date")] = String(iv->getChannelFieldValueInt(CH0, FLD_FW_BUILD_YEAR, rec)) + String(buf); + val = iv->getChannelFieldValueInt(CH0, FLD_FW_BUILD_HOUR_MINUTE, rec); + snprintf(buf, 10, "%02d:%02d", (val / 100), (val % 100)); + obj[F("fw_time")] = String(buf); + val = iv->getChannelFieldValueInt(CH0, FLD_FW_VERSION, rec); + snprintf(buf, 10, "%d.%02d.%02d", (val / 10000), ((val % 10000) / 100), (val % 100)); + obj[F("fw_ver")] = String(buf); obj[F("boot_ver")] = iv->getChannelFieldValueInt(CH0, FLD_BOOTLOADER_VER, rec); } diff --git a/src/web/html/colorBright.css b/src/web/html/colorBright.css index 81d57326..255b5130 100644 --- a/src/web/html/colorBright.css +++ b/src/web/html/colorBright.css @@ -17,6 +17,8 @@ --footer-bg: #282828; --modal-bg: #fff; + --invalid-bg: #f99; + --total-head-title: #8e5903; --total-bg: #b06e04; --iv-head-title: #1c6800; diff --git a/src/web/html/colorDark.css b/src/web/html/colorDark.css index 549158b9..d143f8be 100644 --- a/src/web/html/colorDark.css +++ b/src/web/html/colorDark.css @@ -17,6 +17,8 @@ --footer-bg: #282828; --modal-bg: #666; + --invalid-bg: #400; + --total-head-title: #555511; --total-bg: #666622; --iv-head-title: #115511; diff --git a/src/web/html/style.css b/src/web/html/style.css index f61b1a18..4d4dc6f8 100644 --- a/src/web/html/style.css +++ b/src/web/html/style.css @@ -501,7 +501,7 @@ input[type=text], input[type=password], select, input[type=number] { input:invalid { border: 2px solid #f00 !important; - background-color: #400 !important; + background-color: var(--invalid-bg) !important; } input.sh { diff --git a/src/web/html/visualization.html b/src/web/html/visualization.html index a8048eb3..c7de12ff 100644 --- a/src/web/html/visualization.html +++ b/src/web/html/visualization.html @@ -261,7 +261,7 @@ case 3: model = "HMT-"; break; default: model = "???-"; break; } - model += String(obj.max_pwr); + model += String(obj.max_pwr) + " (Serial: " + obj.serial + ")"; var html = ml("table", {class: "table"}, [ @@ -276,15 +276,15 @@ ]), ml("tr", {}, [ ml("th", {}, "Hardware Version / Build"), - ml("td", {}, String(obj.hw_ver) + " (build: " + String(obj.prod_cw) + "/" + String(obj.prod_year) + ")") + ml("td", {}, (obj.hw_ver.toString(16) / 100).toFixed(2) + " (build: " + String(obj.prod_cw) + "/" + String(obj.prod_year) + ")") ]), ml("tr", {}, [ ml("th", {}, "Hardware Number"), - ml("td", {}, String(obj.part_num)) + ml("td", {}, obj.part_num.toString(16)) ]), ml("tr", {}, [ ml("th", {}, "Bootloader Version"), - ml("td", {}, String(obj.boot_ver)) + ml("td", {}, (obj.boot_ver / 100).toFixed(2)) ]) ]) ]); From 6d12fcc38438f2758aad443dd4f0ac1b4b696107 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 21 Aug 2023 20:14:07 +0200 Subject: [PATCH 011/267] github action update --- .github/workflows/compile_development.yml | 5 +++-- .github/workflows/compile_release.yml | 10 ++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/.github/workflows/compile_development.yml b/.github/workflows/compile_development.yml index 047bc33d..b064e3ca 100644 --- a/.github/workflows/compile_development.yml +++ b/.github/workflows/compile_development.yml @@ -78,11 +78,12 @@ jobs: src/install.html - name: Deploy + working-directory: src/firmware uses: nogsantos/scp-deploy@master with: - src: src/firmware/ + src: src/firmware/* host: ${{ secrets.FW_SSH_HOST }} - remote: ${{ secrets.FW_SSH_DIR }}/dev + remote: ${{ secrets.FW_SSH_DIR }}/dev/${{ steps.rename-binary-files.outputs.name }}/ port: ${{ secrets.FW_SSH_PORT }} user: ${{ secrets.FW_SSH_USER }} key: ${{ secrets.FW_SSH_KEY }} diff --git a/.github/workflows/compile_release.yml b/.github/workflows/compile_release.yml index a773e574..ec47e2b7 100644 --- a/.github/workflows/compile_release.yml +++ b/.github/workflows/compile_release.yml @@ -93,3 +93,13 @@ jobs: asset_path: ./${{ steps.rename-binary-files.outputs.name }}.zip asset_name: ${{ steps.rename-binary-files.outputs.name }}.zip asset_content_type: application/zip + + - name: Deploy + uses: nogsantos/scp-deploy@master + with: + src: src/firmware/* + host: ${{ secrets.FW_SSH_HOST }} + remote: ${{ secrets.FW_SSH_DIR }}/release/${{ steps.rename-binary-files.outputs.name }}/ + port: ${{ secrets.FW_SSH_PORT }} + user: ${{ secrets.FW_SSH_USER }} + key: ${{ secrets.FW_SSH_KEY }} From 49505ed88cffbfbd6fcf80185d4fb230592c98a4 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 21 Aug 2023 20:16:33 +0200 Subject: [PATCH 012/267] github action update --- .github/workflows/compile_development.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/compile_development.yml b/.github/workflows/compile_development.yml index b064e3ca..27e5b4b3 100644 --- a/.github/workflows/compile_development.yml +++ b/.github/workflows/compile_development.yml @@ -78,7 +78,6 @@ jobs: src/install.html - name: Deploy - working-directory: src/firmware uses: nogsantos/scp-deploy@master with: src: src/firmware/* From 8f0bbfc93cab28a491781438e0ec03fcd2500155 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 21 Aug 2023 22:45:02 +0200 Subject: [PATCH 013/267] github action update --- .github/workflows/compile_development.yml | 7 +++++-- .github/workflows/compile_release.yml | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.github/workflows/compile_development.yml b/.github/workflows/compile_development.yml index 27e5b4b3..e010c4a7 100644 --- a/.github/workflows/compile_development.yml +++ b/.github/workflows/compile_development.yml @@ -77,12 +77,15 @@ jobs: src/User_Manual.md src/install.html + - name: Rename firmware directory + run: mv src/firmware src/${{ steps.rename-binary-files.outputs.name }} + - name: Deploy uses: nogsantos/scp-deploy@master with: - src: src/firmware/* + src: src/${{ steps.rename-binary-files.outputs.name }}/ host: ${{ secrets.FW_SSH_HOST }} - remote: ${{ secrets.FW_SSH_DIR }}/dev/${{ steps.rename-binary-files.outputs.name }}/ + remote: ${{ secrets.FW_SSH_DIR }}/dev port: ${{ secrets.FW_SSH_PORT }} user: ${{ secrets.FW_SSH_USER }} key: ${{ secrets.FW_SSH_KEY }} diff --git a/.github/workflows/compile_release.yml b/.github/workflows/compile_release.yml index ec47e2b7..96c7f28c 100644 --- a/.github/workflows/compile_release.yml +++ b/.github/workflows/compile_release.yml @@ -94,12 +94,15 @@ jobs: asset_name: ${{ steps.rename-binary-files.outputs.name }}.zip asset_content_type: application/zip + - name: Rename firmware directory + run: mv src/firmware src/${{ steps.rename-binary-files.outputs.name }} + - name: Deploy uses: nogsantos/scp-deploy@master with: - src: src/firmware/* + src: src/${{ steps.rename-binary-files.outputs.name }}/ host: ${{ secrets.FW_SSH_HOST }} - remote: ${{ secrets.FW_SSH_DIR }}/release/${{ steps.rename-binary-files.outputs.name }}/ + remote: ${{ secrets.FW_SSH_DIR }}/release port: ${{ secrets.FW_SSH_PORT }} user: ${{ secrets.FW_SSH_USER }} key: ${{ secrets.FW_SSH_KEY }} From fd2fd206f007eebb716da338b00c35f23226c47e Mon Sep 17 00:00:00 2001 From: lumapu Date: Tue, 22 Aug 2023 00:35:00 +0200 Subject: [PATCH 014/267] 0.7.40 * added default pins for opendtu-fusion-v1 board * fixed hw version display in `live` * removed development builds, renamed environments in `platform.ini` --- .github/workflows/compile_development.yml | 4 +- .github/workflows/compile_release.yml | 4 +- scripts/getVersion.py | 18 ++-- src/CHANGES.md | 5 + src/config/config.h | 77 +++++++++++--- src/config/settings.h | 31 +++--- src/defines.h | 2 +- src/hm/hmDefines.h | 8 +- src/hm/hmRadio.h | 2 +- src/platformio.ini | 124 ++++++---------------- src/web/html/visualization.html | 4 +- src/web/web.h | 12 +-- 12 files changed, 141 insertions(+), 150 deletions(-) diff --git a/.github/workflows/compile_development.yml b/.github/workflows/compile_development.yml index e010c4a7..49d9d713 100644 --- a/.github/workflows/compile_development.yml +++ b/.github/workflows/compile_development.yml @@ -47,10 +47,10 @@ jobs: run: python convert.py - name: Run PlatformIO - run: pio run -d src --environment esp8266-release --environment esp8266-release-prometheus --environment esp8285-release --environment esp32-wroom32-release --environment esp32-wroom32-release-prometheus --environment esp32-wroom32-ethernet-release --environment opendtufusionv1-release + run: pio run -d src --environment esp8266 --environment esp8266-prometheus --environment esp8285 --environment esp32-wroom32 --environment esp32-wroom32-prometheus --environment esp32-wroom32-ethernet --environment opendtufusionv1 - name: Copy boot_app0.bin - run: cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin src/.pio/build/opendtufusionv1-release/ota.bin + run: cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin src/.pio/build/opendtufusionv1/ota.bin - name: Rename Binary files id: rename-binary-files diff --git a/.github/workflows/compile_release.yml b/.github/workflows/compile_release.yml index 96c7f28c..5d7078e2 100644 --- a/.github/workflows/compile_release.yml +++ b/.github/workflows/compile_release.yml @@ -51,10 +51,10 @@ jobs: run: python convert.py - name: Run PlatformIO - run: pio run -d src --environment esp8266-release --environment esp8266-release-prometheus --environment esp8285-release --environment esp32-wroom32-release --environment esp32-wroom32-release-prometheus --environment esp32-wroom32-ethernet-release --environment opendtufusionv1-release + run: pio run -d src --environment esp8266 --environment esp8266-prometheus --environment esp8285 --environment esp32-wroom32 --environment esp32-wroom32-prometheus --environment esp32-wroom32-ethernet --environment opendtufusionv1 - name: Copy boot_app0.bin - run: cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin src/.pio/build/opendtufusionv1-release/ota.bin + run: cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin src/.pio/build/opendtufusionv1/ota.bin - name: Rename Binary files id: rename-binary-files diff --git a/scripts/getVersion.py b/scripts/getVersion.py index 11a76f62..9e6c90b7 100644 --- a/scripts/getVersion.py +++ b/scripts/getVersion.py @@ -54,50 +54,50 @@ def readVersion(path, infile): sha = os.getenv("SHA",default="sha") versionout = version[:-1] + "_" + sha + "_esp8266.bin" - src = path + ".pio/build/esp8266-release/firmware.bin" + src = path + ".pio/build/esp8266/firmware.bin" dst = path + "firmware/" + versionout os.rename(src, dst) versionout = version[:-1] + "_" + sha + "_esp8266_prometheus.bin" - src = path + ".pio/build/esp8266-release-prometheus/firmware.bin" + src = path + ".pio/build/esp8266-prometheus/firmware.bin" dst = path + "firmware/" + versionout os.rename(src, dst) versionout = version[:-1] + "_" + sha + "_esp8285.bin" - src = path + ".pio/build/esp8285-release/firmware.bin" + src = path + ".pio/build/esp8285/firmware.bin" dst = path + "firmware/" + versionout os.rename(src, dst) gzip_bin(dst, dst + ".gz") versionout = version[:-1] + "_" + sha + "_esp32.bin" - src = path + ".pio/build/esp32-wroom32-release/firmware.bin" + src = path + ".pio/build/esp32-wroom32/firmware.bin" dst = path + "firmware/" + versionout os.rename(src, dst) versionout = version[:-1] + "_" + sha + "_esp32_prometheus.bin" - src = path + ".pio/build/esp32-wroom32-release-prometheus/firmware.bin" + src = path + ".pio/build/esp32-wroom32-prometheus/firmware.bin" dst = path + "firmware/" + versionout os.rename(src, dst) versionout = version[:-1] + "_" + sha + "_esp32_ethernet.bin" - src = path + ".pio/build/esp32-wroom32-ethernet-release/firmware.bin" + src = path + ".pio/build/esp32-wroom32-ethernet/firmware.bin" dst = path + "firmware/" + versionout os.rename(src, dst) versionout = version[:-1] + "_" + sha + "_esp32s3.bin" - src = path + ".pio/build/opendtufusionv1-release/firmware.bin" + src = path + ".pio/build/opendtufusionv1/firmware.bin" dst = path + "firmware/s3/" + versionout os.rename(src, dst) # other ESP32 bin files - src = path + ".pio/build/esp32-wroom32-release/" + src = path + ".pio/build/esp32-wroom32/" dst = path + "firmware/" os.rename(src + "bootloader.bin", dst + "bootloader.bin") os.rename(src + "partitions.bin", dst + "partitions.bin") genOtaBin(path + "firmware/") # other ESP32S3 bin files - src = path + ".pio/build/opendtufusionv1-release/" + src = path + ".pio/build/opendtufusionv1/" dst = path + "firmware/s3/" os.rename(src + "bootloader.bin", dst + "bootloader.bin") os.rename(src + "partitions.bin", dst + "partitions.bin") diff --git a/src/CHANGES.md b/src/CHANGES.md index 83e4124d..c660a8da 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,10 @@ # Development Changes +## 0.7.40 - 2023-08-21 +* added default pins for opendtu-fusion-v1 board +* fixed hw version display in `live` +* removed development builds, renamed environments in `platform.ini` + ## 0.7.39 - 2023-08-21 * fix background color of invalid inputs * add hardware info (click in `live` on inverter name) diff --git a/src/config/config.h b/src/config/config.h index 5169edd3..397ad15a 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -7,6 +7,10 @@ #define __CONFIG_H__ +// globally used +#define DEF_PIN_OFF 255 + + //------------------------------------- // WIFI CONFIGURATION //------------------------------------- @@ -60,25 +64,66 @@ // for the ESP32-S3 there is no sane 'default', as it has full flexibility // to map its two HW SPIs anywhere and PCBs differ materially, // so it has to be selected in the Web UI - #define DEF_CS_PIN 5 - #define DEF_CE_PIN 17 - #define DEF_IRQ_PIN 16 - #define DEF_MISO_PIN 19 - #define DEF_MOSI_PIN 23 - #define DEF_SCLK_PIN 18 - - #define DEF_CMT_CSB 27 - #define DEF_CMT_FCSB 26 - #define DEF_CMT_IRQ 34 + #ifndef DEF_NRF_CS_PIN + #define DEF_NRF_CS_PIN 5 + #endif + #ifndef DEF_NRF_CE_PIN + #define DEF_NRF_CE_PIN 17 + #endif + #ifndef DEF_NRF_IRQ_PIN + #define DEF_NRF_IRQ_PIN 16 + #endif + #ifndef DEF_NRF_MISO_PIN + #define DEF_NRF_MISO_PIN 19 + #endif + #ifndef DEF_NRF_MOSI_PIN + #define DEF_NRF_MOSI_PIN 23 + #endif + #ifndef DEF_NRF_SCLK_PIN + #define DEF_NRF_SCLK_PIN 18 + #endif + + #ifndef DEF_CMT_CSB + #define DEF_CMT_CSB 27 + #endif + #ifndef DEF_CMT_FCSB + #define DEF_CMT_FCSB 26 + #endif + #ifndef DEF_CMT_IRQ + #define DEF_CMT_IRQ 34 + #endif #else - #define DEF_CS_PIN 15 - #define DEF_CE_PIN 0 - #define DEF_IRQ_PIN 2 + #ifndef DEF_NRF_CS_PIN + #define DEF_NRF_CS_PIN 15 + #endif + #ifndef DEF_NRF_CE_PIN + #define DEF_NRF_CE_PIN 0 + #endif + #ifndef DEF_NRF_IRQ_PIN + #define DEF_NRF_IRQ_PIN 2 + #endif // these are given to relay the correct values via API // they cannot actually be moved for ESP82xx models - #define DEF_MISO_PIN 12 - #define DEF_MOSI_PIN 13 - #define DEF_SCLK_PIN 14 + #ifndef DEF_NRF_MISO_PIN + #define DEF_NRF_MISO_PIN 12 + #endif + #ifndef DEF_NRF_MOSI_PIN + #define DEF_NRF_MOSI_PIN 13 + #endif + #ifndef DEF_NRF_SCLK_PIN + #define DEF_NRF_SCLK_PIN 14 + #endif +#endif +#ifndef DEF_LED0 + #define DEF_LED0 DEF_PIN_OFF +#endif +#ifndef DEF_LED1 + #define DEF_LED1 DEF_PIN_OFF +#endif +#ifdef LED_ACTIVE_HIGH + #define LED_HIGH_ACTIVE true +#else + #define LED_HIGH_ACTIVE false #endif // default NRF24 power, possible values (0 - 3) diff --git a/src/config/settings.h b/src/config/settings.h index fe1be71a..99da3265 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -29,7 +29,6 @@ * More info: * https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html#flash-layout * */ -#define DEF_PIN_OFF 255 #define PROT_MASK_INDEX 0x0001 @@ -385,12 +384,12 @@ class settings { mCfg.nrf.sendInterval = SEND_INTERVAL; mCfg.nrf.maxRetransPerPyld = DEF_MAX_RETRANS_PER_PYLD; - mCfg.nrf.pinCs = DEF_CS_PIN; - mCfg.nrf.pinCe = DEF_CE_PIN; - mCfg.nrf.pinIrq = DEF_IRQ_PIN; - mCfg.nrf.pinMiso = DEF_MISO_PIN; - mCfg.nrf.pinMosi = DEF_MOSI_PIN; - mCfg.nrf.pinSclk = DEF_SCLK_PIN; + mCfg.nrf.pinCs = DEF_NRF_CS_PIN; + mCfg.nrf.pinCe = DEF_NRF_CE_PIN; + mCfg.nrf.pinIrq = DEF_NRF_IRQ_PIN; + mCfg.nrf.pinMiso = DEF_NRF_MISO_PIN; + mCfg.nrf.pinMosi = DEF_NRF_MOSI_PIN; + mCfg.nrf.pinSclk = DEF_NRF_SCLK_PIN; mCfg.nrf.amplifierPower = DEF_AMPLIFIERPOWER & 0x03; mCfg.nrf.enabled = true; @@ -433,9 +432,9 @@ class settings { mCfg.inst.rstMaxValsMidNight = false; mCfg.inst.yieldEffiency = 0.955f; - mCfg.led.led0 = DEF_PIN_OFF; - mCfg.led.led1 = DEF_PIN_OFF; - mCfg.led.led_high_active = false; + mCfg.led.led0 = DEF_LED0; + mCfg.led.led1 = DEF_LED1; + mCfg.led.led_high_active = LED_HIGH_ACTIVE; memset(&mCfg.inst, 0, sizeof(cfgInst_t)); @@ -522,12 +521,12 @@ class settings { mCfg.nrf.enabled = (bool) obj[F("en")]; #endif 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; - mCfg.nrf.pinSclk = DEF_SCLK_PIN; - mCfg.nrf.pinMosi = DEF_MOSI_PIN; - mCfg.nrf.pinMiso = DEF_MISO_PIN; + mCfg.nrf.pinCs = DEF_NRF_CS_PIN; + mCfg.nrf.pinCe = DEF_NRF_CE_PIN; + mCfg.nrf.pinIrq = DEF_NRF_IRQ_PIN; + mCfg.nrf.pinSclk = DEF_NRF_SCLK_PIN; + mCfg.nrf.pinMosi = DEF_NRF_MOSI_PIN; + mCfg.nrf.pinMiso = DEF_NRF_MISO_PIN; } } } diff --git a/src/defines.h b/src/defines.h index ffdcab75..f75c01af 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 7 -#define VERSION_PATCH 39 +#define VERSION_PATCH 40 //------------------------------------- typedef struct { diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index a040d01b..3c63aa9e 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -268,11 +268,11 @@ const devInfo_t devInfo[] = { { 0x101020, 350 }, { 0x101030, 400 }, { 0x101040, 400 }, - { 0x101110, 600 }, + { 0x101110, 600 }, // [TSOL800(DE) ..20, HWv=??], [HM-600 ..20, HWv=2.66] { 0x101120, 700 }, { 0x101130, 800 }, { 0x101140, 800 }, - { 0x101210, 1200 }, + { 0x101210, 1200 }, // ..00 { 0x101230, 1500 }, // HMS @@ -287,12 +287,12 @@ const devInfo_t devInfo[] = { { 0x102241, 1600 }, { 0x101251, 1800 }, { 0x102251, 1800 }, - { 0x101271, 2000 }, + { 0x101271, 2000 }, // ..00 { 0x102271, 2000 }, // HMT { 0x103311, 1800 }, - { 0x103331, 2250 } + { 0x103331, 2250 } // ..00 }; #endif /*__HM_DEFINES_H__*/ diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 07bb8c00..583479e8 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -27,7 +27,7 @@ const char* const rf24AmpPowerNames[] = {"MIN", "LOW", "HIGH", "MAX"}; //----------------------------------------------------------------------------- // HM Radio class //----------------------------------------------------------------------------- -template +template class HmRadio { public: HmRadio() : mNrf24(CE_PIN, CS_PIN, SPI_SPEED) { diff --git a/src/platformio.ini b/src/platformio.ini index 28c47783..50be00c4 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -32,125 +32,60 @@ lib_deps = https://github.com/JChristensen/Timezone @ ^1.2.4 olikraus/U8g2 @ ^2.34.17 zinggjm/GxEPD2 @ ^1.5.2 +build_flags = + -std=c++17 + -std=gnu++17 +build_unflags = + -std=gnu++11 -[env:esp8266-release] +[env:esp8266] platform = espressif8266 board = esp12e board_build.f_cpu = 80000000L -build_flags = - -D RELEASE - -std=gnu++17 +build_flags = ${env.build_flags} -DEMC_MIN_FREE_MEMORY=4096 ;-Wl,-Map,output.map monitor_filters = esp8266_exception_decoder -[env:esp8266-release-prometheus] +[env:esp8266-prometheus] platform = espressif8266 board = esp12e board_build.f_cpu = 80000000L -build_flags = - -D RELEASE - -std=gnu++17 +build_flags = ${env.build_flags} -DENABLE_PROMETHEUS_EP -DEMC_MIN_FREE_MEMORY=4096 monitor_filters = esp8266_exception_decoder -[env:esp8266-debug] -platform = espressif8266 -board = esp12e -board_build.f_cpu = 80000000L -build_flags = - -DDEBUG_LEVEL=DBG_DEBUG - -std=gnu++17 - -DEMC_MIN_FREE_MEMORY=4096 - -DDEBUG_ESP_CORE - -DDEBUG_ESP_WIFI - -DDEBUG_ESP_HTTP_CLIENT - -DDEBUG_ESP_HTTP_SERVER - -DDEBUG_ESP_OOM - -DDEBUG_ESP_PORT=Serial - -DPIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48 -build_type = debug -monitor_filters = - time ; Add timestamp with milliseconds for each new line - log2file ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory - -[env:esp8285-release] +[env:esp8285] platform = espressif8266 board = esp8285 board_build.ldscript = eagle.flash.1m64.ld board_build.f_cpu = 80000000L -build_flags = - -D RELEASE - -std=gnu++17 +build_flags = ${env.build_flags} -DEMC_MIN_FREE_MEMORY=4096 monitor_filters = - time ; Add timestamp with milliseconds for each new line - -[env:esp8285-debug] -platform = espressif8266 -board = esp8285 -board_build.ldscript = eagle.flash.1m64.ld -board_build.f_cpu = 80000000L -build_flags = - -DDEBUG_LEVEL=DBG_DEBUG - -DEMC_MIN_FREE_MEMORY=4096 - -DDEBUG_ESP_CORE - -DDEBUG_ESP_WIFI - -DDEBUG_ESP_HTTP_CLIENT - -DDEBUG_ESP_HTTP_SERVER - -DDEBUG_ESP_OOM - -DDEBUG_ESP_PORT=Serial -build_type = debug -monitor_filters = - time ; Add timestamp with milliseconds for each new line - log2file ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory + esp8266_exception_decoder -[env:esp32-wroom32-release] +[env:esp32-wroom32] platform = espressif32@6.1.0 board = lolin_d32 -build_flags = - -D RELEASE - -std=gnu++17 -build_unflags = -std=gnu++11 +build_flags = ${env.build_flags} monitor_filters = esp32_exception_decoder -[env:esp32-wroom32-release-prometheus] +[env:esp32-wroom32-prometheus] platform = espressif32@6.1.0 board = lolin_d32 -build_flags = - -D RELEASE - -std=gnu++17 +build_flags = ${env.build_flags} -DENABLE_PROMETHEUS_EP -build_unflags = -std=gnu++11 monitor_filters = esp32_exception_decoder -[env:esp32-wroom32-debug] -platform = espressif32@6.1.0 -board = lolin_d32 -build_flags = - -DDEBUG_LEVEL=DBG_DEBUG - -DDEBUG_ESP_CORE - -DDEBUG_ESP_WIFI - -DDEBUG_ESP_HTTP_CLIENT - -DDEBUG_ESP_HTTP_SERVER - -DDEBUG_ESP_OOM - -DDEBUG_ESP_PORT=Serial - -std=gnu++17 -build_unflags = -std=gnu++11 -build_type = debug -monitor_filters = - time ; Add timestamp with milliseconds for each new line - log2file ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory - - -[env:esp32-wroom32-ethernet-release] +[env:esp32-wroom32-ethernet] platform = espressif32 board = esp32dev lib_deps = @@ -163,25 +98,32 @@ lib_deps = https://github.com/JChristensen/Timezone @ ^1.2.4 olikraus/U8g2 @ ^2.34.17 zinggjm/GxEPD2 @ ^1.5.2 -build_flags = +build_flags = ${env.build_flags} -D ETHERNET -DRELEASE -DLOG_LOCAL_LEVEL=ESP_LOG_INFO -DDEBUG_LEVEL=DBG_INFO - -std=gnu++17 -build_unflags = -std=gnu++11 monitor_filters = esp32_exception_decoder -[env:opendtufusionv1-release] +[env:opendtufusionv1] platform = espressif32@6.1.0 board = esp32-s3-devkitc-1 upload_protocol = esp-builtin debug_tool = esp-builtin debug_speed = 12000 -build_flags = - -D RELEASE - -std=gnu++17 -build_unflags = -std=gnu++11 +build_flags = ${env.build_flags} + -DDEF_NRF_CS_PIN=37 + -DDEF_NRF_CE_PIN=38 + -DDEF_NRF_IRQ_PIN=47 + -DDEF_NRF_MISO_PIN=48 + -DDEF_NRF_MOSI_PIN=35 + -DDEF_NRF_SCLK_PIN=36 + -DDEF_CMT_CSB=4 + -DDEF_CMT_FCSB=21 + -DDEF_CMT_IRQ=8 + -DDEF_LED0=17 + -DDEF_LED1=18 + -DLED_ACTIVE_HIGH monitor_filters = - time ; Add timestamp with milliseconds for each new line + esp32_exception_decoder diff --git a/src/web/html/visualization.html b/src/web/html/visualization.html index c7de12ff..0d72afac 100644 --- a/src/web/html/visualization.html +++ b/src/web/html/visualization.html @@ -276,7 +276,7 @@ ]), ml("tr", {}, [ ml("th", {}, "Hardware Version / Build"), - ml("td", {}, (obj.hw_ver.toString(16) / 100).toFixed(2) + " (build: " + String(obj.prod_cw) + "/" + String(obj.prod_year) + ")") + ml("td", {}, (obj.hw_ver/100).toFixed(2) + " (build: " + String(obj.prod_cw) + "/" + String(obj.prod_year) + ")") ]), ml("tr", {}, [ ml("th", {}, "Hardware Number"), @@ -284,7 +284,7 @@ ]), ml("tr", {}, [ ml("th", {}, "Bootloader Version"), - ml("td", {}, (obj.boot_ver / 100).toFixed(2)) + ml("td", {}, (obj.boot_ver/100).toFixed(2)) ]) ]) ]); diff --git a/src/web/web.h b/src/web/web.h index ae099656..aa3ad6f4 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -546,12 +546,12 @@ class Web { for (uint8_t i = 0; i < 12; i++) { pin = request->arg(String(pinArgNames[i])).toInt(); switch(i) { - case 0: mConfig->nrf.pinCs = ((pin != 0xff) ? pin : DEF_CS_PIN); break; - case 1: mConfig->nrf.pinCe = ((pin != 0xff) ? pin : DEF_CE_PIN); break; - case 2: mConfig->nrf.pinIrq = ((pin != 0xff) ? pin : DEF_IRQ_PIN); break; - case 3: mConfig->nrf.pinSclk = ((pin != 0xff) ? pin : DEF_SCLK_PIN); break; - case 4: mConfig->nrf.pinMosi = ((pin != 0xff) ? pin : DEF_MOSI_PIN); break; - case 5: mConfig->nrf.pinMiso = ((pin != 0xff) ? pin : DEF_MISO_PIN); break; + case 0: mConfig->nrf.pinCs = ((pin != 0xff) ? pin : DEF_NRF_CS_PIN); break; + case 1: mConfig->nrf.pinCe = ((pin != 0xff) ? pin : DEF_NRF_CE_PIN); break; + case 2: mConfig->nrf.pinIrq = ((pin != 0xff) ? pin : DEF_NRF_IRQ_PIN); break; + case 3: mConfig->nrf.pinSclk = ((pin != 0xff) ? pin : DEF_NRF_SCLK_PIN); break; + case 4: mConfig->nrf.pinMosi = ((pin != 0xff) ? pin : DEF_NRF_MOSI_PIN); break; + case 5: mConfig->nrf.pinMiso = ((pin != 0xff) ? pin : DEF_NRF_MISO_PIN); break; case 6: mConfig->led.led0 = pin; break; case 7: mConfig->led.led1 = pin; break; case 8: mConfig->led.led_high_active = pin; break; // this is not really a pin but a polarity, but handling it close to here makes sense From ae3e98e77d00c40260a8fe5bb3ff566527bf025b Mon Sep 17 00:00:00 2001 From: Alexander Dahl Date: Wed, 23 Aug 2023 06:37:55 +0200 Subject: [PATCH 015/267] Fix typos throughout code Found with `codespell -w -i3 src/**` and reviewed manually. Fixes: #1112 --- src/app.h | 2 +- src/config/config_override_example.h | 4 ++-- src/hm/hmInverter.h | 6 +++--- src/hm/hmRadio.h | 2 +- src/hm/miPayload.h | 6 +++--- src/hms/cmt2300a.h | 8 ++++---- src/plugins/Display/Display_ePaper.cpp | 2 +- src/publisher/pubMqtt.h | 2 +- src/utils/improv.h | 12 ++++++------ src/web/RestApi.h | 2 +- src/web/html/index.html | 2 +- src/web/html/setup.html | 10 +++++----- src/web/web.h | 2 +- 13 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/app.h b/src/app.h index 78a5a9df..fb3da7f6 100644 --- a/src/app.h +++ b/src/app.h @@ -172,7 +172,7 @@ class app : public IApp, public ah::Scheduler { } void ivSendHighPrio(Inverter<> *iv) { - if(mIVCommunicationOn) { // only send commands if communcation is enabled + if(mIVCommunicationOn) { // only send commands if communication is enabled if (iv->ivGen == IV_HM) mPayload.ivSendHighPrio(iv); else if (iv->ivGen == IV_MI) diff --git a/src/config/config_override_example.h b/src/config/config_override_example.h index e7c06b77..7413831a 100644 --- a/src/config/config_override_example.h +++ b/src/config/config_override_example.h @@ -9,11 +9,11 @@ // override fallback WiFi info #define FB_WIFI_OVERRIDDEN -// each ovveride must be preceeded with an #undef statement +// each override must be preceded with an #undef statement #undef FB_WIFI_SSID #define FB_WIFI_SSID "MY_SSID" -// each ovveride must be preceeded with an #undef statement +// each override must be preceded with an #undef statement #undef FB_WIFI_PWD #define FB_WIFI_PWD "MY_WIFI_KEY" diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 75ab9ec4..6223f4a7 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -65,7 +65,7 @@ struct calcFunc_t { template struct record_t { - byteAssign_t* assign; // assigment of bytes in payload + byteAssign_t* assign; // assignment of bytes in payload uint8_t length; // length of the assignment list T *record; // data pointer uint32_t ts; // timestamp of last received payload @@ -151,7 +151,7 @@ class Inverter { InverterStatus status; // indicates the current inverter status std::array lastAlarm; // holds last 10 alarms uint8_t alarmNxtWrPos; // indicates the position in array (rolling buffer) - uint16_t alarmCnt; // counts the total number of occured alarms + uint16_t alarmCnt; // counts the total number of occurred alarms int8_t rssi; // HMS and HMT inverters only @@ -361,7 +361,7 @@ class Inverter { //} } else - DPRINTLN(DBG_WARN, F("add with unknown assginment")); + DPRINTLN(DBG_WARN, F("add with unknown assignment")); } else DPRINTLN(DBG_ERROR, F("addValue: assignment not found with cmd 0x")); diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 583479e8..789b80d5 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -231,7 +231,7 @@ class HmRadio { uint8_t getDataRate(void) { if(!mNrf24.isChipConnected()) - return 3; // unkown + return 3; // unknown return mNrf24.getDataRate(); } diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index fb909663..e461a8dc 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -271,7 +271,7 @@ 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 misleading! // 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]; @@ -280,7 +280,7 @@ const byteAssign_t InfoAssignment[] = { if (*pid == 0x00) { 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! + } else if (p->packet[9] == 0x81) { // might need some additional check, as this is only meant for short answers! DPRINT_IVID(DBG_WARN, iv->id); DBGPRINTLN(F("seems to use 3rd gen. protocol - switching ivGen!")); iv->ivGen = IV_HM; @@ -404,7 +404,7 @@ const byteAssign_t InfoAssignment[] = { (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 + // no processing needed if txId is not one of 0x95, 0x88, 0x89, 0x91, 0x92 or response to 0x36ff mPayload[iv->id].complete = true; continue; // skip to next inverter } diff --git a/src/hms/cmt2300a.h b/src/hms/cmt2300a.h index 95d62191..f27ce3c3 100644 --- a/src/hms/cmt2300a.h +++ b/src/hms/cmt2300a.h @@ -8,7 +8,7 @@ #include "esp32_3wSpi.h" -#define WORK_FREQ_KHZ 865000 // disired work frequency between DTU and +#define WORK_FREQ_KHZ 865000 // desired work frequency between DTU and // inverter in kHz #define HOY_BASE_FREQ_KHZ 860000 // in kHz #define HOY_MAX_FREQ_KHZ 923500 // 0xFE * 250kHz + Base_freq @@ -153,7 +153,7 @@ #define CMT2300A_MASK_TX_DONE_FLG 0x08 #define CMT2300A_MASK_PKT_OK_FLG 0x01 -// default CMT paramters +// default CMT parameters static uint8_t cmtConfig[0x60] PROGMEM { // 0x00 - 0x0f -- RSSI offset +- 0 and 13dBm 0x00, 0x66, 0xEC, 0x1C, 0x70, 0x80, 0x14, 0x08, @@ -360,7 +360,7 @@ class Cmt2300a { inline uint8_t freq2Chan(const uint32_t freqKhz) { if((freqKhz % FREQ_STEP_KHZ) != 0) { - DPRINT(DBG_WARN, F("swtich frequency to ")); + DPRINT(DBG_WARN, F("switch frequency to ")); DBGPRINT(String(freqKhz)); DBGPRINT(F("kHz not possible!")); return 0xff; // error @@ -373,7 +373,7 @@ class Cmt2300a { return 0xff; // error if((freqKhz < FREQ_WARN_MIN_KHZ) || (freqKhz > FREQ_WARN_MAX_KHZ)) - DPRINTLN(DBG_WARN, F("Disired frequency is out of EU legal range! (863 - 870MHz)")); + DPRINTLN(DBG_WARN, F("Desired frequency is out of EU legal range! (863 - 870MHz)")); return (freqKhz - HOY_BASE_FREQ_KHZ) / FREQ_STEP_KHZ; } diff --git a/src/plugins/Display/Display_ePaper.cpp b/src/plugins/Display/Display_ePaper.cpp index 74000180..f4b16ff7 100644 --- a/src/plugins/Display/Display_ePaper.cpp +++ b/src/plugins/Display/Display_ePaper.cpp @@ -205,7 +205,7 @@ void DisplayEPaper::actualPowerPaged(float totalPower, float totalYieldDay, floa void DisplayEPaper::loop(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) { // check if the IP has changed if (_settedIP != WiFi.localIP().toString().c_str()) { - // save the new IP and call the Headline Funktion to adapt the Headline + // save the new IP and call the Headline Function to adapt the Headline _settedIP = WiFi.localIP().toString().c_str(); headlineIP(); } diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 095d6c19..a65a6b61 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -606,7 +606,7 @@ class PubMqtt { uint32_t mIvLastRTRpub[MAX_NUM_INVERTERS]; uint16_t mIntervalTimeout; - // last will topic and payload must be available trough lifetime of 'espMqttClient' + // last will topic and payload must be available through lifetime of 'espMqttClient' 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 diff --git a/src/utils/improv.h b/src/utils/improv.h index 23850ba9..02165239 100644 --- a/src/utils/improv.h +++ b/src/utils/improv.h @@ -39,7 +39,7 @@ class Improv { if(!checkPaket(&buf[0], len, [this](uint8_t type, uint8_t buf[], uint8_t len) { parsePayload(type, buf, len); })) { - DBGPRINTLN(F("check paket failed")); + DBGPRINTLN(F("check packet failed")); } dumpBuf(buf, len); } @@ -100,7 +100,7 @@ class Improv { if(0 != strncmp((char*)buf, "IMPROV", 6)) return false; - // verison check (only version 1 is supported!) + // version check (only version 1 is supported!) if(0x01 != buf[6]) return false; @@ -124,7 +124,7 @@ class Improv { void sendDevInfo(void) { uint8_t buf[50]; buf[7] = TYPE_RPC_RESPONSE; - buf[9] = GET_DEVICE_INFO; // repsonse to cmd + buf[9] = GET_DEVICE_INFO; // response to cmd uint8_t p = 11; // firmware name p += char2Improv("AhoyDTU", &buf[p]); @@ -140,7 +140,7 @@ class Improv { p += char2Improv(mDevName, &buf[p]); buf[10] = p - 11; // sub length - buf[8] = p - 9; // paket length + buf[8] = p - 9; // packet length sendPaket(buf, p); } @@ -157,7 +157,7 @@ class Improv { uint8_t buf[50]; buf[7] = TYPE_RPC_RESPONSE; - buf[9] = GET_WIFI_NETWORKS; // repsonse to cmd + buf[9] = GET_WIFI_NETWORKS; // response to cmd uint8_t p = 11; JsonArray arr = obj[F("networks")]; @@ -170,7 +170,7 @@ class Improv { p += char2Improv(String(arr[i][F("rssi")]).c_str(), &buf[p]); buf[10] = p - 11; // sub length - buf[8] = p - 9; // paket length + buf[8] = p - 9; // packet length sendPaket(buf, p); } diff --git a/src/web/RestApi.h b/src/web/RestApi.h index a0a457d1..270cb372 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -280,7 +280,7 @@ class RestApi { getGeneric(request, obj.createNestedObject(F("generic"))); obj[F("refresh")] = 3; obj[F("refresh_url")] = "/"; - obj[F("html")] = F("succesfully logged out"); + obj[F("html")] = F("successfully logged out"); } void getHtmlReboot(AsyncWebServerRequest *request, JsonObject obj) { diff --git a/src/web/html/index.html b/src/web/html/index.html index 3e3abc5a..4f723fed 100644 --- a/src/web/html/index.html +++ b/src/web/html/index.html @@ -47,7 +47,7 @@ function apiCb(obj) { var e = document.getElementById("apiResult"); if(obj["success"]) { - e.innerHTML = " command excuted"; + e.innerHTML = " command executed"; getAjax("/api/index", parse); } else diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 536cf2ca..94c3d461 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -65,7 +65,7 @@
-

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

+

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

Search Networks
@@ -181,7 +181,7 @@
-
Yield Effiency (should be between 0.95 and 0.96)
+
Yield Efficiency (should be between 0.95 and 0.96)
@@ -200,7 +200,7 @@
-
NTP Intervall (in Minutes, min. 5 Minutes)
+
NTP Interval (in Minutes, min. 5 Minutes)
@@ -487,7 +487,7 @@ function apiCbNtp(obj) { var e = document.getElementById("apiResultNtp"); if(obj["success"]) - e.innerHTML = "command excuted, set new time ..."; + e.innerHTML = "command executed, set new time ..."; else e.innerHTML = "Error: " + obj["error"]; } @@ -501,7 +501,7 @@ function apiCbMqtt(obj) { var e = document.getElementById("apiResultMqtt"); if(obj["success"]) - e.innerHTML = "command excuted"; + e.innerHTML = "command executed"; else e.innerHTML = "Error: " + obj["error"]; } diff --git a/src/web/web.h b/src/web/web.h index aa3ad6f4..f1a14e2b 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -666,7 +666,7 @@ class Web { #ifdef ENABLE_PROMETHEUS_EP // Note // Prometheus exposition format is defined here: https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md - // TODO: Check packetsize for MAX_NUM_INVERTERS. Successfull Tested with 4 Inverters (each with 4 channels) + // TODO: Check packetsize for MAX_NUM_INVERTERS. Successfully Tested with 4 Inverters (each with 4 channels) enum { metricsStateStart, metricsStateInverter1, metricsStateInverter2, metricsStateInverter3, metricsStateInverter4, From 20713c9ffbf378a968bb77222616d40d77509dc1 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Wed, 23 Aug 2023 10:45:58 +0200 Subject: [PATCH 016/267] MI - first update on HW detection see https://github.com/lumapu/ahoy/issues/1111 --- src/hm/hmDefines.h | 6 +++++- src/hm/miPayload.h | 37 ++++++++++++++++++++++++------------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index 3c63aa9e..edf1fc99 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -25,7 +25,7 @@ enum {FLD_UDC = 0, FLD_IDC, FLD_PDC, FLD_YD, FLD_YW, FLD_YT, FLD_FW_BUILD_MONTH_DAY, FLD_FW_BUILD_HOUR_MINUTE, FLD_BOOTLOADER_VER, FLD_ACT_ACTIVE_PWR_LIMIT, FLD_PART_NUM, FLD_HW_VERSION, FLD_GRID_PROFILE_CODE, FLD_GRID_PROFILE_VERSION, /*FLD_ACT_REACTIVE_PWR_LIMIT, FLD_ACT_PF,*/ FLD_LAST_ALARM_CODE, FLD_MP}; - + const char* const fields[] = {"U_DC", "I_DC", "P_DC", "YieldDay", "YieldWeek", "YieldTotal", "U_AC", "U_AC_1N", "U_AC_2N", "U_AC_3N", "UAC_12", "UAC_23", "UAC_31", "I_AC", "IAC_1", "I_AC_2", "I_AC_3", "P_AC", "F_AC", "Temp", "PF_AC", "Efficiency", "Irradiation","Q_AC", @@ -260,6 +260,10 @@ typedef struct { } devInfo_t; const devInfo_t devInfo[] = { + // MI 2nd gen + { 0x13118f, 600 }, + + // MI 3rd gen { 0x100230, 1500 }, diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index fb909663..efb6102b 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -219,12 +219,13 @@ case InverterDevInform_All: 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 } + { FLD_BOOTLOADER_VER, UNIT_NONE, CH0, 8, 2, 1 } }; */ @@ -237,27 +238,37 @@ const byteAssign_t InfoAssignment[] = { mPayload[iv->id].gotFragment = true; if(mSerialDebug) { DPRINT_IVID(DBG_INFO, iv->id); - DPRINT(DBG_INFO,F("HW_VER is ")); - DBGPRINTLN(String((p->packet[24] << 8) + p->packet[25])); + DPRINT(DBG_INFO,F("HW_VER is ")); + DBGPRINTLN(String((p->packet[24] << 8) + p->packet[25])); } + record_t<> *rec = iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure + rec->ts = mPayload[iv->id].ts; + iv->setValue(1, rec, (uint16_t) ((p->packet[24] << 8) + p->packet[25])/1); + //28737 } else if ( p->packet[9] == 0x01 || p->packet[9] == 0x10 ) {//second frame for MI, 3rd gen. answers in 0x10 DPRINT_IVID(DBG_INFO, iv->id); if ( p->packet[9] == 0x01 ) { DBGPRINTLN(F("got 2nd frame (hw info)")); - 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])); + 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])); mPayload[iv->id].gotFragment = true; - iv->setValue(iv->getPosByChFld(0, FLD_YT, rec), rec, (float) ((p->packet[20] << 8) + p->packet[21])/1); + record_t<> *rec = iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure + rec->ts = mPayload[iv->id].ts; + /*for (uint8_t i = 0; i < 5; i++) { + iv->setValue(i, rec, (float) ((p->packet[(10+2*i)] << 8) + p->packet[(11+2*i)])/1); + }*/ + iv->setValue(0, rec, (uint32_t) ((((p->packet[10] << 8) | p->packet[11]) << 8 | p->packet[12]) << 8 | p->packet[13])/1); + if(mSerialDebug) { - 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_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_ECapValue ")); DBGPRINTLN(String((p->packet[20] << 8) + p->packet[21])); - } + } } else { DBGPRINTLN(F("3rd gen. inverter!")); // see table in OpenDTU code, DevInfoParser.cpp devInfo[] } From f917d588f578be604137cee847723354352a0b5b Mon Sep 17 00:00:00 2001 From: DanielR92 Date: Wed, 23 Aug 2023 17:31:17 +0200 Subject: [PATCH 017/267] Add new codes to the list --- src/hm/hmInverter.h | 65 ++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 75ab9ec4..aa4e95a6 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -623,40 +623,49 @@ class Inverter { switch (alarmCode) { // breaks are intentionally missing! case 1: return String(F("Inverter start")); case 2: return String(F("DTU command failed")); + case 73: return String(F("Temperature >80°C")); // https://github.com/tbnobody/OpenDTU/discussions/590#discussioncomment-6049750 case 121: return String(F("Over temperature protection")); + case 124: return String(F("Shut down by remote control")); case 125: return String(F("Grid configuration parameter error")); case 126: return String(F("Software error code 126")); case 127: return String(F("Firmware error")); case 128: return String(F("Software error code 128")); - case 129: return String(F("Software error code 129")); + case 129: return String(F("Abnormal bias")); case 130: return String(F("Offline")); - case 141: return String(F("Grid overvoltage")); - case 142: return String(F("Average grid overvoltage")); - case 143: return String(F("Grid undervoltage")); - case 144: return String(F("Grid overfrequency")); - case 145: return String(F("Grid underfrequency")); - case 146: return String(F("Rapid grid frequency change")); - case 147: return String(F("Power grid outage")); - case 148: return String(F("Grid disconnection")); - case 149: return String(F("Island detected")); - case 205: return String(F("Input port 1 & 2 overvoltage")); - case 206: return String(F("Input port 3 & 4 overvoltage")); - case 207: return String(F("Input port 1 & 2 undervoltage")); - case 208: return String(F("Input port 3 & 4 undervoltage")); - case 209: return String(F("Port 1 no input")); - case 210: return String(F("Port 2 no input")); - case 211: return String(F("Port 3 no input")); - case 212: return String(F("Port 4 no input")); - case 213: return String(F("PV-1 & PV-2 abnormal wiring")); - case 214: return String(F("PV-3 & PV-4 abnormal wiring")); - case 215: return String(F("PV-1 Input overvoltage")); - case 216: return String(F("PV-1 Input undervoltage")); - case 217: return String(F("PV-2 Input overvoltage")); - case 218: return String(F("PV-2 Input undervoltage")); - case 219: return String(F("PV-3 Input overvoltage")); - case 220: return String(F("PV-3 Input undervoltage")); - case 221: return String(F("PV-4 Input overvoltage")); - case 222: return String(F("PV-4 Input undervoltage")); + case 141: return String(F("Grid: Grid overvoltage")); + case 142: return String(F("Grid: 10 min value grid overvoltage")); + case 143: return String(F("Grid: Grid undervoltage")); + case 144: return String(F("Grid: Grid overfrequency")); + case 145: return String(F("Grid: Grid underfrequency")); + case 146: return String(F("Grid: Rapid grid frequency change rate")); + case 147: return String(F("Grid: Power grid outage")); + case 148: return String(F("Grid: Grid disconnection")); + case 149: return String(F("Grid: Island detected")); + case 171: return String(F("Grid: Abnormal phase difference between phase to phase")); + case 205: return String(F("MPPT-A: Input overvoltage")); + case 206: return String(F("MPPT-B: Input overvoltage")); + case 207: return String(F("MPPT-A: Input undervoltage")); + case 208: return String(F("MPPT-B: Input undervoltage")); + case 209: return String(F("PV-1: No input")); + case 210: return String(F("PV-2: No input")); + case 211: return String(F("PV-3: No input")); + case 212: return String(F("PV-4: No input")); + case 213: return String(F("MPPT-A: PV-1 & PV-2 abnormal wiring")); + case 214: return String(F("MPPT-B: PV-3 & PV-4 abnormal wiring")); + case 215: return String(F("PV-1: Input overvoltage")); + case 215: return String(F("MPPT-C: Input overvoltage")); + case 216: return String(F("PV-1: Input undervoltage")); + case 216: return String(F("MPPT-C: Input undervoltage")); + case 217: return String(F("PV-2: Input overvoltage")); + case 217: return String(F("PV-5: No input")); + case 218: return String(F("PV-2: Input undervoltage")); + case 218: return String(F("PV-6: No input")); + case 219: return String(F("PV-3: Input overvoltage")); + case 219: return String(F("MPPT-C: PV-5 & PV-6 abnormal wiring")); + case 220: return String(F("PV-3: Input undervoltage")); + case 221: return String(F("PV-4: Input overvoltage")); + case 221: return String(F("Abnormal wiring of grid neutral line")); + case 222: return String(F("PV-4: Input undervoltage")); case 301: return String(F("Hardware error code 301")); case 302: return String(F("Hardware error code 302")); case 303: return String(F("Hardware error code 303")); From 5fc80f660a64f249d25d7dc8e4efd395ae5f2500 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Wed, 23 Aug 2023 18:28:44 +0200 Subject: [PATCH 018/267] Add files via upload --- src/hm/hmInverter.h | 2 +- src/hm/miPayload.h | 32 ++++++++++++++++++++++++++++---- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 75ab9ec4..dc6c9779 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -210,7 +210,7 @@ class Inverter { enqueCommand(InverterDevInform_Simple); // hardware version enqueCommand(RealTimeRunData_Debug); // live data } else if (ivGen == IV_MI){ - if (getFwVersion() == 0) + if (getFwVersion() == 0 || getHwVersion() == 0) enqueCommand(InverterDevInform_All); // firmware version; might not work, esp. for 1/2 ch hardware if (type == INV_TYPE_4CH) { enqueCommand(0x36); diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index efb6102b..a16cbe21 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -243,20 +243,26 @@ const byteAssign_t InfoAssignment[] = { } record_t<> *rec = iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure rec->ts = mPayload[iv->id].ts; - iv->setValue(1, rec, (uint16_t) ((p->packet[24] << 8) + p->packet[25])/1); + iv->setValue(1, rec, (uint32_t) ((p->packet[24] << 8) + p->packet[25])); //28737 } else if ( p->packet[9] == 0x01 || p->packet[9] == 0x10 ) {//second frame for MI, 3rd gen. answers in 0x10 DPRINT_IVID(DBG_INFO, iv->id); if ( p->packet[9] == 0x01 ) { DBGPRINTLN(F("got 2nd frame (hw info)")); + /* according to xlsx (different start byte -1!) + byte[11] to byte[14] HW_PN + byte[15] byte[16] HW_FB_TLmValue + byte[17] byte[18] HW_FB_ReSPRT + byte[19] byte[20] HW_GridSamp_ResValule + byte[21] byte[22] HW_ECapValue + byte[23] to byte[26] Matching_APPFW_PN + */ + 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])); mPayload[iv->id].gotFragment = true; record_t<> *rec = iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure rec->ts = mPayload[iv->id].ts; - /*for (uint8_t i = 0; i < 5; i++) { - iv->setValue(i, rec, (float) ((p->packet[(10+2*i)] << 8) + p->packet[(11+2*i)])/1); - }*/ iv->setValue(0, rec, (uint32_t) ((((p->packet[10] << 8) | p->packet[11]) << 8 | p->packet[12]) << 8 | p->packet[13])/1); if(mSerialDebug) { @@ -268,6 +274,8 @@ const byteAssign_t InfoAssignment[] = { DBGPRINTLN(String((p->packet[18] << 8) + p->packet[19])); DPRINT(DBG_INFO,F("HW_ECapValue ")); DBGPRINTLN(String((p->packet[20] << 8) + p->packet[21])); + DPRINT(DBG_INFO,F("Matching_APPFW_PN ")); + DBGPRINTLN(String((uint32_t) (((p->packet[22] << 8) | p->packet[23]) << 8 | p->packet[24]) << 8 | p->packet[25])); } } else { DBGPRINTLN(F("3rd gen. inverter!")); // see table in OpenDTU code, DevInfoParser.cpp devInfo[] @@ -276,6 +284,22 @@ const byteAssign_t InfoAssignment[] = { } else if ( p->packet[9] == 0x12 ) {//3rd frame DPRINT_IVID(DBG_INFO, iv->id); DBGPRINTLN(F("got 3rd frame (hw info)")); + /* according to xlsx (different start byte -1!) + byte[11] byte[12] APPFW_MINVER + byte[13] byte[14] HWInfoAddr + byte[15] byte[16] PNInfoCRC_gusv + byte[15] byte[16] PNInfoCRC_gusv + */ + if(mSerialDebug) { + DPRINT(DBG_INFO,F("APPFW_MINVER ")); + DBGPRINTLN(String((p->packet[10] << 8) + p->packet[11])); + DPRINT(DBG_INFO,F("HWInfoAddr ")); + DBGPRINTLN(String((p->packet[12] << 8) + p->packet[13])); + DPRINT(DBG_INFO,F("PNInfoCRC_gusv ")); + DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15])); + DPRINT(DBG_INFO,F("PNInfoCRC_gusv (pt. 2?) ")); + DBGPRINTLN(String((p->packet[16] << 8) + p->packet[17])); + } iv->setQueuedCmdFinished(); mPayload[iv->id].complete = true; mStat->rxSuccess++; From 55b087ba7745e56c7bb9194df3eaeac929c1277d Mon Sep 17 00:00:00 2001 From: DanielR92 Date: Wed, 23 Aug 2023 19:01:47 +0200 Subject: [PATCH 019/267] change rf24Power names --- src/web/html/setup.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 536cf2ca..55bd964a 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -778,10 +778,10 @@ ml("div", {class: "col-12 col-sm-3 my-2"}, "Power Level"), ml("div", {class: "col-12 col-sm-9"}, sel("rf24Power", [ - [0, "MIN"], + [0, "MIN (recommended)"], [1, "LOW"], [2, "HIGH"], - [3, "MAX"] + [3, "MAX (experimental)"] ], obj["power_level"]) ) ]) From f9857b52ab41f47c4418eac4519685f53f81fed1 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 24 Aug 2023 10:10:47 +0200 Subject: [PATCH 020/267] MI - assure HW part no is there --- src/hm/hmInverter.h | 9 +++++++-- src/hm/miPayload.h | 4 +++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index dc6c9779..d00e9e5d 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -210,8 +210,13 @@ class Inverter { enqueCommand(InverterDevInform_Simple); // hardware version enqueCommand(RealTimeRunData_Debug); // live data } else if (ivGen == IV_MI){ - if (getFwVersion() == 0 || getHwVersion() == 0) - enqueCommand(InverterDevInform_All); // firmware version; might not work, esp. for 1/2 ch hardware + if (getFwVersion() == 0) { + enqueCommand(InverterDevInform_All); // hard- and firmware version + } else { + record_t<> *rec = getRecordStruct(InverterDevInform_Simple); + if (getChannelFieldValue(CH0, FLD_PART_NUM, rec) == 0) + enqueCommand(InverterDevInform_All); // hard- and firmware version for missing HW part nr, delivered by frame 1 + } if (type == INV_TYPE_4CH) { enqueCommand(0x36); } else { diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index a16cbe21..c96e9896 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -243,7 +243,8 @@ const byteAssign_t InfoAssignment[] = { } record_t<> *rec = iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure rec->ts = mPayload[iv->id].ts; - iv->setValue(1, rec, (uint32_t) ((p->packet[24] << 8) + p->packet[25])); + iv->setValue(1, rec, (uint32_t) ((p->packet[24] << 8) + p->packet[25])/1); + notify(InverterDevInform_All, iv); //28737 } else if ( p->packet[9] == 0x01 || p->packet[9] == 0x10 ) {//second frame for MI, 3rd gen. answers in 0x10 DPRINT_IVID(DBG_INFO, iv->id); @@ -277,6 +278,7 @@ const byteAssign_t InfoAssignment[] = { DPRINT(DBG_INFO,F("Matching_APPFW_PN ")); DBGPRINTLN(String((uint32_t) (((p->packet[22] << 8) | p->packet[23]) << 8 | p->packet[24]) << 8 | p->packet[25])); } + notify(InverterDevInform_Simple, iv); } else { DBGPRINTLN(F("3rd gen. inverter!")); // see table in OpenDTU code, DevInfoParser.cpp devInfo[] } From df2b0120933a8841d5a03ff319ae615aa81424fc Mon Sep 17 00:00:00 2001 From: DanielR92 Date: Thu, 24 Aug 2023 14:02:13 +0200 Subject: [PATCH 021/267] NRF signal quality aprox --- src/hm/hmRadio.h | 11 ++++++++++- src/web/RestApi.h | 3 +++ src/web/html/system.html | 3 ++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 583479e8..dc282910 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -21,7 +21,7 @@ #define ALL_FRAMES 0x80 #define SINGLE_FRAME 0x81 -const char* const rf24AmpPowerNames[] = {"MIN", "LOW", "HIGH", "MAX"}; +const char* const rf24AmpPowerNames[] = {"MIN (recommended)", "LOW", "HIGH", "MAX (experimental)"}; //----------------------------------------------------------------------------- @@ -205,6 +205,7 @@ class HmRadio { } cnt++; } + sendPacket(invId, cnt, isRetransmit, isNoMI); } @@ -239,6 +240,14 @@ class HmRadio { return mNrf24.isPVariant(); } + bool goodSignal(void) { + bool goodSignal = mNrf24.testRPD(); + DPRINT(DBG_INFO, F("NRF Signal: ")); + DPRINT(DBG_INFO, String(goodSignal)); + mNrf24.read(0,0); + return goodSignal; + } + std::queue mBufCtrl; uint32_t mSendCnt; diff --git a/src/web/RestApi.h b/src/web/RestApi.h index a0a457d1..4fb4b53f 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -502,6 +502,7 @@ class RestApi { obj[F("isconnected")] = mRadio->isChipConnected(); obj[F("DataRate")] = mRadio->getDataRate(); obj[F("isPVariant")] = mRadio->isPVariant(); + obj[F("goodSignal")] = mRadio->goodSignal(); obj[F("en")] = (bool) mConfig->nrf.enabled; } @@ -570,6 +571,8 @@ class RestApi { warn.add(F("reboot your ESP to apply all your configuration changes")); if(0 == mApp->getTimestamp()) warn.add(F("time not set. No communication to inverter possible")); + + /*if(0 == mSys->getNumInverters()) warn.add(F("no inverter configured"));*/ diff --git a/src/web/html/system.html b/src/web/html/system.html index 0f1df319..4ab63931 100644 --- a/src/web/html/system.html +++ b/src/web/html/system.html @@ -50,7 +50,7 @@ } function parseRadio(obj, stat) { - const pa = ["MIN", "LOW", "HIGH", "MAX"]; + const pa = ["MIN (recommended)", "LOW", "HIGH", "MAX"]; const datarate = ["1 MBps", "2 MBps", "250 kbps"]; var main = document.getElementById("radio"); @@ -61,6 +61,7 @@ main.appendChild(h); main.appendChild(genTabRow("nrf24l01" + (obj["isPVariant"] ? "+ " : ""), (obj["isconnected"] ? "is connected " : "is not connected "))); + main.appendChild(genTabRow("NRF Signal: ", (obj["goodSignal"] ? "Strong signal > 64dBm" : "Weak signal < 64dBm"))); if(obj["isconnected"]) { main.appendChild(genTabRow("Datarate", datarate[obj["DataRate"]])); From 3105cd43808c824ba6f7481d9d30bf3eb87447e0 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Fri, 25 Aug 2023 08:45:43 +0200 Subject: [PATCH 022/267] HW info triggers next request immediate request prod. data if HW info was received --- src/hm/hmInverter.h | 3 +++ src/hm/hmPayload.h | 3 +++ src/hm/miPayload.h | 7 +++++-- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index d00e9e5d..8ce964e9 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -339,6 +339,9 @@ class Inverter { DPRINT(DBG_INFO, "alarm ID incremented to "); DBGPRINTLN(String(alarmMesIndex)); enqueCommand(AlarmData); +// ivSendHighPrio(id); +// if(mHighPrioIv == NULL) // process the request immediately if possible +// mHighPrioIv = iv; } } } diff --git a/src/hm/hmPayload.h b/src/hm/hmPayload.h index 441981cf..3d8692e4 100644 --- a/src/hm/hmPayload.h +++ b/src/hm/hmPayload.h @@ -338,6 +338,9 @@ class HmPayload { yield(); } } + if( (InverterDevInform_All == mPayload[iv->id].txCmd) && (mHighPrioIv == NULL) ) // process next request immediately if possible + mHighPrioIv = iv; + } else { DPRINT(DBG_ERROR, F("plausibility check failed, expected ")); DBGPRINT(String(rec->pyldLen)); diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index c96e9896..ecef1330 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -193,6 +193,8 @@ class MiPayload { record_t<> *rec = iv->getRecordStruct(InverterDevInform_All); // choose the record structure rec->ts = mPayload[iv->id].ts; mPayload[iv->id].gotFragment = true; + if(mHighPrioIv == NULL) // process next request immediately if possible + mHighPrioIv = iv; /* Polling the device software and hardware version number command @@ -244,7 +246,7 @@ const byteAssign_t InfoAssignment[] = { record_t<> *rec = iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure rec->ts = mPayload[iv->id].ts; iv->setValue(1, rec, (uint32_t) ((p->packet[24] << 8) + p->packet[25])/1); - notify(InverterDevInform_All, iv); + //notify(InverterDevInform_All, iv); //28737 } else if ( p->packet[9] == 0x01 || p->packet[9] == 0x10 ) {//second frame for MI, 3rd gen. answers in 0x10 DPRINT_IVID(DBG_INFO, iv->id); @@ -278,7 +280,8 @@ const byteAssign_t InfoAssignment[] = { DPRINT(DBG_INFO,F("Matching_APPFW_PN ")); DBGPRINTLN(String((uint32_t) (((p->packet[22] << 8) | p->packet[23]) << 8 | p->packet[24]) << 8 | p->packet[25])); } - notify(InverterDevInform_Simple, iv); + //notify(InverterDevInform_Simple, iv); + notify(InverterDevInform_All, iv); } else { DBGPRINTLN(F("3rd gen. inverter!")); // see table in OpenDTU code, DevInfoParser.cpp devInfo[] } From b509f0f9842cff43003695553055ef562489df09 Mon Sep 17 00:00:00 2001 From: DanielR92 Date: Fri, 25 Aug 2023 23:20:16 +0200 Subject: [PATCH 023/267] Update User_Manual.md add Copro to the list. https://github.com/lumapu/ahoy/issues/896 --- User_Manual.md | 51 +++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/User_Manual.md b/User_Manual.md index 5e1111b0..6be66f69 100644 --- a/User_Manual.md +++ b/User_Manual.md @@ -265,31 +265,32 @@ In the same approach as for MQTT any other SubCmd and also MainCmd can be applie Gather user inverter information here to understand what differs between some inverters. To get the information open the URL `/api/record/info` on your AhoyDTU. The information will only be present once the AhoyDTU was able to communicate with an inverter. -| Name | Inverter Typ | Bootloader V. | FWVersion | FWBuild [YYYY] | FWBuild [MM-DD] | HWPartId | | | -| ---------- | ------------ | ------------- | --------- | -------------- | --------------- | --------- | -------- | --------- | -| DanielR92 | HM-1500 | | 1.0.16 | 2021 | 10-12 | 100 | | | -| isdor | HM-300 | | 1.0.14 | 2021 | 12-09 | 102 | | | -| aschiffler | HM-1500 | | 1.0.12 | 2020 | 06-24 | 100 | | | -| klahus1 | HM-300 | | 1.0.10 | 2020 | 07-07 | 102 | | | -| roku133 | HM-400 | | 1.0.10 | 2020 | 07-07 | 102 | | | -| eeprom23 | HM-1200 | 0.1.0 | 1.0.18 | 2021 | 12-24 | 269619201 | 18:21:00 | HWRev 256 | -| eeprom23 | HM-1200 2t | 0.1.0 | 1.0.16 | 2021 | 10-12 | 269619207 | 17:06:00 | HWRev 256 | -| fila612 | HM-700 | | 1.0.10 | 2021 | 11-01 | 104 | | | -| tfhcm | TSUN-350 | | 1.0.14 | 2021 | 12-09 | 102 | | | -| Groobi | TSOL-M400 | | 1.0.14 | 2021 | 12-09 | 102 | | | -| setje | HM-600 | | 1.0.08 | 2020 | 07-10 | 104 | | | -| madmartin | HM-600 | 0.1.4 | 1.0.10 | 2021 | 11-01 | 104 | | | -| lumapu | HM-1200 | 0.1.0 | 1.0.12 | 2020 | 06-24 | | | | -| chehrlic | HM-600 | | 1.0.10 | 2021 | 11-01 | 104 | | | -| chehrlic | TSOL-M800de | | 1.0.10 | 2021 | 11-01 | 104 | | | -| B5r1oJ0A9G | HM-800 | | 1.0.10 | 2021 | | 104 | | | -| B5r1oJ0A9G | HM-800 | | 1.0.10 | 2021 | | 104 | | | -| 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 | | | -| | | | | | | | | | +| Name | Inverter Typ | Bootloader V. | FWVersion | FWBuild [YYYY] | FWBuild [MM-DD] | HWPartId | FWBuild [HH:MM:SS] | | +| ---------- | ------------ | ------------- | --------- | -------------- | --------------- | --------- | -------------------- | --------- | +| lumapu | HM-1200 | 0.1.0 | 1.0.12 | 2020 | 06-24 | | | | +| dragricola | HM-1200 | | 1.0.16 | 2021 | 10-12 | 100 | | | +| eeprom23 | HM-1200 | 0.1.0 | 1.0.18 | 2021 | 12-24 | 269619201 | 18:21:00 | | +| eeprom23 | HM-1200 2t | 0.1.0 | 1.0.16 | 2021 | 10-12 | 269619207 | 17:06:00 | | +| aschiffler | HM-1500 | | 1.0.12 | 2020 | 06-24 | 100 | | | +| DanielR92 | HM-1500 | | 1.0.16 | 2021 | 10-12 | 100 | | | +| Copro | HM-300 | | 1.0.10 | 2020 | 07-07 | 102 | 14:12:00 | | +| klahus1 | HM-300 | | 1.0.10 | 2020 | 07-07 | 102 | | | +| isdor | HM-300 | | 1.0.14 | 2021 | 12-09 | 102 | | | +| roku133 | HM-400 | | 1.0.10 | 2020 | 07-07 | 102 | | HWRev 256 | +| setje | HM-600 | | 1.0.08 | 2020 | 07-10 | 104 | | HWRev 256 | +| madmartin | HM-600 | 0.1.4 | 1.0.10 | 2021 | 11-01 | 104 | | | +| chehrlic | HM-600 | | 1.0.10 | 2021 | 11-01 | 104 | | | +| fila612 | HM-700 | | 1.0.10 | 2021 | 11-01 | 104 | | | +| B5r1oJ0A9G | HM-800 | | 1.0.10 | 2021 | | 104 | | | +| B5r1oJ0A9G | HM-800 | | 1.0.10 | 2021 | | 104 | | | +| rejoe2 | MI-1500 | | 1.0.12 | 2020 | 06-24 | 100 | | | +| dragricola | MI-300 | | 230 | 2017 | 08-08 | 1 | | | +| rejoe2 | MI-600 | | 236 | 2018 | 11-27 | 17 | | | +| tomquist | TSOL-M1600 | | 1.0.12 | 2020 | 06-24 | 100 | | | +| Groobi | TSOL-M400 | | 1.0.14 | 2021 | 12-09 | 102 | | | +| chehrlic | TSOL-M800de | | 1.0.10 | 2021 | 11-01 | 104 | | | +| tfhcm | TSUN-350 | | 1.0.14 | 2021 | 12-09 | 102 | | | +| | | | | | | | | | ## Developer Information about Command Queue After reboot or startup the ahoy firmware it will enque three commands in the following sequence: From f6a01c53c316ee50024d1594c92c299d61d9f9e4 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 26 Aug 2023 02:05:23 +0200 Subject: [PATCH 024/267] 0.7.41 * merge PR #1117 code spelling --- src/CHANGES.md | 3 +++ src/defines.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index c660a8da..074ca108 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.7.41 - 2023-08-26 +* merge PR #1117 code spelling + ## 0.7.40 - 2023-08-21 * added default pins for opendtu-fusion-v1 board * fixed hw version display in `live` diff --git a/src/defines.h b/src/defines.h index f75c01af..a5df274b 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 7 -#define VERSION_PATCH 40 +#define VERSION_PATCH 41 //------------------------------------- typedef struct { From 2c6094358f71b66e83f199720d4873c437e0a17a Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 26 Aug 2023 02:20:18 +0200 Subject: [PATCH 025/267] 0.7.41 * alarms were not read after the first day --- src/CHANGES.md | 3 ++- src/hm/hmInverter.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 074ca108..a4a234ee 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,7 +1,8 @@ # Development Changes ## 0.7.41 - 2023-08-26 -* merge PR #1117 code spelling +* merge PR #1117 code spelling fixes #1112 +* alarms were not read after the first day ## 0.7.40 - 2023-08-21 * added default pins for opendtu-fusion-v1 board diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 6223f4a7..b3c6b942 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -438,6 +438,7 @@ class Inverter { if((*timestamp - recordMeas.ts) > INVERTER_OFF_THRES_SEC) { status = InverterStatus::OFF; actPowerLimit = 0xffff; // power limit will be read once inverter becomes available + alarmMesIndex = 0; } else status = InverterStatus::WAS_ON; From 55868e10903c7aa8a10ba024560ef5ec5881e4a9 Mon Sep 17 00:00:00 2001 From: DanielR92 Date: Sat, 26 Aug 2023 18:03:38 +0200 Subject: [PATCH 026/267] Update some lines, remove dbg --- src/hm/hmRadio.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index dc282910..3c4fc29d 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -21,7 +21,7 @@ #define ALL_FRAMES 0x80 #define SINGLE_FRAME 0x81 -const char* const rf24AmpPowerNames[] = {"MIN (recommended)", "LOW", "HIGH", "MAX (experimental)"}; +const char* const rf24AmpPowerNames[] = {"MIN", "LOW", "HIGH", "MAX"}; //----------------------------------------------------------------------------- @@ -240,10 +240,13 @@ class HmRadio { return mNrf24.isPVariant(); } + /* Test whether a signal (carrier or otherwise) greater than or equal to -64dBm is present on the channel. + Valid only on nRF24L01P (+) hardware. On nRF24L01, use testCarrier(). + Useful to check for interference on the current channel and channel hopping strategies. + bool goodSignal = radio.testRPD(); + if(radio.available()){ Serial.println(goodSignal ? "Strong signal > 64dBm" : "Weak signal < 64dBm" ); radio.read(0,0); } */ bool goodSignal(void) { bool goodSignal = mNrf24.testRPD(); - DPRINT(DBG_INFO, F("NRF Signal: ")); - DPRINT(DBG_INFO, String(goodSignal)); mNrf24.read(0,0); return goodSignal; } From e41f7a1c4bd1b6e8e1e56e054330a83b43b4238b Mon Sep 17 00:00:00 2001 From: DanielR92 Date: Sat, 26 Aug 2023 19:39:02 +0200 Subject: [PATCH 027/267] some lines removed. (the removed one was for HMS/HMT) --- src/hm/hmInverter.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index bfcc9c17..b8dd4468 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -653,19 +653,13 @@ class Inverter { case 212: return String(F("PV-4: No input")); case 213: return String(F("MPPT-A: PV-1 & PV-2 abnormal wiring")); case 214: return String(F("MPPT-B: PV-3 & PV-4 abnormal wiring")); - case 215: return String(F("PV-1: Input overvoltage")); case 215: return String(F("MPPT-C: Input overvoltage")); case 216: return String(F("PV-1: Input undervoltage")); - case 216: return String(F("MPPT-C: Input undervoltage")); case 217: return String(F("PV-2: Input overvoltage")); - case 217: return String(F("PV-5: No input")); case 218: return String(F("PV-2: Input undervoltage")); - case 218: return String(F("PV-6: No input")); case 219: return String(F("PV-3: Input overvoltage")); - case 219: return String(F("MPPT-C: PV-5 & PV-6 abnormal wiring")); case 220: return String(F("PV-3: Input undervoltage")); case 221: return String(F("PV-4: Input overvoltage")); - case 221: return String(F("Abnormal wiring of grid neutral line")); case 222: return String(F("PV-4: Input undervoltage")); case 301: return String(F("Hardware error code 301")); case 302: return String(F("Hardware error code 302")); From abdf2185fff1d57c1f3ff9518667ddac44d59cc6 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 27 Aug 2023 22:33:01 +0200 Subject: [PATCH 028/267] 0.7.42 * fix ePaper for opendtufusion_v2.x boards (Software SPI) --- patches/GxEPD2_SW_SPI.patch | 361 +++++++++++++++++++++++++ scripts/applyPatches.py | 9 + src/CHANGES.md | 3 + src/defines.h | 2 +- src/platformio.ini | 4 +- src/plugins/Display/Display_ePaper.cpp | 6 +- src/plugins/Display/Display_ePaper.h | 3 - 7 files changed, 381 insertions(+), 7 deletions(-) create mode 100644 patches/GxEPD2_SW_SPI.patch diff --git a/patches/GxEPD2_SW_SPI.patch b/patches/GxEPD2_SW_SPI.patch new file mode 100644 index 00000000..3eb6a32c --- /dev/null +++ b/patches/GxEPD2_SW_SPI.patch @@ -0,0 +1,361 @@ +diff --git a/src/GxEPD2_EPD.cpp b/src/GxEPD2_EPD.cpp +index 1588444..592869b 100644 +--- a/src/GxEPD2_EPD.cpp ++++ b/src/GxEPD2_EPD.cpp +@@ -19,9 +19,9 @@ + + GxEPD2_EPD::GxEPD2_EPD(int16_t cs, int16_t dc, int16_t rst, int16_t busy, int16_t busy_level, uint32_t busy_timeout, + uint16_t w, uint16_t h, GxEPD2::Panel p, bool c, bool pu, bool fpu) : +- WIDTH(w), HEIGHT(h), panel(p), hasColor(c), hasPartialUpdate(pu), hasFastPartialUpdate(fpu), ++ WIDTH(w), HEIGHT(h), panel(p), hasColor(c), hasPartialUpdate(pu), hasFastPartialUpdate(fpu), _sck(-1), _mosi(-1), + _cs(cs), _dc(dc), _rst(rst), _busy(busy), _busy_level(busy_level), _busy_timeout(busy_timeout), _diag_enabled(false), +- _pSPIx(&SPI), _spi_settings(4000000, MSBFIRST, SPI_MODE0) ++ _spi_settings(4000000, MSBFIRST, SPI_MODE0) + { + _initial_write = true; + _initial_refresh = true; +@@ -67,27 +67,30 @@ void GxEPD2_EPD::init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset + { + pinMode(_busy, INPUT); + } +- _pSPIx->begin(); +- if (_busy == MISO) // may be overridden +- { +- pinMode(_busy, INPUT); +- } +- if (_dc == MISO) // may be overridden, TTGO T5 V2.66 +- { +- pinMode(_dc, OUTPUT); +- } +- if (_cs == MISO) // may be overridden ++ if (_sck < 0) SPI.begin(); ++} ++ ++void GxEPD2_EPD::init(int16_t sck, int16_t mosi, uint32_t serial_diag_bitrate, bool initial, uint16_t reset_duration, bool pulldown_rst_mode) ++{ ++ if ((sck >= 0) && (mosi >= 0)) + { +- pinMode(_cs, INPUT); +- } ++ _sck = sck; ++ _mosi = mosi; ++ digitalWrite(_sck, LOW); ++ digitalWrite(_mosi, LOW); ++ pinMode(_sck, OUTPUT); ++ pinMode(_mosi, OUTPUT); ++ } else _sck = -1; ++ init(serial_diag_bitrate, initial, reset_duration, pulldown_rst_mode); + } + + void GxEPD2_EPD::end() + { +- _pSPIx->end(); + if (_cs >= 0) pinMode(_cs, INPUT); + if (_dc >= 0) pinMode(_dc, INPUT); + if (_rst >= 0) pinMode(_rst, INPUT); ++ if (_sck >= 0) pinMode(_sck, INPUT); ++ if (_mosi >= 0) pinMode(_mosi, INPUT); + } + + void GxEPD2_EPD::setBusyCallback(void (*busyCallback)(const void*), const void* busy_callback_parameter) +@@ -96,12 +99,6 @@ void GxEPD2_EPD::setBusyCallback(void (*busyCallback)(const void*), const void* + _busy_callback_parameter = busy_callback_parameter; + } + +-void GxEPD2_EPD::selectSPI(SPIClass& spi, SPISettings spi_settings) +-{ +- _pSPIx = &spi; +- _spi_settings = spi_settings; +-} +- + void GxEPD2_EPD::_reset() + { + if (_rst >= 0) +@@ -168,115 +165,201 @@ void GxEPD2_EPD::_waitWhileBusy(const char* comment, uint16_t busy_time) + + void GxEPD2_EPD::_writeCommand(uint8_t c) + { +- _pSPIx->beginTransaction(_spi_settings); ++ _beginTransaction(_spi_settings); + if (_dc >= 0) digitalWrite(_dc, LOW); + if (_cs >= 0) digitalWrite(_cs, LOW); +- _pSPIx->transfer(c); ++ _spi_write(c); + if (_cs >= 0) digitalWrite(_cs, HIGH); + if (_dc >= 0) digitalWrite(_dc, HIGH); +- _pSPIx->endTransaction(); ++ _endTransaction(); + } + + void GxEPD2_EPD::_writeData(uint8_t d) + { +- _pSPIx->beginTransaction(_spi_settings); ++ _beginTransaction(_spi_settings); + if (_cs >= 0) digitalWrite(_cs, LOW); +- _pSPIx->transfer(d); ++ _spi_write(d); + if (_cs >= 0) digitalWrite(_cs, HIGH); +- _pSPIx->endTransaction(); ++ _endTransaction(); + } + + void GxEPD2_EPD::_writeData(const uint8_t* data, uint16_t n) + { +- _pSPIx->beginTransaction(_spi_settings); ++ _beginTransaction(_spi_settings); + if (_cs >= 0) digitalWrite(_cs, LOW); +- for (uint16_t i = 0; i < n; i++) ++ for (uint8_t i = 0; i < n; i++) + { +- _pSPIx->transfer(*data++); ++ _spi_write(*data++); + } + if (_cs >= 0) digitalWrite(_cs, HIGH); +- _pSPIx->endTransaction(); ++ _endTransaction(); + } + + void GxEPD2_EPD::_writeDataPGM(const uint8_t* data, uint16_t n, int16_t fill_with_zeroes) + { +- _pSPIx->beginTransaction(_spi_settings); ++ _beginTransaction(_spi_settings); + if (_cs >= 0) digitalWrite(_cs, LOW); +- for (uint16_t i = 0; i < n; i++) ++ for (uint8_t i = 0; i < n; i++) + { +- _pSPIx->transfer(pgm_read_byte(&*data++)); ++ _spi_write(pgm_read_byte(&*data++)); + } + while (fill_with_zeroes > 0) + { +- _pSPIx->transfer(0x00); ++ _spi_write(0x00); + fill_with_zeroes--; + } + if (_cs >= 0) digitalWrite(_cs, HIGH); +- _pSPIx->endTransaction(); ++ _endTransaction(); + } + + void GxEPD2_EPD::_writeDataPGM_sCS(const uint8_t* data, uint16_t n, int16_t fill_with_zeroes) + { +- _pSPIx->beginTransaction(_spi_settings); ++ _beginTransaction(_spi_settings); + for (uint8_t i = 0; i < n; i++) + { + if (_cs >= 0) digitalWrite(_cs, LOW); +- _pSPIx->transfer(pgm_read_byte(&*data++)); ++ _spi_write(pgm_read_byte(&*data++)); + if (_cs >= 0) digitalWrite(_cs, HIGH); + } + while (fill_with_zeroes > 0) + { + if (_cs >= 0) digitalWrite(_cs, LOW); +- _pSPIx->transfer(0x00); ++ _spi_write(0x00); + fill_with_zeroes--; + if (_cs >= 0) digitalWrite(_cs, HIGH); + } +- _pSPIx->endTransaction(); ++ _endTransaction(); + } + + void GxEPD2_EPD::_writeCommandData(const uint8_t* pCommandData, uint8_t datalen) + { +- _pSPIx->beginTransaction(_spi_settings); ++ _beginTransaction(_spi_settings); + if (_dc >= 0) digitalWrite(_dc, LOW); + if (_cs >= 0) digitalWrite(_cs, LOW); +- _pSPIx->transfer(*pCommandData++); ++ _spi_write(*pCommandData++); + if (_dc >= 0) digitalWrite(_dc, HIGH); + for (uint8_t i = 0; i < datalen - 1; i++) // sub the command + { +- _pSPIx->transfer(*pCommandData++); ++ _spi_write(*pCommandData++); + } + if (_cs >= 0) digitalWrite(_cs, HIGH); +- _pSPIx->endTransaction(); ++ _endTransaction(); + } + + void GxEPD2_EPD::_writeCommandDataPGM(const uint8_t* pCommandData, uint8_t datalen) + { +- _pSPIx->beginTransaction(_spi_settings); ++ _beginTransaction(_spi_settings); + if (_dc >= 0) digitalWrite(_dc, LOW); + if (_cs >= 0) digitalWrite(_cs, LOW); +- _pSPIx->transfer(pgm_read_byte(&*pCommandData++)); ++ _spi_write(pgm_read_byte(&*pCommandData++)); + if (_dc >= 0) digitalWrite(_dc, HIGH); + for (uint8_t i = 0; i < datalen - 1; i++) // sub the command + { +- _pSPIx->transfer(pgm_read_byte(&*pCommandData++)); ++ _spi_write(pgm_read_byte(&*pCommandData++)); + } + if (_cs >= 0) digitalWrite(_cs, HIGH); +- _pSPIx->endTransaction(); ++ _endTransaction(); + } + + void GxEPD2_EPD::_startTransfer() + { +- _pSPIx->beginTransaction(_spi_settings); ++ _beginTransaction(_spi_settings); + if (_cs >= 0) digitalWrite(_cs, LOW); + } + + void GxEPD2_EPD::_transfer(uint8_t value) + { +- _pSPIx->transfer(value); ++ _spi_write(value); + } + + void GxEPD2_EPD::_endTransfer() + { + if (_cs >= 0) digitalWrite(_cs, HIGH); +- _pSPIx->endTransaction(); ++ _endTransaction(); ++} ++ ++void GxEPD2_EPD::_beginTransaction(const SPISettings& settings) ++{ ++ if (_sck < 0) SPI.beginTransaction(settings); ++} ++ ++void GxEPD2_EPD::_spi_write(uint8_t data) ++{ ++ if (_sck < 0) SPI.transfer(data); ++ else ++ { ++#if defined (ESP8266) ++ yield(); ++#endif ++ for (int i = 0; i < 8; i++) ++ { ++ digitalWrite(_mosi, (data & 0x80) ? HIGH : LOW); ++ data <<= 1; ++ digitalWrite(_sck, HIGH); ++ digitalWrite(_sck, LOW); ++ } ++ } ++} ++ ++void GxEPD2_EPD::_endTransaction() ++{ ++ if (_sck < 0) SPI.endTransaction(); ++} ++ ++uint8_t GxEPD2_EPD::_readData() ++{ ++ uint8_t data = 0; ++ _beginTransaction(_spi_settings); ++ if (_cs >= 0) digitalWrite(_cs, LOW); ++ if (_sck < 0) ++ { ++ data = SPI.transfer(0); ++ } ++ else ++ { ++ pinMode(_mosi, INPUT); ++ for (int i = 0; i < 8; i++) ++ { ++ data <<= 1; ++ digitalWrite(_sck, HIGH); ++ data |= digitalRead(_mosi); ++ digitalWrite(_sck, LOW); ++ } ++ pinMode(_mosi, OUTPUT); ++ } ++ if (_cs >= 0) digitalWrite(_cs, HIGH); ++ _endTransaction(); ++ return data; ++} ++ ++void GxEPD2_EPD::_readData(uint8_t* data, uint16_t n) ++{ ++ _beginTransaction(_spi_settings); ++ if (_cs >= 0) digitalWrite(_cs, LOW); ++ if (_sck < 0) ++ { ++ for (uint8_t i = 0; i < n; i++) ++ { ++ *data++ = SPI.transfer(0); ++ } ++ } ++ else ++ { ++ pinMode(_mosi, INPUT); ++ for (uint8_t i = 0; i < n; i++) ++ { ++ *data = 0; ++ for (int i = 0; i < 8; i++) ++ { ++ *data <<= 1; ++ digitalWrite(_sck, HIGH); ++ *data |= digitalRead(_mosi); ++ digitalWrite(_sck, LOW); ++ } ++ data++; ++ } ++ pinMode(_mosi, OUTPUT); ++ } ++ if (_cs >= 0) digitalWrite(_cs, HIGH); ++ _endTransaction(); + } +diff --git a/src/GxEPD2_EPD.h b/src/GxEPD2_EPD.h +index ef2318f..50aa961 100644 +--- a/src/GxEPD2_EPD.h ++++ b/src/GxEPD2_EPD.h +@@ -8,6 +8,10 @@ + // Version: see library.properties + // + // Library: https://github.com/ZinggJM/GxEPD2 ++// To use SW SPI with GxEPD2: ++// add the special call to the added init method BEFORE the normal init method: ++// display.epd2.init(SW_SCK, SW_MOSI, 115200, true, 20, false); // define or replace SW_SCK, SW_MOSI ++// display.init(115200); // needed to init upper level + + #ifndef _GxEPD2_EPD_H_ + #define _GxEPD2_EPD_H_ +@@ -35,6 +39,7 @@ class GxEPD2_EPD + uint16_t w, uint16_t h, GxEPD2::Panel p, bool c, bool pu, bool fpu); + virtual void init(uint32_t serial_diag_bitrate = 0); // serial_diag_bitrate = 0 : disabled + virtual void init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset_duration = 10, bool pulldown_rst_mode = false); ++ virtual void init(int16_t sck, int16_t mosi, uint32_t serial_diag_bitrate, bool initial, uint16_t reset_duration = 20, bool pulldown_rst_mode = false); + virtual void end(); // release SPI and control pins + // Support for Bitmaps (Sprites) to Controller Buffer and to Screen + virtual void clearScreen(uint8_t value) = 0; // init controller memory and screen (default white) +@@ -97,7 +102,6 @@ class GxEPD2_EPD + { + return (a > b ? a : b); + }; +- void selectSPI(SPIClass& spi, SPISettings spi_settings); + protected: + void _reset(); + void _waitWhileBusy(const char* comment = 0, uint16_t busy_time = 5000); +@@ -111,16 +115,21 @@ class GxEPD2_EPD + void _startTransfer(); + void _transfer(uint8_t value); + void _endTransfer(); ++ void _beginTransaction(const SPISettings& settings); ++ void _spi_write(uint8_t data); ++ void _endTransaction(); ++ public: ++ uint8_t _readData(); ++ void _readData(uint8_t* data, uint16_t n); + protected: +- int16_t _cs, _dc, _rst, _busy, _busy_level; ++ int16_t _cs, _dc, _rst, _busy, _busy_level, _sck, _mosi;; + uint32_t _busy_timeout; + bool _diag_enabled, _pulldown_rst_mode; +- SPIClass* _pSPIx; + SPISettings _spi_settings; + bool _initial_write, _initial_refresh; + bool _power_is_on, _using_partial_mode, _hibernating; + uint16_t _reset_duration; +- void (*_busy_callback)(const void*); ++ void (*_busy_callback)(const void*); + const void* _busy_callback_parameter; + }; + diff --git a/scripts/applyPatches.py b/scripts/applyPatches.py index 7250f5cb..51fbaa40 100644 --- a/scripts/applyPatches.py +++ b/scripts/applyPatches.py @@ -3,7 +3,11 @@ import subprocess Import("env") def applyPatch(libName, patchFile): + # save current wd + start = os.getcwd() + if os.path.exists('.pio/libdeps/' + env['PIOENV'] + '/' + libName) == False: + print("path '" + '.pio/libdeps/' + env['PIOENV'] + '/' + libName + "' does not exist") return os.chdir('.pio/libdeps/' + env['PIOENV'] + '/' + libName) @@ -18,6 +22,11 @@ def applyPatch(libName, patchFile): else: print('applying \'' + patchFile + '\' failed') + os.chdir(start) + # list of patches to apply (relative to /src) applyPatch("ESP Async WebServer", "../patches/AsyncWeb_Prometheus.patch") + +if env['PIOENV'] == "opendtufusionv1": + applyPatch("GxEPD2", "../patches/GxEPD2_SW_SPI.patch") diff --git a/src/CHANGES.md b/src/CHANGES.md index a4a234ee..a582c030 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.7.42 - 2023-08-27 +* fix ePaper for opendtufusion_v2.x boards (Software SPI) + ## 0.7.41 - 2023-08-26 * merge PR #1117 code spelling fixes #1112 * alarms were not read after the first day diff --git a/src/defines.h b/src/defines.h index a5df274b..25779f7b 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 7 -#define VERSION_PATCH 41 +#define VERSION_PATCH 42 //------------------------------------- typedef struct { diff --git a/src/platformio.ini b/src/platformio.ini index 50be00c4..d80aa0c4 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -31,7 +31,7 @@ lib_deps = bblanchon/ArduinoJson @ ^6.21.3 https://github.com/JChristensen/Timezone @ ^1.2.4 olikraus/U8g2 @ ^2.34.17 - zinggjm/GxEPD2 @ ^1.5.2 + https://github.com/zinggjm/GxEPD2 @ ^1.5.2 build_flags = -std=c++17 -std=gnu++17 @@ -74,6 +74,7 @@ monitor_filters = platform = espressif32@6.1.0 board = lolin_d32 build_flags = ${env.build_flags} + -DUSE_HSPI_FOR_EPD monitor_filters = esp32_exception_decoder @@ -101,6 +102,7 @@ lib_deps = build_flags = ${env.build_flags} -D ETHERNET -DRELEASE + -DUSE_HSPI_FOR_EPD -DLOG_LOCAL_LEVEL=ESP_LOG_INFO -DDEBUG_LEVEL=DBG_INFO monitor_filters = diff --git a/src/plugins/Display/Display_ePaper.cpp b/src/plugins/Display/Display_ePaper.cpp index f4b16ff7..8a72a485 100644 --- a/src/plugins/Display/Display_ePaper.cpp +++ b/src/plugins/Display/Display_ePaper.cpp @@ -29,12 +29,14 @@ void DisplayEPaper::init(uint8_t type, uint8_t _CS, uint8_t _DC, uint8_t _RST, u if (type == 10) { Serial.begin(115200); _display = new GxEPD2_BW(GxEPD2_150_BN(_CS, _DC, _RST, _BUSY)); - hspi.begin(_SCK, _BUSY, _MOSI, _CS); #if defined(ESP32) && defined(USE_HSPI_FOR_EPD) + hspi.begin(_SCK, _BUSY, _MOSI, _CS); _display->epd2.selectSPI(hspi, SPISettings(spiClk, MSBFIRST, SPI_MODE0)); +#elif defined(ESP32) + _display->epd2.init(_SCK, _MOSI, 115200, true, 20, false); #endif - _display->init(115200, true, 2, false); + _display->init(115200, true, 20, false); _display->setRotation(mDisplayRotation); _display->setFullWindow(); diff --git a/src/plugins/Display/Display_ePaper.h b/src/plugins/Display/Display_ePaper.h index ad422b26..d9b24e34 100644 --- a/src/plugins/Display/Display_ePaper.h +++ b/src/plugins/Display/Display_ePaper.h @@ -3,9 +3,6 @@ #if defined(ESP32) -// uncomment next line to use HSPI for EPD (and VSPI for SD), e.g. with Waveshare ESP32 Driver Board -#define USE_HSPI_FOR_EPD - /// uncomment next line to use class GFX of library GFX_Root instead of Adafruit_GFX, to use less code and ram // #include // base class GxEPD2_GFX can be used to pass references or pointers to the display instance as parameter, uses ~1.2k more code From 1253960177413467a301d752b27a04352553e110 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 27 Aug 2023 22:38:28 +0200 Subject: [PATCH 029/267] small improvements - code review --- src/hm/hmRadio.h | 4 +--- src/web/html/system.html | 6 ++++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 18d9fb09..cd9018b8 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -205,7 +205,6 @@ class HmRadio { } cnt++; } - sendPacket(invId, cnt, isRetransmit, isNoMI); } @@ -243,8 +242,7 @@ class HmRadio { /* Test whether a signal (carrier or otherwise) greater than or equal to -64dBm is present on the channel. Valid only on nRF24L01P (+) hardware. On nRF24L01, use testCarrier(). Useful to check for interference on the current channel and channel hopping strategies. - bool goodSignal = radio.testRPD(); - if(radio.available()){ Serial.println(goodSignal ? "Strong signal > 64dBm" : "Weak signal < 64dBm" ); radio.read(0,0); } */ + bool goodSignal = radio.testRPD();*/ bool goodSignal(void) { bool goodSignal = mNrf24.testRPD(); mNrf24.read(0,0); diff --git a/src/web/html/system.html b/src/web/html/system.html index 4ab63931..295f0a55 100644 --- a/src/web/html/system.html +++ b/src/web/html/system.html @@ -60,8 +60,10 @@ h.appendChild(r); main.appendChild(h); - main.appendChild(genTabRow("nrf24l01" + (obj["isPVariant"] ? "+ " : ""), (obj["isconnected"] ? "is connected " : "is not connected "))); - main.appendChild(genTabRow("NRF Signal: ", (obj["goodSignal"] ? "Strong signal > 64dBm" : "Weak signal < 64dBm"))); + main.append( + genTabRow("nrf24l01" + (obj["isPVariant"] ? "+ " : ""), (obj["isconnected"] ? "is connected " : "is not connected ")), + genTabRow("NRF Signal: ", (obj["goodSignal"] ? "Strong signal > 64dBm" : "Weak signal < 64dBm")) + ); if(obj["isconnected"]) { main.appendChild(genTabRow("Datarate", datarate[obj["DataRate"]])); From 4f45444b5fd1dcf9f662055e57be5708a371e2aa Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 27 Aug 2023 22:40:31 +0200 Subject: [PATCH 030/267] 0.7.42 * add signal strength for NRF24 - PR #1119 --- src/CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CHANGES.md b/src/CHANGES.md index a582c030..c5eeb197 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -2,6 +2,7 @@ ## 0.7.42 - 2023-08-27 * fix ePaper for opendtufusion_v2.x boards (Software SPI) +* add signal strength for NRF24 - PR #1119 ## 0.7.41 - 2023-08-26 * merge PR #1117 code spelling fixes #1112 From 0d65016ca1506c732e52736f92b4becf4fd47916 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 27 Aug 2023 23:03:29 +0200 Subject: [PATCH 031/267] refactor wifi for ESP32 S2 (PR #1127) --- src/app.cpp | 2 +- src/platformio.ini | 13 +++ src/wifi/ahoywifi.cpp | 193 ++++++++++++++++++++++++------------------ src/wifi/ahoywifi.h | 12 ++- 4 files changed, 135 insertions(+), 85 deletions(-) diff --git a/src/app.cpp b/src/app.cpp index 4fd1a6a6..13b44fe4 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -225,8 +225,8 @@ void app::onNetwork(bool gotIp) { #if !defined(ETHERNET) if (WIFI_AP == WiFi.getMode()) { mMqttEnabled = false; - everySec(std::bind(&ahoywifi::tickWifiLoop, &mWifi), "wifiL"); } + everySec(std::bind(&ahoywifi::tickWifiLoop, &mWifi), "wifiL"); #endif /* !defined(ETHERNET) */ mInnerLoopCb = [this]() { this->loopStandard(); }; } else { diff --git a/src/platformio.ini b/src/platformio.ini index d80aa0c4..600615a5 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -108,6 +108,19 @@ build_flags = ${env.build_flags} monitor_filters = esp32_exception_decoder +[env:esp-32-s2-mini-release] +platform = espressif32@6.3.2 +board = lolin_s2_mini +build_flags = ${env.build_flags} + -DDEF_NRF_CS_PIN=12 + -DDEF_NRF_CE_PIN=3 + -DDEF_NRF_IRQ_PIN=5 + -DDEF_NRF_MISO_PIN=9 + -DDEF_NRF_MOSI_PIN=11 + -DDEF_NRF_SCLK_PIN=7 +monitor_filters = + esp32_exception_decoder + [env:opendtufusionv1] platform = espressif32@6.1.0 board = esp32-s3-devkitc-1 diff --git a/src/wifi/ahoywifi.cpp b/src/wifi/ahoywifi.cpp index 863ca88f..49db3d84 100644 --- a/src/wifi/ahoywifi.cpp +++ b/src/wifi/ahoywifi.cpp @@ -29,7 +29,8 @@ void ahoywifi::setup(settings_t *config, uint32_t *utcTimestamp, appWifiCb cb) { mUtcTimestamp = utcTimestamp; mAppWifiCb = cb; - mStaConn = DISCONNECTED; + mGotDisconnect = false; + mStaConn = DISCONNECTED; mCnt = 0; mScanActive = false; mScanCnt = 0; @@ -69,12 +70,35 @@ void ahoywifi::setupWifi(bool startAP = false) { } -//----------------------------------------------------------------------------- void ahoywifi::tickWifiLoop() { + static const uint8_t DISCONN_TIMEOUT = 10; + static const uint8_t TIMEOUT = 20; + static const uint8_t SCAN_TIMEOUT = 10; #if !defined(AP_ONLY) - if(mStaConn != GOT_IP) { - if (WiFi.softAPgetStationNum() > 0) { // do not reconnect if any AP connection exists - if(mStaConn != IN_AP_MODE) { + uint8_t timeout = (mStaConn == DISCONNECTED) ? DISCONN_TIMEOUT : TIMEOUT; // seconds + + mCnt++; + + switch (mStaConn) { + case IN_STA_MODE: + // Nothing to do + if (mGotDisconnect) { + mStaConn = RESET; + } + return; + case IN_AP_MODE: + if (WiFi.softAPgetStationNum() == 0) { + mCnt = 0; + mDns.stop(); + WiFi.mode(WIFI_AP_STA); + mStaConn = DISCONNECTED; + } else { + mDns.processNextRequest(); + return; + } + break; + case DISCONNECTED: + if (WiFi.softAPgetStationNum() > 0) { mStaConn = IN_AP_MODE; // first time switch to AP Mode if (mScanActive) { @@ -86,56 +110,45 @@ void ahoywifi::tickWifiLoop() { WiFi.mode(WIFI_AP); mDns.start(53, "*", mApIp); mAppWifiCb(true); + mDns.processNextRequest(); + return; + } else if (!mScanActive) { + DBGPRINT(F("scanning APs with SSID ")); + DBGPRINTLN(String(mConfig->sys.stationSsid)); + mScanCnt = 0; + mCnt = 0; + mScanActive = true; +#if defined(ESP8266) + WiFi.scanNetworks(true, true, 0U, ([this]() { + if (mConfig->sys.isHidden) + return (uint8_t*)NULL; + return (uint8_t*)(mConfig->sys.stationSsid); + })()); +#else + WiFi.scanNetworks(true, true, false, 300U, 0U, ([this]() { + if (mConfig->sys.isHidden) + return (char*)NULL; + return (mConfig->sys.stationSsid); + })()); +#endif + return; + } else if(getBSSIDs()) { + // Scan ready + mStaConn = SCAN_READY; + } else { + // In case of a timeout, what do we do? + // For now we start scanning again as the original code did. + // Would be better to into PA mode + + if (isTimeout(SCAN_TIMEOUT)) { + WiFi.scanDelete(); + mScanActive = false; + } } - mDns.processNextRequest(); - return; - } - else if(mStaConn == IN_AP_MODE) { - mCnt = 0; - mDns.stop(); - WiFi.mode(WIFI_AP_STA); - mStaConn = DISCONNECTED; - } - mCnt++; - - uint8_t timeout = (mStaConn == DISCONNECTED) ? 10 : 20; // seconds - if (mStaConn == CONNECTED) // connected but no ip - timeout = 20; - - 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; - mScanActive = true; - #if defined(ESP8266) - WiFi.scanNetworks(true, true, 0U, ([this] () { - if(mConfig->sys.isHidden) - return (uint8_t *)NULL; - return (uint8_t *)(mConfig->sys.stationSsid); - })()); - #else - WiFi.scanNetworks(true, true, false, 300U, 0U, ([this] () { - if(mConfig->sys.isHidden) - return (char*)NULL; - return (mConfig->sys.stationSsid); - })()); - #endif - return; - } - DBGPRINT(F("reconnect in ")); - DBGPRINT(String(timeout-mCnt)); - DBGPRINTLN(F(" seconds")); - if(mScanActive) { - getBSSIDs(); - if((!mScanActive) && (!mBSSIDList.empty())) // scan completed - if ((mCnt % timeout) < timeout - 2) - mCnt = timeout - 2; - } - if((mCnt % timeout) == 0) { // try to reconnect after x sec without connection - mStaConn = CONNECTING; - WiFi.disconnect(); - - if(mBSSIDList.size() > 0) { // get first BSSID in list + break; + case SCAN_READY: + mStaConn = CONNECTING; + mCnt = 0; DBGPRINT(F("try to connect to AP with BSSID:")); uint8_t bssid[6]; for (int j = 0; j < 6; j++) { @@ -144,17 +157,47 @@ void ahoywifi::tickWifiLoop() { DBGPRINT(" " + String(bssid[j], HEX)); } DBGPRINTLN(""); + mGotDisconnect = false; WiFi.begin(mConfig->sys.stationSsid, mConfig->sys.stationPwd, 0, &bssid[0]); - } - else - mStaConn = DISCONNECTED; - mCnt = 0; - } + break; + case CONNECTING: + if (isTimeout(TIMEOUT)) { + WiFi.disconnect(); + mStaConn = mBSSIDList.empty() ? DISCONNECTED : SCAN_READY; + } + break; + case CONNECTED: + // Connection but no IP yet + if (isTimeout(TIMEOUT) || mGotDisconnect) { + mStaConn = RESET; + } + break; + case GOT_IP: + welcome(WiFi.localIP().toString(), F(" (Station)")); + WiFi.softAPdisconnect(); + WiFi.mode(WIFI_STA); + DBGPRINTLN(F("[WiFi] AP disabled")); + delay(100); + mAppWifiCb(true); + mGotDisconnect = false; + mStaConn = IN_STA_MODE; + break; + case RESET: + mGotDisconnect = false; + mStaConn = DISCONNECTED; + mCnt = 5; // try to reconnect in 5 sec + setupWifi(); // reconnect with AP / Station setup + mAppWifiCb(false); + DPRINTLN(DBG_INFO, "[WiFi] Connection Lost"); + break; + default: + DBGPRINTLN(F("Unhandled status")); + break; } - #endif -} +#endif +} //----------------------------------------------------------------------------- void ahoywifi::setupAp(void) { @@ -213,7 +256,7 @@ void ahoywifi::setupStation(void) { //----------------------------------------------------------------------------- bool ahoywifi::getNtpTime(void) { - if(GOT_IP != mStaConn) + if(IN_STA_MODE != mStaConn) return false; IPAddress timeServer; @@ -314,11 +357,12 @@ bool ahoywifi::getAvailNetworks(JsonObject obj) { } //----------------------------------------------------------------------------- -void ahoywifi::getBSSIDs() { +bool ahoywifi::getBSSIDs() { + bool result = false; int n = WiFi.scanComplete(); if (n < 0) { if (++mScanCnt < 20) - return; + return false; } if(n > 0) { mBSSIDList.clear(); @@ -333,9 +377,11 @@ void ahoywifi::getBSSIDs() { } DBGPRINTLN(""); } + result = true; } mScanActive = false; WiFi.scanDelete(); + return result; } //----------------------------------------------------------------------------- @@ -346,32 +392,17 @@ void ahoywifi::connectionEvent(WiFiStatus_t status) { case CONNECTED: if(mStaConn != CONNECTED) { mStaConn = CONNECTED; + mGotDisconnect = false; DBGPRINTLN(F("\n[WiFi] Connected")); } break; case GOT_IP: mStaConn = GOT_IP; - if (mScanActive) { // maybe another scan has started - WiFi.scanDelete(); - mScanActive = false; - } - welcome(WiFi.localIP().toString(), F(" (Station)")); - WiFi.softAPdisconnect(); - WiFi.mode(WIFI_STA); - DBGPRINTLN(F("[WiFi] AP disabled")); - delay(100); - mAppWifiCb(true); break; case DISCONNECTED: - if(mStaConn != CONNECTING) { - mStaConn = DISCONNECTED; - mCnt = 5; // try to reconnect in 5 sec - setupWifi(); // reconnect with AP / Station setup - mAppWifiCb(false); - DPRINTLN(DBG_INFO, "[WiFi] Connection Lost"); - } + mGotDisconnect = true; break; default: diff --git a/src/wifi/ahoywifi.h b/src/wifi/ahoywifi.h index ef4f2b71..e44d6858 100644 --- a/src/wifi/ahoywifi.h +++ b/src/wifi/ahoywifi.h @@ -32,10 +32,13 @@ class ahoywifi { private: typedef enum WiFiStatus { DISCONNECTED = 0, + SCAN_READY, CONNECTING, CONNECTED, IN_AP_MODE, - GOT_IP + GOT_IP, + IN_STA_MODE, + RESET } WiFiStatus_t; void setupWifi(bool startAP); @@ -43,9 +46,11 @@ class ahoywifi { void setupStation(void); void sendNTPpacket(IPAddress& address); void sortRSSI(int *sort, int n); - void getBSSIDs(void); + bool getBSSIDs(void); void connectionEvent(WiFiStatus_t status); - #if defined(ESP8266) + bool isTimeout(uint8_t timeout) { return (mCnt % timeout) == 0; } + +#if defined(ESP8266) void onConnect(const WiFiEventStationModeConnected& event); void onGotIP(const WiFiEventStationModeGotIP& event); void onDisconnect(const WiFiEventStationModeDisconnected& event); @@ -71,6 +76,7 @@ class ahoywifi { uint8_t mScanCnt; bool mScanActive; + bool mGotDisconnect; std::list mBSSIDList; }; From 20649ee9f0dfc605daaa50d0fb60e97823c35422 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 27 Aug 2023 23:20:55 +0200 Subject: [PATCH 032/267] cleaned warnings --- src/platformio.ini | 10 +++++----- src/wifi/ahoywifi.cpp | 2 -- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/platformio.ini b/src/platformio.ini index 600615a5..ed1c9837 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -71,7 +71,7 @@ monitor_filters = esp8266_exception_decoder [env:esp32-wroom32] -platform = espressif32@6.1.0 +platform = espressif32@6.3.2 board = lolin_d32 build_flags = ${env.build_flags} -DUSE_HSPI_FOR_EPD @@ -79,7 +79,7 @@ monitor_filters = esp32_exception_decoder [env:esp32-wroom32-prometheus] -platform = espressif32@6.1.0 +platform = espressif32@6.3.2 board = lolin_d32 build_flags = ${env.build_flags} -DENABLE_PROMETHEUS_EP @@ -122,7 +122,7 @@ monitor_filters = esp32_exception_decoder [env:opendtufusionv1] -platform = espressif32@6.1.0 +platform = espressif32@6.3.2 board = esp32-s3-devkitc-1 upload_protocol = esp-builtin debug_tool = esp-builtin @@ -137,8 +137,8 @@ build_flags = ${env.build_flags} -DDEF_CMT_CSB=4 -DDEF_CMT_FCSB=21 -DDEF_CMT_IRQ=8 - -DDEF_LED0=17 - -DDEF_LED1=18 + -DDEF_LED0=18 + -DDEF_LED1=17 -DLED_ACTIVE_HIGH monitor_filters = esp32_exception_decoder diff --git a/src/wifi/ahoywifi.cpp b/src/wifi/ahoywifi.cpp index 49db3d84..8632de49 100644 --- a/src/wifi/ahoywifi.cpp +++ b/src/wifi/ahoywifi.cpp @@ -71,11 +71,9 @@ void ahoywifi::setupWifi(bool startAP = false) { void ahoywifi::tickWifiLoop() { - static const uint8_t DISCONN_TIMEOUT = 10; static const uint8_t TIMEOUT = 20; static const uint8_t SCAN_TIMEOUT = 10; #if !defined(AP_ONLY) - uint8_t timeout = (mStaConn == DISCONNECTED) ? DISCONN_TIMEOUT : TIMEOUT; // seconds mCnt++; From 4a9c9f57b451e112b50970c5b52cc6e42a0d47ed Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 27 Aug 2023 23:40:35 +0200 Subject: [PATCH 033/267] 0.7.42 * update platform for ESP32 to 6.3.2 * fix opendtufusion LED (were mixed) * fix `last_success` transmitted to often #1124 --- src/CHANGES.md | 4 ++++ src/publisher/pubMqttIvData.h | 18 ++++++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index c5eeb197..7b24a832 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -3,6 +3,10 @@ ## 0.7.42 - 2023-08-27 * fix ePaper for opendtufusion_v2.x boards (Software SPI) * add signal strength for NRF24 - PR #1119 +* refactor wifi class to support ESP32 S2 PR #1127 +* update platform for ESP32 to 6.3.2 +* fix opendtufusion LED (were mixed) +* fix `last_success` transmitted to often #1124 ## 0.7.41 - 2023-08-26 * merge PR #1117 code spelling fixes #1112 diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h index 22a2626d..9393733e 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -102,14 +102,16 @@ class PubMqttIvData { mPos = 0; if(found) { record_t<> *rec = mIv->getRecordStruct(mCmd); - snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/last_success", mIv->config->name); - snprintf(mVal, 40, "%d", mIv->getLastTs(rec)); - mPublish(mSubTopic, mVal, true, QOS_0); - - if((mIv->ivGen == IV_HMS) || (mIv->ivGen == IV_HMT)) { - snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/ch0/rssi", mIv->config->name); - snprintf(mVal, 40, "%d", mIv->rssi); - mPublish(mSubTopic, mVal, false, QOS_0); + if(mIv->getLastTs(rec) != mIvLastRTRpub[mIv->id]) { + snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/last_success", mIv->config->name); + snprintf(mVal, 40, "%d", mIv->getLastTs(rec)); + mPublish(mSubTopic, mVal, true, QOS_0); + + if((mIv->ivGen == IV_HMS) || (mIv->ivGen == IV_HMT)) { + snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/ch0/rssi", mIv->config->name); + snprintf(mVal, 40, "%d", mIv->rssi); + mPublish(mSubTopic, mVal, false, QOS_0); + } } mIv->isProducing(); // recalculate status From e8ac63df188ce771a0dfda10996ed2bd0d3ecb70 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 28 Aug 2023 00:04:09 +0200 Subject: [PATCH 034/267] 0.7.42 * fix prometheus compile ESP32 * added ESP32-S3-mini to github actions * added old Changlog Entries, to have full log of changes --- .github/workflows/compile_development.yml | 2 +- .github/workflows/compile_release.yml | 2 +- scripts/getVersion.py | 5 + src/CHANGES.md | 666 +++++++++++++++++++++- src/platformio.ini | 3 +- 5 files changed, 673 insertions(+), 5 deletions(-) diff --git a/.github/workflows/compile_development.yml b/.github/workflows/compile_development.yml index 49d9d713..aa5789c6 100644 --- a/.github/workflows/compile_development.yml +++ b/.github/workflows/compile_development.yml @@ -47,7 +47,7 @@ jobs: run: python convert.py - name: Run PlatformIO - run: pio run -d src --environment esp8266 --environment esp8266-prometheus --environment esp8285 --environment esp32-wroom32 --environment esp32-wroom32-prometheus --environment esp32-wroom32-ethernet --environment opendtufusionv1 + run: pio run -d src --environment esp8266 --environment esp8266-prometheus --environment esp8285 --environment esp32-wroom32 --environment esp32-wroom32-prometheus --environment esp32-wroom32-ethernet --environment esp32-s2-mini --environment opendtufusionv1 - name: Copy boot_app0.bin run: cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin src/.pio/build/opendtufusionv1/ota.bin diff --git a/.github/workflows/compile_release.yml b/.github/workflows/compile_release.yml index 5d7078e2..ce75358e 100644 --- a/.github/workflows/compile_release.yml +++ b/.github/workflows/compile_release.yml @@ -51,7 +51,7 @@ jobs: run: python convert.py - name: Run PlatformIO - run: pio run -d src --environment esp8266 --environment esp8266-prometheus --environment esp8285 --environment esp32-wroom32 --environment esp32-wroom32-prometheus --environment esp32-wroom32-ethernet --environment opendtufusionv1 + run: pio run -d src --environment esp8266 --environment esp8266-prometheus --environment esp8285 --environment esp32-wroom32 --environment esp32-wroom32-prometheus --environment esp32-wroom32-ethernet --environment esp32-s2-mini --environment opendtufusionv1 - name: Copy boot_app0.bin run: cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin src/.pio/build/opendtufusionv1/ota.bin diff --git a/scripts/getVersion.py b/scripts/getVersion.py index 9e6c90b7..7754c69d 100644 --- a/scripts/getVersion.py +++ b/scripts/getVersion.py @@ -84,6 +84,11 @@ def readVersion(path, infile): dst = path + "firmware/" + versionout os.rename(src, dst) + versionout = version[:-1] + "_" + sha + "_esp32s2-mini.bin" + src = path + ".pio/build/ --environment esp32-s2-mini/firmware.bin" + dst = path + "firmware/" + versionout + os.rename(src, dst) + versionout = version[:-1] + "_" + sha + "_esp32s3.bin" src = path + ".pio/build/opendtufusionv1/firmware.bin" dst = path + "firmware/s3/" + versionout diff --git a/src/CHANGES.md b/src/CHANGES.md index 7b24a832..d611f052 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -7,6 +7,8 @@ * update platform for ESP32 to 6.3.2 * fix opendtufusion LED (were mixed) * fix `last_success` transmitted to often #1124 +* added ESP32-S3-mini to github actions +* added old Changlog Entries, to have full log of changes ## 0.7.41 - 2023-08-26 * merge PR #1117 code spelling fixes #1112 @@ -30,5 +32,665 @@ * fix alarm time on WebGui #1099 * added RSSI info for HMS and HMT inverters (MqTT + REST API) -## 0.7.36 -* last Release +# RELEASE 0.7.36 - 2023-08-18 + +## 0.7.35 - 2023-08-17 +* fixed timestamp for alarms send over MqTT +* auto-patch of `AsyncWebServer` #834, #1036 +* Update documentation in Git regarding `ESP8266` default NRF24 pin assignments + +## 0.7.34 - 2023-08-16 +* fixed timezone offset of alarms +* added `AC` and `DC` to `/live` #1098 +* changed `ESP8266` default NRF24 pin assignments (`D3` = `CE` and `D4` = `IRQ`) +* fixed background of modal window for bright color +* fix MI chrashes +* fix some lost debug messages +* merged PR #1095, MI fixes for 0.7.x versions +* fix scheduled reboot #1097 +* added vector graphic logo `/doc/logo.svg` +* merge PR #1093, improved Nokia5110 display layout + +## 0.7.33 - 2023-08-15 +* add alarms overview to WebGui #608 +* fix webGui total values #1084 + +## 0.7.32 - 2023-08-14 +* fix colors of live view #1091 + +## 0.7.31 - 2023-08-13 +* fixed docu #1085 +* changed active power limit MqTT messages to QOS2 #1072 +* improved alarm messages, added alarm-id to log #1089 +* trigger power limit read on next day (if inverter was offline meanwhile) +* disabled improv implementation to check if it is related to 'Schwuppdizitaet' +* changed live view to gray once inverter isn't available +* added inverter status to API +* changed sum of totals on WebGui depending on inverter status #1084 +* merge maximum power (AC and DC) from PR #1080 + +## 0.7.30 - 2023-08-10 +* attempt to improve speed / repsonse times (Schwuppdizitaet) #1075 + +## 0.7.29 - 2023-08-09 +* MqTT alarm data was never sent, fixed +* REST API: added alarm data +* REST API: made get record obsolete +* REST API: added power limit acknowledge `/api/inverter/id/[0-x]` #1072 + +## 0.7.28 - 2023-08-08 +* fix MI inverter support #1078 + +## 0.7.27 - 2023-08-08 +* added compile option for ethernet #886 +* fix ePaper configuration, missing `Busy`-Pin #1075 + +# RELEASE 0.7.26 - 2023-08-06 + +* fix MqTT `last_success` + +# RELEASE 0.7.25 - 2023-08-06 + +## 0.7.24 - 2023-08-05 +* merge PR #1069 make MqTT client ID configurable +* fix #1016, general MqTT status depending on inverter state machine +* changed icon for fully available inverter to a filled check mark #1070 +* fixed `last_success` update with MqTT #1068 +* removed `improv` esp-web-installer script, because it is not fully functional at this time + +## 0.7.23 - 2023-08-04 +* merge PR #1056, visualization html +* update MqTT library to 1.4.4 +* update RF24 library to 1.4.7 +* update ArduinoJson library to 6.21.3 +* set minimum invervall for `/live` to 5 seconds + +## 0.7.22 - 2023-08-04 +* attempt to fix homeassistant auto discovery #1066 + +## 0.7.21 - 2023-07-30 +* fix MqTT YieldDay Total goes to 0 serveral times #1016 + +## 0.7.20 - 2023-07-28 +* merge PR #1048 version and hash in API, fixes #1045 +* fix: no yield day update if yield day reads `0` after inverter reboot (mostly on evening) #848 +* try to fix Wifi override #1047 +* added information after NTP sync to WebUI #1040 + +## 0.7.19 - 2023-07-27 +* next attempt to fix yield day for multiple inverters #1016 +* reduced threshold for inverter state machine from 60min to 15min to go from state `WAS_ON` to `OFF` + +## 0.7.18 - 2023-07-26 +* next attempt to fix yield day for multiple inverters #1016 + +## 0.7.17 - 2023-07-25 +* next attempt to fix yield day for multiple inverters #1016 +* added two more states for the inverter status (also docu) + +## 0.7.16 - 2023-07-24 +* next attempt to fix yield day for multiple inverters #1016 +* fix export settings date #1040 +* fix time on WebUI (timezone was not observed) #913 #1016 + +## 0.7.15 - 2023-07-23 +* add NTP sync interval #1019 +* adjusted range of contrast / luminance setting #1041 +* use only ISO time format in Web-UI #913 + +## 0.7.14 - 2023-07-23 +* fix Contrast for Nokia Display #1041 +* attempt to fix #1016 by improving inverter status +* added option to adjust effiency for yield (day/total) #1028 + +## 0.7.13 - 2023-07-19 +* merged display PR #1027 +* add date, time and version to export json #1024 + +## 0.7.12 - 2023-07-09 +* added inverter status - state-machine #1016 + +## 0.7.11 - 2023-07-09 +* fix MqTT endless loop #1013 + +## 0.7.10 - 2023-07-08 +* fix MqTT endless loop #1013 + +## 0.7.9 - 2023-07-08 +* added 'improve' functions to set wifi password directly with ESP web tools #1014 +* fixed MqTT publish while appling power limit #1013 +* slightly improved HMT live view (Voltage & Current) + +## 0.7.8 - 2023-07-05 +* fix `YieldDay`, `YieldTotal` and `P_AC` in `TotalValues` #929 +* fix some serial debug prints +* merge PR #1005 which fixes issue #889 +* merge homeassistant PR #963 +* merge PR #890 which gives option for scheduled reboot at midnight (default off) + +## 0.7.7 - 2023-07-03 +* attempt to fix MqTT `YieldDay` in `TotalValues` #927 +* attempt to fix MqTT `YieldDay` and `YieldTotal` even if inverters are not completly available #929 +* fix wrong message 'NRF not connected' if it is disabled #1007 + +## 0.7.6 - 2023-06-17 +* fix display of hidden SSID checkbox +* changed yield correction data type to `double`, now decimal places are supported +* corrected name of 0.91" display in settings +* attempt to fix MqTT zero values only if setting is there #980, #957 +* made AP password configurable #951 +* added option to start without time-sync, eg. for AP-only-mode #951 + +## 0.7.5 - 2023-06-16 +* fix yield day reset on midnight #957 +* improved tickers in `app.cpp` + +## 0.7.4 - 2023-06-15 +* fix MqTT `P_AC` send if inverters are available #987 +* fix assignments for HMS 1CH and 2CH devices +* fixed uptime overflow #990 + +## 0.7.3 - 2023-06-09 +* fix hidden SSID scan #983 +* improved NRF24 missing message on home screen #981 +* fix MqTT publishing only updated values #982 + +## 0.7.2 - 2023-06-08 +* fix HMS-800 and HMS-1000 assignments #981 +* make nrf enabled all the time for ESP8266 +* fix menu item `active` highlight for 'API' and 'Doku' +* fix MqTT totals issue #927, #980 +* reduce maximum number of inverters to 4 for ESP8266, increase to 16 for ESP32 + +## 0.7.1 - 2023-06-05 +* enabled power limit control for HMS / HMT devices +* changed NRF24 lib version back to 1.4.5 because of compile problems for EPS8266 + +## 0.7.0 - 2023-06-04 +* HMS / HMT support for ESP32 devices + +## 0.6.15 - 2023-05-25 +* improved Prometheus Endpoint PR #958 +* fix turn off ePaper only if setting was set #956 +* improved reset values and update MqTT #957 + +## 0.6.14 - 2023-05-21 +* merge PR #902 Mono-Display + +## 0.6.13 - 2023-05-16 +* merge PR #934 (fix JSON API) and #944 (update manual) + +## 0.6.12 - 2023-04-28 +* improved MqTT +* fix menu active item + +## 0.6.11 - 2023-04-27 +* added MqTT class for publishing all values in Arduino `loop` + +## 0.6.10 - HMS +* Version available in `HMS` branch + +# RELEASE 0.6.9 - 2023-04-19 + +## 0.6.8 - 2023-04-19 +* fix #892 `zeroYieldDay` loop was not applied to all channels + +## 0.6.7 - 2023-04-13 +* merge PR #883, improved store of settings and javascript, thx @tastendruecker123 +* support `.` and `,` as floating point seperator in setup #881 + +## 0.6.6 - 2023-04-12 +* increased distance for `import` button in mobile view #879 +* changed `led_high_active` to `bool` #879 + +## 0.6.5 - 2023-04-11 +* fix #845 MqTT subscription for `ctrl/power/[IV-ID]` was missing +* merge PR #876, check JSON settings during read for existance +* **NOTE:** incompatible change: renamed `led_high_active` to `act_high`, maybe setting must be changed after update +* merge PR #861 do not send channel metric if channel is disabled + +## 0.6.4 - 2023-04-06 +* merge PR #846, improved NRF24 communication and MI, thx @beegee3 & @rejoe2 +* merge PR #859, fix burger menu height, thx @ThomasPohl + +## 0.6.3 - 2023-04-04 +* fix login, password length was not checked #852 +* merge PR #854 optimize browser caching, thx @tastendruecker123 #828 +* fix WiFi reconnect not working #851 +* updated issue templates #822 + +## 0.6.2 - 2023-04-04 +* fix login from multiple clients #819 +* fix login screen on small displays + +## 0.6.1 - 2023-04-01 +* merge LED fix - LED1 shows MqTT state, LED configureable active high/low #839 +* only publish new inverter data #826 +* potential fix of WiFi hostname during boot up #752 + +# RELEASE 0.6.0 - 2023-03-27 + +## 0.5.110 +* MQTT fix reconnection by new lib version #780 +* add `about` page +* improved documentation regarding SPI pins #814 +* improved documentation (getting started) #815 #816 +* improved MI 4-ch inverter #820 + +## 0.5.109 +* reduced heap fragmentation by optimizing MqTT #768 +* ePaper: centered text thx @knickohr + +## 0.5.108 +* merge: PR SPI pins configureable (ESP32) #807, #806 (requires manual set of MISO=19, MOSI=23, SCLK=18 in GUI for existing installs) +* merge: PR MI serial outputs #809 +* fix: no MQTT `total` sensor for autodiscover if only one inverter was found #805 +* fix: MQTT `total` renamed to `device_name` + `_TOTOL` for better visibility #805 + +## 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 +* fixed MQTT autodiscover #794, #632 + +## 0.5.105 +* merged MI, thx @rejoe2 #788 +* fixed reboot message #793 + +## 0.5.104 +* further improved save settings +* 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 +* changed display inverter online message +* merged heap improvements #772 + +## 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 +* 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 +* 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` +* 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 +* repaired inverter wise limit control +* fix upload settings #686 + +## 0.5.97 +* Attention: re-ordered display types, check your settings! #746 +* improved saving settings of display #747, #746 +* disabled contrast for Nokia display #746 +* added Prometheus as compile option #719, #615 +* update MQTT lib to v1.4.1 +* limit decimal places to 2 in `live` +* added `-DPIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48` to esp8266 debug build #657 +* a `max-module-power` of `0` disables channel in live view `setup` +* merge MI improvements, get firmware information #753 + +## 0.5.96 +* added Nokia display again for ESP8266 #764 +* changed `var` / `VAr` to SI unit `var` #732 +* fix MQTT retained flags for totals (P_AC, P_DC) #726, #721 + +## 0.5.95 +* merged #742 MI Improvments +* merged #736 remove obsolete JSON Endpoint + +## 0.5.94 +* added ePaper (for ESP32 only!), thx @dAjaY85 #735 +* improved `/live` margins #732 +* renamed `var` to `VAr` #732 + +## 0.5.93 +* improved web API for `live` +* added dark mode option +* converted all forms to reponsive design +* repaired menu with password protection #720, #716, #709 +* merged MI series fixes #729 + +## 0.5.92 +* fix mobile menu +* fix inverters in select `serial.html` #709 + +## 0.5.91 +* improved html and navi, navi is visible even when API dies #660 +* reduced maximum allowed JSON size for API to 6000Bytes #660 +* small fix: output command at `prepareDevInformCmd` #692 +* improved inverter handling #671 + +## 0.5.90 +* merged PR #684, #698, #705 +* webserial minor overflow fix #660 +* web `index.html` improve version information #701 +* fix MQTT sets power limit to zero (0) #692 +* changed `reset at midnight` with timezone #697 + +## 0.5.89 +* reduced heap fragmentation (removed `strtok` completely) #644, #645, #682 +* added part of mac address to MQTT client ID to seperate multiple ESPs in same network +* added dictionary for MQTT to reduce heap-fragmentation +* removed `last Alarm` from Live view, because it showed always the same alarm - will change in future + +## 0.5.88 +* MQTT Yield Day zero, next try to fix #671, thx @beegee3 +* added Solenso inverter to supported devices +* improved reconnection of MQTT #650 + +## 0.5.87 +* fix yield total correction as module (inverter input) value #570 +* reneabled instant start communication (once NTP is synced) #674 + +## 0.5.86 +* prevent send devcontrol request during disabled night communication +* changed yield total correction as module (inverter input) value #570 +* MQTT Yield Day zero, next try to fix #671 + +## 0.5.85 +* fix power-limit was not checked for max retransmits #667 +* fix blue LED lights up all the time #672 +* fix installing schedulers if NTP server isn't available +* improved zero values on triggers #671 +* hardcoded MQTT subtopics, because wildcard `#` leads to errors +* rephrased some messages on webif, thx to @Argafal #638 +* fixed 'polling stop message' on `index.html` #639 + +## 0.5.84 +* fix blue LED lights up all the time #672 +* added an instant start communication (once NTP is synced) +* add MI 3rd generation inverters (10x2 serial numbers) +* first decodings of messages from MI 2nd generation inverters + +## 0.5.83 +* fix MQTT publishing, `callback` was set but reset by following `setup()` + +## 0.5.82 +* fixed communication error #652 +* reset values is no bound to MQTT any more, setting moved to `inverter` #649 +* fixed wording on `index.hmtl` #661 + +## 0.5.81 +* started implementation of MI inverters (setup.html, own processing `MiPayload.h`) + +## 0.5.80 +* fixed communication #656 + +## 0.5.79 +* fixed mixed reset flags #648 +* fixed `mCbAlarm` if MQTT is not used #653 +* fixed MQTT `autodiscover` #630 thanks to @antibill51 +* next changes from @beegee many thanks for your contribution! +* replaced `CircularBuffer` by `std::queue` +* reworked `hmRadio.h` completely (interrupts, packaging) +* fix exception while `reboot` +* cleanup MQTT coding + +## 0.5.78 +* further improvements regarding wifi #611, fix connection if only one AP with same SSID is there +* fix endless loop in `zerovalues` #564 +* fix auto discover again #565 +* added total values to autodiscover #630 +* improved zero at midnight #625 + +## 0.5.77 +* fix wrong filename for automatically created manifest (online installer) #620 +* added rotate display feature #619 +* improved Prometheus endpoint #615, thx to @fsck-block +* improved wifi to connect always to strongest RSSI, thx to @beegee3 #611 + +## 0.5.76 +* reduce MQTT retry interval from maximum speed to one second +* fixed homeassistant autodiscovery #565 +* implemented `getNTPTime` improvements #609 partially #611 +* added alarm messages to MQTT #177, #600, #608 + +## 0.5.75 +* fix wakeup issue, once wifi was lost during night the communication didn't start in the morning +* reenabled FlashStringHelper because of lacking RAM +* complete rewrite of monochrome display class, thx to @dAjaY85 -> displays are now configurable in setup +* fix power limit not possible #607 + +## 0.5.74 +* improved payload handling (retransmit all fragments on CRC error) +* improved `isAvailable`, checkes all record structs, inverter becomes available more early because version is check first +* fix tickers were not set if NTP is not available +* disabled annoying `FlashStringHelper` it gives randomly Expeptions during development, feels more stable since then +* moved erase button to the bottom in settings, not nice but more functional +* split `tx_count` to `tx_cnt` and `retransmits` in `system.html` +* fix mqtt retransmit IP address #602 +* added debug infos for `scheduler` (web -> `/debug` as trigger prints list of tickers to serial console) + +## 0.5.73 +* improved payload handling (request / retransmit) #464 +* included alarm ID parse to serial console (in development) + +## 0.5.72 +* repaired system, scheduler was not called any more #596 + +## 0.5.71 +* improved wifi handling and tickers, many thanks to @beegee3 #571 +* fixed YieldTotal correction calculation #589 +* fixed serial output of power limit acknowledge #569 +* reviewed `sendDiscoveryConfig` #565 +* merged PR `Monodisplay`, many thanks to @dAjaY85 #566, Note: (settings are introduced but not able to be modified, will be included in next version) + +## 0.5.70 +* corrected MQTT `comm_disabled` #529 +* fix Prometheus and JSON endpoints (`config_override.h`) #561 +* publish MQTT with fixed interval even if inverter is not available #542 +* added JSON settings upload. NOTE: settings JSON download changed, so only settings should be uploaded starting from version `0.5.70` #551 +* MQTT topic and inverter name have more allowed characters: `[A-Za-z0-9./#$%&=+_-]+`, thx: @Mo Demman +* improved potential issue with `checkTicker`, thx @cbscpe +* MQTT option for reset values on midnight / not avail / communication stop #539 +* small fix in `tickIVCommunication` #534 +* add `YieldTotal` correction, eg. to have the option to zero at year start #512 + +## 0.5.69 +* merged SH1106 1.3" Display, thx @dAjaY85 +* added SH1106 to automatic build +* added IP address to MQTT (version, device and IP are retained and only transmitted once after boot) #556 +* added `set_power_limit` acknowledge MQTT publish #553 +* changed: version, device name are only published via MQTT once after boot +* added `Login` to menu if admin password is set #554 +* added `development` to second changelog link in `index.html` #543 +* added interval for MQTT (as option). With this settings MQTT live data is published in a fixed timing (only if inverter is available) #542, #523 +* added MQTT `comm_disabled` #529 +* changed name of binaries, moved GIT-Sha to the front #538 + +## 0.5.68 +* repaired receive payload +* Powerlimit is transfered immediately to inverter + +## 0.5.67 +* changed calculation of start / stop communication to 1 min after last comm. stop #515 +* moved payload send to `payload.h`, function `ivSend` #515 +* payload: if last frame is missing, request all frames again + +# RELEASE 0.5.66 - 2022-12-30 + +## 0.5.65 +* wifi, code optimization #509 + +## 0.5.64 +* channel name can use any character, not limited any more +* added `/` to MQTT topic and Inverter name +* trigger for `calcSunrise` is now using local time #515 +* fix reconnect timeout for WiFi #509 +* start AP only after boot, not on WiFi connection loss +* improved /system `free_heap` value (measured before JSON-tree is built) + +## 0.5.63 +* fix Update button protection (prevent double click #527) +* optimized scheduler #515 (thx @beegee3) +* potential fix of #526 duplicates in API `/api/record/live` +* added update information to `index.html` + +## 0.5.62 +* fix MQTT `status` update +* removed MQTT `available_text` (can be deducted from `available`) +* enhanced MQTT documentation in `User_Manual.md` +* remvoed `tickSunset` and `tickSunrise` from MQTT. It's not needed any more because of minute wise check of status (`processIvStatus`) +* changed MQTT topic `status` to nummeric value, check documentation in `User_Manual.md` +* fix regular expression of `setup.html` for inverter name and channel name + +## 0.5.61 +* fix #521 no reconnect at beginning of day +* added immediate (each minute) report of inverter status MQTT #522 +* added protection mask to select which pages should be protected +* update of monochrome display, show values also if nothing changed + +## 0.5.60 +* added regex to inverter name and MQTT topic (setup.html) +* beautified serial.html +* added ticker for wifi loop #515 + +## 0.5.59 +* fix night communication enable +* improved different WiFi connection scenarios (STA WiFi not found, reconnect #509, redirect for AP to configuration) +* increased MQTT user, pwd and topic length to 64 characters + `\0`. (The string end `\0` reduces the available size by one) #516 + +## 0.5.58 +* improved stability +* improved WiFi initial connection - especially if station WiFi is not available +* removed new operators from web.h (reduce dynamic allocation) +* improved sun calculation #515, #505 +* fixed WiFi auto reconnect #509 +* added disable night communication flag to MQTT #505 +* changed MQTT publish of `available` and `available_text` to sunset #468 + +## 0.5.57 +* improved stability +* added icons to index.html, added WiFi-strength symbol on each page +* moved packet stats and sun to system.html +* refactored communication offset (adjustable in minutes now) + +## 0.5.56 +* factory reset formats entire little fs +* renamed sunrise / sunset on index.html to start / stop communication +* show system information only if called directly from menu +* beautified system.html + +## 0.5.55 +* fixed static IP save + +## 0.5.54 +* changed sunrise / sunset calculation, angle is now `-3.5` instead of original `-0.83` +* improved scheduler (removed -1 from `reload`) #483 +* improved reboot flag in `app.h` +* fixed #493 no MQTT payload once display is defined + +## 0.5.53 +* Mono-Display: show values in offline mode #498 +* improved WiFi class #483 +* added communication enable / disable (to test mutliple DTUs with the same inverter) +* fix factory reset #495 + +## 0.5.52 +* improved ahoyWifi class +* added interface class for app +* refactored web and webApi -> RestApi +* fix calcSunrise was not called every day +* added MQTT RX counter to index.html +* all values are displayed on /live even if they are 0 +* added MQTT /status to show status over all inverters + +## 0.5.51 +* improved scheduler, @beegee3 #483 +* refactored get NTP time, @beegee3 #483 +* generate `bin.gz` only for 1M device ESP8285 +* fix calcSunrise was not called every day +* incresed number of allowed characters for MQTT user, broker and password, @DanielR92 +* added NRF24 info to Systeminfo, @DanielR92 +* added timezone for monochrome displays, @gh-fx2 +* added support for second inverter for monochrome displays, @gh-fx2 + +## 0.5.50 +* fixed scheduler, uptime and timestamp counted too fast +* added / renamed automatically build outputs +* fixed MQTT ESP uptime on reconnect (not zero any more) +* changed uptime on index.html to count each second, synced with ESP each 10 seconds + +## 0.5.49 +* fixed AP mode on brand new ESP modules +* fixed `last_success` MQTT message +* fixed MQTT inverter available status at sunset +* reordered enqueue commands after boot up to prevent same payload length for successive commands +* added automatic build for Nokia5110 and SSD1306 displays (ESP8266) + +## 0.5.48 +* added MQTT message send at sunset +* added monochrome display support +* added `once` and `onceAt` to scheduler to make code cleaner +* improved sunrise / sunset calculation + +## 0.5.47 +* refactored ahoyWifi class: AP is opened on every boot, once station connection is successful the AP will be closed +* improved NTP sync after boot, faster sync +* fix NRF24 details only on valid SPI connection + +## 0.5.46 +* fix sunrise / sunset calculation +* improved setup.html: `reboot on save` is checked as default + +## 0.5.45 +* changed MQTT last will topic from `status` to `mqtt` +* fix sunrise / sunset calculation +* fix time of serial web console + +## 0.5.44 +* marked some MQTT messages as retained +* moved global functions to global location (no duplicates) +* changed index.html inverval to static 10 seconds +* fix static IP +* fix NTP with static IP +* print MQTT info only if MQTT was configured + +## 0.5.43 +* updated REST API and MQTT (both of them use the same functionality) +* added ESP-heap information as MQTT message +* changed output name of automatic development build to fixed name (to have a static link from https://ahoydtu.de) +* updated user manual to latest MQTT and API changes + +## 0.5.42 +* fix web logout (auto logout) +* switched MQTT library + +# RELEASE 0.5.41 - 2022-11-22 + +# RELEASE 0.5.28 - 2022-10-30 + +# RELEASE 0.5.17 - 2022-09-06 + +# RELEASE 0.5.16 - 2022-09-04 + diff --git a/src/platformio.ini b/src/platformio.ini index ed1c9837..0a17faff 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -82,6 +82,7 @@ monitor_filters = platform = espressif32@6.3.2 board = lolin_d32 build_flags = ${env.build_flags} + -DUSE_HSPI_FOR_EPD -DENABLE_PROMETHEUS_EP monitor_filters = esp32_exception_decoder @@ -108,7 +109,7 @@ build_flags = ${env.build_flags} monitor_filters = esp32_exception_decoder -[env:esp-32-s2-mini-release] +[env:esp32-s2-mini] platform = espressif32@6.3.2 board = lolin_s2_mini build_flags = ${env.build_flags} From 91518a7029aae76b6fbb95da0d9ddf2555337729 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 28 Aug 2023 00:06:02 +0200 Subject: [PATCH 035/267] 0.7.42 * fix ESP32-S2 build --- src/platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/src/platformio.ini b/src/platformio.ini index 0a17faff..1e61dda1 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -113,6 +113,7 @@ monitor_filters = platform = espressif32@6.3.2 board = lolin_s2_mini build_flags = ${env.build_flags} + -DUSE_HSPI_FOR_EPD -DDEF_NRF_CS_PIN=12 -DDEF_NRF_CE_PIN=3 -DDEF_NRF_IRQ_PIN=5 From a515dbbde1c8fc83960e1a39f4251cd0757c9385 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 28 Aug 2023 08:00:19 +0200 Subject: [PATCH 036/267] 0.7.42 * fix compile --- scripts/getVersion.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/getVersion.py b/scripts/getVersion.py index 7754c69d..f0000758 100644 --- a/scripts/getVersion.py +++ b/scripts/getVersion.py @@ -85,7 +85,7 @@ def readVersion(path, infile): os.rename(src, dst) versionout = version[:-1] + "_" + sha + "_esp32s2-mini.bin" - src = path + ".pio/build/ --environment esp32-s2-mini/firmware.bin" + src = path + ".pio/build/esp32-s2-mini/firmware.bin" dst = path + "firmware/" + versionout os.rename(src, dst) From 3600a2e28c4ba4d38da94013407818504f553120 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 28 Aug 2023 16:07:12 +0200 Subject: [PATCH 037/267] 0.7.43 * improved RSSI for NRF24, now it's read per package (and inverter) #1129 * arranged `heap` related info together in `/system` * fix display navi during save * clean up binary output, separated to folders --- scripts/getVersion.py | 33 ++++++++++++++++++++------------- src/CHANGES.md | 6 ++++++ src/app.cpp | 8 +++++--- src/defines.h | 3 ++- src/hm/hmDefines.h | 2 +- src/hm/hmPayload.h | 19 ++++++++++++++----- src/hm/hmRadio.h | 31 +++++++++++-------------------- src/hms/hmsPayload.h | 11 ++++++----- src/web/RestApi.h | 7 +++---- src/web/html/save.html | 4 +++- src/web/html/setup.html | 2 +- src/web/html/system.html | 5 ++--- src/web/html/visualization.html | 8 ++++++-- 13 files changed, 80 insertions(+), 59 deletions(-) diff --git a/scripts/getVersion.py b/scripts/getVersion.py index f0000758..d04766af 100644 --- a/scripts/getVersion.py +++ b/scripts/getVersion.py @@ -55,58 +55,65 @@ def readVersion(path, infile): versionout = version[:-1] + "_" + sha + "_esp8266.bin" src = path + ".pio/build/esp8266/firmware.bin" - dst = path + "firmware/" + versionout + dst = path + "firmware/ESP8266/" + versionout os.rename(src, dst) versionout = version[:-1] + "_" + sha + "_esp8266_prometheus.bin" src = path + ".pio/build/esp8266-prometheus/firmware.bin" - dst = path + "firmware/" + versionout + dst = path + "firmware/ESP8266/" + versionout os.rename(src, dst) versionout = version[:-1] + "_" + sha + "_esp8285.bin" src = path + ".pio/build/esp8285/firmware.bin" - dst = path + "firmware/" + versionout + dst = path + "firmware/ESP8285/" + versionout os.rename(src, dst) gzip_bin(dst, dst + ".gz") versionout = version[:-1] + "_" + sha + "_esp32.bin" src = path + ".pio/build/esp32-wroom32/firmware.bin" - dst = path + "firmware/" + versionout + dst = path + "firmware/ESP32/" + versionout os.rename(src, dst) versionout = version[:-1] + "_" + sha + "_esp32_prometheus.bin" src = path + ".pio/build/esp32-wroom32-prometheus/firmware.bin" - dst = path + "firmware/" + versionout + dst = path + "firmware/ESP32/" + versionout os.rename(src, dst) versionout = version[:-1] + "_" + sha + "_esp32_ethernet.bin" src = path + ".pio/build/esp32-wroom32-ethernet/firmware.bin" - dst = path + "firmware/" + versionout + dst = path + "firmware/ESP32/" + versionout os.rename(src, dst) versionout = version[:-1] + "_" + sha + "_esp32s2-mini.bin" src = path + ".pio/build/esp32-s2-mini/firmware.bin" - dst = path + "firmware/" + versionout + dst = path + "firmware/ESP32-S2/" + versionout os.rename(src, dst) versionout = version[:-1] + "_" + sha + "_esp32s3.bin" src = path + ".pio/build/opendtufusionv1/firmware.bin" - dst = path + "firmware/s3/" + versionout + dst = path + "firmware/ESP32-S3/" + versionout os.rename(src, dst) # other ESP32 bin files src = path + ".pio/build/esp32-wroom32/" - dst = path + "firmware/" + dst = path + "firmware/ESP32/" os.rename(src + "bootloader.bin", dst + "bootloader.bin") os.rename(src + "partitions.bin", dst + "partitions.bin") - genOtaBin(path + "firmware/") + genOtaBin(dst) - # other ESP32S3 bin files + # other ESP32-S2 bin files + src = path + ".pio/build/esp32-s2-mini/" + dst = path + "firmware/ESP32-S2/" + os.rename(src + "bootloader.bin", dst + "bootloader.bin") + os.rename(src + "partitions.bin", dst + "partitions.bin") + genOtaBin(dst) + + # other ESP32-S3 bin files src = path + ".pio/build/opendtufusionv1/" - dst = path + "firmware/s3/" + dst = path + "firmware/ESP32-S3/" os.rename(src + "bootloader.bin", dst + "bootloader.bin") os.rename(src + "partitions.bin", dst + "partitions.bin") - os.rename(src + "ota.bin", dst + "ota.bin") + genOtaBin(dst) os.rename("../scripts/gh-action-dev-build-flash.html", path + "install.html") diff --git a/src/CHANGES.md b/src/CHANGES.md index d611f052..d3d7ee53 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,11 @@ # Development Changes +## 0.7.43 - 2023-08-28 +* improved RSSI for NRF24, now it's read per package (and inverter) #1129 +* arranged `heap` related info together in `/system` +* fix display navi during save +* clean up binary output, separated to folders + ## 0.7.42 - 2023-08-27 * fix ePaper for opendtufusion_v2.x boards (Software SPI) * add signal strength for NRF24 - PR #1119 diff --git a/src/app.cpp b/src/app.cpp index 13b44fe4..25a849ee 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -145,9 +145,11 @@ void app::loopStandard(void) { if (mConfig->serial.debug) { DPRINT(DBG_INFO, F("RX ")); DBGPRINT(String(p->len)); - DBGPRINT(F("B Ch")); + DBGPRINT(F(" CH")); DBGPRINT(String(p->ch)); - DBGPRINT(F(" | ")); + DBGPRINT(F(", ")); + DBGPRINT(String(p->rssi)); + DBGPRINT(F("dBm | ")); ah::dumpBuf(p->packet, p->len); } mStat.frmCnt++; @@ -172,7 +174,7 @@ void app::loopStandard(void) { if (mConfig->serial.debug) { DPRINT(DBG_INFO, F("RX ")); DBGPRINT(String(p->data[0])); - DBGPRINT(F(" RSSI ")); + DBGPRINT(F(", ")); DBGPRINT(String(p->rssi)); DBGPRINT(F("dBm | ")); ah::dumpBuf(&p->data[1], p->data[0]); diff --git a/src/defines.h b/src/defines.h index 25779f7b..758f355e 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,12 +13,13 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 7 -#define VERSION_PATCH 42 +#define VERSION_PATCH 43 //------------------------------------- typedef struct { uint8_t ch; uint8_t len; + int8_t rssi; uint8_t packet[MAX_RF_PAYLOAD_SIZE]; } packet_t; diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index 3c63aa9e..7b1549ab 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -11,7 +11,7 @@ // inverter generations enum {IV_MI = 0, IV_HM, IV_HMS, IV_HMT, IV_UNKNOWN}; -const char* const generationNames[] = {"HM", "MI", "HMS", "HMT", "UNKNOWN"}; +const char* const generationNames[] = {"MI", "HM", "HMS", "HMT", "UNKNOWN"}; // units enum {UNIT_V = 0, UNIT_A, UNIT_W, UNIT_WH, UNIT_KWH, UNIT_HZ, UNIT_C, UNIT_PCT, UNIT_VAR, UNIT_NONE}; diff --git a/src/hm/hmPayload.h b/src/hm/hmPayload.h index 441981cf..f5b56405 100644 --- a/src/hm/hmPayload.h +++ b/src/hm/hmPayload.h @@ -18,6 +18,7 @@ typedef struct { uint8_t invId; uint32_t ts; uint8_t data[MAX_PAYLOAD_ENTRIES][MAX_RF_PAYLOAD_SIZE]; + int8_t rssi[MAX_PAYLOAD_ENTRIES]; uint8_t len[MAX_PAYLOAD_ENTRIES]; bool complete; uint8_t maxPackId; @@ -172,6 +173,7 @@ class HmPayload { 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; + mPayload[iv->id].rssi[(*pid & 0x7F) - 1] = p->rssi; } if ((*pid & ALL_FRAMES) == ALL_FRAMES) { @@ -284,8 +286,8 @@ class HmPayload { } else { // payload complete DPRINT(DBG_INFO, F("procPyld: cmd: 0x")); DBGHEXLN(mPayload[iv->id].txCmd); - DPRINT(DBG_INFO, F("procPyld: txid: 0x")); - DBGHEXLN(mPayload[iv->id].txId); + //DPRINT(DBG_DEBUG, F("procPyld: txid: 0x")); + //DBGHEXLN(mPayload[iv->id].txId); DPRINT(DBG_DEBUG, F("procPyld: max: ")); DPRINTLN(DBG_DEBUG, String(mPayload[iv->id].maxPackId)); record_t<> *rec = iv->getRecordStruct(mPayload[iv->id].txCmd); // choose the parser @@ -296,6 +298,8 @@ class HmPayload { memset(payload, 0, 150); + int8_t rssi = -127; + for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId); i++) { if((mPayload[iv->id].len[i] + payloadLen) > 150) { DPRINTLN(DBG_ERROR, F("payload buffer to small!")); @@ -303,12 +307,16 @@ class HmPayload { } memcpy(&payload[payloadLen], mPayload[iv->id].data[i], (mPayload[iv->id].len[i])); payloadLen += (mPayload[iv->id].len[i]); + // get worst RSSI + if(mPayload[iv->id].rssi[i] > rssi) + rssi = mPayload[iv->id].rssi[i]; yield(); } payloadLen -= 2; if (mSerialDebug) { - DPRINT(DBG_INFO, F("Payload (")); + DPRINT_IVID(DBG_INFO, iv->id); + DBGPRINT(F("Payload (")); DBGPRINT(String(payloadLen)); DBGPRINT(F("): ")); ah::dumpBuf(payload, payloadLen); @@ -325,6 +333,7 @@ class HmPayload { iv->addValue(i, payload, rec); yield(); } + iv->rssi = rssi; iv->doCalculations(); notify(mPayload[iv->id].txCmd, iv); @@ -388,8 +397,8 @@ class HmPayload { } void reset(uint8_t id) { - DPRINT_IVID(DBG_INFO, id); - DBGPRINTLN(F("resetPayload")); + //DPRINT_IVID(DBG_INFO, id); + //DBGPRINTLN(F("resetPayload")); 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 cd9018b8..0b5feea5 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -239,16 +239,6 @@ class HmRadio { return mNrf24.isPVariant(); } - /* Test whether a signal (carrier or otherwise) greater than or equal to -64dBm is present on the channel. - Valid only on nRF24L01P (+) hardware. On nRF24L01, use testCarrier(). - Useful to check for interference on the current channel and channel hopping strategies. - bool goodSignal = radio.testRPD();*/ - bool goodSignal(void) { - bool goodSignal = mNrf24.testRPD(); - mNrf24.read(0,0); - return goodSignal; - } - std::queue mBufCtrl; uint32_t mSendCnt; @@ -268,16 +258,17 @@ class HmRadio { if (len > 0) { packet_t p; p.ch = mRfChLst[mRxChIdx]; - p.len = len; - mNrf24.read(p.packet, len); + p.len = (len > MAX_RF_PAYLOAD_SIZE) ? MAX_RF_PAYLOAD_SIZE : len; + p.rssi = mNrf24.testRPD() ? -64 : -75; + mNrf24.read(p.packet, p.len); if (p.packet[0] != 0x00) { - mBufCtrl.push(p); - if (p.packet[0] == (TX_REQ_INFO + ALL_FRAMES)) // response from get information command - isLastPackage = (p.packet[9] > ALL_FRAMES); // > ALL_FRAMES indicates last packet received - else if (p.packet[0] == ( 0x0f + ALL_FRAMES) ) // response from MI get information command - isLastPackage = (p.packet[9] > 0x10); // > 0x10 indicates last packet received - else if ((p.packet[0] != 0x88) && (p.packet[0] != 0x92)) // ignore fragment number zero and MI status messages //#0 was p.packet[0] != 0x00 && - isLastPackage = true; // response from dev control command + mBufCtrl.push(p); + if (p.packet[0] == (TX_REQ_INFO + ALL_FRAMES)) // response from get information command + isLastPackage = (p.packet[9] > ALL_FRAMES); // > ALL_FRAMES indicates last packet received + else if (p.packet[0] == ( 0x0f + ALL_FRAMES) ) // response from MI get information command + isLastPackage = (p.packet[9] > 0x10); // > 0x10 indicates last packet received + else if ((p.packet[0] != 0x88) && (p.packet[0] != 0x92)) // ignore fragment number zero and MI status messages //#0 was p.packet[0] != 0x00 && + isLastPackage = true; // response from dev control command } } yield(); @@ -321,7 +312,7 @@ class HmRadio { if(mSerialDebug) { DPRINT(DBG_INFO, F("TX ")); DBGPRINT(String(len)); - DBGPRINT("B Ch"); + DBGPRINT(" CH"); DBGPRINT(String(mRfChLst[mTxChIdx])); DBGPRINT(F(" | ")); ah::dumpBuf(mTxBuf, len); diff --git a/src/hms/hmsPayload.h b/src/hms/hmsPayload.h index bfa75f1a..2ece3c45 100644 --- a/src/hms/hmsPayload.h +++ b/src/hms/hmsPayload.h @@ -272,8 +272,8 @@ class HmsPayload { }*/ 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)); + //DPRINT(DBG_DEBUG, F("procPyld: txid: 0x")); + //DBGPRINTLN(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; @@ -300,7 +300,8 @@ class HmsPayload { payloadLen -= 2; if (mSerialDebug) { - DPRINT(DBG_INFO, F("Payload (")); + DPRINT_IVID(DBG_INFO, iv->id); + DBGPRINT(F("Payload (")); DBGPRINT(String(payloadLen)); DBGPRINT(F("): ")); ah::dumpBuf(payload, payloadLen); @@ -382,8 +383,8 @@ class HmsPayload { } void reset(uint8_t id) { - DPRINT(DBG_INFO, "resetPayload: id: "); - DBGPRINTLN(String(id)); + //DPRINT(DBG_INFO, "resetPayload: id: "); + //DBGPRINTLN(String(id)); memset(&mPayload[id], 0, sizeof(hmsPayload_t)); mPayload[id].txCmd = 0; mPayload[id].gotFragment = false; diff --git a/src/web/RestApi.h b/src/web/RestApi.h index cb147a07..095b065e 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -242,10 +242,10 @@ class RestApi { getStatistics(obj.createNestedObject(F("statistics"))); #if defined(ESP32) - obj[F("heap_total")] = ESP.getHeapSize(); obj[F("chip_revision")] = ESP.getChipRevision(); obj[F("chip_model")] = ESP.getChipModel(); obj[F("chip_cores")] = ESP.getChipCores(); + obj[F("heap_total")] = ESP.getHeapSize(); //obj[F("core_version")] = F("n/a"); //obj[F("flash_size")] = F("n/a"); //obj[F("heap_frag")] = F("n/a"); @@ -256,10 +256,10 @@ class RestApi { //obj[F("chip_revision")] = F("n/a"); //obj[F("chip_model")] = F("n/a"); //obj[F("chip_cores")] = F("n/a"); - obj[F("core_version")] = ESP.getCoreVersion(); - obj[F("flash_size")] = ESP.getFlashChipRealSize() / 1024; // in kb obj[F("heap_frag")] = mHeapFrag; obj[F("max_free_blk")] = mHeapFreeBlk; + obj[F("core_version")] = ESP.getCoreVersion(); + obj[F("flash_size")] = ESP.getFlashChipRealSize() / 1024; // in kb obj[F("reboot_reason")] = ESP.getResetReason(); #endif //obj[F("littlefs_total")] = LittleFS.totalBytes(); @@ -502,7 +502,6 @@ class RestApi { obj[F("isconnected")] = mRadio->isChipConnected(); obj[F("DataRate")] = mRadio->getDataRate(); obj[F("isPVariant")] = mRadio->isPVariant(); - obj[F("goodSignal")] = mRadio->goodSignal(); obj[F("en")] = (bool) mConfig->nrf.enabled; } diff --git a/src/web/html/save.html b/src/web/html/save.html index 4c924c40..ce50c6ca 100644 --- a/src/web/html/save.html +++ b/src/web/html/save.html @@ -51,7 +51,9 @@ parseHtml(obj); } } - intervalId = window.setInterval("getAjax('/api/html/save', parse)", 2500); + + intervalId = window.setInterval("getAjax('/api/html/save', parse)", 2500); + getAjax("/api/generic", parseGeneric); diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 3f8a6c64..9df891c8 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -899,8 +899,8 @@ function parse(root) { if(null != root) { - parseSys(root["system"]); parseGeneric(root["generic"]); + parseSys(root["system"]); parseStaticIp(root["static_ip"]); parseMqtt(root["mqtt"]); parseNtp(root["ntp"]); diff --git a/src/web/html/system.html b/src/web/html/system.html index 295f0a55..d51c01cc 100644 --- a/src/web/html/system.html +++ b/src/web/html/system.html @@ -60,9 +60,8 @@ h.appendChild(r); main.appendChild(h); - main.append( - genTabRow("nrf24l01" + (obj["isPVariant"] ? "+ " : ""), (obj["isconnected"] ? "is connected " : "is not connected ")), - genTabRow("NRF Signal: ", (obj["goodSignal"] ? "Strong signal > 64dBm" : "Weak signal < 64dBm")) + main.appendChild( + genTabRow("nrf24l01" + (obj["isPVariant"] ? "+ " : ""), (obj["isconnected"] ? "is connected " : "is not connected ")) ); if(obj["isconnected"]) { diff --git a/src/web/html/visualization.html b/src/web/html/visualization.html index 0d72afac..03ff4083 100644 --- a/src/web/html/visualization.html +++ b/src/web/html/visualization.html @@ -177,8 +177,12 @@ else ageInfo += "nothing received"; - if((gen >= 2) && (rssi > -127)) - ageInfo += " (RSSI: " + rssi + "dBm)"; + if(rssi > -127) { + if(gen < 2) + ageInfo += " (RSSI: " + ((rssi == -64) ? ">=" : "<") + " -64dBm)"; + else + ageInfo += " (RSSI: " + rssi + "dBm)"; + } return ml("div", {class: "mb-5"}, [ ml("div", {class: "row p-1 ts-h mx-2"}, From c586af97fe7576a50d9ccc629bf7777c252b0145 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 28 Aug 2023 16:26:16 +0200 Subject: [PATCH 038/267] 0.7.43 fix generate binary folders --- scripts/buildManifest.py | 10 +++++----- scripts/getVersion.py | 5 ++++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/scripts/buildManifest.py b/scripts/buildManifest.py index db29b352..2664a39f 100644 --- a/scripts/buildManifest.py +++ b/scripts/buildManifest.py @@ -33,16 +33,16 @@ def buildManifest(path, infile, outfile): esp32 = {} esp32["chipFamily"] = "ESP32" esp32["parts"] = [] - esp32["parts"].append({"path": "bootloader.bin", "offset": 4096}) - esp32["parts"].append({"path": "partitions.bin", "offset": 32768}) - esp32["parts"].append({"path": "ota.bin", "offset": 57344}) - esp32["parts"].append({"path": version[1] + "_" + sha + "_esp32.bin", "offset": 65536}) + esp32["parts"].append({"path": "ESP32/bootloader.bin", "offset": 4096}) + esp32["parts"].append({"path": "ESP32/partitions.bin", "offset": 32768}) + esp32["parts"].append({"path": "ESP32/ota.bin", "offset": 57344}) + esp32["parts"].append({"path": "ESP32/" + version[1] + "_" + sha + "_esp32.bin", "offset": 65536}) data["builds"].append(esp32) esp8266 = {} esp8266["chipFamily"] = "ESP8266" esp8266["parts"] = [] - esp8266["parts"].append({"path": version[1] + "_" + sha + "_esp8266.bin", "offset": 0}) + esp8266["parts"].append({"path": "ESP8266/" + version[1] + "_" + sha + "_esp8266.bin", "offset": 0}) data["builds"].append(esp8266) jsonString = json.dumps(data, indent=2) diff --git a/scripts/getVersion.py b/scripts/getVersion.py index d04766af..cf739710 100644 --- a/scripts/getVersion.py +++ b/scripts/getVersion.py @@ -50,7 +50,10 @@ def readVersion(path, infile): versionnumber += line[p+13:].rstrip() + "." os.mkdir(path + "firmware/") - os.mkdir(path + "firmware/s3/") + os.mkdir(path + "firmware/ESP8266/") + os.mkdir(path + "firmware/ESP32/") + os.mkdir(path + "firmware/ESP32-S2/") + os.mkdir(path + "firmware/ESP32-S3/") sha = os.getenv("SHA",default="sha") versionout = version[:-1] + "_" + sha + "_esp8266.bin" From 3e5fe74b38f2f43170c90a3f6dcf1efcf1214ff3 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 28 Aug 2023 16:42:29 +0200 Subject: [PATCH 039/267] 0.7.44 * fix `last_success` transmitted to often #1124 * fix github action --- scripts/getVersion.py | 1 + src/CHANGES.md | 3 +++ src/defines.h | 2 +- src/publisher/pubMqttIvData.h | 7 +++++-- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/scripts/getVersion.py b/scripts/getVersion.py index cf739710..b6bef458 100644 --- a/scripts/getVersion.py +++ b/scripts/getVersion.py @@ -51,6 +51,7 @@ def readVersion(path, infile): os.mkdir(path + "firmware/") os.mkdir(path + "firmware/ESP8266/") + os.mkdir(path + "firmware/ESP8285/") os.mkdir(path + "firmware/ESP32/") os.mkdir(path + "firmware/ESP32-S2/") os.mkdir(path + "firmware/ESP32-S3/") diff --git a/src/CHANGES.md b/src/CHANGES.md index d3d7ee53..a16a638e 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.7.44 - 2023-08-28 +* fix `last_success` transmitted to often #1124 + ## 0.7.43 - 2023-08-28 * improved RSSI for NRF24, now it's read per package (and inverter) #1129 * arranged `heap` related info together in `/system` diff --git a/src/defines.h b/src/defines.h index 758f355e..ca67f8fb 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 7 -#define VERSION_PATCH 43 +#define VERSION_PATCH 44 //------------------------------------- typedef struct { diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h index 9393733e..8446b4e8 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -28,7 +28,8 @@ class PubMqttIvData { mState = IDLE; mZeroValues = false; - memset(mIvLastRTRpub, 0, MAX_NUM_INVERTERS * 4); + memset(mIvLastRTRpub, 0, MAX_NUM_INVERTERS * sizeof(uint32_t)); + memset(mIvLastPublish, 0, MAX_NUM_INVERTERS * sizeof(uint32_t)); mRTRDataHasBeenSent = false; mTable[IDLE] = &PubMqttIvData::stateIdle; @@ -102,7 +103,7 @@ class PubMqttIvData { mPos = 0; if(found) { record_t<> *rec = mIv->getRecordStruct(mCmd); - if(mIv->getLastTs(rec) != mIvLastRTRpub[mIv->id]) { + if(mIv->getLastTs(rec) != mIvLastPublish[mIv->id]) { snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/last_success", mIv->config->name); snprintf(mVal, 40, "%d", mIv->getLastTs(rec)); mPublish(mSubTopic, mVal, true, QOS_0); @@ -133,6 +134,7 @@ class PubMqttIvData { pubData &= (lastTs != mIvLastRTRpub[mIv->id]); if (pubData) { + mIvLastPublish[mIv->id] = lastTs; if(mPos < rec->length) { bool retained = false; if (mCmd == RealTimeRunData_Debug) { @@ -239,6 +241,7 @@ class PubMqttIvData { Inverter<> *mIv, *mIvSend; uint8_t mPos; uint32_t mIvLastRTRpub[MAX_NUM_INVERTERS]; + uint32_t mIvLastPublish[MAX_NUM_INVERTERS]; bool mRTRDataHasBeenSent; char mSubTopic[32 + MAX_NAME_LENGTH + 1]; From e2f8fcab408049ec1ab641bce687545cd8094d87 Mon Sep 17 00:00:00 2001 From: dAjaY85 Date: Tue, 29 Aug 2023 14:56:10 +0200 Subject: [PATCH 040/267] Symbols instead of Text --- src/plugins/Display/Display_ePaper.cpp | 107 ++++++++++++++++--------- src/plugins/Display/imagedata.h | 41 ++++++++++ 2 files changed, 111 insertions(+), 37 deletions(-) diff --git a/src/plugins/Display/Display_ePaper.cpp b/src/plugins/Display/Display_ePaper.cpp index 8a72a485..2ac0238a 100644 --- a/src/plugins/Display/Display_ePaper.cpp +++ b/src/plugins/Display/Display_ePaper.cpp @@ -1,9 +1,9 @@ #include "Display_ePaper.h" #ifdef ESP8266 - #include +#include #elif defined(ESP32) - #include +#include #endif #include "../../utils/helper.h" #include "imagedata.h" @@ -21,7 +21,6 @@ DisplayEPaper::DisplayEPaper() { mHeadFootPadding = 16; } - //*************************************************************************** void DisplayEPaper::init(uint8_t type, uint8_t _CS, uint8_t _DC, uint8_t _RST, uint8_t _BUSY, uint8_t _SCK, uint8_t _MOSI, uint32_t *utcTs, const char *version) { mUtcTs = utcTs; @@ -154,9 +153,11 @@ void DisplayEPaper::actualPowerPaged(float totalPower, float totalYieldDay, floa _display->setPartialWindow(0, mHeadFootPadding, _display->width(), _display->height() - (mHeadFootPadding * 2)); _display->fillScreen(GxEPD_WHITE); + do { + // actual Production if (totalPower > 9999) { - snprintf(_fmtText, sizeof(_fmtText), "%.1f kW", (totalPower / 10000)); + snprintf(_fmtText, sizeof(_fmtText), "%.1f kW", (totalPower / 1000)); _changed = true; } else if ((totalPower > 0) && (totalPower <= 9999)) { snprintf(_fmtText, sizeof(_fmtText), "%.0f W", totalPower); @@ -164,43 +165,75 @@ void DisplayEPaper::actualPowerPaged(float totalPower, float totalYieldDay, floa } else { snprintf(_fmtText, sizeof(_fmtText), "offline"); } - if (totalPower == 0){ - _display->fillRect(0, mHeadFootPadding, 200,200, GxEPD_BLACK); - _display->drawBitmap(0, 0, logo, 200, 200, GxEPD_WHITE); - } else { - _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); - x = ((_display->width() - tbw) / 2) - tbx; - _display->setCursor(x, mHeadFootPadding + tbh + 10); - _display->print(_fmtText); + _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); + x = ((_display->width() - tbw) / 2) - tbx; + _display->setCursor(x, mHeadFootPadding + tbh + 10); + _display->print(_fmtText); - _display->setFont(&FreeSans12pt7b); + if ((totalYieldDay > 0) && (totalYieldTotal > 0)) { + // Today Production + _display->setFont(&FreeSans18pt7b); y = _display->height() / 2; _display->setCursor(5, y); - _display->print("today:"); - snprintf(_fmtText, _display->width(), "%.0f", totalYieldDay); - _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); - x = ((_display->width() - tbw) / 2) - tbx; - _display->setCursor(x, y); - _display->print(_fmtText); - _display->setCursor(_display->width() - 38, y); - _display->println("Wh"); - y = y + tbh + 7; + if (totalYieldDay > 9999) { + snprintf(_fmtText, _display->width(), "%.1f", (totalYieldDay / 1000)); + _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); + _display->drawInvertedBitmap(5, y - ((tbh + 30) / 2), myToday, 30, 30, GxEPD_BLACK); + x = ((_display->width() - tbw - 20) / 2) - tbx; + _display->setCursor(x, y); + _display->print(_fmtText); + _display->setCursor(_display->width() - 50, y); + _display->setFont(&FreeSans12pt7b); + _display->println("kWh"); + } else if (totalYieldDay <= 9999) { + snprintf(_fmtText, _display->width(), "%.0f", (totalYieldDay)); + _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); + _display->drawInvertedBitmap(5, y - tbh, myToday, 30, 30, GxEPD_BLACK); + x = ((_display->width() - tbw - 20) / 2) - tbx; + _display->setCursor(x, y); + _display->print(_fmtText); + _display->setCursor(_display->width() - 38, y); + _display->setFont(&FreeSans12pt7b); + _display->println("Wh"); + } + y = y + tbh + 15; + + // Total Production + _display->setFont(&FreeSans18pt7b); _display->setCursor(5, y); - _display->print("total:"); - snprintf(_fmtText, _display->width(), "%.1f", totalYieldTotal); - _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); - x = ((_display->width() - tbw) / 2) - tbx; - _display->setCursor(x, y); - _display->print(_fmtText); - _display->setCursor(_display->width() - 50, y); - _display->println("kWh"); - - _display->setCursor(10, _display->height() - (mHeadFootPadding + 10)); - snprintf(_fmtText, sizeof(_fmtText), "%d Inverter online", isprod); - _display->println(_fmtText); - + if (totalYieldTotal > 9999) { + snprintf(_fmtText, _display->width(), "%.1f", (totalYieldTotal / 1000)); + _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); + _display->drawInvertedBitmap(5, y - tbh, mySigma, 30, 30, GxEPD_BLACK); + x = ((_display->width() - tbw - 20) / 2) - tbx; + _display->setCursor(x, y); + _display->print(_fmtText); + _display->setCursor(_display->width() - 59, y); + _display->setFont(&FreeSans12pt7b); + _display->println("MWh"); + } else if (totalYieldTotal <= 9999) { + snprintf(_fmtText, _display->width(), "%.0f", (totalYieldTotal)); + _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); + _display->drawInvertedBitmap(5, y - tbh, mySigma, 30, 30, GxEPD_BLACK); + x = ((_display->width() - tbw - 20) / 2) - tbx; + _display->setCursor(x, y); + _display->print(_fmtText); + _display->setCursor(_display->width() - 50, y); + _display->setFont(&FreeSans12pt7b); + _display->println("kWh"); + } } + + // Inverter online + _display->setFont(&FreeSans12pt7b); + y = _display->height() - (mHeadFootPadding + 10); + snprintf(_fmtText, sizeof(_fmtText), " %d online", isprod); + _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); + _display->drawInvertedBitmap(10, y - tbh, myWR, 20, 20, GxEPD_BLACK); + x = ((_display->width() - tbw - 20) / 2) - tbx; + _display->setCursor(x, y); + _display->println(_fmtText); } while (_display->nextPage()); } //*************************************************************************** @@ -219,10 +252,10 @@ void DisplayEPaper::loop(float totalPower, float totalYieldDay, float totalYield if ((isprod > 0) && (_changed)) { _changed = false; lastUpdatePaged(); - } else if((0 == totalPower) && (mEnPowerSafe)) + } else if ((0 == totalPower) && (mEnPowerSafe)) offlineFooter(); _display->powerOff(); } //*************************************************************************** -#endif // ESP32 +#endif // ESP32 diff --git a/src/plugins/Display/imagedata.h b/src/plugins/Display/imagedata.h index baaddec8..b136193b 100644 --- a/src/plugins/Display/imagedata.h +++ b/src/plugins/Display/imagedata.h @@ -9,6 +9,47 @@ #include #endif +// 'Sigma', 30x30px +const unsigned char mySigma[] PROGMEM = { + 0x80, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xf0, + 0x3f, 0x80, 0x07, 0xf0, 0x3f, 0x80, 0x07, 0xf0, 0x3f, 0x9f, 0xe7, 0xf0, 0x3f, 0xcf, 0xe7, 0xf0, + 0x3f, 0xcf, 0xff, 0xf0, 0x3f, 0xe7, 0xff, 0xf0, 0x3f, 0xe7, 0xff, 0xf0, 0x3f, 0xf3, 0xff, 0xf0, + 0x3f, 0xf3, 0xff, 0xf0, 0x3f, 0xf9, 0xff, 0xf0, 0x3f, 0xf8, 0xff, 0xf0, 0x3f, 0xf8, 0xff, 0xf0, + 0x3f, 0xf9, 0xff, 0xf0, 0x3f, 0xf3, 0xff, 0xf0, 0x3f, 0xf3, 0xff, 0xf0, 0x3f, 0xe7, 0xff, 0xf0, + 0x3f, 0xe7, 0xff, 0xf0, 0x3f, 0xcf, 0xff, 0xf0, 0x3f, 0xcf, 0xe7, 0xf0, 0x3f, 0x9f, 0xe7, 0xf0, + 0x3f, 0x80, 0x07, 0xf0, 0x3f, 0x80, 0x07, 0xf0, 0x3f, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x04 +}; +// 'Sun', 30x30px +const unsigned char mySun[] PROGMEM = { + 0x80, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xfb, 0xf0, + 0x3f, 0xfc, 0xfb, 0xf0, 0x3f, 0xfc, 0xfb, 0xf0, 0x3e, 0xfc, 0xf3, 0xf0, 0x3c, 0x7c, 0xf3, 0xf0, + 0x3e, 0x30, 0x33, 0xf0, 0x3f, 0x0f, 0xcb, 0xf0, 0x3f, 0x9f, 0xeb, 0xf0, 0x3f, 0xbf, 0xeb, 0xf0, + 0x3f, 0x7f, 0xd8, 0x30, 0x3f, 0x7f, 0xdf, 0xb0, 0x30, 0x7f, 0xdf, 0xb0, 0x30, 0x7f, 0xbf, 0x70, + 0x3f, 0x7f, 0xbf, 0x70, 0x3f, 0x7f, 0x83, 0x70, 0x3f, 0xbf, 0xf2, 0xf0, 0x3f, 0x9f, 0xe2, 0xf0, + 0x3f, 0x0f, 0xca, 0xf0, 0x3e, 0x30, 0x39, 0xf0, 0x3c, 0x7c, 0xf9, 0xf0, 0x3e, 0xfc, 0xf9, 0xf0, + 0x3f, 0xfc, 0xfb, 0xf0, 0x3f, 0xfc, 0xfb, 0xf0, 0x3f, 0xff, 0xfb, 0xf0, 0x3f, 0xff, 0xff, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x04 +}; +// 'Today', 30x30px +const unsigned char myToday[] PROGMEM = { + 0xf3, 0xff, 0xff, 0x3c, 0xf3, 0xff, 0xff, 0x3c, 0x80, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x33, 0xff, 0xff, 0x30, 0x33, 0xff, 0xff, 0x30, 0x3f, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xf0, + 0x3f, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xfc, 0xf0, 0x3f, 0xff, 0xf8, 0xf0, 0x3f, 0xff, 0xf1, 0xf0, + 0x3f, 0xff, 0xe3, 0xf0, 0x3f, 0xff, 0xc7, 0xf0, 0x3f, 0xff, 0x8f, 0xf0, 0x3f, 0xff, 0x1f, 0xf0, + 0x3f, 0xfe, 0x3f, 0xf0, 0x3e, 0x7c, 0x7f, 0xf0, 0x3e, 0x38, 0xff, 0xf0, 0x3f, 0x11, 0xff, 0xf0, + 0x3f, 0x83, 0xff, 0xf0, 0x3f, 0xc7, 0xff, 0xf0, 0x3f, 0xef, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x04 +}; +// 'WR', 20x20px +const unsigned char myWR[] PROGMEM = { + 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3f, 0xff, 0x80, 0x3f, 0xff, 0x40, 0x30, 0x7e, 0xc0, 0x3f, + 0xfd, 0xc0, 0x30, 0x7b, 0xc0, 0x3f, 0xf7, 0xc0, 0x3f, 0xef, 0xc0, 0x3f, 0xdf, 0xc0, 0x3f, 0xbf, + 0xc0, 0x3f, 0x7f, 0xc0, 0x3e, 0xff, 0xc0, 0x3d, 0xf7, 0xc0, 0x3b, 0xea, 0xc0, 0x37, 0xfd, 0xc0, + 0x2f, 0xff, 0xc0, 0x1f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10 +}; + // 'Logo', 200x200px const unsigned char logo[] PROGMEM = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, From b12effd59ed30c0dee46d40585d0c3fe519f8db7 Mon Sep 17 00:00:00 2001 From: dAjaY85 Date: Tue, 29 Aug 2023 15:28:28 +0200 Subject: [PATCH 041/267] bug fixes --- src/plugins/Display/Display_ePaper.cpp | 140 +++++++++++++------------ 1 file changed, 73 insertions(+), 67 deletions(-) diff --git a/src/plugins/Display/Display_ePaper.cpp b/src/plugins/Display/Display_ePaper.cpp index 2ac0238a..b24bbd07 100644 --- a/src/plugins/Display/Display_ePaper.cpp +++ b/src/plugins/Display/Display_ePaper.cpp @@ -165,75 +165,81 @@ void DisplayEPaper::actualPowerPaged(float totalPower, float totalYieldDay, floa } else { snprintf(_fmtText, sizeof(_fmtText), "offline"); } - _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); - x = ((_display->width() - tbw) / 2) - tbx; - _display->setCursor(x, mHeadFootPadding + tbh + 10); - _display->print(_fmtText); - - if ((totalYieldDay > 0) && (totalYieldTotal > 0)) { - // Today Production - _display->setFont(&FreeSans18pt7b); - y = _display->height() / 2; - _display->setCursor(5, y); - - if (totalYieldDay > 9999) { - snprintf(_fmtText, _display->width(), "%.1f", (totalYieldDay / 1000)); - _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); - _display->drawInvertedBitmap(5, y - ((tbh + 30) / 2), myToday, 30, 30, GxEPD_BLACK); - x = ((_display->width() - tbw - 20) / 2) - tbx; - _display->setCursor(x, y); - _display->print(_fmtText); - _display->setCursor(_display->width() - 50, y); - _display->setFont(&FreeSans12pt7b); - _display->println("kWh"); - } else if (totalYieldDay <= 9999) { - snprintf(_fmtText, _display->width(), "%.0f", (totalYieldDay)); - _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); - _display->drawInvertedBitmap(5, y - tbh, myToday, 30, 30, GxEPD_BLACK); - x = ((_display->width() - tbw - 20) / 2) - tbx; - _display->setCursor(x, y); - _display->print(_fmtText); - _display->setCursor(_display->width() - 38, y); - _display->setFont(&FreeSans12pt7b); - _display->println("Wh"); - } - y = y + tbh + 15; - - // Total Production - _display->setFont(&FreeSans18pt7b); - _display->setCursor(5, y); - if (totalYieldTotal > 9999) { - snprintf(_fmtText, _display->width(), "%.1f", (totalYieldTotal / 1000)); - _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); - _display->drawInvertedBitmap(5, y - tbh, mySigma, 30, 30, GxEPD_BLACK); - x = ((_display->width() - tbw - 20) / 2) - tbx; - _display->setCursor(x, y); - _display->print(_fmtText); - _display->setCursor(_display->width() - 59, y); - _display->setFont(&FreeSans12pt7b); - _display->println("MWh"); - } else if (totalYieldTotal <= 9999) { - snprintf(_fmtText, _display->width(), "%.0f", (totalYieldTotal)); - _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); - _display->drawInvertedBitmap(5, y - tbh, mySigma, 30, 30, GxEPD_BLACK); - x = ((_display->width() - tbw - 20) / 2) - tbx; - _display->setCursor(x, y); - _display->print(_fmtText); - _display->setCursor(_display->width() - 50, y); - _display->setFont(&FreeSans12pt7b); - _display->println("kWh"); + + if ((totalPower == 0) && (mEnPowerSafe)) { + _display->fillRect(0, mHeadFootPadding, 200, 200, GxEPD_BLACK); + _display->drawBitmap(0, 0, logo, 200, 200, GxEPD_WHITE); + } else { + _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); + x = ((_display->width() - tbw) / 2) - tbx; + _display->setCursor(x, mHeadFootPadding + tbh + 10); + _display->print(_fmtText); + + if ((totalYieldDay > 0) && (totalYieldTotal > 0)) { + // Today Production + _display->setFont(&FreeSans18pt7b); + y = _display->height() / 2; + _display->setCursor(5, y); + + if (totalYieldDay > 9999) { + snprintf(_fmtText, _display->width(), "%.1f", (totalYieldDay / 1000)); + _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); + _display->drawInvertedBitmap(5, y - ((tbh + 30) / 2), myToday, 30, 30, GxEPD_BLACK); + x = ((_display->width() - tbw - 20) / 2) - tbx; + _display->setCursor(x, y); + _display->print(_fmtText); + _display->setCursor(_display->width() - 50, y); + _display->setFont(&FreeSans12pt7b); + _display->println("kWh"); + } else if (totalYieldDay <= 9999) { + snprintf(_fmtText, _display->width(), "%.0f", (totalYieldDay)); + _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); + _display->drawInvertedBitmap(5, y - tbh, myToday, 30, 30, GxEPD_BLACK); + x = ((_display->width() - tbw - 20) / 2) - tbx; + _display->setCursor(x, y); + _display->print(_fmtText); + _display->setCursor(_display->width() - 38, y); + _display->setFont(&FreeSans12pt7b); + _display->println("Wh"); + } + y = y + tbh + 15; + + // Total Production + _display->setFont(&FreeSans18pt7b); + _display->setCursor(5, y); + if (totalYieldTotal > 9999) { + snprintf(_fmtText, _display->width(), "%.1f", (totalYieldTotal / 1000)); + _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); + _display->drawInvertedBitmap(5, y - tbh, mySigma, 30, 30, GxEPD_BLACK); + x = ((_display->width() - tbw - 20) / 2) - tbx; + _display->setCursor(x, y); + _display->print(_fmtText); + _display->setCursor(_display->width() - 59, y); + _display->setFont(&FreeSans12pt7b); + _display->println("MWh"); + } else if (totalYieldTotal <= 9999) { + snprintf(_fmtText, _display->width(), "%.0f", (totalYieldTotal)); + _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); + _display->drawInvertedBitmap(5, y - tbh, mySigma, 30, 30, GxEPD_BLACK); + x = ((_display->width() - tbw - 20) / 2) - tbx; + _display->setCursor(x, y); + _display->print(_fmtText); + _display->setCursor(_display->width() - 50, y); + _display->setFont(&FreeSans12pt7b); + _display->println("kWh"); + } } - } - // Inverter online - _display->setFont(&FreeSans12pt7b); - y = _display->height() - (mHeadFootPadding + 10); - snprintf(_fmtText, sizeof(_fmtText), " %d online", isprod); - _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); - _display->drawInvertedBitmap(10, y - tbh, myWR, 20, 20, GxEPD_BLACK); - x = ((_display->width() - tbw - 20) / 2) - tbx; - _display->setCursor(x, y); - _display->println(_fmtText); + // Inverter online + _display->setFont(&FreeSans12pt7b); + y = _display->height() - (mHeadFootPadding + 10); + snprintf(_fmtText, sizeof(_fmtText), " %d online", isprod); + _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); + _display->drawInvertedBitmap(10, y - tbh, myWR, 20, 20, GxEPD_BLACK); + x = ((_display->width() - tbw - 20) / 2) - tbx; + _display->setCursor(x, y); + _display->println(_fmtText); + } } while (_display->nextPage()); } //*************************************************************************** From 4ef38f126618f75a02e278d51dc36a46f39dcf45 Mon Sep 17 00:00:00 2001 From: dAjaY85 Date: Tue, 29 Aug 2023 22:01:56 +0200 Subject: [PATCH 042/267] Integration VersionNr durring startup --- src/plugins/Display/Display_ePaper.cpp | 23 +++++++++++++++ src/plugins/Display/Display_ePaper.h | 41 +++++++++++++------------- 2 files changed, 44 insertions(+), 20 deletions(-) diff --git a/src/plugins/Display/Display_ePaper.cpp b/src/plugins/Display/Display_ePaper.cpp index b24bbd07..c2f93938 100644 --- a/src/plugins/Display/Display_ePaper.cpp +++ b/src/plugins/Display/Display_ePaper.cpp @@ -53,6 +53,9 @@ void DisplayEPaper::init(uint8_t type, uint8_t _CS, uint8_t _DC, uint8_t _RST, u headlineIP(); + _version = version; + versionFooter(); + // call the PowerPage to change the PV Power Values actualPowerPaged(0, 0, 0, 0); } @@ -122,6 +125,26 @@ void DisplayEPaper::lastUpdatePaged() { } while (_display->nextPage()); } //*************************************************************************** +void DisplayEPaper::versionFooter() { + int16_t tbx, tby; + uint16_t tbw, tbh; + + _display->setFont(&FreeSans9pt7b); + _display->setTextColor(GxEPD_WHITE); + + _display->setPartialWindow(0, _display->height() - mHeadFootPadding, _display->width(), mHeadFootPadding); + _display->fillScreen(GxEPD_BLACK); + do { + snprintf(_fmtText, sizeof(_fmtText), "Version: %s", _version); + + _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); + uint16_t x = ((_display->width() - tbw) / 2) - tbx; + + _display->setCursor(x, (_display->height() - 3)); + _display->println(_fmtText); + } while (_display->nextPage()); +} +//*************************************************************************** void DisplayEPaper::offlineFooter() { int16_t tbx, tby; uint16_t tbw, tbh; diff --git a/src/plugins/Display/Display_ePaper.h b/src/plugins/Display/Display_ePaper.h index d9b24e34..65c5b91a 100644 --- a/src/plugins/Display/Display_ePaper.h +++ b/src/plugins/Display/Display_ePaper.h @@ -25,27 +25,28 @@ class DisplayEPaper { public: - DisplayEPaper(); - void fullRefresh(); - void init(uint8_t type, uint8_t _CS, uint8_t _DC, uint8_t _RST, uint8_t _BUSY, uint8_t _SCK, uint8_t _MOSI, uint32_t *utcTs, const char* version); - void config(uint8_t rotation, bool enPowerSafe); - void loop(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod); - + DisplayEPaper(); + void fullRefresh(); + void init(uint8_t type, uint8_t _CS, uint8_t _DC, uint8_t _RST, uint8_t _BUSY, uint8_t _SCK, uint8_t _MOSI, uint32_t* utcTs, const char* version); + void config(uint8_t rotation, bool enPowerSafe); + void loop(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod); private: - void headlineIP(); - void actualPowerPaged(float _totalPower, float _totalYieldDay, float _totalYieldTotal, uint8_t _isprod); - void lastUpdatePaged(); - void offlineFooter(); - - uint8_t mDisplayRotation; - bool _changed = false; - char _fmtText[35]; - const char* _settedIP; - uint8_t mHeadFootPadding; - GxEPD2_GFX* _display; - uint32_t *mUtcTs; - bool mEnPowerSafe; + void headlineIP(); + void actualPowerPaged(float _totalPower, float _totalYieldDay, float _totalYieldTotal, uint8_t _isprod); + void lastUpdatePaged(); + void offlineFooter(); + void versionFooter(); + + uint8_t mDisplayRotation; + bool _changed = false; + char _fmtText[35]; + const char* _settedIP; + uint8_t mHeadFootPadding; + GxEPD2_GFX* _display; + uint32_t* mUtcTs; + bool mEnPowerSafe; + const char* _version; }; -#endif // ESP32 +#endif // ESP32 From 201098ae0bc1874c5b4a81a1187d0a1b840aca12 Mon Sep 17 00:00:00 2001 From: lumapu Date: Wed, 30 Aug 2023 00:06:32 +0200 Subject: [PATCH 043/267] 0.7.45 * change ePaper text to symbols PR #1131 * added some invertes to dev info list #1111 --- src/CHANGES.md | 4 +++ src/defines.h | 2 +- src/hm/hmDefines.h | 47 +++++++++++++++++++++++----- src/plugins/Display/Display_ePaper.h | 46 +++++++++++++-------------- 4 files changed, 68 insertions(+), 31 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index a16a638e..974c7282 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,9 @@ # Development Changes +## 0.7.45 - 2023-08-29 +* change ePaper text to symbols PR #1131 +* added some invertes to dev info list #1111 + ## 0.7.44 - 2023-08-28 * fix `last_success` transmitted to often #1124 diff --git a/src/defines.h b/src/defines.h index ca67f8fb..8a125bfa 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 7 -#define VERSION_PATCH 44 +#define VERSION_PATCH 45 //------------------------------------- typedef struct { diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index 7b1549ab..87d47699 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -25,7 +25,7 @@ enum {FLD_UDC = 0, FLD_IDC, FLD_PDC, FLD_YD, FLD_YW, FLD_YT, FLD_FW_BUILD_MONTH_DAY, FLD_FW_BUILD_HOUR_MINUTE, FLD_BOOTLOADER_VER, FLD_ACT_ACTIVE_PWR_LIMIT, FLD_PART_NUM, FLD_HW_VERSION, FLD_GRID_PROFILE_CODE, FLD_GRID_PROFILE_VERSION, /*FLD_ACT_REACTIVE_PWR_LIMIT, FLD_ACT_PF,*/ FLD_LAST_ALARM_CODE, FLD_MP}; - + const char* const fields[] = {"U_DC", "I_DC", "P_DC", "YieldDay", "YieldWeek", "YieldTotal", "U_AC", "U_AC_1N", "U_AC_2N", "U_AC_3N", "UAC_12", "UAC_23", "UAC_31", "I_AC", "IAC_1", "I_AC_2", "I_AC_3", "P_AC", "F_AC", "Temp", "PF_AC", "Efficiency", "Irradiation","Q_AC", @@ -259,20 +259,52 @@ typedef struct { uint16_t maxPower; } devInfo_t; +// https://github.com/lumapu/ahoy/issues/1111 +// Hardware number: +// 0xAABBCCDD +// ^^ ------- always 10 (for MI, HM, HMS, HMT) +// ^ ------ 0 = MI +// 1 = HM +// 1, 2 = HMS (version) +// 3 = HMT +// ^ ----- 0 = 1 Input +// 1 = 2 Inputs +// 2 = 4 Inputs +// 3 = 6 Inputs +// ^ ---- 0 = smallest with x inputs +// 7 = biggest with x inputs + const devInfo_t devInfo[] = { // MI 3rd gen + { 0x001311, 600 }, + { 0x001411, 700 }, + { 0x002111, 1000 }, + { 0x002311, 1200 }, + { 0x002411, 1500 }, + { 0x002511, 1500 }, + + { 0x100000, 250 }, + { 0x100010, 300 }, + { 0x100020, 350 }, + { 0x100030, 400 }, + { 0x100100, 500 }, + { 0x100110, 600 }, + { 0x100120, 700 }, + { 0x100130, 800 }, + { 0x100200, 1000 }, + { 0x100210, 1200 }, { 0x100230, 1500 }, // HM { 0x101010, 300 }, { 0x101020, 350 }, { 0x101030, 400 }, - { 0x101040, 400 }, - { 0x101110, 600 }, // [TSOL800(DE) ..20, HWv=??], [HM-600 ..20, HWv=2.66] + { 0x101110, 600 }, // [TSOL800(DE) ..20, HWv=2.66], [HM-600 ..20, HWv=2.66] { 0x101120, 700 }, { 0x101130, 800 }, { 0x101140, 800 }, - { 0x101210, 1200 }, // ..00 + { 0x101200, 1000 }, + { 0x101210, 1200 }, { 0x101230, 1500 }, // HMS @@ -281,18 +313,19 @@ const devInfo_t devInfo[] = { { 0x101051, 450 }, { 0x101071, 500 }, { 0x102111, 600 }, + { 0x101120, 700 }, { 0x102141, 800 }, { 0x101151, 900 }, { 0x102171, 1000 }, { 0x102241, 1600 }, { 0x101251, 1800 }, { 0x102251, 1800 }, - { 0x101271, 2000 }, // ..00 - { 0x102271, 2000 }, + { 0x101271, 2000 }, // v1 grey backplane, 14A + { 0x102271, 2000 }, // v2 black backplane, 16A // HMT { 0x103311, 1800 }, - { 0x103331, 2250 } // ..00 + { 0x103331, 2250 } }; #endif /*__HM_DEFINES_H__*/ diff --git a/src/plugins/Display/Display_ePaper.h b/src/plugins/Display/Display_ePaper.h index 65c5b91a..e89c191b 100644 --- a/src/plugins/Display/Display_ePaper.h +++ b/src/plugins/Display/Display_ePaper.h @@ -24,29 +24,29 @@ // GDEH0154D67 1.54" b/w 200x200 class DisplayEPaper { - public: - DisplayEPaper(); - void fullRefresh(); - void init(uint8_t type, uint8_t _CS, uint8_t _DC, uint8_t _RST, uint8_t _BUSY, uint8_t _SCK, uint8_t _MOSI, uint32_t* utcTs, const char* version); - void config(uint8_t rotation, bool enPowerSafe); - void loop(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod); - - private: - void headlineIP(); - void actualPowerPaged(float _totalPower, float _totalYieldDay, float _totalYieldTotal, uint8_t _isprod); - void lastUpdatePaged(); - void offlineFooter(); - void versionFooter(); - - uint8_t mDisplayRotation; - bool _changed = false; - char _fmtText[35]; - const char* _settedIP; - uint8_t mHeadFootPadding; - GxEPD2_GFX* _display; - uint32_t* mUtcTs; - bool mEnPowerSafe; - const char* _version; + public: + DisplayEPaper(); + void fullRefresh(); + void init(uint8_t type, uint8_t _CS, uint8_t _DC, uint8_t _RST, uint8_t _BUSY, uint8_t _SCK, uint8_t _MOSI, uint32_t* utcTs, const char* version); + void config(uint8_t rotation, bool enPowerSafe); + void loop(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod); + + private: + void headlineIP(); + void actualPowerPaged(float _totalPower, float _totalYieldDay, float _totalYieldTotal, uint8_t _isprod); + void lastUpdatePaged(); + void offlineFooter(); + void versionFooter(); + + uint8_t mDisplayRotation; + bool _changed = false; + char _fmtText[35]; + const char* _settedIP; + uint8_t mHeadFootPadding; + GxEPD2_GFX* _display; + uint32_t* mUtcTs; + bool mEnPowerSafe; + const char* _version; }; #endif // ESP32 From c0bb7403f365d58a28230f3d6423138e7ce67590 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Wed, 30 Aug 2023 14:48:40 +0200 Subject: [PATCH 044/267] MI - add model codes thx to beegee3 in https://github.com/lumapu/ahoy/issues/1111#issuecomment-1698100571 Only MI-600 (0x001311) is tested! --- src/hm/hmDefines.h | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index edf1fc99..cef64fc1 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -260,9 +260,20 @@ typedef struct { } devInfo_t; const devInfo_t devInfo[] = { - // MI 2nd gen - { 0x13118f, 600 }, - + // MI 2nd gen; only 0x001311 is tested, + // others (starting with MI-250) according to https://github.com/lumapu/ahoy/issues/1111#issuecomment-1698100571 + { 0x000111, 250 }, + { 0x000311, 300 }, + { 0x000411, 350 }, + { 0x001111, 500 }, + { 0x001311, 600 }, + { 0x001321, 600 }, + { 0x001421, 700 }, + { 0x001411, 700 }, + { 0x002111, 1000 }, + { 0x002311, 1200 }, + { 0x002511, 1500 }, + { 0x002411, 1500 }, // MI 3rd gen { 0x100230, 1500 }, From 63a74eb02b30b9f9bacd751fc92bc07afcc566ea Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Wed, 30 Aug 2023 15:04:19 +0200 Subject: [PATCH 045/267] Typo in miPayload.h --- 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 a438c346..7909f016 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -737,7 +737,7 @@ const byteAssign_t InfoAssignment[] = { uint8_t txCmd = mPayload[id].txCmd; if(!*complete) { - DPRINTLN(DBG_VERBOSE, F("incomlete, txCmd is 0x") + String(txCmd, HEX)); + DPRINTLN(DBG_VERBOSE, F("incomplete, txCmd is 0x") + String(txCmd, HEX)); //DBGHEXLN(txCmd); if (txCmd == 0x09 || txCmd == 0x11 || (txCmd >= 0x36 && txCmd <= 0x39)) return false; From b0590b6ea73c097c418467227fc174aafdc3e846 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Wed, 30 Aug 2023 20:02:07 +0200 Subject: [PATCH 046/267] MI models - cleanup delete unintented duplicates --- src/hm/hmDefines.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index a04d7d68..71a61db5 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -291,13 +291,6 @@ const devInfo_t devInfo[] = { { 0x002411, 1500 }, // MI 3rd gen - { 0x001311, 600 }, - { 0x001411, 700 }, - { 0x002111, 1000 }, - { 0x002311, 1200 }, - { 0x002411, 1500 }, - { 0x002511, 1500 }, - { 0x100000, 250 }, { 0x100010, 300 }, { 0x100020, 350 }, From f3192b49ab82e3b9863749c3805d85e33c27234d Mon Sep 17 00:00:00 2001 From: lumapu Date: Fri, 1 Sep 2023 07:58:33 +0200 Subject: [PATCH 047/267] 0.7.46 * removed `delay` from ePaper * started improvements of `/system` * fix LEDs to check all configured inverters --- src/CHANGES.md | 5 + src/app.cpp | 26 ++-- src/app.h | 1 + src/hm/miPayload.h | 4 +- src/hms/hmsRadio.h | 16 ++- src/platformio.ini | 6 +- src/plugins/Display/Display.h | 8 +- src/plugins/Display/Display_Mono_64X48.h | 2 +- src/plugins/Display/Display_Mono_84X48.h | 2 +- src/plugins/Display/Display_ePaper.cpp | 166 +++++++++++++---------- src/plugins/Display/Display_ePaper.h | 15 +- src/web/RestApi.h | 2 +- src/web/html/colorBright.css | 1 + src/web/html/colorDark.css | 1 + src/web/html/style.css | 29 +++- src/web/html/system.html | 58 +++++--- 16 files changed, 218 insertions(+), 124 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 974c7282..c81162ad 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,10 @@ # Development Changes +## 0.7.46 - 2023-09-01 +* removed `delay` from ePaper +* started improvements of `/system` +* fix LEDs to check all configured inverters + ## 0.7.45 - 2023-08-29 * change ePaper text to symbols PR #1131 * added some invertes to dev info list #1111 diff --git a/src/app.cpp b/src/app.cpp index 25a849ee..15fc432c 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -567,11 +567,11 @@ void app::mqttSubRxCb(JsonObject obj) { void app::setupLed(void) { uint8_t led_off = (mConfig->led.led_high_active) ? LOW : HIGH; - if (mConfig->led.led0 != 0xff) { + if (mConfig->led.led0 != DEF_PIN_OFF) { pinMode(mConfig->led.led0, OUTPUT); digitalWrite(mConfig->led.led0, led_off); } - if (mConfig->led.led1 != 0xff) { + if (mConfig->led.led1 != DEF_PIN_OFF) { pinMode(mConfig->led.led1, OUTPUT); digitalWrite(mConfig->led.led1, led_off); } @@ -582,17 +582,23 @@ void app::updateLed(void) { uint8_t led_off = (mConfig->led.led_high_active) ? LOW : HIGH; uint8_t led_on = (mConfig->led.led_high_active) ? HIGH : LOW; - if (mConfig->led.led0 != 0xff) { - Inverter<> *iv = mSys.getInverterByPos(0); - if (NULL != iv) { - if (iv->isProducing()) - digitalWrite(mConfig->led.led0, led_on); - else - digitalWrite(mConfig->led.led0, led_off); + if (mConfig->led.led0 != DEF_PIN_OFF) { + Inverter<> *iv; + for (uint8_t id = 0; id < mSys.getNumInverters(); id++) { + iv = mSys.getInverterByPos(id); + if (NULL != iv) { + if (iv->isProducing()) { + // turn on when at least one inverter is producing + digitalWrite(mConfig->led.led0, led_on); + break; + } + else if(iv->config->enabled) + digitalWrite(mConfig->led.led0, led_off); + } } } - if (mConfig->led.led1 != 0xff) { + if (mConfig->led.led1 != DEF_PIN_OFF) { if (getMqttIsConnected()) { digitalWrite(mConfig->led.led1, led_on); } else { diff --git a/src/app.h b/src/app.h index fb3da7f6..5a7831c1 100644 --- a/src/app.h +++ b/src/app.h @@ -273,6 +273,7 @@ class app : public IApp, public ah::Scheduler { #endif if(mConfig->plugin.display.type != 0) mDisplay.payloadEventListener(cmd); + updateLed(); } void mqttSubRxCb(JsonObject obj); diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index e461a8dc..5619b1d6 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -728,8 +728,8 @@ const byteAssign_t InfoAssignment[] = { */ void reset(uint8_t id, bool clrSts = false) { - DPRINT_IVID(DBG_INFO, id); - DBGPRINTLN(F("resetPayload")); + //DPRINT_IVID(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/hms/hmsRadio.h b/src/hms/hmsRadio.h index dc79afcb..c515ae0e 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -25,7 +25,8 @@ class CmtRadio { typedef Cmt2300a CmtType; public: CmtRadio() { - mDtuSn = DTU_SN; + mDtuSn = DTU_SN; + mCmtAvail = false; } void setup(uint8_t pinCsb, uint8_t pinFcsb, bool genDtuSn = true) { @@ -63,6 +64,10 @@ class CmtRadio { mSerialDebug = true; } + bool cmtIsAvail() { + return mCmtAvail; + } + void sendControlPacket(const uint64_t *ivId, uint8_t cmd, uint16_t *data, bool isRetransmit) { DPRINT(DBG_INFO, F("sendControlPacket cmd: 0x")); DBGHEXLN(cmd); @@ -143,10 +148,14 @@ class CmtRadio { inline void reset(bool genDtuSn) { if(genDtuSn) generateDtuSn(); - if(!mCmt.reset()) + if(!mCmt.reset()) { + mCmtAvail = false; DPRINTLN(DBG_WARN, F("Initializing CMT2300A failed!")); - else + } + else { + mCmtAvail = true; mCmt.goRx(); + } mSendCnt = 0; mRetransmits = 0; @@ -208,6 +217,7 @@ class CmtRadio { bool mSerialDebug; bool mIrqRcvd; bool mRqstGetRx; + bool mCmtAvail; }; #endif /*__HMS_RADIO_H__*/ diff --git a/src/platformio.ini b/src/platformio.ini index 1e61dda1..42c1557a 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -127,8 +127,6 @@ monitor_filters = platform = espressif32@6.3.2 board = esp32-s3-devkitc-1 upload_protocol = esp-builtin -debug_tool = esp-builtin -debug_speed = 12000 build_flags = ${env.build_flags} -DDEF_NRF_CS_PIN=37 -DDEF_NRF_CE_PIN=38 @@ -142,5 +140,7 @@ build_flags = ${env.build_flags} -DDEF_LED0=18 -DDEF_LED1=17 -DLED_ACTIVE_HIGH + -DARDUINO_USB_MODE=1 + -DARDUINO_USB_CDC_ON_BOOT=1 monitor_filters = - esp32_exception_decoder + esp32_exception_decoder, colorize diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index 2340fd42..584d1c84 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -61,11 +61,14 @@ class Display { if (mMono != NULL) mMono->loop(); - if (mNewPayload || ((++mLoopCnt % 10) == 0)) { + if (mNewPayload || (((++mLoopCnt) % 30) == 0)) { mNewPayload = false; mLoopCnt = 0; DataScreen(); } + #if defined(ESP32) + mEpaper.tickerSecond(); + #endif } private: @@ -102,13 +105,10 @@ class Display { } #if defined(ESP32) else if (mCfg->type == 10) { - mEpaper.loop(totalPower, totalYieldDay, totalYieldTotal, isprod); mRefreshCycle++; } -#endif -#if defined(ESP32) if (mRefreshCycle > 480) { mEpaper.fullRefresh(); mRefreshCycle = 0; diff --git a/src/plugins/Display/Display_Mono_64X48.h b/src/plugins/Display/Display_Mono_64X48.h index 8c355322..67b38e44 100644 --- a/src/plugins/Display/Display_Mono_64X48.h +++ b/src/plugins/Display/Display_Mono_64X48.h @@ -50,7 +50,7 @@ class DisplayMono64X48 : public DisplayMono { void loop(void) { if (mEnPowerSafe) { if (mTimeout != 0) - mTimeout--; + mTimeout--; } } diff --git a/src/plugins/Display/Display_Mono_84X48.h b/src/plugins/Display/Display_Mono_84X48.h index aefe1372..9f7761dc 100644 --- a/src/plugins/Display/Display_Mono_84X48.h +++ b/src/plugins/Display/Display_Mono_84X48.h @@ -50,7 +50,7 @@ class DisplayMono84X48 : public DisplayMono { void loop(void) { if (mEnPowerSafe) { if (mTimeout != 0) - mTimeout--; + mTimeout--; } } diff --git a/src/plugins/Display/Display_ePaper.cpp b/src/plugins/Display/Display_ePaper.cpp index c2f93938..9a4b594c 100644 --- a/src/plugins/Display/Display_ePaper.cpp +++ b/src/plugins/Display/Display_ePaper.cpp @@ -21,10 +21,14 @@ DisplayEPaper::DisplayEPaper() { mHeadFootPadding = 16; } + //*************************************************************************** void DisplayEPaper::init(uint8_t type, uint8_t _CS, uint8_t _DC, uint8_t _RST, uint8_t _BUSY, uint8_t _SCK, uint8_t _MOSI, uint32_t *utcTs, const char *version) { mUtcTs = utcTs; + mRefreshState = RefreshStatus::LOGO; + mSecondCnt = 0; + if (type == 10) { Serial.begin(115200); _display = new GxEPD2_BW(GxEPD2_150_BN(_CS, _DC, _RST, _BUSY)); @@ -38,26 +42,7 @@ void DisplayEPaper::init(uint8_t type, uint8_t _CS, uint8_t _DC, uint8_t _RST, u _display->init(115200, true, 20, false); _display->setRotation(mDisplayRotation); _display->setFullWindow(); - - // Logo - _display->fillScreen(GxEPD_BLACK); - _display->drawBitmap(0, 0, logo, 200, 200, GxEPD_WHITE); - while (_display->nextPage()) - ; - - // clean the screen - delay(2000); - _display->fillScreen(GxEPD_WHITE); - while (_display->nextPage()) - ; - - headlineIP(); - _version = version; - versionFooter(); - - // call the PowerPage to change the PV Power Values - actualPowerPaged(0, 0, 0, 0); } } @@ -68,15 +53,51 @@ void DisplayEPaper::config(uint8_t rotation, bool enPowerSafe) { //*************************************************************************** void DisplayEPaper::fullRefresh() { - // screen complete black - _display->fillScreen(GxEPD_BLACK); - while (_display->nextPage()) - ; - delay(2000); - // screen complete white - _display->fillScreen(GxEPD_WHITE); - while (_display->nextPage()) - ; + if(RefreshStatus::DONE != mRefreshState) + return; + mSecondCnt = 2; + mRefreshState = RefreshStatus::BLACK; +} + +//*************************************************************************** +void DisplayEPaper::refreshLoop() { + switch(mRefreshState) { + case RefreshStatus::LOGO: + _display->fillScreen(GxEPD_BLACK); + _display->drawBitmap(0, 0, logo, 200, 200, GxEPD_WHITE); + mNextRefreshState = RefreshStatus::PARTITIALS; + mRefreshState = RefreshStatus::WAIT; + break; + + case RefreshStatus::BLACK: + _display->fillScreen(GxEPD_BLACK); + mNextRefreshState = RefreshStatus::WHITE; + mRefreshState = RefreshStatus::WAIT; + break; + + case RefreshStatus::WHITE: + if(mSecondCnt == 0) { + _display->fillScreen(GxEPD_WHITE); + mNextRefreshState = RefreshStatus::PARTITIALS; + mRefreshState = RefreshStatus::WAIT; + } + break; + + case RefreshStatus::WAIT: + if(!_display->nextPage()) + mRefreshState = mNextRefreshState; + break; + + case RefreshStatus::PARTITIALS: + headlineIP(); + versionFooter(); + mSecondCnt = 4; // display Logo time during boot up + mRefreshState = RefreshStatus::DONE; + break; + + default: // RefreshStatus::DONE + break; + } } //*************************************************************************** void DisplayEPaper::headlineIP() { @@ -185,9 +206,8 @@ void DisplayEPaper::actualPowerPaged(float totalPower, float totalYieldDay, floa } else if ((totalPower > 0) && (totalPower <= 9999)) { snprintf(_fmtText, sizeof(_fmtText), "%.0f W", totalPower); _changed = true; - } else { + } else snprintf(_fmtText, sizeof(_fmtText), "offline"); - } if ((totalPower == 0) && (mEnPowerSafe)) { _display->fillRect(0, mHeadFootPadding, 200, 200, GxEPD_BLACK); @@ -200,57 +220,43 @@ void DisplayEPaper::actualPowerPaged(float totalPower, float totalYieldDay, floa if ((totalYieldDay > 0) && (totalYieldTotal > 0)) { // Today Production + bool kwh = (totalYieldDay > 9999); + if(kwh) + snprintf(_fmtText, _display->width(), "%.1f", (totalYieldDay / 1000)); + else + snprintf(_fmtText, _display->width(), "%.0f", (totalYieldDay)); + _display->setFont(&FreeSans18pt7b); y = _display->height() / 2; _display->setCursor(5, y); - - if (totalYieldDay > 9999) { - snprintf(_fmtText, _display->width(), "%.1f", (totalYieldDay / 1000)); - _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); - _display->drawInvertedBitmap(5, y - ((tbh + 30) / 2), myToday, 30, 30, GxEPD_BLACK); - x = ((_display->width() - tbw - 20) / 2) - tbx; - _display->setCursor(x, y); - _display->print(_fmtText); - _display->setCursor(_display->width() - 50, y); - _display->setFont(&FreeSans12pt7b); - _display->println("kWh"); - } else if (totalYieldDay <= 9999) { - snprintf(_fmtText, _display->width(), "%.0f", (totalYieldDay)); - _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); - _display->drawInvertedBitmap(5, y - tbh, myToday, 30, 30, GxEPD_BLACK); - x = ((_display->width() - tbw - 20) / 2) - tbx; - _display->setCursor(x, y); - _display->print(_fmtText); - _display->setCursor(_display->width() - 38, y); - _display->setFont(&FreeSans12pt7b); - _display->println("Wh"); - } + _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); + _display->drawInvertedBitmap(5, ((kwh) ? (y - ((tbh + 30) / 2)) : (y - tbh)), myToday, 30, 30, GxEPD_BLACK); + x = ((_display->width() - tbw - 20) / 2) - tbx; + _display->setCursor(x, y); + _display->print(_fmtText); + _display->setCursor(_display->width() - ((kwh) ? 50 : 38), y); + _display->setFont(&FreeSans12pt7b); + _display->println((kwh) ? "kWh" : "Wh"); y = y + tbh + 15; + // Total Production - _display->setFont(&FreeSans18pt7b); - _display->setCursor(5, y); - if (totalYieldTotal > 9999) { + bool mwh = (totalYieldTotal > 9999); + if(mwh) snprintf(_fmtText, _display->width(), "%.1f", (totalYieldTotal / 1000)); - _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); - _display->drawInvertedBitmap(5, y - tbh, mySigma, 30, 30, GxEPD_BLACK); - x = ((_display->width() - tbw - 20) / 2) - tbx; - _display->setCursor(x, y); - _display->print(_fmtText); - _display->setCursor(_display->width() - 59, y); - _display->setFont(&FreeSans12pt7b); - _display->println("MWh"); - } else if (totalYieldTotal <= 9999) { + else snprintf(_fmtText, _display->width(), "%.0f", (totalYieldTotal)); - _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); - _display->drawInvertedBitmap(5, y - tbh, mySigma, 30, 30, GxEPD_BLACK); - x = ((_display->width() - tbw - 20) / 2) - tbx; - _display->setCursor(x, y); - _display->print(_fmtText); - _display->setCursor(_display->width() - 50, y); - _display->setFont(&FreeSans12pt7b); - _display->println("kWh"); - } + + _display->setFont(&FreeSans18pt7b); + _display->setCursor(5, y); + _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); + _display->drawInvertedBitmap(5, y - tbh, mySigma, 30, 30, GxEPD_BLACK); + x = ((_display->width() - tbw - 20) / 2) - tbx; + _display->setCursor(x, y); + _display->print(_fmtText); + _display->setCursor(_display->width() - ((mwh) ? 59 : 50), y); + _display->setFont(&FreeSans12pt7b); + _display->println((mwh) ? "MWh" : "kWh"); } // Inverter online @@ -263,14 +269,18 @@ void DisplayEPaper::actualPowerPaged(float totalPower, float totalYieldDay, floa _display->setCursor(x, y); _display->println(_fmtText); } + yield(); } while (_display->nextPage()); } //*************************************************************************** void DisplayEPaper::loop(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) { + if(RefreshStatus::DONE != mRefreshState) + return; + // check if the IP has changed - if (_settedIP != WiFi.localIP().toString().c_str()) { + if (_settedIP != WiFi.localIP().toString()) { // save the new IP and call the Headline Function to adapt the Headline - _settedIP = WiFi.localIP().toString().c_str(); + _settedIP = WiFi.localIP().toString(); headlineIP(); } @@ -286,5 +296,11 @@ void DisplayEPaper::loop(float totalPower, float totalYieldDay, float totalYield _display->powerOff(); } + //*************************************************************************** +void DisplayEPaper::tickerSecond() { + if(mSecondCnt != 0) + mSecondCnt--; + refreshLoop(); +} #endif // ESP32 diff --git a/src/plugins/Display/Display_ePaper.h b/src/plugins/Display/Display_ePaper.h index e89c191b..2ff7e58d 100644 --- a/src/plugins/Display/Display_ePaper.h +++ b/src/plugins/Display/Display_ePaper.h @@ -30,6 +30,8 @@ class DisplayEPaper { void init(uint8_t type, uint8_t _CS, uint8_t _DC, uint8_t _RST, uint8_t _BUSY, uint8_t _SCK, uint8_t _MOSI, uint32_t* utcTs, const char* version); void config(uint8_t rotation, bool enPowerSafe); void loop(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod); + void refreshLoop(); + void tickerSecond(); private: void headlineIP(); @@ -38,15 +40,26 @@ class DisplayEPaper { void offlineFooter(); void versionFooter(); + enum class RefreshStatus : uint8_t { + DONE, + BLACK, + WHITE, + WAIT, + PARTITIALS, + LOGO + }; + uint8_t mDisplayRotation; bool _changed = false; char _fmtText[35]; - const char* _settedIP; + String _settedIP; uint8_t mHeadFootPadding; GxEPD2_GFX* _display; uint32_t* mUtcTs; bool mEnPowerSafe; const char* _version; + RefreshStatus mRefreshState, mNextRefreshState; + uint8_t mSecondCnt; }; #endif // ESP32 diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 095b065e..7f722d89 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -224,7 +224,7 @@ class RestApi { #endif /* !defined(ETHERNET) */ obj[F("device_name")] = mConfig->sys.deviceName; obj[F("dark_mode")] = (bool)mConfig->sys.darkMode; - obj[F("sched_reboot")] = (bool)mConfig->sys.schedReboot; + obj[F("sched_reboot")] = (bool)mConfig->sys.schedReboot; obj[F("mac")] = WiFi.macAddress(); obj[F("hostname")] = mConfig->sys.deviceName; diff --git a/src/web/html/colorBright.css b/src/web/html/colorBright.css index 255b5130..47382daa 100644 --- a/src/web/html/colorBright.css +++ b/src/web/html/colorBright.css @@ -8,6 +8,7 @@ --success: #009900; --input-bg: #eee; + --table-border: #ccc; --nav-bg: #333; --primary: #006ec0; diff --git a/src/web/html/colorDark.css b/src/web/html/colorDark.css index d143f8be..3d9d167a 100644 --- a/src/web/html/colorDark.css +++ b/src/web/html/colorDark.css @@ -8,6 +8,7 @@ --success: #00bb00; --input-bg: #333; + --table-border: #333; --nav-bg: #333; --primary: #004d87; diff --git a/src/web/html/style.css b/src/web/html/style.css index 4d4dc6f8..6d19bd21 100644 --- a/src/web/html/style.css +++ b/src/web/html/style.css @@ -329,7 +329,7 @@ th { .table td, .table th { padding: .75rem; - border-bottom: 1px solid var(--nav-bg); + border-bottom: 1px solid var(--table-border); } #wrapper { @@ -737,3 +737,30 @@ h5 { .pointer { cursor: pointer; } + +.badge-success { + color: #fff; + background-color: #28a745; +} + +.badge-warning { + color: #212529; + background-color: #ffc107; +} + +.badge-error { + color: #fff; + background-color: #dc3545; +} + +.badge { + display: inline-block; + padding: .25em .4em; + font-size: 75%; + font-weight: 700; + line-height: 1; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: .25rem; +} diff --git a/src/web/html/system.html b/src/web/html/system.html index d51c01cc..c504057f 100644 --- a/src/web/html/system.html +++ b/src/web/html/system.html @@ -49,33 +49,47 @@ } } + function badge(success, text) { + return ml("span", {class: "badge badge-" + ((success) ? "success" : "error")}, text); + } + + function headline(text) { + return ml("div", {class: "head p-2 mt-3"}, ml("div", {class: "row"}, ml("div", {class: "col a-c"}, text))) + } + + function tr(val1, val2) { + if(typeof val2 == "number") + val2 = String(val2); + return ml("tr", {}, [ + ml("th", {}, val1), + ml("td", {}, val2) + ]); + } + function parseRadio(obj, stat) { const pa = ["MIN (recommended)", "LOW", "HIGH", "MAX"]; const datarate = ["1 MBps", "2 MBps", "250 kbps"]; - var main = document.getElementById("radio"); - var h = div(["head", "p-2"]); - var r = div(["row"]); - r.appendChild(div(["col", "a-c"], "Radio")); - h.appendChild(r); - main.appendChild(h); - - main.appendChild( - genTabRow("nrf24l01" + (obj["isPVariant"] ? "+ " : ""), (obj["isconnected"] ? "is connected " : "is not connected ")) - ); - - if(obj["isconnected"]) { - main.appendChild(genTabRow("Datarate", datarate[obj["DataRate"]])); - main.appendChild(genTabRow("Power Level", pa[obj["power_level"]])); - } + document.getElementById("radio").append( + headline("NRF Radio"), + ml("table", {class: "table"}, [ + ml("tbody", {}, [ + tr("NRF24L01", badge(obj.isconnected, ((obj.isconnected) ? "" : "not ") + "connected")), + tr("Power Level", pa[obj.power_level]) + ]) + ]), - main.append( - genTabRow("TX count", stat["tx_cnt"]), - genTabRow("RX success", stat["rx_success"]), - genTabRow("RX fail", stat["rx_fail"]), - genTabRow("RX no answer", stat["rx_fail_answer"]), - genTabRow("RX fragments", stat["frame_cnt"]), - genTabRow("TX retransmits", stat["retransmits"]) + headline("Statistics"), + ml("table", {class: "table"}, [ + ml("tbody", {}, [ + tr("TX count", stat.tx_cnt), + tr("RX success", stat.rx_success), + tr("RX fail", stat.rx_fail), + tr("RX no answer", stat.rx_fail_answer), + tr("RX fragments", stat.frame_cnt), + tr("TX retransmits", stat.retransmits) + ]) + ]) ); } From 69e2a63eab755313938a88a7be66c2211c0e132d Mon Sep 17 00:00:00 2001 From: lumapu Date: Fri, 1 Sep 2023 23:35:51 +0200 Subject: [PATCH 048/267] 0.7.46 * send loop skip disabled inverters fix * print generated DTU SN to console --- src/CHANGES.md | 2 ++ src/app.cpp | 30 ++++++++++++++++-------------- src/hm/hmRadio.h | 7 ++++--- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index c81162ad..e55fc198 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -4,6 +4,8 @@ * removed `delay` from ePaper * started improvements of `/system` * fix LEDs to check all configured inverters +* send loop skip disabled inverters fix +* print generated DTU SN to console ## 0.7.45 - 2023-08-29 * change ePaper text to symbols PR #1131 diff --git a/src/app.cpp b/src/app.cpp index 15fc432c..ca33a895 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -454,24 +454,26 @@ void app::tickSend(void) { int8_t maxLoop = MAX_NUM_INVERTERS; Inverter<> *iv = mSys.getInverterByPos(mSendLastIvId); do { - mSendLastIvId = ((MAX_NUM_INVERTERS - 1) == mSendLastIvId) ? 0 : mSendLastIvId + 1; - iv = mSys.getInverterByPos(mSendLastIvId); - } while ((NULL == iv) && ((maxLoop--) > 0)); + do { + mSendLastIvId = ((MAX_NUM_INVERTERS - 1) == mSendLastIvId) ? 0 : mSendLastIvId + 1; + iv = mSys.getInverterByPos(mSendLastIvId); + } while ((NULL == iv) && ((maxLoop--) > 0)); + } while((!iv->config->enabled) && (maxLoop > 0)); if (NULL != iv) { if (iv->config->enabled) { if(mConfig->nrf.enabled) { - if (iv->ivGen == IV_HM) - mPayload.ivSend(iv); - else if(iv->ivGen == IV_MI) - mMiPayload.ivSend(iv); - } - #if defined(ESP32) - if(mConfig->cmt.enabled) { - if((iv->ivGen == IV_HMS) || (iv->ivGen == IV_HMT)) - mHmsPayload.ivSend(iv); - } - #endif + if (iv->ivGen == IV_HM) + mPayload.ivSend(iv); + else if(iv->ivGen == IV_MI) + mMiPayload.ivSend(iv); + } + #if defined(ESP32) + if(mConfig->cmt.enabled) { + if((iv->ivGen == IV_HMS) || (iv->ivGen == IV_HMT)) + mHmsPayload.ivSend(iv); + } + #endif } } } else { diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 0b5feea5..ee037adb 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -32,7 +32,7 @@ class HmRadio { public: HmRadio() : mNrf24(CE_PIN, CS_PIN, SPI_SPEED) { if(mSerialDebug) { - DPRINT(DBG_VERBOSE, F("hmRadio.h : HmRadio():mNrf24(CE_PIN: ")); + DPRINT(DBG_VERBOSE, F("hmRadio.h : HmRadio():mNrf24(CE_PIN: ")); DBGPRINT(String(CE_PIN)); DBGPRINT(F(", CS_PIN: ")); DBGPRINT(String(CS_PIN)); @@ -117,8 +117,9 @@ class HmRadio { if(mNrf24.isChipConnected()) { DPRINTLN(DBG_INFO, F("Radio Config:")); mNrf24.printPrettyDetails(); - } - else + DPRINT(DBG_INFO, F("DTU_SN: 0x")); + DBGPRINTLN(String(DTU_RADIO_ID, HEX)); + } else DPRINTLN(DBG_WARN, F("WARNING! your NRF24 module can't be reached, check the wiring")); } From 7c6cb35c8ed78de7c91263b99b8f79217beb4d46 Mon Sep 17 00:00:00 2001 From: dAjaY85 Date: Mon, 4 Sep 2023 11:02:25 +0200 Subject: [PATCH 049/267] Integration 2.42" Display als Typ 6 --- src/plugins/Display/Display.h | 2 +- src/plugins/Display/Display_Mono_128X64.h | 4 +++- src/web/html/setup.html | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index 2340fd42..76b41c77 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -35,7 +35,7 @@ class Display { case 3: mMono = new DisplayMono84X48(); break; case 4: mMono = new DisplayMono128X32(); break; case 5: mMono = new DisplayMono64X48(); break; - + case 6: mMono = new DisplayMono128X64(); break; #if defined(ESP32) case 10: mMono = NULL; // ePaper does not use this diff --git a/src/plugins/Display/Display_Mono_128X64.h b/src/plugins/Display/Display_Mono_128X64.h index a828816c..b7d52868 100644 --- a/src/plugins/Display/Display_Mono_128X64.h +++ b/src/plugins/Display/Display_Mono_128X64.h @@ -27,10 +27,12 @@ class DisplayMono128X64 : public DisplayMono { case 1: mDisplay = new U8G2_SSD1306_128X64_NONAME_F_HW_I2C(rot, reset, clock, data); break; - default: case 2: mDisplay = new U8G2_SH1106_128X64_NONAME_F_HW_I2C(rot, reset, clock, data); break; + case 6: + mDisplay = new U8G2_SSD1309_128X64_NONAME0_F_HW_I2C(rot, reset, clock, data); + break; } mUtcTs = utcTs; diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 9df891c8..dbc82a75 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -839,7 +839,7 @@ } // keep display types grouped - var opts = [[0, "None"], [2, "SH1106 1.3\" 128X64"], [5, "SSD1306 0.66\" 64X48 (Wemos OLED Shield)"], [4, "SSD1306 0.91\" 128X32"], [1, "SSD1306 0.96\" 128X64"], [3, "Nokia5110"]]; + var opts = [[0, "None"], [2, "SH1106 1.3\" 128X64"], [5, "SSD1306 0.66\" 64X48 (Wemos OLED Shield)"], [4, "SSD1306 0.91\" 128X32"], [1, "SSD1306 0.96\" 128X64"], [6, "SSD1309 2.42\" 128X64"], [3, "Nokia5110"]]; if("ESP32" == type) opts.push([10, "ePaper"]); var dispType = sel("disp_typ", opts, obj["disp_typ"]); From 67d3e824afce8ed705e8eb81f9086d00a4e6e178 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 4 Sep 2023 20:27:06 +0200 Subject: [PATCH 050/267] 0.7.46 * HW Versions for MI series PR #1133 --- src/CHANGES.md | 3 ++- src/hm/hmInverter.h | 3 --- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index e55fc198..71b15400 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,11 +1,12 @@ # Development Changes -## 0.7.46 - 2023-09-01 +## 0.7.46 - 2023-09-04 * removed `delay` from ePaper * started improvements of `/system` * fix LEDs to check all configured inverters * send loop skip disabled inverters fix * print generated DTU SN to console +* HW Versions for MI series PR #1133 ## 0.7.45 - 2023-08-29 * change ePaper text to symbols PR #1131 diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index c491f754..c8088087 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -339,9 +339,6 @@ class Inverter { DPRINT(DBG_INFO, "alarm ID incremented to "); DBGPRINTLN(String(alarmMesIndex)); enqueCommand(AlarmData); -// ivSendHighPrio(id); -// if(mHighPrioIv == NULL) // process the request immediately if possible -// mHighPrioIv = iv; } } } From 7dfe7d425f3872477e45a8dbe7507e8fc6cd7dd6 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 4 Sep 2023 20:30:05 +0200 Subject: [PATCH 051/267] 0.7.46 * 2.42" display (SSD1309) integration PR #1139 --- src/CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CHANGES.md b/src/CHANGES.md index 71b15400..402ec595 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -7,6 +7,7 @@ * send loop skip disabled inverters fix * print generated DTU SN to console * HW Versions for MI series PR #1133 +* 2.42" display (SSD1309) integration PR #1139 ## 0.7.45 - 2023-08-29 * change ePaper text to symbols PR #1131 From a1a9a1f9cbf4f4cc16f6f170e8170926096fc67a Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 4 Sep 2023 20:45:31 +0200 Subject: [PATCH 052/267] 0.7.46 * add / rename alarm codes PR #1118 --- src/CHANGES.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/CHANGES.md b/src/CHANGES.md index 402ec595..f142a012 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -8,6 +8,8 @@ * print generated DTU SN to console * HW Versions for MI series PR #1133 * 2.42" display (SSD1309) integration PR #1139 +* update user manual PR #1121 +* add / rename alarm codes PR #1118 ## 0.7.45 - 2023-08-29 * change ePaper text to symbols PR #1131 From 4b34aadc1690566cb37bc37b4b5f8e20b40ec94d Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 4 Sep 2023 21:32:23 +0200 Subject: [PATCH 053/267] 0.7.46 * luminance of display can be changed during runtime #1106 --- src/CHANGES.md | 2 ++ src/config/config.h | 2 +- src/plugins/Display/Display.h | 2 +- src/plugins/Display/Display_Mono_128X32.h | 7 ++++++- src/plugins/Display/Display_Mono_128X64.h | 7 ++++++- src/plugins/Display/Display_Mono_64X48.h | 7 ++++++- src/plugins/Display/Display_Mono_84X48.h | 7 ++++++- 7 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index f142a012..6c59822e 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -10,6 +10,8 @@ * 2.42" display (SSD1309) integration PR #1139 * update user manual PR #1121 * add / rename alarm codes PR #1118 +* revert default pin ESP32 for NRF23-CE #1132 +* luminance of display can be changed during runtime #1106 ## 0.7.45 - 2023-08-29 * change ePaper text to symbols PR #1131 diff --git a/src/config/config.h b/src/config/config.h index 397ad15a..54686ab8 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -68,7 +68,7 @@ #define DEF_NRF_CS_PIN 5 #endif #ifndef DEF_NRF_CE_PIN - #define DEF_NRF_CE_PIN 17 + #define DEF_NRF_CE_PIN 4 #endif #ifndef DEF_NRF_IRQ_PIN #define DEF_NRF_IRQ_PIN 16 diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index 915a7475..36a7df46 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -59,7 +59,7 @@ class Display { void tickerSecond() { if (mMono != NULL) - mMono->loop(); + mMono->loop(mCfg->contrast); if (mNewPayload || (((++mLoopCnt) % 30) == 0)) { mNewPayload = false; diff --git a/src/plugins/Display/Display_Mono_128X32.h b/src/plugins/Display/Display_Mono_128X32.h index e9e09d28..5a6d6c7e 100644 --- a/src/plugins/Display/Display_Mono_128X32.h +++ b/src/plugins/Display/Display_Mono_128X32.h @@ -46,11 +46,16 @@ class DisplayMono128X32 : public DisplayMono { mLuminance = lum; } - void loop(void) { + void loop(uint8_t lum) { if (mEnPowerSafe) { if (mTimeout != 0) mTimeout--; } + + if(mLuminance != lum) { + mLuminance = lum; + mDisplay->setContrast(mLuminance); + } } void disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) { diff --git a/src/plugins/Display/Display_Mono_128X64.h b/src/plugins/Display/Display_Mono_128X64.h index b7d52868..438cb79e 100644 --- a/src/plugins/Display/Display_Mono_128X64.h +++ b/src/plugins/Display/Display_Mono_128X64.h @@ -54,11 +54,16 @@ class DisplayMono128X64 : public DisplayMono { mLuminance = lum; } - void loop(void) { + void loop(uint8_t lum) { if (mEnPowerSafe) { if (mTimeout != 0) mTimeout--; } + + if(mLuminance != lum) { + mLuminance = lum; + mDisplay->setContrast(mLuminance); + } } void disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) { diff --git a/src/plugins/Display/Display_Mono_64X48.h b/src/plugins/Display/Display_Mono_64X48.h index 67b38e44..ae074c33 100644 --- a/src/plugins/Display/Display_Mono_64X48.h +++ b/src/plugins/Display/Display_Mono_64X48.h @@ -47,11 +47,16 @@ class DisplayMono64X48 : public DisplayMono { mLuminance = lum; } - void loop(void) { + void loop(uint8_t lum) { if (mEnPowerSafe) { if (mTimeout != 0) mTimeout--; } + + if(mLuminance != lum) { + mLuminance = lum; + mDisplay->setContrast(mLuminance); + } } void disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) { diff --git a/src/plugins/Display/Display_Mono_84X48.h b/src/plugins/Display/Display_Mono_84X48.h index 9f7761dc..fff983bc 100644 --- a/src/plugins/Display/Display_Mono_84X48.h +++ b/src/plugins/Display/Display_Mono_84X48.h @@ -47,11 +47,16 @@ class DisplayMono84X48 : public DisplayMono { mLuminance = lum; } - void loop(void) { + void loop(uint8_t lum) { if (mEnPowerSafe) { if (mTimeout != 0) mTimeout--; } + + if(mLuminance != lum) { + mLuminance = lum; + mDisplay->setContrast(mLuminance); + } } void disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) { From 81dfff15ca52f680fa3e70163b5abb7bee309064 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 4 Sep 2023 21:36:02 +0200 Subject: [PATCH 054/267] 0.7.46 * fix compile --- src/plugins/Display/Display_Mono.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/Display/Display_Mono.h b/src/plugins/Display/Display_Mono.h index 42eea5f3..4739f83f 100644 --- a/src/plugins/Display/Display_Mono.h +++ b/src/plugins/Display/Display_Mono.h @@ -23,7 +23,7 @@ class DisplayMono { virtual void 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) = 0; virtual void config(bool enPowerSafe, bool enScreenSaver, uint8_t lum) = 0; - virtual void loop(void) = 0; + virtual void loop(uint8_t lum) = 0; virtual void disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) = 0; protected: From 6b721cbe0cf736afbe93479288417fa60db50988 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 4 Sep 2023 21:37:02 +0200 Subject: [PATCH 055/267] 0.7.46 * version number increase --- src/defines.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/defines.h b/src/defines.h index 8a125bfa..465bf201 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 7 -#define VERSION_PATCH 45 +#define VERSION_PATCH 46 //------------------------------------- typedef struct { From f28f314fcff47b673aeec48e799522470a1f6959 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 7 Sep 2023 21:30:41 +0200 Subject: [PATCH 056/267] 0.7.47 * fix boot loop #1140 --- src/CHANGES.md | 3 +++ src/app.cpp | 7 +++++-- src/defines.h | 2 +- src/web/html/index.html | 9 +++------ 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 6c59822e..df48a2d9 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.7.47 - 2023-09-07 +* fix boot loop #1140 + ## 0.7.46 - 2023-09-04 * removed `delay` from ePaper * started improvements of `/system` diff --git a/src/app.cpp b/src/app.cpp index ca33a895..53feeb48 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -453,12 +453,15 @@ void app::tickSend(void) { int8_t maxLoop = MAX_NUM_INVERTERS; Inverter<> *iv = mSys.getInverterByPos(mSendLastIvId); - do { + while(maxLoop > 0) { do { mSendLastIvId = ((MAX_NUM_INVERTERS - 1) == mSendLastIvId) ? 0 : mSendLastIvId + 1; iv = mSys.getInverterByPos(mSendLastIvId); } while ((NULL == iv) && ((maxLoop--) > 0)); - } while((!iv->config->enabled) && (maxLoop > 0)); + if(NULL != iv) + if(iv->config->enabled) + break; + } if (NULL != iv) { if (iv->config->enabled) { diff --git a/src/defines.h b/src/defines.h index 465bf201..13bb75a1 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 7 -#define VERSION_PATCH 46 +#define VERSION_PATCH 47 //------------------------------------- typedef struct { diff --git a/src/web/html/index.html b/src/web/html/index.html index 4f723fed..a7c79c25 100644 --- a/src/web/html/index.html +++ b/src/web/html/index.html @@ -126,16 +126,13 @@ icon = iconWarn; cl = "icon-warn"; avail = "disabled"; - } - else if(false == i["is_avail"]) { + } else if(false == i["is_avail"]) { icon = iconInfo; cl = "icon-info"; avail = "not yet available"; - } - else if(0 == i["ts_last_success"]) { + } else if(0 == i["ts_last_success"]) { avail = "available but no data was received until now"; - } - else { + } else { avail = "available and is "; if(false == i["is_producing"]) avail += "not "; From 7207d3c9d483a3a77da95cc4e08c7ae449f83014 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 7 Sep 2023 23:19:43 +0200 Subject: [PATCH 057/267] 0.7.47 * fix regex in `setup` page * fix MI serial number display `max-module-power` in `setup` #1142 * renamed `opendtufusionv1` to `opendtufusion` --- .github/workflows/compile_development.yml | 4 ++-- .github/workflows/compile_release.yml | 4 ++-- scripts/getVersion.py | 4 ++-- src/CHANGES.md | 3 +++ src/platformio.ini | 4 ++-- src/web/RestApi.h | 2 +- src/web/html/api.js | 5 +++-- src/web/html/setup.html | 16 +++++++++------- 8 files changed, 24 insertions(+), 18 deletions(-) diff --git a/.github/workflows/compile_development.yml b/.github/workflows/compile_development.yml index aa5789c6..7c3e9d76 100644 --- a/.github/workflows/compile_development.yml +++ b/.github/workflows/compile_development.yml @@ -47,10 +47,10 @@ jobs: run: python convert.py - name: Run PlatformIO - run: pio run -d src --environment esp8266 --environment esp8266-prometheus --environment esp8285 --environment esp32-wroom32 --environment esp32-wroom32-prometheus --environment esp32-wroom32-ethernet --environment esp32-s2-mini --environment opendtufusionv1 + run: pio run -d src --environment esp8266 --environment esp8266-prometheus --environment esp8285 --environment esp32-wroom32 --environment esp32-wroom32-prometheus --environment esp32-wroom32-ethernet --environment esp32-s2-mini --environment opendtufusion - name: Copy boot_app0.bin - run: cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin src/.pio/build/opendtufusionv1/ota.bin + run: cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin src/.pio/build/opendtufusion/ota.bin - name: Rename Binary files id: rename-binary-files diff --git a/.github/workflows/compile_release.yml b/.github/workflows/compile_release.yml index ce75358e..87cabd22 100644 --- a/.github/workflows/compile_release.yml +++ b/.github/workflows/compile_release.yml @@ -51,10 +51,10 @@ jobs: run: python convert.py - name: Run PlatformIO - run: pio run -d src --environment esp8266 --environment esp8266-prometheus --environment esp8285 --environment esp32-wroom32 --environment esp32-wroom32-prometheus --environment esp32-wroom32-ethernet --environment esp32-s2-mini --environment opendtufusionv1 + run: pio run -d src --environment esp8266 --environment esp8266-prometheus --environment esp8285 --environment esp32-wroom32 --environment esp32-wroom32-prometheus --environment esp32-wroom32-ethernet --environment esp32-s2-mini --environment opendtufusion - name: Copy boot_app0.bin - run: cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin src/.pio/build/opendtufusionv1/ota.bin + run: cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin src/.pio/build/opendtufusion/ota.bin - name: Rename Binary files id: rename-binary-files diff --git a/scripts/getVersion.py b/scripts/getVersion.py index b6bef458..be36895e 100644 --- a/scripts/getVersion.py +++ b/scripts/getVersion.py @@ -94,7 +94,7 @@ def readVersion(path, infile): os.rename(src, dst) versionout = version[:-1] + "_" + sha + "_esp32s3.bin" - src = path + ".pio/build/opendtufusionv1/firmware.bin" + src = path + ".pio/build/opendtufusion/firmware.bin" dst = path + "firmware/ESP32-S3/" + versionout os.rename(src, dst) @@ -113,7 +113,7 @@ def readVersion(path, infile): genOtaBin(dst) # other ESP32-S3 bin files - src = path + ".pio/build/opendtufusionv1/" + src = path + ".pio/build/opendtufusion/" dst = path + "firmware/ESP32-S3/" os.rename(src + "bootloader.bin", dst + "bootloader.bin") os.rename(src + "partitions.bin", dst + "partitions.bin") diff --git a/src/CHANGES.md b/src/CHANGES.md index df48a2d9..f241e5f2 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -2,6 +2,9 @@ ## 0.7.47 - 2023-09-07 * fix boot loop #1140 +* fix regex in `setup` page +* fix MI serial number display `max-module-power` in `setup` #1142 +* renamed `opendtufusionv1` to `opendtufusion` ## 0.7.46 - 2023-09-04 * removed `delay` from ePaper diff --git a/src/platformio.ini b/src/platformio.ini index 42c1557a..85c4cf67 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -123,7 +123,7 @@ build_flags = ${env.build_flags} monitor_filters = esp32_exception_decoder -[env:opendtufusionv1] +[env:opendtufusion] platform = espressif32@6.3.2 board = esp32-s3-devkitc-1 upload_protocol = esp-builtin @@ -141,6 +141,6 @@ build_flags = ${env.build_flags} -DDEF_LED1=17 -DLED_ACTIVE_HIGH -DARDUINO_USB_MODE=1 - -DARDUINO_USB_CDC_ON_BOOT=1 + ;-DARDUINO_USB_CDC_ON_BOOT=1 monitor_filters = esp32_exception_decoder, colorize diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 7f722d89..b5052d37 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -493,7 +493,7 @@ class RestApi { void getRadioCmt(JsonObject obj) { obj[F("csb")] = mConfig->cmt.pinCsb; obj[F("fcsb")] = mConfig->cmt.pinFcsb; - obj[F("irq")] = mConfig->cmt.pinIrq; + obj[F("gpio3")] = mConfig->cmt.pinIrq; obj[F("en")] = (bool) mConfig->cmt.enabled; } diff --git a/src/web/html/api.js b/src/web/html/api.js index 93429afc..82405a71 100644 --- a/src/web/html/api.js +++ b/src/web/html/api.js @@ -132,11 +132,12 @@ function toIsoTimeStr(d) { // UTC! function setHide(id, hide) { var elm = document.getElementById(id); + if(null == elm) + return; if(hide) { if(!elm.classList.contains("hide")) elm.classList.add("hide"); - } - else + } else elm.classList.remove('hide'); } diff --git a/src/web/html/setup.html b/src/web/html/setup.html index dbc82a75..a3ecca25 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -50,7 +50,7 @@
Interval [s]
-
+
@@ -267,7 +267,7 @@
Topic
-
+

Send Inverter data in a fixed interval, even if there is no change. A value of '0' disables the fixed interval. The data is published once it was successfully received from inverter. (default: 0)

@@ -449,7 +449,7 @@ [1, "high active"], ]; - const re = /1[1,3][2,4,6,8][1,2,4].*/; + const re = /1[0,1,3][2,4,6,8][1,2,4].*/; window.onload = function() { for(it of document.getElementsByClassName("s_collapsible")) { @@ -576,7 +576,8 @@ iv.appendChild(des("Inverter " + id)); id = "inv" + id; - var addr = inp(id + "Addr", obj["serial"], 12, ["text"], null, "text", "[0-9]+", "Invalid input"); + var addr = ml("input", {name: id + "Addr", class: "text", type: "number", max: 138999999999, value: obj["serial"]}, null); + iv.append( mlCb(id + "Enable", "Communication Enable", obj["enabled"]), mlE("Serial Number (12 digits)*", addr) @@ -599,6 +600,7 @@ if((serial.charAt(1) == 0) || (serial.charAt(1) == 1) || (serial.charAt(1) == 3)) { if((serial.charAt(3) == 1) || (serial.charAt(3) == 2) || (serial.charAt(3) == 4)) { switch(serial.charAt(2)) { + default: case "2": max = 1; break; case "4": max = 2; break; case "6": max = 4; break; @@ -621,12 +623,12 @@ }) }); - iv.append(mlE("Name*", inp(id + "Name", obj["name"], 16, ["text"], null, "text", "[A-Za-z0-9./#$%&=+_-]+", "Invalid input"))); + iv.append(mlE("Name*", inp(id + "Name", obj["name"], 16, ["text"], null, "text", "[\\-\\+A-Za-z0-9.\\/#$%&=_]+", "Invalid input"))); for(var j of [ ["ModPwr", "ch_max_pwr", "Max Module Power (Wp)", 4, "[0-9]+"], ["ModName", "ch_name", "Module Name", 15, null], - ["YieldCor", "ch_yield_cor", "Yield Total Correction [kWh]", 8, "[0-9-\.]+"]]) { + ["YieldCor", "ch_yield_cor", "Yield Total Correction [kWh]", 8, "[\\-0-9\.]+"]]) { var cl = (re.test(obj["serial"])) ? "" : " hide"; @@ -799,7 +801,7 @@ ml("div", {class: "col-4 col-sm-9"}, en) ]) ); - pins = [['csb', 'pinCsb'], ['fcsb', 'pinFcsb'], ['irq', 'pinGpio3']]; + pins = [['csb', 'pinCsb'], ['fcsb', 'pinFcsb'], ['gpio3', 'pinGpio3']]; for(p of pins) { e.append( ml("div", {class: "row mb-3"}, [ From 3aa99475cffd4a51eadef1a4753dee83f0027657 Mon Sep 17 00:00:00 2001 From: Lukas Pusch Date: Thu, 7 Sep 2023 23:47:53 +0200 Subject: [PATCH 058/267] 0.7.47 Update applyPatches.py --- scripts/applyPatches.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/applyPatches.py b/scripts/applyPatches.py index 51fbaa40..9537e0bd 100644 --- a/scripts/applyPatches.py +++ b/scripts/applyPatches.py @@ -28,5 +28,5 @@ def applyPatch(libName, patchFile): # list of patches to apply (relative to /src) applyPatch("ESP Async WebServer", "../patches/AsyncWeb_Prometheus.patch") -if env['PIOENV'] == "opendtufusionv1": +if env['PIOENV'] == "opendtufusion": applyPatch("GxEPD2", "../patches/GxEPD2_SW_SPI.patch") From 7673721bd7d64fa641526e5014964eda7ab53690 Mon Sep 17 00:00:00 2001 From: Frank Date: Sun, 10 Sep 2023 10:39:32 +0200 Subject: [PATCH 059/267] Use default channel name if non is set. Export inverter metrics as _total metric if channel metrics also available. --- doc/prometheus_ep_description.md | 69 +++++++++++++++++--------------- src/web/web.h | 21 ++++++++-- 2 files changed, 54 insertions(+), 36 deletions(-) diff --git a/doc/prometheus_ep_description.md b/doc/prometheus_ep_description.md index 755fd1e4..711299dd 100644 --- a/doc/prometheus_ep_description.md +++ b/doc/prometheus_ep_description.md @@ -15,37 +15,40 @@ Prometheus metrics provided at `/metrics`. | channel | Channel (Module) name from setup. Label only available if max power level of module is set to non-zero. Be sure to have a cannel name set in configuration. | ## Exported 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 | -| `ahoy_solar_inverter_is_producing` | Gauge | Is the inverter producing? | inverter | -| `ahoy_solar_U_AC_volt` | Gauge | AC voltage of inverter [V] | inverter | -| `ahoy_solar_I_AC_ampere` | Gauge | AC current of inverter [A] | inverter | -| `ahoy_solar_P_AC_watt` | Gauge | AC power of inverter [W] | inverter | -| `ahoy_solar_Q_AC_var` | Gauge | AC reactive power[var] | inverter | -| `ahoy_solar_F_AC_hertz` | Gauge | AC frequency [Hz] | inverter | -| `ahoy_solar_PF_AC` | Gauge | AC Power factor | inverter | -| `ahoy_solar_Temp_celsius` | Gauge | Temperature of inverter | inverter | -| `ahoy_solar_ALARM_MES_ID` | Gauge | Alarm message index of inverter | inverter | -| `ahoy_solar_LastAlarmCode` | Gauge | Last alarm code from inverter | inverter | -| `ahoy_solar_YieldDay_wattHours` | Counter | Energy converted to AC per day [Wh] | inverter | -| `ahoy_solar_YieldTotal_kilowattHours` | Counter | Energy converted to AC since reset [kWh] | inverter | -| `ahoy_solar_P_DC_watt` | Gauge | DC power of inverter [W] | inverter | -| `ahoy_solar_Efficiency_ratio` | Gauge | ration AC Power over DC Power [%] | inverter | -| `ahoy_solar_U_DC_volt` | Gauge | DC voltage of channel [V] | inverter, channel | -| `ahoy_solar_I_DC_ampere` | Gauge | DC current of channel [A] | inverter, channel | -| `ahoy_solar_P_DC_watt` | Gauge | DC power of channel [P] | inverter, channel | -| `ahoy_solar_YieldDay_wattHours` | Counter | Energy converted to AC per day [Wh] | inverter, channel | -| `ahoy_solar_YieldTotal_kilowattHours` | Counter | Energy converted to AC since reset [kWh] | inverter, channel | -| `ahoy_solar_Irradiation_ratio` | Gauge | ratio DC Power over set maximum power per channel [%] | inverter, channel | -| `ahoy_solar_radio_rx_success` | Gauge | NRF24 statistic | | -| `ahoy_solar_radio_rx_fail` | Gauge | NRF24 statistic | | -| `ahoy_solar_radio_rx_fail_answer` | Gauge | NRF24 statistic | | -| `ahoy_solar_radio_frame_cnt` | Gauge | NRF24 statistic | | -| `ahoy_solar_radio_tx_cnt` | Gauge | NRF24 statistic | | +| 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 | +| `ahoy_solar_inverter_is_producing` | Gauge | Is the inverter producing? | inverter | +| `ahoy_solar_U_AC_volt` | Gauge | AC voltage of inverter [V] | inverter | +| `ahoy_solar_I_AC_ampere` | Gauge | AC current of inverter [A] | inverter | +| `ahoy_solar_P_AC_watt` | Gauge | AC power of inverter [W] | inverter | +| `ahoy_solar_Q_AC_var` | Gauge | AC reactive power[var] | inverter | +| `ahoy_solar_F_AC_hertz` | Gauge | AC frequency [Hz] | inverter | +| `ahoy_solar_PF_AC` | Gauge | AC Power factor | inverter | +| `ahoy_solar_Temp_celsius` | Gauge | Temperature of inverter | inverter | +| `ahoy_solar_ALARM_MES_ID` | Gauge | Alarm message index of inverter | inverter | +| `ahoy_solar_LastAlarmCode` | Gauge | Last alarm code from inverter | inverter | +| `ahoy_solar_YieldDay_wattHours` | Counter | Energy converted to AC per day [Wh] | inverter,channel | +| `ahoy_solar_YieldDay_wattHours_total` | Counter | Energy converted to AC per day [Wh] for all moduls | inverter | +| `ahoy_solar_YieldTotal_kilowattHours` | Counter | Energy converted to AC since reset [kWh] | inverter,channel | +| `ahoy_solar_YieldTotal_kilowattHours_total` | Counter | Energy converted to AC since reset [kWh] for all modules | inverter | +| `ahoy_solar_P_DC_watt` | Gauge | DC power of inverter [W] | inverter | +| `ahoy_solar_Efficiency_ratio` | Gauge | ration AC Power over DC Power [%] | inverter | +| `ahoy_solar_U_DC_volt` | Gauge | DC voltage of channel [V] | inverter, channel | +| `ahoy_solar_I_DC_ampere` | Gauge | DC current of channel [A] | inverter, channel | +| `ahoy_solar_P_DC_watt` | Gauge | DC power of channel [P] | inverter, channel | +| `ahoy_solar_P_DC_watt_total` | Gauge | DC power of inverter [P] | inverter | +| `ahoy_solar_YieldDay_wattHours` | Counter | Energy converted to AC per day [Wh] | inverter, channel | +| `ahoy_solar_YieldTotal_kilowattHours` | Counter | Energy converted to AC since reset [kWh] | inverter, channel | +| `ahoy_solar_Irradiation_ratio` | Gauge | ratio DC Power over set maximum power per channel [%] | inverter, channel | +| `ahoy_solar_radio_rx_success` | Gauge | NRF24 statistic | | +| `ahoy_solar_radio_rx_fail` | Gauge | NRF24 statistic | | +| `ahoy_solar_radio_rx_fail_answer` | Gauge | NRF24 statistic | | +| `ahoy_solar_radio_frame_cnt` | Gauge | NRF24 statistic | | +| `ahoy_solar_radio_tx_cnt` | Gauge | NRF24 statistic | | diff --git a/src/web/web.h b/src/web/web.h index f1a14e2b..d4f5d069 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -800,16 +800,31 @@ class Web { // This is the correct field to report std::tie(promUnit, promType) = convertToPromUnits(iv->getUnit(metricsChannelId, rec)); // Declare metric only once - if (!metricDeclared) { + if (channel != 0 && !metricDeclared) { snprintf(type, sizeof(type), "# TYPE ahoy_solar_%s%s %s\n", iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), promType.c_str()); metrics += type; metricDeclared = true; } // report value if (0 == channel) { - snprintf(topic, sizeof(topic), "ahoy_solar_%s%s{inverter=\"%s\"}", iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), iv->config->name); + char total[7]; + total[0] = 0; + if (metricDeclared) { + // A declaration and value for channels has been delivered. So declare and deliver a _total metric + strncpy(total,"_total",sizeof(total)); + } + snprintf(type, sizeof(type), "# TYPE ahoy_solar_%s%s%s %s\n", iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), total, promType.c_str()); + metrics += type; + snprintf(topic, sizeof(topic), "ahoy_solar_%s%s%s{inverter=\"%s\"}", iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), total,iv->config->name); } else { - snprintf(topic, sizeof(topic), "ahoy_solar_%s%s{inverter=\"%s\",channel=\"%s\"}", iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), iv->config->name,iv->config->chName[channel-1]); + // Use a fallback channel name (ch0, ch1, ...)if non is given by user + char chName[MAX_NAME_LENGTH]; + if (iv->config->chName[channel-1][0] != 0) { + strncpy(chName, iv->config->chName[channel-1], sizeof(chName)); + } else { + snprintf(chName,sizeof(chName),"ch%1d",channel); + } + snprintf(topic, sizeof(topic), "ahoy_solar_%s%s{inverter=\"%s\",channel=\"%s\"}", iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), iv->config->name,chName); } snprintf(val, sizeof(val), " %.3f\n", iv->getValue(metricsChannelId, rec)); metrics += topic; From e8fa9c747eb13af54faf71acd6a1d38b71ca4fcc Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 10 Sep 2023 16:01:07 +0200 Subject: [PATCH 060/267] 0.7.48 * fix SSD1309 2.42" display pinout * improved setup page: save and delete of inverters --- src/CHANGES.md | 4 ++++ src/defines.h | 2 +- src/web/html/setup.html | 43 ++++++++++++++++++++++++----------------- 3 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index f241e5f2..d4898317 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,9 @@ # Development Changes +## 0.7.48 - 2023-09-10 +* fix SSD1309 2.42" display pinout +* improved setup page: save and delete of inverters + ## 0.7.47 - 2023-09-07 * fix boot loop #1140 * fix regex in `setup` page diff --git a/src/defines.h b/src/defines.h index 13bb75a1..c29f3932 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 7 -#define VERSION_PATCH 47 +#define VERSION_PATCH 48 //------------------------------------- typedef struct { diff --git a/src/web/html/setup.html b/src/web/html/setup.html index a3ecca25..7af9fa88 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -343,7 +343,6 @@
{#HTML_FOOTER} diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 8b28da14..d58aa226 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -683,7 +683,7 @@ if(!obj["pwd_set"]) e.value = ""; var d = document.getElementById("prot_mask"); - var a = ["Index", "Live", "Serial / Console", "Settings", "Update", "System"]; + var a = ["Index", "Live", "Webserial", "Settings", "Update", "System"]; var el = []; for(var i = 0; i < 6; i++) { var chk = ((obj["prot_mask"] & (1 << i)) == (1 << i)); diff --git a/src/web/html/visualization.html b/src/web/html/visualization.html index d790147c..24153389 100644 --- a/src/web/html/visualization.html +++ b/src/web/html/visualization.html @@ -20,6 +20,7 @@ var mIvHtml = []; var mNum = 0; var total = Array(5).fill(0); + var tPwrAck; function parseGeneric(obj) { if(true == exeOnce){ @@ -113,8 +114,10 @@ ml("div", {class: "col mx-2 mx-md-1"}, ml("span", { class: "pointer", onclick: function() { getAjax("/api/inverter/version/" + obj.id, parseIvVersion); }}, obj.name)), - ml("div", {class: "col a-c d-none d-sm-block"}, "Active Power Control: " + pwrLimit), - ml("div", {class: "col a-c d-block d-sm-none"}, "APC: " + pwrLimit), + ml("div", {class: "col a-c", onclick: function() {limitModal(obj)}}, [ + ml("span", {class: "d-none d-sm-block pointer"}, "Active Power Control: " + pwrLimit), + ml("span", {class: "d-block d-sm-none pointer"}, "APC: " + pwrLimit) + ]), ml("div", {class: "col a-c"}, ml("span", { class: "pointer", onclick: function() { getAjax("/api/inverter/alarm/" + obj.id, parseIvAlarm); }}, ("Alarms: " + obj.alarm_cnt))), @@ -305,6 +308,102 @@ modal("Radio statistics for inverter " + obj.name, ml("div", {}, html)); } + function limitModal(obj) { + var opt = [["pct", "%"], ["watt", "W"]]; + var html = ml("div", {}, [ + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-12 col-sm-5 my-2"}, "Limit Value"), + ml("div", {class: "col-8 col-sm-5"}, ml("input", {name: "limit", type: "number"}, "")), + ml("div", {class: "col-4 col-sm-2"}, sel("type", opt, "pct")) + ]), + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-8 col-sm-5"}, "Keep limit over inverter restart"), + ml("div", {class: "col-4 col-sm-7"}, ml("input", {type: "checkbox", name: "keep"})) + ]), + ml("div", {class: "row my-3"}, + ml("div", {class: "col a-r"}, ml("input", {type: "button", value: "Apply", class: "btn", onclick: function() { + applyLimit(obj.id); + }}, null)) + ), + ml("div", {class: "row my-4"}, [ + ml("div", {class: "col-12 col-sm-5 my-2"}, "Control"), + ml("div", {class: "col col-sm-7 a-r"}, [ + ml("input", {type: "button", value: "restart", class: "btn", onclick: function() { + applyCtrl(obj.id, "restart"); + }}, null), + ml("input", {type: "button", value: "turn off", class: "btn mx-1", onclick: function() { + applyCtrl(obj.id, "power", 0); + }}, null), + ml("input", {type: "button", value: "turn on", class: "btn", onclick: function() { + applyCtrl(obj.id, "power", 1); + }}, null) + ]) + ]), + ml("div", {class: "row mt-1"}, [ + ml("div", {class: "col-12 col-sm-5 my-2"}, "Result"), + ml("div", {class: "col-sm-7 my-2"}, ml("span", {name: "pwrres"}, "-")) + ]) + ]); + modal("Active Power Control for inverter " + obj.name, html); + } + + function applyLimit(id) { + var cmd = "limit_"; + if(!document.getElementsByName("keep")[0].checked) + cmd += "non"; + cmd += "persistent_"; + if(document.getElementsByName("type")[0].value == "pct") + cmd += "relative"; + else + cmd += "absolute"; + + var val = document.getElementsByName("limit")[0].value; + if(isNaN(val)) + val = 100; + + var obj = new Object(); + obj.id = id; + obj.cmd = cmd; + obj.val = val; + getAjax("/api/ctrl", ctrlCb, "POST", JSON.stringify(obj)); + } + + function applyCtrl(id, cmd, val=0) { + var obj = new Object(); + obj.id = id; + obj.cmd = cmd; + obj.val = val; + getAjax("/api/ctrl", ctrlCb2, "POST", JSON.stringify(obj)); + } + + function ctrlCb(obj) { + var e = document.getElementsByName("pwrres")[0]; + if(obj.success) { + e.innerHTML = "received command, waiting for inverter acknowledge ..."; + tPwrAck = window.setInterval("getAjax('/api/inverter/pwrack/" + obj.id + "', updatePwrAck)", 1000); + } + else + e.innerHTML = "Error: " + obj["error"]; + } + + function ctrlCb2(obj) { + var e = document.getElementsByName("pwrres")[0]; + if(obj.success) + e.innerHTML = "command received"; + else + e.innerHTML = "Error: " + obj["error"]; + } + + function updatePwrAck(obj) { + if(!obj.ack) + return; + var e = document.getElementsByName("pwrres")[0]; + clearInterval(tPwrAck); + if(null == e) + return; + e.innerHTML = "inverter acknowledged active power control command"; + } + function parse(obj) { if(null != obj) { parseGeneric(obj["generic"]); From 50ca076f55d0697c3da526de9d65a1ea52de70da Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 2 Oct 2023 10:45:48 +0200 Subject: [PATCH 131/267] 0.7.65 * MI control command review #1197 --- src/CHANGES.md | 3 +++ src/defines.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 1cc2f00a..1b6ec262 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.7.65 - 2023-10-02 +* MI control command review #1197 + ## 0.7.64 - 2023-10-02 * moved active power control to modal in `live` view (per inverter) by click on current APC state diff --git a/src/defines.h b/src/defines.h index ac96ff43..f5543752 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 7 -#define VERSION_PATCH 64 +#define VERSION_PATCH 65 //------------------------------------- typedef struct { From 3e9d6b89003e9032d473f89434d75a9506d2c2a4 Mon Sep 17 00:00:00 2001 From: lumapu Date: Wed, 4 Oct 2023 22:16:32 +0200 Subject: [PATCH 132/267] 0.7.66 - 2023-10-04 * prepared PA-Level for CMT * removed settings for number of retransmits, its fixed to `5` now * added parentheses to have a excactly defined behaviour --- src/CHANGES.md | 5 ++++ src/app.cpp | 4 +-- src/config/config.h | 5 +--- src/config/settings.h | 4 --- src/defines.h | 2 +- src/hm/hmPayload.h | 4 +-- src/hm/miPayload.h | 4 +-- src/hm/radio.h | 4 +-- src/hms/cmt2300a.h | 64 +++++++++++++++++++++++++++++++++++++++-- src/web/RestApi.h | 1 - src/web/html/setup.html | 6 ++-- src/web/web.h | 2 -- 12 files changed, 80 insertions(+), 25 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 1b6ec262..2afb1ece 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,10 @@ # Development Changes +## 0.7.66 - 2023-10-04 +* prepared PA-Level for CMT +* removed settings for number of retransmits, its fixed to `5` now +* added parentheses to have a excactly defined behaviour + ## 0.7.65 - 2023-10-02 * MI control command review #1197 diff --git a/src/app.cpp b/src/app.cpp index 478cd1e5..84423d4c 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -71,11 +71,11 @@ void app::setup() { }); } - mPayload.setup(this, &mSys, mConfig->nrf.maxRetransPerPyld, &mTimestamp); + mPayload.setup(this, &mSys, &mTimestamp); mPayload.enableSerialDebug(mConfig->serial.debug); mPayload.addPayloadListener(std::bind(&app::payloadEventListener, this, std::placeholders::_1, std::placeholders::_2)); if (mConfig->nrf.enabled) { - mMiPayload.setup(this, &mSys, mConfig->nrf.maxRetransPerPyld, &mTimestamp); + mMiPayload.setup(this, &mSys, &mTimestamp); mMiPayload.enableSerialDebug(mConfig->serial.debug); mMiPayload.addPayloadListener(std::bind(&app::payloadEventListener, this, std::placeholders::_1, std::placeholders::_2)); } diff --git a/src/config/config.h b/src/config/config.h index 445fe35e..da027fd6 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -149,7 +149,7 @@ #define SERIAL_INTERVAL 5 // default send interval -#define SEND_INTERVAL 30 +#define SEND_INTERVAL 15 // maximum human readable inverter name length #define MAX_NAME_LENGTH 16 @@ -160,9 +160,6 @@ // maximum total payload buffers (must be greater than the number of received frame fragments) #define MAX_PAYLOAD_ENTRIES 10 -// maximum requests for retransmits per payload (per inverter) -#define DEF_MAX_RETRANS_PER_PYLD 5 - // number of seconds since last successful response, before inverter is marked inactive #define INVERTER_INACT_THRES_SEC 5*60 diff --git a/src/config/settings.h b/src/config/settings.h index a6100d99..0771c148 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -82,7 +82,6 @@ typedef struct { typedef struct { bool enabled; uint16_t sendInterval; - uint8_t maxRetransPerPyld; uint8_t pinCs; uint8_t pinCe; uint8_t pinIrq; @@ -385,7 +384,6 @@ class settings { snprintf(mCfg.sys.deviceName, DEVNAME_LEN, DEF_DEVICE_NAME); mCfg.nrf.sendInterval = SEND_INTERVAL; - mCfg.nrf.maxRetransPerPyld = DEF_MAX_RETRANS_PER_PYLD; mCfg.nrf.pinCs = DEF_NRF_CS_PIN; mCfg.nrf.pinCe = DEF_NRF_CE_PIN; mCfg.nrf.pinIrq = DEF_NRF_IRQ_PIN; @@ -502,7 +500,6 @@ class settings { void jsonNrf(JsonObject obj, bool set = false) { if(set) { obj[F("intvl")] = mCfg.nrf.sendInterval; - obj[F("maxRetry")] = mCfg.nrf.maxRetransPerPyld; obj[F("cs")] = mCfg.nrf.pinCs; obj[F("ce")] = mCfg.nrf.pinCe; obj[F("irq")] = mCfg.nrf.pinIrq; @@ -513,7 +510,6 @@ class settings { obj[F("en")] = (bool) mCfg.nrf.enabled; } else { getVal(obj, F("intvl"), &mCfg.nrf.sendInterval); - getVal(obj, F("maxRetry"), &mCfg.nrf.maxRetransPerPyld); getVal(obj, F("cs"), &mCfg.nrf.pinCs); getVal(obj, F("ce"), &mCfg.nrf.pinCe); getVal(obj, F("irq"), &mCfg.nrf.pinIrq); diff --git a/src/defines.h b/src/defines.h index f5543752..c7d5700a 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 7 -#define VERSION_PATCH 65 +#define VERSION_PATCH 66 //------------------------------------- typedef struct { diff --git a/src/hm/hmPayload.h b/src/hm/hmPayload.h index 0efa28a4..13f4edd5 100644 --- a/src/hm/hmPayload.h +++ b/src/hm/hmPayload.h @@ -44,10 +44,10 @@ class HmPayload { public: HmPayload() {} - void setup(IApp *app, HMSYSTEM *sys, uint8_t maxRetransmits, uint32_t *timestamp) { + void setup(IApp *app, HMSYSTEM *sys, uint32_t *timestamp) { mApp = app; mSys = sys; - mMaxRetrans = maxRetransmits; + mMaxRetrans = 5; mTimestamp = timestamp; for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { reset(i); diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index 32b16696..94f7a9b3 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -44,10 +44,10 @@ class MiPayload { public: MiPayload() {} - void setup(IApp *app, HMSYSTEM *sys, uint8_t maxRetransmits, uint32_t *timestamp) { + void setup(IApp *app, HMSYSTEM *sys, uint32_t *timestamp) { mApp = app; mSys = sys; - mMaxRetrans = maxRetransmits; + mMaxRetrans = 5; mTimestamp = timestamp; for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { reset(i, false, true); diff --git a/src/hm/radio.h b/src/hm/radio.h index 5f95fc8a..e2112586 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -66,9 +66,9 @@ class Radio { void updateCrcs(uint8_t *len, bool appendCrc16=true) { // append crc's - if (appendCrc16 && (*len > 10)) { + if (appendCrc16 && ((*len) > 10)) { // crc control data - uint16_t crc = ah::crc16(&mTxBuf[10], *len - 10); + uint16_t crc = ah::crc16(&mTxBuf[10], (*len) - 10); mTxBuf[(*len)++] = (crc >> 8) & 0xff; mTxBuf[(*len)++] = (crc ) & 0xff; } diff --git a/src/hms/cmt2300a.h b/src/hms/cmt2300a.h index a4308519..9d00ba20 100644 --- a/src/hms/cmt2300a.h +++ b/src/hms/cmt2300a.h @@ -25,6 +25,10 @@ #define CMT2300A_MASK_CHIP_MODE_STA 0x0F #define CMT2300A_CUS_CMT10 0x09 +#define CMT2300A_CUS_TX5 0x59 +#define CMT2300A_CUS_TX8 0x5C +#define CMT2300A_CUS_TX9 0x5D +#define CMT2300A_CUS_TX10 0x5E #define CMT2300A_CUS_MODE_CTL 0x60 // [7] go_switch // [6] go_tx @@ -153,6 +157,42 @@ #define CMT2300A_MASK_TX_DONE_FLG 0x08 #define CMT2300A_MASK_PKT_OK_FLG 0x01 +// this list and the TX5, TX10 registers were compiled from the output of +// HopeRF RFPDK Tool v1.54 +static uint8_t paLevelList[31][2] PROGMEM = { + {0x17, 0x01}, // -10dBm + {0x1a, 0x01}, // -09dBm + {0x1d, 0x01}, // -08dBm + {0x21, 0x01}, // -07dBm + {0x25, 0x01}, // -06dBm + {0x29, 0x01}, // -05dBm + {0x2d, 0x01}, // -04dBm + {0x33, 0x01}, // -03dBm + {0x39, 0x02}, // -02dBm + {0x41, 0x02}, // -01dBm + {0x4b, 0x02}, // 00dBm + {0x56, 0x03}, // 01dBm + {0x63, 0x03}, // 02dBm + {0x71, 0x04}, // 03dBm + {0x80, 0x04}, // 04dBm + {0x22, 0x01}, // 05dBm + {0x27, 0x04}, // 06dBm + {0x2c, 0x05}, // 07dBm + {0x31, 0x06}, // 08dBm + {0x38, 0x06}, // 09dBm + {0x3f, 0x07}, // 10dBm + {0x48, 0x08}, // 11dBm + {0x52, 0x09}, // 12dBm + {0x5d, 0x0b}, // 13dBm + {0x6a, 0x0c}, // 14dBm + {0x79, 0x0d}, // 15dBm + {0x46, 0x10}, // 16dBm + {0x51, 0x10}, // 17dBm + {0x60, 0x12}, // 18dBm + {0x71, 0x14}, // 19dBm + {0x8c, 0x1c} // 20dBm +}; + // default CMT parameters static uint8_t cmtConfig[0x60] PROGMEM { // 0x00 - 0x0f -- RSSI offset +- 0 and 13dBm @@ -168,11 +208,11 @@ static uint8_t cmtConfig[0x60] PROGMEM { 0x10, 0x00, 0xB4, 0x00, 0x00, 0x01, 0x00, 0x00, 0x12, 0x1E, 0x00, 0xAA, 0x06, 0x00, 0x00, 0x00, // 0x40 - 0x4f - 0x00, 0x48, 0x5A, 0x48, 0x4D, 0x01, 0x1D, 0x00, + 0x00, 0x48, 0x5A, 0x48, 0x4D, 0x01, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x60, // 0x50 - 0x5f 0xFF, 0x00, 0x00, 0x1F, 0x10, 0x70, 0x4D, 0x06, - 0x00, 0x07, 0x50, 0x00, 0x42, 0x0C, 0x3F, 0x7F // - TX 13dBm + 0x00, 0x07, 0x50, 0x00, 0x5D, 0x0B, 0x3F, 0x7F // - TX 13dBm }; @@ -391,6 +431,26 @@ class Cmt2300a { return HOY_BASE_FREQ_KHZ + (mCurCh * FREQ_STEP_KHZ); } + void setPaLevel(int8_t level) { + if(level < -10) + level = -10; + if(level > 20) + level = 20; + + level += 10; // unsigned value + + if(level >= 15) { + mSpi.writeReg(CMT2300A_CUS_TX5, 0x07); + mSpi.writeReg(CMT2300A_CUS_TX10, 0x3f); + } else { + mSpi.writeReg(CMT2300A_CUS_TX5, 0x13); + mSpi.writeReg(CMT2300A_CUS_TX10, 0x18); + } + + mSpi.writeReg(CMT2300A_CUS_TX8, paLevelList[level][0]); + mSpi.writeReg(CMT2300A_CUS_TX9, paLevelList[level][1]); + } + private: void init() { mTxPending = false; diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 39c97532..225c26c8 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -356,7 +356,6 @@ class RestApi { } } obj[F("interval")] = String(mConfig->nrf.sendInterval); - obj[F("retries")] = String(mConfig->nrf.maxRetransPerPyld); obj[F("max_num_inverters")] = MAX_NUM_INVERTERS; obj[F("rstMid")] = (bool)mConfig->inst.rstYieldMidNight; obj[F("rstNotAvail")] = (bool)mConfig->inst.rstValsNotAvail; diff --git a/src/web/html/setup.html b/src/web/html/setup.html index d58aa226..b9697141 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -30,7 +30,7 @@
System Config -

Pinout

+

Status LEDs

Radio (NRF24L01+)

@@ -736,11 +736,11 @@ function parsePinout(obj, type, system) { var e = document.getElementById("pinout"); - pins = [['led0', 'pinLed0'], ['led1', 'pinLed1']]; + pins = [['led0', 'pinLed0', 'At least one inverter is producing'], ['led1', 'pinLed1', 'MqTT connected']]; for(p of pins) { e.append( ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-12 col-sm-3 my-2"}, p[0].toUpperCase()), + ml("div", {class: "col-12 col-sm-3 my-2"}, p[2]), ml("div", {class: "col-12 col-sm-9"}, sel(p[1], ("ESP8266" == type) ? esp8266pins : ("ESP32-S3" == system["chip_model"]) ? esp32s3pins : esp32pins, obj[p[0]]) ) diff --git a/src/web/web.h b/src/web/web.h index 99dd5924..fabbd604 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -527,8 +527,6 @@ class Web { if (request->arg("invInterval") != "") mConfig->nrf.sendInterval = request->arg("invInterval").toInt(); - if (request->arg("invRetry") != "") - mConfig->nrf.maxRetransPerPyld = request->arg("invRetry").toInt(); mConfig->inst.rstYieldMidNight = (request->arg("invRstMid") == "on"); mConfig->inst.rstValsCommStop = (request->arg("invRstComStop") == "on"); mConfig->inst.rstValsNotAvail = (request->arg("invRstNotAvail") == "on"); From 5a81a54738b3f1ec1231e4130520e256b843eeb7 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 9 Oct 2023 23:59:04 +0200 Subject: [PATCH 133/267] started to improve communication (from scratch) --- src/app.cpp | 25 +++++--- src/app.h | 8 +++ src/defines.h | 1 + src/hm/CommQueue.h | 87 +++++++++++++++++++++++++++ src/hm/Communication.h | 129 +++++++++++++++++++++++++++++++++++++++++ src/hm/hmRadio.h | 2 - src/hm/radio.h | 4 ++ src/hms/hmsRadio.h | 2 - 8 files changed, 246 insertions(+), 12 deletions(-) create mode 100644 src/hm/CommQueue.h create mode 100644 src/hm/Communication.h diff --git a/src/app.cpp b/src/app.cpp index 84423d4c..a834d091 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -59,26 +59,29 @@ void app::setup() { #endif #endif /* defined(ETHERNET) */ + mCommunication.setup(&mTimestamp); mSys.setup(&mTimestamp, &mConfig->inst); for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { mSys.addInverter(i, [this](Inverter<> *iv) { + // will be only called for valid inverters if((IV_MI == iv->ivGen) || (IV_HM == iv->ivGen)) iv->radio = &mNrfRadio; #if defined(ESP32) else if((IV_HMS == iv->ivGen) || (IV_HMT == iv->ivGen)) iv->radio = &mCmtRadio; #endif + mCommunication.add(iv, 0x01, false); }); } - mPayload.setup(this, &mSys, &mTimestamp); + /*mPayload.setup(this, &mSys, &mTimestamp); mPayload.enableSerialDebug(mConfig->serial.debug); mPayload.addPayloadListener(std::bind(&app::payloadEventListener, this, std::placeholders::_1, std::placeholders::_2)); if (mConfig->nrf.enabled) { mMiPayload.setup(this, &mSys, &mTimestamp); mMiPayload.enableSerialDebug(mConfig->serial.debug); mMiPayload.addPayloadListener(std::bind(&app::payloadEventListener, this, std::placeholders::_1, std::placeholders::_2)); - } + }*/ if(mConfig->nrf.enabled) { if (!mNrfRadio.isChipConnected()) @@ -91,8 +94,8 @@ void app::setup() { if (mMqttEnabled) { mMqtt.setup(&mConfig->mqtt, mConfig->sys.deviceName, mVersion, &mSys, &mTimestamp, &mUptime); mMqtt.setSubscriptionCb(std::bind(&app::mqttSubRxCb, this, std::placeholders::_1)); - mPayload.addAlarmListener([this](Inverter<> *iv) { mMqtt.alarmEvent(iv); }); - mMiPayload.addAlarmListener([this](Inverter<> *iv) { mMqtt.alarmEvent(iv); }); + //mPayload.addAlarmListener([this](Inverter<> *iv) { mMqtt.alarmEvent(iv); }); + //mMiPayload.addAlarmListener([this](Inverter<> *iv) { mMqtt.alarmEvent(iv); }); } #endif setupLed(); @@ -103,8 +106,10 @@ void app::setup() { mApi.setup(this, &mSys, mWeb.getWebSrvPtr(), mConfig); // Plugins + #if defined(PLUGIN_DISPLAY) if (mConfig->plugin.display.type != 0) mDisplay.setup(this, &mConfig->plugin.display, &mSys, &mNrfRadio, &mTimestamp); + #endif mPubSerial.setup(mConfig, &mSys, &mTimestamp); @@ -120,7 +125,9 @@ void app::loop(void) { ah::Scheduler::loop(); bool processPayload = false; - if (mNrfRadio.loop() && mConfig->nrf.enabled) { + mCommunication.loop(); + + /*if (mNrfRadio.loop() && mConfig->nrf.enabled) { while (!mNrfRadio.mBufCtrl.empty()) { packet_t *p = &mNrfRadio.mBufCtrl.front(); if (mConfig->serial.debug) { @@ -178,7 +185,7 @@ void app::loop(void) { mPayload.process(true); mPayload.loop(); - mMiPayload.loop(); + mMiPayload.loop();*/ if (mMqttEnabled && mNetworkConnected) mMqtt.loop(); @@ -208,8 +215,10 @@ void app::regularTickers(void) { DPRINTLN(DBG_DEBUG, F("regularTickers")); everySec(std::bind(&WebType::tickSecond, &mWeb), "webSc"); // Plugins + #if defined(PLUGIN_DISPLAY) if (mConfig->plugin.display.type != 0) everySec(std::bind(&DisplayType::tickerSecond, &mDisplay), "disp"); + #endif every(std::bind(&PubSerialType::tick, &mPubSerial), mConfig->serial.interval, "uart"); #if !defined(ETHERNET) //everySec([this]() { mImprov.tickSerial(); }, "impro"); @@ -391,7 +400,7 @@ void app::tickMidnight(void) { //----------------------------------------------------------------------------- void app::tickSend(void) { - if(mConfig->nrf.enabled) { + /*if(mConfig->nrf.enabled) { if(!mNrfRadio.isChipConnected()) { DPRINTLN(DBG_WARN, F("NRF24 not connected!")); } @@ -437,7 +446,7 @@ void app::tickSend(void) { if (mConfig->serial.debug) DPRINTLN(DBG_WARN, F("Time not set or it is night time, therefore no communication to the inverter!")); } - yield(); + yield();*/ updateLed(); } diff --git a/src/app.h b/src/app.h index ac516302..9cc90100 100644 --- a/src/app.h +++ b/src/app.h @@ -25,6 +25,7 @@ #include "utils/scheduler.h" #include "web/RestApi.h" #include "web/web.h" +#include "hm/Communication.h" #if defined(ETHERNET) #include "eth/ahoyeth.h" #else /* defined(ETHERNET) */ @@ -52,9 +53,11 @@ typedef PubMqtt PubMqttType; typedef PubSerial PubSerialType; // PLUGINS +#if defined(PLUGIN_DISPLAY) #include "plugins/Display/Display.h" #include "plugins/Display/Display_data.h" typedef Display> DisplayType; +#endif class app : public IApp, public ah::Scheduler { public: @@ -258,8 +261,10 @@ class app : public IApp, public ah::Scheduler { if (mMqttEnabled) mMqtt.payloadEventListener(cmd, iv); #endif + #if defined(PLUGIN_DISPLAY) if(mConfig->plugin.display.type != 0) mDisplay.payloadEventListener(cmd); + #endif updateLed(); } @@ -302,6 +307,7 @@ class app : public IApp, public ah::Scheduler { HmSystemType mSys; HmRadio<> mNrfRadio; + Communication mCommunication; bool mShowRebootRequest; bool mIVCommunicationOn; @@ -344,8 +350,10 @@ class app : public IApp, public ah::Scheduler { uint32_t mSunrise, mSunset; // plugins + #if defined(PLUGIN_DISPLAY) DisplayType mDisplay; DisplayData mDispData; + #endif }; #endif /*__APP_H__*/ diff --git a/src/defines.h b/src/defines.h index c7d5700a..860231ba 100644 --- a/src/defines.h +++ b/src/defines.h @@ -21,6 +21,7 @@ typedef struct { uint8_t len; int8_t rssi; uint8_t packet[MAX_RF_PAYLOAD_SIZE]; + //uint32_t millis; } packet_t; typedef enum { diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h new file mode 100644 index 00000000..3f0e2da8 --- /dev/null +++ b/src/hm/CommQueue.h @@ -0,0 +1,87 @@ +//----------------------------------------------------------------------------- +// 2023 Ahoy, https://github.com/lumpapu/ahoy +// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed +//----------------------------------------------------------------------------- + +#ifndef __COMM_QUEUE_H__ +#define __COMM_QUEUE_H__ + +#include +#include +#include "hmInverter.h" + +template +class CommQueue { + public: + CommQueue() {} + + void addImportant(Inverter<> *iv, uint8_t cmd, bool delIfFailed = true) { + dec(&mRdPtr); + mQueue[mRdPtr] = queue_s(iv, cmd, delIfFailed); + } + + void add(Inverter<> *iv, uint8_t cmd, bool delIfFailed = true) { + mQueue[mWrPtr] = queue_s(iv, cmd, delIfFailed); + inc(&mWrPtr); + } + + protected: + struct queue_s { + Inverter<> *iv; + uint8_t cmd; + uint8_t attempts; + bool delIfFailed; + bool done; + uint32_t ts; + queue_s() {} + queue_s(Inverter<> *i, uint8_t c, bool d) : + iv(i), cmd(c), attempts(5), done(false), ts(0), delIfFailed(d) {} + }; + + protected: + void add(queue_s q) { + mQueue[mWrPtr] = q; + inc(&mWrPtr); + } + + void get(std::function cb) { + if(mRdPtr == mWrPtr) { + cb(false, &mQueue[mRdPtr]); // empty + return; + } + cb(true, &mQueue[mRdPtr]); + } + + void pop(void) { + if(!mQueue[mRdPtr].delIfFailed) + add(mQueue[mRdPtr]); // add to the end again + inc(&mRdPtr); + } + + void setTs(uint32_t *ts) { + mQueue[mRdPtr].ts = *ts; + } + + void setDone(void) { + mQueue[mRdPtr].done = true; + } + + void inc(uint8_t *ptr) { + if(++(*ptr) >= N) + *ptr = 0; + } + void dec(uint8_t *ptr) { + if((*ptr) == 0) + *ptr = N-1; + else + --(*ptr); + } + + protected: + std::array mQueue; + uint8_t mWrPtr = 0; + uint8_t mRdPtr = 0; +}; + + +#endif /*__COMM_QUEUE_H__*/ diff --git a/src/hm/Communication.h b/src/hm/Communication.h new file mode 100644 index 00000000..1d165186 --- /dev/null +++ b/src/hm/Communication.h @@ -0,0 +1,129 @@ +//----------------------------------------------------------------------------- +// 2023 Ahoy, https://github.com/lumpapu/ahoy +// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed +//----------------------------------------------------------------------------- + +#ifndef __COMMUNICATION_H__ +#define __COMMUNICATION_H__ + +#include "CommQueue.h" +#include +#include "../utils/crc.h" + +class Communication : public CommQueue<> { + public: + void setup(uint32_t *timestamp) { + mTimestamp = timestamp; + } + + void loop() { + get([this](bool valid, const queue_s *q) { + if(!valid) + return; // empty + + switch(mState) { + case States::IDLE: + setTs(mTimestamp); + q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); + lastMillis = millis(); + lastFound = false; + mState = States::WAIT; + break; + + case States::WAIT: + if((millis()-lastMillis) < 500) + return; + mState = States::CHECK_FRAMES; + break; + + case States::CHECK_FRAMES: + if(!q->iv->radio->loop()) + break; // radio buffer empty + + while(!q->iv->radio->mBufCtrl.empty()) { + packet_t *p = &q->iv->radio->mBufCtrl.front(); + q->iv->radio->mBufCtrl.pop(); + + if(!checkIvSerial(&p->packet[1], q->iv)) + continue; // inverter ID incorrect + + q->iv->radioStatistics.frmCnt++; + + if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) // response from get information command + parseFrame(p); + else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) // response from dev control command + parseDevCtrl(p); + + yield(); + } + break; + } + }); + } + + void gotData() { + setDone(); + } + + private: + inline bool checkIvSerial(uint8_t buf[], Inverter<> *iv) { + uint8_t tmp[4]; + CP_U32_BigEndian(tmp, iv->radioId.u64 >> 8); + for(uint8_t i = 0; i < 4; i++) { + if(tmp[i] != buf[i]) + return false; + } + return true; + } + + inline bool checkFrameCrc(uint8_t buf[], uint8_t len) { + return (ah::crc8(buf, len - 1) == buf[len-1]); + } + + inline void parseFrame(packet_t *p) { + uint8_t *frameId = &p->packet[9]; + if(0x00 == *frameId) + return; // skip current packet + if((*frameId & 0x7f) > MAX_PAYLOAD_ENTRIES) + return; // local storage is to small for id + + if(!checkFrameCrc(p->packet, p->len)) + return; // CRC8 is wrong, frame invalid + + if((*frameId & ALL_FRAMES) == ALL_FRAMES) { + maxFrameId = (*frameId & 0x7f); + if(*frameId > 0x81) + lastFound = true; + } + + frame_t *f = &mLocalBuf[(*frameId & 0x7f) - 1]; + memcpy(f->buf, &p->packet[10], p->len-11); + f->len = p->len - 11; + f->rssi = p->rssi; + } + + inline void parseDevCtrl(packet_t *p) { + //if((p->packet[12] == ActivePowerContr) && (p->packet[13] == 0x00)) + } + + private: + enum class States : uint8_t { + IDLE, WAIT, CHECK_FRAMES + }; + + typedef struct { + uint8_t buf[MAX_RF_PAYLOAD_SIZE]; + uint8_t len; + int8_t rssi; + } frame_t; + + private: + States mState = States::IDLE; + uint32_t *mTimestamp; + uint32_t lastMillis; + std::array mLocalBuf; + bool lastFound; + uint8_t maxFrameId; +}; + +#endif /*__COMMUNICATION_H__*/ diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index a3368c0f..45278e6b 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -238,8 +238,6 @@ class HmRadio : public Radio { return mNrf24.isPVariant(); } - std::queue mBufCtrl; - private: inline bool getReceived(void) { bool tx_ok, tx_fail, rx_ready; diff --git a/src/hm/radio.h b/src/hm/radio.h index e2112586..8e9f5ef4 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -23,6 +23,7 @@ class Radio { public: virtual void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit, bool isNoMI = true, uint16_t powerMax = 0) = 0; virtual bool switchFrequency(Inverter<> *iv, uint32_t fromkHz, uint32_t tokHz) { return true; } + virtual bool loop(void) = 0; void handleIntr(void) { mIrqRcvd = true; @@ -52,6 +53,9 @@ class Radio { sendPacket(iv, 24, isRetransmit); } + public: + std::queue mBufCtrl; + protected: virtual void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) = 0; virtual uint64_t getIvId(Inverter<> *iv) = 0; diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index 42eee1bc..5cee324b 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -78,8 +78,6 @@ class CmtRadio : public Radio { return true; } - std::queue mBufCtrl; - private: void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) { updateCrcs(&len, appendCrc16); From c7f3f21469869bee4ec8d74854952eeaf29d4452 Mon Sep 17 00:00:00 2001 From: lumapu Date: Tue, 10 Oct 2023 23:53:59 +0200 Subject: [PATCH 134/267] further improved new communication model --- src/app.cpp | 4 +- src/hm/CommQueue.h | 24 ++++--- src/hm/Communication.h | 149 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 147 insertions(+), 30 deletions(-) diff --git a/src/app.cpp b/src/app.cpp index a834d091..684914e2 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -70,7 +70,9 @@ void app::setup() { else if((IV_HMS == iv->ivGen) || (IV_HMT == iv->ivGen)) iv->radio = &mCmtRadio; #endif - mCommunication.add(iv, 0x01, false); + mCommunication.add(iv, 0x01); + mCommunication.add(iv, 0x05); + mCommunication.add(iv, 0x0b); }); } diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index 3f0e2da8..d9745eb1 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -15,13 +15,13 @@ class CommQueue { public: CommQueue() {} - void addImportant(Inverter<> *iv, uint8_t cmd, bool delIfFailed = true) { + void addImportant(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) { dec(&mRdPtr); - mQueue[mRdPtr] = queue_s(iv, cmd, delIfFailed); + mQueue[mRdPtr] = queue_s(iv, cmd, delOnPop); } - void add(Inverter<> *iv, uint8_t cmd, bool delIfFailed = true) { - mQueue[mWrPtr] = queue_s(iv, cmd, delIfFailed); + void add(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) { + mQueue[mWrPtr] = queue_s(iv, cmd, delOnPop); inc(&mWrPtr); } @@ -30,12 +30,11 @@ class CommQueue { Inverter<> *iv; uint8_t cmd; uint8_t attempts; - bool delIfFailed; - bool done; + bool delOnPop; uint32_t ts; queue_s() {} queue_s(Inverter<> *i, uint8_t c, bool d) : - iv(i), cmd(c), attempts(5), done(false), ts(0), delIfFailed(d) {} + iv(i), cmd(c), attempts(5), ts(0), delOnPop(d) {} }; protected: @@ -52,9 +51,11 @@ class CommQueue { cb(true, &mQueue[mRdPtr]); } - void pop(void) { - if(!mQueue[mRdPtr].delIfFailed) + void pop(bool force = false) { + if(!mQueue[mRdPtr].delOnPop && !force) { + mQueue[mRdPtr].attempts = 5; add(mQueue[mRdPtr]); // add to the end again + } inc(&mRdPtr); } @@ -62,8 +63,9 @@ class CommQueue { mQueue[mRdPtr].ts = *ts; } - void setDone(void) { - mQueue[mRdPtr].done = true; + void setAttempt(void) { + if(mQueue[mRdPtr].attempts) + mQueue[mRdPtr].attempts--; } void inc(uint8_t *ptr) { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 1d165186..65dd2d5c 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -22,49 +22,106 @@ class Communication : public CommQueue<> { return; // empty switch(mState) { - case States::IDLE: + case States::RESET: + lastFound = false; + for(uint8_t i = 0; i < MAX_PAYLOAD_ENTRIES; i++) { + mLocalBuf[i].len = 0; + } + mState = States::START; + break; + + case States::START: setTs(mTimestamp); q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); - lastMillis = millis(); - lastFound = false; + mWaitTimeout = millis() + 500; + setAttempt(); mState = States::WAIT; break; case States::WAIT: - if((millis()-lastMillis) < 500) + if(millis() < mWaitTimeout) return; mState = States::CHECK_FRAMES; break; - case States::CHECK_FRAMES: - if(!q->iv->radio->loop()) + case States::CHECK_FRAMES: { + if(!q->iv->radio->loop()) { + pop(); + q->iv->radioStatistics.rxFailNoAnser++; // got nothing + mState = States::RESET; break; // radio buffer empty + } + States nextState = States::RESET; while(!q->iv->radio->mBufCtrl.empty()) { packet_t *p = &q->iv->radio->mBufCtrl.front(); q->iv->radio->mBufCtrl.pop(); + DPRINT_IVID(DBG_INFO, q->iv->id); + DPRINT(DBG_INFO, F("RX ")); + DBGPRINT(String(p->len)); + DBGPRINT(F(" CH")); + DBGPRINT(String(p->ch)); + DBGPRINT(F(", ")); + DBGPRINT(String(p->rssi)); + DBGPRINT(F("dBm | ")); + ah::dumpBuf(p->packet, p->len); + if(!checkIvSerial(&p->packet[1], q->iv)) continue; // inverter ID incorrect q->iv->radioStatistics.frmCnt++; - if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) // response from get information command + if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command parseFrame(p); - else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) // response from dev control command + nextState = States::CHECK_PACKAGE; + } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) // response from dev control command parseDevCtrl(p); yield(); } + mState = nextState; + } + break; + + case States::CHECK_PACKAGE: + if(!lastFound) { + DPRINT_IVID(DBG_WARN, q->iv->id); + DBGPRINT(F("last frame ")); + DBGPRINT(String(mMaxFrameId+1)); + DBGPRINTLN(F(" missing: Request Retransmit")); + + q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + mMaxFrameId + 1), true); + setAttempt(); + mWaitTimeout = millis() + 100; + mState = States::WAIT; + break; + } + + for(uint8_t i = 0; i < mMaxFrameId; i++) { + if(mLocalBuf[i].len == 0) { + DPRINT_IVID(DBG_WARN, q->iv->id); + DBGPRINT(F("frame ")); + DBGPRINT(String(i + 1)); + DBGPRINTLN(F(" missing: Request Retransmit")); + + q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true); + setAttempt(); + mWaitTimeout = millis() + 100; + mState = States::WAIT; + return; + } + } + + compilePayload(q); + + pop(true); // remove done request + mState = States::RESET; // everything ok, next request break; } }); } - void gotData() { - setDone(); - } - private: inline bool checkIvSerial(uint8_t buf[], Inverter<> *iv) { uint8_t tmp[4]; @@ -84,14 +141,16 @@ class Communication : public CommQueue<> { uint8_t *frameId = &p->packet[9]; if(0x00 == *frameId) return; // skip current packet - if((*frameId & 0x7f) > MAX_PAYLOAD_ENTRIES) + if((*frameId & 0x7f) > MAX_PAYLOAD_ENTRIES) { + DPRINTLN(DBG_WARN, F("local buffer to small for payload fragments!")); return; // local storage is to small for id + } if(!checkFrameCrc(p->packet, p->len)) return; // CRC8 is wrong, frame invalid if((*frameId & ALL_FRAMES) == ALL_FRAMES) { - maxFrameId = (*frameId & 0x7f); + mMaxFrameId = (*frameId & 0x7f); if(*frameId > 0x81) lastFound = true; } @@ -106,9 +165,62 @@ class Communication : public CommQueue<> { //if((p->packet[12] == ActivePowerContr) && (p->packet[13] == 0x00)) } + inline void compilePayload(const queue_s *q) { + uint16_t crc = 0xffff, crcRcv = 0x0000; + for(uint8_t i = 0; i < mMaxFrameId; i++) { + if(i == (mMaxFrameId - 1)) { + crc = ah::crc16(mLocalBuf[i].buf, mLocalBuf[i].len - 2, crc); + crcRcv = (mLocalBuf[i].buf[mLocalBuf[i].len-2] << 8); + crcRcv |= mLocalBuf[i].buf[mLocalBuf[i].len-1]; + } else + crc = ah::crc16(mLocalBuf[i].buf, mLocalBuf[i].len, crc); + } + + if(crc != crcRcv) { + DPRINT_IVID(DBG_WARN, q->iv->id); + DBGPRINT(F("CRC Error ")); + if(q->attempts == 0) { + DBGPRINTLN(F("-> Fail")); + q->iv->radioStatistics.rxFail++; // got fragments but not complete response + pop(); + } else + DBGPRINTLN(F("-> complete retransmit")); + mState = States::RESET; + return; + } + + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("procPyld: cmd: 0x")); + DBGHEXLN(q->cmd); + + memset(mPayload, 0, 150); + int8_t rssi = -127; + uint8_t len = 0; + + for(uint8_t i = 0; i < mMaxFrameId; i++) { + if(mLocalBuf[i].len + len > 150) { + DPRINTLN(DBG_ERROR, F("payload buffer to small!")); + return; + } + memcpy(&mPayload[len], mLocalBuf[i].buf, mLocalBuf[i].len); + len += mLocalBuf[i].len; + // get worst RSSI + if(mLocalBuf[i].rssi > rssi) + rssi = mLocalBuf[i].rssi; + } + + len -= 2; + + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("Payload (")); + DBGPRINT(String(len)); + DBGPRINT(F("): ")); + ah::dumpBuf(mPayload, len); + } + private: enum class States : uint8_t { - IDLE, WAIT, CHECK_FRAMES + RESET, START, WAIT, CHECK_FRAMES, CHECK_PACKAGE }; typedef struct { @@ -118,12 +230,13 @@ class Communication : public CommQueue<> { } frame_t; private: - States mState = States::IDLE; + States mState = States::RESET; uint32_t *mTimestamp; - uint32_t lastMillis; + uint32_t mWaitTimeout; std::array mLocalBuf; bool lastFound; - uint8_t maxFrameId; + uint8_t mMaxFrameId; + uint8_t mPayload[150]; }; #endif /*__COMMUNICATION_H__*/ From b34e5a7416d0dde8764434b8f7afa9f8ef108556 Mon Sep 17 00:00:00 2001 From: lumapu Date: Wed, 11 Oct 2023 21:07:03 +0200 Subject: [PATCH 135/267] added millis to each packet for radio analysis fixed several issue regarding communication --- src/app.cpp | 27 +++++++++++---- src/app.h | 6 ++-- src/defines.h | 2 +- src/hm/CommQueue.h | 2 +- src/hm/Communication.h | 79 ++++++++++++++++++++++++------------------ src/hm/hmRadio.h | 11 +++--- src/hm/radio.h | 6 +++- src/hms/hmsRadio.h | 12 +++---- 8 files changed, 89 insertions(+), 56 deletions(-) diff --git a/src/app.cpp b/src/app.cpp index 684914e2..2255aa14 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -70,9 +70,6 @@ void app::setup() { else if((IV_HMS == iv->ivGen) || (IV_HMT == iv->ivGen)) iv->radio = &mCmtRadio; #endif - mCommunication.add(iv, 0x01); - mCommunication.add(iv, 0x05); - mCommunication.add(iv, 0x0b); }); } @@ -127,6 +124,10 @@ void app::loop(void) { ah::Scheduler::loop(); bool processPayload = false; + mNrfRadio.loop(); + #if defined(ESP32) + mCmtRadio.loop(); + #endif mCommunication.loop(); /*if (mNrfRadio.loop() && mConfig->nrf.enabled) { @@ -199,7 +200,8 @@ void app::onNetwork(bool gotIp) { mNetworkConnected = gotIp; ah::Scheduler::resetTicker(); regularTickers(); //reinstall regular tickers - every(std::bind(&app::tickSend, this), mConfig->nrf.sendInterval, "tSend"); + //every(std::bind(&app::tickSend, this), mConfig->nrf.sendInterval, "tSend"); + once(std::bind(&app::tickSend, this), 20, "tSend"); mMqttReconnect = true; mSunrise = 0; // needs to be set to 0, to reinstall sunrise and ivComm tickers! //once(std::bind(&app::tickNtpUpdate, this), 2, "ntp2"); @@ -290,7 +292,7 @@ void app::tickNtpUpdate(void) { // immediately start communicating if (isOK && mSendFirst) { mSendFirst = false; - once(std::bind(&app::tickSend, this), 2, "senOn"); + //once(std::bind(&app::tickSend, this), 2, "senOn"); } mMqttReconnect = false; @@ -402,6 +404,17 @@ void app::tickMidnight(void) { //----------------------------------------------------------------------------- void app::tickSend(void) { + DPRINTLN(DBG_INFO, "tickSend"); + + for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { + Inverter<> *iv = mSys.getInverterByPos(i); + if(NULL != iv) { + mCommunication.add(iv, 0x01); + mCommunication.add(iv, 0x05); + mCommunication.add(iv, 0x0b, false); + }; + } + /*if(mConfig->nrf.enabled) { if(!mNrfRadio.isChipConnected()) { DPRINTLN(DBG_WARN, F("NRF24 not connected!")); @@ -448,9 +461,9 @@ void app::tickSend(void) { if (mConfig->serial.debug) DPRINTLN(DBG_WARN, F("Time not set or it is night time, therefore no communication to the inverter!")); } - yield();*/ + yield(); - updateLed(); + updateLed();*/ } //----------------------------------------------------------------------------- diff --git a/src/app.h b/src/app.h index 9cc90100..d1a13a6a 100644 --- a/src/app.h +++ b/src/app.h @@ -176,8 +176,8 @@ class app : public IApp, public ah::Scheduler { if(mIVCommunicationOn) { // only send commands if communication is enabled if (iv->ivGen == IV_MI) mMiPayload.ivSendHighPrio(iv); - else - mPayload.ivSendHighPrio(iv); + //else + // mPayload.ivSendHighPrio(iv); } } @@ -319,7 +319,7 @@ class app : public IApp, public ah::Scheduler { #endif /* defined(ETHERNET) */ WebType mWeb; RestApiType mApi; - PayloadType mPayload; + //PayloadType mPayload; MiPayloadType mMiPayload; PubSerialType mPubSerial; #if !defined(ETHERNET) diff --git a/src/defines.h b/src/defines.h index 860231ba..80ecf9c0 100644 --- a/src/defines.h +++ b/src/defines.h @@ -21,7 +21,7 @@ typedef struct { uint8_t len; int8_t rssi; uint8_t packet[MAX_RF_PAYLOAD_SIZE]; - //uint32_t millis; + uint16_t millis; } packet_t; typedef enum { diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index d9745eb1..5f13d03d 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -51,7 +51,7 @@ class CommQueue { cb(true, &mQueue[mRdPtr]); } - void pop(bool force = false) { + void cmdDone(bool force = false) { if(!mQueue[mRdPtr].delOnPop && !force) { mQueue[mRdPtr].attempts = 5; add(mQueue[mRdPtr]); // add to the end again diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 65dd2d5c..ecb28ce0 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -23,7 +23,7 @@ class Communication : public CommQueue<> { switch(mState) { case States::RESET: - lastFound = false; + mMaxFrameId = 0; for(uint8_t i = 0; i < MAX_PAYLOAD_ENTRIES; i++) { mLocalBuf[i].len = 0; } @@ -33,7 +33,7 @@ class Communication : public CommQueue<> { case States::START: setTs(mTimestamp); q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); - mWaitTimeout = millis() + 500; + mWaitTimeout = millis() + 1500; setAttempt(); mState = States::WAIT; break; @@ -45,20 +45,29 @@ class Communication : public CommQueue<> { break; case States::CHECK_FRAMES: { - if(!q->iv->radio->loop()) { - pop(); + if(!q->iv->radio->get()) { // radio buffer empty + cmdDone(); + DBGPRINTLN(F("request timeout")); q->iv->radioStatistics.rxFailNoAnser++; // got nothing - mState = States::RESET; - break; // radio buffer empty + if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { + q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, WORK_FREQ_KHZ); + mWaitTimeout = millis() + 2000; + mState = States::GAP; + break; + } else { + mState = States::RESET; + break; + } } States nextState = States::RESET; while(!q->iv->radio->mBufCtrl.empty()) { packet_t *p = &q->iv->radio->mBufCtrl.front(); - q->iv->radio->mBufCtrl.pop(); DPRINT_IVID(DBG_INFO, q->iv->id); DPRINT(DBG_INFO, F("RX ")); + DBGPRINT(String(p->millis)); + DBGPRINT(F("ms ")); DBGPRINT(String(p->len)); DBGPRINT(F(" CH")); DBGPRINT(String(p->ch)); @@ -67,29 +76,33 @@ class Communication : public CommQueue<> { DBGPRINT(F("dBm | ")); ah::dumpBuf(p->packet, p->len); - if(!checkIvSerial(&p->packet[1], q->iv)) - continue; // inverter ID incorrect - - q->iv->radioStatistics.frmCnt++; + if(checkIvSerial(&p->packet[1], q->iv)) { + q->iv->radioStatistics.frmCnt++; - if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command - parseFrame(p); - nextState = States::CHECK_PACKAGE; - } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) // response from dev control command - parseDevCtrl(p); + if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command + parseFrame(p); + nextState = States::CHECK_PACKAGE; + } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) // response from dev control command + parseDevCtrl(p); + } + q->iv->radio->mBufCtrl.pop(); yield(); } mState = nextState; } break; + case States::GAP: + if(millis() < mWaitTimeout) + return; + mState = States::RESET; + break; + case States::CHECK_PACKAGE: - if(!lastFound) { + if(0 == mMaxFrameId) { DPRINT_IVID(DBG_WARN, q->iv->id); - DBGPRINT(F("last frame ")); - DBGPRINT(String(mMaxFrameId+1)); - DBGPRINTLN(F(" missing: Request Retransmit")); + DBGPRINT(F("last frame missing: request retransmit")); q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + mMaxFrameId + 1), true); setAttempt(); @@ -103,9 +116,9 @@ class Communication : public CommQueue<> { DPRINT_IVID(DBG_WARN, q->iv->id); DBGPRINT(F("frame ")); DBGPRINT(String(i + 1)); - DBGPRINTLN(F(" missing: Request Retransmit")); + DBGPRINTLN(F(" missing: request retransmit")); - q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true); + q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (ALL_FRAMES + i), true); setAttempt(); mWaitTimeout = millis() + 100; mState = States::WAIT; @@ -115,7 +128,7 @@ class Communication : public CommQueue<> { compilePayload(q); - pop(true); // remove done request + cmdDone(true); // remove done request mState = States::RESET; // everything ok, next request break; } @@ -139,21 +152,22 @@ class Communication : public CommQueue<> { inline void parseFrame(packet_t *p) { uint8_t *frameId = &p->packet[9]; - if(0x00 == *frameId) + if(0x00 == *frameId) { + DPRINTLN(DBG_WARN, F("invalid frameId 0x00")); return; // skip current packet + } if((*frameId & 0x7f) > MAX_PAYLOAD_ENTRIES) { - DPRINTLN(DBG_WARN, F("local buffer to small for payload fragments!")); + DPRINTLN(DBG_WARN, F("local buffer to small for payload fragments")); return; // local storage is to small for id } - if(!checkFrameCrc(p->packet, p->len)) + if(!checkFrameCrc(p->packet, p->len)) { + DPRINTLN(DBG_WARN, F("frame CRC is wrong")); return; // CRC8 is wrong, frame invalid + } - if((*frameId & ALL_FRAMES) == ALL_FRAMES) { + if((*frameId & ALL_FRAMES) == ALL_FRAMES) mMaxFrameId = (*frameId & 0x7f); - if(*frameId > 0x81) - lastFound = true; - } frame_t *f = &mLocalBuf[(*frameId & 0x7f) - 1]; memcpy(f->buf, &p->packet[10], p->len-11); @@ -182,7 +196,7 @@ class Communication : public CommQueue<> { if(q->attempts == 0) { DBGPRINTLN(F("-> Fail")); q->iv->radioStatistics.rxFail++; // got fragments but not complete response - pop(); + cmdDone(); } else DBGPRINTLN(F("-> complete retransmit")); mState = States::RESET; @@ -220,7 +234,7 @@ class Communication : public CommQueue<> { private: enum class States : uint8_t { - RESET, START, WAIT, CHECK_FRAMES, CHECK_PACKAGE + RESET, START, WAIT, CHECK_FRAMES, CHECK_PACKAGE, GAP }; typedef struct { @@ -234,7 +248,6 @@ class Communication : public CommQueue<> { uint32_t *mTimestamp; uint32_t mWaitTimeout; std::array mLocalBuf; - bool lastFound; uint8_t mMaxFrameId; uint8_t mPayload[150]; }; diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 45278e6b..7e76644d 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -105,9 +105,9 @@ class HmRadio : public Radio { DPRINTLN(DBG_WARN, F("WARNING! your NRF24 module can't be reached, check the wiring")); } - bool loop(void) { + void loop(void) { if (!mIrqRcvd) - return false; // nothing to do + return; // 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 @@ -124,7 +124,7 @@ class HmRadio : public Radio { if (mIrqRcvd) { mIrqRcvd = false; if (getReceived()) { // everything received - return true; + return; } } yield(); @@ -137,7 +137,7 @@ class HmRadio : public Radio { yield(); } // not finished but time is over - return true; + return; } bool isChipConnected(void) { @@ -252,6 +252,7 @@ class HmRadio : public Radio { p.ch = mRfChLst[mRxChIdx]; p.len = (len > MAX_RF_PAYLOAD_SIZE) ? MAX_RF_PAYLOAD_SIZE : len; p.rssi = mNrf24.testRPD() ? -64 : -75; + p.millis = millis() - mMillis; mNrf24.read(p.packet, p.len); if (p.packet[0] != 0x00) { mBufCtrl.push(p); @@ -288,6 +289,7 @@ class HmRadio : public Radio { mNrf24.setChannel(mRfChLst[mTxChIdx]); mNrf24.openWritingPipe(reinterpret_cast(&iv->radioId.u64)); mNrf24.startWrite(mTxBuf, len, false); // false = request ACK response + mMillis = millis(); if(isRetransmit) iv->radioStatistics.retransmits++; @@ -303,6 +305,7 @@ class HmRadio : public Radio { uint8_t mRfChLst[RF_CHANNELS]; uint8_t mTxChIdx; uint8_t mRxChIdx; + uint32_t mMillis; SPIClass* mSpi; RF24 mNrf24; diff --git a/src/hm/radio.h b/src/hm/radio.h index 8e9f5ef4..2096f108 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -23,7 +23,11 @@ class Radio { public: virtual void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit, bool isNoMI = true, uint16_t powerMax = 0) = 0; virtual bool switchFrequency(Inverter<> *iv, uint32_t fromkHz, uint32_t tokHz) { return true; } - virtual bool loop(void) = 0; + virtual void loop(void) {}; + + bool get() { + return !mBufCtrl.empty(); + } void handleIntr(void) { mIrqRcvd = true; diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index 5cee324b..c01a95bc 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -29,18 +29,15 @@ class CmtRadio : public Radio { reset(genDtuSn); } - bool loop() { + void loop() { mCmt.loop(); - if((!mIrqRcvd) && (!mRqstGetRx)) - return false; + return; getRx(); if(CMT_SUCCESS == mCmt.goRx()) { mIrqRcvd = false; mRqstGetRx = false; - return true; - } else - return false; + } } bool isConnected() { @@ -90,6 +87,7 @@ class CmtRadio : public Radio { } uint8_t status = mCmt.tx(mTxBuf, len); + mMillis = millis(); if(CMT_SUCCESS != status) { DPRINT(DBG_WARN, F("CMT TX failed, code: ")); DBGPRINTLN(String(status)); @@ -144,6 +142,7 @@ class CmtRadio : public Radio { inline void getRx(void) { packet_t p; + p.millis = millis() - mMillis; uint8_t status = mCmt.getRx(p.packet, &p.len, 28, &p.rssi); if(CMT_SUCCESS == status) mBufCtrl.push(p); @@ -152,6 +151,7 @@ class CmtRadio : public Radio { CmtType mCmt; bool mRqstGetRx; bool mCmtAvail; + uint32_t mMillis; }; #endif /*__HMS_RADIO_H__*/ From 5b39d38d8644b67b492741da21b81fbbe17a1466 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 12 Oct 2023 07:56:49 +0200 Subject: [PATCH 136/267] included dev-control again --- src/app.cpp | 14 +++++++---- src/hm/CommQueue.h | 9 ++++--- src/hm/Communication.h | 55 +++++++++++++++++++++++++++--------------- src/hm/hmInverter.h | 12 +++++++++ 4 files changed, 62 insertions(+), 28 deletions(-) diff --git a/src/app.cpp b/src/app.cpp index 2255aa14..0e0aec5f 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -200,8 +200,7 @@ void app::onNetwork(bool gotIp) { mNetworkConnected = gotIp; ah::Scheduler::resetTicker(); regularTickers(); //reinstall regular tickers - //every(std::bind(&app::tickSend, this), mConfig->nrf.sendInterval, "tSend"); - once(std::bind(&app::tickSend, this), 20, "tSend"); + every(std::bind(&app::tickSend, this), mConfig->nrf.sendInterval, "tSend"); mMqttReconnect = true; mSunrise = 0; // needs to be set to 0, to reinstall sunrise and ivComm tickers! //once(std::bind(&app::tickNtpUpdate, this), 2, "ntp2"); @@ -406,12 +405,17 @@ void app::tickMidnight(void) { void app::tickSend(void) { DPRINTLN(DBG_INFO, "tickSend"); + if(!mIVCommunicationOn) { + DPRINTLN(DBG_WARN, F("Time not set or it is night time, therefore no communication to the inverter!")); + return; + } + for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { Inverter<> *iv = mSys.getInverterByPos(i); if(NULL != iv) { - mCommunication.add(iv, 0x01); - mCommunication.add(iv, 0x05); - mCommunication.add(iv, 0x0b, false); + iv->tickSend([this, iv](uint8_t cmd) { + mCommunication.add(iv, cmd); + }); }; } diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index 5f13d03d..9c9da707 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -17,11 +17,11 @@ class CommQueue { void addImportant(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) { dec(&mRdPtr); - mQueue[mRdPtr] = queue_s(iv, cmd, delOnPop); + mQueue[mRdPtr] = queue_s(iv, cmd, delOnPop, true); } void add(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) { - mQueue[mWrPtr] = queue_s(iv, cmd, delOnPop); + mQueue[mWrPtr] = queue_s(iv, cmd, delOnPop, false); inc(&mWrPtr); } @@ -31,10 +31,11 @@ class CommQueue { uint8_t cmd; uint8_t attempts; bool delOnPop; + bool isDevControl; uint32_t ts; queue_s() {} - queue_s(Inverter<> *i, uint8_t c, bool d) : - iv(i), cmd(c), attempts(5), ts(0), delOnPop(d) {} + queue_s(Inverter<> *i, uint8_t c, bool d, bool dev) : + iv(i), cmd(c), attempts(5), ts(0), delOnPop(d), isDevControl(dev) {} }; protected: diff --git a/src/hm/Communication.h b/src/hm/Communication.h index ecb28ce0..e65484e7 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -16,6 +16,11 @@ class Communication : public CommQueue<> { mTimestamp = timestamp; } + void addImportant(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) { + mState = States::RESET; // cancel current operation + CommQueue::addImportant(iv, cmd, delOnPop); + } + void loop() { get([this](bool valid, const queue_s *q) { if(!valid) @@ -23,6 +28,8 @@ class Communication : public CommQueue<> { switch(mState) { case States::RESET: + if(millis() < mWaitTimeout) + return; mMaxFrameId = 0; for(uint8_t i = 0; i < MAX_PAYLOAD_ENTRIES; i++) { mLocalBuf[i].len = 0; @@ -32,8 +39,13 @@ class Communication : public CommQueue<> { case States::START: setTs(mTimestamp); - q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); - mWaitTimeout = millis() + 1500; + if(q->isDevControl) { + if(ActivePowerContr == q->cmd) + q->iv->powerLimitAck = false; + q->iv->radio->sendControlPacket(q->iv, q->cmd, q->iv->powerLimit, false); + } else + q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); + mWaitTimeout = millis() + 500; setAttempt(); mState = States::WAIT; break; @@ -51,13 +63,10 @@ class Communication : public CommQueue<> { q->iv->radioStatistics.rxFailNoAnser++; // got nothing if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, WORK_FREQ_KHZ); - mWaitTimeout = millis() + 2000; - mState = States::GAP; - break; - } else { - mState = States::RESET; - break; + mWaitTimeout = millis() + 1000; } + mState = States::RESET; + break; } States nextState = States::RESET; @@ -83,7 +92,7 @@ class Communication : public CommQueue<> { parseFrame(p); nextState = States::CHECK_PACKAGE; } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) // response from dev control command - parseDevCtrl(p); + parseDevCtrl(p, q); } q->iv->radio->mBufCtrl.pop(); @@ -93,12 +102,6 @@ class Communication : public CommQueue<> { } break; - case States::GAP: - if(millis() < mWaitTimeout) - return; - mState = States::RESET; - break; - case States::CHECK_PACKAGE: if(0 == mMaxFrameId) { DPRINT_IVID(DBG_WARN, q->iv->id); @@ -175,8 +178,22 @@ class Communication : public CommQueue<> { f->rssi = p->rssi; } - inline void parseDevCtrl(packet_t *p) { - //if((p->packet[12] == ActivePowerContr) && (p->packet[13] == 0x00)) + inline void parseDevCtrl(packet_t *p, const queue_s *q) { + if((p->packet[12] != ActivePowerContr) || (p->packet[13] != 0x00)) + return; + bool accepted = true; + if((p->packet[10] == 0x00) && (p->packet[11] == 0x00)) + q->iv->powerLimitAck = true; + else + accepted = false; + + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F(" has ")); + if(!accepted) DBGPRINT(F("not ")); + DBGPRINT(F("accepted power limit set point ")); + DBGPRINT(String(q->iv->powerLimit[0])); + DBGPRINT(F(" with PowerLimitControl ")); + DBGPRINTLN(String(q->iv->powerLimit[1])); } inline void compilePayload(const queue_s *q) { @@ -234,7 +251,7 @@ class Communication : public CommQueue<> { private: enum class States : uint8_t { - RESET, START, WAIT, CHECK_FRAMES, CHECK_PACKAGE, GAP + RESET, START, WAIT, CHECK_FRAMES, CHECK_PACKAGE }; typedef struct { @@ -246,7 +263,7 @@ class Communication : public CommQueue<> { private: States mState = States::RESET; uint32_t *mTimestamp; - uint32_t mWaitTimeout; + uint32_t mWaitTimeout = 0; std::array mLocalBuf; uint8_t mMaxFrameId; uint8_t mPayload[150]; diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 238e80e4..8dfb5156 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -15,6 +15,7 @@ #include "../hms/hmsDefines.h" #include #include +#include #include "../config/settings.h" #include "radio.h" @@ -180,6 +181,17 @@ class Inverter { // TODO: cleanup } + void tickSend(std::function cb) { + if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) + cb(AlarmData); // get last alarms + else if(0 == getFwVersion()) + cb(InverterDevInform_All); // get firmware version + else if(0 == getHwVersion()) + cb(InverterDevInform_Simple); // get hardware version + else + cb(RealTimeRunData_Debug); // get live data + } + template void enqueCommand(uint8_t cmd) { _commandQueue.push(std::make_shared(cmd)); From bf772756ed60879b4e93e0869fe087dbbd9586ed Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 12 Oct 2023 17:22:56 +0200 Subject: [PATCH 137/267] improved set limit and radio statistics communication with HMS / HMT is fine - for HM it tries to receive on the same channel which does not work for 4-ch inverter --- src/app.cpp | 13 +++-- src/app.h | 15 +++--- src/defines.h | 4 +- src/hm/Communication.h | 101 +++++++++++++++++++++++++++++++++------ src/hm/hmDefines.h | 9 ++++ src/hm/hmInverter.h | 29 +++++------ src/hm/hmRadio.h | 12 ++--- src/hms/cmt2300a.h | 9 ---- src/hms/hmsRadio.h | 8 +--- src/web/RestApi.h | 2 +- src/web/html/serial.html | 6 +-- src/web/html/style.css | 5 ++ 12 files changed, 143 insertions(+), 70 deletions(-) diff --git a/src/app.cpp b/src/app.cpp index 0e0aec5f..44d8ab30 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -60,6 +60,7 @@ void app::setup() { #endif /* defined(ETHERNET) */ mCommunication.setup(&mTimestamp); + mCommunication.addPayloadListener(std::bind(&app::payloadEventListener, this, std::placeholders::_1, std::placeholders::_2)); mSys.setup(&mTimestamp, &mConfig->inst); for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { mSys.addInverter(i, [this](Inverter<> *iv) { @@ -93,6 +94,7 @@ void app::setup() { if (mMqttEnabled) { mMqtt.setup(&mConfig->mqtt, mConfig->sys.deviceName, mVersion, &mSys, &mTimestamp, &mUptime); mMqtt.setSubscriptionCb(std::bind(&app::mqttSubRxCb, this, std::placeholders::_1)); + mCommunication.addAlarmListener([this](Inverter<> *iv) { mMqtt.alarmEvent(iv); }); //mPayload.addAlarmListener([this](Inverter<> *iv) { mMqtt.alarmEvent(iv); }); //mMiPayload.addAlarmListener([this](Inverter<> *iv) { mMqtt.alarmEvent(iv); }); } @@ -122,7 +124,7 @@ void app::setup() { //----------------------------------------------------------------------------- void app::loop(void) { ah::Scheduler::loop(); - bool processPayload = false; + //bool processPayload = false; mNrfRadio.loop(); #if defined(ESP32) @@ -403,8 +405,6 @@ void app::tickMidnight(void) { //----------------------------------------------------------------------------- void app::tickSend(void) { - DPRINTLN(DBG_INFO, "tickSend"); - if(!mIVCommunicationOn) { DPRINTLN(DBG_WARN, F("Time not set or it is night time, therefore no communication to the inverter!")); return; @@ -413,8 +413,11 @@ void app::tickSend(void) { for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { Inverter<> *iv = mSys.getInverterByPos(i); if(NULL != iv) { - iv->tickSend([this, iv](uint8_t cmd) { - mCommunication.add(iv, cmd); + iv->tickSend([this, iv](uint8_t cmd, bool isDevControl) { + if(isDevControl) + mCommunication.addImportant(iv, cmd); + else + mCommunication.add(iv, cmd); }); }; } diff --git a/src/app.h b/src/app.h index d1a13a6a..d28c3bf6 100644 --- a/src/app.h +++ b/src/app.h @@ -12,12 +12,11 @@ #include "config/settings.h" #include "defines.h" #include "appInterface.h" -#include "hm/hmPayload.h" #include "hm/hmSystem.h" #include "hm/hmRadio.h" #include "hms/hmsRadio.h" -#include "hm/hmPayload.h" -#include "hm/miPayload.h" +//#include "hm/hmPayload.h" +//#include "hm/miPayload.h" #include "publisher/pubMqtt.h" #include "publisher/pubSerial.h" #include "utils/crc.h" @@ -42,8 +41,8 @@ #define ACOS(x) (degrees(acos(x))) typedef HmSystem HmSystemType; -typedef HmPayload PayloadType; -typedef MiPayload MiPayloadType; +//typedef HmPayload PayloadType; +//typedef MiPayload MiPayloadType; #ifdef ESP32 typedef CmtRadio CmtRadioType; #endif @@ -174,8 +173,8 @@ class app : public IApp, public ah::Scheduler { void ivSendHighPrio(Inverter<> *iv) { if(mIVCommunicationOn) { // only send commands if communication is enabled - if (iv->ivGen == IV_MI) - mMiPayload.ivSendHighPrio(iv); + //if (iv->ivGen == IV_MI) + // mMiPayload.ivSendHighPrio(iv); //else // mPayload.ivSendHighPrio(iv); } @@ -320,7 +319,7 @@ class app : public IApp, public ah::Scheduler { WebType mWeb; RestApiType mApi; //PayloadType mPayload; - MiPayloadType mMiPayload; + //MiPayloadType mMiPayload; PubSerialType mPubSerial; #if !defined(ETHERNET) //Improv mImprov; diff --git a/src/defines.h b/src/defines.h index 80ecf9c0..be59fb4f 100644 --- a/src/defines.h +++ b/src/defines.h @@ -12,8 +12,8 @@ // VERSION //------------------------------------- #define VERSION_MAJOR 0 -#define VERSION_MINOR 7 -#define VERSION_PATCH 66 +#define VERSION_MINOR 8 +#define VERSION_PATCH 0 //------------------------------------- typedef struct { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index e65484e7..4cdf0beb 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -10,6 +10,9 @@ #include #include "../utils/crc.h" +typedef std::function *)> payloadListenerType; +typedef std::function *)> alarmListenerType; + class Communication : public CommQueue<> { public: void setup(uint32_t *timestamp) { @@ -21,6 +24,14 @@ class Communication : public CommQueue<> { CommQueue::addImportant(iv, cmd, delOnPop); } + void addPayloadListener(payloadListenerType cb) { + mCbPayload = cb; + } + + void addAlarmListener(alarmListenerType cb) { + mCbAlarm = cb; + } + void loop() { get([this](bool valid, const queue_s *q) { if(!valid) @@ -45,6 +56,7 @@ class Communication : public CommQueue<> { q->iv->radio->sendControlPacket(q->iv, q->cmd, q->iv->powerLimit, false); } else q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); + q->iv->radioStatistics.txCnt++; mWaitTimeout = millis() + 500; setAttempt(); mState = States::WAIT; @@ -59,7 +71,10 @@ class Communication : public CommQueue<> { case States::CHECK_FRAMES: { if(!q->iv->radio->get()) { // radio buffer empty cmdDone(); - DBGPRINTLN(F("request timeout")); + DPRINT(DBG_INFO, F("request timeout: ")); + DBGPRINT(String(millis() - mWaitTimeout + 500)); + DBGPRINTLN(F("ms")); + q->iv->radioStatistics.rxFailNoAnser++; // got nothing if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, WORK_FREQ_KHZ); @@ -74,12 +89,14 @@ class Communication : public CommQueue<> { packet_t *p = &q->iv->radio->mBufCtrl.front(); DPRINT_IVID(DBG_INFO, q->iv->id); - DPRINT(DBG_INFO, F("RX ")); + DBGPRINT(F("RX ")); DBGPRINT(String(p->millis)); DBGPRINT(F("ms ")); DBGPRINT(String(p->len)); - DBGPRINT(F(" CH")); - DBGPRINT(String(p->ch)); + if(IV_HM == q->iv->ivGen) { + DBGPRINT(F(" CH")); + DBGPRINT(String(p->ch)); + } DBGPRINT(F(", ")); DBGPRINT(String(p->rssi)); DBGPRINT(F("dBm | ")); @@ -91,8 +108,10 @@ class Communication : public CommQueue<> { if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command parseFrame(p); nextState = States::CHECK_PACKAGE; - } 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 parseDevCtrl(p, q); + cmdDone(true); // remove done request + } } q->iv->radio->mBufCtrl.pop(); @@ -104,26 +123,40 @@ class Communication : public CommQueue<> { case States::CHECK_PACKAGE: if(0 == mMaxFrameId) { + setAttempt(); + DPRINT_IVID(DBG_WARN, q->iv->id); - DBGPRINT(F("last frame missing: request retransmit")); + DBGPRINT(F("last frame missing: request retransmit (")); + DBGPRINT(String(q->attempts)); + DBGPRINTLN(F(" attempts left)")); + + uint8_t i = 0; + while(i < MAX_PAYLOAD_ENTRIES) { + if(mLocalBuf[i++].len == 0) + break; + } - q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + mMaxFrameId + 1), true); - setAttempt(); - mWaitTimeout = millis() + 100; + q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (ALL_FRAMES + i), true); + q->iv->radioStatistics.retransmits++; + mWaitTimeout = millis() + 500; mState = States::WAIT; break; } for(uint8_t i = 0; i < mMaxFrameId; i++) { if(mLocalBuf[i].len == 0) { + setAttempt(); + DPRINT_IVID(DBG_WARN, q->iv->id); DBGPRINT(F("frame ")); DBGPRINT(String(i + 1)); - DBGPRINTLN(F(" missing: request retransmit")); + DBGPRINT(F(" missing: request retransmit (")); + DBGPRINT(String(q->attempts)); + DBGPRINTLN(F(" attempts left)")); q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (ALL_FRAMES + i), true); - setAttempt(); - mWaitTimeout = millis() + 100; + q->iv->radioStatistics.retransmits++; + mWaitTimeout = millis() + 500; mState = States::WAIT; return; } @@ -131,6 +164,9 @@ class Communication : public CommQueue<> { compilePayload(q); + if(NULL != mCbPayload) + (mCbPayload)(q->cmd, q->iv); + cmdDone(true); // remove done request mState = States::RESET; // everything ok, next request break; @@ -194,6 +230,7 @@ class Communication : public CommQueue<> { DBGPRINT(String(q->iv->powerLimit[0])); DBGPRINT(F(" with PowerLimitControl ")); DBGPRINTLN(String(q->iv->powerLimit[1])); + q->iv->actPowerLimit = 0xffff; // unknown, readback current value } inline void compilePayload(const queue_s *q) { @@ -220,9 +257,9 @@ class Communication : public CommQueue<> { return; } - DPRINT_IVID(DBG_INFO, q->iv->id); + /*DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("procPyld: cmd: 0x")); - DBGHEXLN(q->cmd); + DBGHEXLN(q->cmd);*/ memset(mPayload, 0, 150); int8_t rssi = -127; @@ -247,6 +284,40 @@ class Communication : public CommQueue<> { DBGPRINT(String(len)); DBGPRINT(F("): ")); ah::dumpBuf(mPayload, len); + + record_t<> *rec = q->iv->getRecordStruct(q->cmd); + if(NULL == rec) { + DPRINTLN(DBG_ERROR, F("record is NULL!")); + return; + } + if((rec->pyldLen != len) && (0 != rec->pyldLen)) { + DPRINT(DBG_ERROR, F("plausibility check failed, expected ")); + DBGPRINT(String(rec->pyldLen)); + DBGPRINTLN(F(" bytes")); + q->iv->radioStatistics.rxFail++; + return; + } + + q->iv->radioStatistics.rxSuccess++; + + rec->ts = q->ts; + for (uint8_t i = 0; i < rec->length; i++) { + q->iv->addValue(i, mPayload, rec); + } + + q->iv->rssi = rssi; + q->iv->doCalculations(); + + if(AlarmData == q->cmd) { + uint8_t i = 0; + while(1) { + if(0 == q->iv->parseAlarmLog(i++, mPayload, len)) + break; + if (NULL != mCbAlarm) + (mCbAlarm)(q->iv); + yield(); + } + } } private: @@ -267,6 +338,8 @@ class Communication : public CommQueue<> { std::array mLocalBuf; uint8_t mMaxFrameId; uint8_t mPayload[150]; + payloadListenerType mCbPayload = NULL; + alarmListenerType mCbAlarm = NULL; }; #endif /*__COMMUNICATION_H__*/ diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index 72ab5c4c..acd81541 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -77,6 +77,15 @@ enum {CH0 = 0, CH1, CH2, CH3, CH4, CH5, CH6}; enum {INV_TYPE_1CH = 0, INV_TYPE_2CH, INV_TYPE_4CH, INV_TYPE_6CH}; +#define WORK_FREQ_KHZ 865000 // desired work frequency between DTU and + // inverter in kHz +#define HOY_BASE_FREQ_KHZ 860000 // in kHz +#define HOY_MAX_FREQ_KHZ 923500 // 0xFE * 250kHz + Base_freq +#define HOY_BOOT_FREQ_KHZ 868000 // Hoymiles boot/init frequency after power up inverter +#define FREQ_STEP_KHZ 250 // channel step size in kHz +#define FREQ_WARN_MIN_KHZ 863000 // for EU 863 - 870 MHz is allowed +#define FREQ_WARN_MAX_KHZ 870000 // for EU 863 - 870 MHz is allowed + typedef struct { uint8_t fieldId; // field id diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 8dfb5156..5e3e4266 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -181,18 +181,23 @@ class Inverter { // TODO: cleanup } - void tickSend(std::function cb) { - if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) - cb(AlarmData); // get last alarms + void tickSend(std::function cb) { + if(mDevControlRequest) { + cb(devControlCmd, true); + mDevControlRequest = false; + } else if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) + cb(AlarmData, false); // get last alarms else if(0 == getFwVersion()) - cb(InverterDevInform_All); // get firmware version + cb(InverterDevInform_All, false); // get firmware version else if(0 == getHwVersion()) - cb(InverterDevInform_Simple); // get hardware version + cb(InverterDevInform_Simple, false); // get hardware version + else if(actPowerLimit == 0xffff) + cb(SystemConfigPara, false); // power limit info else - cb(RealTimeRunData_Debug); // get live data + cb(RealTimeRunData_Debug, false); // get live data } - template + /*template void enqueCommand(uint8_t cmd) { _commandQueue.push(std::make_shared(cmd)); DPRINT_IVID(DBG_INFO, id); @@ -240,7 +245,7 @@ class Inverter { enqueCommand(SystemConfigPara); // power limit info } return _commandQueue.front().get()->getCmd(); - } + }*/ void init(void) { @@ -305,10 +310,6 @@ class Inverter { mDevControlRequest = false; } - inline bool getDevControlRequest() { - return mDevControlRequest; - } - void addValue(uint8_t pos, uint8_t buf[], record_t<> *rec) { DPRINTLN(DBG_VERBOSE, F("hmInverter.h:addValue")); if(NULL != rec) { @@ -350,7 +351,7 @@ class Inverter { DPRINT(DBG_INFO, "alarm ID incremented to "); DBGPRINTLN(String(alarmMesIndex)); - enqueCommand(AlarmData); + //enqueCommand(AlarmData); } } } @@ -727,7 +728,7 @@ class Inverter { radioId.b[0] = 0x01; } - std::queue> _commandQueue; + //std::queue> _commandQueue; bool mDevControlRequest; // true if change needed }; diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 7e76644d..461fd08e 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -118,8 +118,8 @@ class HmRadio : public Radio { mNrf24.startListening(); uint32_t startMicros = micros(); - uint32_t loopMillis = millis(); - while (millis()-loopMillis < 400) { + uint32_t loopMillis = millis() + 400; + while (millis() < loopMillis) { while (micros()-startMicros < 5110) { // listen (4088us or?) 5110us to each channel if (mIrqRcvd) { mIrqRcvd = false; @@ -277,7 +277,8 @@ class HmRadio : public Radio { mRxChIdx = (mTxChIdx + 2) % RF_CHANNELS; if(mSerialDebug) { - DPRINT(DBG_INFO, F("TX ")); + DPRINT_IVID(DBG_INFO, iv->id); + DBGPRINT(F("TX ")); DBGPRINT(String(len)); DBGPRINT(" CH"); DBGPRINT(String(mRfChLst[mTxChIdx])); @@ -290,11 +291,6 @@ class HmRadio : public Radio { mNrf24.openWritingPipe(reinterpret_cast(&iv->radioId.u64)); mNrf24.startWrite(mTxBuf, len, false); // false = request ACK response mMillis = millis(); - - if(isRetransmit) - iv->radioStatistics.retransmits++; - else - iv->radioStatistics.txCnt++; } uint64_t getIvId(Inverter<> *iv) { diff --git a/src/hms/cmt2300a.h b/src/hms/cmt2300a.h index 9d00ba20..ab54617d 100644 --- a/src/hms/cmt2300a.h +++ b/src/hms/cmt2300a.h @@ -8,15 +8,6 @@ #include "esp32_3wSpi.h" -#define WORK_FREQ_KHZ 865000 // desired work frequency between DTU and - // inverter in kHz -#define HOY_BASE_FREQ_KHZ 860000 // in kHz -#define HOY_MAX_FREQ_KHZ 923500 // 0xFE * 250kHz + Base_freq -#define HOY_BOOT_FREQ_KHZ 868000 // Hoymiles boot/init frequency after power up inverter -#define FREQ_STEP_KHZ 250 // channel step size in kHz -#define FREQ_WARN_MIN_KHZ 863000 // for EU 863 - 870 MHz is allowed -#define FREQ_WARN_MAX_KHZ 870000 // for EU 863 - 870 MHz is allowed - // detailed register infos from AN142_CMT2300AW_Quick_Start_Guide-Rev0.8.pdf #define CMT2300A_MASK_CFG_RETAIN 0x10 diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index c01a95bc..24c3c7cd 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -80,7 +80,8 @@ class CmtRadio : public Radio { updateCrcs(&len, appendCrc16); if(mSerialDebug) { - DPRINT(DBG_INFO, F("TX ")); + DPRINT_IVID(DBG_INFO, iv->id); + DBGPRINT(F("TX ")); DBGPRINT(String(mCmt.getFreqKhz()/1000.0f)); DBGPRINT(F("Mhz | ")); ah::dumpBuf(mTxBuf, len); @@ -94,11 +95,6 @@ class CmtRadio : public Radio { if(CMT_ERR_RX_IN_FIFO == status) mIrqRcvd = true; } - - if(isRetransmit) - iv->radioStatistics.retransmits++; - else - iv->radioStatistics.txCnt++; } uint64_t getIvId(Inverter<> *iv) { diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 225c26c8..e53c91da 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -683,7 +683,7 @@ class RestApi { } else if(F("dev") == jsonIn[F("cmd")]) { DPRINTLN(DBG_INFO, F("dev cmd")); - iv->enqueCommand(jsonIn[F("val")].as()); + //iv->enqueCommand(jsonIn[F("val")].as()); } else { jsonOut[F("error")] = F("unknown cmd: '") + jsonIn["cmd"].as() + "'"; diff --git a/src/web/html/serial.html b/src/web/html/serial.html index 10d1769e..3f9b4d94 100644 --- a/src/web/html/serial.html +++ b/src/web/html/serial.html @@ -7,9 +7,9 @@ {#HTML_NAV}
-
+
- +
console active:
@@ -42,7 +42,7 @@ if(true == exeOnce) { parseNav(obj); parseESP(obj); - window.setInterval("getAjax('/api/generic', parseGeneric)", 10000); + window.setInterval("getAjax('/api/generic', parseGeneric)", 5000); exeOnce = false; setTimeOffset(); } diff --git a/src/web/html/style.css b/src/web/html/style.css index cca955eb..95cbff3b 100644 --- a/src/web/html/style.css +++ b/src/web/html/style.css @@ -24,6 +24,11 @@ input[type=file] { width: 100%; } +textarea { + color: var(--fg); + background-color: var(--bg); +} + #live span { color: var(--fg2); } From 0e7874935d47b4e76f2b8e7845bc43823c3a0822 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Wed, 18 Oct 2023 12:51:29 +0200 Subject: [PATCH 138/267] Add files via upload --- src/hm/Communication.h | 37 +- src/hm/hmDefines.h | 4 + src/hm/hmInverter.h | 42 +- src/hm/miPayload.h | 2 +- src/hm/radio.h | 2 +- src/web/html/h/about_html.h | 82 +++ src/web/html/h/api_js.h | 216 ++++++ src/web/html/h/colorBright_css.h | 22 + src/web/html/h/colorDark_css.h | 21 + src/web/html/h/favicon_ico.h | 101 +++ src/web/html/h/index_html.h | 191 +++++ src/web/html/h/login_html.h | 47 ++ src/web/html/h/save_html.h | 86 +++ src/web/html/h/serial_html.h | 113 +++ src/web/html/h/setup_html.h | 545 +++++++++++++++ src/web/html/h/style_css.h | 188 +++++ src/web/html/h/system_html.h | 139 ++++ src/web/html/h/update_html.h | 74 ++ src/web/html/h/visualization_html.h | 275 ++++++++ src/web/html/tmp/about.html | 100 +++ src/web/html/tmp/index.html | 263 +++++++ src/web/html/tmp/login.html | 43 ++ src/web/html/tmp/save.html | 102 +++ src/web/html/tmp/serial.html | 132 ++++ src/web/html/tmp/setup.html | 1000 +++++++++++++++++++++++++++ src/web/html/tmp/style.css | 781 +++++++++++++++++++++ src/web/html/tmp/system.html | 188 +++++ src/web/html/tmp/update.html | 80 +++ src/web/html/tmp/visualization.html | 479 +++++++++++++ 29 files changed, 5332 insertions(+), 23 deletions(-) create mode 100644 src/web/html/h/about_html.h create mode 100644 src/web/html/h/api_js.h create mode 100644 src/web/html/h/colorBright_css.h create mode 100644 src/web/html/h/colorDark_css.h create mode 100644 src/web/html/h/favicon_ico.h create mode 100644 src/web/html/h/index_html.h create mode 100644 src/web/html/h/login_html.h create mode 100644 src/web/html/h/save_html.h create mode 100644 src/web/html/h/serial_html.h create mode 100644 src/web/html/h/setup_html.h create mode 100644 src/web/html/h/style_css.h create mode 100644 src/web/html/h/system_html.h create mode 100644 src/web/html/h/update_html.h create mode 100644 src/web/html/h/visualization_html.h create mode 100644 src/web/html/tmp/about.html create mode 100644 src/web/html/tmp/index.html create mode 100644 src/web/html/tmp/login.html create mode 100644 src/web/html/tmp/save.html create mode 100644 src/web/html/tmp/serial.html create mode 100644 src/web/html/tmp/setup.html create mode 100644 src/web/html/tmp/style.css create mode 100644 src/web/html/tmp/system.html create mode 100644 src/web/html/tmp/update.html create mode 100644 src/web/html/tmp/visualization.html diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 4cdf0beb..c14bd4f0 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -50,12 +50,32 @@ class Communication : public CommQueue<> { case States::START: setTs(mTimestamp); - if(q->isDevControl) { - if(ActivePowerContr == q->cmd) - q->iv->powerLimitAck = false; - q->iv->radio->sendControlPacket(q->iv, q->cmd, q->iv->powerLimit, false); - } else - q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); + if (q->iv->ivGen != IV_MI) { + if(q->isDevControl) { + if(ActivePowerContr == q->cmd) + q->iv->powerLimitAck = false; + q->iv->radio->sendControlPacket(q->iv, q->cmd, q->iv->powerLimit, false); + } else + q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); + } else { // IV_MI + if(q->isDevControl) { + if(ActivePowerContr == q->cmd) + q->iv->powerLimitAck = false; + q->iv->radio->sendControlPacket(q->iv, q->cmd, q->iv->powerLimit, false, false, (q->iv->powerLimit[1] == RelativNonPersistent) ? 0 : q->iv->getMaxPower()); + } else { + //uint8_t cmd = q->iv->type == INV_TYPE_4CH ? MI_REQ_4CH : MI_REQ_CH1; + //q->iv->radio->sendCmdPacket(q->iv, cmd, cmd, false, false); + q->iv->radio->sendCmdPacket(q->iv, q->cmd, q->cmd, false, false); + //if (q->iv->radio->mSerialDebug) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("legacy cmd 0x")); + DBGHEXLN(q->cmd); + //} + //mPayload[q->iv->id]. = cmd; + } + + } + q->iv->radioStatistics.txCnt++; mWaitTimeout = millis() + 500; setAttempt(); @@ -71,7 +91,8 @@ class Communication : public CommQueue<> { case States::CHECK_FRAMES: { if(!q->iv->radio->get()) { // radio buffer empty cmdDone(); - DPRINT(DBG_INFO, F("request timeout: ")); + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("request timeout: ")); DBGPRINT(String(millis() - mWaitTimeout + 500)); DBGPRINTLN(F("ms")); @@ -93,7 +114,7 @@ class Communication : public CommQueue<> { DBGPRINT(String(p->millis)); DBGPRINT(F("ms ")); DBGPRINT(String(p->len)); - if(IV_HM == q->iv->ivGen) { + if((IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen)) { DBGPRINT(F(" CH")); DBGPRINT(String(p->ch)); } diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index acd81541..c00f4940 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -346,4 +346,8 @@ const devInfo_t devInfo[] = { { 0x103331, 2250 } }; +#define MI_REQ_CH1 0x09 +#define MI_REQ_CH2 0x11 +#define MI_REQ_4CH 0x36 + #endif /*__HM_DEFINES_H__*/ diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 5e3e4266..04aca4d2 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -182,19 +182,35 @@ class Inverter { } void tickSend(std::function cb) { - if(mDevControlRequest) { - cb(devControlCmd, true); - mDevControlRequest = false; - } else if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) - cb(AlarmData, false); // get last alarms - else if(0 == getFwVersion()) - cb(InverterDevInform_All, false); // get firmware version - else if(0 == getHwVersion()) - cb(InverterDevInform_Simple, false); // get hardware version - else if(actPowerLimit == 0xffff) - cb(SystemConfigPara, false); // power limit info - else - cb(RealTimeRunData_Debug, false); // get live data + if (ivGen != IV_MI) { + if(mDevControlRequest) { + cb(devControlCmd, true); + mDevControlRequest = false; + } else if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) + cb(AlarmData, false); // get last alarms + else if(0 == getFwVersion()) + cb(InverterDevInform_All, false); // get firmware version + else if(0 == getHwVersion()) + cb(InverterDevInform_Simple, false); // get hardware version + else if(actPowerLimit == 0xffff) + cb(SystemConfigPara, false); // power limit info + else + cb(RealTimeRunData_Debug, false); // get live data + } else { + if(mDevControlRequest) { + cb(devControlCmd, true); + mDevControlRequest = false; + } + else if(0 == getFwVersion()) + cb(InverterDevInform_All, false); // get firmware version + else { + record_t<> *rec = getRecordStruct(InverterDevInform_Simple); + if (getChannelFieldValue(CH0, FLD_PART_NUM, rec) == 0) + cb(InverterDevInform_All, false); // hard- and firmware version for missing HW part nr, delivered by frame 1 + else + cb(type == INV_TYPE_4CH ? MI_REQ_4CH : MI_REQ_CH1, false); + } + } } /*template diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index 94f7a9b3..892dc0a8 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -36,7 +36,7 @@ typedef struct { } miPayload_t; -typedef std::function *)> miPayloadListenerType; +//typedef std::function *)> miPayloadListenerType; template diff --git a/src/hm/radio.h b/src/hm/radio.h index 2096f108..46c05d99 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -42,7 +42,7 @@ class Radio { sendPacket(iv, 10, isRetransmit, appendCrc16); } - void prepareDevInformCmd(Inverter<> *iv, 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. + void prepareDevInformCmd(Inverter<> *iv, uint8_t cmd, uint32_t ts, uint16_t alarmMesId, bool isRetransmit, uint8_t reqfld=TX_REQ_INFO) { if(mSerialDebug) { DPRINT(DBG_DEBUG, F("prepareDevInformCmd 0x")); DPRINTLN(DBG_DEBUG,String(cmd, HEX)); diff --git a/src/web/html/h/about_html.h b/src/web/html/h/about_html.h new file mode 100644 index 00000000..1e486394 --- /dev/null +++ b/src/web/html/h/about_html.h @@ -0,0 +1,82 @@ +#ifndef __ABOUT_HTML_H__ +#define __ABOUT_HTML_H__ +#define about_html_len 1227 +const uint8_t about_html[] PROGMEM = { +0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0xc5, 0x58, 0x6d, 0x6f, 0xdb, 0x36, +0x10, 0xfe, 0xbe, 0x5f, 0xc1, 0xea, 0xc3, 0x90, 0x00, 0x91, 0xe9, 0x38, 0x49, 0x93, 0xba, 0xb6, +0x37, 0xd7, 0x49, 0xb3, 0x0c, 0x6d, 0x11, 0xc4, 0x09, 0x8a, 0x62, 0x18, 0x0a, 0x8a, 0xa2, 0x24, +0x26, 0x14, 0xa9, 0x92, 0x94, 0x63, 0x77, 0xe8, 0x7f, 0x1f, 0x29, 0xf9, 0x45, 0xaf, 0x4e, 0xba, +0xba, 0x58, 0x3e, 0x44, 0xd6, 0xf1, 0x5e, 0x9e, 0x3b, 0xde, 0x9d, 0x8e, 0x1c, 0xbc, 0xf0, 0x05, +0xd6, 0x8b, 0x84, 0x80, 0x48, 0xc7, 0x6c, 0xf4, 0xcb, 0x20, 0x7f, 0x00, 0xf3, 0x37, 0x88, 0x08, +0xf2, 0xf3, 0x9f, 0xd9, 0xab, 0xa6, 0x9a, 0x91, 0xd1, 0xd8, 0x13, 0xa9, 0x1e, 0xc0, 0xfc, 0x65, +0xb3, 0xc8, 0x28, 0x7f, 0x00, 0x92, 0xb0, 0xa1, 0xa3, 0xf4, 0x82, 0x11, 0x15, 0x11, 0xa2, 0x1d, +0x60, 0x15, 0x0f, 0x1d, 0x4d, 0xe6, 0x1a, 0x62, 0xa5, 0x1c, 0x10, 0x49, 0x12, 0x2c, 0x39, 0x3a, +0x86, 0xf0, 0xdb, 0x6c, 0xd8, 0xed, 0x9c, 0x75, 0xba, 0xdd, 0xee, 0xa1, 0x03, 0x8d, 0xed, 0x98, +0x68, 0x04, 0x38, 0x8a, 0x8d, 0xcc, 0x8c, 0x92, 0xc7, 0x44, 0x48, 0xa3, 0x03, 0x0b, 0xae, 0x09, +0xd7, 0x43, 0xe7, 0x91, 0xfa, 0x3a, 0x1a, 0xfa, 0x64, 0x46, 0x31, 0x71, 0xb3, 0x97, 0x03, 0x40, +0x39, 0xd5, 0x14, 0x31, 0x57, 0x61, 0xc4, 0xc8, 0xf0, 0xd0, 0x59, 0x29, 0xc1, 0x11, 0x92, 0x8a, +0x18, 0xa1, 0xbb, 0xdb, 0xb7, 0xee, 0x99, 0x25, 0x2b, 0x2c, 0x69, 0xa2, 0x8b, 0x88, 0xee, 0xd1, +0x0c, 0xe5, 0x54, 0x07, 0x28, 0x89, 0x87, 0x0e, 0x4a, 0x68, 0xe7, 0xbe, 0x04, 0x6a, 0x34, 0x80, +0x39, 0x87, 0x51, 0xf0, 0x3d, 0x1e, 0x62, 0xc1, 0x84, 0x54, 0x4f, 0xb8, 0x28, 0x85, 0x27, 0xb4, +0x2a, 0x38, 0xc8, 0x05, 0xe5, 0x3e, 0x99, 0x1f, 0x00, 0x2e, 0x02, 0xc1, 0x98, 0x78, 0x74, 0x00, +0x5c, 0x6e, 0x05, 0xdc, 0xec, 0xc5, 0xc0, 0x13, 0xfe, 0xa2, 0x10, 0x79, 0x9f, 0xce, 0x00, 0x66, +0x48, 0x29, 0x03, 0x43, 0x24, 0x1c, 0xcd, 0x9c, 0x25, 0x1f, 0x5a, 0x82, 0x81, 0x45, 0x0c, 0x6b, +0x56, 0xbb, 0x7f, 0xce, 0x68, 0x1c, 0x89, 0xc5, 0xf9, 0xed, 0xdd, 0x00, 0xa2, 0x8a, 0xd0, 0x26, +0x38, 0xfd, 0x99, 0xa0, 0xfe, 0x5e, 0x77, 0xff, 0xf5, 0x5a, 0x96, 0x1a, 0xc4, 0x0e, 0x10, 0x1c, +0x33, 0x8a, 0x1f, 0x56, 0x56, 0xf7, 0xf6, 0x9d, 0x02, 0x28, 0x95, 0x20, 0x6e, 0x83, 0x67, 0x1f, +0xdf, 0x4d, 0xdd, 0xa0, 0xb1, 0xbe, 0x51, 0x7f, 0xed, 0xd8, 0x0a, 0x40, 0x2c, 0x3c, 0x6a, 0xd1, +0x6f, 0x74, 0xa0, 0x8c, 0xcd, 0xf0, 0x1c, 0xad, 0x99, 0x22, 0xea, 0x93, 0xd5, 0x7e, 0x40, 0x46, +0x67, 0xa4, 0xb4, 0xb1, 0xef, 0x0c, 0x61, 0x6d, 0xa7, 0xac, 0xe2, 0xb8, 0x59, 0x85, 0x22, 0xd2, +0x64, 0x5a, 0x49, 0xc9, 0x47, 0xe2, 0xe5, 0xd4, 0x16, 0x4d, 0x27, 0x6d, 0x9a, 0x74, 0x9a, 0x94, +0x14, 0x4d, 0x89, 0xd6, 0x94, 0x87, 0xaa, 0xac, 0xc7, 0x46, 0x64, 0xa5, 0x40, 0x91, 0x84, 0x48, +0xa4, 0x85, 0x74, 0xea, 0x01, 0x5c, 0xdb, 0x7b, 0xd9, 0x6c, 0x2f, 0x4d, 0x7c, 0xa4, 0xcb, 0xee, +0xdf, 0x65, 0xa4, 0x16, 0xd8, 0xa7, 0x2d, 0xb0, 0x17, 0x4a, 0x93, 0xb8, 0x8c, 0x3b, 0x23, 0xfd, +0x20, 0xea, 0xb3, 0xb5, 0x05, 0x53, 0x80, 0xa6, 0xa2, 0x90, 0x0c, 0x6d, 0xe5, 0x7e, 0xf6, 0x18, +0xe2, 0x0f, 0xce, 0xe8, 0xe6, 0x62, 0x7a, 0x0b, 0xc6, 0xd7, 0x57, 0x2d, 0x60, 0x5f, 0xad, 0xa4, +0x23, 0xad, 0x13, 0xd5, 0x87, 0x10, 0x99, 0x94, 0xf6, 0x75, 0xda, 0xb1, 0xc8, 0xab, 0xba, 0xce, +0x05, 0x4e, 0x63, 0x53, 0x6b, 0x48, 0x53, 0xc1, 0x5b, 0x14, 0x1e, 0x76, 0x37, 0x78, 0x6c, 0xaf, +0x2b, 0x39, 0xbc, 0xec, 0x7e, 0x3f, 0xe4, 0x6f, 0xb7, 0x25, 0x45, 0x45, 0x48, 0xb9, 0x49, 0x4c, +0xfb, 0x68, 0x83, 0xd6, 0x2a, 0x69, 0x50, 0x65, 0xa2, 0x45, 0x74, 0x03, 0x68, 0xca, 0xa7, 0x52, +0x48, 0x8f, 0x34, 0xa0, 0x79, 0xf9, 0xae, 0x6a, 0x99, 0x07, 0xc2, 0x82, 0xcd, 0x58, 0x0b, 0x12, +0x65, 0x29, 0x89, 0x12, 0xe3, 0x58, 0xa1, 0xe0, 0x4a, 0xcb, 0xcb, 0x06, 0x56, 0x59, 0xae, 0x36, +0xa7, 0x78, 0xe1, 0x1e, 0x19, 0x4b, 0x51, 0x2f, 0x0f, 0x22, 0x58, 0xb7, 0x1e, 0x43, 0xa9, 0x18, +0x6e, 0x17, 0xaf, 0xb1, 0x54, 0xd9, 0xa4, 0x78, 0x04, 0x96, 0x15, 0xd8, 0x86, 0xd9, 0xc2, 0x5f, +0x95, 0x49, 0xdc, 0x9e, 0xa9, 0x08, 0x45, 0x7c, 0xf0, 0x8e, 0x7a, 0x12, 0x49, 0x4a, 0x54, 0x0b, +0xa0, 0x4a, 0x58, 0x9f, 0x00, 0x62, 0xbc, 0x45, 0x95, 0xe4, 0x0c, 0xa9, 0x8e, 0x52, 0xaf, 0x83, +0x45, 0x0c, 0x3d, 0x22, 0x75, 0x4c, 0x18, 0x55, 0x90, 0xa8, 0xe4, 0xfd, 0x17, 0xad, 0x27, 0x8c, +0xda, 0x28, 0xd6, 0x92, 0xb6, 0x85, 0xd1, 0xee, 0xf3, 0xae, 0xb0, 0x2c, 0x52, 0x4f, 0xcc, 0x5d, +0x2e, 0x7c, 0xe2, 0x0a, 0x19, 0xc2, 0x8b, 0xe9, 0xf5, 0x58, 0x2d, 0x38, 0x36, 0xfd, 0x6d, 0x4a, +0xe4, 0xcc, 0xec, 0x7c, 0x0d, 0xd4, 0x53, 0x12, 0xbb, 0x44, 0xe7, 0x59, 0x9b, 0x38, 0x12, 0x1c, +0x8e, 0xa5, 0x9f, 0x52, 0x2e, 0xfe, 0x54, 0x36, 0x83, 0x6b, 0x71, 0x6a, 0x62, 0xdb, 0x25, 0x0e, +0x2e, 0x83, 0xde, 0x31, 0xbc, 0x79, 0xdb, 0x3b, 0xae, 0x1b, 0xdf, 0xac, 0xed, 0xd2, 0x62, 0x82, +0x52, 0xa6, 0xb4, 0x08, 0x02, 0x49, 0x42, 0xc2, 0xe1, 0x2d, 0x8d, 0x1b, 0x9a, 0x5a, 0x03, 0xd3, +0x2e, 0x31, 0x08, 0x46, 0x1f, 0x24, 0x4a, 0x15, 0xbc, 0x3b, 0x0b, 0x7b, 0x75, 0xeb, 0xa5, 0xe5, +0x5d, 0xda, 0xfd, 0x6a, 0x3e, 0x88, 0xe1, 0x7d, 0x0c, 0x2f, 0xe7, 0x17, 0xd7, 0xe7, 0x0d, 0x86, +0xcb, 0xeb, 0x05, 0xcb, 0x3f, 0xaf, 0x47, 0x4c, 0x4c, 0xa3, 0x43, 0x58, 0x83, 0x2b, 0xd3, 0x34, +0x65, 0xbc, 0xfc, 0x88, 0xec, 0xa4, 0x51, 0x3c, 0x0b, 0x83, 0x99, 0x2a, 0xdd, 0x13, 0x60, 0xff, +0xab, 0xd8, 0x36, 0xc3, 0xcb, 0x2c, 0x58, 0xe0, 0x86, 0x24, 0x42, 0x51, 0xf3, 0xd1, 0x59, 0x6c, +0xb1, 0xd8, 0xa4, 0xeb, 0x74, 0xa5, 0xeb, 0xd5, 0xf6, 0x9d, 0x60, 0x69, 0x8c, 0x92, 0x34, 0xfb, +0xb0, 0x3a, 0xa3, 0xed, 0xeb, 0x4f, 0x25, 0xc0, 0xcf, 0x0e, 0xc9, 0x39, 0x55, 0x58, 0x48, 0x1f, +0x4c, 0x22, 0xa4, 0x77, 0x19, 0x0d, 0x3f, 0xd7, 0xdb, 0x09, 0x43, 0xf8, 0xf1, 0x6b, 0x34, 0xbf, +0xf8, 0xf4, 0xb2, 0x17, 0xbf, 0x69, 0x98, 0x2f, 0x72, 0xb6, 0xff, 0x3b, 0x0a, 0x17, 0xee, 0x7b, +0x44, 0xd9, 0x2e, 0xfc, 0x8f, 0x8d, 0x1e, 0x2d, 0xfa, 0x38, 0x4f, 0xfc, 0xdf, 0x0b, 0xb3, 0xd5, +0xa8, 0x4e, 0xfb, 0x6f, 0x6e, 0x37, 0x90, 0xab, 0x73, 0x48, 0xcb, 0x58, 0x12, 0x08, 0xa1, 0x4b, +0x53, 0x49, 0xd1, 0x25, 0x46, 0x02, 0x5d, 0x3e, 0x21, 0x3c, 0x7f, 0x4c, 0x5c, 0x8e, 0x26, 0xe0, +0x57, 0x2c, 0x92, 0x05, 0xe8, 0x75, 0x7b, 0x47, 0xe5, 0x81, 0x2c, 0x65, 0x15, 0xbc, 0x8c, 0xee, +0x26, 0x65, 0x8c, 0x9e, 0xa7, 0x15, 0xb7, 0x54, 0x66, 0x4d, 0x73, 0xde, 0x1e, 0xea, 0x8a, 0x07, +0x70, 0x85, 0xbf, 0x3a, 0x21, 0xae, 0x12, 0x8f, 0x86, 0x51, 0x29, 0x76, 0x2d, 0xfe, 0x56, 0x0c, +0x3e, 0x0b, 0x26, 0x34, 0xef, 0x31, 0xd5, 0x0a, 0x7a, 0xc1, 0xe9, 0x69, 0xef, 0xf4, 0xc4, 0xc0, +0xbc, 0xba, 0x05, 0xd3, 0x3f, 0xc6, 0x7d, 0xb0, 0xa4, 0x80, 0x7e, 0x1f, 0xac, 0x06, 0xee, 0xd6, +0xa8, 0x64, 0xfb, 0x6f, 0xc6, 0xa1, 0xcf, 0xf6, 0xfc, 0xed, 0x3c, 0x37, 0x72, 0x58, 0x12, 0xd3, +0xb4, 0x67, 0xc4, 0x62, 0x10, 0x5c, 0x75, 0xec, 0xe4, 0x62, 0xce, 0xb0, 0x84, 0x2b, 0x62, 0x00, +0x2d, 0x5c, 0x8e, 0x5d, 0x85, 0xe0, 0x71, 0xa7, 0x0b, 0x7d, 0x42, 0xfc, 0x5a, 0x44, 0xc1, 0x68, +0x32, 0x01, 0x6f, 0x3e, 0xb9, 0x1f, 0x26, 0xee, 0x74, 0x0c, 0x0c, 0xdb, 0x33, 0x62, 0x5b, 0xcd, +0xdd, 0xad, 0xd7, 0x10, 0x65, 0x17, 0x82, 0x94, 0x63, 0xfb, 0x89, 0x01, 0x89, 0xbd, 0xcb, 0xb8, +0x24, 0xdc, 0x1c, 0x35, 0xf1, 0x9e, 0xf0, 0xee, 0xf7, 0xc1, 0x3f, 0xb5, 0x2a, 0xca, 0x78, 0x3e, +0x98, 0x63, 0xb8, 0x5d, 0x7f, 0xdd, 0xbc, 0x6c, 0x86, 0xb4, 0x6d, 0xcb, 0x37, 0x4a, 0xd1, 0x86, +0xf5, 0x6f, 0x5b, 0x40, 0xb5, 0xa1, 0xa1, 0xc1, 0x1e, 0x4f, 0x19, 0x03, 0x2f, 0x86, 0xa0, 0x85, +0x63, 0x6d, 0xb5, 0xe0, 0xd7, 0x5f, 0x4e, 0x98, 0xbf, 0x38, 0x7f, 0x37, 0x60, 0xfc, 0xb6, 0x05, +0x95, 0xd9, 0xa5, 0xf1, 0x3d, 0x9a, 0xef, 0x65, 0x47, 0x48, 0x68, 0xaf, 0xb0, 0xa0, 0x42, 0x33, +0xe2, 0x1c, 0xe4, 0x36, 0x0a, 0xda, 0x36, 0x17, 0x3a, 0xf9, 0x5b, 0x7e, 0x99, 0x32, 0x80, 0xf9, +0xb5, 0xd7, 0xbf, 0x27, 0x09, 0x59, 0x3f, 0x0e, 0x13, 0x00, 0x00}; +#endif /*__ABOUT_HTML_H__*/ diff --git a/src/web/html/h/api_js.h b/src/web/html/h/api_js.h new file mode 100644 index 00000000..d9bf93cb --- /dev/null +++ b/src/web/html/h/api_js.h @@ -0,0 +1,216 @@ +#ifndef __API_JS_H__ +#define __API_JS_H__ +#define api_js_len 3363 +const uint8_t api_js[] PROGMEM = { +0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0xdd, 0x59, 0x79, 0x6f, 0xdb, 0x46, +0x16, 0xff, 0xdf, 0x9f, 0x62, 0x42, 0x60, 0x63, 0x2a, 0x91, 0x46, 0xbc, 0x8f, 0xb8, 0xea, 0x42, +0x75, 0x9d, 0xc4, 0x0b, 0xc7, 0x2e, 0x62, 0xb7, 0xbb, 0x80, 0x61, 0x04, 0xb4, 0x34, 0xb6, 0xd8, +0x50, 0xa4, 0x96, 0xa4, 0xec, 0xc4, 0x85, 0xbf, 0xfb, 0xfe, 0xde, 0x90, 0x94, 0x78, 0xc9, 0xf1, +0x9e, 0x2d, 0x56, 0x31, 0xaf, 0x99, 0x77, 0x5f, 0xf3, 0x66, 0x32, 0x7e, 0xf5, 0x6a, 0x8f, 0xbd, +0x62, 0xe7, 0xbf, 0xbc, 0x63, 0xc7, 0x87, 0x67, 0xa7, 0xe7, 0xf8, 0x18, 0xef, 0xed, 0x85, 0xb3, +0x24, 0xfe, 0x6b, 0x78, 0x13, 0xea, 0x6c, 0xc2, 0x2e, 0xf7, 0x18, 0x7e, 0xca, 0x07, 0x5d, 0xe7, +0x9a, 0xe5, 0x30, 0x5d, 0xe3, 0x96, 0x6d, 0xcd, 0xb8, 0x61, 0x38, 0x23, 0xba, 0x71, 0xdd, 0xb3, +0x47, 0xdc, 0xd1, 0x70, 0xd3, 0x47, 0xdc, 0xb5, 0xa7, 0x0e, 0xb7, 0x5c, 0x93, 0x15, 0x77, 0x4d, +0xfe, 0xf3, 0x98, 0x3f, 0x1b, 0x01, 0xdb, 0x61, 0xda, 0xc8, 0xc0, 0xc3, 0xe0, 0x86, 0x6d, 0xe1, +0xcd, 0xb7, 0x1c, 0xee, 0x6a, 0x16, 0xc8, 0x78, 0x36, 0xd7, 0x2d, 0x50, 0x30, 0x41, 0xcf, 0x36, +0x30, 0xa2, 0x83, 0x52, 0xc4, 0x35, 0xdd, 0xa6, 0x6b, 0xc6, 0x75, 0x87, 0xfe, 0x2c, 0xcd, 0xe5, +0xba, 0xcf, 0x1d, 0x92, 0xc4, 0x9f, 0xda, 0xe0, 0xe0, 0xb1, 0xe2, 0x4e, 0x5c, 0x74, 0xf0, 0xd1, +0xb5, 0x19, 0xf7, 0x1c, 0xfa, 0xd6, 0xb9, 0xe3, 0x73, 0x43, 0xd3, 0x99, 0xc1, 0x2d, 0x83, 0xdb, +0x0e, 0xde, 0x4d, 0x50, 0xb5, 0x40, 0xd0, 0x25, 0x0a, 0x23, 0x90, 0xd0, 0x25, 0x87, 0x11, 0xdd, +0x1e, 0x3e, 0xf8, 0x24, 0x9f, 0x0e, 0x68, 0xe8, 0xa6, 0xfb, 0xd0, 0x0d, 0x37, 0x5c, 0xde, 0x08, +0x02, 0x01, 0x04, 0x32, 0x39, 0xce, 0x54, 0xe7, 0xbe, 0xcf, 0xe4, 0xad, 0xd2, 0x0c, 0xb2, 0xd8, +0x41, 0x6b, 0x98, 0x74, 0x85, 0x8e, 0xde, 0x0c, 0x9a, 0x99, 0x1e, 0x34, 0xa3, 0x27, 0xc4, 0x77, +0x2c, 0x22, 0x04, 0x3a, 0x11, 0xd4, 0x26, 0xd5, 0x9d, 0x80, 0xdb, 0xdc, 0x2e, 0x69, 0xe1, 0xdb, +0x65, 0x1a, 0x4d, 0x81, 0x27, 0xde, 0x1f, 0x94, 0xbd, 0xab, 0x83, 0xad, 0x2b, 0x8c, 0xba, 0x2b, +0x4c, 0x58, 0xde, 0x67, 0x1e, 0x37, 0x5c, 0x1d, 0x9e, 0xd0, 0xc9, 0x13, 0x64, 0x22, 0x1f, 0x0c, +0x6c, 0x17, 0xe8, 0x9a, 0x63, 0x82, 0x86, 0x65, 0x4f, 0x7d, 0x68, 0xec, 0xb0, 0xe2, 0x5e, 0x89, +0xec, 0x90, 0x33, 0x7c, 0x0d, 0x7c, 0x47, 0x26, 0x77, 0x3c, 0x18, 0x67, 0x04, 0xf3, 0x3b, 0xd0, +0x1e, 0xaa, 0x42, 0x24, 0xcb, 0xc3, 0x5f, 0xa9, 0x09, 0x51, 0x22, 0x42, 0x98, 0x91, 0x57, 0x25, +0xab, 0x63, 0x93, 0x23, 0xed, 0x29, 0x40, 0x1d, 0x26, 0x6f, 0x95, 0x0b, 0xdc, 0xa0, 0x3d, 0x66, +0x41, 0x26, 0x17, 0xc4, 0x4d, 0xd3, 0x81, 0xb0, 0x1a, 0x78, 0x99, 0x06, 0x31, 0xd1, 0x35, 0x8f, +0xe8, 0x10, 0x0f, 0xfb, 0x61, 0x89, 0x78, 0xd0, 0x3d, 0x93, 0xc9, 0xfb, 0xef, 0x14, 0x5d, 0xde, +0xff, 0x77, 0x74, 0x79, 0x45, 0x74, 0xb9, 0x7d, 0xd1, 0x65, 0xd6, 0xa3, 0xcb, 0xe6, 0xa6, 0x67, +0xc1, 0xc6, 0xba, 0x6e, 0x53, 0x34, 0xd8, 0x74, 0x6d, 0xe2, 0xc1, 0x22, 0x7c, 0x13, 0xc2, 0x92, +0x32, 0x16, 0x2b, 0x1f, 0x95, 0xc0, 0xe6, 0xa1, 0x0d, 0xf3, 0xfb, 0x8c, 0x1c, 0xe9, 0x1a, 0x26, +0x33, 0xb9, 0xe7, 0x19, 0x90, 0xc9, 0x84, 0x29, 0x4d, 0xd7, 0xef, 0x21, 0xe7, 0x11, 0x35, 0x6e, +0xeb, 0x1e, 0x5d, 0x9b, 0xf0, 0x42, 0x58, 0x6a, 0xf6, 0x14, 0xea, 0x5b, 0x96, 0xb4, 0x82, 0x65, +0x6d, 0xdd, 0x60, 0xcd, 0x60, 0x72, 0xca, 0x15, 0x44, 0x96, 0x67, 0xb8, 0xdc, 0xd3, 0x0c, 0x08, +0xeb, 0xea, 0x0e, 0x05, 0x8f, 0x63, 0x15, 0x21, 0x46, 0x41, 0xec, 0x23, 0xd2, 0x88, 0x14, 0xb1, +0xf1, 0x1f, 0x94, 0x61, 0x4f, 0xf6, 0x90, 0x40, 0x14, 0x8c, 0x46, 0x2d, 0xde, 0xb7, 0x99, 0x63, +0xb3, 0xe2, 0xfe, 0x7b, 0x66, 0x8e, 0xb3, 0xcd, 0x1c, 0xa7, 0x99, 0x39, 0xe6, 0x1f, 0x27, 0x73, +0xfe, 0x63, 0x75, 0x79, 0x93, 0x38, 0xce, 0x1f, 0xaf, 0x2c, 0x77, 0x13, 0x27, 0x48, 0xe3, 0x5a, +0xde, 0xb8, 0xdc, 0x37, 0x3d, 0xe8, 0x05, 0xe1, 0xa7, 0x14, 0x79, 0xba, 0x59, 0xe9, 0xcf, 0x35, +0x84, 0xa8, 0x11, 0x34, 0x06, 0x65, 0x7c, 0x68, 0x64, 0x40, 0x4b, 0x5e, 0x9b, 0x61, 0xdb, 0xc2, +0xe5, 0x46, 0x0e, 0xf7, 0x6c, 0x97, 0xf4, 0x70, 0x1c, 0x77, 0xc6, 0x35, 0x08, 0x0a, 0xd9, 0x34, +0x13, 0x0e, 0x31, 0x2c, 0xa2, 0x47, 0xde, 0x06, 0x45, 0x10, 0xc1, 0x55, 0x20, 0x8f, 0x0a, 0x64, +0x4a, 0x5c, 0x79, 0x6d, 0x46, 0x1d, 0x60, 0xea, 0xee, 0x7b, 0x9d, 0xf8, 0x04, 0x94, 0xd6, 0x74, +0xd5, 0x66, 0xc9, 0xd6, 0x6e, 0x0f, 0xad, 0x91, 0x24, 0xe6, 0xca, 0x6b, 0x23, 0x9f, 0x06, 0xbb, +0x83, 0xf7, 0x09, 0x12, 0x0f, 0x55, 0x02, 0xea, 0xba, 0x24, 0x87, 0xe5, 0xd2, 0x55, 0x53, 0x82, +0x08, 0xb8, 0x0f, 0x4b, 0x6a, 0x1a, 0xf0, 0x6e, 0x91, 0x37, 0xa0, 0xbb, 0x5e, 0x19, 0x80, 0xbc, +0xe1, 0x83, 0xe8, 0x09, 0x58, 0xda, 0x8c, 0x52, 0xd2, 0x34, 0x67, 0x04, 0xe7, 0x72, 0xd7, 0xf5, +0x28, 0x0a, 0x00, 0xeb, 0x3a, 0xb0, 0xa9, 0x57, 0xbc, 0x2c, 0x00, 0xe3, 0xea, 0x08, 0x70, 0xcf, +0xf3, 0x65, 0x1c, 0x59, 0x26, 0x82, 0xc0, 0xf7, 0x01, 0x30, 0x92, 0x00, 0x27, 0x1e, 0x5e, 0x0d, +0x4a, 0x45, 0xc7, 0xd9, 0x26, 0xbb, 0x2b, 0x6d, 0xaf, 0x1b, 0x01, 0xe8, 0x49, 0xd9, 0x10, 0x79, +0xe5, 0xb3, 0xd0, 0x13, 0x5f, 0x0f, 0x80, 0xd2, 0x11, 0xb1, 0xbe, 0x8f, 0x7a, 0x87, 0xf4, 0x2e, +0x52, 0x5c, 0xc2, 0xe8, 0x9c, 0xaa, 0x26, 0x12, 0xc0, 0x46, 0x29, 0x43, 0xd1, 0x41, 0x64, 0x20, +0x7f, 0x71, 0x95, 0xd8, 0xd0, 0x07, 0x3a, 0x6c, 0xd0, 0x6b, 0xc1, 0x71, 0x1c, 0xdf, 0x24, 0xb5, +0xe0, 0x80, 0x16, 0xf6, 0xd4, 0x65, 0x6e, 0x49, 0x17, 0x9f, 0x41, 0xf1, 0xa5, 0x15, 0x72, 0x59, +0x0f, 0x4b, 0xdc, 0xa7, 0x1e, 0xf3, 0xca, 0x11, 0x3c, 0x83, 0xe2, 0xab, 0xf8, 0xa7, 0x6f, 0x95, +0x5a, 0x42, 0x53, 0xca, 0x64, 0xdb, 0xf3, 0x90, 0xad, 0x06, 0xf2, 0xc9, 0x43, 0x6c, 0x6a, 0x28, +0x64, 0x08, 0x6b, 0xca, 0x24, 0x59, 0x07, 0x7c, 0x8b, 0x52, 0xca, 0x84, 0xb8, 0xe4, 0x41, 0xc3, +0xa3, 0xba, 0xe2, 0x47, 0x54, 0xbc, 0x51, 0xa6, 0xf1, 0x4e, 0x79, 0x80, 0x8e, 0x81, 0x7b, 0x3e, +0xc4, 0x87, 0xc2, 0x28, 0x33, 0x48, 0x62, 0x4f, 0xf3, 0xca, 0x37, 0xdb, 0x92, 0x46, 0x00, 0x36, +0xec, 0x6c, 0xd8, 0x64, 0x59, 0xcb, 0x41, 0x2d, 0xb0, 0x7d, 0x0f, 0x09, 0x0a, 0xd6, 0xdc, 0xd2, +0x1d, 0xca, 0x25, 0xa2, 0x8f, 0x0f, 0x1f, 0xa2, 0x58, 0x78, 0x71, 0x3c, 0xa7, 0x78, 0x31, 0x5c, +0x2a, 0x94, 0x28, 0xfb, 0x54, 0x82, 0x7c, 0x54, 0x2b, 0x93, 0xd2, 0xd5, 0x36, 0xcd, 0x93, 0xad, +0xfc, 0x48, 0x70, 0xaa, 0x72, 0x5b, 0xef, 0x8c, 0x1a, 0xde, 0x21, 0x5f, 0xd5, 0x6c, 0x7a, 0xbe, +0x9e, 0xcd, 0x44, 0x96, 0xfd, 0x97, 0xcc, 0xfa, 0x01, 0xad, 0xad, 0xef, 0x42, 0x1c, 0x1f, 0x6e, +0x36, 0x90, 0x69, 0xb8, 0x36, 0xc5, 0x1c, 0x71, 0x6e, 0x18, 0x70, 0xb4, 0x85, 0x56, 0x06, 0x8b, +0x82, 0xee, 0xb2, 0x62, 0x95, 0x84, 0x85, 0x0d, 0xc4, 0xbf, 0x6b, 0x73, 0xd7, 0xde, 0x96, 0x19, +0x2a, 0xda, 0x9a, 0x73, 0xe2, 0x10, 0x3d, 0xaa, 0x8a, 0x4d, 0x08, 0x9a, 0x74, 0x7d, 0x22, 0x1a, +0x99, 0x88, 0x1a, 0x63, 0x04, 0x96, 0x7e, 0x87, 0x86, 0x4b, 0xd1, 0xa5, 0xd9, 0x5d, 0xf5, 0xdf, +0xae, 0xa3, 0xa8, 0xbe, 0x5c, 0x63, 0xc9, 0xd8, 0x28, 0x28, 0x55, 0xdc, 0x28, 0x88, 0x6f, 0xa4, +0x18, 0x56, 0x08, 0xb0, 0x71, 0x71, 0xd3, 0xba, 0x92, 0x7a, 0xff, 0x5b, 0xbd, 0x50, 0x68, 0xea, +0x5a, 0xb1, 0x71, 0xb1, 0xfd, 0x78, 0x77, 0x74, 0x7a, 0xf4, 0xf1, 0xf8, 0x90, 0xbd, 0xfd, 0xf9, +0xf4, 0xf0, 0xe2, 0xb8, 0xda, 0x86, 0xdc, 0xac, 0xe3, 0x59, 0x1e, 0x26, 0x31, 0x5b, 0x46, 0x6a, +0x1e, 0xdc, 0x9e, 0x06, 0x4b, 0x31, 0x64, 0x9c, 0xf3, 0x20, 0xbd, 0xcd, 0x06, 0xec, 0x37, 0xa9, +0xff, 0x5d, 0x90, 0x32, 0x41, 0xe6, 0x98, 0x27, 0xb3, 0xf5, 0x52, 0xc4, 0x39, 0x9f, 0xa5, 0x22, +0xc8, 0xc5, 0x51, 0x24, 0xe8, 0xab, 0xc2, 0x1b, 0x1c, 0x48, 0xe8, 0xf0, 0x46, 0x25, 0xe4, 0x4b, +0xed, 0xaa, 0xc2, 0xa7, 0xdf, 0x4d, 0x92, 0xaa, 0x44, 0x27, 0x06, 0x20, 0x0b, 0x63, 0xd6, 0x03, +0x52, 0x22, 0x13, 0x04, 0x0f, 0xe3, 0xb9, 0xf8, 0x72, 0x76, 0xa3, 0x2a, 0x49, 0xac, 0x0c, 0xd8, +0x64, 0x32, 0x61, 0x5a, 0x1b, 0x94, 0x7e, 0x22, 0xe2, 0xc1, 0x7c, 0x7e, 0x74, 0x07, 0x29, 0x4e, +0xc2, 0x2c, 0x17, 0xb1, 0x48, 0x0b, 0xfc, 0x6c, 0x7d, 0x9d, 0xe5, 0xa9, 0x6a, 0x0c, 0x78, 0x9e, +0x9c, 0x24, 0xf7, 0x22, 0x3d, 0x0c, 0x32, 0xa1, 0x0e, 0x86, 0x15, 0xdf, 0x4b, 0x82, 0xba, 0x1a, +0xb2, 0x9b, 0x20, 0xca, 0xc4, 0xa0, 0x41, 0xf7, 0x11, 0x54, 0x33, 0xd1, 0xcf, 0x2c, 0x13, 0xf9, +0x34, 0xcf, 0xd3, 0xf0, 0x7a, 0x9d, 0x0b, 0xc9, 0xa8, 0x45, 0xb0, 0x34, 0xc1, 0x86, 0xd4, 0x5e, +0xf3, 0xed, 0xb1, 0x34, 0x10, 0x53, 0x5f, 0x48, 0x34, 0xbd, 0xa1, 0x7f, 0x2a, 0xf2, 0x35, 0x16, +0x3b, 0x11, 0x1d, 0xd4, 0x80, 0xcb, 0xc1, 0x58, 0x40, 0xbb, 0x54, 0x15, 0x51, 0xc9, 0x10, 0x98, +0x7b, 0x8f, 0x7b, 0x5b, 0xef, 0xd5, 0xe6, 0xe3, 0x8a, 0x26, 0xf1, 0xc9, 0xbf, 0xae, 0x44, 0x72, +0xc3, 0x62, 0x69, 0x42, 0x05, 0x26, 0x09, 0xe3, 0x5b, 0xa5, 0xce, 0x14, 0x4a, 0x85, 0x31, 0xcc, +0xf6, 0xfe, 0xe2, 0xc3, 0x09, 0x3c, 0x1c, 0x97, 0xbc, 0x0b, 0x1b, 0x10, 0x85, 0x18, 0xde, 0xca, +0xf2, 0x20, 0x9e, 0x11, 0x9d, 0x69, 0x9a, 0x06, 0x5f, 0xfb, 0xdc, 0x1a, 0x02, 0x57, 0x3b, 0xc0, +0xe3, 0x3b, 0x16, 0xf3, 0x48, 0xc4, 0xb7, 0xf9, 0x02, 0x5f, 0xaf, 0x5f, 0x77, 0xfd, 0xbb, 0x95, +0xe9, 0x32, 0xbc, 0xda, 0x29, 0x56, 0xf5, 0x23, 0xda, 0x79, 0x37, 0xf2, 0x2e, 0xc4, 0x97, 0xfc, +0x34, 0x99, 0xc3, 0x07, 0x20, 0xd2, 0x32, 0x7a, 0x15, 0x17, 0xab, 0x95, 0x88, 0xe7, 0x87, 0x8b, +0x30, 0x9a, 0xab, 0x79, 0xdb, 0x2f, 0x35, 0xf5, 0x48, 0x8a, 0x9a, 0x86, 0x44, 0x75, 0xf0, 0xdb, +0xb7, 0x08, 0xf6, 0xb0, 0xed, 0xf8, 0x7a, 0x87, 0x09, 0x5b, 0x0c, 0xda, 0x84, 0x07, 0x5d, 0xdf, +0x53, 0x40, 0xd4, 0x7d, 0x9d, 0x27, 0xab, 0x38, 0xb8, 0x53, 0x2b, 0x73, 0xe5, 0xc9, 0xed, 0x6d, +0x24, 0x54, 0xa5, 0x18, 0x56, 0x86, 0x58, 0xbb, 0x92, 0xeb, 0x30, 0x12, 0xca, 0xa0, 0x89, 0xb6, +0x0a, 0xd2, 0x4c, 0x9c, 0x02, 0x31, 0xb9, 0xfe, 0xb5, 0xc2, 0x25, 0xf7, 0xd5, 0x5c, 0xa7, 0xeb, +0x1d, 0xa7, 0x21, 0x21, 0x01, 0x30, 0x61, 0x46, 0x33, 0x49, 0x50, 0x29, 0xf3, 0x30, 0x5e, 0x8b, +0xad, 0x0d, 0xc8, 0x53, 0x8d, 0x1a, 0x71, 0x2b, 0xf2, 0xb2, 0x40, 0xfc, 0xf0, 0xf5, 0x78, 0xae, +0x2a, 0x24, 0xdc, 0xeb, 0xb0, 0x66, 0x35, 0x90, 0xbe, 0x47, 0x9e, 0x27, 0xf7, 0x3c, 0x4a, 0x66, +0x01, 0xc9, 0xc8, 0x57, 0x41, 0xbe, 0x90, 0x15, 0x82, 0xc2, 0x62, 0xac, 0xb0, 0xd7, 0x2c, 0xe2, +0x8b, 0x54, 0xdc, 0x94, 0xf9, 0x8c, 0x28, 0x51, 0xb5, 0x61, 0x35, 0xb6, 0xa9, 0x11, 0x7f, 0x56, +0x06, 0x03, 0x9e, 0xad, 0xa2, 0x30, 0x57, 0xf7, 0xc7, 0xfb, 0x03, 0xbe, 0x4a, 0x56, 0xea, 0xa0, +0xa7, 0xb2, 0x40, 0x93, 0x17, 0x13, 0x94, 0xed, 0xc1, 0xcb, 0x97, 0xac, 0x78, 0xf7, 0x07, 0x83, +0x8e, 0xab, 0x23, 0x3e, 0x8b, 0x82, 0x2c, 0xa3, 0x7a, 0x42, 0xc5, 0x45, 0x55, 0x02, 0xd8, 0xef, +0x4e, 0x9a, 0x73, 0xeb, 0xe1, 0xba, 0x12, 0xb0, 0xe7, 0xa5, 0x02, 0x3d, 0xd7, 0x9f, 0x56, 0x69, +0x92, 0x1f, 0xc5, 0x4a, 0x5f, 0x55, 0x6b, 0x02, 0x75, 0x41, 0x4a, 0x30, 0x8d, 0x34, 0x0f, 0xbb, +0x42, 0xb5, 0x05, 0x4b, 0xc5, 0x32, 0xb9, 0x83, 0xd3, 0x17, 0xe1, 0xbc, 0x21, 0xd9, 0x36, 0xac, +0x64, 0xec, 0x41, 0xcb, 0xef, 0xe1, 0xba, 0x1e, 0x5e, 0x95, 0x49, 0x6a, 0x82, 0x2d, 0x83, 0xec, +0xb3, 0x72, 0xc5, 0xbe, 0xff, 0x1e, 0xc6, 0x19, 0x19, 0x30, 0xe0, 0x4b, 0xa6, 0x7d, 0xd1, 0x74, +0x2a, 0xbf, 0xf4, 0xa2, 0xf5, 0x4b, 0xf5, 0xcf, 0x4a, 0xf6, 0xd8, 0x9f, 0x89, 0xd0, 0xfc, 0x45, +0xaf, 0xe6, 0xcf, 0xa1, 0xfd, 0xd8, 0xd0, 0x57, 0x6f, 0x12, 0xf9, 0x16, 0x81, 0xc7, 0x6e, 0x96, +0xfc, 0x22, 0xd2, 0x0c, 0x1f, 0xf5, 0x4c, 0xd9, 0x19, 0xd6, 0x77, 0x05, 0xac, 0x32, 0x68, 0xe4, +0xf1, 0x46, 0x82, 0x28, 0x8c, 0x3f, 0x83, 0x5f, 0x9e, 0xaf, 0xb2, 0x37, 0xe3, 0xf1, 0x6d, 0x98, +0x2f, 0xd6, 0xd7, 0x7c, 0x96, 0x2c, 0xc7, 0xd1, 0x7a, 0x19, 0xac, 0xd6, 0xe3, 0x60, 0x91, 0x7c, +0x1d, 0xe3, 0x7b, 0x19, 0xe6, 0x99, 0x0c, 0x78, 0xe9, 0x8f, 0xeb, 0x35, 0x88, 0x28, 0x58, 0x9f, +0x94, 0x77, 0x61, 0xce, 0xce, 0xdf, 0x4f, 0xdf, 0xb0, 0xf6, 0x1c, 0x3e, 0x15, 0xf6, 0xa6, 0x36, +0x5e, 0x09, 0x42, 0x58, 0x9f, 0xae, 0xa3, 0x20, 0xfe, 0xac, 0x14, 0x86, 0xe8, 0xab, 0x03, 0x47, +0xe7, 0x3f, 0x3d, 0x4b, 0x3b, 0x91, 0xad, 0x3e, 0x51, 0xbd, 0x86, 0x7a, 0xa9, 0x58, 0x45, 0xc1, +0x4c, 0x48, 0xfd, 0x52, 0x11, 0x6f, 0x55, 0xdc, 0x55, 0x9b, 0x95, 0x1f, 0x92, 0x20, 0x9d, 0xd7, +0x24, 0xdc, 0x10, 0xbb, 0xda, 0x2d, 0xd8, 0xc7, 0x2c, 0x0b, 0xeb, 0x92, 0xc9, 0xc5, 0x05, 0xd5, +0x06, 0x95, 0x65, 0x73, 0x8e, 0xb2, 0xe9, 0x33, 0x24, 0xd5, 0x7b, 0x0c, 0x7d, 0x4a, 0x81, 0x06, +0x9b, 0x7c, 0x37, 0x61, 0x23, 0xaf, 0x16, 0xa8, 0x2d, 0x4c, 0xbd, 0xc0, 0xac, 0x82, 0xa5, 0x17, +0xdd, 0xdd, 0x8d, 0x6e, 0x1c, 0x3c, 0x6d, 0x2c, 0x22, 0x45, 0xb0, 0x3d, 0xc6, 0xca, 0xee, 0x6e, +0x55, 0x9a, 0x1a, 0x32, 0xd3, 0x28, 0x2e, 0x09, 0x8d, 0x6a, 0xdd, 0x16, 0x62, 0x30, 0x68, 0x57, +0xfb, 0xe3, 0x2c, 0xf9, 0x11, 0x76, 0x3d, 0x47, 0x3f, 0x33, 0xaf, 0xcc, 0xb2, 0x69, 0x0b, 0xee, +0x19, 0xcd, 0xa9, 0x73, 0x12, 0xe6, 0x22, 0x5c, 0xa2, 0xc7, 0x81, 0xb5, 0xb7, 0x9f, 0x0f, 0x49, +0x2c, 0xce, 0x6e, 0x6e, 0xd0, 0xb7, 0x60, 0xe2, 0x15, 0x1b, 0x39, 0x1a, 0x7e, 0x03, 0xea, 0x8a, +0x8e, 0xcf, 0xcf, 0xce, 0x8b, 0x8a, 0x3a, 0x68, 0x56, 0x57, 0xdd, 0xdf, 0x88, 0xaf, 0xee, 0x5f, +0xec, 0x0f, 0x19, 0xfd, 0xf5, 0x09, 0x45, 0xf4, 0x2b, 0xa1, 0xd8, 0x78, 0xcc, 0x7e, 0xbe, 0x38, +0x7c, 0xf1, 0x2d, 0xe1, 0x76, 0x73, 0xd6, 0xf5, 0xe7, 0xb1, 0x86, 0x2a, 0xef, 0x91, 0xbd, 0x6a, +0x38, 0x1f, 0x32, 0x4a, 0xe3, 0x66, 0x93, 0xba, 0x7c, 0x62, 0x05, 0x0a, 0xe7, 0xdb, 0x0e, 0x35, +0x96, 0xfd, 0xfd, 0x84, 0x30, 0x06, 0xad, 0x06, 0x6c, 0x03, 0x53, 0xa7, 0x5e, 0x0e, 0xbd, 0x00, +0x7c, 0xad, 0x9c, 0xd0, 0x2a, 0x18, 0x60, 0x6d, 0xaf, 0x0a, 0x4a, 0xb3, 0xf0, 0x34, 0x61, 0xe5, +0x52, 0xd2, 0xa8, 0x3b, 0x32, 0x0e, 0xf7, 0xfa, 0xa1, 0xcb, 0x42, 0xb5, 0x4f, 0x08, 0x5d, 0xe3, +0xcb, 0x05, 0x9f, 0x0c, 0x30, 0x8b, 0x26, 0x25, 0xcd, 0xba, 0x15, 0x9e, 0x69, 0x83, 0x17, 0xa2, +0x4f, 0x95, 0x59, 0x54, 0x53, 0x43, 0xb4, 0x14, 0xc0, 0xe4, 0x36, 0x85, 0x7a, 0xa1, 0x4a, 0xc1, +0x25, 0x60, 0x5d, 0x68, 0xc8, 0x31, 0xfd, 0x35, 0xf8, 0xa2, 0xae, 0x53, 0xb4, 0xa8, 0xab, 0x3c, +0x1d, 0xb2, 0xa5, 0xc8, 0x17, 0xc9, 0x7c, 0xa2, 0xbc, 0x3b, 0xba, 0x40, 0x1a, 0xfc, 0x9a, 0x25, +0xf1, 0x84, 0xbc, 0x52, 0xd7, 0xe4, 0xcb, 0x22, 0xa5, 0x9e, 0x14, 0x71, 0xf4, 0xb7, 0x0f, 0x27, +0xef, 0x51, 0x43, 0x3f, 0x8a, 0xbf, 0xaf, 0xd1, 0xe9, 0xaa, 0x5b, 0x25, 0x08, 0x04, 0x0b, 0x47, +0x1d, 0x13, 0x3f, 0x8c, 0xf2, 0x04, 0xd5, 0x58, 0x2d, 0x98, 0x0c, 0x99, 0x64, 0x9b, 0xa7, 0x6b, +0xb1, 0x5d, 0x35, 0x24, 0x4c, 0x8c, 0x92, 0x35, 0xff, 0x8a, 0xe6, 0x2c, 0x17, 0xb3, 0x45, 0x10, +0xdf, 0x92, 0xed, 0x56, 0x1b, 0x10, 0xd0, 0x57, 0x7e, 0x3a, 0x3b, 0xbf, 0x50, 0x28, 0x54, 0x0a, +0x52, 0x4d, 0x17, 0x13, 0x0d, 0x04, 0x64, 0x29, 0xd6, 0x7b, 0xd0, 0x42, 0x13, 0xae, 0x1c, 0xc2, +0x96, 0x30, 0xf8, 0xe8, 0x82, 0x6a, 0x1d, 0x32, 0x1d, 0x0b, 0x43, 0x14, 0x16, 0x1d, 0xce, 0x98, +0xf4, 0x3c, 0x00, 0x2b, 0x94, 0xba, 0x7c, 0xf2, 0xf3, 0xc5, 0xdb, 0x91, 0xa7, 0x34, 0x45, 0xca, +0xb0, 0x86, 0xa8, 0x04, 0x35, 0xa8, 0x6f, 0x03, 0xb6, 0x45, 0x52, 0x6d, 0x85, 0x24, 0xe1, 0x48, +0x25, 0xce, 0x49, 0x09, 0x12, 0xd4, 0xea, 0xdb, 0x54, 0x51, 0xbc, 0xc3, 0x4e, 0x05, 0x74, 0xb6, +0x4a, 0xe2, 0x4c, 0x16, 0xea, 0x1d, 0x6d, 0x48, 0x05, 0x0e, 0x47, 0xf5, 0xaf, 0xfa, 0x98, 0x50, +0xff, 0x72, 0x7e, 0x76, 0xca, 0x65, 0xd1, 0x56, 0x3b, 0x64, 0xbf, 0xb9, 0x11, 0x42, 0x6c, 0x94, +0xfb, 0xd2, 0xc3, 0x8f, 0x47, 0xd3, 0x8b, 0x23, 0xf6, 0xe3, 0xd9, 0x87, 0xd6, 0xd6, 0xb4, 0x16, +0xf1, 0xb4, 0xc9, 0x88, 0x50, 0x20, 0x70, 0x37, 0xb6, 0xdb, 0x9b, 0x6a, 0x27, 0x41, 0xa3, 0xb2, +0x63, 0x8c, 0xd7, 0xcb, 0x6b, 0x91, 0x2a, 0x83, 0x5a, 0x53, 0x4a, 0x33, 0xac, 0x2c, 0x37, 0x12, +0xfb, 0xa0, 0x5e, 0xa2, 0xb0, 0xe9, 0x55, 0xf2, 0x14, 0x3e, 0xfa, 0xed, 0x71, 0x58, 0x6e, 0xf6, +0xe9, 0x27, 0x87, 0x17, 0x34, 0x9c, 0xe5, 0x5f, 0x23, 0xf1, 0x86, 0x8a, 0xf5, 0x3c, 0x5f, 0xbc, +0x61, 0xb6, 0xf6, 0x27, 0xe5, 0x51, 0x8a, 0xa1, 0x0f, 0x86, 0x4d, 0xf0, 0x79, 0x49, 0x45, 0x32, +0x91, 0x53, 0x57, 0xad, 0x14, 0x98, 0x8b, 0x8c, 0x44, 0xa8, 0xe4, 0x17, 0xbb, 0x37, 0xd4, 0xfb, +0xab, 0xfd, 0x2a, 0xcf, 0xda, 0x15, 0x04, 0x05, 0x13, 0x74, 0x94, 0xcd, 0x74, 0x7d, 0xf3, 0x06, +0xe2, 0x0d, 0xed, 0x44, 0x93, 0x7f, 0x74, 0x1d, 0xa9, 0x8b, 0x7c, 0x19, 0xa1, 0xe9, 0x97, 0x62, +0xca, 0xf2, 0x41, 0x9e, 0x1e, 0xb2, 0x70, 0xde, 0xc8, 0xbd, 0xa7, 0x44, 0x8b, 0x82, 0x6b, 0x11, +0x6d, 0xc5, 0x23, 0x82, 0x6f, 0x13, 0x4a, 0xd3, 0x92, 0xf4, 0x93, 0x82, 0xd5, 0x42, 0x0b, 0x15, +0xa2, 0xa3, 0x1d, 0xe7, 0x7c, 0x53, 0x61, 0x6a, 0xa0, 0x28, 0x5a, 0x44, 0x70, 0x4e, 0x4b, 0xf1, +0xfc, 0x29, 0x0d, 0xc3, 0x78, 0x55, 0xee, 0xca, 0xa5, 0x7a, 0xcb, 0xe0, 0xcb, 0x84, 0x96, 0x5a, +0xa8, 0x79, 0xa9, 0xe4, 0x08, 0x4b, 0xea, 0x8d, 0x4a, 0x55, 0x51, 0x0d, 0x10, 0x3c, 0xe5, 0x2b, +0xb6, 0x1d, 0xd8, 0x3d, 0xc7, 0xd5, 0x44, 0x98, 0x47, 0xd5, 0xcc, 0x6c, 0x21, 0x66, 0x9f, 0xc5, +0xf3, 0xad, 0x03, 0x09, 0xd6, 0xf9, 0x2e, 0xe7, 0xd5, 0xd5, 0x13, 0xbc, 0xd8, 0xe7, 0xc8, 0x03, +0x91, 0x8e, 0xc6, 0x32, 0x4c, 0x04, 0xc7, 0x63, 0x2d, 0x76, 0xd8, 0x0f, 0xca, 0x11, 0x08, 0x1e, +0x27, 0x72, 0xbb, 0xcd, 0xe4, 0xd0, 0x73, 0x6c, 0x57, 0x9b, 0x25, 0x1b, 0xd0, 0x3c, 0x3d, 0x59, +0xf1, 0xd9, 0x81, 0x29, 0x8d, 0x43, 0x60, 0xe5, 0x2b, 0xdb, 0x0c, 0x76, 0x09, 0x92, 0xed, 0x24, +0x45, 0x7a, 0x61, 0xe5, 0x40, 0xd7, 0xf9, 0x85, 0x59, 0x65, 0x04, 0x14, 0xaf, 0x6c, 0x33, 0xf8, +0x94, 0x83, 0x33, 0x11, 0x95, 0x0e, 0x4e, 0x56, 0x34, 0x90, 0x0d, 0x69, 0xe8, 0x78, 0xfe, 0x1c, +0xd7, 0x00, 0x50, 0xcc, 0x6a, 0xbe, 0xe9, 0xd8, 0x5f, 0x6e, 0x86, 0x73, 0x86, 0x82, 0x52, 0x12, +0xaf, 0x17, 0x47, 0x3a, 0x67, 0xc6, 0x30, 0x00, 0x2e, 0x35, 0x8a, 0xa2, 0xfc, 0x52, 0xc7, 0xa3, +0xf8, 0xa4, 0xda, 0x53, 0x88, 0x51, 0x2b, 0x7b, 0xa2, 0xb1, 0x1f, 0x48, 0x06, 0x3d, 0x87, 0x3a, +0x5d, 0xe5, 0x7e, 0x14, 0xd1, 0x34, 0x8a, 0xce, 0xc0, 0x07, 0x1f, 0x8d, 0x16, 0x78, 0x28, 0x37, +0xd7, 0x18, 0xe5, 0xa5, 0x70, 0xe5, 0x29, 0x0b, 0x1b, 0x31, 0xfd, 0xa0, 0xb1, 0x97, 0x8f, 0x68, +0x2f, 0xff, 0x7d, 0xb1, 0xa7, 0x1f, 0x8d, 0xea, 0x3a, 0x10, 0x76, 0xb9, 0x3e, 0x87, 0xbd, 0x9b, +0x1f, 0x52, 0x50, 0x66, 0x0e, 0xe5, 0xb2, 0x34, 0xed, 0xa4, 0x38, 0x20, 0x2b, 0x89, 0x24, 0x4f, +0x98, 0xb7, 0x10, 0xab, 0x32, 0x6f, 0xd2, 0x8d, 0xdd, 0xa4, 0x51, 0x12, 0x88, 0xc3, 0x26, 0x2c, +0x48, 0xd9, 0xad, 0xa5, 0x79, 0xe1, 0x29, 0x19, 0x13, 0xb4, 0x64, 0x37, 0x02, 0x22, 0x69, 0xd5, +0xd4, 0xf0, 0x0e, 0xbd, 0x06, 0x04, 0x7e, 0x76, 0x86, 0x02, 0xe3, 0x39, 0xf9, 0x59, 0x0b, 0xd6, +0xc5, 0xa0, 0x55, 0xce, 0x16, 0x4f, 0x86, 0xe8, 0x2a, 0x88, 0xd5, 0x7f, 0xb9, 0xba, 0x12, 0xf6, +0xfe, 0xe0, 0xf7, 0xac, 0xa1, 0xd7, 0xa9, 0xda, 0xda, 0x64, 0xec, 0x92, 0xf5, 0x3a, 0x6d, 0x77, +0xa6, 0x72, 0xb3, 0x3b, 0xcf, 0x72, 0xd4, 0x50, 0x54, 0x5b, 0xdc, 0x83, 0x14, 0x7d, 0x5f, 0xa7, +0xad, 0x0b, 0x9e, 0x30, 0x40, 0x50, 0x69, 0xff, 0xad, 0x93, 0x3f, 0xe2, 0x50, 0x82, 0x06, 0xf2, +0x3c, 0x88, 0x60, 0xb3, 0xbc, 0x5b, 0x91, 0xa4, 0x0c, 0xdb, 0xf0, 0x0a, 0x78, 0x31, 0xc2, 0xaa, +0xa9, 0x8a, 0x46, 0xdf, 0x81, 0x61, 0x69, 0x81, 0xa0, 0xe5, 0x62, 0x6c, 0xe6, 0xe6, 0x41, 0x1e, +0x94, 0xee, 0xbd, 0x9f, 0x18, 0x16, 0x45, 0x20, 0xdd, 0x37, 0x3e, 0xcf, 0x93, 0x24, 0xca, 0xc3, +0x55, 0x47, 0xf7, 0x6c, 0xa7, 0xee, 0xa7, 0xe7, 0x68, 0xf7, 0xd1, 0xe3, 0xbe, 0x19, 0x8f, 0xef, +0xef, 0xef, 0xf9, 0xbd, 0xc9, 0x93, 0xf4, 0x76, 0x6c, 0x60, 0xbf, 0x36, 0x06, 0x43, 0xda, 0x09, +0xd1, 0xa3, 0x14, 0x2c, 0x6b, 0x1e, 0x45, 0xef, 0xcb, 0xfe, 0x04, 0x30, 0xf7, 0x3b, 0xe6, 0x17, +0x22, 0xbc, 0x5d, 0xe4, 0x00, 0x58, 0xec, 0x00, 0xb8, 0x0b, 0xc5, 0xfd, 0x0f, 0xc9, 0x17, 0x62, +0x53, 0xfc, 0x97, 0x0d, 0xfe, 0xf6, 0x07, 0xbd, 0x11, 0xd7, 0x46, 0x95, 0xf1, 0xb7, 0x4f, 0xba, +0x77, 0xe1, 0xc9, 0x4c, 0xed, 0xf3, 0x62, 0x6c, 0x35, 0xb2, 0x1c, 0x59, 0x80, 0x42, 0xdb, 0x9e, +0x2e, 0x8f, 0x16, 0x31, 0x1d, 0xfe, 0x1b, 0x76, 0xa2, 0x53, 0xc4, 0xfd, 0x56, 0x07, 0x1a, 0xb6, +0x84, 0x9e, 0x03, 0x50, 0xb4, 0x60, 0xb2, 0x46, 0x0c, 0x84, 0x8d, 0x03, 0xbf, 0xfa, 0xf1, 0xfd, +0x36, 0xb6, 0x0a, 0x27, 0xd7, 0x35, 0x28, 0xa4, 0xcf, 0x77, 0x47, 0xb8, 0x22, 0x57, 0xc4, 0xfa, +0xe9, 0x55, 0xde, 0x60, 0xbb, 0x33, 0xde, 0x4b, 0x5e, 0x35, 0xc4, 0xac, 0x37, 0x66, 0x1b, 0x4b, +0x4c, 0xd6, 0x8c, 0xdc, 0x65, 0x32, 0x0f, 0x22, 0x55, 0x4a, 0x30, 0x64, 0xd7, 0xc9, 0xfc, 0x6b, +0xad, 0x99, 0xae, 0xb6, 0xc4, 0x3b, 0x8f, 0x37, 0x24, 0xb2, 0xd2, 0x38, 0x58, 0xdd, 0x7d, 0x14, +0x92, 0x92, 0x68, 0xe9, 0xe6, 0x54, 0x4c, 0x6d, 0x18, 0x9a, 0x1a, 0x66, 0xd4, 0x61, 0xea, 0x98, +0x43, 0x3a, 0x20, 0x92, 0x94, 0x47, 0x15, 0x0e, 0x45, 0x12, 0x22, 0xaa, 0x1a, 0xa7, 0x33, 0x92, +0x78, 0x86, 0x0d, 0xd4, 0xe7, 0x37, 0x85, 0xfc, 0x87, 0x51, 0x92, 0x89, 0xc7, 0x5a, 0xff, 0xbd, +0x93, 0x64, 0x87, 0xd4, 0xe3, 0xb0, 0xb3, 0x9b, 0xa9, 0x21, 0x36, 0x60, 0x47, 0xb3, 0x62, 0x17, +0xa7, 0x34, 0x76, 0x06, 0xcf, 0xc6, 0x5e, 0xc8, 0xbd, 0xe0, 0xd3, 0xc8, 0x15, 0x81, 0x85, 0x5d, +0xee, 0x1d, 0x8a, 0xee, 0x69, 0xf8, 0x4d, 0x04, 0x84, 0x70, 0x9e, 0xc4, 0x75, 0xa6, 0x33, 0xb2, +0x89, 0x52, 0x34, 0xb5, 0xf8, 0xdc, 0x00, 0xf4, 0x59, 0x0e, 0x3b, 0xd2, 0x97, 0x79, 0xb8, 0x14, +0xd9, 0x81, 0xb2, 0xfb, 0x48, 0xf7, 0xea, 0x09, 0x31, 0x76, 0x2a, 0x4d, 0x11, 0x45, 0x2a, 0xcb, +0xc8, 0xea, 0x45, 0xbf, 0xea, 0x8c, 0x36, 0xe1, 0xb6, 0x5f, 0xbd, 0x0d, 0xca, 0x56, 0x0b, 0xf5, +0xb9, 0x27, 0x1e, 0x55, 0xd8, 0x76, 0x4a, 0x53, 0xe3, 0x6c, 0x47, 0x54, 0x8d, 0x51, 0x2d, 0xbd, +0x9e, 0xa6, 0x38, 0xda, 0x86, 0x78, 0x13, 0x95, 0x24, 0xfe, 0x07, 0x65, 0xb7, 0x8f, 0xf0, 0xf2, +0x29, 0x00, 0x00}; +#endif /*__API_JS_H__*/ diff --git a/src/web/html/h/colorBright_css.h b/src/web/html/h/colorBright_css.h new file mode 100644 index 00000000..7968d278 --- /dev/null +++ b/src/web/html/h/colorBright_css.h @@ -0,0 +1,22 @@ +#ifndef __COLORBRIGHT_CSS_H__ +#define __COLORBRIGHT_CSS_H__ +#define colorBright_css_len 261 +const uint8_t colorBright_css[] PROGMEM = { +0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0x55, 0x90, 0xdd, 0x6e, 0xc3, 0x20, +0x0c, 0x85, 0x5f, 0x65, 0x52, 0xae, 0x91, 0xbc, 0xfc, 0x42, 0xf6, 0x34, 0x60, 0x9c, 0x06, 0x29, +0x85, 0x8a, 0xd0, 0x54, 0xd3, 0xb4, 0x77, 0x1f, 0xa6, 0x4d, 0x96, 0x8a, 0x1b, 0xfc, 0xf9, 0x70, +0xec, 0xc3, 0x18, 0x43, 0x48, 0x1f, 0x3f, 0x42, 0x98, 0xcb, 0x58, 0x4d, 0xd3, 0xf4, 0x25, 0xc4, +0x94, 0x6f, 0x00, 0x50, 0x6e, 0xf5, 0x0e, 0x9d, 0x9f, 0x42, 0xc1, 0x60, 0x6d, 0x2e, 0x1f, 0x3a, +0x7a, 0x6e, 0x0d, 0x43, 0x11, 0xae, 0x77, 0x44, 0x5a, 0x57, 0x16, 0x28, 0x55, 0x88, 0xf3, 0xb7, +0x7b, 0x2a, 0xa6, 0x44, 0x94, 0xeb, 0xa4, 0xcd, 0x42, 0xc2, 0x84, 0x68, 0x29, 0x8e, 0x15, 0x22, +0x66, 0xe6, 0xf5, 0x56, 0x14, 0x4d, 0xd3, 0xe4, 0xea, 0x16, 0xdd, 0x55, 0xc7, 0x6f, 0xf6, 0xe8, +0x09, 0xe1, 0x9f, 0x88, 0x39, 0x6c, 0xfc, 0x08, 0xda, 0x96, 0x64, 0xcf, 0xd3, 0x08, 0x83, 0xb7, +0x2f, 0xed, 0x50, 0xa3, 0x7c, 0x79, 0x69, 0x4c, 0x6e, 0xa3, 0xb1, 0xea, 0xba, 0x8e, 0x97, 0xcf, +0xc1, 0x28, 0x96, 0x01, 0xb5, 0xe4, 0x93, 0xd9, 0x35, 0x58, 0xbd, 0x9c, 0xa2, 0x3a, 0xbf, 0xe9, +0xc5, 0xd9, 0x27, 0x51, 0x8a, 0xf7, 0x0c, 0x29, 0x2b, 0x66, 0xd2, 0x56, 0x24, 0x97, 0x96, 0xec, +0x26, 0xa9, 0x53, 0xd0, 0x1c, 0x2d, 0x96, 0x9a, 0xbc, 0x21, 0xb4, 0xfc, 0x7e, 0x7b, 0x93, 0x7e, +0x62, 0x2f, 0x9f, 0xe9, 0x5f, 0xbc, 0xa4, 0xab, 0x0d, 0xec, 0x62, 0xeb, 0xd6, 0xc3, 0x56, 0xca, +0x83, 0x8d, 0x95, 0x2a, 0xc3, 0x71, 0x7e, 0xb3, 0x03, 0x68, 0x50, 0xc2, 0x89, 0x9b, 0xcb, 0xe9, +0x77, 0xd2, 0x5a, 0xe0, 0xfe, 0x7d, 0xb9, 0xe4, 0x36, 0x67, 0xff, 0xfd, 0x03, 0x3b, 0xc9, 0xfb, +0x95, 0xd5, 0x01, 0x00, 0x00}; +#endif /*__COLORBRIGHT_CSS_H__*/ diff --git a/src/web/html/h/colorDark_css.h b/src/web/html/h/colorDark_css.h new file mode 100644 index 00000000..a24f888b --- /dev/null +++ b/src/web/html/h/colorDark_css.h @@ -0,0 +1,21 @@ +#ifndef __COLORDARK_CSS_H__ +#define __COLORDARK_CSS_H__ +#define colorDark_css_len 255 +const uint8_t colorDark_css[] PROGMEM = { +0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0x5d, 0x90, 0xd9, 0x6e, 0xc3, 0x20, +0x10, 0x45, 0x7f, 0xa5, 0x92, 0x9f, 0x91, 0x58, 0x6c, 0xc7, 0x72, 0xbf, 0x66, 0xd8, 0x6a, 0x24, +0x07, 0x22, 0x20, 0x44, 0x55, 0xd5, 0x7f, 0x2f, 0x0c, 0x76, 0xd2, 0x56, 0xbc, 0xcc, 0x9c, 0xb9, +0xdc, 0x59, 0xd6, 0x18, 0x42, 0x7e, 0xfb, 0x22, 0x44, 0x7e, 0xac, 0x03, 0xe7, 0xfc, 0x9d, 0x10, +0x5b, 0x23, 0xa5, 0x14, 0x46, 0x7c, 0x1d, 0xac, 0xb5, 0x35, 0x74, 0xde, 0x86, 0x75, 0xa0, 0xf4, +0xc2, 0xd5, 0x52, 0xd3, 0x07, 0x44, 0xdf, 0x4a, 0x00, 0x94, 0xd6, 0x34, 0xdd, 0x95, 0x32, 0x29, +0x35, 0x81, 0x94, 0x48, 0x9c, 0xbf, 0xdd, 0x33, 0x9a, 0x0a, 0x21, 0x6a, 0x9e, 0x41, 0xee, 0x86, +0xc8, 0x10, 0xb5, 0x89, 0x27, 0xf3, 0x50, 0x7e, 0x29, 0x6e, 0xd1, 0x5d, 0x21, 0x7e, 0x36, 0x8f, +0x51, 0x2f, 0x97, 0x17, 0x21, 0x5b, 0x28, 0xed, 0x13, 0xe5, 0x82, 0x4d, 0x53, 0xeb, 0x66, 0x54, +0xf0, 0xfa, 0xd0, 0x1e, 0x03, 0x35, 0x2f, 0x50, 0xd9, 0x15, 0xb3, 0x0e, 0x13, 0xaa, 0x6c, 0x5d, +0xcc, 0xc4, 0xbe, 0xd7, 0xd2, 0x5e, 0x65, 0xd7, 0xa0, 0x61, 0x47, 0x34, 0xcf, 0x33, 0x4e, 0x59, +0x60, 0x77, 0x1a, 0xc9, 0x88, 0x73, 0xe7, 0x90, 0xab, 0x62, 0x33, 0xa0, 0x49, 0x76, 0x79, 0xef, +0x6e, 0x13, 0x63, 0xcf, 0xd2, 0xf1, 0x79, 0xc6, 0x53, 0xb9, 0xf2, 0x47, 0xca, 0xd8, 0x21, 0x3d, +0x79, 0x3f, 0xea, 0x4b, 0xac, 0x5d, 0x3a, 0xb5, 0x7d, 0xe9, 0xce, 0x6a, 0xf3, 0x71, 0xac, 0x99, +0xda, 0xfe, 0xd9, 0x71, 0x8e, 0xab, 0x9c, 0xbc, 0xdb, 0x09, 0x81, 0xb3, 0xe7, 0x84, 0xf0, 0x79, +0xe0, 0x84, 0xe5, 0xb6, 0xfb, 0xf7, 0x0f, 0xe9, 0x86, 0x9e, 0xcf, 0xd5, 0x01, 0x00, 0x00}; +#endif /*__COLORDARK_CSS_H__*/ diff --git a/src/web/html/h/favicon_ico.h b/src/web/html/h/favicon_ico.h new file mode 100644 index 00000000..defec936 --- /dev/null +++ b/src/web/html/h/favicon_ico.h @@ -0,0 +1,101 @@ +#ifndef __FAVICON_ICO_H__ +#define __FAVICON_ICO_H__ +#define favicon_ico_len 1534 +const uint8_t favicon_ico[] PROGMEM = { +0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0xed, 0x5c, 0x4b, 0x6c, 0x1b, 0x55, +0x14, 0x3d, 0x4e, 0x9c, 0xba, 0x48, 0x51, 0x93, 0x05, 0x48, 0x95, 0x88, 0x62, 0xf3, 0x59, 0x64, +0x97, 0xa0, 0x4a, 0x6d, 0x11, 0x51, 0x5d, 0x21, 0x40, 0x88, 0xa6, 0xec, 0xb2, 0x42, 0x95, 0xb2, +0x2a, 0xec, 0xa0, 0xa2, 0xcd, 0x58, 0x22, 0x90, 0x49, 0xf3, 0xe9, 0x07, 0x5a, 0x3b, 0x69, 0x8b, +0x28, 0xb4, 0xa8, 0xad, 0x9b, 0xb6, 0x44, 0x7c, 0xa4, 0x02, 0x25, 0x69, 0x91, 0x6a, 0x67, 0x01, +0x9b, 0x2e, 0xd8, 0x56, 0x75, 0x22, 0x8b, 0x0d, 0xbb, 0x28, 0x4b, 0x2f, 0xac, 0x3c, 0xee, 0x9d, +0x79, 0xe3, 0x38, 0x93, 0x89, 0xff, 0xf1, 0x4b, 0xfc, 0xf2, 0xa4, 0xa3, 0x63, 0x8f, 0xe7, 0xcd, +0xb9, 0xe7, 0xcc, 0x78, 0xe6, 0x65, 0xde, 0xc4, 0x80, 0x0f, 0xcd, 0x68, 0x6f, 0x07, 0x71, 0x08, +0x1f, 0xf9, 0x81, 0xfd, 0x00, 0x42, 0x21, 0xfb, 0xfd, 0x3d, 0x5a, 0xfe, 0x3d, 0x2d, 0x3b, 0x7c, +0xd8, 0x7e, 0xdf, 0xf5, 0x26, 0xf0, 0xce, 0x0b, 0x40, 0x17, 0xad, 0xd3, 0xce, 0xeb, 0xc1, 0x5e, +0xbe, 0x51, 0x5b, 0x48, 0x46, 0xcd, 0x85, 0x64, 0x4c, 0x10, 0x0c, 0x71, 0x1b, 0xd7, 0x09, 0x42, +0x4c, 0xe3, 0xe9, 0x23, 0x03, 0xbd, 0x73, 0x06, 0x04, 0x83, 0x5f, 0x0f, 0xf6, 0xe1, 0x29, 0x41, +0x18, 0x7d, 0xb8, 0xde, 0xdd, 0x09, 0xa3, 0x27, 0x08, 0xc1, 0x58, 0x98, 0x8f, 0x8d, 0xc8, 0x6d, +0x54, 0xd6, 0xdf, 0xd2, 0x8e, 0x9a, 0xcf, 0x1e, 0x4f, 0x75, 0x54, 0xde, 0xdf, 0xda, 0xc6, 0x07, +0x22, 0x8e, 0x8f, 0x2b, 0xef, 0x4f, 0xf5, 0x4f, 0xa3, 0x87, 0xfa, 0x8f, 0x56, 0xdc, 0x9f, 0xeb, +0x9f, 0xc6, 0x30, 0x61, 0xa0, 0xe2, 0xfe, 0x5c, 0xff, 0x6d, 0x7c, 0x36, 0x3b, 0x88, 0xfd, 0x15, +0xf7, 0xa7, 0xfa, 0x79, 0xdf, 0x52, 0xdf, 0xd1, 0x6a, 0xfa, 0x3b, 0xdb, 0xa8, 0xa6, 0x3f, 0xb7, +0xbf, 0x4e, 0xe0, 0xb9, 0x32, 0xfd, 0x8f, 0xb9, 0x8f, 0xd3, 0xc1, 0x23, 0x18, 0x2b, 0x31, 0xff, +0x0b, 0x1b, 0x1d, 0xeb, 0xc6, 0x51, 0x8c, 0x17, 0xec, 0x7f, 0x0b, 0x07, 0x50, 0xa4, 0x9d, 0x7c, +0x0f, 0x07, 0xbc, 0xfa, 0xa7, 0xe6, 0xa3, 0x03, 0x28, 0xb1, 0xf5, 0x84, 0x30, 0xb0, 0xa6, 0x7f, +0x22, 0x76, 0xd1, 0x6b, 0xbd, 0xc7, 0x26, 0x76, 0x33, 0x3c, 0xb7, 0xd1, 0x89, 0x09, 0xab, 0xff, +0x06, 0x7d, 0x67, 0x4c, 0xec, 0x9a, 0x8b, 0xe0, 0x57, 0xda, 0x7f, 0x73, 0x9c, 0xff, 0x46, 0xdb, +0x28, 0x54, 0x67, 0x13, 0xa1, 0x99, 0x61, 0x12, 0x12, 0x40, 0x20, 0x0d, 0xb4, 0x2d, 0x03, 0xc1, +0x0c, 0x70, 0x68, 0x08, 0x18, 0x3a, 0x64, 0x9f, 0x67, 0xf8, 0xec, 0x72, 0xb8, 0xf4, 0xf3, 0x8c, +0x83, 0x25, 0x5e, 0x2e, 0xee, 0xa0, 0x57, 0xee, 0xf3, 0x55, 0xc4, 0x71, 0x9f, 0x3f, 0x9b, 0x8d, +0xc0, 0x70, 0xbe, 0x03, 0x0e, 0x78, 0x19, 0x7f, 0x76, 0xaa, 0x0f, 0xf7, 0xf9, 0x78, 0xc8, 0x07, +0xed, 0xdf, 0x5e, 0xcb, 0x57, 0x10, 0x4b, 0x4e, 0xbe, 0x0e, 0xac, 0x1a, 0xac, 0x73, 0x95, 0x1a, +0xfd, 0xd4, 0x7c, 0x6c, 0xdc, 0x55, 0x43, 0x5d, 0xf5, 0x59, 0x73, 0x31, 0x11, 0x3b, 0x9f, 0x57, +0x43, 0xdd, 0xf5, 0xad, 0x1a, 0x92, 0xb1, 0x51, 0x5e, 0x87, 0xf8, 0x53, 0x15, 0xfa, 0x16, 0xe6, +0xa3, 0xe7, 0x9c, 0xe3, 0x52, 0x89, 0xbe, 0x55, 0x43, 0x6c, 0xc4, 0xd2, 0x9f, 0xc6, 0x7e, 0x25, +0xfa, 0x72, 0xff, 0x5b, 0x35, 0xf0, 0x35, 0x4f, 0x91, 0xbe, 0x98, 0x42, 0x40, 0xd6, 0x30, 0xa1, +0x44, 0x9f, 0xf7, 0x3f, 0x5d, 0xb3, 0x65, 0x0d, 0x63, 0x4a, 0xf4, 0x6d, 0xdf, 0x5f, 0xe4, 0x6a, +0x50, 0xa3, 0xbf, 0x5a, 0x43, 0x1c, 0x6f, 0x2b, 0xd2, 0xcf, 0xd5, 0xa0, 0x50, 0x9f, 0xc7, 0x2f, +0x27, 0xf8, 0xb3, 0x87, 0x11, 0x0c, 0x28, 0xd1, 0x97, 0xfb, 0xdf, 0x1a, 0x7f, 0x45, 0x30, 0xa1, +0x52, 0xdf, 0x5d, 0x83, 0x0a, 0x7d, 0x39, 0x0e, 0x3d, 0xa3, 0x52, 0xdf, 0xa9, 0x41, 0xa5, 0x3e, +0xb7, 0x07, 0xa7, 0xf0, 0x8a, 0x4a, 0x7d, 0xa7, 0x6d, 0xb2, 0xbe, 0x59, 0x4c, 0x9f, 0xf4, 0xcc, +0x4d, 0xd2, 0xff, 0x46, 0x08, 0x1a, 0xca, 0x16, 0x6f, 0x3e, 0xd2, 0x9c, 0xac, 0xa9, 0x7e, 0x1c, +0x57, 0x4b, 0xd4, 0xf6, 0xac, 0xa1, 0x2a, 0xfd, 0xf2, 0xb5, 0x73, 0x35, 0x90, 0xee, 0x54, 0x95, +0xfa, 0xdf, 0x56, 0xa8, 0xbd, 0xa6, 0x86, 0x8a, 0xf4, 0x67, 0xd0, 0x5a, 0xa5, 0x76, 0xae, 0x06, +0xb3, 0x1f, 0xad, 0x95, 0x8c, 0xbf, 0x6a, 0xdd, 0x4a, 0xd1, 0x4f, 0x25, 0x63, 0x97, 0x36, 0x4b, +0xff, 0xb5, 0x20, 0x2e, 0x15, 0xd2, 0x4f, 0x25, 0x26, 0xbf, 0x13, 0xc2, 0x6c, 0xc2, 0xe6, 0x35, +0x1f, 0x69, 0x5e, 0xf6, 0xd2, 0xaf, 0x44, 0x7b, 0xee, 0x24, 0x5e, 0x62, 0x54, 0x53, 0x83, 0xd4, +0xbf, 0x56, 0xae, 0xf6, 0x23, 0x03, 0x9d, 0x74, 0xdd, 0x59, 0x9c, 0x1b, 0xc4, 0xbf, 0x7f, 0x46, +0xf0, 0x72, 0x05, 0x35, 0x5c, 0x91, 0xfa, 0x65, 0x6b, 0xff, 0x11, 0x41, 0x88, 0xc6, 0x40, 0x69, +0xe7, 0xda, 0xcf, 0xaf, 0x79, 0x59, 0x25, 0x35, 0xf8, 0x77, 0xb7, 0x87, 0xc6, 0x08, 0x6f, 0x11, +0x5e, 0x25, 0x3c, 0x4f, 0x68, 0x25, 0xf0, 0xf2, 0x5d, 0x84, 0x16, 0x7e, 0x7d, 0x96, 0xf0, 0x2e, +0xa1, 0x8b, 0xb0, 0xd7, 0xfe, 0xcc, 0xdf, 0x4a, 0xd8, 0x43, 0x68, 0x63, 0xc4, 0x08, 0xff, 0x10, +0x96, 0x57, 0x11, 0xcc, 0x84, 0xfc, 0xe1, 0x6c, 0xc8, 0x3f, 0xbc, 0x12, 0xf2, 0x0b, 0x11, 0x0a, +0x08, 0x91, 0x76, 0xd0, 0xb6, 0x32, 0xbc, 0x1c, 0xcc, 0x86, 0x33, 0xe1, 0x4c, 0x30, 0xdb, 0x25, +0xef, 0x51, 0x98, 0xe5, 0xdf, 0xa7, 0xf0, 0xfa, 0xdb, 0x2d, 0x95, 0xdf, 0x87, 0xc6, 0x8b, 0xc6, +0xba, 0x6b, 0x98, 0x17, 0xa6, 0x71, 0xdc, 0x35, 0x9e, 0x58, 0x72, 0x8f, 0x2f, 0x3d, 0xb0, 0xe4, +0xba, 0x0f, 0x76, 0xdc, 0x7d, 0xdd, 0xf3, 0xc4, 0x11, 0x7b, 0x9c, 0x92, 0x77, 0x4e, 0x48, 0xb9, +0xbf, 0x93, 0x5e, 0xf0, 0xb8, 0x4f, 0xa2, 0x9d, 0xff, 0xa2, 0x19, 0x68, 0xe0, 0xdf, 0xba, 0x47, +0x93, 0x88, 0x9e, 0xd6, 0xcd, 0xff, 0xc2, 0xfc, 0xe4, 0x85, 0xa2, 0x19, 0x34, 0xb2, 0x7f, 0x7b, +0x6c, 0xf0, 0x55, 0xc1, 0x0c, 0x1a, 0xdc, 0xbf, 0x67, 0x06, 0xc9, 0xd8, 0xa8, 0x4e, 0xfe, 0xed, +0x0c, 0xa2, 0x5f, 0x7a, 0x66, 0xa0, 0x89, 0x7f, 0xaf, 0x0c, 0x52, 0xc9, 0xc9, 0x31, 0x9d, 0xfc, +0xdb, 0x73, 0x5b, 0xf6, 0xdc, 0xc5, 0x6a, 0x06, 0xb1, 0x0f, 0x75, 0xf2, 0x9f, 0x3f, 0x77, 0xe2, +0xd5, 0x74, 0xf0, 0x5f, 0x28, 0x03, 0x5d, 0xfc, 0xbb, 0xe7, 0x8e, 0xb4, 0xf4, 0x6f, 0x61, 0x72, +0xd8, 0xe5, 0x7f, 0x40, 0x2b, 0xff, 0xae, 0xf3, 0xff, 0xba, 0xf9, 0x2b, 0x0d, 0xfd, 0x97, 0x94, +0x41, 0x83, 0xfb, 0x97, 0x19, 0x9c, 0xd1, 0xcd, 0xbf, 0xb8, 0x89, 0x17, 0xd7, 0xbc, 0x8f, 0xe3, +0xa2, 0x56, 0xfe, 0xf9, 0xfc, 0x2f, 0xe7, 0x90, 0xf3, 0x32, 0x38, 0xab, 0x95, 0x7f, 0xd7, 0xdc, +0xad, 0x67, 0x06, 0x8d, 0xef, 0x7f, 0x4d, 0x06, 0x3c, 0xaf, 0x40, 0xef, 0x27, 0x35, 0xf3, 0xcf, +0x73, 0x49, 0x9f, 0x7b, 0x66, 0xa0, 0x8b, 0x7f, 0xef, 0x0c, 0xa6, 0xb4, 0xf2, 0x2f, 0x9f, 0x63, +0x75, 0x65, 0xd0, 0xa1, 0x99, 0x7f, 0x3e, 0xe6, 0x87, 0x36, 0x9c, 0x57, 0xd2, 0xc1, 0xbf, 0xeb, +0x38, 0xd0, 0xd4, 0xbf, 0x67, 0x06, 0x9a, 0xf9, 0xe7, 0x73, 0xe2, 0xfb, 0xf9, 0xfd, 0x1e, 0x46, +0x70, 0x49, 0x2b, 0xff, 0xae, 0xf3, 0xbf, 0x00, 0x7c, 0xb3, 0x06, 0x2e, 0xeb, 0xea, 0xbf, 0xc4, +0x0c, 0x1a, 0xda, 0xbf, 0x93, 0xc1, 0x5c, 0x04, 0x57, 0x74, 0xf5, 0x5f, 0x24, 0x03, 0x2d, 0xfc, +0x17, 0xc8, 0x40, 0x1b, 0xff, 0xb9, 0x0c, 0x0c, 0x7c, 0xad, 0xab, 0x7f, 0x8f, 0x0c, 0xb4, 0xf3, +0xef, 0xca, 0x40, 0x4b, 0xff, 0x79, 0xe7, 0x83, 0x09, 0x5d, 0xfd, 0x7b, 0x3e, 0xf7, 0xbb, 0xe3, +0x7f, 0xc7, 0xff, 0xf6, 0xf5, 0x7f, 0xac, 0x6a, 0xff, 0x47, 0x71, 0x6c, 0x5b, 0xfa, 0x8f, 0xe3, +0xae, 0x98, 0xb1, 0xfe, 0x9d, 0xb4, 0xaa, 0x66, 0x9a, 0x68, 0xa2, 0x0c, 0x6e, 0x6c, 0x2b, 0xff, +0x35, 0xf2, 0x5e, 0x56, 0x06, 0x5b, 0xc7, 0xff, 0x3d, 0xf1, 0x18, 0xfe, 0x5a, 0x3f, 0xe0, 0xcd, +0x19, 0x9c, 0xea, 0xc3, 0xcd, 0x2d, 0xee, 0x7f, 0x53, 0xbc, 0x3b, 0xad, 0xbf, 0x1f, 0xcd, 0x1b, +0x66, 0xa0, 0xde, 0xff, 0x0f, 0x9b, 0xe9, 0x3d, 0x3f, 0x03, 0xf2, 0x7b, 0x6b, 0x8b, 0xf9, 0xaf, +0x8b, 0xf7, 0x82, 0x19, 0xa8, 0xf3, 0x5f, 0x57, 0xef, 0x6b, 0xbe, 0x0b, 0x47, 0x11, 0x57, 0xec, +0x7f, 0x46, 0x85, 0x77, 0xcf, 0x0c, 0xea, 0xef, 0x5f, 0xa9, 0xf7, 0x75, 0x19, 0xd4, 0xd3, 0x7f, +0x1c, 0xdd, 0xb5, 0xbc, 0xbe, 0xd7, 0x22, 0x03, 0xa3, 0x0f, 0xdd, 0x2a, 0x9e, 0x7f, 0xd9, 0xaa, +0x6d, 0xc7, 0xff, 0x8e, 0xff, 0x5a, 0xf9, 0x5f, 0x4c, 0x46, 0x6f, 0x6c, 0x3b, 0xff, 0x9d, 0xb8, +0x51, 0x23, 0xff, 0x3f, 0x3e, 0x79, 0x72, 0xb5, 0x65, 0xbb, 0xf9, 0xef, 0x07, 0x9a, 0xc9, 0xdf, +0x74, 0x95, 0xfe, 0xb7, 0xa5, 0xf7, 0x72, 0x32, 0x68, 0x54, 0xef, 0xae, 0x0c, 0xee, 0x94, 0xe9, +0xff, 0xa7, 0x46, 0xf0, 0x5e, 0x4a, 0x06, 0x2a, 0xbd, 0xcf, 0x1a, 0x18, 0x67, 0xd4, 0x2b, 0x83, +0xee, 0x20, 0xee, 0x16, 0xf1, 0x5f, 0x3f, 0xef, 0x11, 0x9c, 0xce, 0xcd, 0x79, 0x0d, 0xe2, 0xbc, +0xaa, 0x0c, 0xf2, 0x9e, 0xf1, 0xff, 0xed, 0xd9, 0x83, 0xa9, 0x40, 0x3d, 0xea, 0x78, 0x68, 0x60, +0x64, 0xdd, 0xef, 0xec, 0x18, 0x38, 0x57, 0x0f, 0xed, 0x7d, 0xfb, 0xd0, 0x42, 0xbe, 0x7f, 0x76, +0xf9, 0xff, 0x5d, 0xa5, 0x77, 0x45, 0x19, 0xfc, 0x22, 0xfd, 0x6f, 0x09, 0xef, 0xb9, 0xdf, 0x1c, +0xa0, 0x75, 0xea, 0x99, 0x01, 0x0e, 0x22, 0x1d, 0x40, 0x07, 0x4c, 0xc9, 0x09, 0xc9, 0x69, 0xc9, +0x9f, 0x48, 0x3e, 0x28, 0xb9, 0x43, 0xf2, 0x1e, 0xc9, 0x01, 0xc9, 0xcd, 0xb3, 0x36, 0xfb, 0x32, +0x36, 0xc3, 0xe1, 0x88, 0x64, 0xb9, 0x1e, 0x7a, 0x25, 0x1f, 0x92, 0x1c, 0x96, 0xfc, 0x86, 0x69, +0xf3, 0xeb, 0x09, 0xb9, 0x7e, 0x5a, 0xf2, 0x80, 0xe4, 0x1e, 0xc9, 0x7b, 0x25, 0xb7, 0x4a, 0x0e, +0x48, 0x6e, 0x96, 0xec, 0x5b, 0xab, 0xb7, 0xca, 0xcb, 0x92, 0x33, 0x92, 0xb3, 0x92, 0x57, 0x24, +0x0b, 0x87, 0xcf, 0x48, 0xfe, 0x5b, 0xf2, 0x7f, 0x92, 0x45, 0x49, 0xec, 0x13, 0xc2, 0xb4, 0xea, +0x11, 0x22, 0x61, 0xd5, 0x27, 0x44, 0x9a, 0xb9, 0x4d, 0x88, 0x65, 0xe6, 0xa0, 0x10, 0x19, 0xe6, +0xb0, 0x10, 0x59, 0xe6, 0x61, 0x21, 0x56, 0x98, 0x05, 0x35, 0xf6, 0xcf, 0x7c, 0x8d, 0x72, 0x61, +0xce, 0x16, 0xe7, 0x61, 0xe6, 0x15, 0x7e, 0xe0, 0x94, 0x1b, 0x7c, 0x36, 0x9b, 0xa4, 0xbe, 0x42, +0x1f, 0x25, 0x48, 0x3d, 0x1b, 0xe6, 0xdf, 0x86, 0x20, 0x55, 0x52, 0x5e, 0x66, 0xf0, 0xeb, 0xb0, +0xfd, 0x9b, 0x11, 0xd9, 0xff, 0x01, 0xd3, 0x39, 0x74, 0x2c, 0x6e, 0x57, 0x00, 0x00}; +#endif /*__FAVICON_ICO_H__*/ diff --git a/src/web/html/h/index_html.h b/src/web/html/h/index_html.h new file mode 100644 index 00000000..7ae17e4c --- /dev/null +++ b/src/web/html/h/index_html.h @@ -0,0 +1,191 @@ +#ifndef __INDEX_HTML_H__ +#define __INDEX_HTML_H__ +#define index_html_len 2967 +const uint8_t index_html[] PROGMEM = { +0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0xbd, 0x5a, 0xff, 0x6f, 0xdb, 0x36, +0x16, 0xff, 0xbd, 0x7f, 0x05, 0xa7, 0xc3, 0xb5, 0xf2, 0xc5, 0x96, 0x9c, 0xa4, 0x4d, 0x7b, 0x89, +0xe3, 0x21, 0x4b, 0xb2, 0x2d, 0x87, 0xae, 0x2d, 0xea, 0xf4, 0x8a, 0xa1, 0x28, 0x02, 0x5a, 0xa2, +0x6d, 0xb6, 0x32, 0x29, 0x88, 0x94, 0x5d, 0x6f, 0xeb, 0xff, 0x7e, 0xef, 0x51, 0x5f, 0x6c, 0x59, +0xa2, 0x6c, 0xaf, 0xbb, 0x19, 0x08, 0x62, 0x51, 0xe4, 0xe3, 0xe7, 0x7d, 0x7f, 0x8f, 0xf4, 0xe0, +0xbb, 0x50, 0x06, 0x7a, 0x15, 0x33, 0x32, 0xd3, 0xf3, 0x68, 0xf8, 0x68, 0x90, 0xfd, 0x23, 0xf0, +0x19, 0xcc, 0x18, 0x0d, 0xb3, 0xaf, 0xe6, 0x51, 0x73, 0x1d, 0xb1, 0xe1, 0x9d, 0x08, 0xd9, 0x97, +0x81, 0x9f, 0x3d, 0xac, 0x5f, 0x46, 0x5c, 0x7c, 0x26, 0x09, 0x8b, 0x2e, 0x1d, 0xa5, 0x57, 0x11, +0x53, 0x33, 0xc6, 0xb4, 0x43, 0x90, 0xf0, 0xa5, 0xa3, 0xd9, 0x17, 0xed, 0x07, 0x4a, 0x39, 0x64, +0x96, 0xb0, 0x49, 0x3e, 0xc3, 0x83, 0x81, 0xef, 0x17, 0x97, 0x7d, 0xef, 0x85, 0xd7, 0xef, 0xf7, +0x8f, 0x1d, 0x1f, 0xf6, 0x9e, 0x33, 0x4d, 0x89, 0xa0, 0x73, 0x58, 0xb3, 0xe0, 0x6c, 0x19, 0xcb, +0x04, 0x68, 0x04, 0x52, 0x68, 0x26, 0xf4, 0xa5, 0xb3, 0xe4, 0xa1, 0x9e, 0x5d, 0x86, 0x6c, 0xc1, +0x03, 0xd6, 0x33, 0x0f, 0x5d, 0xc2, 0x05, 0xd7, 0x9c, 0x46, 0x3d, 0x15, 0xd0, 0x88, 0x5d, 0x1e, +0x3b, 0x05, 0x91, 0x60, 0x46, 0x13, 0xc5, 0x60, 0xd1, 0xbb, 0xfb, 0x1f, 0x7b, 0x2f, 0x70, 0x58, +0x05, 0x09, 0x8f, 0xf5, 0x26, 0xa2, 0x4f, 0x74, 0x41, 0xb3, 0x51, 0x87, 0xa8, 0x24, 0xb8, 0x74, +0x68, 0xcc, 0xbd, 0x4f, 0x15, 0x50, 0xc3, 0x81, 0x9f, 0xcd, 0x00, 0x02, 0x87, 0x70, 0x18, 0xc8, +0x48, 0x26, 0x6a, 0x07, 0x8b, 0x89, 0x1c, 0x4b, 0xad, 0x36, 0x18, 0x14, 0x92, 0xa3, 0x70, 0xbb, +0x44, 0xc8, 0x89, 0x8c, 0x22, 0xb9, 0x74, 0x88, 0x9f, 0xab, 0xc2, 0x5f, 0xeb, 0x62, 0x30, 0x96, +0xe1, 0x6a, 0x43, 0xf2, 0x21, 0x5f, 0x90, 0x20, 0xa2, 0x4a, 0x01, 0x0c, 0x19, 0x0b, 0xba, 0x70, +0xf2, 0x79, 0x34, 0x07, 0xe3, 0x6f, 0x62, 0x28, 0xa7, 0xa2, 0xfe, 0x9c, 0xe1, 0xd5, 0x4c, 0xae, +0x6e, 0xee, 0xdf, 0x0d, 0x7c, 0xba, 0xb5, 0x68, 0x2d, 0x9c, 0xf3, 0x85, 0xe4, 0xa1, 0xdb, 0xef, +0x5c, 0x94, 0x6b, 0x39, 0x20, 0x76, 0x88, 0x14, 0x41, 0xc4, 0x83, 0xcf, 0xc5, 0xae, 0x6e, 0xc7, +0xd9, 0x00, 0xa5, 0x62, 0x2a, 0x50, 0x78, 0xf8, 0xef, 0xe0, 0xd1, 0x35, 0x1a, 0xe4, 0x8d, 0x87, +0x25, 0x63, 0x05, 0x80, 0xb9, 0x1c, 0x73, 0x44, 0xbf, 0xa6, 0x41, 0xcd, 0x34, 0x98, 0x73, 0x5a, +0x4e, 0x9a, 0xf1, 0x90, 0x15, 0xfa, 0xf0, 0x23, 0xbe, 0x60, 0x15, 0xc5, 0xbe, 0x84, 0x81, 0x72, +0x9f, 0x2a, 0x89, 0xa7, 0xcd, 0x24, 0x14, 0x4b, 0xc0, 0xd2, 0x2a, 0x44, 0xde, 0xb3, 0x71, 0x36, +0x6a, 0xa1, 0xf4, 0xcc, 0x46, 0x49, 0xa7, 0x71, 0x85, 0xd0, 0x88, 0x69, 0xcd, 0xc5, 0x54, 0x55, +0xe9, 0xa0, 0x44, 0x0a, 0x02, 0x8a, 0xc5, 0x2c, 0xa1, 0x5a, 0x26, 0x4e, 0x5d, 0x80, 0xe5, 0x7e, +0x67, 0xcd, 0xfb, 0xa5, 0x71, 0x48, 0x75, 0x95, 0xfd, 0x77, 0x66, 0xc8, 0x02, 0xfb, 0xb9, 0x05, +0xf6, 0x4a, 0x69, 0x36, 0xaf, 0xe2, 0x36, 0x43, 0xdf, 0x88, 0xfa, 0x45, 0xb9, 0x03, 0x38, 0x20, +0x78, 0x14, 0x4d, 0xa6, 0xe8, 0xb9, 0x0f, 0xe3, 0x88, 0x8a, 0xcf, 0xce, 0xf0, 0xed, 0xed, 0xe8, +0x9e, 0x5c, 0xbd, 0xb9, 0xb3, 0x80, 0xfd, 0x77, 0xb1, 0x7a, 0xa6, 0x75, 0xac, 0xce, 0x7d, 0x9f, +0x82, 0x49, 0x87, 0x3a, 0xf5, 0x10, 0xf9, 0x36, 0xad, 0x1b, 0x19, 0xa4, 0x73, 0xf0, 0x35, 0xaa, +0xb9, 0x14, 0x16, 0x82, 0xc7, 0xfd, 0x35, 0x9e, 0xb1, 0x4c, 0x75, 0x85, 0xe1, 0x2b, 0x1c, 0xf9, +0x46, 0x7e, 0xfb, 0x16, 0x13, 0x95, 0x53, 0x2e, 0xc0, 0x30, 0xf1, 0x9f, 0x0d, 0x9a, 0x75, 0x25, +0xa0, 0x32, 0x4b, 0x37, 0xd1, 0x0d, 0x7c, 0x70, 0x9f, 0x2d, 0x47, 0x5a, 0xf2, 0x09, 0xcf, 0xdc, +0xb7, 0xf0, 0x65, 0x31, 0x91, 0x08, 0xd6, 0x4c, 0xdd, 0x58, 0x51, 0x5d, 0x95, 0xd0, 0x18, 0x18, +0xdb, 0x70, 0xb8, 0xca, 0xeb, 0x3c, 0x80, 0x6d, 0xbd, 0x36, 0x53, 0xe2, 0xfa, 0x58, 0x4d, 0x68, +0x21, 0x53, 0x68, 0x90, 0x9a, 0xcf, 0xd9, 0x39, 0xc9, 0xc5, 0x96, 0x4d, 0x40, 0xe2, 0xa9, 0x79, +0x51, 0xca, 0x73, 0x30, 0x4e, 0xfc, 0x7d, 0x69, 0xde, 0x8e, 0xde, 0xf4, 0xee, 0x9b, 0xa9, 0xa2, +0xf5, 0xd7, 0x75, 0x54, 0x92, 0xf2, 0xe3, 0x6f, 0xe1, 0x25, 0xf3, 0x0a, 0x72, 0x07, 0xa2, 0x55, +0xe7, 0xb6, 0x3d, 0x2a, 0x12, 0xe4, 0x8b, 0x52, 0x07, 0xd6, 0x79, 0x85, 0xe6, 0x93, 0xdd, 0x53, +0x8d, 0xce, 0x68, 0x22, 0x1e, 0x2a, 0xda, 0x6d, 0xe4, 0xf2, 0x91, 0x95, 0x80, 0x90, 0x9a, 0x39, +0x96, 0x4d, 0x66, 0xa7, 0xc3, 0x51, 0x1a, 0x63, 0x7e, 0x26, 0x7a, 0xc6, 0x15, 0x89, 0x13, 0xf9, +0x89, 0x05, 0x1a, 0x98, 0x85, 0x37, 0xcd, 0x4b, 0xd2, 0xa8, 0xf9, 0x45, 0x5e, 0x3d, 0x0c, 0xcb, +0xcc, 0x53, 0xf8, 0xf1, 0x94, 0xeb, 0x59, 0x3a, 0xf6, 0x02, 0x39, 0xf7, 0xa3, 0x74, 0x4e, 0xe3, +0xd4, 0x78, 0xb6, 0x3f, 0x8e, 0xe4, 0xd8, 0x9f, 0x53, 0x2e, 0x7c, 0xc8, 0xd9, 0xfe, 0xf5, 0xcf, +0x57, 0xaf, 0x7e, 0xba, 0x1d, 0x79, 0xf3, 0xb0, 0xee, 0xec, 0xd7, 0x33, 0x2a, 0xa6, 0x0c, 0x9c, +0x03, 0x3d, 0x62, 0x00, 0x29, 0xa0, 0x1d, 0xc0, 0x0d, 0x57, 0x41, 0xaa, 0x14, 0x59, 0xc2, 0xbe, +0x24, 0x55, 0x90, 0xdf, 0x48, 0x0d, 0x53, 0x08, 0x73, 0x64, 0x12, 0x7a, 0xd3, 0xa9, 0xff, 0xfe, +0xb7, 0xd9, 0x97, 0xdb, 0x5f, 0xcf, 0x4e, 0xe6, 0x3f, 0x38, 0x66, 0x29, 0x0c, 0xef, 0xb7, 0xcf, +0x5b, 0x66, 0xe4, 0xb6, 0x2f, 0xbf, 0x5c, 0xa9, 0x14, 0x8c, 0xaa, 0xc6, 0x5d, 0x36, 0xbe, 0xdf, +0x96, 0xd7, 0xe0, 0xa0, 0x09, 0x1f, 0xa7, 0x9a, 0x11, 0x2d, 0xc9, 0xe1, 0x92, 0x7e, 0x07, 0x59, +0xee, 0xe1, 0x17, 0x2a, 0x52, 0x1a, 0x19, 0x49, 0xd7, 0xc0, 0x84, 0xdb, 0x71, 0x75, 0x37, 0xa6, +0x1a, 0x0a, 0xc1, 0xa7, 0x33, 0x1d, 0xad, 0x3c, 0xac, 0xb3, 0x2a, 0x38, 0x96, 0x32, 0xf9, 0x3c, +0x81, 0x6a, 0x48, 0xf9, 0x80, 0x30, 0x86, 0xc4, 0xff, 0x00, 0x35, 0x20, 0xe8, 0x35, 0xc6, 0x1d, +0xfd, 0x8d, 0xef, 0xfd, 0xd3, 0x22, 0xf8, 0xe3, 0x0c, 0xef, 0x37, 0x1e, 0x37, 0x65, 0x80, 0xa5, +0x88, 0x24, 0x35, 0xba, 0x22, 0x8f, 0xc9, 0x3d, 0x53, 0x9a, 0x6c, 0x90, 0x20, 0x13, 0x9e, 0xcc, +0xc1, 0x75, 0x58, 0xf7, 0x30, 0x31, 0x55, 0x51, 0xec, 0xb2, 0xcc, 0x9b, 0x8d, 0x0d, 0x0f, 0xb4, +0xd2, 0x39, 0xfd, 0xcc, 0x08, 0xad, 0x83, 0x8b, 0xe9, 0x2a, 0x46, 0xed, 0x30, 0xc0, 0x16, 0xa7, +0x2a, 0x98, 0x35, 0x6a, 0x49, 0xec, 0xa1, 0xa0, 0x81, 0x6f, 0x73, 0xd5, 0x41, 0x5c, 0x04, 0x21, +0x28, 0xfc, 0x1c, 0x3b, 0xce, 0xfb, 0x8d, 0x90, 0x40, 0x96, 0x54, 0x11, 0x05, 0x48, 0x34, 0x0b, +0xc9, 0x24, 0x91, 0xf3, 0x3a, 0xf4, 0xe5, 0x72, 0xe9, 0xcd, 0xf9, 0xe7, 0x44, 0x62, 0x1e, 0x49, +0xa0, 0xf0, 0x65, 0x89, 0x27, 0x98, 0xf6, 0xa1, 0xe8, 0xe3, 0x81, 0xff, 0xec, 0xe4, 0xd9, 0xf3, +0xe7, 0x2f, 0xea, 0x32, 0x34, 0x71, 0x27, 0xcc, 0x7c, 0x16, 0x78, 0xf2, 0x88, 0xfb, 0x4b, 0x9d, +0x46, 0xa7, 0x92, 0x48, 0x77, 0x87, 0xf8, 0x7a, 0xa0, 0xdc, 0x4e, 0x89, 0x96, 0x0c, 0x39, 0x91, +0x10, 0x2d, 0x37, 0x13, 0xe4, 0x66, 0xc8, 0x8e, 0xd8, 0x44, 0x57, 0x8b, 0xd5, 0xfd, 0x2b, 0x96, +0xbc, 0x40, 0x27, 0x8f, 0x03, 0x19, 0xaf, 0xc8, 0x49, 0xff, 0xe4, 0xb4, 0x5a, 0x1b, 0x6c, 0xeb, +0xaa, 0xd1, 0xb5, 0x9a, 0xc3, 0x56, 0xdd, 0x2c, 0xdb, 0xc2, 0xd8, 0x01, 0x31, 0xba, 0x4e, 0xf9, +0x27, 0x33, 0xaf, 0x4e, 0x78, 0x6d, 0x6b, 0xdb, 0xc5, 0x4a, 0x2e, 0xba, 0x04, 0x83, 0x82, 0xb3, +0x9b, 0xdf, 0xad, 0x0d, 0xf7, 0xf3, 0x5c, 0x78, 0x9e, 0x73, 0xad, 0xfc, 0xf1, 0xe4, 0xf9, 0xf3, +0x93, 0xe7, 0xcf, 0x00, 0xe6, 0xdd, 0x3d, 0x19, 0xfd, 0x7c, 0x75, 0x4e, 0xf2, 0x11, 0x72, 0x7e, +0x4e, 0x8a, 0xda, 0xcf, 0x2a, 0x15, 0xa3, 0x7f, 0xa6, 0xe2, 0x07, 0x6c, 0x05, 0x9d, 0x7d, 0x25, +0x17, 0x24, 0x0c, 0x7c, 0x71, 0xc1, 0x10, 0x83, 0x14, 0xca, 0x93, 0xc9, 0x14, 0x16, 0x06, 0x4c, +0x28, 0x06, 0x80, 0x56, 0x3d, 0x11, 0xf4, 0x14, 0xf5, 0x9f, 0x7a, 0x7d, 0x08, 0x2d, 0xac, 0x1e, +0x42, 0xc8, 0xf0, 0xfa, 0x9a, 0xfc, 0xf0, 0x6b, 0xef, 0xd5, 0x75, 0x6f, 0x74, 0x45, 0x60, 0xda, +0x1e, 0xb2, 0xdd, 0xb6, 0xdd, 0xd6, 0x8e, 0xb8, 0xca, 0xc2, 0x82, 0x26, 0x84, 0x7d, 0x61, 0xaf, +0x45, 0xc0, 0xc8, 0x25, 0xd1, 0x49, 0xca, 0x2e, 0x6a, 0xef, 0x35, 0x34, 0x83, 0xd7, 0x10, 0xd0, +0x2e, 0x49, 0xbf, 0xe1, 0xa5, 0x6a, 0x1e, 0x47, 0xf6, 0xb1, 0x4e, 0x82, 0xb7, 0x8e, 0x53, 0x7f, +0x0d, 0xed, 0x36, 0xa3, 0x0a, 0xf7, 0x14, 0x69, 0x14, 0x5d, 0x54, 0xab, 0x95, 0x49, 0x2a, 0x02, +0x0c, 0x67, 0x04, 0xda, 0x86, 0xeb, 0xb1, 0x2b, 0xc7, 0x9f, 0x3a, 0xe4, 0xf7, 0x9a, 0x4f, 0x1b, +0xe8, 0x40, 0xa0, 0x48, 0x51, 0x1e, 0x88, 0xf1, 0x36, 0x62, 0xf8, 0xf5, 0x87, 0xd5, 0x5d, 0xe8, +0x62, 0xd7, 0xff, 0x96, 0xa9, 0x34, 0xd2, 0x4e, 0xe7, 0xa2, 0xb6, 0x9a, 0x4f, 0x90, 0xee, 0x07, +0x47, 0xa5, 0x41, 0xc0, 0xa0, 0xbf, 0xff, 0xd8, 0xb4, 0x05, 0x7e, 0x98, 0xc7, 0x85, 0x60, 0xc9, +0xcf, 0xf7, 0xbf, 0xbc, 0x44, 0x5e, 0x0c, 0x63, 0x54, 0x84, 0x28, 0xb5, 0x00, 0xf2, 0x6e, 0xe8, +0x5c, 0x34, 0x2e, 0x03, 0x30, 0x57, 0x9f, 0xe8, 0x17, 0xd7, 0xf4, 0x3e, 0xbe, 0x69, 0xff, 0x9d, +0x2e, 0x89, 0xf1, 0xf0, 0xa2, 0x01, 0xcd, 0xd7, 0xda, 0x08, 0x8b, 0x14, 0xdb, 0x0b, 0xcf, 0x6d, +0x92, 0xc8, 0xe4, 0x1c, 0xbe, 0x1c, 0x11, 0xc3, 0x10, 0xc3, 0x67, 0xe7, 0x63, 0x75, 0x8f, 0xaf, +0x16, 0x01, 0x43, 0xc3, 0x8a, 0x75, 0xb4, 0x6b, 0x93, 0x2f, 0x56, 0xd3, 0xa8, 0x23, 0xb6, 0x24, +0x37, 0xf0, 0xd5, 0x6d, 0x80, 0x8e, 0xd3, 0x60, 0xe3, 0x7c, 0xd6, 0xeb, 0x31, 0xe6, 0x86, 0xa6, +0x79, 0x30, 0xc7, 0x0b, 0xe6, 0x21, 0x62, 0x86, 0x5d, 0x1f, 0x4c, 0xed, 0xdf, 0x3c, 0x6b, 0x41, +0x23, 0x98, 0x65, 0x44, 0x75, 0x27, 0xb4, 0x8b, 0x18, 0x50, 0xb7, 0x39, 0x50, 0x9f, 0x1c, 0x83, +0xd7, 0x36, 0x6c, 0x50, 0x95, 0xb8, 0x69, 0xc5, 0x41, 0xe2, 0xc6, 0x84, 0xba, 0xc4, 0x79, 0xf3, +0x7a, 0x74, 0x0f, 0x8f, 0xff, 0x19, 0xbd, 0x7e, 0xe5, 0x29, 0xa8, 0x99, 0xc4, 0x94, 0x4f, 0x56, +0xc6, 0xb4, 0x3a, 0xfb, 0x89, 0xca, 0xe0, 0xf9, 0x89, 0x81, 0xe8, 0x79, 0x60, 0x33, 0x49, 0x30, +0xaa, 0xdc, 0x99, 0x3a, 0x8d, 0xba, 0x33, 0x34, 0xa0, 0x79, 0x31, 0xeb, 0xeb, 0x1c, 0x98, 0xd7, +0x6f, 0x21, 0xeb, 0x35, 0xbc, 0x6f, 0x85, 0x05, 0x7d, 0x89, 0x0d, 0x92, 0xf1, 0x4f, 0x63, 0x18, +0x5a, 0x3d, 0x08, 0xb9, 0xdc, 0xb6, 0x0c, 0x9b, 0xa6, 0x2b, 0x4b, 0xc8, 0xbf, 0x6c, 0x42, 0xc7, +0xa5, 0x69, 0x5c, 0x6c, 0x31, 0xcd, 0xc4, 0xe3, 0x7c, 0x34, 0x4b, 0xf3, 0x06, 0xcf, 0xba, 0xe1, +0x4a, 0x6d, 0xaa, 0x19, 0xa8, 0xf8, 0xe4, 0xc5, 0xd9, 0x53, 0xd8, 0x86, 0xfc, 0x93, 0x9c, 0x9e, +0x3d, 0x6b, 0x5e, 0x36, 0x4b, 0x14, 0xa9, 0x2d, 0x3b, 0x3d, 0xcb, 0x56, 0x9d, 0x3c, 0x6d, 0x5e, +0x34, 0xe7, 0xa2, 0xbe, 0xe8, 0xcc, 0x2c, 0x39, 0xeb, 0x37, 0x2f, 0x51, 0x2c, 0xc0, 0x25, 0x30, +0xd3, 0x3e, 0xa7, 0x35, 0xfa, 0xe4, 0xdc, 0x37, 0xc8, 0xac, 0xea, 0xc1, 0x46, 0x0e, 0x47, 0xe0, +0xbf, 0x37, 0x74, 0xe5, 0x34, 0xc6, 0xa9, 0x63, 0xf2, 0x5d, 0x36, 0xad, 0xb3, 0x33, 0x20, 0x1c, +0xa1, 0x77, 0x39, 0xed, 0x5b, 0xe2, 0x9c, 0xae, 0x89, 0x17, 0xae, 0xd3, 0x77, 0x8e, 0x40, 0xa0, +0x1d, 0x4f, 0xa5, 0x63, 0x70, 0x0a, 0xb7, 0x77, 0xd2, 0x41, 0x28, 0xe7, 0x4e, 0xd3, 0x46, 0xf9, +0x7c, 0x90, 0xe5, 0x41, 0xf3, 0x41, 0x90, 0x9b, 0xf3, 0x2d, 0xc6, 0x30, 0xc2, 0x56, 0xbb, 0x45, +0x9a, 0xa6, 0xad, 0x6f, 0x0e, 0xe3, 0x7d, 0x14, 0x4f, 0xc5, 0x5c, 0x6d, 0xa1, 0xbc, 0x88, 0xf9, +0xa5, 0x59, 0x0f, 0xc8, 0xf1, 0xd9, 0x8b, 0x7e, 0xf6, 0xe9, 0x58, 0xab, 0xde, 0x32, 0x48, 0x36, +0x47, 0x7a, 0x6b, 0xa4, 0xc6, 0x8f, 0x61, 0xac, 0xa2, 0x6f, 0x2d, 0xef, 0x94, 0x44, 0x17, 0x1b, +0x81, 0x40, 0x90, 0xad, 0xbd, 0xd3, 0x81, 0x85, 0xab, 0xfa, 0x16, 0x8e, 0x25, 0x27, 0x15, 0x36, +0xcb, 0x45, 0xec, 0x62, 0x10, 0x46, 0x33, 0x50, 0x2b, 0x11, 0x64, 0xe5, 0xfb, 0x38, 0x81, 0x4e, +0x0c, 0x4a, 0xdd, 0x2e, 0xe9, 0x77, 0xc9, 0x07, 0x67, 0xac, 0x85, 0xf3, 0xb1, 0x4b, 0x8a, 0x79, +0xd0, 0x63, 0x6a, 0x29, 0x1c, 0x8b, 0x0c, 0x32, 0x0c, 0x78, 0x96, 0x24, 0xc2, 0xeb, 0x19, 0x8f, +0x42, 0x17, 0xcf, 0x46, 0x5c, 0xe7, 0xd5, 0xfd, 0x1b, 0x82, 0x6e, 0x00, 0x74, 0x17, 0x0c, 0x22, +0x85, 0x80, 0xe2, 0x28, 0x98, 0xd1, 0x71, 0xc4, 0x3c, 0xe2, 0x74, 0xf6, 0x26, 0xc6, 0x0e, 0xdc, +0xd6, 0x41, 0x06, 0xf0, 0xab, 0xe1, 0x60, 0xa3, 0x0e, 0xb0, 0xa9, 0xd0, 0xa3, 0x61, 0x78, 0xbb, +0x00, 0x6b, 0x7b, 0xc9, 0x95, 0xc6, 0x20, 0xe6, 0x3a, 0xe6, 0x0c, 0x1c, 0x08, 0xe5, 0xda, 0x6f, +0xd4, 0x92, 0xb5, 0xaa, 0x80, 0xba, 0xfc, 0x15, 0x16, 0xb8, 0xd7, 0x50, 0x2c, 0xb4, 0xda, 0xa3, +0x5b, 0x5a, 0xa4, 0x02, 0xe1, 0x70, 0x05, 0xe1, 0x92, 0xf4, 0x4a, 0x6b, 0x96, 0x93, 0x09, 0x8a, +0x1f, 0x08, 0x0c, 0xb6, 0x2c, 0xdc, 0x6a, 0x70, 0x8f, 0x1f, 0x93, 0x0a, 0x4d, 0xb3, 0xbe, 0xa8, +0x0d, 0x2a, 0x24, 0x87, 0x5b, 0x24, 0x6d, 0x28, 0xf1, 0xb3, 0x59, 0xcd, 0xbd, 0x81, 0x26, 0x0c, +0xd2, 0x27, 0x58, 0x11, 0xa8, 0x14, 0x7a, 0x23, 0x57, 0x75, 0xba, 0x64, 0xc9, 0xa3, 0x08, 0xe2, +0x6b, 0x0a, 0x56, 0x4a, 0x35, 0xc9, 0xf6, 0xcd, 0x62, 0x4c, 0x99, 0x51, 0xf6, 0x43, 0x95, 0x67, +0x1a, 0x4f, 0xcb, 0x97, 0x12, 0xaf, 0x7e, 0x46, 0x26, 0x57, 0xbb, 0x4f, 0x42, 0xd6, 0xbb, 0xb9, +0x7d, 0x62, 0x53, 0xe0, 0x57, 0xab, 0x67, 0xee, 0xc9, 0x94, 0xd1, 0x96, 0x31, 0xd5, 0x6e, 0xc9, +0x18, 0x89, 0x73, 0x4e, 0x41, 0x9b, 0x68, 0xb2, 0x21, 0xd8, 0xd2, 0x85, 0x95, 0x5a, 0x2d, 0xb8, +0x0c, 0xc9, 0x7e, 0xba, 0x6d, 0x93, 0x7b, 0x05, 0x26, 0x06, 0x6e, 0x23, 0xe2, 0x10, 0x65, 0xfc, +0xf7, 0x09, 0xd7, 0x2e, 0xe0, 0x3d, 0x84, 0x5c, 0xe3, 0xc0, 0x58, 0x8a, 0x39, 0x37, 0x28, 0xe5, +0xdb, 0xca, 0x4d, 0x8b, 0x53, 0xfc, 0xd5, 0xec, 0x7c, 0xdd, 0x11, 0x88, 0x5b, 0x6b, 0xb0, 0xbb, +0x05, 0xa2, 0xee, 0x42, 0xc1, 0x65, 0x2b, 0xa6, 0xb1, 0x4c, 0x82, 0x46, 0xcd, 0xfd, 0xe0, 0x08, +0x29, 0x80, 0xa7, 0x06, 0x7c, 0x13, 0x99, 0xb8, 0x38, 0x95, 0x13, 0x39, 0x21, 0x96, 0x8a, 0xae, +0x20, 0x87, 0xa7, 0xfd, 0x18, 0xcc, 0xe1, 0xdf, 0x28, 0x6b, 0x62, 0xec, 0x51, 0x3f, 0xc0, 0x8a, +0xda, 0x5c, 0xef, 0xf5, 0x8a, 0x86, 0xc7, 0x3e, 0x19, 0x7a, 0x45, 0x1e, 0xb5, 0xa4, 0x11, 0xb0, +0xf4, 0x09, 0x45, 0xad, 0x5f, 0xc2, 0xee, 0xd0, 0x70, 0x08, 0xe3, 0x1c, 0xf6, 0x30, 0x67, 0xd6, +0xac, 0xc1, 0xbe, 0xa7, 0x89, 0xb0, 0x6b, 0x66, 0x03, 0x29, 0x1e, 0x74, 0xb7, 0x38, 0x5c, 0x09, +0xb3, 0x70, 0x4f, 0xcb, 0xdc, 0xaf, 0x99, 0x89, 0x62, 0xb0, 0xdd, 0x84, 0xcd, 0xd5, 0x83, 0xa1, +0x80, 0xb8, 0xff, 0xf8, 0x83, 0x40, 0x19, 0x01, 0xe3, 0xa0, 0xbc, 0x3d, 0xb9, 0x40, 0x7b, 0xde, +0x8b, 0x0b, 0x73, 0x52, 0xbf, 0x07, 0x17, 0x42, 0x6a, 0xb2, 0x82, 0xa0, 0x69, 0x06, 0x90, 0x9f, +0x9d, 0xec, 0xf4, 0x73, 0x4e, 0xc0, 0x27, 0x22, 0xaa, 0xf4, 0xc3, 0xce, 0x56, 0xb6, 0xb2, 0x5f, +0xb9, 0x0f, 0x81, 0xd4, 0x4e, 0x84, 0xc4, 0x0e, 0x80, 0x9a, 0x43, 0xbd, 0x84, 0x05, 0x8c, 0x2f, +0x20, 0xca, 0xa4, 0x42, 0xc3, 0x5c, 0x8c, 0x66, 0xad, 0x50, 0x0e, 0xda, 0x0c, 0x5b, 0x67, 0xae, +0x76, 0x04, 0xd2, 0x2d, 0x3d, 0xc5, 0x89, 0x0c, 0xd3, 0x00, 0x5c, 0xbb, 0x2d, 0xf1, 0xad, 0xf7, +0x3b, 0xca, 0xa5, 0xb9, 0x5e, 0x76, 0xf1, 0x2d, 0xd1, 0xab, 0xee, 0x67, 0x3f, 0x9a, 0x23, 0x8b, +0xfd, 0x80, 0x94, 0x20, 0x4c, 0x88, 0xe3, 0x5e, 0x90, 0x26, 0x0f, 0xf1, 0x32, 0xc1, 0xb2, 0xf9, +0xbd, 0x73, 0x78, 0x80, 0x6a, 0x6e, 0x2b, 0xf3, 0x12, 0xc8, 0xb5, 0x97, 0xb0, 0x8b, 0xa9, 0x8b, +0x0c, 0x74, 0xc9, 0x69, 0x3f, 0xfb, 0x33, 0xc6, 0x69, 0x30, 0x05, 0x51, 0xa7, 0x6b, 0x5f, 0x68, +0xea, 0xa9, 0xbb, 0x22, 0x23, 0xfe, 0xc3, 0x30, 0x01, 0x4a, 0x09, 0x4d, 0x86, 0x71, 0xb2, 0x73, +0x07, 0x18, 0xc0, 0x1f, 0x3e, 0x64, 0x43, 0x46, 0xbb, 0xf0, 0xc5, 0x88, 0xa0, 0x85, 0xf2, 0x38, +0x71, 0x9b, 0x95, 0xd9, 0xb9, 0x78, 0xf4, 0x68, 0x3f, 0xbb, 0x28, 0xfd, 0xf7, 0xf7, 0x36, 0x63, +0x6a, 0xf2, 0x10, 0x48, 0xce, 0xfd, 0x5d, 0x79, 0xb7, 0xa9, 0x2b, 0x6e, 0xa4, 0x65, 0x6d, 0x8e, +0x1b, 0x75, 0x94, 0x49, 0xb4, 0x37, 0x24, 0x48, 0x85, 0xe4, 0x54, 0x26, 0x69, 0x44, 0x74, 0x42, +0x85, 0x9a, 0x73, 0x73, 0xe8, 0x9d, 0xc9, 0xb5, 0xde, 0x2a, 0x40, 0xa5, 0x85, 0x72, 0xfb, 0xcb, +0x33, 0x9b, 0x29, 0xa6, 0x6d, 0xbd, 0x17, 0x5f, 0x38, 0x1d, 0x2f, 0x61, 0x71, 0x44, 0x03, 0x66, +0xaa, 0xec, 0x84, 0x09, 0x37, 0x3e, 0xe4, 0x7c, 0x02, 0x43, 0xbe, 0x8b, 0xe1, 0xfc, 0x2f, 0x48, +0x8d, 0x4b, 0x4c, 0x8d, 0x36, 0x5a, 0x55, 0x49, 0xe7, 0x46, 0x8f, 0xbb, 0x6f, 0x1b, 0xfe, 0x3a, +0xc1, 0x80, 0x48, 0x8d, 0x4a, 0x96, 0x76, 0xd9, 0x36, 0x17, 0xfa, 0x45, 0x55, 0xe3, 0x45, 0x4c, +0x4c, 0xf5, 0xcc, 0x98, 0xd4, 0x7e, 0x80, 0x70, 0x55, 0x23, 0x20, 0x93, 0x2b, 0x0a, 0x40, 0x05, +0xfd, 0x35, 0xae, 0x26, 0x14, 0x78, 0x7c, 0x8a, 0x0d, 0x70, 0x7e, 0xa0, 0xda, 0xd2, 0x6a, 0x80, +0x5a, 0xff, 0xcb, 0x12, 0x3c, 0xfe, 0x70, 0xca, 0x9f, 0x3d, 0x60, 0x63, 0xb1, 0x1e, 0x2f, 0x68, +0xd8, 0x83, 0xec, 0x9f, 0x64, 0xc5, 0xc9, 0x7e, 0x95, 0xb2, 0xce, 0x6d, 0x5d, 0x02, 0x71, 0x30, +0xc1, 0x5b, 0xb2, 0x7c, 0xcf, 0x90, 0x40, 0x84, 0x59, 0x5b, 0x7e, 0x81, 0xa4, 0xd5, 0xdc, 0x8b, +0x3c, 0xd8, 0xcc, 0xd8, 0xf0, 0x6f, 0x61, 0xec, 0x57, 0x99, 0x12, 0x9a, 0x30, 0x92, 0x2a, 0xd3, +0x28, 0x6c, 0x5c, 0xff, 0xe5, 0xfc, 0x94, 0xd7, 0x0c, 0x1e, 0xb9, 0x13, 0x24, 0xc0, 0x33, 0x6f, +0xb0, 0xdf, 0xec, 0x8e, 0x97, 0xac, 0x60, 0xf5, 0x9c, 0xae, 0xc0, 0x9c, 0x61, 0x81, 0x96, 0x10, +0x02, 0x56, 0x44, 0xcf, 0x58, 0x29, 0x1c, 0x28, 0x93, 0x31, 0x67, 0xe6, 0xf0, 0x0f, 0x10, 0x8d, +0x4d, 0x5a, 0xff, 0x67, 0xfe, 0xbf, 0x19, 0x7b, 0x83, 0xa7, 0x59, 0xc3, 0xd2, 0xfa, 0x77, 0x10, +0x7f, 0x3e, 0x3a, 0xe1, 0xd5, 0x86, 0x6b, 0x39, 0xc9, 0x35, 0xe7, 0x4a, 0xda, 0x72, 0xe8, 0xb6, +0xe3, 0xa0, 0xca, 0x7e, 0xe2, 0xb3, 0xd1, 0xe4, 0x1c, 0x1d, 0x61, 0xaf, 0x90, 0x67, 0x8f, 0x4e, +0xf3, 0xe1, 0x16, 0xcc, 0xc9, 0x6f, 0x5f, 0x86, 0x97, 0x30, 0xd1, 0xe6, 0xde, 0xd6, 0x2b, 0x9a, +0xed, 0xc3, 0xf1, 0x27, 0xeb, 0xeb, 0x88, 0x27, 0xfb, 0x5e, 0x47, 0xb4, 0x86, 0xf6, 0x96, 0xa3, +0xf0, 0x22, 0x34, 0xb5, 0xf4, 0x31, 0xbb, 0x0e, 0xcc, 0xcb, 0x53, 0xf1, 0x57, 0x74, 0xe1, 0x56, +0x8f, 0x98, 0x2d, 0x96, 0xbf, 0x7d, 0x4c, 0xbf, 0xe7, 0x8a, 0xe2, 0x04, 0xbd, 0x65, 0xca, 0x5d, +0x8e, 0xa0, 0x38, 0x1e, 0xc0, 0xb3, 0x25, 0xbc, 0xae, 0xc8, 0x1a, 0xfe, 0xb6, 0x95, 0x26, 0xfd, +0x99, 0xb5, 0x68, 0xb3, 0xf8, 0x73, 0x40, 0x2b, 0x98, 0x0d, 0x81, 0xb4, 0x94, 0x27, 0x4b, 0x50, +0xa0, 0x5c, 0x7a, 0xd0, 0x06, 0x43, 0x74, 0x63, 0xc9, 0x82, 0x46, 0xae, 0x93, 0x99, 0xb2, 0xd3, +0xdd, 0x55, 0x8c, 0xac, 0x6f, 0xfb, 0x4c, 0x35, 0x65, 0x9f, 0x58, 0xde, 0xa7, 0x94, 0xb7, 0xd9, +0x31, 0xf7, 0x36, 0x2e, 0x5c, 0xc1, 0xe7, 0xa4, 0xaa, 0x5c, 0xbb, 0xe6, 0xee, 0x0d, 0x83, 0x60, +0xdf, 0x4a, 0x17, 0xf7, 0x5d, 0x6f, 0x73, 0xaf, 0xbf, 0xf8, 0xb3, 0x4d, 0x77, 0xb3, 0xf9, 0xad, +0xc3, 0x3b, 0xe8, 0xc3, 0x56, 0x58, 0x50, 0xe0, 0x13, 0x5e, 0x7b, 0x2a, 0x8e, 0xb8, 0x76, 0x9f, +0x78, 0x4f, 0x1a, 0x50, 0x24, 0x4c, 0xa7, 0x89, 0x20, 0x2e, 0xfd, 0xd0, 0xff, 0x48, 0x06, 0x03, +0x72, 0xf2, 0x14, 0x3a, 0x42, 0x7c, 0x3c, 0x36, 0x8f, 0xc7, 0x67, 0xf8, 0x48, 0x3f, 0x9c, 0x7c, +0x3c, 0xa0, 0xe2, 0xc9, 0x79, 0xb6, 0x79, 0xc7, 0xfa, 0xfa, 0xd3, 0x98, 0x45, 0x56, 0x3d, 0xe7, +0xa7, 0xe4, 0x78, 0x84, 0x71, 0xb6, 0xf3, 0x7e, 0xab, 0xed, 0x46, 0x71, 0x0b, 0xd9, 0x7e, 0x0b, +0xd7, 0x3f, 0x88, 0xce, 0x9e, 0xb2, 0x1f, 0x23, 0x0f, 0xfc, 0xec, 0x67, 0xe3, 0xff, 0x03, 0x2a, +0x4c, 0xb5, 0xf1, 0x4e, 0x2e, 0x00, 0x00}; +#endif /*__INDEX_HTML_H__*/ diff --git a/src/web/html/h/login_html.h b/src/web/html/h/login_html.h new file mode 100644 index 00000000..37b1bccb --- /dev/null +++ b/src/web/html/h/login_html.h @@ -0,0 +1,47 @@ +#ifndef __LOGIN_HTML_H__ +#define __LOGIN_HTML_H__ +#define login_html_len 665 +const uint8_t login_html[] PROGMEM = { +0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0x95, 0x55, 0xcb, 0x6e, 0xdb, 0x30, +0x10, 0xbc, 0xf7, 0x2b, 0x58, 0x1e, 0x7a, 0x8a, 0x44, 0x47, 0x49, 0x9b, 0xc0, 0x90, 0x54, 0xe4, +0xd1, 0x17, 0x50, 0xf4, 0x92, 0x04, 0x45, 0x4e, 0x01, 0x45, 0xd1, 0x12, 0x13, 0x8a, 0x24, 0x48, +0xca, 0x8e, 0xfb, 0xf5, 0x5d, 0xbd, 0x6a, 0x59, 0x8e, 0xeb, 0xc4, 0x17, 0x89, 0xe4, 0xec, 0xec, +0xee, 0xcc, 0x52, 0x8e, 0xdf, 0xe7, 0x9a, 0xf9, 0xb5, 0xe1, 0xa8, 0xf4, 0x95, 0x4c, 0xdf, 0xc5, +0xdd, 0x03, 0xc1, 0x2f, 0x2e, 0x39, 0xcd, 0xbb, 0xd7, 0x76, 0xe9, 0x85, 0x97, 0x3c, 0xfd, 0xa9, +0x0b, 0xa1, 0x62, 0xd2, 0x2d, 0x36, 0x87, 0x52, 0xa8, 0x27, 0x64, 0xb9, 0x4c, 0xb0, 0xf3, 0x6b, +0xc9, 0x5d, 0xc9, 0xb9, 0xc7, 0xa8, 0x21, 0x4e, 0xb0, 0xe7, 0xcf, 0x9e, 0x30, 0xe7, 0x30, 0x2a, +0x2d, 0x5f, 0xf4, 0x88, 0x10, 0x36, 0x3e, 0x2f, 0x93, 0x59, 0x78, 0x1e, 0xce, 0x66, 0xb3, 0x63, +0x4c, 0x20, 0x77, 0xc5, 0x3d, 0x45, 0x8a, 0x56, 0x10, 0xb3, 0x14, 0x7c, 0x65, 0xb4, 0x05, 0x0e, +0xa6, 0x95, 0xe7, 0xca, 0x27, 0x78, 0x25, 0x72, 0x5f, 0x26, 0x39, 0x5f, 0x0a, 0xc6, 0x83, 0x76, +0x71, 0x84, 0x84, 0x12, 0x5e, 0x50, 0x19, 0x38, 0x46, 0x25, 0x4f, 0x8e, 0xf1, 0x40, 0xc2, 0x4a, +0x6a, 0x1d, 0x87, 0xa0, 0xbb, 0xdb, 0xaf, 0xc1, 0x79, 0xb3, 0xed, 0x98, 0x15, 0xc6, 0x8f, 0x2b, +0x7a, 0xa4, 0x4b, 0xda, 0xed, 0x62, 0xe4, 0x2c, 0x4b, 0x30, 0x35, 0x22, 0x7c, 0xdc, 0x2a, 0x2a, +0x8d, 0x49, 0x87, 0x00, 0x82, 0xb7, 0x74, 0xc8, 0xb4, 0xd4, 0xd6, 0x1d, 0x68, 0xd1, 0xea, 0x4c, +0x7b, 0x37, 0x6a, 0x50, 0x69, 0xa1, 0x72, 0xfe, 0x7c, 0x84, 0x94, 0x5e, 0x68, 0x29, 0xf5, 0x0a, +0x23, 0xd2, 0x5b, 0x41, 0x36, 0x5e, 0xc4, 0x99, 0xce, 0xd7, 0x23, 0xe5, 0x73, 0xb1, 0x44, 0x22, +0x07, 0x79, 0x2c, 0x35, 0x86, 0x5b, 0xbc, 0x39, 0xda, 0x3a, 0x96, 0x8d, 0x6f, 0x93, 0xc3, 0x7f, +0x00, 0x26, 0xa9, 0x73, 0x09, 0x36, 0xc1, 0xe9, 0x0b, 0x88, 0x16, 0xb5, 0xd0, 0xb6, 0x42, 0x94, +0x79, 0xa1, 0x55, 0x82, 0x49, 0x47, 0x86, 0xa0, 0x99, 0x52, 0x03, 0xb7, 0xd1, 0xce, 0xef, 0x09, +0x9c, 0xa6, 0xb0, 0xd0, 0x55, 0x1a, 0x97, 0x51, 0x7a, 0x51, 0xea, 0xf5, 0xf5, 0xed, 0x1d, 0x74, +0x16, 0x81, 0xca, 0x80, 0x78, 0x43, 0xfc, 0x5e, 0xe4, 0x14, 0x0d, 0x3e, 0x04, 0xc7, 0x11, 0x6a, +0x1e, 0xae, 0x0a, 0xce, 0x51, 0x95, 0x05, 0x27, 0x90, 0x5e, 0x28, 0x53, 0x0f, 0xa3, 0x60, 0x00, +0xb8, 0xd2, 0x36, 0xc7, 0xbd, 0x2b, 0x66, 0x05, 0xaf, 0xb4, 0xf6, 0x60, 0x01, 0xab, 0xdd, 0xa1, +0xd2, 0xfe, 0x9f, 0xf0, 0x74, 0x92, 0xcb, 0xd5, 0x59, 0x25, 0xfc, 0x90, 0xa9, 0x17, 0x71, 0x49, +0x65, 0xbd, 0x59, 0xf5, 0x3c, 0x99, 0x57, 0xf8, 0xa0, 0x2c, 0xfb, 0x8f, 0x63, 0xd2, 0xf8, 0xf5, +0x82, 0xd9, 0xbb, 0x21, 0x93, 0xad, 0xe9, 0x72, 0x18, 0x9f, 0x85, 0xd6, 0x7e, 0x6b, 0xb8, 0xc6, +0x5d, 0x4b, 0xbe, 0x18, 0xfb, 0x1f, 0xd3, 0xfe, 0x1a, 0x94, 0xde, 0x1b, 0x37, 0x27, 0x84, 0x82, +0xd7, 0xb9, 0xaf, 0xc3, 0x9c, 0xc3, 0x85, 0xa1, 0xb6, 0x68, 0x2e, 0xe6, 0x43, 0x26, 0xa9, 0x7a, +0xc2, 0xc3, 0x1c, 0xa0, 0x0f, 0x4c, 0x9b, 0x35, 0x8a, 0x66, 0xd1, 0x49, 0x4c, 0xe8, 0x88, 0xab, +0x96, 0x93, 0x7a, 0xa5, 0x48, 0x77, 0x12, 0xe4, 0xc2, 0x31, 0xf0, 0x30, 0x2c, 0x0a, 0xf2, 0xfb, +0x4f, 0xf9, 0xfc, 0xe5, 0xfe, 0x53, 0x54, 0x5d, 0xee, 0xe6, 0xba, 0xee, 0x60, 0x4d, 0x82, 0x98, +0x00, 0xcf, 0x61, 0xe2, 0x42, 0xf8, 0xb2, 0xce, 0x42, 0xa6, 0x2b, 0x22, 0xeb, 0x8a, 0x9a, 0xba, +0xed, 0x65, 0x97, 0xf9, 0x5b, 0x8b, 0xdb, 0x25, 0x8e, 0xc9, 0x50, 0xff, 0x48, 0xd8, 0xad, 0x79, +0x16, 0x45, 0xb9, 0xa5, 0xdd, 0x9e, 0x7e, 0x27, 0x09, 0x5f, 0x55, 0x26, 0x81, 0x35, 0xcc, 0x9b, +0x23, 0xd9, 0xe2, 0xec, 0x2c, 0x3a, 0xfb, 0x08, 0x65, 0xfe, 0xb8, 0x45, 0x37, 0xdf, 0x2f, 0xe6, +0xa8, 0xdf, 0x41, 0xf3, 0x39, 0x1a, 0x3e, 0x4f, 0x7b, 0x55, 0x69, 0xfd, 0xe7, 0xce, 0x3c, 0x34, +0x43, 0x8c, 0x5f, 0xab, 0x1c, 0xb3, 0x9c, 0x7a, 0xb1, 0xe4, 0x4d, 0x0d, 0x5a, 0xb9, 0x50, 0xdb, +0x02, 0x02, 0x19, 0x57, 0x8e, 0x43, 0x41, 0xeb, 0x40, 0xb1, 0xc0, 0x51, 0x72, 0x1a, 0xce, 0x48, +0xce, 0x79, 0xbe, 0xa3, 0x28, 0x4a, 0xaf, 0xae, 0xd0, 0xe5, 0x7d, 0xf0, 0xeb, 0x2a, 0xb8, 0xb9, +0x40, 0x00, 0x7b, 0x85, 0xb6, 0x63, 0x89, 0x49, 0xf7, 0x95, 0x84, 0xcf, 0x4b, 0xfb, 0x7f, 0xf6, +0x17, 0x29, 0x0f, 0xde, 0x34, 0xe7, 0x06, 0x00, 0x00}; +#endif /*__LOGIN_HTML_H__*/ diff --git a/src/web/html/h/save_html.h b/src/web/html/h/save_html.h new file mode 100644 index 00000000..e2853924 --- /dev/null +++ b/src/web/html/h/save_html.h @@ -0,0 +1,86 @@ +#ifndef __SAVE_HTML_H__ +#define __SAVE_HTML_H__ +#define save_html_len 1286 +const uint8_t save_html[] PROGMEM = { +0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0xad, 0x57, 0x5b, 0x4f, 0x1b, 0x39, +0x14, 0x7e, 0xef, 0xaf, 0x70, 0xfd, 0xb0, 0x04, 0x2d, 0x99, 0x19, 0x92, 0x52, 0x58, 0x72, 0x59, +0x05, 0x4a, 0x0b, 0x12, 0x8b, 0x2a, 0x02, 0xaa, 0xaa, 0xaa, 0xaa, 0x1c, 0xdb, 0xc9, 0x18, 0x1c, +0x7b, 0x3a, 0xf6, 0x04, 0xb2, 0x2b, 0xfe, 0xfb, 0x1e, 0xcf, 0x25, 0x99, 0x49, 0x32, 0x01, 0xb6, +0x3b, 0x2f, 0x89, 0xed, 0x73, 0xf9, 0xbe, 0xe3, 0x73, 0x8e, 0xed, 0xee, 0x5b, 0xa6, 0xa9, 0x9d, +0x47, 0x1c, 0x85, 0x76, 0x2a, 0xfb, 0x6f, 0xba, 0xd9, 0x0f, 0x82, 0xaf, 0x1b, 0x72, 0xc2, 0xb2, +0xbf, 0xe9, 0xd0, 0x0a, 0x2b, 0x79, 0x7f, 0x48, 0x66, 0xbc, 0xeb, 0x67, 0xff, 0x97, 0x6b, 0x52, +0xa8, 0x7b, 0x14, 0x73, 0xd9, 0xc3, 0xc6, 0xce, 0x25, 0x37, 0x21, 0xe7, 0x16, 0x23, 0x67, 0xb7, +0x87, 0x2d, 0x7f, 0xb4, 0x3e, 0x35, 0x06, 0xa3, 0x30, 0xe6, 0xe3, 0x5c, 0xc2, 0x83, 0x89, 0x3f, +0x67, 0xbd, 0xc0, 0x3b, 0xf2, 0x82, 0x20, 0xd8, 0xc7, 0x3e, 0xb8, 0x9e, 0x72, 0x4b, 0x90, 0x22, +0x53, 0xd0, 0x99, 0x09, 0xfe, 0x10, 0xe9, 0x18, 0x6c, 0x50, 0xad, 0x2c, 0x57, 0xb6, 0x87, 0x1f, +0x04, 0xb3, 0x61, 0x8f, 0xf1, 0x99, 0xa0, 0xbc, 0x99, 0x0e, 0xf6, 0x90, 0x50, 0xc2, 0x0a, 0x22, +0x9b, 0x86, 0x12, 0xc9, 0x7b, 0xfb, 0xb8, 0x30, 0x42, 0x43, 0x12, 0x1b, 0x0e, 0x4a, 0xb7, 0x37, +0x1f, 0x9b, 0x47, 0x6e, 0xda, 0xd0, 0x58, 0x44, 0xb6, 0x8c, 0xe8, 0x8e, 0xcc, 0x48, 0x36, 0x8b, +0x91, 0x89, 0x69, 0x0f, 0x93, 0x48, 0x78, 0x77, 0x15, 0x50, 0xfd, 0xae, 0x9f, 0x49, 0x80, 0x81, +0xd7, 0x30, 0xa4, 0x5a, 0xea, 0xd8, 0x3c, 0x43, 0x31, 0xd6, 0x23, 0x6d, 0x4d, 0x89, 0xa0, 0xd2, +0x42, 0x31, 0xfe, 0xb8, 0x87, 0x94, 0x1e, 0x6b, 0x29, 0xf5, 0x03, 0x46, 0x7e, 0xbe, 0x13, 0xfe, +0x72, 0x2b, 0xba, 0x23, 0xcd, 0xe6, 0xa5, 0xc8, 0x33, 0x31, 0x43, 0x54, 0x12, 0x63, 0x00, 0x86, +0x8e, 0x14, 0x99, 0xe1, 0x5c, 0x8e, 0xe4, 0x60, 0xfc, 0x32, 0x86, 0x85, 0xa8, 0xdb, 0x3f, 0xdc, +0x1f, 0x84, 0x7a, 0xfe, 0xe1, 0xe6, 0xb6, 0xeb, 0x93, 0x15, 0xa5, 0x65, 0x70, 0x8e, 0x67, 0x5a, +0xb0, 0x46, 0xb0, 0xdb, 0x59, 0xe8, 0x0a, 0x40, 0x8c, 0x91, 0x56, 0x54, 0x0a, 0x7a, 0x5f, 0x78, +0x6d, 0xec, 0xe2, 0x12, 0x28, 0x13, 0x11, 0xe5, 0x82, 0xe7, 0x7e, 0x5e, 0x3d, 0xbb, 0x44, 0xe3, +0xb8, 0x09, 0xb6, 0x20, 0x56, 0x00, 0x98, 0xea, 0x91, 0x70, 0xe8, 0x97, 0x36, 0x48, 0x2a, 0x06, +0x32, 0xed, 0x85, 0x50, 0x28, 0x18, 0x2f, 0xf6, 0xc3, 0x97, 0x62, 0xc6, 0x2b, 0x1b, 0x7b, 0x29, +0x5c, 0x16, 0x93, 0x4d, 0x26, 0xde, 0x6d, 0x36, 0x61, 0x78, 0x0c, 0x99, 0x56, 0x31, 0xf2, 0x85, +0x8f, 0xb2, 0xd9, 0x1a, 0x4b, 0x07, 0x75, 0x96, 0x6c, 0x12, 0x55, 0x0c, 0x0d, 0xb9, 0xb5, 0x42, +0x4d, 0x4c, 0xd5, 0x8e, 0x8b, 0x48, 0x61, 0xc0, 0xf0, 0x88, 0xc7, 0xc4, 0xea, 0x18, 0xaf, 0x07, +0x70, 0xe1, 0xef, 0xfd, 0x66, 0x7f, 0x49, 0xc4, 0x88, 0xad, 0xd2, 0xbf, 0x4d, 0xa7, 0x6a, 0x60, +0x1f, 0xd6, 0xc0, 0x9e, 0x1b, 0xcb, 0xa7, 0x55, 0xdc, 0xe9, 0xd4, 0x2f, 0xa2, 0x3e, 0x5a, 0x78, +0x80, 0x02, 0x84, 0x8a, 0x22, 0xf1, 0xc4, 0x55, 0xee, 0x8f, 0x91, 0x24, 0xea, 0x1e, 0xf7, 0xaf, +0xcf, 0x86, 0x37, 0x68, 0xf0, 0xf9, 0xa2, 0x06, 0xec, 0x1f, 0x85, 0x76, 0x68, 0x6d, 0x64, 0x8e, +0x7d, 0x9f, 0x40, 0x4a, 0x33, 0x9b, 0x78, 0x0e, 0xf9, 0xaa, 0xad, 0x0f, 0x9a, 0x26, 0x53, 0xa8, +0x35, 0x62, 0x85, 0x56, 0x35, 0x06, 0xf7, 0x83, 0x25, 0x9e, 0x91, 0x4e, 0x6c, 0x85, 0xf0, 0xc0, +0xcd, 0xfc, 0x22, 0xdf, 0xa0, 0x26, 0x45, 0xf5, 0x44, 0x28, 0x48, 0x4c, 0xf7, 0x53, 0x07, 0xad, +0x56, 0x13, 0x50, 0xa5, 0xaa, 0x65, 0x74, 0x5d, 0x1f, 0xca, 0x67, 0xa5, 0x90, 0x1e, 0xc4, 0x58, +0x64, 0xe5, 0x5b, 0xd4, 0xb2, 0x1a, 0x6b, 0x07, 0x36, 0x15, 0x2d, 0x69, 0x54, 0xb5, 0x62, 0x12, +0x01, 0xb1, 0x52, 0xc1, 0x55, 0x96, 0xf3, 0x06, 0xb6, 0xb2, 0x5c, 0x11, 0x71, 0x87, 0xca, 0xb2, +0x7c, 0x6d, 0xb3, 0x8d, 0xa6, 0xa3, 0x66, 0x1b, 0xbb, 0xc3, 0x04, 0xf2, 0x1e, 0x99, 0x3c, 0xff, +0x3d, 0xcf, 0x5b, 0xc1, 0xb0, 0x42, 0x64, 0xd3, 0xb0, 0xf0, 0x31, 0xd6, 0xda, 0x56, 0x40, 0x96, +0x5b, 0xa3, 0xe4, 0x63, 0x5b, 0x6d, 0x18, 0x2f, 0xcf, 0x9a, 0xbc, 0x49, 0xa2, 0xdf, 0xa8, 0x8e, +0xe6, 0xa8, 0x15, 0xb4, 0xda, 0xd5, 0xfd, 0x49, 0xe4, 0x0a, 0x5e, 0x29, 0xfa, 0x6b, 0x0e, 0x98, +0x30, 0x54, 0xc7, 0xcc, 0x9b, 0x4c, 0xfc, 0x2f, 0x7f, 0x87, 0x8f, 0x67, 0x5f, 0xdf, 0xb7, 0xa6, +0x27, 0x1b, 0x32, 0x34, 0x13, 0x73, 0x0e, 0xba, 0xd0, 0xb5, 0x5e, 0x60, 0x78, 0x22, 0x6c, 0x98, +0x8c, 0x3c, 0xaa, 0xa7, 0xbe, 0x4c, 0xa6, 0x24, 0x4a, 0x52, 0x2e, 0xeb, 0x96, 0x3f, 0xa5, 0x72, +0xeb, 0x86, 0xbb, 0x7e, 0x81, 0x7f, 0x35, 0x61, 0xf2, 0xd0, 0xc5, 0x62, 0x12, 0x56, 0x62, 0x57, +0xc3, 0x77, 0xc5, 0xe1, 0x8b, 0x60, 0xfa, 0x30, 0x9e, 0x0a, 0x6b, 0xfc, 0xd1, 0xf8, 0xf0, 0xb0, +0x75, 0x78, 0x00, 0x30, 0x2f, 0x6e, 0xd0, 0xf0, 0x7c, 0x70, 0x8c, 0xf2, 0x19, 0x74, 0x7c, 0x8c, +0x8a, 0xfa, 0xab, 0x8d, 0x4a, 0xba, 0xff, 0xdc, 0x44, 0x3f, 0xdc, 0x71, 0x8c, 0x5f, 0x1a, 0x39, +0x1a, 0x73, 0x68, 0x04, 0x33, 0xee, 0x30, 0x68, 0x65, 0x3c, 0x1d, 0x4f, 0x40, 0x91, 0x72, 0x65, +0x38, 0x00, 0x9a, 0x37, 0x15, 0x6d, 0x1a, 0xe2, 0xbf, 0xf3, 0x02, 0x9f, 0x71, 0xce, 0xd6, 0x22, +0x8a, 0xfa, 0xa7, 0xa7, 0xe8, 0xe4, 0x6b, 0xf3, 0xea, 0xb4, 0x39, 0x1c, 0x20, 0x10, 0x7b, 0x41, +0x6c, 0x57, 0x73, 0x77, 0xeb, 0xad, 0xa4, 0x4a, 0x61, 0x46, 0x62, 0xb8, 0xee, 0x40, 0x86, 0xcf, +0x88, 0xbc, 0x60, 0xa8, 0x87, 0x54, 0x22, 0x65, 0xe7, 0x4d, 0x45, 0x66, 0x9c, 0x28, 0xea, 0x5a, +0x1b, 0x8a, 0xdc, 0xf5, 0xe7, 0x13, 0x57, 0x70, 0x3a, 0xd1, 0x86, 0x1e, 0xdd, 0xed, 0xa2, 0x7f, +0xd6, 0x8a, 0x33, 0x95, 0xb9, 0x82, 0x93, 0xdb, 0xad, 0x77, 0x36, 0x2f, 0x9f, 0x0d, 0x3f, 0x6f, +0x5b, 0xbe, 0x36, 0x46, 0x6c, 0x58, 0x7f, 0xda, 0x86, 0xea, 0x1c, 0x5a, 0x41, 0x1d, 0x24, 0xc7, +0xd1, 0xb5, 0x0a, 0x60, 0x87, 0xf1, 0xba, 0x4f, 0x31, 0x6e, 0xbc, 0x05, 0x4d, 0x2f, 0xe2, 0x8a, +0x41, 0xbb, 0xd8, 0x64, 0x21, 0x17, 0x2b, 0x05, 0xea, 0x6d, 0x16, 0xa9, 0x3a, 0x61, 0xf7, 0x51, +0xc9, 0x49, 0x7c, 0x91, 0xab, 0x94, 0x74, 0x37, 0xd0, 0xce, 0xe8, 0xd5, 0x78, 0x75, 0xd8, 0x4c, +0x42, 0x29, 0x37, 0x66, 0x9b, 0x3b, 0xc7, 0x32, 0xbd, 0x07, 0xf6, 0x10, 0xcb, 0x0f, 0x24, 0x2f, +0xcd, 0x45, 0x7e, 0x26, 0xb9, 0x1b, 0x35, 0x76, 0xdc, 0xf2, 0x4e, 0x8d, 0x7b, 0xf7, 0xb9, 0x75, +0xcf, 0xe5, 0xf1, 0xd9, 0xcf, 0x04, 0x2a, 0x15, 0xc2, 0x05, 0x99, 0x1d, 0xc3, 0xa5, 0x14, 0xd7, +0xaa, 0x14, 0xc1, 0x8b, 0xf9, 0x08, 0x1a, 0xe5, 0x36, 0x7c, 0xee, 0x2b, 0x76, 0xa1, 0xb8, 0x99, +0xa0, 0x9c, 0xd7, 0x18, 0x42, 0x39, 0x47, 0x06, 0xde, 0x00, 0xcc, 0x43, 0x83, 0xc4, 0xea, 0x29, +0x94, 0x10, 0x85, 0x9d, 0x9d, 0x70, 0x77, 0x39, 0xd6, 0x84, 0x41, 0x92, 0xa2, 0x36, 0x74, 0x74, +0x38, 0x15, 0x98, 0xf1, 0x70, 0x67, 0xab, 0x9b, 0x94, 0x47, 0x7e, 0x7e, 0x80, 0xbb, 0x76, 0xbd, +0xf4, 0x13, 0xe2, 0xd2, 0xf0, 0xff, 0x03, 0xf5, 0x75, 0x1a, 0x00, 0x58, 0x2e, 0x13, 0x88, 0x39, +0x13, 0x31, 0xa7, 0xd6, 0xa1, 0x6f, 0x05, 0xff, 0x11, 0x3e, 0x28, 0xfe, 0x8e, 0x70, 0x07, 0xdd, +0x5e, 0x5f, 0xf6, 0xfc, 0x2d, 0xaa, 0x4f, 0xb5, 0x2b, 0x8b, 0x7c, 0x80, 0x46, 0x93, 0x27, 0x83, +0x39, 0x99, 0xdf, 0x90, 0xc9, 0x15, 0x3c, 0x19, 0x1a, 0x3b, 0xee, 0x15, 0xb0, 0xb3, 0xfb, 0x2d, +0xf8, 0xee, 0xb9, 0x03, 0x59, 0xb1, 0xd3, 0x50, 0x48, 0xd6, 0x70, 0x28, 0xea, 0x52, 0xf5, 0xb9, +0xa8, 0x15, 0x11, 0xfb, 0x48, 0xe0, 0x46, 0xcd, 0x5c, 0x88, 0x2a, 0xe7, 0x31, 0x7e, 0x69, 0x05, +0xac, 0xcf, 0x6c, 0xa0, 0x72, 0x32, 0xbf, 0x60, 0x8d, 0xec, 0x2e, 0xb0, 0xeb, 0x09, 0x05, 0xdd, +0xe9, 0xfc, 0xe6, 0xaf, 0x4b, 0x70, 0xef, 0xa6, 0x5e, 0xd1, 0x42, 0xea, 0xda, 0x07, 0xa4, 0xb8, +0x2b, 0x75, 0x57, 0xf2, 0x35, 0x12, 0x8b, 0xce, 0x55, 0xea, 0x8d, 0xdf, 0xf0, 0x24, 0x1b, 0xe0, +0xef, 0x35, 0x51, 0xac, 0xf6, 0xad, 0xce, 0x33, 0xe4, 0x57, 0xa0, 0x57, 0x7a, 0x36, 0x7a, 0x80, +0x27, 0x9e, 0x7e, 0xf0, 0x20, 0xc0, 0x8b, 0x7e, 0x03, 0xee, 0xed, 0xe0, 0x8e, 0x3c, 0x36, 0x76, +0xdc, 0x05, 0xd8, 0x77, 0xb1, 0xf0, 0x5d, 0xaa, 0xee, 0xec, 0x65, 0x8e, 0x77, 0xf1, 0x1e, 0x6a, +0x1d, 0x04, 0xc1, 0x8a, 0xe3, 0x42, 0x2b, 0xbd, 0x36, 0xfb, 0x05, 0x85, 0xbd, 0x0a, 0xbd, 0x92, +0xca, 0xf2, 0x25, 0x9b, 0x8d, 0xb2, 0x57, 0x64, 0xd7, 0xcf, 0x9e, 0xfb, 0xff, 0x02, 0xcf, 0x43, +0x5b, 0x09, 0x06, 0x10, 0x00, 0x00}; +#endif /*__SAVE_HTML_H__*/ diff --git a/src/web/html/h/serial_html.h b/src/web/html/h/serial_html.h new file mode 100644 index 00000000..2d3ab07f --- /dev/null +++ b/src/web/html/h/serial_html.h @@ -0,0 +1,113 @@ +#ifndef __SERIAL_HTML_H__ +#define __SERIAL_HTML_H__ +#define serial_html_len 1724 +const uint8_t serial_html[] PROGMEM = { +0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0xa5, 0x58, 0x5b, 0x53, 0xdb, 0x38, +0x14, 0x7e, 0xe7, 0x57, 0x08, 0xef, 0x74, 0x49, 0x16, 0x62, 0x9b, 0x3b, 0x1b, 0x92, 0x74, 0x28, +0xb0, 0x2d, 0x3b, 0x2c, 0x30, 0x4d, 0x98, 0x4e, 0x67, 0xd9, 0x61, 0x14, 0x59, 0x49, 0x04, 0xb6, +0xe4, 0x91, 0xe4, 0x40, 0xba, 0xd3, 0xff, 0xbe, 0x47, 0xbe, 0x24, 0xbe, 0xb2, 0x94, 0xe6, 0x25, +0x96, 0x7c, 0xce, 0xd1, 0x77, 0x6e, 0x9f, 0x24, 0xf7, 0xd6, 0x3d, 0x41, 0xf4, 0x22, 0xa4, 0x68, +0xa6, 0x03, 0x7f, 0xb0, 0xd6, 0x33, 0x7f, 0xc8, 0xc7, 0x7c, 0xda, 0xb7, 0x28, 0xb7, 0x06, 0x6b, +0x08, 0x7e, 0xbd, 0x19, 0xc5, 0x5e, 0xf2, 0x18, 0x0f, 0x35, 0xd3, 0x3e, 0x1d, 0x0c, 0xa9, 0x64, +0xd8, 0x47, 0xa7, 0x82, 0x2b, 0xe1, 0xd3, 0x9e, 0x93, 0xcc, 0xae, 0xa4, 0x7c, 0xc6, 0x1f, 0x91, +0xa4, 0x7e, 0xdf, 0x52, 0x7a, 0xe1, 0x53, 0x35, 0xa3, 0x54, 0x5b, 0xc8, 0xac, 0xd5, 0xb7, 0x34, +0x7d, 0xd6, 0x0e, 0x51, 0xca, 0x42, 0x33, 0x49, 0x27, 0xa9, 0x84, 0x0d, 0x13, 0xef, 0xe7, 0x7d, +0xd7, 0x3e, 0xb2, 0x5d, 0xd7, 0xdd, 0xb6, 0x1c, 0x80, 0x13, 0x50, 0x8d, 0x11, 0xc7, 0x01, 0xe8, +0xcc, 0x19, 0x7d, 0x0a, 0x85, 0x04, 0x1b, 0x44, 0x70, 0x4d, 0xb9, 0xee, 0x5b, 0x4f, 0xcc, 0xd3, +0xb3, 0xbe, 0x47, 0xe7, 0x8c, 0xd0, 0x4e, 0x3c, 0xd8, 0x42, 0x8c, 0x33, 0x0d, 0xb8, 0x3a, 0x8a, +0x60, 0x9f, 0xf6, 0xb7, 0xad, 0xcc, 0x08, 0x99, 0x61, 0xa9, 0x28, 0x28, 0xdd, 0x8e, 0xfe, 0xe8, +0x1c, 0x99, 0x69, 0x45, 0x24, 0x0b, 0x75, 0x1e, 0xd1, 0x03, 0x9e, 0xe3, 0x64, 0xd6, 0x42, 0x4a, +0x92, 0xbe, 0x85, 0x43, 0x66, 0x3f, 0x14, 0x40, 0x0d, 0x7a, 0x4e, 0x22, 0x01, 0x06, 0x7e, 0xc4, +0x43, 0x22, 0x7c, 0x21, 0xd5, 0xff, 0xb8, 0x28, 0xc5, 0x58, 0x68, 0x95, 0x73, 0x90, 0x0b, 0xc6, +0x3d, 0xfa, 0xbc, 0x85, 0xb8, 0x98, 0x08, 0xdf, 0x17, 0x4f, 0x16, 0x72, 0xd2, 0x9c, 0x38, 0xab, +0xa4, 0xf4, 0xc6, 0xc2, 0x5b, 0xe4, 0x22, 0xef, 0xb1, 0x39, 0x22, 0x3e, 0x56, 0x0a, 0x60, 0x88, +0x90, 0xe3, 0x79, 0x96, 0x47, 0x9c, 0x82, 0x71, 0xf2, 0x18, 0x96, 0xa2, 0x26, 0x7f, 0xd6, 0xe0, +0x64, 0x26, 0x16, 0x67, 0xa3, 0xdb, 0x9e, 0x83, 0x4b, 0x4a, 0xab, 0xe0, 0x74, 0xe7, 0x82, 0x79, +0x2d, 0xb7, 0x7d, 0xbc, 0xd4, 0x65, 0x80, 0xd8, 0x42, 0x82, 0x13, 0x9f, 0x91, 0xc7, 0x6c, 0xd5, +0x56, 0xdb, 0xca, 0x81, 0x52, 0x21, 0xe6, 0x26, 0x78, 0xe6, 0xef, 0x87, 0x67, 0x57, 0x68, 0x8c, +0x6f, 0xcc, 0x5b, 0x3a, 0x96, 0x01, 0x08, 0xc4, 0x98, 0x19, 0xf4, 0x2b, 0x1b, 0x38, 0x16, 0x03, +0x99, 0xdd, 0xa5, 0xd0, 0x8c, 0x79, 0x34, 0xcb, 0x87, 0xe3, 0xb3, 0x39, 0x2d, 0x24, 0xf6, 0x12, +0x26, 0x96, 0xeb, 0x14, 0x4d, 0xec, 0xd5, 0x9b, 0x50, 0x71, 0x07, 0x14, 0x8c, 0x7c, 0xa1, 0xe3, +0x64, 0xb6, 0xc1, 0xd2, 0x7e, 0x93, 0x25, 0x1d, 0x85, 0x05, 0x43, 0x43, 0xaa, 0x35, 0xe3, 0x53, +0x55, 0xb4, 0x63, 0x22, 0x92, 0x19, 0x50, 0x34, 0xa4, 0x12, 0x6b, 0x21, 0xad, 0x6a, 0x00, 0x97, +0xeb, 0x1d, 0xd4, 0xaf, 0x17, 0x85, 0x1e, 0xd6, 0x45, 0xf7, 0x6f, 0xe3, 0xa9, 0x06, 0xd8, 0x87, +0x0d, 0xb0, 0x17, 0x4a, 0xd3, 0xa0, 0x88, 0x3b, 0x9e, 0xfa, 0x49, 0xd4, 0x47, 0xcb, 0x15, 0xa0, +0x01, 0xa1, 0xa3, 0xb0, 0x9c, 0x9a, 0xce, 0xbd, 0x1f, 0x03, 0x31, 0x3d, 0x5a, 0x83, 0xcf, 0xe7, +0xc3, 0x11, 0x3a, 0xb9, 0xb9, 0x68, 0x00, 0xfb, 0x7b, 0xa6, 0x3d, 0xd3, 0x3a, 0x54, 0x5d, 0xc7, +0xc1, 0x50, 0xd2, 0x9e, 0x8e, 0x6c, 0x83, 0xbc, 0x6c, 0xeb, 0x4c, 0x90, 0x28, 0x80, 0x5e, 0xc3, +0x9a, 0x09, 0xde, 0x60, 0x70, 0xdb, 0x5d, 0xe1, 0x19, 0x8b, 0x48, 0x17, 0x1c, 0x3e, 0x31, 0x33, +0x3f, 0xe9, 0xaf, 0xdb, 0x50, 0xa2, 0x62, 0xca, 0x80, 0x83, 0x2f, 0xcd, 0x5f, 0x13, 0xb4, 0x46, +0x4d, 0x40, 0x15, 0xab, 0xe6, 0xd1, 0xf5, 0x1c, 0x68, 0x9f, 0x52, 0x23, 0x3d, 0xb1, 0x09, 0x4b, +0xda, 0x37, 0xeb, 0x65, 0x3e, 0x11, 0x06, 0x6c, 0x2c, 0x9a, 0xd3, 0x28, 0x6a, 0x49, 0x1c, 0x82, +0x63, 0xb9, 0x86, 0x2b, 0xbc, 0x4e, 0x09, 0x0c, 0x58, 0xd4, 0x10, 0x23, 0xb4, 0x27, 0x7e, 0x4e, +0xf8, 0xb9, 0x8b, 0xb6, 0x5d, 0xf7, 0x1d, 0x5a, 0x67, 0x81, 0xa1, 0x72, 0xcc, 0xf5, 0x71, 0xc9, +0x44, 0x99, 0xc0, 0x24, 0x70, 0x5e, 0x55, 0x22, 0xd9, 0x86, 0x80, 0x62, 0xb1, 0xa4, 0x49, 0x2c, +0x92, 0xae, 0x5b, 0xf1, 0x81, 0xee, 0x98, 0xbe, 0x17, 0x3e, 0x3c, 0x1f, 0x41, 0x78, 0xc1, 0x0c, +0x3c, 0xed, 0x99, 0x27, 0xa0, 0x4d, 0xc1, 0xfd, 0x05, 0x78, 0x98, 0x19, 0xa8, 0x41, 0x50, 0x74, +0xbb, 0x01, 0x18, 0x0a, 0x16, 0xb0, 0x4a, 0x03, 0xba, 0x9c, 0x28, 0xc0, 0x30, 0x72, 0x24, 0xd9, +0x29, 0x11, 0x26, 0x1a, 0xa8, 0xa6, 0x5b, 0xac, 0x13, 0x4f, 0x40, 0xb4, 0x8c, 0x23, 0xc9, 0xdb, +0x65, 0xb5, 0x34, 0x20, 0xa9, 0x5d, 0xc2, 0xf8, 0xdb, 0x51, 0x41, 0x67, 0x2f, 0x05, 0x76, 0x1b, +0x6a, 0x16, 0x2c, 0x17, 0x32, 0xc6, 0xa3, 0x78, 0xe6, 0x2d, 0xc6, 0x0f, 0x56, 0xc6, 0x71, 0x47, +0x36, 0x38, 0x1d, 0x2b, 0x32, 0x1e, 0x46, 0xd9, 0xae, 0x3a, 0x8e, 0xb4, 0x36, 0xa5, 0x35, 0xc7, +0x7e, 0x04, 0x43, 0xe2, 0x53, 0x2c, 0x97, 0x39, 0x1a, 0x6b, 0x9e, 0xb8, 0x9c, 0x4c, 0x3b, 0x6f, +0xb3, 0x89, 0x23, 0x2d, 0x60, 0x5b, 0x82, 0xdd, 0xb1, 0x6a, 0x38, 0x9d, 0x6f, 0xb0, 0xdc, 0x94, +0xe4, 0xea, 0x74, 0xb9, 0x0b, 0x1a, 0x9a, 0x62, 0x22, 0x84, 0x2e, 0xf4, 0x44, 0x3e, 0x88, 0x3e, +0x9d, 0xe8, 0xe2, 0xfe, 0xf4, 0x7a, 0x92, 0x4a, 0xf7, 0x64, 0xf4, 0x2b, 0x11, 0xe1, 0x02, 0xed, +0xb8, 0x3b, 0xbb, 0x45, 0x3a, 0x88, 0xfc, 0x12, 0x5e, 0x9f, 0x0d, 0x2a, 0x0b, 0x78, 0x4c, 0x11, +0x21, 0x3d, 0x7b, 0x3a, 0x75, 0xbe, 0x7c, 0x9b, 0x3d, 0x9f, 0x7f, 0x3d, 0xd8, 0x09, 0x3e, 0xd4, +0x10, 0x62, 0x22, 0x66, 0x16, 0xe8, 0xc1, 0x26, 0xf9, 0x0a, 0xc3, 0x53, 0xa6, 0x67, 0xd1, 0xd8, +0x26, 0x22, 0x70, 0xfc, 0x28, 0xc0, 0x61, 0x14, 0xfb, 0x52, 0xb5, 0xfc, 0x31, 0x96, 0xab, 0x1a, +0xee, 0x39, 0x19, 0xfe, 0x32, 0x3f, 0x65, 0xad, 0xc6, 0xa6, 0xb3, 0x42, 0xec, 0x1a, 0xfc, 0x2d, +0x2d, 0xf8, 0x2a, 0x98, 0x0e, 0x8c, 0x03, 0xa6, 0x95, 0x33, 0x9e, 0x1c, 0x1e, 0xee, 0x1c, 0xee, +0x03, 0xcc, 0x8b, 0x11, 0x1a, 0x7e, 0x3a, 0xe9, 0xa2, 0x74, 0x06, 0x75, 0xbb, 0x28, 0xa3, 0xfb, +0xc6, 0xa8, 0xc4, 0xf9, 0xa7, 0x2a, 0xbc, 0x37, 0x35, 0x6a, 0xbd, 0x36, 0x72, 0x04, 0xc8, 0xc7, +0x74, 0xbb, 0xc1, 0x00, 0xe4, 0x60, 0x0b, 0x39, 0x05, 0x45, 0x42, 0xb9, 0xa2, 0x00, 0x68, 0xd1, +0xe1, 0xa4, 0xa3, 0xb0, 0xb3, 0x67, 0xbb, 0x8e, 0x47, 0xa9, 0x57, 0x89, 0x28, 0x1a, 0x9c, 0x9e, +0xa2, 0x0f, 0x5f, 0x3b, 0x57, 0xa7, 0x9d, 0xe1, 0x09, 0x02, 0xb1, 0x57, 0xc4, 0xb6, 0x5c, 0xbb, +0x2f, 0x1e, 0x82, 0x8b, 0x2e, 0xcc, 0xb1, 0x44, 0xc1, 0x09, 0xb4, 0xdb, 0x30, 0x6e, 0x2b, 0xd4, +0x47, 0x5a, 0x46, 0xf4, 0xb8, 0x22, 0x03, 0x3c, 0x07, 0xef, 0xbc, 0x74, 0x63, 0xb5, 0x01, 0xf1, +0xb9, 0x4f, 0xcd, 0xe3, 0x87, 0xc5, 0x85, 0xd7, 0xca, 0x98, 0xba, 0x5d, 0x55, 0xa4, 0xcf, 0xf4, +0x9a, 0x13, 0xba, 0x34, 0x5c, 0x10, 0x98, 0x44, 0x9c, 0x98, 0x3d, 0x1a, 0x85, 0xe6, 0x1c, 0xff, +0x91, 0x72, 0x30, 0x43, 0x5a, 0x62, 0xfc, 0xd0, 0x46, 0xff, 0x56, 0x7a, 0xd8, 0x58, 0x8b, 0x42, +0x30, 0x04, 0xef, 0xff, 0xb6, 0xb4, 0xba, 0x4f, 0x89, 0xef, 0x9f, 0xe3, 0x5a, 0x51, 0x0f, 0x2f, +0x14, 0x08, 0xc7, 0x96, 0x2f, 0xb8, 0x6e, 0x81, 0xaa, 0x83, 0x8e, 0x0e, 0xf6, 0x5c, 0xb7, 0x8d, +0xde, 0xa1, 0xdd, 0x83, 0xfd, 0x7a, 0xb5, 0x99, 0x54, 0xa8, 0xa2, 0xb6, 0x7b, 0x90, 0x68, 0xed, +0xec, 0xd5, 0x2b, 0x05, 0x8c, 0x57, 0x95, 0x0e, 0x62, 0x95, 0x03, 0xb7, 0x5e, 0x45, 0x51, 0x62, +0x54, 0x40, 0xb2, 0x5e, 0xa6, 0x31, 0xd4, 0xa9, 0xd7, 0x6d, 0x9b, 0x71, 0x08, 0xd7, 0xa7, 0xd1, +0x5f, 0x97, 0x26, 0x31, 0xc6, 0xd9, 0x4d, 0x64, 0xa1, 0x33, 0x78, 0xd8, 0x42, 0x56, 0x2d, 0x37, +0x6e, 0xa2, 0x96, 0xe5, 0x5a, 0x9b, 0xe0, 0x61, 0xdb, 0x56, 0xd1, 0x58, 0x69, 0xd9, 0xea, 0xec, +0xb4, 0x8d, 0x5a, 0xf7, 0x45, 0x05, 0xf0, 0xee, 0xc7, 0x14, 0xc0, 0xb7, 0xbc, 0x42, 0x29, 0xe9, +0xe6, 0x17, 0x47, 0xea, 0xb3, 0x52, 0x2c, 0x4e, 0x76, 0xd5, 0x7b, 0x36, 0x69, 0x99, 0x72, 0x41, +0xfd, 0x7e, 0x56, 0x40, 0x75, 0x15, 0xb1, 0xb4, 0x74, 0x05, 0x17, 0x93, 0x7a, 0x43, 0x4b, 0x91, +0xf3, 0xe1, 0xcd, 0x0b, 0x22, 0x4f, 0x70, 0x25, 0x13, 0x4f, 0x36, 0x1c, 0xd9, 0x21, 0x7d, 0x54, +0xc2, 0x36, 0xd4, 0xb2, 0x20, 0xf0, 0x27, 0x0f, 0xf8, 0xb9, 0xb5, 0x61, 0x0e, 0xac, 0xce, 0x34, +0x29, 0xce, 0x8d, 0xad, 0x42, 0xad, 0xb6, 0xad, 0x2d, 0xb4, 0x0f, 0x24, 0xd2, 0x60, 0x76, 0x55, +0xfc, 0x13, 0xec, 0x2b, 0x5a, 0x2f, 0x04, 0x8b, 0x8e, 0x20, 0xa3, 0xd7, 0x93, 0x09, 0x3c, 0xb5, +0x6a, 0x2c, 0x7d, 0x5f, 0x2b, 0x8e, 0xea, 0x5b, 0xa8, 0x64, 0xa6, 0x26, 0x5c, 0x8e, 0x63, 0x84, +0x90, 0x29, 0x1f, 0x24, 0x62, 0x31, 0x34, 0x11, 0xa6, 0x12, 0xe3, 0x3b, 0x7f, 0x7a, 0x92, 0xa9, +0x2d, 0x56, 0x08, 0x1c, 0xf8, 0xc0, 0xe9, 0x13, 0xba, 0x1e, 0x3f, 0x50, 0x52, 0x8b, 0x12, 0x64, +0x6c, 0x12, 0x78, 0x20, 0x97, 0xb2, 0xc1, 0x7d, 0xa4, 0xc9, 0x7d, 0xb2, 0x8e, 0x55, 0x2f, 0x0e, +0x61, 0x4e, 0xcd, 0x9e, 0xc1, 0x35, 0xa5, 0xd5, 0x36, 0xb5, 0x6e, 0x7c, 0xf8, 0x26, 0xf8, 0xca, +0x8f, 0xdf, 0x50, 0xa7, 0xae, 0x3f, 0xb2, 0xec, 0xc4, 0xd7, 0x89, 0xe4, 0xae, 0x05, 0xb9, 0xe0, +0x91, 0xef, 0x43, 0xf9, 0xdf, 0x5c, 0x0f, 0x47, 0x30, 0xfa, 0x73, 0x78, 0x7d, 0x65, 0x43, 0x11, +0xc2, 0x9d, 0x8b, 0x4d, 0x16, 0x71, 0xfa, 0x4b, 0xc0, 0x4b, 0xc1, 0x6c, 0x6c, 0xba, 0xe4, 0x34, +0xd3, 0xb6, 0xb1, 0xe7, 0x9d, 0xcf, 0x61, 0xf6, 0x92, 0xc1, 0x8d, 0x08, 0x2a, 0xc0, 0xbc, 0x81, +0xdb, 0x31, 0xac, 0x95, 0xe5, 0xa1, 0x36, 0xf2, 0x10, 0x5b, 0x3b, 0x3e, 0xda, 0x98, 0xe8, 0x94, +0x82, 0xf1, 0xbd, 0x04, 0xa9, 0x99, 0x63, 0x93, 0x83, 0xcf, 0x9b, 0x41, 0x14, 0x69, 0x7e, 0x3d, +0x37, 0xac, 0x46, 0x57, 0xcf, 0x98, 0x5a, 0x22, 0x6e, 0xe5, 0x44, 0xdb, 0xe8, 0x3d, 0x2a, 0x1c, +0xcf, 0xba, 0x08, 0x2e, 0x02, 0x3c, 0x82, 0x4c, 0xa6, 0x33, 0x55, 0xef, 0xd6, 0x8a, 0x9d, 0x8d, +0x5a, 0xeb, 0xeb, 0x69, 0xbf, 0xc5, 0x6e, 0x0c, 0x45, 0x24, 0xeb, 0xfb, 0x3b, 0xe6, 0xc9, 0xf8, +0x6d, 0x5a, 0x26, 0x39, 0x79, 0x68, 0x4b, 0x6a, 0x46, 0x6a, 0xa3, 0xa6, 0x16, 0x13, 0xa5, 0x6a, +0xa0, 0x36, 0x44, 0x48, 0xf9, 0x46, 0x2e, 0x4e, 0x8d, 0xb4, 0xd2, 0x98, 0x85, 0xf4, 0x28, 0x0f, +0xfc, 0x16, 0x7f, 0xde, 0x1a, 0x63, 0xf2, 0x38, 0x95, 0x22, 0xe2, 0xde, 0xa9, 0xf9, 0x18, 0x64, +0xf2, 0xfb, 0x8b, 0x4b, 0xdc, 0x9a, 0x82, 0xff, 0xbe, 0x95, 0x90, 0x40, 0x1d, 0x1d, 0x36, 0xe2, +0xa5, 0x52, 0x0a, 0xf9, 0x2a, 0xc0, 0x26, 0xae, 0xd4, 0x4e, 0x0e, 0x13, 0xb6, 0xb9, 0x0f, 0x2d, +0x86, 0x70, 0xff, 0xa5, 0x68, 0xbd, 0x9f, 0x8f, 0x9a, 0x7d, 0x7d, 0x73, 0x7e, 0xd5, 0x64, 0xe2, +0x67, 0xfd, 0x9e, 0xb8, 0x75, 0x7e, 0x57, 0x19, 0xec, 0xcd, 0xd1, 0x48, 0x78, 0xe5, 0x55, 0xe1, +0x58, 0x75, 0xdc, 0x26, 0x6c, 0x21, 0xb6, 0x87, 0x35, 0x86, 0xa8, 0x84, 0x3e, 0x86, 0xca, 0x71, +0xee, 0x7a, 0x92, 0xdf, 0x0d, 0x9c, 0xe9, 0x16, 0xda, 0xb8, 0x93, 0x77, 0x7c, 0xa3, 0x81, 0xbd, +0x61, 0x13, 0xca, 0x57, 0x7e, 0x63, 0xcc, 0xcc, 0x5a, 0x49, 0xf1, 0x8f, 0x84, 0x39, 0x9f, 0xac, +0xc6, 0x9f, 0xa8, 0x39, 0xe5, 0xbe, 0x58, 0x0b, 0x2f, 0xb0, 0x51, 0x91, 0xe2, 0xd2, 0x0d, 0xc8, +0x2a, 0x6d, 0x40, 0xc7, 0xb9, 0x63, 0x61, 0xf6, 0x11, 0x33, 0x19, 0x25, 0x1f, 0x10, 0x7b, 0x4e, +0xf2, 0x11, 0xf8, 0x3f, 0x36, 0x79, 0x7e, 0xc0, 0x15, 0x16, 0x00, 0x00}; +#endif /*__SERIAL_HTML_H__*/ diff --git a/src/web/html/h/setup_html.h b/src/web/html/h/setup_html.h new file mode 100644 index 00000000..40481cd7 --- /dev/null +++ b/src/web/html/h/setup_html.h @@ -0,0 +1,545 @@ +#ifndef __SETUP_HTML_H__ +#define __SETUP_HTML_H__ +#define setup_html_len 8636 +const uint8_t setup_html[] PROGMEM = { +0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0xed, 0x3d, 0xfb, 0x5b, 0xdb, 0x48, +0x92, 0xbf, 0xe7, 0xaf, 0xe8, 0x68, 0xef, 0x06, 0x79, 0x63, 0xfc, 0x86, 0x10, 0x02, 0xec, 0x47, +0x80, 0x24, 0xdc, 0xf2, 0x3a, 0x4c, 0x36, 0xb3, 0x47, 0xfc, 0xf1, 0xc9, 0x52, 0x1b, 0x2b, 0xc8, +0x92, 0x46, 0x92, 0x0d, 0xde, 0xd9, 0xfc, 0xef, 0x57, 0xd5, 0x0f, 0xf9, 0xd5, 0x2d, 0xcb, 0x60, +0x07, 0x66, 0xee, 0xb2, 0x3b, 0x89, 0xdc, 0x8f, 0xea, 0xee, 0xea, 0xea, 0xaa, 0xea, 0xea, 0xea, +0xea, 0x9d, 0xd7, 0x4e, 0x60, 0x27, 0xc3, 0x90, 0x92, 0x6e, 0xd2, 0xf3, 0xf6, 0x5e, 0xed, 0xe0, +0x3f, 0xc4, 0xb3, 0xfc, 0xdb, 0x5d, 0x83, 0xfa, 0xc6, 0xde, 0x2b, 0x02, 0x7f, 0x76, 0xba, 0xd4, +0x72, 0xf8, 0x27, 0xfb, 0x99, 0xb8, 0x89, 0x47, 0xf7, 0x9a, 0x34, 0xe9, 0x87, 0x3b, 0x65, 0xfe, +0x63, 0x94, 0xe9, 0xb9, 0xfe, 0x1d, 0x89, 0xa8, 0xb7, 0x6b, 0xc4, 0xc9, 0xd0, 0xa3, 0x71, 0x97, +0xd2, 0xc4, 0x20, 0xd8, 0xc4, 0xae, 0x91, 0xd0, 0x87, 0xa4, 0x6c, 0xc7, 0xb1, 0x41, 0xba, 0x11, +0xed, 0x88, 0x12, 0x25, 0x48, 0xf8, 0xdb, 0x60, 0xb7, 0x52, 0xda, 0x2a, 0x55, 0x2a, 0x95, 0xaa, +0x51, 0x86, 0x5e, 0xf4, 0x68, 0x62, 0x11, 0xdf, 0xea, 0x41, 0x9d, 0x81, 0x4b, 0xef, 0xc3, 0x20, +0x02, 0x18, 0x76, 0xe0, 0x27, 0xd4, 0x4f, 0x76, 0x8d, 0x7b, 0xd7, 0x49, 0xba, 0xbb, 0x0e, 0x1d, +0xb8, 0x36, 0x5d, 0x67, 0x3f, 0x8a, 0xc4, 0xf5, 0xdd, 0xc4, 0xb5, 0xbc, 0xf5, 0xd8, 0xb6, 0x3c, +0xba, 0x5b, 0x35, 0x24, 0x10, 0xbb, 0x6b, 0x45, 0x31, 0x85, 0x4a, 0x5f, 0xae, 0x3e, 0xae, 0x6f, +0x61, 0x72, 0x6c, 0x47, 0x6e, 0x98, 0x8c, 0xf7, 0xe8, 0xbb, 0x35, 0xb0, 0x78, 0xaa, 0x41, 0xe2, +0xc8, 0xde, 0x35, 0xac, 0xd0, 0x2d, 0x7d, 0x9f, 0xe8, 0xd4, 0xde, 0x4e, 0x99, 0x97, 0x00, 0x00, +0x8b, 0x8c, 0xd0, 0x0e, 0xbc, 0x20, 0x8a, 0xe7, 0x0c, 0x31, 0x0a, 0xda, 0x41, 0x12, 0x8f, 0x0d, +0xd0, 0x0f, 0x5c, 0xdf, 0xa1, 0x0f, 0x45, 0xe2, 0x07, 0x9d, 0xc0, 0xf3, 0x82, 0x7b, 0x83, 0x94, +0xc5, 0x54, 0x94, 0x47, 0x73, 0xb1, 0xd3, 0x0e, 0x9c, 0xe1, 0x18, 0xe6, 0x1d, 0x77, 0x40, 0x6c, +0xcf, 0x8a, 0x63, 0xe8, 0x46, 0x10, 0xfa, 0xd6, 0x40, 0x4e, 0x9f, 0x25, 0x3a, 0x53, 0x1e, 0xef, +0x43, 0x5a, 0x14, 0xe7, 0xcf, 0xd8, 0xdb, 0xef, 0x06, 0xc3, 0xc3, 0xab, 0x2f, 0x3b, 0x65, 0x6b, +0xaa, 0xd2, 0x08, 0x39, 0xdb, 0x83, 0xc0, 0x75, 0xcc, 0x4a, 0xe1, 0x7d, 0x5a, 0xd7, 0x85, 0x1e, +0x1b, 0x24, 0xf0, 0x6d, 0xcf, 0xb5, 0xef, 0x64, 0xab, 0x66, 0xc1, 0x18, 0xeb, 0x54, 0x1c, 0x5a, +0x3e, 0x22, 0x0f, 0xff, 0x59, 0x38, 0x75, 0xd4, 0x1b, 0x1c, 0x9b, 0xeb, 0xa4, 0x03, 0x93, 0x1d, +0xe8, 0x05, 0x6d, 0x17, 0x7b, 0x3f, 0x82, 0x61, 0xb1, 0x62, 0x50, 0xa6, 0x9e, 0x16, 0xea, 0xba, +0x0e, 0x95, 0xf3, 0x51, 0xf6, 0xdc, 0x01, 0x9d, 0x98, 0xd8, 0x13, 0x48, 0x48, 0xdb, 0x99, 0x04, +0xd1, 0x50, 0x83, 0x88, 0x69, 0x04, 0x94, 0x36, 0x01, 0xe4, 0x2b, 0x6d, 0xf3, 0x54, 0x0d, 0xa4, +0x0d, 0x1d, 0x24, 0x58, 0x42, 0x13, 0x80, 0x60, 0x51, 0x25, 0xae, 0x7f, 0x1b, 0x4f, 0xc2, 0x41, +0x8c, 0x48, 0x00, 0x31, 0x0d, 0x69, 0x64, 0x25, 0x41, 0x64, 0xcc, 0x22, 0x30, 0x6d, 0x6f, 0x53, +0xdd, 0x5e, 0x3f, 0x74, 0xac, 0x64, 0x72, 0xf8, 0x5f, 0x58, 0x92, 0xa6, 0xdb, 0x6f, 0x35, 0xdd, +0x1e, 0xc6, 0x09, 0xed, 0x4d, 0xf6, 0x9b, 0x25, 0x3d, 0xb1, 0xd7, 0x5b, 0x69, 0x0b, 0xb0, 0x00, +0x61, 0x45, 0x59, 0xd1, 0x2d, 0xae, 0xdc, 0x9b, 0x36, 0xf0, 0xa3, 0x3b, 0x63, 0xef, 0xf2, 0xa8, +0x79, 0x45, 0xf6, 0x2f, 0x8e, 0x35, 0x9d, 0x7d, 0x27, 0x6b, 0x77, 0x93, 0x24, 0x8c, 0xb7, 0xcb, +0x65, 0x0b, 0x48, 0xda, 0x49, 0xfa, 0x25, 0xec, 0xf9, 0x34, 0xac, 0xc3, 0xc0, 0xee, 0xf7, 0x60, +0xad, 0x59, 0x89, 0x1b, 0xf8, 0x1a, 0x80, 0xd5, 0xca, 0xa8, 0x3f, 0xed, 0xa0, 0x9f, 0x4c, 0x0c, +0x78, 0x1f, 0x53, 0x9e, 0x38, 0xde, 0x8a, 0x86, 0x44, 0x83, 0x5b, 0x17, 0x58, 0xef, 0x09, 0xfe, +0xa3, 0xeb, 0x9a, 0xb6, 0x26, 0xf4, 0x8a, 0x55, 0x1d, 0xef, 0xdd, 0x4e, 0x19, 0x96, 0xcf, 0xd4, +0x42, 0xba, 0x77, 0x3b, 0x2e, 0x5f, 0xbe, 0x72, 0x2d, 0xfb, 0x9d, 0x00, 0x3b, 0xcb, 0x8a, 0x8e, +0xd5, 0x98, 0xac, 0x15, 0x59, 0x21, 0x0c, 0x6c, 0x6c, 0xc1, 0x4d, 0x64, 0x0b, 0x06, 0x36, 0x95, +0xcd, 0x8a, 0x74, 0x82, 0xa8, 0x47, 0x80, 0xe7, 0x75, 0x03, 0x28, 0x17, 0x06, 0x31, 0x70, 0x4c, +0xcb, 0x46, 0xe4, 0x23, 0x3d, 0x59, 0x03, 0x18, 0x03, 0x02, 0x88, 0x05, 0xf9, 0x2b, 0x20, 0x70, +0x28, 0x2e, 0xf5, 0x1c, 0x28, 0xa4, 0xc9, 0x6e, 0xf7, 0x93, 0x24, 0xf0, 0x05, 0x2b, 0xe6, 0x3f, +0xd2, 0xf1, 0xc5, 0x37, 0xc0, 0x8b, 0x3d, 0x2b, 0x8c, 0xdd, 0xb6, 0x47, 0x49, 0x2f, 0x59, 0x6f, +0x48, 0xaa, 0x25, 0x07, 0x81, 0xdf, 0x71, 0x6f, 0x77, 0xca, 0xbc, 0x86, 0x06, 0xf6, 0x18, 0x77, +0x45, 0x50, 0xba, 0x81, 0x4e, 0x74, 0x33, 0x65, 0x53, 0xed, 0xf5, 0x9a, 0xa6, 0x2c, 0x97, 0x99, +0xf4, 0x96, 0xfa, 0x8e, 0x2c, 0xed, 0x50, 0x18, 0xff, 0x21, 0x93, 0x6e, 0xe4, 0x33, 0x60, 0x8a, +0x9c, 0x81, 0x94, 0xd8, 0x29, 0xf3, 0x42, 0x19, 0x50, 0xc6, 0x7a, 0x18, 0x05, 0xf7, 0x04, 0x1a, +0xad, 0x67, 0x34, 0x3a, 0x5d, 0x05, 0xb0, 0xb3, 0x5e, 0xad, 0x11, 0xfc, 0x27, 0xee, 0x61, 0x4d, +0xd1, 0x03, 0xde, 0xf8, 0x04, 0x39, 0x2c, 0x06, 0xea, 0x1d, 0x50, 0x95, 0xeb, 0x87, 0xfd, 0x71, +0x91, 0x6b, 0x08, 0xc9, 0xc7, 0x65, 0x38, 0xc8, 0xc3, 0x39, 0x2d, 0xcc, 0xcb, 0x7e, 0xfa, 0xd0, +0xb7, 0xc6, 0x46, 0x7e, 0x49, 0xdb, 0x41, 0x90, 0x10, 0x14, 0x89, 0xc4, 0x4a, 0x48, 0xcf, 0x75, +0x7c, 0xf7, 0xb6, 0x9b, 0x3c, 0x02, 0x0b, 0x0d, 0x1d, 0x12, 0xec, 0x2e, 0xb5, 0xef, 0xda, 0xc1, +0x83, 0x44, 0x44, 0x0c, 0x09, 0x0e, 0x6f, 0xf7, 0xa5, 0x61, 0xe3, 0xd0, 0x8a, 0xee, 0xc8, 0x69, +0xe0, 0xd0, 0x55, 0x8e, 0xdf, 0x81, 0x46, 0xb0, 0x8d, 0xf9, 0x83, 0x57, 0x13, 0x9b, 0xb1, 0x67, +0xd2, 0x5e, 0x98, 0x0c, 0x49, 0x1b, 0x46, 0x0c, 0xa2, 0x98, 0xd8, 0x16, 0x34, 0x41, 0x82, 0x88, +0xf4, 0x63, 0x4a, 0x0e, 0xae, 0x2e, 0x4f, 0xc8, 0x1b, 0xf2, 0x71, 0x83, 0x58, 0x9d, 0x04, 0x32, +0x23, 0x3e, 0xc1, 0x49, 0x40, 0x80, 0x9d, 0x79, 0x43, 0x92, 0x74, 0xdd, 0x98, 0x08, 0xde, 0x53, +0x78, 0x3c, 0xf2, 0x77, 0xca, 0x73, 0xf8, 0x93, 0x82, 0x2f, 0x34, 0x16, 0xe4, 0x0b, 0x53, 0x2c, +0x6b, 0x2e, 0x53, 0x08, 0x27, 0x6b, 0x83, 0xc0, 0xeb, 0xc7, 0xe4, 0xe4, 0xe8, 0x10, 0x34, 0x8c, +0x70, 0x0e, 0x09, 0x21, 0x43, 0x0e, 0x5d, 0x9f, 0x49, 0x14, 0x31, 0xea, 0xbc, 0xed, 0x5c, 0x5a, +0x8e, 0x1b, 0x10, 0xf3, 0xec, 0xf2, 0x63, 0xad, 0x71, 0x52, 0xa9, 0xbe, 0x29, 0xe4, 0x6b, 0x2d, +0xea, 0xd4, 0x1a, 0xc6, 0x3c, 0x02, 0x58, 0xb0, 0x0f, 0x07, 0xa7, 0x57, 0xb5, 0x7a, 0xa5, 0xb2, +0x9f, 0xb3, 0x0b, 0x76, 0x0f, 0x47, 0xab, 0xa2, 0xaf, 0xa3, 0xe6, 0x45, 0xbd, 0x06, 0xca, 0xae, +0x37, 0x14, 0x24, 0xb2, 0xa4, 0x7e, 0x36, 0x99, 0xe2, 0x88, 0x33, 0x1a, 0x07, 0x1e, 0x9d, 0xdf, +0xcb, 0xe5, 0xad, 0xec, 0x30, 0x72, 0xfd, 0x04, 0x76, 0x4e, 0x03, 0x1a, 0xe1, 0xaa, 0x00, 0x45, +0xd0, 0x5a, 0x29, 0x8f, 0xa3, 0xd1, 0x91, 0xff, 0xd2, 0xb8, 0x9b, 0xc0, 0xfe, 0x21, 0x6d, 0xf7, +0x6f, 0x57, 0x3c, 0xf8, 0xc3, 0xf6, 0xed, 0x4b, 0x18, 0xfd, 0x98, 0x90, 0x27, 0xbd, 0x21, 0x2a, +0x26, 0xc7, 0xa0, 0xcc, 0x44, 0x03, 0xc0, 0xc2, 0x75, 0xdc, 0x5a, 0xaa, 0xa8, 0xf7, 0xfb, 0xbd, +0x36, 0x68, 0x8b, 0x23, 0x14, 0x40, 0x4b, 0x03, 0x0f, 0xb4, 0x71, 0xdc, 0x73, 0xee, 0x1a, 0xc7, +0x3e, 0x34, 0xea, 0x3a, 0x84, 0x55, 0x79, 0x12, 0x6a, 0xe6, 0x72, 0xde, 0x0c, 0xf6, 0x95, 0x5f, +0x6b, 0x34, 0xf6, 0xce, 0x68, 0x72, 0x1f, 0x44, 0x77, 0xcb, 0x53, 0x15, 0x1f, 0xa3, 0x2e, 0xea, +0x44, 0xc3, 0x57, 0xf7, 0xa3, 0x3b, 0x92, 0x08, 0xb9, 0xa7, 0x30, 0x27, 0x19, 0xe5, 0x23, 0xa5, +0xfd, 0x0b, 0x72, 0x01, 0xd9, 0x80, 0x24, 0x87, 0x98, 0x3d, 0xd7, 0x2f, 0x11, 0x8f, 0xfa, 0xb7, +0x49, 0x77, 0x9b, 0x6c, 0x15, 0x72, 0x90, 0xd6, 0xe3, 0x35, 0x49, 0x2b, 0xbc, 0x09, 0xef, 0x1d, +0x03, 0x94, 0x35, 0x9f, 0xb7, 0xb8, 0x6b, 0x6c, 0xa1, 0xd5, 0x24, 0x0f, 0x3d, 0xcf, 0x91, 0x6d, +0x9c, 0x67, 0xef, 0x1d, 0xe1, 0x2a, 0x01, 0x55, 0x81, 0x12, 0x3b, 0xa2, 0x0e, 0x4c, 0x29, 0xf0, +0x8d, 0x18, 0x75, 0x88, 0x61, 0xd0, 0x8f, 0x48, 0x08, 0x3b, 0x30, 0x1a, 0x41, 0x06, 0xc1, 0x69, +0x20, 0x31, 0xdf, 0x59, 0x96, 0xc8, 0xfe, 0x98, 0xc2, 0x01, 0xda, 0x05, 0xab, 0xcf, 0xb5, 0x5e, +0x92, 0x44, 0x2e, 0x65, 0x00, 0x80, 0x44, 0x7c, 0x6a, 0x27, 0xe4, 0xde, 0x4d, 0xba, 0x5c, 0x17, +0xc1, 0xcd, 0x58, 0xd4, 0xe3, 0x20, 0x98, 0x44, 0x78, 0x9e, 0xd9, 0x6c, 0x52, 0x2b, 0xb2, 0xbb, +0x44, 0x50, 0x7d, 0xbc, 0xf4, 0x09, 0x94, 0x8b, 0x4d, 0xea, 0xc0, 0x96, 0xdf, 0x4e, 0x7c, 0xb1, +0x13, 0x94, 0x3f, 0x04, 0x20, 0xf6, 0x0d, 0xec, 0xa2, 0x2f, 0x0a, 0x8e, 0x99, 0x9d, 0xf0, 0xa7, +0x59, 0x30, 0x96, 0x37, 0xd7, 0xb3, 0xe8, 0xac, 0xe1, 0x5f, 0x5c, 0x60, 0x2c, 0x63, 0x91, 0x0c, +0x2c, 0xd7, 0x5b, 0x2a, 0x56, 0xe7, 0xd6, 0xe6, 0x06, 0x0a, 0xea, 0x21, 0x99, 0x71, 0x6c, 0xfb, +0xa2, 0x79, 0x8e, 0xee, 0xd1, 0xaf, 0xc0, 0x3f, 0xe8, 0x5a, 0xfe, 0x2d, 0xe3, 0xd7, 0x1e, 0xf4, +0x71, 0xc2, 0x9c, 0x37, 0xb7, 0x89, 0x20, 0x44, 0x9a, 0x95, 0x13, 0xb5, 0x5e, 0x35, 0x08, 0x6f, +0x14, 0xd6, 0x85, 0xe3, 0xc6, 0x16, 0x30, 0x51, 0x87, 0x74, 0x5d, 0x07, 0x96, 0xcf, 0x9e, 0x0f, +0x1a, 0x38, 0x4e, 0x9d, 0x4f, 0x9d, 0x9d, 0x32, 0xaf, 0x97, 0x73, 0x1c, 0x65, 0x0e, 0x33, 0x07, +0xce, 0x72, 0x13, 0xc4, 0xb3, 0xd2, 0x43, 0xb3, 0x79, 0x7c, 0xb8, 0x52, 0xe6, 0x18, 0xc7, 0xae, +0xb3, 0xd0, 0xfa, 0x78, 0x1e, 0x74, 0x70, 0x4c, 0x10, 0xe0, 0x7f, 0x9c, 0x44, 0x96, 0x8e, 0x93, +0x69, 0xa5, 0x0c, 0x9b, 0xf9, 0x03, 0xe0, 0x45, 0x90, 0x89, 0x14, 0xac, 0x4b, 0x47, 0x4b, 0x28, +0x00, 0x4b, 0xb4, 0x30, 0x41, 0x2a, 0x96, 0xf0, 0xef, 0x17, 0x5f, 0x0f, 0x7f, 0x2c, 0x05, 0x47, +0xf3, 0x74, 0xb4, 0xc7, 0xec, 0x90, 0xb5, 0xbb, 0x64, 0x14, 0xbf, 0x36, 0x39, 0xbe, 0x20, 0x26, +0xe7, 0x2c, 0x96, 0x57, 0x98, 0xbf, 0x59, 0x16, 0x82, 0x7e, 0x2e, 0x66, 0x4f, 0xa8, 0x35, 0xa0, +0x84, 0x77, 0x95, 0x30, 0x83, 0x32, 0x01, 0x71, 0x4d, 0x0e, 0x3f, 0x1f, 0x5c, 0xec, 0xb4, 0xa3, +0xf2, 0x7c, 0x00, 0x57, 0xa0, 0x04, 0xf0, 0x83, 0x1d, 0x54, 0x09, 0x04, 0x20, 0x2b, 0xa2, 0x24, +0xc4, 0xc3, 0x2a, 0x54, 0x88, 0xb9, 0x1a, 0xc0, 0x95, 0x80, 0x6d, 0x52, 0x7d, 0x57, 0x2b, 0x55, +0x37, 0xb7, 0x4a, 0x8d, 0x52, 0x75, 0xce, 0x0c, 0x84, 0x7b, 0xcf, 0xa3, 0x29, 0x00, 0xa6, 0xf7, +0x1d, 0x27, 0xa2, 0x71, 0xbc, 0x52, 0x46, 0xe6, 0x86, 0xd8, 0x0a, 0x68, 0x79, 0xd6, 0x83, 0xd4, +0xf2, 0xaa, 0x1b, 0x8b, 0xa9, 0x79, 0xcf, 0xa3, 0x48, 0xf5, 0xdb, 0x3d, 0x2b, 0xbe, 0x5b, 0x31, +0x6e, 0x4e, 0xa1, 0x89, 0x3f, 0x1e, 0x6e, 0x0e, 0xcf, 0x9a, 0xa4, 0xba, 0x62, 0xcc, 0x1c, 0xfa, +0x71, 0xf5, 0x8f, 0x89, 0x99, 0xda, 0xea, 0x31, 0x53, 0xfb, 0xe3, 0x61, 0xe6, 0x93, 0x95, 0xd0, +0x7b, 0x6b, 0xb8, 0x62, 0xdc, 0x88, 0x56, 0x56, 0x82, 0x9e, 0x9f, 0x65, 0xb1, 0xb8, 0x88, 0x82, +0x84, 0xda, 0xfc, 0x94, 0x73, 0xd5, 0x46, 0x8b, 0xc5, 0x25, 0x35, 0xe9, 0x3d, 0x30, 0xcd, 0x66, +0xac, 0x93, 0xb9, 0x84, 0xf4, 0x0a, 0xe8, 0x8a, 0x69, 0x6b, 0x09, 0xdb, 0x9e, 0x39, 0x3d, 0x10, +0xc0, 0x3f, 0x4d, 0xdb, 0xb2, 0xb0, 0xb9, 0xd5, 0xa8, 0x5c, 0x42, 0xa1, 0x69, 0xf2, 0x7d, 0x5f, +0x68, 0xdd, 0x02, 0xc6, 0xef, 0xbb, 0x2e, 0x6c, 0xe9, 0xe3, 0x6e, 0xd0, 0xf7, 0x1c, 0xd2, 0x06, +0x95, 0x83, 0xe3, 0x1e, 0xb4, 0x8e, 0xf6, 0x90, 0x84, 0xe9, 0xa0, 0xf3, 0x28, 0x12, 0xec, 0x80, +0x00, 0xaa, 0xdf, 0xa0, 0x6c, 0x33, 0xf6, 0x5e, 0x08, 0xc5, 0x1f, 0x0b, 0x7b, 0xf6, 0x6a, 0xcf, +0x73, 0x75, 0xb4, 0xae, 0xd2, 0x46, 0x47, 0x3d, 0xca, 0x75, 0x86, 0x8b, 0x68, 0x95, 0x46, 0xf9, +0xf9, 0x58, 0x55, 0xec, 0x3a, 0x9e, 0x72, 0xea, 0xbb, 0x54, 0xfb, 0xaf, 0x9c, 0x28, 0x1c, 0x51, +0x3b, 0xf1, 0x41, 0x77, 0x53, 0xda, 0x73, 0x20, 0x9d, 0x48, 0x1c, 0xad, 0xc2, 0x42, 0xfe, 0x34, +0x84, 0xa4, 0xa7, 0x35, 0x71, 0xbf, 0xcd, 0xa6, 0xf3, 0x2c, 0x48, 0xd8, 0x31, 0xcd, 0x93, 0x51, +0x15, 0xee, 0xed, 0x93, 0x35, 0x90, 0x2d, 0xa4, 0x17, 0x38, 0x7d, 0x0f, 0x96, 0x62, 0x70, 0x4f, +0xa3, 0x35, 0x8e, 0x15, 0x12, 0x74, 0xc8, 0x5a, 0x65, 0x4d, 0x5a, 0x4d, 0x62, 0x6e, 0x78, 0xec, +0xa2, 0xb9, 0xc4, 0xc3, 0xfd, 0xc1, 0x1a, 0x3a, 0x32, 0x41, 0x59, 0x97, 0xde, 0xe7, 0xe8, 0xcb, +0xb3, 0xe3, 0xec, 0x13, 0xf5, 0x69, 0x84, 0xee, 0x51, 0x4b, 0x40, 0xdb, 0xff, 0xd9, 0x03, 0x14, +0x60, 0x0a, 0xb2, 0xa5, 0x15, 0x9c, 0xa1, 0xac, 0x0c, 0x3b, 0xa7, 0x40, 0xe1, 0x11, 0xe5, 0xd6, +0xee, 0x90, 0x46, 0x20, 0x59, 0x87, 0x5e, 0x60, 0x39, 0xab, 0x45, 0xd4, 0x25, 0x34, 0x38, 0x7c, +0x59, 0x87, 0x8d, 0x62, 0x59, 0x5d, 0x52, 0x94, 0x24, 0x6c, 0x91, 0xc3, 0xa6, 0x1f, 0x44, 0xc5, +0x3f, 0x51, 0xba, 0x1c, 0x5a, 0x3f, 0xcd, 0xd7, 0x04, 0xb1, 0x13, 0x27, 0xa7, 0x79, 0x4c, 0x82, +0xcf, 0x8d, 0x9e, 0xfb, 0x2e, 0xf5, 0x47, 0x07, 0xd4, 0x21, 0x88, 0x79, 0x34, 0x98, 0x84, 0x56, +0x3f, 0x46, 0xdc, 0x25, 0x24, 0xee, 0xfb, 0x50, 0x7a, 0xf5, 0xc8, 0x3a, 0x08, 0x7a, 0xcd, 0x24, +0x08, 0x5f, 0x9e, 0xa3, 0x92, 0x16, 0x57, 0x31, 0xf7, 0xf4, 0x70, 0x63, 0xb2, 0x86, 0x86, 0x76, +0x0b, 0x8f, 0x1c, 0x50, 0x90, 0xac, 0xad, 0x1e, 0x59, 0x20, 0x1f, 0xd9, 0x09, 0xc7, 0xcb, 0xc4, +0x16, 0x0a, 0xdc, 0xb5, 0x74, 0xf9, 0xfd, 0xd4, 0x15, 0x67, 0x3d, 0xbc, 0xb8, 0x45, 0xc7, 0x4c, +0xa5, 0x11, 0x3f, 0x7a, 0x0c, 0xb0, 0xff, 0x6e, 0x8f, 0x92, 0x78, 0xe8, 0xdb, 0xc4, 0x84, 0x35, +0xd6, 0xe9, 0x33, 0x5d, 0x63, 0xff, 0x62, 0xfd, 0xdc, 0xf7, 0x86, 0xeb, 0xe8, 0xa0, 0x55, 0x58, +0xa9, 0x93, 0x44, 0x12, 0x25, 0x5f, 0x93, 0x6e, 0x72, 0xd5, 0x7b, 0x69, 0x58, 0x62, 0x3c, 0x9a, +0x1c, 0x75, 0x3a, 0xae, 0xed, 0x52, 0xdf, 0x1e, 0x12, 0x73, 0xb4, 0x83, 0x6a, 0xd3, 0xe4, 0x9e, +0xc2, 0xda, 0xab, 0x94, 0xde, 0x6d, 0x30, 0x86, 0x0e, 0x1f, 0x9b, 0x4b, 0xc5, 0xd3, 0xa4, 0x74, +0x1b, 0x7a, 0x0e, 0x74, 0xc4, 0x80, 0x25, 0x4e, 0x43, 0xd8, 0x3e, 0xfa, 0xc3, 0x3f, 0x86, 0xeb, +0xc4, 0xd5, 0x05, 0x69, 0x82, 0xee, 0xf2, 0x5c, 0x1b, 0x33, 0xdd, 0xe6, 0x6c, 0xbc, 0x5f, 0x3f, +0xd7, 0xc5, 0x56, 0xa8, 0x47, 0xa3, 0x0e, 0x90, 0x32, 0x39, 0xbe, 0x58, 0x99, 0xaf, 0xad, 0x9f, +0x70, 0xe3, 0xf9, 0x8b, 0xd4, 0x11, 0x11, 0x09, 0x17, 0x41, 0x94, 0xac, 0x50, 0x29, 0x84, 0xf1, +0x63, 0x0b, 0x2f, 0x77, 0xfc, 0xe9, 0x2e, 0xc2, 0x04, 0x9e, 0x7b, 0xea, 0xfa, 0xfd, 0x84, 0xc6, +0x45, 0xc2, 0x9c, 0x68, 0x36, 0xe4, 0xef, 0xc2, 0x6a, 0x11, 0xc4, 0xfd, 0xb3, 0x5e, 0x24, 0x86, +0x70, 0x95, 0x0b, 0xe7, 0x57, 0x14, 0x52, 0x4f, 0xc5, 0xc3, 0x7c, 0x83, 0x9e, 0xde, 0x51, 0x05, +0x10, 0xf5, 0x41, 0xfa, 0xa9, 0xc8, 0x6f, 0x85, 0x59, 0xa3, 0x13, 0x05, 0x3d, 0xe9, 0x8f, 0x3c, +0xee, 0xae, 0x42, 0x93, 0x2b, 0x18, 0x00, 0xf3, 0x58, 0x79, 0x62, 0x2f, 0x9a, 0x20, 0xa8, 0xd3, +0x6e, 0xf0, 0x1f, 0x2a, 0x77, 0x19, 0x14, 0xe7, 0x40, 0x60, 0xe3, 0x7d, 0x80, 0xa4, 0xb4, 0x13, +0xf9, 0xce, 0x2c, 0xf9, 0xf5, 0x16, 0x6c, 0xcb, 0x0a, 0x5d, 0x50, 0xa5, 0xfa, 0x5e, 0x72, 0x96, +0x84, 0xb3, 0xd7, 0x5b, 0x1e, 0x65, 0x0b, 0xff, 0xf9, 0xe4, 0x24, 0x48, 0xe9, 0xea, 0xc9, 0xa4, +0x24, 0xe0, 0x8d, 0xd0, 0x83, 0xf7, 0xa9, 0x52, 0xb4, 0xbc, 0x7c, 0xb9, 0xdc, 0xec, 0xfb, 0x91, +0x1b, 0x53, 0xf2, 0x0b, 0x69, 0x8a, 0xcd, 0xd4, 0x4b, 0x92, 0xce, 0xb3, 0xbd, 0x7b, 0x16, 0x19, +0x7d, 0x62, 0x25, 0x6e, 0xd2, 0x77, 0x28, 0x31, 0x1d, 0x6a, 0xbb, 0x3d, 0xe6, 0x4d, 0xb0, 0x3a, +0x3f, 0xd9, 0xbe, 0x0f, 0xed, 0x2d, 0x4b, 0xbf, 0x5b, 0x1d, 0x4e, 0x02, 0xff, 0xf6, 0xe7, 0x22, +0x05, 0x89, 0xf8, 0x85, 0x23, 0xe5, 0xbc, 0xd3, 0x41, 0x82, 0x37, 0xc3, 0x88, 0xa2, 0x71, 0x02, +0x69, 0xb7, 0x48, 0xf0, 0xba, 0x9b, 0x30, 0x55, 0x3c, 0x1d, 0x45, 0x13, 0x4e, 0x7c, 0x00, 0x14, +0x5b, 0x64, 0xec, 0x86, 0xfb, 0xc4, 0xbd, 0xa8, 0x5d, 0xd3, 0x05, 0x1a, 0x6a, 0x52, 0xb3, 0x8d, +0xb4, 0x4d, 0xc4, 0xc4, 0xe9, 0x47, 0x98, 0xb0, 0xfa, 0x5b, 0x55, 0x7d, 0xff, 0xd0, 0x8d, 0xcf, +0xb0, 0x99, 0x83, 0xa0, 0xf7, 0x87, 0xd8, 0x26, 0x9d, 0xfe, 0xf7, 0xd5, 0xd5, 0xcb, 0x62, 0xc1, +0xbc, 0x47, 0xcf, 0xc2, 0x76, 0x3f, 0x44, 0xc1, 0x1d, 0xdb, 0x16, 0x89, 0xfd, 0xd1, 0x0a, 0x77, +0x47, 0xbd, 0xdf, 0x92, 0xe4, 0xe5, 0x6e, 0x8f, 0x56, 0xbc, 0x35, 0xc2, 0xc1, 0xbf, 0xdc, 0xbd, +0xd1, 0x81, 0xe7, 0x02, 0x85, 0x93, 0x63, 0x67, 0xc2, 0x99, 0x6f, 0x85, 0x74, 0xc0, 0x1b, 0x3c, +0x76, 0x5e, 0x26, 0x3a, 0xbe, 0xc0, 0x76, 0x02, 0xfb, 0xfa, 0xb3, 0xb0, 0x81, 0xed, 0xbd, 0xd0, +0x55, 0x91, 0xde, 0x34, 0x59, 0x0d, 0x26, 0xa6, 0x3d, 0x35, 0xd8, 0x32, 0xb9, 0x7f, 0xa1, 0x64, +0x71, 0x15, 0x84, 0xae, 0xbd, 0x52, 0x42, 0x60, 0x2d, 0x18, 0x24, 0xb4, 0x12, 0x10, 0xe2, 0xfe, +0xae, 0x71, 0xfd, 0x6d, 0xfd, 0xdb, 0x9b, 0xfd, 0xf5, 0xff, 0xb1, 0xd6, 0xff, 0x55, 0x59, 0x7f, +0xf7, 0xad, 0xf4, 0xad, 0xfc, 0x97, 0x6f, 0xff, 0xf1, 0x9f, 0xbf, 0xec, 0xde, 0xb4, 0xde, 0x68, +0x8e, 0x27, 0xc9, 0x93, 0x31, 0x37, 0x7d, 0x75, 0xd2, 0x1f, 0x79, 0x0e, 0xb0, 0xfb, 0x8b, 0x68, +0xae, 0xb6, 0x48, 0xc7, 0x7d, 0x60, 0x5e, 0xb4, 0xdc, 0x9e, 0x52, 0x24, 0x74, 0x80, 0x47, 0x23, +0x1d, 0x3c, 0x43, 0x07, 0xbd, 0xcc, 0x8d, 0x89, 0x1f, 0xb0, 0xb3, 0xf4, 0x5b, 0x5a, 0x22, 0xfb, +0x19, 0xe7, 0xed, 0x93, 0x70, 0x4a, 0xcc, 0x6f, 0x97, 0xb7, 0x12, 0x93, 0xb0, 0xdf, 0xf6, 0xdc, +0xb8, 0x0b, 0xf9, 0xb0, 0xab, 0x06, 0xa0, 0x09, 0xb9, 0xb7, 0x62, 0xd0, 0xf2, 0x6c, 0x9b, 0xc6, +0x71, 0xa7, 0xef, 0x79, 0x43, 0x12, 0x51, 0x9b, 0xba, 0x03, 0x28, 0xc1, 0x2c, 0x01, 0x52, 0xfd, +0x29, 0xa1, 0xbe, 0xdc, 0xb1, 0x60, 0xff, 0xbc, 0x4d, 0x2a, 0x85, 0x55, 0xdf, 0xf7, 0x7c, 0xb6, +0xc3, 0x6a, 0xa4, 0x98, 0x39, 0xa7, 0xd5, 0xe4, 0x45, 0x2e, 0x24, 0xd0, 0x18, 0xed, 0x00, 0xa6, +0x6a, 0x28, 0x2e, 0x59, 0x13, 0xb3, 0x1b, 0xf4, 0x28, 0x54, 0x70, 0xe3, 0xc4, 0xf2, 0x9f, 0xae, +0xc1, 0x3f, 0xc5, 0xe6, 0x83, 0x48, 0x4d, 0xfb, 0xc7, 0x2d, 0x3f, 0x53, 0x49, 0x2a, 0xfb, 0x0f, +0xac, 0x92, 0x09, 0xfb, 0x93, 0xef, 0xa4, 0x15, 0xf8, 0x10, 0x73, 0xda, 0xa2, 0x66, 0x2d, 0x40, +0xa7, 0xd0, 0xf8, 0xaa, 0x4d, 0x40, 0x3f, 0x4b, 0xf3, 0x06, 0x9c, 0x84, 0x9e, 0x35, 0xfc, 0x29, +0xd1, 0x40, 0x16, 0xd5, 0xc1, 0xa7, 0xfb, 0x96, 0xdb, 0x8f, 0x0c, 0xd8, 0x59, 0x78, 0x05, 0x83, +0xcf, 0xe7, 0x47, 0x26, 0x6b, 0x5c, 0x06, 0xc9, 0x63, 0x1c, 0xcf, 0x9e, 0xb2, 0x55, 0xbc, 0xea, +0x47, 0x3e, 0xf0, 0xe0, 0x0e, 0xfa, 0x27, 0x7a, 0x74, 0x6c, 0xaf, 0x88, 0xd7, 0x22, 0x20, 0x1d, +0x76, 0x90, 0xab, 0x0d, 0x40, 0x01, 0xc3, 0xbe, 0x09, 0xef, 0xa3, 0x97, 0x76, 0xf0, 0x78, 0xe4, +0xa3, 0x38, 0x22, 0x4d, 0x3b, 0xa2, 0xd4, 0xc7, 0x40, 0x39, 0x11, 0x31, 0x43, 0x10, 0x4b, 0x1e, +0x89, 0xbb, 0x6e, 0x07, 0xaf, 0x94, 0x16, 0xc9, 0xf9, 0xc9, 0xd1, 0xe1, 0x78, 0x60, 0x82, 0x55, +0x62, 0xe8, 0x81, 0x35, 0xfb, 0x42, 0x2d, 0x52, 0xfd, 0x9e, 0xeb, 0x5b, 0x20, 0x8d, 0x57, 0x28, +0xd6, 0x18, 0x16, 0x70, 0xc1, 0xb3, 0xab, 0xc6, 0xbb, 0x46, 0x85, 0x79, 0x87, 0xef, 0x1a, 0xb5, +0x8d, 0x8d, 0xe5, 0x59, 0x61, 0x26, 0xb5, 0x9c, 0x0b, 0x16, 0x83, 0x23, 0x5f, 0xf8, 0x0a, 0xec, +0x1e, 0x94, 0x8f, 0x33, 0x97, 0xef, 0x93, 0x38, 0xea, 0xec, 0xc4, 0x35, 0x44, 0x34, 0xa5, 0x57, +0x8f, 0xa1, 0x6f, 0x11, 0x6b, 0x47, 0x5c, 0x89, 0xe6, 0xe1, 0x59, 0x46, 0x4a, 0x14, 0x41, 0x8a, +0x5f, 0x80, 0x94, 0xa6, 0x09, 0xfa, 0x55, 0x6e, 0x39, 0x3b, 0x4d, 0xed, 0xfc, 0xc6, 0x36, 0xc8, +0x0a, 0x4c, 0x07, 0x15, 0xae, 0xbc, 0x00, 0xac, 0xb8, 0xdf, 0xee, 0xb9, 0xc9, 0x48, 0xfe, 0xb2, +0xf0, 0x56, 0x23, 0xc1, 0x4c, 0x22, 0x34, 0x48, 0x65, 0x49, 0xdc, 0xcc, 0xb9, 0x53, 0x66, 0xc1, +0x94, 0x06, 0x51, 0x4f, 0x91, 0x3e, 0x86, 0x9c, 0x6e, 0xc4, 0x96, 0x19, 0xce, 0x96, 0xde, 0xd1, +0x77, 0xbc, 0xc2, 0xbc, 0xb9, 0xdd, 0xb1, 0x26, 0xd4, 0x0d, 0x11, 0x84, 0x8c, 0x46, 0x56, 0x0c, +0xf2, 0xe6, 0xe8, 0x72, 0xbf, 0x79, 0x44, 0x9a, 0x47, 0x57, 0x57, 0xc7, 0x67, 0x9f, 0x9a, 0xc4, +0x44, 0x2f, 0x24, 0xbc, 0x1a, 0x5f, 0x98, 0x08, 0x69, 0xb6, 0x6c, 0x41, 0x79, 0xdc, 0xc3, 0x58, +0x91, 0xa4, 0x4c, 0x8e, 0x1e, 0xd8, 0xc7, 0x7f, 0x35, 0xcf, 0xcf, 0xc8, 0x28, 0xa8, 0xde, 0x23, +0xac, 0x58, 0x73, 0xa9, 0x7b, 0xae, 0x37, 0x2c, 0xef, 0xd3, 0xea, 0xd5, 0x46, 0x16, 0x62, 0x0d, +0x99, 0x00, 0x7e, 0x18, 0x69, 0xb0, 0xb5, 0x8b, 0xf3, 0xe6, 0xd5, 0x58, 0xb0, 0xb5, 0x7e, 0x88, +0xce, 0x97, 0x06, 0xa1, 0xbe, 0xcd, 0xa9, 0xb5, 0x07, 0x7a, 0x9c, 0x1b, 0x5a, 0x51, 0xc2, 0x48, +0x68, 0x1d, 0xf7, 0x37, 0x58, 0xdc, 0xa6, 0x61, 0xb2, 0x9e, 0x46, 0xcf, 0xec, 0x27, 0x1d, 0x16, +0x3d, 0x93, 0xe4, 0xf8, 0x33, 0x85, 0xc4, 0x45, 0xae, 0x8f, 0x6b, 0x11, 0xb0, 0x25, 0x8f, 0xd9, +0xc6, 0xd7, 0x59, 0x07, 0x63, 0x3f, 0x8a, 0xf5, 0x2a, 0x86, 0xb5, 0x97, 0xf3, 0xba, 0xc6, 0xfc, +0x16, 0x1b, 0xaa, 0x16, 0xa7, 0x34, 0xc8, 0x71, 0x2d, 0x9b, 0xcf, 0xf2, 0x98, 0x9e, 0x8d, 0x91, +0xf9, 0xf0, 0xf2, 0xfc, 0x02, 0x3d, 0xca, 0x7b, 0xd7, 0x44, 0xb3, 0xd8, 0x57, 0x7a, 0xe4, 0xfa, +0xd4, 0x75, 0x20, 0xd0, 0xc9, 0xd7, 0xe5, 0xea, 0x17, 0x83, 0x92, 0x35, 0xdd, 0xd2, 0xe4, 0x86, +0xc5, 0xdc, 0x9c, 0x0d, 0x08, 0x29, 0xf8, 0x85, 0x0c, 0x40, 0x48, 0x4c, 0xc6, 0x39, 0x90, 0xc2, +0x18, 0xc3, 0xe2, 0xb1, 0x49, 0x89, 0x89, 0x5a, 0x96, 0x70, 0x1e, 0x2c, 0xa6, 0xb7, 0x65, 0x62, +0x72, 0xef, 0x7a, 0x1e, 0xba, 0x82, 0x45, 0xb4, 0x07, 0xdb, 0x2a, 0xe7, 0x75, 0xe1, 0xf9, 0xb6, +0x44, 0x8a, 0x6a, 0xd3, 0xd1, 0x1c, 0x35, 0xc1, 0x1d, 0x3b, 0x20, 0xf0, 0x26, 0x62, 0x3b, 0x8e, +0x4f, 0x81, 0x47, 0x3b, 0xc9, 0x64, 0x9c, 0xd5, 0xfc, 0xc1, 0x36, 0x45, 0x6c, 0x59, 0xf2, 0x8b, +0x1d, 0x84, 0x43, 0x52, 0xab, 0xd4, 0xea, 0x93, 0x61, 0x2d, 0xfb, 0xde, 0x54, 0x7f, 0x3d, 0x77, +0x6f, 0xa6, 0x01, 0x07, 0xb7, 0xac, 0x91, 0x53, 0xba, 0xbd, 0x2d, 0x7f, 0xfd, 0x57, 0xf7, 0xe1, +0xe8, 0x9f, 0x9b, 0xb5, 0xde, 0x07, 0x45, 0x60, 0x4f, 0x5e, 0x8c, 0xcd, 0x59, 0x19, 0xe0, 0xcc, +0x07, 0x7c, 0xeb, 0x26, 0xdd, 0x7e, 0xbb, 0x64, 0x07, 0xbd, 0xb2, 0xd7, 0xef, 0x59, 0x61, 0x9f, +0x8d, 0x65, 0x16, 0xf2, 0x27, 0x56, 0x6e, 0x16, 0xf0, 0x4e, 0x59, 0xf6, 0x7f, 0x3a, 0xce, 0xa6, +0x5c, 0x40, 0x4c, 0xdc, 0xcf, 0x1f, 0xef, 0x54, 0x83, 0xb9, 0xba, 0x59, 0x86, 0xdf, 0xa0, 0x6b, +0xc4, 0xe5, 0x76, 0xe7, 0xed, 0xdb, 0xda, 0x5b, 0xd0, 0x41, 0x3f, 0x1d, 0x5f, 0x91, 0xe6, 0xe7, +0xfd, 0x6d, 0x22, 0x52, 0xc8, 0xf6, 0x36, 0x91, 0x61, 0x4b, 0xb5, 0x58, 0x61, 0xf3, 0x4f, 0x41, +0xb3, 0x4d, 0xc4, 0x5e, 0x31, 0x17, 0xe6, 0x60, 0x4f, 0x62, 0x25, 0xee, 0x80, 0x62, 0x1f, 0x02, +0x3f, 0x2e, 0x05, 0xd1, 0x2d, 0x54, 0xb4, 0x61, 0x9f, 0x42, 0xa1, 0x43, 0xc3, 0x75, 0xdf, 0x5e, +0x8f, 0xad, 0x72, 0xa3, 0x54, 0x29, 0x3b, 0x94, 0x3a, 0x33, 0x18, 0x25, 0x7b, 0x07, 0x07, 0xe4, +0xc3, 0x3f, 0xd7, 0xcf, 0x0e, 0xd6, 0x9b, 0xfb, 0x04, 0x8a, 0xe5, 0xc0, 0xed, 0x34, 0xed, 0x66, +0x06, 0x73, 0x9e, 0x1c, 0xc2, 0xc0, 0x8a, 0x50, 0x55, 0x3f, 0xf6, 0x07, 0x64, 0x97, 0x54, 0xde, +0xcf, 0xe4, 0x25, 0x31, 0x4f, 0x9f, 0xc9, 0x00, 0xbc, 0x6c, 0xd5, 0x36, 0x37, 0x43, 0x50, 0xab, +0xa1, 0xc4, 0xf5, 0xcc, 0x8a, 0xbb, 0x06, 0xdd, 0xbf, 0x48, 0x0c, 0xdc, 0xbc, 0x96, 0x89, 0x30, +0xed, 0x19, 0xad, 0xe2, 0x6c, 0xb9, 0x0a, 0x94, 0x3a, 0xac, 0x13, 0xf3, 0xd3, 0xc5, 0xf1, 0x79, +0xa5, 0xa0, 0x2c, 0x52, 0x85, 0x22, 0x57, 0xbf, 0xf2, 0x22, 0x55, 0x75, 0x91, 0x1a, 0x42, 0x69, +0xf0, 0x22, 0x35, 0x75, 0x91, 0x3a, 0x14, 0xb9, 0x14, 0x50, 0xea, 0xea, 0x22, 0x0d, 0x84, 0x52, +0xe3, 0x45, 0xe0, 0xbb, 0x79, 0xb8, 0xaf, 0x2e, 0x87, 0x23, 0x3b, 0xac, 0xf2, 0x72, 0xf0, 0xdd, +0x3c, 0x38, 0x51, 0x97, 0xdb, 0x84, 0x72, 0x58, 0x66, 0x53, 0x99, 0xfb, 0x56, 0xe4, 0xbe, 0x55, +0xe6, 0x6e, 0x89, 0xdc, 0x2d, 0x65, 0xee, 0x3b, 0x91, 0xfb, 0x4e, 0x8d, 0xb0, 0x8a, 0xc8, 0xae, +0x56, 0xd4, 0xf9, 0x55, 0x99, 0x5f, 0x55, 0xe7, 0x33, 0x74, 0x6e, 0x0a, 0x8c, 0x6b, 0xf0, 0x59, +0x45, 0x84, 0x1e, 0xbe, 0x15, 0x85, 0x34, 0x18, 0xad, 0x32, 0x94, 0x6e, 0x88, 0x42, 0x0d, 0x4d, +0x21, 0x86, 0xcf, 0x2d, 0x51, 0x68, 0x43, 0x53, 0x08, 0x91, 0x79, 0x58, 0x11, 0x85, 0x36, 0xc9, +0x3a, 0xda, 0xab, 0x8f, 0x2f, 0xff, 0xfb, 0x35, 0x14, 0x9f, 0x28, 0xdd, 0x9a, 0xa2, 0x56, 0x15, +0xe9, 0xd6, 0x6b, 0x4b, 0x21, 0x5c, 0x8e, 0xc4, 0x8a, 0x8e, 0x68, 0xf3, 0x50, 0x2d, 0x07, 0x01, +0x34, 0x77, 0x72, 0x74, 0xa8, 0xa5, 0xdb, 0x3c, 0x84, 0xcb, 0x01, 0x35, 0x74, 0xf4, 0xca, 0xb3, +0x37, 0xf4, 0xd3, 0xcd, 0xa7, 0x9a, 0x98, 0x9f, 0x9b, 0x17, 0xc7, 0xe4, 0xf4, 0xb8, 0x79, 0x9e, +0x31, 0xeb, 0x7c, 0xc6, 0x65, 0xd9, 0xf3, 0xe6, 0x71, 0xc6, 0xe4, 0xf3, 0x89, 0x17, 0x65, 0x61, +0xa5, 0xfc, 0x3d, 0x83, 0x06, 0xf8, 0xfc, 0xeb, 0xa7, 0x9f, 0x4f, 0xbd, 0x3a, 0x5f, 0xae, 0xa6, +0xaa, 0x7a, 0x39, 0x55, 0xe5, 0x7a, 0xaa, 0x02, 0x9d, 0xfd, 0x63, 0x4e, 0x5f, 0xe4, 0xea, 0xaa, +0xbe, 0x13, 0x65, 0xf5, 0xf8, 0xa8, 0xc9, 0xa5, 0x54, 0x03, 0x7e, 0xa0, 0x65, 0x18, 0x35, 0x89, +0xe1, 0x1a, 0x60, 0x58, 0xcb, 0x2e, 0x6a, 0x12, 0xb7, 0xb5, 0xba, 0x6c, 0x57, 0x8b, 0xdb, 0x9a, +0xc4, 0x57, 0x4d, 0x8d, 0xaf, 0x9a, 0xc4, 0x57, 0x4d, 0x8d, 0xaf, 0x9a, 0xc4, 0x57, 0x4d, 0x8d, +0xaf, 0xba, 0xec, 0x71, 0xbd, 0xa6, 0xce, 0x97, 0x7d, 0xad, 0xd7, 0xd5, 0xf9, 0x72, 0xee, 0xeb, +0x0d, 0xe6, 0xba, 0xcb, 0x2c, 0x71, 0xea, 0x92, 0x72, 0x24, 0xf5, 0x8d, 0x79, 0x25, 0x71, 0x4c, +0xff, 0xb8, 0x10, 0x2b, 0x61, 0x13, 0xdf, 0x37, 0xc8, 0x2a, 0x8d, 0xb3, 0xf8, 0x8f, 0x33, 0x51, +0xfa, 0xdd, 0x78, 0xe9, 0x69, 0x7e, 0xa1, 0xe4, 0x10, 0x71, 0x7d, 0x99, 0x3c, 0x82, 0x98, 0x87, +0xe7, 0x67, 0x57, 0xe4, 0x0b, 0x6c, 0xff, 0xd7, 0xc9, 0x87, 0xf3, 0xf3, 0xab, 0x82, 0x9e, 0x6b, +0x30, 0xd2, 0x9b, 0xc3, 0x30, 0xf4, 0xac, 0x82, 0x0d, 0x77, 0x05, 0x5c, 0x62, 0x53, 0x66, 0x6b, +0xa5, 0xd9, 0x1c, 0x71, 0x36, 0x47, 0x9e, 0xad, 0x5c, 0xa0, 0x71, 0x0e, 0x37, 0x8f, 0xab, 0xcd, +0xe3, 0x64, 0xcf, 0xcd, 0xbd, 0xe6, 0x73, 0xac, 0x31, 0x42, 0xfb, 0xd2, 0xfc, 0xb0, 0xae, 0xe1, +0x1f, 0x12, 0xa3, 0xb5, 0xca, 0x74, 0x8d, 0x37, 0x73, 0x39, 0xdd, 0x3c, 0x8e, 0x43, 0xcc, 0x8b, +0xe6, 0xe5, 0xfe, 0x29, 0x93, 0xd1, 0x63, 0xd7, 0xec, 0x0a, 0xf3, 0x38, 0x11, 0x31, 0x3f, 0x9e, +0xec, 0x37, 0x3f, 0xe7, 0xac, 0x27, 0x71, 0x52, 0xdb, 0x5a, 0xac, 0x9e, 0xc4, 0x55, 0xed, 0xdd, +0x42, 0xf5, 0xea, 0x12, 0x63, 0xf5, 0xca, 0x62, 0xf5, 0x24, 0xde, 0xea, 0xd5, 0xc5, 0xea, 0x8d, +0x38, 0xf0, 0x62, 0xf5, 0x46, 0x9c, 0x99, 0x1b, 0x18, 0x29, 0xec, 0xe2, 0x63, 0x76, 0x24, 0x4f, +0xbe, 0x5e, 0x9e, 0x9f, 0x9f, 0x8a, 0x9b, 0xf5, 0x71, 0x61, 0x3e, 0xe3, 0x7e, 0x44, 0xf5, 0x11, +0x37, 0xd7, 0xf3, 0x70, 0xce, 0xbf, 0xd5, 0xf9, 0x92, 0x1a, 0xea, 0x1a, 0xb9, 0x24, 0x67, 0xbd, +0xbe, 0xa5, 0xe7, 0xfa, 0x9c, 0xe3, 0xab, 0x79, 0xa0, 0x9c, 0xc5, 0x86, 0x9a, 0x93, 0x34, 0xe4, +0x6c, 0x35, 0xd4, 0x54, 0xde, 0x90, 0xb3, 0xd2, 0x50, 0x73, 0x92, 0x86, 0xc4, 0x7e, 0x43, 0xc3, +0x83, 0x25, 0x7a, 0x1b, 0x6a, 0x4e, 0xd2, 0x90, 0xf8, 0x6b, 0x6c, 0x4c, 0xac, 0xcb, 0xe6, 0xd5, +0xe5, 0xfe, 0xc5, 0xc5, 0xf1, 0xd9, 0x27, 0x02, 0x7f, 0x69, 0x94, 0x40, 0x89, 0xda, 0xc6, 0xe6, +0xc2, 0x55, 0x25, 0xd6, 0x1b, 0x6a, 0xac, 0x37, 0x24, 0xd6, 0x1b, 0x33, 0x58, 0x9f, 0x12, 0x9f, +0x33, 0xb2, 0xd4, 0xa3, 0xce, 0x4d, 0x17, 0x36, 0xfb, 0x37, 0x68, 0x6c, 0x1d, 0x50, 0xb5, 0x3c, +0xc5, 0x49, 0xf1, 0x82, 0x7b, 0xc2, 0xcb, 0x68, 0x37, 0x81, 0x08, 0x47, 0x53, 0x66, 0x5a, 0xeb, +0xb7, 0x61, 0xef, 0x9d, 0x90, 0x08, 0xdb, 0x2b, 0x57, 0x01, 0x7e, 0xb5, 0x58, 0x6f, 0x81, 0xf8, +0x6c, 0x14, 0x37, 0x8b, 0x5b, 0x2d, 0x00, 0x06, 0x9f, 0xad, 0xd2, 0x5f, 0xcb, 0x53, 0xb5, 0xee, +0x5d, 0xdf, 0x09, 0xee, 0x4b, 0xa0, 0x26, 0x04, 0x96, 0x03, 0x55, 0x3b, 0x7d, 0x9f, 0x99, 0x88, +0xcd, 0x02, 0xf9, 0x7d, 0xa6, 0x4b, 0x9d, 0x20, 0x32, 0xdd, 0x04, 0x7d, 0x64, 0x1c, 0xf1, 0x70, +0x4a, 0x09, 0x76, 0xf2, 0x47, 0x1e, 0xc5, 0xcf, 0xf8, 0xc3, 0xf0, 0x00, 0x2d, 0x1d, 0xf8, 0x52, +0x84, 0x39, 0x75, 0xaa, 0x5e, 0x50, 0x41, 0xc3, 0x3f, 0x6e, 0x52, 0xb2, 0x1c, 0xe7, 0x68, 0x00, +0xf5, 0x4f, 0xdc, 0x38, 0xc1, 0xf0, 0x10, 0xa6, 0xc1, 0x2c, 0xa7, 0x46, 0x31, 0xbb, 0x2f, 0xf2, +0x0f, 0x46, 0xc8, 0x2b, 0x31, 0x13, 0x0b, 0x02, 0x28, 0x25, 0xc1, 0xed, 0xad, 0x07, 0xed, 0x0b, +0x9c, 0x15, 0xde, 0x6b, 0x2b, 0xe2, 0x54, 0x89, 0x23, 0x7b, 0x18, 0x37, 0x03, 0xe3, 0xd3, 0x07, +0x39, 0x9a, 0x26, 0xf4, 0xdb, 0xf5, 0x6f, 0xf5, 0xd5, 0x45, 0xd5, 0x12, 0x7f, 0xbc, 0xca, 0x11, +0x27, 0xf3, 0xbb, 0xc4, 0xd4, 0x64, 0xec, 0xee, 0x12, 0xa3, 0xed, 0x05, 0x30, 0xb0, 0x02, 0xf9, +0x1b, 0x31, 0xfc, 0xc0, 0xa7, 0x06, 0xd9, 0x96, 0x69, 0xea, 0x76, 0x7e, 0x28, 0xba, 0xff, 0x63, +0xf6, 0x40, 0x4e, 0x31, 0x19, 0x1f, 0x86, 0xc7, 0x8e, 0x39, 0x7a, 0x47, 0xa5, 0xa0, 0xc0, 0xb2, +0x38, 0x9e, 0xca, 0x81, 0x66, 0xc4, 0x14, 0x33, 0x7f, 0xa3, 0x6e, 0x98, 0x36, 0xf6, 0x5b, 0x9f, +0x46, 0x43, 0x1e, 0x53, 0x28, 0x88, 0xf6, 0x3d, 0xcf, 0x34, 0x58, 0x99, 0x6b, 0x66, 0x84, 0x59, +0xe3, 0xc7, 0xa5, 0x6b, 0x2d, 0xdd, 0x0c, 0x60, 0xa4, 0x44, 0x93, 0x01, 0x66, 0xe6, 0x16, 0xf8, +0x67, 0x47, 0xb4, 0x51, 0xe2, 0x31, 0xb6, 0x20, 0xe9, 0xcd, 0x9b, 0xac, 0x89, 0x77, 0x3b, 0xa8, +0x3c, 0x63, 0x8d, 0x6b, 0xb7, 0x55, 0x62, 0xc6, 0xd8, 0x12, 0x7b, 0x2f, 0xeb, 0xbc, 0x63, 0x1a, +0x45, 0xc0, 0xf2, 0xeb, 0x5d, 0xb2, 0x5e, 0x2d, 0x64, 0xda, 0x5e, 0xa7, 0xea, 0x43, 0x57, 0xa6, +0x21, 0x46, 0x14, 0xa6, 0xcf, 0xa6, 0x08, 0x11, 0x96, 0x63, 0x49, 0x37, 0x9c, 0x1f, 0xaf, 0xe6, +0xcd, 0xdd, 0xd4, 0xbc, 0x69, 0xe7, 0x4c, 0x04, 0xc8, 0x29, 0x3c, 0x76, 0x5d, 0xb8, 0x83, 0xcf, +0x49, 0xcf, 0x63, 0x76, 0xeb, 0x12, 0x8b, 0x23, 0x69, 0xae, 0xfd, 0x6e, 0x50, 0xe6, 0x3e, 0xe0, +0x18, 0xdb, 0x49, 0xd4, 0xa7, 0x45, 0x03, 0xcf, 0x4a, 0x8c, 0x6d, 0x03, 0xc6, 0xc4, 0x9f, 0xab, +0xe2, 0xdf, 0x22, 0xac, 0x4c, 0x6c, 0x6c, 0x6f, 0xe2, 0x8f, 0x9b, 0x9e, 0xf5, 0xc0, 0x5c, 0x21, +0xb6, 0x81, 0x99, 0xa4, 0xff, 0x6b, 0xb1, 0x2c, 0x0e, 0xe0, 0x1a, 0x6b, 0x4d, 0xfc, 0x9f, 0xe7, +0x0e, 0xd1, 0x2a, 0x0d, 0xeb, 0x7f, 0xba, 0xea, 0x8f, 0xb5, 0xc2, 0x34, 0x52, 0x0a, 0x53, 0xec, +0x48, 0x0e, 0x8d, 0x58, 0xa1, 0x7b, 0xd0, 0xfe, 0xea, 0x76, 0x5c, 0x33, 0x68, 0x7f, 0x57, 0x8d, +0x93, 0xed, 0x5a, 0xc6, 0xe9, 0x71, 0x1a, 0x91, 0x69, 0x2c, 0x63, 0xc5, 0x94, 0xc5, 0xd4, 0x3b, +0xa4, 0x1e, 0x10, 0xed, 0x79, 0x98, 0x98, 0x54, 0x51, 0xc0, 0xed, 0x60, 0xbb, 0xd7, 0x86, 0x38, +0x83, 0x36, 0x5a, 0x6a, 0x3a, 0xa2, 0x25, 0x7c, 0x08, 0xc9, 0x77, 0x0e, 0xba, 0xae, 0xe7, 0xa0, +0xfb, 0xa9, 0x89, 0xc1, 0x8e, 0x81, 0x50, 0x58, 0x44, 0x63, 0xbc, 0xdc, 0x50, 0x2a, 0x01, 0xcd, +0xcc, 0x56, 0x06, 0x34, 0xd3, 0xc5, 0x20, 0x1e, 0x45, 0x51, 0x10, 0x01, 0xbf, 0x20, 0x6f, 0x08, +0xeb, 0x19, 0xc5, 0xdf, 0xd0, 0xaf, 0x6c, 0x32, 0x9b, 0xc4, 0xe7, 0x59, 0x12, 0x3e, 0x1a, 0x9d, +0x13, 0xd7, 0xfd, 0x9e, 0x82, 0x31, 0x17, 0x88, 0x2c, 0xfa, 0x7c, 0x75, 0x7a, 0x02, 0xad, 0x19, +0x68, 0x33, 0xc6, 0xbb, 0xf2, 0xf4, 0x81, 0xda, 0xfd, 0x84, 0x3a, 0x45, 0x3c, 0x7a, 0x21, 0x3e, +0xbd, 0xe7, 0x21, 0x08, 0x10, 0x7b, 0xef, 0x17, 0x41, 0xde, 0x04, 0x70, 0x0d, 0xca, 0x16, 0x43, +0x58, 0x6d, 0x65, 0x18, 0x43, 0x00, 0x78, 0x4b, 0x10, 0x60, 0xe0, 0x80, 0x0f, 0xe1, 0x93, 0xa3, +0x30, 0x89, 0x6f, 0xfc, 0xe0, 0xde, 0x68, 0x91, 0xbf, 0x92, 0x6a, 0xa5, 0x52, 0x51, 0x54, 0x9d, +0x1a, 0x28, 0xde, 0xe3, 0x04, 0x7d, 0x15, 0x63, 0xc4, 0xe2, 0x60, 0x93, 0xe0, 0x38, 0x0e, 0x10, +0x5c, 0x33, 0x89, 0x4c, 0x6c, 0xa1, 0x00, 0x89, 0x40, 0x43, 0x8e, 0xdb, 0xe9, 0xd0, 0x88, 0x42, +0x59, 0x5e, 0xce, 0x04, 0x86, 0xbe, 0x4e, 0x26, 0x9a, 0x64, 0x25, 0x7b, 0xb1, 0xb1, 0x00, 0x8e, +0xd0, 0xf9, 0xef, 0xe9, 0x38, 0x62, 0x2e, 0x84, 0x2b, 0x23, 0xab, 0xe7, 0x22, 0xa2, 0xf4, 0x92, +0xaf, 0x06, 0x37, 0xd3, 0xd3, 0xaf, 0xa1, 0x12, 0x68, 0x58, 0x94, 0x3a, 0x6f, 0x7f, 0x07, 0x79, +0xab, 0x2a, 0x07, 0x65, 0x4a, 0x76, 0xcf, 0x61, 0xe4, 0x40, 0x93, 0x1b, 0x5c, 0x3e, 0x86, 0xba, +0x14, 0x3a, 0xfd, 0xee, 0xf2, 0x18, 0xc3, 0xc7, 0x7e, 0xc2, 0x08, 0x04, 0xe7, 0x45, 0x74, 0xb4, +0xac, 0xa3, 0x39, 0x28, 0xb2, 0xff, 0xdd, 0x7a, 0x30, 0xd9, 0xb3, 0x7c, 0xfc, 0xcd, 0x42, 0xa0, +0x29, 0xb9, 0x4c, 0x80, 0x43, 0x31, 0x0f, 0x83, 0x22, 0xf3, 0xb5, 0x00, 0xe5, 0x07, 0xaf, 0x76, +0xb9, 0x9d, 0x21, 0xa3, 0x0c, 0x25, 0x07, 0x66, 0x0d, 0x06, 0xfd, 0xc4, 0x1c, 0x17, 0x67, 0xb2, +0x91, 0x35, 0xd6, 0x08, 0x13, 0xe7, 0x6b, 0xa3, 0x46, 0x6a, 0x85, 0x1f, 0x45, 0x52, 0x9b, 0xed, +0x9e, 0x16, 0xfd, 0xec, 0x49, 0x00, 0x0d, 0xee, 0x17, 0x45, 0x2a, 0xc0, 0xba, 0xc1, 0xe7, 0xf2, +0x8c, 0x85, 0x50, 0x83, 0x22, 0x6c, 0x25, 0xb8, 0x61, 0xad, 0x94, 0xa5, 0x90, 0x03, 0x24, 0x79, +0xa0, 0x27, 0xc8, 0xc7, 0x04, 0x10, 0x4f, 0x1b, 0x0b, 0xe0, 0x29, 0xbd, 0x07, 0xbe, 0x24, 0x5c, +0x01, 0xbc, 0x1b, 0x1f, 0xb8, 0xde, 0x9f, 0x83, 0x8a, 0x54, 0x9e, 0xd2, 0xcb, 0x41, 0x94, 0x23, +0xc1, 0xde, 0xd8, 0x9d, 0xdb, 0xc5, 0xb0, 0x85, 0x0c, 0x73, 0x11, 0x74, 0xe9, 0x46, 0xc7, 0xfd, +0x53, 0x14, 0xc3, 0xd1, 0xf2, 0x6c, 0xe6, 0x57, 0x54, 0x28, 0xf1, 0xfd, 0x83, 0x8e, 0x65, 0x65, +0x72, 0x7d, 0xe9, 0x29, 0xad, 0x94, 0x6c, 0x42, 0xe3, 0x66, 0x0a, 0x10, 0x08, 0x2b, 0x13, 0x3d, +0x28, 0x4c, 0xe1, 0xd8, 0x83, 0xf1, 0xac, 0x22, 0xe4, 0xe7, 0x79, 0x47, 0xe7, 0x50, 0xef, 0x78, +0xa0, 0x9d, 0x2d, 0xd7, 0x91, 0x3b, 0x3f, 0xd7, 0xc1, 0xf1, 0x70, 0x04, 0x9a, 0xb0, 0x37, 0x97, +0x89, 0x7c, 0x2f, 0xb2, 0x5e, 0x57, 0xf4, 0x54, 0x37, 0x3a, 0xd7, 0x29, 0x94, 0xb8, 0x03, 0x88, +0x99, 0xb3, 0x93, 0x3d, 0xef, 0xa0, 0x0d, 0xd5, 0x40, 0x40, 0xa3, 0x3b, 0x89, 0xdd, 0xbd, 0xdb, +0xed, 0x58, 0x20, 0x9d, 0x74, 0xbd, 0xb6, 0xdb, 0xd0, 0xeb, 0x9e, 0xdc, 0x6f, 0xc1, 0xe4, 0xff, +0x8e, 0x5b, 0x2e, 0x10, 0x51, 0xa9, 0xf3, 0x62, 0x11, 0x46, 0xb6, 0x4d, 0x10, 0x22, 0x2a, 0xea, +0xf8, 0x05, 0x14, 0x6f, 0x68, 0xc4, 0x2b, 0xb4, 0xa7, 0x96, 0xa9, 0x76, 0xbb, 0x24, 0xdd, 0x1e, +0x01, 0x4b, 0xb0, 0x71, 0x98, 0xad, 0x1e, 0x01, 0x45, 0x46, 0x3e, 0xeb, 0x8c, 0xe3, 0x0e, 0xb0, +0x2b, 0x6c, 0x27, 0x0e, 0x7d, 0x49, 0xbd, 0x79, 0xa1, 0xe5, 0x6b, 0x25, 0x78, 0x45, 0xa5, 0x29, +0xaf, 0xd0, 0x1f, 0x0c, 0x23, 0x85, 0xe2, 0x22, 0xd5, 0xc7, 0xdc, 0x3e, 0xa1, 0xba, 0xdd, 0x9e, +0x1d, 0x5a, 0x2b, 0xf7, 0xac, 0x1c, 0x99, 0x6c, 0x42, 0x94, 0x13, 0xb1, 0x82, 0x91, 0xcf, 0x78, +0x49, 0x3d, 0x66, 0xfc, 0xe3, 0xfe, 0x51, 0x3f, 0xb0, 0xef, 0x8f, 0x1e, 0x3f, 0x90, 0xf5, 0xc7, +0x88, 0x52, 0xa0, 0xe8, 0xcc, 0xe5, 0x53, 0x99, 0xa5, 0x0a, 0xe6, 0xbb, 0x0f, 0x04, 0x0d, 0x5b, +0x7a, 0xee, 0x69, 0xa1, 0xb5, 0xfe, 0x74, 0x4c, 0xbf, 0xef, 0x81, 0x36, 0x92, 0xc1, 0x2b, 0x5c, +0x7f, 0x80, 0xba, 0x17, 0xac, 0x2a, 0xfd, 0x56, 0x5e, 0x4c, 0x86, 0xeb, 0xa8, 0x37, 0xe7, 0xae, +0xf3, 0xe6, 0x8d, 0xca, 0x90, 0xa2, 0x01, 0x83, 0x5d, 0xca, 0x87, 0x22, 0xb1, 0xd7, 0xce, 0x50, +0x7e, 0x19, 0x8a, 0xc6, 0x30, 0xa9, 0x5c, 0x81, 0x12, 0x07, 0x30, 0x46, 0x0d, 0xa2, 0x80, 0xf3, +0x7f, 0x46, 0x3e, 0x2d, 0xad, 0x03, 0x45, 0xb6, 0x1e, 0x35, 0xb6, 0x08, 0x3e, 0x8c, 0x5c, 0x96, +0x23, 0xd6, 0xc5, 0x81, 0x60, 0x27, 0x82, 0x9a, 0x90, 0x75, 0x8c, 0xb0, 0x0e, 0x34, 0x84, 0xdd, +0x5b, 0x80, 0xff, 0x8d, 0x82, 0x16, 0x17, 0x26, 0xf6, 0xb2, 0xee, 0x40, 0x35, 0xfa, 0xc1, 0x44, +0x19, 0x20, 0x77, 0xd3, 0x48, 0x6f, 0xf2, 0xc9, 0x79, 0x57, 0x54, 0x63, 0xd2, 0x33, 0xed, 0xe4, +0x7b, 0xf5, 0xc8, 0x2c, 0xc7, 0x89, 0xa6, 0x59, 0xa5, 0x64, 0x88, 0xb8, 0xcf, 0x61, 0x17, 0xbd, +0x8b, 0x44, 0x2e, 0x1f, 0x76, 0xd1, 0xb1, 0x48, 0x04, 0x33, 0x15, 0xfe, 0xfe, 0x45, 0x24, 0xe1, +0x6d, 0x52, 0xad, 0x6f, 0xbd, 0x93, 0x7f, 0x8a, 0xdc, 0xf3, 0x6f, 0x9b, 0xef, 0x07, 0x84, 0x05, +0xa5, 0x35, 0x42, 0x94, 0x7e, 0x90, 0xa6, 0x66, 0x25, 0x33, 0xf6, 0x8f, 0x3d, 0xe2, 0xd7, 0x3c, +0x70, 0xbb, 0x7f, 0x00, 0x3b, 0x98, 0xbe, 0xef, 0xda, 0xec, 0xf1, 0x2f, 0x92, 0xa6, 0xf3, 0x2d, +0x88, 0xb0, 0xe6, 0xb4, 0xb4, 0xac, 0xe1, 0xc8, 0x34, 0xc4, 0x8b, 0x86, 0x67, 0x6c, 0x18, 0xc4, +0x04, 0xbe, 0xe0, 0xb8, 0xb7, 0x6e, 0x12, 0x17, 0xfe, 0x8a, 0x1a, 0x04, 0x8c, 0x7c, 0x76, 0x39, +0xa9, 0xfa, 0x7e, 0xbd, 0x76, 0x47, 0x87, 0xfd, 0x10, 0xd4, 0xa7, 0x35, 0x7e, 0x55, 0x72, 0xad, +0x55, 0x02, 0x05, 0xe0, 0xc8, 0xb2, 0xbb, 0x23, 0x95, 0x8b, 0x0e, 0x12, 0x1d, 0xe5, 0x62, 0x4b, +0xb3, 0xa6, 0x2c, 0xa8, 0x50, 0x24, 0x26, 0x30, 0xd6, 0xdd, 0xbd, 0x0c, 0x0b, 0x1f, 0xce, 0x21, +0x47, 0x2f, 0xcc, 0x22, 0x03, 0xc4, 0x6d, 0x72, 0xe3, 0x92, 0xba, 0x31, 0xc7, 0xc2, 0x8b, 0x71, +0x95, 0x95, 0x4c, 0x6a, 0xdc, 0xa6, 0xcd, 0x96, 0xc1, 0x6e, 0xe5, 0xbd, 0xbb, 0xb3, 0xf9, 0x7e, +0x8e, 0xd5, 0x71, 0x7c, 0x35, 0x02, 0x5f, 0x31, 0x4e, 0x03, 0xe7, 0xe2, 0x3e, 0x32, 0xde, 0xb8, +0x99, 0x4b, 0x52, 0x53, 0x13, 0x4d, 0xe5, 0x8f, 0xa9, 0xca, 0xc2, 0x10, 0x1e, 0x04, 0xb9, 0x9a, +0xfd, 0xf1, 0x6a, 0x1e, 0x44, 0xe6, 0x9d, 0xfd, 0x66, 0x6c, 0x30, 0x73, 0x61, 0x2a, 0x6b, 0xb2, +0xc1, 0x3c, 0xa2, 0x6a, 0x3a, 0x98, 0xb4, 0x6e, 0x86, 0xc9, 0xd7, 0xe4, 0xf4, 0x50, 0x42, 0x8f, +0xf4, 0xfd, 0xc4, 0xac, 0x14, 0x90, 0x6f, 0x56, 0xe7, 0x4d, 0x18, 0xd4, 0x9b, 0xaa, 0x58, 0x65, +0x15, 0xa1, 0xfa, 0xbf, 0xff, 0x4d, 0x94, 0x59, 0x55, 0x7d, 0x56, 0xbd, 0x30, 0xaf, 0x3d, 0x75, +0x9b, 0x75, 0x3d, 0x60, 0x9e, 0x55, 0xd3, 0x67, 0x35, 0x72, 0xb5, 0xc9, 0x10, 0x7c, 0xef, 0x26, +0xb0, 0x36, 0x27, 0x81, 0xd4, 0x72, 0x57, 0x67, 0x9c, 0x5d, 0xdc, 0x4b, 0xce, 0x5d, 0xc1, 0xb6, +0x62, 0x4a, 0x8c, 0x9a, 0xb1, 0x2d, 0x96, 0x5b, 0xf5, 0x3d, 0x69, 0x47, 0xd4, 0xba, 0x7b, 0xbf, +0x20, 0x84, 0x46, 0x0a, 0xa1, 0xf6, 0x48, 0x08, 0x9b, 0x29, 0x84, 0xc6, 0x23, 0x21, 0x6c, 0xa5, +0x10, 0x36, 0x17, 0x82, 0xf0, 0xe3, 0xd5, 0xd3, 0x4a, 0xfc, 0xc8, 0x58, 0xc1, 0x59, 0x0b, 0x02, +0xfb, 0xfa, 0x9a, 0x91, 0x72, 0xf6, 0x04, 0x4f, 0xf2, 0x39, 0xa8, 0x95, 0x87, 0xd3, 0x65, 0x70, +0x3b, 0xbe, 0x45, 0x79, 0xbf, 0x68, 0xf5, 0x94, 0xe5, 0x3d, 0xa6, 0xfe, 0x04, 0xdf, 0xcb, 0x03, +0xe0, 0x47, 0x2e, 0x96, 0xaa, 0x60, 0x80, 0x79, 0x80, 0x67, 0x71, 0xc1, 0xc7, 0xd5, 0x1f, 0x63, +0x85, 0xf3, 0x00, 0xfc, 0xd0, 0x1c, 0x18, 0x2a, 0xcf, 0xa1, 0x32, 0x34, 0x12, 0xa6, 0x2b, 0x60, +0xa7, 0x51, 0x2d, 0x00, 0x2d, 0x49, 0x28, 0x22, 0x62, 0x18, 0x4c, 0xdd, 0x60, 0x87, 0x3d, 0xad, +0x22, 0x41, 0x97, 0x9f, 0x6b, 0xae, 0x25, 0xb5, 0xb8, 0xb2, 0x53, 0x4c, 0x95, 0x26, 0xe3, 0xfa, +0xdb, 0xb7, 0xf5, 0x6f, 0x63, 0x71, 0x20, 0x4a, 0xdf, 0xbe, 0x95, 0xff, 0x22, 0xc3, 0x40, 0x40, +0xfe, 0xe4, 0x95, 0xff, 0x42, 0x41, 0xd5, 0x2b, 0x49, 0xa2, 0xdf, 0xf1, 0x84, 0x59, 0xbd, 0x75, +0xba, 0x1e, 0x4d, 0xd1, 0xf8, 0x11, 0x15, 0xfc, 0xc2, 0xf0, 0xf2, 0xa7, 0xfc, 0x01, 0x85, 0x0b, +0x7c, 0x40, 0x81, 0x98, 0x5f, 0xc3, 0x02, 0x64, 0xa0, 0xf7, 0xc1, 0x35, 0x74, 0x08, 0xba, 0xd1, +0x2a, 0xea, 0x61, 0x8a, 0x01, 0xa7, 0x87, 0x5b, 0x08, 0x91, 0x43, 0x13, 0x39, 0x38, 0x7a, 0x1c, +0xb3, 0x16, 0xc8, 0xd8, 0xe4, 0x4d, 0x1e, 0x82, 0xc1, 0x6f, 0x1e, 0x37, 0xf8, 0x2a, 0x48, 0xd8, +0x0b, 0xdf, 0x51, 0xc4, 0x5f, 0xb9, 0x21, 0xd7, 0x77, 0x5f, 0xbb, 0x2d, 0xc8, 0xdf, 0x12, 0x08, +0x64, 0xf1, 0x33, 0xb0, 0xa3, 0x2d, 0x5c, 0x98, 0xda, 0xb3, 0x58, 0x1b, 0xf5, 0x21, 0x33, 0xa2, +0xa5, 0x84, 0xc6, 0x89, 0x39, 0xa1, 0x85, 0x16, 0xd8, 0xe1, 0x32, 0x3b, 0x58, 0x66, 0x96, 0x1d, +0x43, 0x23, 0x4d, 0x5d, 0xbd, 0x52, 0x64, 0x45, 0xd1, 0xb1, 0x8f, 0x4e, 0x0b, 0x2d, 0xed, 0xc9, +0xad, 0x70, 0x02, 0xc0, 0x96, 0xbf, 0x5f, 0x57, 0x79, 0x6f, 0x75, 0x84, 0xca, 0xc0, 0x95, 0xc2, +0x7e, 0xdc, 0x35, 0x35, 0x5b, 0xd6, 0x3a, 0x81, 0x9d, 0xea, 0xbc, 0x63, 0x5a, 0x4e, 0x97, 0xdf, +0xaf, 0x2b, 0x2d, 0xd4, 0xf8, 0x81, 0x54, 0x41, 0x81, 0xfc, 0x7e, 0x5d, 0x07, 0x42, 0xbc, 0x6e, +0x15, 0xc9, 0x54, 0xa6, 0xa4, 0xca, 0xef, 0xd7, 0x8d, 0xd6, 0x2c, 0xed, 0x69, 0x9b, 0x2a, 0x64, +0xac, 0x37, 0x57, 0xb5, 0x85, 0xcc, 0xe0, 0xce, 0x73, 0x74, 0x7e, 0xcd, 0x0e, 0x7e, 0xe6, 0xc1, +0x48, 0x18, 0x8f, 0xed, 0x71, 0x73, 0x0e, 0x63, 0x13, 0x6c, 0xbb, 0x23, 0xc6, 0xaa, 0xb5, 0x2f, +0x3c, 0xc2, 0xce, 0xf0, 0xfd, 0xba, 0xa6, 0xdb, 0x4d, 0x2c, 0x64, 0x70, 0x98, 0xcb, 0xce, 0xd5, +0x83, 0xc6, 0x2e, 0x30, 0x42, 0xc9, 0x3e, 0xae, 0xd7, 0xe7, 0x6a, 0x8e, 0x85, 0x0a, 0xb9, 0x77, +0xc1, 0x0e, 0xf5, 0xa6, 0xb7, 0x8a, 0xb2, 0x7f, 0x78, 0x57, 0x17, 0xfe, 0x3b, 0xa4, 0xde, 0x68, +0x77, 0x28, 0x6e, 0x00, 0x4a, 0x43, 0xdb, 0x1b, 0xc3, 0x61, 0xb9, 0x62, 0x63, 0x68, 0xfc, 0x6a, +0x64, 0xec, 0x9b, 0xa9, 0x97, 0x71, 0xb6, 0xcf, 0x0c, 0x96, 0x59, 0x1b, 0x65, 0xce, 0xb1, 0xa1, +0x33, 0x34, 0xa1, 0xbc, 0x7c, 0x5e, 0x5b, 0xa8, 0x3b, 0xf8, 0xe4, 0x05, 0x6d, 0x9d, 0xb5, 0x22, +0xd5, 0x0f, 0x18, 0xf3, 0xbd, 0x9e, 0x78, 0x65, 0xa4, 0x88, 0x7b, 0x6d, 0xf1, 0x8d, 0x2b, 0x6e, +0xf4, 0xb2, 0x06, 0xe4, 0x88, 0x37, 0x3d, 0x78, 0x86, 0x08, 0x4a, 0x0e, 0xc9, 0xe2, 0xab, 0xa5, +0x99, 0x19, 0xb5, 0x03, 0x11, 0xf3, 0x1d, 0x72, 0x81, 0xb6, 0x0b, 0xf0, 0x5f, 0xea, 0x93, 0x81, +0x7c, 0xc6, 0x45, 0x3e, 0xf3, 0x7e, 0x4e, 0xaf, 0x0d, 0x0c, 0xac, 0xcf, 0x37, 0xcf, 0xec, 0x9d, +0x06, 0xf8, 0x4c, 0x5f, 0x21, 0xe0, 0x22, 0x02, 0x0b, 0x2c, 0xde, 0x23, 0x11, 0xb9, 0x1f, 0x84, +0x34, 0xeb, 0xd7, 0xc8, 0x2a, 0xca, 0x78, 0x6f, 0x04, 0x39, 0xb8, 0x2e, 0x5b, 0xb9, 0x6c, 0x24, +0x29, 0xcc, 0xb1, 0x28, 0xf7, 0x2a, 0xa8, 0x63, 0xd9, 0x39, 0x0f, 0x1b, 0xd9, 0x89, 0x5e, 0x73, +0x18, 0xe7, 0x9d, 0x61, 0x7e, 0xd9, 0x1e, 0x11, 0xc3, 0xbf, 0x6e, 0xa4, 0xa0, 0xbf, 0xe6, 0x2f, +0x05, 0xa3, 0x1b, 0x03, 0xfe, 0xcb, 0x52, 0xc4, 0xc3, 0xea, 0x90, 0x26, 0xbe, 0x56, 0x3c, 0xb1, +0x59, 0x98, 0x63, 0xef, 0xf5, 0xaa, 0x70, 0xc6, 0x32, 0x16, 0x04, 0xe6, 0x58, 0xd1, 0x1d, 0xbe, +0x68, 0xa0, 0x04, 0x88, 0x99, 0x37, 0x3d, 0xcc, 0x5d, 0x74, 0x72, 0x01, 0x90, 0xc3, 0x83, 0x1a, +0xa8, 0x67, 0x17, 0xf3, 0x6f, 0x44, 0x74, 0x01, 0x05, 0x6c, 0xcd, 0xf1, 0x49, 0x0a, 0x3f, 0x7d, +0x2d, 0x0e, 0x81, 0x2b, 0x8d, 0x8a, 0xaf, 0x59, 0x3b, 0x50, 0x04, 0xaf, 0xba, 0xea, 0x8f, 0xcd, +0xe5, 0x54, 0x18, 0x86, 0xc6, 0x41, 0x21, 0xeb, 0x1c, 0x67, 0xf4, 0xea, 0x9b, 0xe6, 0x14, 0xc8, +0x42, 0x3d, 0x02, 0xe4, 0xaf, 0x43, 0xf1, 0x50, 0xc2, 0x38, 0x41, 0x97, 0x3c, 0xf8, 0xf7, 0x2b, +0x6d, 0x0b, 0x85, 0x05, 0x7e, 0xc8, 0x6b, 0xf9, 0xf8, 0xfd, 0x25, 0x64, 0x61, 0x93, 0x31, 0x95, +0x05, 0x66, 0x56, 0xa1, 0x86, 0x9d, 0x2e, 0x79, 0x1a, 0x05, 0x65, 0x44, 0xe3, 0xa9, 0x57, 0xd9, +0x66, 0xa6, 0x27, 0x19, 0xd3, 0xa7, 0xba, 0x77, 0xa8, 0x50, 0x71, 0x4d, 0x6a, 0x34, 0xa6, 0x16, +0xf9, 0x85, 0x98, 0x55, 0xb2, 0xb3, 0x43, 0xdc, 0x02, 0xdb, 0x84, 0xa7, 0x3f, 0xd4, 0x9a, 0x00, +0xf0, 0x75, 0xa1, 0xe6, 0x1c, 0xb4, 0x39, 0x6e, 0xf8, 0x4b, 0xac, 0x4c, 0x25, 0xb1, 0xae, 0xdd, +0x16, 0x3b, 0xdb, 0x51, 0x98, 0xb1, 0x67, 0x75, 0x79, 0x47, 0x32, 0xfb, 0x52, 0xa9, 0x44, 0xbd, +0xc2, 0x02, 0xeb, 0x9f, 0xbd, 0xb0, 0xe5, 0xda, 0x3a, 0x1e, 0xc0, 0xca, 0x9c, 0x59, 0x03, 0x96, +0xff, 0x5e, 0x9d, 0x7d, 0xd4, 0xbc, 0xc8, 0xca, 0xbe, 0x04, 0xa6, 0x20, 0xf2, 0x67, 0x0a, 0x30, +0x0f, 0xc1, 0x09, 0x87, 0x12, 0xc5, 0xe9, 0x00, 0xf7, 0x38, 0x05, 0xaa, 0x94, 0xf2, 0xc5, 0x34, +0x12, 0x10, 0x7e, 0x26, 0x6a, 0xeb, 0xd5, 0xfc, 0xc7, 0xb2, 0x9c, 0xdd, 0xb1, 0x17, 0x9e, 0x8f, +0xc3, 0xdc, 0x52, 0x2d, 0x14, 0x46, 0x5f, 0xf8, 0x12, 0xa2, 0x8c, 0xbf, 0x97, 0x0b, 0x29, 0x7c, +0xd2, 0x79, 0x1a, 0x7b, 0x29, 0x16, 0x39, 0x23, 0xfe, 0x3b, 0x4a, 0xab, 0x89, 0xb4, 0x9a, 0x4c, +0x93, 0x6f, 0x83, 0x42, 0xf2, 0xad, 0xf8, 0xd4, 0x31, 0x46, 0x69, 0xe8, 0x7f, 0x3d, 0xc6, 0xf7, +0xf4, 0x0a, 0xcd, 0x12, 0xd8, 0x68, 0x26, 0xe2, 0x8e, 0x07, 0x3a, 0x94, 0xa5, 0x97, 0x63, 0xd9, +0x3c, 0xe2, 0x0e, 0xcb, 0xef, 0xf7, 0x6e, 0xd2, 0x48, 0x4c, 0x46, 0xbe, 0x55, 0x87, 0x87, 0xdc, +0x69, 0xa8, 0xbb, 0x71, 0x8f, 0x4e, 0x8d, 0xb6, 0x2c, 0x0f, 0x52, 0xd2, 0x4a, 0xb0, 0x5e, 0x94, +0x6a, 0x50, 0xaa, 0xc3, 0x2c, 0x30, 0xd8, 0x2c, 0x17, 0xa5, 0x69, 0x0a, 0x91, 0xf4, 0xd1, 0x66, +0x41, 0x67, 0xf9, 0x3c, 0xb3, 0xa0, 0xa8, 0x90, 0xc6, 0x42, 0x3b, 0xb0, 0x94, 0x34, 0x36, 0x28, +0x6e, 0xf6, 0xe4, 0x37, 0xcb, 0x61, 0x71, 0x32, 0x21, 0xb5, 0x1f, 0xa7, 0xb5, 0xb9, 0xdc, 0x64, +0x42, 0x13, 0x7f, 0xf3, 0x00, 0x8a, 0xb8, 0x4b, 0x61, 0x1f, 0x2c, 0x4d, 0xad, 0x6a, 0x3d, 0x42, +0x53, 0xc1, 0x38, 0x70, 0xa0, 0xa7, 0x2c, 0x83, 0x44, 0x32, 0xbc, 0x05, 0xa7, 0x91, 0x26, 0x1f, +0x15, 0x41, 0xf5, 0x00, 0xff, 0x65, 0x63, 0x92, 0x2f, 0x6d, 0x4c, 0x20, 0x2e, 0x7d, 0x5d, 0xe2, +0x89, 0x03, 0x5d, 0xca, 0x08, 0x9b, 0x7d, 0x5f, 0x37, 0xc2, 0x4c, 0xe1, 0xce, 0x23, 0xb3, 0xcf, +0x34, 0x6f, 0x78, 0x56, 0xb2, 0xb0, 0xa2, 0xc0, 0x03, 0x9a, 0x2b, 0x60, 0x41, 0xea, 0xe2, 0xb0, +0xc6, 0xe3, 0x5c, 0x2b, 0x15, 0x1a, 0x37, 0x66, 0xe1, 0xb6, 0xed, 0x40, 0x29, 0x5b, 0xf9, 0x1d, +0x82, 0x98, 0x89, 0xd7, 0x39, 0x2d, 0xb1, 0x80, 0xe3, 0x6a, 0xed, 0x63, 0x96, 0x1d, 0xec, 0x92, +0xcd, 0x4a, 0xa6, 0x18, 0x8e, 0x71, 0x53, 0x34, 0xe5, 0xf8, 0x8a, 0xbb, 0x7c, 0xb4, 0x45, 0x61, +0x84, 0x2d, 0x7c, 0xf4, 0x04, 0x48, 0xc6, 0x74, 0x99, 0x1c, 0x66, 0x43, 0x09, 0xb0, 0x03, 0x2d, +0x52, 0x06, 0xd0, 0x85, 0x42, 0xa1, 0x30, 0xef, 0x80, 0x37, 0x93, 0x10, 0x78, 0x6c, 0x2d, 0x84, +0xcb, 0x77, 0x78, 0x45, 0x12, 0x33, 0xfd, 0xe3, 0x51, 0x3e, 0x8d, 0x21, 0x03, 0xa6, 0x52, 0x89, +0xe4, 0xf5, 0xca, 0xeb, 0x35, 0x8f, 0x3a, 0x15, 0x3c, 0x53, 0x83, 0x94, 0x13, 0xf1, 0xb9, 0x9f, +0x10, 0x8f, 0x5a, 0x80, 0xfe, 0xc0, 0x1f, 0x05, 0xbe, 0x63, 0x21, 0x46, 0xa3, 0xc0, 0xe9, 0xdb, +0xa0, 0x22, 0xad, 0xe1, 0x0a, 0xc2, 0xaa, 0xd5, 0x51, 0x55, 0xf6, 0x79, 0xfa, 0xdb, 0xd5, 0x15, +0xce, 0x9d, 0xcf, 0x5e, 0xf0, 0x5d, 0xd3, 0x6d, 0x94, 0x42, 0x5c, 0xad, 0xd8, 0x07, 0xdd, 0x2c, +0xd0, 0x27, 0xd8, 0x2c, 0x32, 0xfc, 0x1d, 0x1e, 0x61, 0x8f, 0x08, 0x7f, 0x96, 0x3d, 0x02, 0x08, +0xcf, 0x0c, 0x81, 0x6d, 0x00, 0x6d, 0x19, 0xa0, 0xf8, 0x60, 0x84, 0x07, 0x03, 0x69, 0x0c, 0xa9, +0x00, 0x6d, 0x69, 0xe3, 0x51, 0x1f, 0xb6, 0x79, 0x99, 0x7a, 0x6d, 0xbd, 0x59, 0x67, 0x85, 0x38, +0x91, 0x5c, 0x1b, 0x76, 0xd7, 0x0d, 0xd9, 0x36, 0x01, 0x2d, 0x70, 0xbc, 0x52, 0x7a, 0x9b, 0x76, +0x7b, 0x74, 0xfb, 0x9e, 0xdb, 0x53, 0x43, 0x58, 0x33, 0xad, 0x9f, 0x61, 0xe7, 0x58, 0x6c, 0x76, +0xc7, 0xd0, 0x49, 0x66, 0xa6, 0x96, 0x64, 0xce, 0xad, 0xaa, 0xaa, 0x72, 0x62, 0x11, 0x8c, 0x81, +0x51, 0x0a, 0xc3, 0xc0, 0xb3, 0x22, 0x37, 0x19, 0x1a, 0x19, 0x73, 0x3c, 0x1f, 0xea, 0x3b, 0x04, +0xf8, 0x6a, 0xde, 0xec, 0x8a, 0x85, 0xf2, 0x19, 0xd8, 0xde, 0x3e, 0xbb, 0x14, 0x84, 0xbe, 0x92, +0x93, 0x57, 0xb4, 0xf8, 0xc4, 0xac, 0x4d, 0xa5, 0xae, 0x65, 0xcc, 0x92, 0x3a, 0x47, 0x51, 0xa1, +0xb0, 0x80, 0xbc, 0x8d, 0x3a, 0x97, 0x96, 0xe3, 0x06, 0x9c, 0x0d, 0xc1, 0x5f, 0xc0, 0x95, 0x96, +0xc0, 0x8e, 0xa2, 0x4e, 0xad, 0xa1, 0xdb, 0x9f, 0x51, 0x9f, 0x5f, 0x79, 0x31, 0x0d, 0x3f, 0xea, +0xa4, 0x4e, 0x06, 0xdc, 0xb4, 0xcf, 0xff, 0x06, 0xe2, 0x6e, 0xa3, 0xe4, 0x9e, 0x28, 0x30, 0xf2, +0x34, 0x53, 0x79, 0xf0, 0xf9, 0xd3, 0x42, 0x87, 0x32, 0x49, 0x36, 0xdf, 0xd5, 0x8f, 0x98, 0xaf, +0x96, 0xca, 0x73, 0xe6, 0x7a, 0x98, 0xa5, 0xec, 0xc6, 0x38, 0xbb, 0xfc, 0x58, 0x6b, 0x48, 0x37, +0x8b, 0x7c, 0x44, 0xa9, 0xf7, 0x3a, 0xa3, 0x7e, 0x7e, 0xf2, 0x50, 0x1d, 0xce, 0x74, 0x94, 0xbc, +0x48, 0xcd, 0xb2, 0x47, 0x22, 0xc5, 0x8e, 0x85, 0x54, 0x38, 0x88, 0xb9, 0xa0, 0xb0, 0xa9, 0x4c, +0xa0, 0x3c, 0xc1, 0x8d, 0x7e, 0x13, 0x29, 0xc7, 0xf0, 0xa5, 0x92, 0x12, 0x3f, 0x98, 0x5b, 0xfc, +0xf2, 0x9b, 0xc2, 0xa4, 0xd8, 0xf6, 0xee, 0x44, 0x5a, 0x13, 0x3f, 0x59, 0x62, 0x2f, 0x88, 0x5d, +0x91, 0x78, 0x8a, 0x9f, 0x3c, 0xd1, 0x8d, 0x03, 0x99, 0x88, 0x9f, 0xca, 0x9e, 0xfe, 0xf1, 0x25, +0x1c, 0x68, 0x67, 0x49, 0xf0, 0x05, 0xba, 0x13, 0x1d, 0x58, 0x31, 0x35, 0x0b, 0x7f, 0x4e, 0x79, +0x07, 0x4c, 0xec, 0x0f, 0x20, 0xf2, 0x96, 0xc2, 0x58, 0x54, 0xd3, 0x6c, 0xf0, 0xc3, 0xc8, 0x13, +0x3a, 0x00, 0x64, 0x2d, 0xce, 0x58, 0x16, 0x98, 0x5d, 0x9c, 0x59, 0xc6, 0xec, 0x59, 0x8b, 0xc6, +0x3c, 0x52, 0x65, 0x87, 0x96, 0x78, 0x0b, 0xf9, 0xf4, 0xf8, 0x0c, 0x0f, 0x13, 0xf1, 0xca, 0x0c, +0x60, 0x8a, 0x3a, 0x05, 0xdd, 0x39, 0xe9, 0x44, 0x4d, 0xbc, 0x9c, 0x7c, 0x72, 0xfe, 0x35, 0x57, +0x59, 0xbc, 0x40, 0xfe, 0xf9, 0xf8, 0xd3, 0xe7, 0x5c, 0x85, 0xf1, 0x36, 0xf9, 0xe9, 0xfe, 0xaf, +0xc4, 0xa4, 0x0f, 0xb0, 0x32, 0x5c, 0x94, 0x63, 0x96, 0x37, 0x1d, 0xc1, 0x64, 0x86, 0x46, 0xc4, +0x51, 0x75, 0x88, 0x43, 0xbf, 0xf1, 0x18, 0xb2, 0x97, 0x22, 0xbd, 0x33, 0x37, 0x93, 0x19, 0xb2, +0xfc, 0xa0, 0x97, 0x8c, 0xc9, 0xf2, 0x27, 0xcb, 0x70, 0xbb, 0x97, 0xcc, 0x17, 0xe1, 0x50, 0x28, +0x5b, 0x84, 0x8f, 0x17, 0xf8, 0xf3, 0x89, 0xf0, 0x83, 0xd3, 0xab, 0x5a, 0xbd, 0x52, 0xd9, 0x7f, +0x1e, 0x29, 0xae, 0x17, 0x96, 0x63, 0x72, 0x0f, 0xa8, 0x62, 0x24, 0xfa, 0x62, 0x20, 0x0f, 0x29, +0x0f, 0xf1, 0x93, 0x0b, 0xd2, 0xb8, 0x9d, 0x8a, 0xd6, 0x36, 0x4f, 0xea, 0x8c, 0xd2, 0x3e, 0xda, +0x32, 0xf1, 0x36, 0x74, 0x83, 0xba, 0x48, 0xfd, 0xc4, 0xbe, 0xff, 0x14, 0x9b, 0xbe, 0xe7, 0x16, +0x89, 0x4f, 0x93, 0x77, 0x85, 0x67, 0xdc, 0xe0, 0x4d, 0xfe, 0xca, 0x34, 0x7a, 0xb1, 0x93, 0x97, +0xbc, 0x96, 0xbd, 0x98, 0x46, 0x47, 0x3e, 0x3b, 0x0a, 0xec, 0x06, 0xf7, 0x37, 0x1e, 0x6c, 0x8b, +0x6e, 0x58, 0x68, 0x60, 0x7e, 0x4c, 0x48, 0xa3, 0xc3, 0xf6, 0x2d, 0x3f, 0x41, 0x6c, 0xf7, 0x6f, +0x9f, 0x64, 0xc7, 0x9b, 0x64, 0x38, 0x8f, 0x38, 0x15, 0x84, 0xce, 0x70, 0xcb, 0xe2, 0xac, 0x2d, +0x6d, 0x64, 0x68, 0x5c, 0xc0, 0x38, 0x28, 0x1e, 0x5b, 0xc8, 0xc7, 0xc1, 0xa7, 0xce, 0xa1, 0xd3, +0x67, 0x04, 0x8a, 0x64, 0x32, 0x60, 0xfe, 0x23, 0x10, 0xa4, 0xc2, 0x4e, 0x4b, 0xe3, 0xf1, 0x9e, +0x29, 0x44, 0xd2, 0xa0, 0xf0, 0x0a, 0x62, 0x2a, 0x97, 0xff, 0x7e, 0x74, 0x74, 0xc1, 0xae, 0x3d, +0x91, 0x20, 0x72, 0x40, 0x63, 0x79, 0xfd, 0xfa, 0xb5, 0xb2, 0x89, 0xb1, 0x5d, 0x00, 0x46, 0xae, +0x40, 0x1e, 0xc4, 0x83, 0xe1, 0x4b, 0xbe, 0x86, 0xe4, 0x91, 0xa6, 0xb2, 0x1f, 0x82, 0xb3, 0x8d, +0x8a, 0x8a, 0x5d, 0x83, 0x63, 0x8f, 0xca, 0xd9, 0x3c, 0x29, 0xa2, 0x31, 0x4d, 0xd2, 0xd4, 0x28, +0x4e, 0x94, 0x7c, 0x4d, 0xc9, 0x6d, 0xf9, 0xe1, 0xdb, 0xf5, 0x5a, 0xbb, 0x1f, 0x0f, 0x53, 0x08, +0x6d, 0xf8, 0x56, 0x9d, 0x23, 0x3c, 0x07, 0xab, 0x1c, 0xb9, 0xf1, 0xdc, 0xe0, 0xa1, 0x20, 0xb2, +0x9c, 0xff, 0xdf, 0x50, 0x3c, 0xca, 0x80, 0x56, 0xfd, 0x39, 0xfc, 0x55, 0xb1, 0x4a, 0xc8, 0x1d, +0xa5, 0x21, 0x91, 0x41, 0x5d, 0x70, 0x8c, 0x31, 0xb9, 0x8d, 0x82, 0x7e, 0x48, 0x1d, 0xf5, 0x7d, +0xd0, 0x30, 0xe1, 0xab, 0xa5, 0xc2, 0x7c, 0x51, 0x7c, 0xee, 0x5f, 0x81, 0x0a, 0x71, 0xf3, 0x73, +0xb5, 0x5a, 0xd9, 0x24, 0xd5, 0x52, 0xfd, 0x9b, 0x41, 0xaa, 0xb5, 0xad, 0x5f, 0x37, 0x1b, 0x2c, +0x0f, 0xa3, 0x21, 0x35, 0x9b, 0x87, 0xd5, 0x3a, 0x64, 0x56, 0x4a, 0x9b, 0x9b, 0x90, 0xbb, 0xd9, +0xf8, 0xb5, 0xb1, 0x45, 0xcc, 0xaf, 0x14, 0x76, 0xcb, 0xfc, 0x95, 0x8f, 0x66, 0x17, 0x1d, 0x0a, +0x0b, 0xac, 0x42, 0x63, 0xa2, 0xc2, 0xbb, 0xaa, 0x00, 0x57, 0xe7, 0x67, 0x94, 0xd5, 0xc9, 0xdc, +0xcd, 0xc9, 0xc6, 0x36, 0xd3, 0xdc, 0x77, 0xa4, 0x56, 0x6a, 0xd4, 0x26, 0x73, 0xeb, 0xac, 0xcf, +0x77, 0xae, 0xb5, 0x51, 0xc5, 0x28, 0x74, 0x79, 0x16, 0x22, 0x8e, 0x57, 0x2c, 0x44, 0x16, 0xc1, +0x8e, 0x5e, 0x58, 0x21, 0x9e, 0x83, 0xe5, 0x59, 0x82, 0xcc, 0xdd, 0x40, 0x3c, 0x54, 0x03, 0x38, +0x63, 0xfb, 0x19, 0xb6, 0x88, 0x01, 0xcd, 0xe8, 0x8b, 0x0a, 0xa0, 0x8b, 0xe9, 0x29, 0x06, 0x4f, +0x6d, 0x2d, 0x72, 0x2f, 0x29, 0x7d, 0x04, 0xa7, 0xf0, 0xfc, 0xbb, 0x42, 0xde, 0x8f, 0x27, 0x6e, +0x07, 0x53, 0x6c, 0x3d, 0x45, 0x51, 0x95, 0x30, 0x66, 0x7d, 0xd2, 0xe4, 0x85, 0x9f, 0x39, 0x37, +0x75, 0xd0, 0xcd, 0xf4, 0x50, 0x88, 0x16, 0x93, 0xaf, 0xd2, 0x34, 0xb6, 0x00, 0x2d, 0xf1, 0x60, +0xcf, 0x5c, 0x1c, 0x17, 0x72, 0x7a, 0x27, 0x4f, 0x2c, 0x9a, 0xca, 0x2f, 0x0e, 0xbd, 0x7d, 0x9f, +0x2e, 0x9b, 0xea, 0x96, 0x4c, 0xc8, 0x43, 0x8e, 0xd3, 0x24, 0x09, 0x00, 0xde, 0xc9, 0xfa, 0x1a, +0x2f, 0x8e, 0xb1, 0xe2, 0x48, 0xff, 0xb5, 0xb7, 0x19, 0xe5, 0x17, 0xa3, 0x3d, 0x7c, 0x4e, 0xe9, +0x05, 0x90, 0x1e, 0x74, 0x83, 0x5d, 0x2a, 0x7b, 0x3a, 0xf9, 0x8d, 0x56, 0x68, 0x14, 0x24, 0x8a, +0x15, 0x8a, 0xa9, 0xad, 0xc2, 0x93, 0x6c, 0xa1, 0x99, 0x9e, 0x5b, 0xe9, 0x1b, 0x3c, 0xb3, 0x1a, +0xdf, 0x28, 0x4f, 0x41, 0x26, 0x0a, 0x8a, 0x45, 0xcf, 0x03, 0xc9, 0x55, 0x16, 0xb8, 0x38, 0x3f, +0x05, 0x25, 0x5d, 0x8f, 0x8a, 0xa5, 0x02, 0xb2, 0x83, 0x05, 0x4a, 0xa7, 0xa8, 0x61, 0x90, 0x9e, +0x15, 0xb2, 0x10, 0x58, 0xd4, 0xb2, 0xbb, 0x13, 0xe2, 0xa4, 0xa4, 0xaa, 0x78, 0x8c, 0x2f, 0xe3, +0x20, 0xd9, 0xc4, 0x18, 0x93, 0xb0, 0xe3, 0x3e, 0x30, 0x18, 0x56, 0x14, 0x41, 0x25, 0x33, 0xa6, +0x34, 0x55, 0xcc, 0x0a, 0xaa, 0xda, 0x2f, 0x45, 0x6b, 0xe3, 0x87, 0xcb, 0x68, 0xd4, 0x85, 0xc1, +0xf3, 0x20, 0x09, 0xf0, 0x65, 0x6a, 0x1c, 0xfd, 0x61, 0xed, 0x4f, 0x04, 0x8f, 0x82, 0x86, 0xca, +0x65, 0x8c, 0x9a, 0xf6, 0x4a, 0x67, 0x8f, 0x82, 0xff, 0xaa, 0x93, 0xc5, 0x85, 0xe0, 0xbb, 0xe1, +0x32, 0xed, 0x95, 0xce, 0x38, 0xa5, 0xa8, 0xc8, 0x84, 0x73, 0x66, 0xbd, 0xba, 0xa8, 0x27, 0xea, +0xf2, 0x7a, 0x17, 0x07, 0x87, 0x5b, 0x1b, 0x8d, 0xc6, 0xcd, 0x16, 0x93, 0xd8, 0xd0, 0x5d, 0x21, +0x3c, 0xd5, 0x20, 0x1a, 0xf3, 0xfa, 0x5c, 0xaf, 0xa9, 0x2b, 0x6e, 0xcc, 0xa9, 0xf8, 0xa0, 0xeb, +0xf4, 0xa6, 0xbe, 0xe2, 0xbb, 0xcc, 0x8a, 0x28, 0xcc, 0xd3, 0xe1, 0xc2, 0xff, 0x5a, 0x2d, 0xa8, +0xc8, 0x85, 0xfb, 0xab, 0x1c, 0x4b, 0x5b, 0xe1, 0x20, 0xc4, 0x54, 0xf6, 0x1c, 0xa1, 0xde, 0xd2, +0x0b, 0x0f, 0xfa, 0x03, 0x2e, 0xa9, 0x50, 0x03, 0x44, 0xd8, 0x1a, 0x81, 0x76, 0x58, 0x18, 0x05, +0x04, 0x7c, 0xaf, 0xf3, 0xc5, 0xe2, 0x74, 0x88, 0xc0, 0xcc, 0x74, 0xd9, 0xa2, 0xcf, 0x51, 0xc6, +0x55, 0x06, 0xdb, 0x93, 0x81, 0x1d, 0xd8, 0xab, 0x2e, 0xf9, 0x63, 0xc1, 0x71, 0xef, 0x40, 0xed, +0xc1, 0x8a, 0x80, 0x0d, 0x02, 0x78, 0x51, 0xc0, 0xf9, 0x5c, 0x1c, 0xb8, 0x77, 0xdd, 0x22, 0x21, +0x3e, 0x98, 0x17, 0x66, 0x61, 0x22, 0x10, 0xd2, 0x44, 0x50, 0x29, 0x33, 0x8d, 0x58, 0x64, 0xbe, +0x79, 0x93, 0xc0, 0x7e, 0x49, 0x44, 0xaa, 0x2a, 0x2c, 0xe2, 0x95, 0x65, 0x46, 0x41, 0xa0, 0xbc, +0x37, 0x3c, 0xe6, 0x29, 0xa7, 0x2b, 0x92, 0x7a, 0x23, 0x4a, 0x7f, 0x47, 0x2c, 0x78, 0x6d, 0xdc, +0xf2, 0x5f, 0x5a, 0xe1, 0x9e, 0xba, 0x48, 0xf3, 0xe2, 0xb1, 0x70, 0x32, 0xcd, 0x2c, 0x2d, 0x3d, +0x0c, 0x45, 0x15, 0xf6, 0xf3, 0xc6, 0x0d, 0xb3, 0x6b, 0x31, 0x8f, 0x33, 0x5e, 0x83, 0x79, 0x64, +0x65, 0x16, 0x46, 0x47, 0x2b, 0x5e, 0x16, 0x63, 0xe6, 0x64, 0xf7, 0xa6, 0xef, 0xcb, 0x8e, 0xf4, +0xfd, 0xec, 0xa2, 0xc2, 0xa7, 0x85, 0x97, 0x16, 0x3e, 0x29, 0xb0, 0xde, 0x27, 0x47, 0x7e, 0x3d, +0x7a, 0xee, 0x63, 0x26, 0x2f, 0xb3, 0xcb, 0xf2, 0xac, 0x9a, 0x57, 0x89, 0xf0, 0x1b, 0xd2, 0x46, +0x40, 0x96, 0xd8, 0xa0, 0xbe, 0x17, 0xa9, 0x95, 0x7d, 0xac, 0x17, 0x90, 0xb6, 0xe2, 0x56, 0x85, +0x01, 0x4d, 0x40, 0x91, 0x17, 0xaf, 0x32, 0x90, 0x25, 0x2d, 0x49, 0xbc, 0x86, 0x90, 0xf6, 0x4b, +0xe9, 0xe4, 0x64, 0x7c, 0x20, 0xe9, 0x34, 0x54, 0xc6, 0x50, 0x50, 0x86, 0x54, 0xc3, 0x07, 0x8f, +0x76, 0x8d, 0x1a, 0x8f, 0x28, 0xa5, 0x5d, 0xac, 0xec, 0x92, 0xfe, 0x52, 0xe2, 0x30, 0xc6, 0xea, +0xe8, 0x18, 0x62, 0x65, 0x48, 0x28, 0x2d, 0x21, 0x34, 0xc8, 0x9e, 0xfe, 0xce, 0x6b, 0xac, 0x0b, +0xa2, 0x18, 0xa2, 0x87, 0x15, 0x25, 0xfc, 0x79, 0x46, 0x22, 0x60, 0x1a, 0x85, 0x42, 0xc6, 0x4d, +0xb7, 0x91, 0xc4, 0xd2, 0x74, 0x64, 0x6e, 0xa0, 0xd2, 0xd9, 0xde, 0x4c, 0x43, 0x42, 0xa9, 0x95, +0xde, 0xb5, 0xc8, 0xc8, 0x64, 0xde, 0x70, 0x26, 0xca, 0x3a, 0x65, 0xa1, 0x08, 0x4a, 0x89, 0x42, +0xce, 0x87, 0x5e, 0x41, 0x3b, 0xae, 0x1f, 0x9a, 0x73, 0xff, 0xc5, 0x70, 0xe9, 0x07, 0x12, 0x81, +0x80, 0xa8, 0xbe, 0x9f, 0x3f, 0x26, 0x13, 0x60, 0x1f, 0xa8, 0xca, 0x5c, 0x3a, 0x31, 0x65, 0x18, +0x40, 0x47, 0x46, 0x62, 0xc4, 0xa3, 0xf6, 0xce, 0xc4, 0x7a, 0x15, 0x65, 0x4e, 0x2c, 0x76, 0xab, +0x73, 0x6e, 0x4c, 0x88, 0x62, 0x99, 0x63, 0x56, 0xc7, 0xef, 0x62, 0xeb, 0x72, 0x6c, 0x00, 0x3b, +0x65, 0xfe, 0x52, 0x91, 0x7c, 0xe2, 0xa8, 0x1d, 0x38, 0x43, 0x7c, 0xe3, 0xa8, 0x9b, 0xf4, 0xbc, +0xbd, 0x57, 0xff, 0x0b, 0x36, 0xc8, 0xe1, 0x4b, 0x9c, 0xc3, 0x00, 0x00}; +#endif /*__SETUP_HTML_H__*/ diff --git a/src/web/html/h/style_css.h b/src/web/html/h/style_css.h new file mode 100644 index 00000000..3bff2337 --- /dev/null +++ b/src/web/html/h/style_css.h @@ -0,0 +1,188 @@ +#ifndef __STYLE_CSS_H__ +#define __STYLE_CSS_H__ +#define style_css_len 2914 +const uint8_t style_css[] PROGMEM = { +0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0x9d, 0x1a, 0x69, 0x8f, 0xdb, 0xb8, +0xf5, 0xaf, 0x68, 0xd7, 0x58, 0x20, 0x13, 0x58, 0x5a, 0x5b, 0xb6, 0xc6, 0x87, 0xd0, 0xa2, 0x45, +0x8b, 0x7c, 0x6b, 0xd1, 0xaf, 0x45, 0x11, 0x2c, 0x28, 0x89, 0x1e, 0x73, 0xa3, 0x0b, 0x12, 0xed, +0x19, 0xef, 0xc0, 0xff, 0xbd, 0xef, 0xf1, 0x12, 0x29, 0xd1, 0x9a, 0x64, 0x27, 0x81, 0x25, 0xf3, +0xf1, 0x78, 0xf7, 0x45, 0x9f, 0x79, 0x55, 0x2e, 0x83, 0xac, 0x29, 0x6e, 0xc1, 0xfb, 0xa9, 0xa9, +0x79, 0x78, 0x22, 0x15, 0x2b, 0x6f, 0xc7, 0xbf, 0x77, 0x8c, 0x94, 0x69, 0x45, 0xba, 0x17, 0x56, +0x1f, 0x57, 0x69, 0x4b, 0x8a, 0x82, 0xd5, 0x2f, 0xf0, 0x76, 0xa6, 0xec, 0xe5, 0xcc, 0x8f, 0xeb, +0xd5, 0xea, 0x97, 0xb4, 0x62, 0x75, 0x68, 0x7f, 0xcf, 0x48, 0xfe, 0xed, 0xa5, 0x6b, 0x2e, 0x75, +0x11, 0xe6, 0x4d, 0xd9, 0x74, 0xc7, 0x2b, 0xe9, 0x3e, 0x85, 0x61, 0xf6, 0xf2, 0x94, 0xda, 0xdf, +0x4f, 0xf0, 0xfd, 0x7e, 0x8e, 0x83, 0x77, 0xb5, 0x6b, 0x58, 0xd2, 0x13, 0xee, 0xd0, 0xbe, 0xa5, +0xf7, 0xbe, 0x25, 0xf5, 0x32, 0x28, 0xd9, 0x32, 0x38, 0x6f, 0xe0, 0x49, 0x32, 0x0a, 0xe8, 0x9d, +0x18, 0x2d, 0x8b, 0x9e, 0xf2, 0xe0, 0x7d, 0xb2, 0x8d, 0x06, 0x2d, 0x03, 0x56, 0xb7, 0x17, 0xfe, +0x3f, 0x7e, 0x6b, 0xe9, 0x5f, 0xfa, 0x4b, 0x56, 0x31, 0xfe, 0x75, 0x19, 0x44, 0x19, 0xaf, 0x83, +0xf7, 0xac, 0xe9, 0x0a, 0xda, 0x85, 0x1d, 0x29, 0xd8, 0xa5, 0x3f, 0x6e, 0xf1, 0x18, 0x6b, 0xf2, +0x89, 0x95, 0xf4, 0x6b, 0xf0, 0xfe, 0xca, 0x0a, 0x7e, 0x96, 0x64, 0xdc, 0x39, 0x7d, 0xe3, 0xa4, +0xa3, 0x64, 0x7a, 0xde, 0x0c, 0x85, 0xf7, 0x45, 0xc9, 0xae, 0x34, 0x40, 0x02, 0xc6, 0xeb, 0x62, +0x80, 0x46, 0xbc, 0x69, 0x6b, 0x72, 0x05, 0x6c, 0xfc, 0x5b, 0x00, 0x4c, 0x6c, 0xd3, 0x36, 0x3d, +0xe3, 0xac, 0xa9, 0x8f, 0x27, 0xf6, 0x46, 0x8b, 0x14, 0x56, 0x01, 0xd3, 0x6d, 0xe4, 0xf4, 0x46, +0xc4, 0x73, 0x8a, 0x16, 0xd3, 0x1a, 0x88, 0x0c, 0xf0, 0x23, 0x45, 0x52, 0xc2, 0x82, 0xe6, 0x4d, +0x47, 0xc4, 0xae, 0x75, 0x53, 0xd3, 0x54, 0x08, 0xba, 0x67, 0x7f, 0xd0, 0xe3, 0x7a, 0x07, 0x73, +0x0a, 0xd6, 0xb7, 0x25, 0xb9, 0x1d, 0xb3, 0xb2, 0xc9, 0xbf, 0x01, 0x1d, 0xe3, 0x03, 0x16, 0xa7, +0xd3, 0xc9, 0x3a, 0x37, 0x62, 0x79, 0x03, 0x24, 0x4a, 0xcc, 0x84, 0xe8, 0x56, 0x16, 0x5f, 0x46, +0xe4, 0xb8, 0x7b, 0x1b, 0xe2, 0x48, 0xd6, 0x37, 0xe5, 0x85, 0x53, 0x6b, 0xdb, 0xe3, 0xb9, 0xb9, +0xd2, 0xee, 0x21, 0x7f, 0xda, 0x8e, 0x81, 0x36, 0xde, 0x42, 0x31, 0xeb, 0x29, 0xf8, 0x89, 0x55, +0x6d, 0xd3, 0x71, 0x52, 0xf3, 0x61, 0x8b, 0x88, 0xd5, 0xa7, 0xc6, 0xc7, 0x95, 0xc9, 0xa9, 0x9d, +0xd0, 0xd9, 0x58, 0x30, 0x08, 0xc8, 0x48, 0x50, 0x25, 0xcc, 0x2e, 0x55, 0x93, 0x81, 0x4a, 0x04, +0xef, 0x1a, 0x75, 0xc1, 0xb2, 0x7b, 0x7f, 0x7d, 0x51, 0x84, 0xc3, 0xf9, 0x9c, 0xe5, 0xa4, 0x0c, +0x49, 0xc9, 0x5e, 0xea, 0x63, 0xc5, 0x8a, 0xa2, 0xa4, 0x86, 0x50, 0x56, 0x97, 0xac, 0xa6, 0xa1, +0xa4, 0x57, 0xda, 0x4f, 0x88, 0x67, 0x84, 0xdb, 0x37, 0x23, 0x1e, 0x38, 0x2f, 0x00, 0xc6, 0x07, +0xf8, 0x14, 0x5a, 0x2f, 0x76, 0x0e, 0x25, 0xfa, 0xa0, 0x8f, 0xa5, 0xc2, 0x1e, 0x07, 0x9e, 0x34, +0xf4, 0x95, 0x74, 0xb5, 0x03, 0xc5, 0x01, 0x03, 0xed, 0x2f, 0x79, 0x4e, 0xfb, 0xde, 0x99, 0xa0, +0xc6, 0x70, 0xce, 0x2b, 0x3b, 0x31, 0x07, 0xa6, 0x95, 0x92, 0x71, 0x24, 0x75, 0x9e, 0xe7, 0xda, +0x7a, 0x51, 0x0f, 0x6c, 0xc6, 0x1b, 0x6d, 0x4b, 0x94, 0xb6, 0x05, 0xeb, 0x67, 0xf8, 0xd8, 0x03, +0x49, 0xd6, 0x34, 0x4b, 0x3c, 0xc8, 0x3e, 0x69, 0x1f, 0xae, 0x5a, 0x48, 0xf5, 0xde, 0x20, 0x2b, +0x94, 0x3b, 0xd9, 0xc0, 0xab, 0x62, 0x5e, 0xd6, 0x70, 0xde, 0x54, 0x42, 0x46, 0x46, 0x90, 0x1d, +0x2d, 0x41, 0x9d, 0xaf, 0xd4, 0xd6, 0x3b, 0xa1, 0xa5, 0xae, 0xa9, 0xc7, 0x8e, 0x5c, 0x49, 0x8e, +0x4b, 0x66, 0x0d, 0x50, 0x4e, 0x79, 0x92, 0x6e, 0x28, 0xea, 0x69, 0x4b, 0xc1, 0x6c, 0x9a, 0xce, +0xf1, 0x0e, 0xda, 0xe1, 0x19, 0x0c, 0x8f, 0x4a, 0x8c, 0x28, 0xce, 0xa9, 0x83, 0x58, 0x6c, 0x0f, +0xf8, 0x6f, 0x62, 0x64, 0xc0, 0x0b, 0x4e, 0x6b, 0x70, 0x69, 0x15, 0x79, 0x0b, 0xd5, 0xf6, 0xeb, +0xed, 0x4a, 0x61, 0xcc, 0x41, 0xbd, 0xce, 0x0f, 0x51, 0x55, 0x70, 0x4a, 0x8a, 0x50, 0x08, 0x70, +0xec, 0x5e, 0x95, 0xbf, 0xc1, 0x49, 0xd9, 0xcb, 0x07, 0xbb, 0x4c, 0x9d, 0xb3, 0x58, 0xcd, 0xae, +0x33, 0xe7, 0x23, 0x70, 0xfe, 0x70, 0x76, 0x9d, 0x3b, 0x59, 0xaf, 0x9f, 0x39, 0x3b, 0x04, 0x7e, +0xcd, 0xad, 0x07, 0xf0, 0x47, 0xc7, 0x7f, 0xc7, 0x16, 0xde, 0xc5, 0xf9, 0x79, 0x86, 0x74, 0x04, +0xce, 0x93, 0x0e, 0x33, 0x66, 0x48, 0xd7, 0xeb, 0x1f, 0x90, 0xce, 0xfb, 0x39, 0xb1, 0xf7, 0x62, +0xed, 0xa3, 0x85, 0x73, 0xa2, 0xee, 0x1f, 0x1d, 0x78, 0xee, 0x4c, 0x7c, 0x44, 0x2f, 0x05, 0x5a, +0x1d, 0x80, 0x8f, 0x64, 0x45, 0xe0, 0x95, 0xb4, 0x52, 0xf8, 0x75, 0x47, 0xab, 0x60, 0x15, 0xe0, +0x23, 0xbd, 0xb7, 0x10, 0x0a, 0x30, 0xc8, 0x48, 0x6f, 0xf8, 0xfb, 0xa5, 0xe7, 0xec, 0x74, 0xb3, +0x43, 0xcc, 0xa6, 0xe5, 0xd3, 0xf0, 0xbf, 0x38, 0x35, 0x0d, 0x9f, 0x71, 0xf7, 0x12, 0x2c, 0x03, +0x6b, 0xd4, 0x35, 0xaf, 0x83, 0xcb, 0x38, 0x95, 0x14, 0x2d, 0xcf, 0x18, 0x0d, 0xda, 0x24, 0x8e, +0x85, 0xaf, 0x1d, 0x69, 0x8f, 0xf8, 0x81, 0x42, 0x68, 0x4a, 0x70, 0x77, 0x30, 0x7a, 0x5c, 0x03, +0xa2, 0x22, 0x6c, 0xc2, 0x50, 0xb8, 0x86, 0x94, 0x00, 0x9f, 0xb1, 0x7a, 0x6e, 0xd4, 0x73, 0xbb, +0x14, 0x8f, 0x44, 0x7d, 0x7d, 0x56, 0xcf, 0x9d, 0x7a, 0xee, 0x25, 0xf8, 0xa0, 0xbe, 0xae, 0x57, +0xfa, 0x45, 0xef, 0xb7, 0x8e, 0xd5, 0x69, 0x70, 0x56, 0x40, 0x2e, 0xbc, 0xd1, 0xe7, 0x69, 0xcf, +0xb1, 0x8f, 0x36, 0xfa, 0x4f, 0xe3, 0x12, 0x1b, 0xaf, 0xf2, 0x1c, 0x3d, 0xcb, 0xbf, 0x9d, 0x86, +0x6d, 0x34, 0x2c, 0x4e, 0xf4, 0xd0, 0x56, 0x0f, 0x6d, 0x36, 0xd1, 0x78, 0xab, 0x44, 0xc3, 0xb6, +0xeb, 0xc9, 0x56, 0xcf, 0x1a, 0x96, 0x18, 0x2e, 0xec, 0xcc, 0xd0, 0x7e, 0xb2, 0xd5, 0x5e, 0xc3, +0x9e, 0xa7, 0x58, 0x1d, 0x34, 0x6c, 0x67, 0xb0, 0x5a, 0xaf, 0x0c, 0x85, 0x53, 0xb4, 0xd6, 0x86, +0xfc, 0xc3, 0x14, 0xaf, 0x75, 0xec, 0xe6, 0x5c, 0x51, 0x8b, 0xdc, 0x32, 0x79, 0x66, 0x14, 0x27, +0x42, 0xbb, 0x60, 0x38, 0xb6, 0x87, 0xcd, 0xe8, 0x66, 0x18, 0x5d, 0xeb, 0xb1, 0xad, 0x35, 0x36, +0xcc, 0x4c, 0x86, 0xd1, 0x8d, 0x1a, 0x7b, 0x73, 0xce, 0x0a, 0xd4, 0x69, 0x81, 0x79, 0x93, 0x73, +0x62, 0x77, 0x8e, 0x99, 0x32, 0xcc, 0xd8, 0xd8, 0x33, 0x1c, 0xab, 0x40, 0xe8, 0xd6, 0x81, 0xea, +0xf5, 0x6b, 0x6b, 0x7d, 0x62, 0xcf, 0xd8, 0x48, 0xb8, 0xc6, 0xf1, 0xe6, 0xe1, 0x87, 0x8b, 0xe1, +0x6d, 0xca, 0x1a, 0x07, 0xbf, 0xdb, 0x98, 0x49, 0x16, 0x76, 0xb7, 0x29, 0xb3, 0x1c, 0xdc, 0x6e, +0x63, 0xb6, 0x0d, 0x98, 0x55, 0xc8, 0x3d, 0x8c, 0x5b, 0xb2, 0x36, 0xf0, 0x72, 0xaf, 0x42, 0xee, +0x39, 0x73, 0xc6, 0xd8, 0x55, 0xc8, 0x3d, 0x6b, 0x86, 0x8b, 0x5f, 0x85, 0xdc, 0xb3, 0xa1, 0x13, +0x0c, 0x2b, 0xe4, 0x9e, 0x35, 0x63, 0x84, 0xe3, 0xcd, 0xc1, 0xd1, 0x87, 0xe1, 0xcd, 0xc1, 0x70, +0x8a, 0xdf, 0xcd, 0xc6, 0x6f, 0x84, 0xdd, 0xcd, 0xc6, 0xce, 0x83, 0xdb, 0xcd, 0xc6, 0x6d, 0x84, +0x19, 0xb7, 0x30, 0x13, 0x3e, 0x57, 0x63, 0x27, 0x60, 0xf1, 0x18, 0x36, 0x80, 0x36, 0x2e, 0x68, +0x6d, 0x00, 0xdb, 0x11, 0xc0, 0x5a, 0x93, 0xb8, 0xa0, 0x8d, 0x02, 0x64, 0x36, 0x0e, 0x2a, 0xc1, +0xb2, 0xd0, 0xc8, 0x6c, 0x34, 0x0c, 0x78, 0x80, 0x6e, 0x26, 0xd0, 0xb5, 0x81, 0x6d, 0xa7, 0x30, +0x6b, 0x65, 0x32, 0x81, 0x2a, 0x94, 0x4e, 0x3d, 0xaa, 0xfb, 0x10, 0x35, 0x36, 0x9a, 0x97, 0x00, +0x88, 0x1d, 0x80, 0x19, 0xde, 0xd8, 0xc3, 0xb1, 0x35, 0x7f, 0xeb, 0x00, 0xcc, 0x70, 0x62, 0x0f, +0xaf, 0xa3, 0xdd, 0xb0, 0xe0, 0xd9, 0x85, 0x0c, 0x80, 0x9d, 0x0b, 0x88, 0x07, 0xc8, 0xde, 0x81, +0x98, 0xe1, 0x83, 0x3d, 0xbc, 0xb2, 0xcf, 0x40, 0x4f, 0x69, 0x83, 0x14, 0x84, 0x84, 0x9d, 0x13, +0x3f, 0x45, 0x65, 0x22, 0xc6, 0x73, 0x67, 0x3c, 0x87, 0x5c, 0x91, 0x76, 0x00, 0x28, 0x42, 0xac, +0x47, 0xdc, 0xea, 0xc4, 0xad, 0x86, 0x0a, 0x59, 0x7c, 0x8c, 0x92, 0x6c, 0x77, 0x0e, 0x46, 0xd4, +0xbf, 0x06, 0x9f, 0x47, 0x25, 0xb8, 0xc2, 0x4a, 0x8f, 0xc9, 0x2a, 0x49, 0xa3, 0xfa, 0x79, 0x19, +0x1c, 0x8f, 0xe4, 0x04, 0x58, 0xe0, 0x4b, 0x46, 0x4f, 0x4d, 0x87, 0xc9, 0x74, 0xf3, 0x86, 0x14, +0xa1, 0x97, 0x50, 0x69, 0x04, 0x8c, 0xa4, 0xf7, 0x5f, 0x3f, 0x07, 0x7d, 0x15, 0x7c, 0xfe, 0xf5, +0x6f, 0x15, 0x2d, 0x18, 0xf9, 0x84, 0x8d, 0x02, 0x15, 0x3a, 0x9e, 0xf7, 0xed, 0xdb, 0x53, 0xf0, +0x2e, 0x62, 0x40, 0x5f, 0xcd, 0x46, 0x48, 0x00, 0xcf, 0x05, 0x49, 0x00, 0x7b, 0xe2, 0x24, 0x8c, +0xce, 0x85, 0x4a, 0x00, 0xcf, 0x45, 0x4b, 0x00, 0x7b, 0x02, 0x26, 0x8c, 0xce, 0xc5, 0x4c, 0x00, +0xcf, 0x85, 0x4d, 0x00, 0x7b, 0x22, 0x27, 0xd2, 0x3e, 0x17, 0x3c, 0x11, 0x3e, 0x17, 0x3f, 0x11, +0x3e, 0x0e, 0xa1, 0x60, 0x60, 0x82, 0xa5, 0xb3, 0xa6, 0x2d, 0xb8, 0x3a, 0x67, 0xdd, 0x82, 0xaf, +0x8f, 0x0d, 0x5c, 0x30, 0x78, 0xce, 0xc6, 0x05, 0x8b, 0x1f, 0x9b, 0xb9, 0x14, 0xba, 0xdf, 0xd2, +0xa5, 0xc4, 0x7d, 0xc6, 0x2e, 0x85, 0xed, 0xb7, 0x77, 0x29, 0x72, 0x9f, 0xc9, 0x4b, 0x69, 0x3f, +0xb0, 0x7a, 0x29, 0x6b, 0xbf, 0xe1, 0x4b, 0x89, 0x3f, 0xb0, 0x7d, 0x29, 0xef, 0x89, 0xf9, 0x17, +0x08, 0xf8, 0xd8, 0xf4, 0xc4, 0xb4, 0x0f, 0x6c, 0x18, 0xed, 0xa7, 0x2a, 0x7c, 0xf6, 0x73, 0x38, +0xc4, 0x83, 0xfd, 0x54, 0xc5, 0xac, 0xfd, 0x00, 0x78, 0xce, 0x7e, 0x00, 0xec, 0xb1, 0x1f, 0x18, +0x9d, 0xb3, 0x1f, 0x00, 0xcf, 0xd9, 0x0f, 0x80, 0x3d, 0xf6, 0x03, 0xa3, 0x73, 0xf6, 0x03, 0xe0, +0x39, 0xfb, 0x01, 0xb0, 0xc7, 0x7e, 0x90, 0xf6, 0x39, 0xfb, 0x41, 0xf8, 0x9c, 0xfd, 0x20, 0x7c, +0x64, 0x3f, 0x77, 0x4e, 0x32, 0xd1, 0x0d, 0x91, 0x8e, 0x0c, 0x66, 0x95, 0xa4, 0xed, 0xe9, 0x51, +0xbf, 0x38, 0x6d, 0x38, 0x7e, 0x76, 0xfc, 0x33, 0xab, 0xcf, 0xb4, 0x63, 0xa2, 0x19, 0x25, 0x36, +0xe1, 0x05, 0x94, 0x06, 0xea, 0xf5, 0x3c, 0x64, 0x52, 0x4a, 0xff, 0x8c, 0xab, 0x94, 0xc6, 0x33, +0x2a, 0xba, 0xc4, 0xb2, 0x50, 0xce, 0xc1, 0x52, 0x09, 0x6b, 0x9a, 0x16, 0x6b, 0xa5, 0x71, 0xbf, +0xd5, 0xea, 0x22, 0x98, 0xd6, 0x12, 0x36, 0x22, 0x62, 0xfc, 0x58, 0xc7, 0xfa, 0x35, 0xc5, 0x96, +0xd9, 0xa9, 0x6c, 0x5e, 0x8f, 0xb2, 0x34, 0x31, 0xb5, 0x97, 0xde, 0x2b, 0x1e, 0x9a, 0x19, 0xb2, +0x57, 0x25, 0x47, 0xec, 0x02, 0xcb, 0x2e, 0xe7, 0xde, 0x86, 0x2d, 0x22, 0x11, 0x23, 0x4c, 0xa3, +0x30, 0xcb, 0x32, 0x5d, 0x23, 0x62, 0x27, 0x28, 0x4e, 0x74, 0x07, 0xd2, 0x09, 0x6e, 0x66, 0x31, +0x06, 0x1d, 0xdf, 0xda, 0x78, 0xa3, 0x3a, 0x2a, 0x2b, 0xbd, 0x89, 0x59, 0x73, 0x81, 0xba, 0xae, +0x64, 0x3d, 0x20, 0xc3, 0x6f, 0xc0, 0x24, 0xec, 0xe0, 0xca, 0x06, 0x9d, 0x5e, 0x8a, 0x4b, 0x04, +0x99, 0x43, 0xcb, 0xda, 0x5e, 0x8c, 0x9d, 0x65, 0xfd, 0x95, 0x78, 0xce, 0x36, 0x32, 0x41, 0xbe, +0x39, 0xc1, 0x11, 0xd1, 0x78, 0xc4, 0x06, 0xd3, 0xbc, 0x74, 0x1a, 0xa6, 0x67, 0x56, 0xcc, 0x19, +0xb9, 0xb4, 0xed, 0xa0, 0xa9, 0xcb, 0x5b, 0xd0, 0xe7, 0x1d, 0xa5, 0x75, 0x40, 0xea, 0x22, 0xf0, +0x19, 0xbb, 0xee, 0x1d, 0x2b, 0x63, 0xdd, 0xb8, 0x1d, 0x36, 0xa7, 0x27, 0x3f, 0xe9, 0xd3, 0x3e, +0x4e, 0x14, 0x86, 0x3e, 0xaf, 0xd3, 0x37, 0x16, 0x6d, 0xd1, 0xa1, 0x6d, 0xa6, 0x5a, 0x84, 0x0e, +0x2f, 0x70, 0x8a, 0xbf, 0x05, 0x3b, 0x6e, 0x9e, 0xaa, 0x76, 0xd7, 0xa8, 0x45, 0x8b, 0x4a, 0x86, +0x42, 0xb2, 0xf7, 0x90, 0xd9, 0xc6, 0x78, 0x54, 0x8b, 0x03, 0x71, 0x32, 0x47, 0xfb, 0x14, 0x5f, +0x36, 0x21, 0x93, 0x41, 0xf1, 0x93, 0x95, 0xa3, 0xa8, 0x52, 0xd7, 0x94, 0x90, 0xe5, 0x4e, 0xc9, +0x88, 0x8d, 0xf7, 0x7b, 0x1b, 0x95, 0x2c, 0x5f, 0x06, 0xe2, 0x81, 0x7c, 0x19, 0xe4, 0xbd, 0x37, +0x4d, 0x8c, 0xc5, 0xe1, 0x70, 0x40, 0x37, 0x4e, 0x7b, 0x27, 0xb5, 0x16, 0x86, 0x36, 0xd3, 0xf5, +0xe8, 0x29, 0xa0, 0x5c, 0x88, 0x6e, 0xea, 0x3d, 0xea, 0x7f, 0x93, 0x9d, 0x46, 0xf0, 0x11, 0xfd, +0x6f, 0xca, 0xbd, 0x30, 0x30, 0xfa, 0x1f, 0xea, 0x81, 0xa7, 0x8e, 0xb2, 0xe1, 0x3e, 0x8a, 0x25, +0x4e, 0xe3, 0xda, 0xd8, 0x3e, 0x68, 0x63, 0x41, 0x6b, 0x35, 0xd3, 0x9c, 0xf8, 0xbd, 0xbd, 0xdf, +0xd7, 0x33, 0xe3, 0x34, 0xcd, 0x2f, 0x5d, 0x0f, 0x5f, 0xda, 0x86, 0x89, 0x6c, 0xd4, 0xf0, 0x3e, +0x76, 0xbd, 0x85, 0x74, 0x5d, 0xf2, 0x7c, 0xcb, 0xfc, 0x91, 0xeb, 0x69, 0x73, 0xe1, 0xd8, 0x20, +0x9f, 0x5c, 0x44, 0x24, 0xde, 0x8e, 0x2f, 0x60, 0x7b, 0xc9, 0x04, 0xab, 0xad, 0xa9, 0xf1, 0x63, +0xd6, 0xda, 0xf2, 0xdd, 0xe9, 0xf5, 0x7f, 0x66, 0x0b, 0xd1, 0xc9, 0xd9, 0x09, 0x6d, 0xc2, 0x6d, +0xc8, 0x11, 0x90, 0xfe, 0xb6, 0x04, 0x43, 0xbf, 0xb2, 0x1e, 0x38, 0x51, 0x28, 0xe7, 0x3f, 0x73, +0xb3, 0x32, 0xa7, 0x00, 0xca, 0x5f, 0xe0, 0x7e, 0xa7, 0x26, 0xbf, 0xf4, 0x83, 0xe3, 0x58, 0x81, +0xbb, 0x22, 0xea, 0xda, 0xea, 0xbb, 0x9b, 0xf2, 0x46, 0x10, 0x3b, 0x6d, 0x03, 0xfa, 0xc5, 0x7f, +0x2d, 0x21, 0x4f, 0xf8, 0xf3, 0x17, 0x2e, 0xe2, 0xf6, 0x6c, 0x19, 0xf4, 0xb4, 0xa4, 0xb9, 0x65, +0x82, 0xbb, 0xa9, 0x05, 0xd8, 0x17, 0x6d, 0xc8, 0xb0, 0xaf, 0xce, 0x3d, 0x5d, 0x4b, 0xfa, 0xfe, +0x15, 0x74, 0xe5, 0xab, 0xde, 0xcb, 0x81, 0xd6, 0x97, 0x2a, 0xa3, 0x9d, 0x7b, 0x35, 0xe7, 0x2f, +0x37, 0x94, 0xbe, 0x0d, 0x71, 0x74, 0x91, 0xe7, 0x79, 0x3a, 0xbd, 0xf6, 0x7b, 0xd4, 0x0b, 0xc6, +0x33, 0xfd, 0xb7, 0x94, 0x02, 0x04, 0xcc, 0xbb, 0x12, 0xdc, 0x56, 0x65, 0x06, 0x78, 0xaf, 0xa0, +0x0f, 0x02, 0x81, 0x39, 0xee, 0xea, 0xd1, 0x09, 0x62, 0x03, 0x3c, 0x63, 0xca, 0xc8, 0xa8, 0x3f, +0x3b, 0xb7, 0x00, 0x63, 0xb7, 0xa4, 0x74, 0xba, 0x53, 0x3e, 0xde, 0x5c, 0x5f, 0xa2, 0x0c, 0xff, +0x49, 0x4b, 0x8f, 0x00, 0x17, 0xb9, 0x8b, 0xd5, 0x30, 0xff, 0x87, 0xb4, 0x4a, 0x51, 0x6b, 0x45, +0x42, 0xa1, 0x60, 0xc2, 0xbd, 0xea, 0x17, 0x5f, 0xd8, 0x14, 0x96, 0xc1, 0x3b, 0x52, 0xf7, 0x50, +0x23, 0x56, 0xc7, 0x0b, 0x26, 0x2f, 0x39, 0xe9, 0x27, 0xee, 0x63, 0x40, 0xeb, 0xa1, 0x2a, 0x2e, +0x56, 0xdb, 0x2d, 0xdd, 0x3f, 0xeb, 0xa9, 0x79, 0x36, 0x29, 0x3c, 0x12, 0x37, 0x75, 0x91, 0xfc, +0x11, 0xf7, 0xc6, 0x26, 0x5c, 0x82, 0xde, 0x78, 0xcd, 0x60, 0xe4, 0x0f, 0xdc, 0xb2, 0x77, 0x3d, +0x10, 0x27, 0xde, 0x4d, 0x3e, 0x22, 0x4e, 0x1c, 0xdd, 0x01, 0xc2, 0xc9, 0xe9, 0xbd, 0xc5, 0x7a, +0x58, 0xf8, 0xc9, 0xb0, 0x6f, 0x49, 0x4e, 0x8f, 0x30, 0x10, 0xaa, 0x7e, 0xb4, 0x8c, 0x3e, 0xe0, +0x87, 0x09, 0x97, 0x6e, 0xf0, 0xae, 0x33, 0x27, 0x39, 0xa6, 0xcb, 0x7e, 0x70, 0x55, 0x2f, 0x5d, +0xeb, 0xcc, 0x54, 0x44, 0x08, 0x66, 0xdf, 0x0b, 0x76, 0x8d, 0xfe, 0xd5, 0x14, 0xff, 0x79, 0x05, +0xdf, 0xa1, 0xde, 0xff, 0x4d, 0x2a, 0x2a, 0xbf, 0xfc, 0x17, 0xef, 0xc2, 0xff, 0x31, 0x5c, 0x57, +0xed, 0x1e, 0x11, 0x2e, 0xb6, 0x39, 0x5b, 0x09, 0x60, 0xab, 0x6d, 0x68, 0x74, 0x09, 0x20, 0xec, +0x68, 0xcc, 0x04, 0xc9, 0xe2, 0x45, 0x0d, 0x71, 0x75, 0xe8, 0x81, 0x69, 0xc0, 0xf0, 0x61, 0xf8, +0x69, 0xc4, 0x62, 0xa7, 0xcf, 0x8b, 0xb2, 0x81, 0x75, 0xa6, 0x92, 0x48, 0xac, 0xbb, 0xbf, 0x78, +0xb5, 0x6a, 0x1f, 0xda, 0xf4, 0x47, 0x16, 0x3c, 0xbd, 0xeb, 0x15, 0x17, 0xbc, 0x70, 0xa4, 0x4c, +0xe2, 0xf0, 0x57, 0x0b, 0x76, 0xa2, 0xfb, 0x6c, 0xe9, 0xb0, 0x98, 0x11, 0xc6, 0x32, 0xe1, 0xd4, +0x95, 0x97, 0xb1, 0xcb, 0x04, 0xd1, 0x7a, 0xc2, 0xe8, 0x7a, 0x8d, 0xf2, 0x73, 0x10, 0x5d, 0x6a, +0xc6, 0x25, 0xdf, 0xf3, 0x73, 0xc8, 0xae, 0x72, 0xc0, 0x09, 0x32, 0x7b, 0x2d, 0x31, 0x98, 0xae, +0x9d, 0xd8, 0x4e, 0x9c, 0xe7, 0xe4, 0xf1, 0x40, 0x21, 0xfc, 0x0d, 0xb2, 0x57, 0x33, 0xf7, 0x92, +0xcd, 0x8a, 0x4f, 0x0e, 0x8a, 0xc2, 0x45, 0x98, 0x5b, 0x53, 0x31, 0xef, 0xbe, 0xe8, 0x29, 0xfe, +0x64, 0xc3, 0xad, 0x68, 0x4c, 0x9a, 0x14, 0x69, 0xa8, 0x73, 0x71, 0x22, 0x6f, 0x1b, 0x8b, 0x86, +0x0f, 0x9a, 0x90, 0x0c, 0x72, 0xf2, 0x5f, 0x67, 0x62, 0x84, 0x72, 0x3d, 0x6b, 0xf2, 0x48, 0xcd, +0x6c, 0xb3, 0x94, 0xc1, 0x1c, 0xef, 0x92, 0x7e, 0xc8, 0x05, 0x41, 0xad, 0xd6, 0xf7, 0xb0, 0x43, +0x53, 0x72, 0xd6, 0xbe, 0x4f, 0xef, 0x7f, 0x1d, 0xb8, 0xf4, 0x22, 0xb2, 0x47, 0xf5, 0xae, 0x28, +0x3f, 0x12, 0xce, 0xbb, 0x4f, 0x05, 0xe1, 0x44, 0xcf, 0x7a, 0x72, 0x2e, 0x8d, 0x81, 0x09, 0xf6, +0xb5, 0xfc, 0x88, 0xb4, 0xcd, 0xa3, 0x08, 0xea, 0x51, 0x33, 0xe3, 0xef, 0xc4, 0x1b, 0xe0, 0x47, +0x3f, 0x85, 0xc0, 0x9a, 0x65, 0x88, 0xa2, 0xb0, 0xd2, 0x0a, 0x51, 0x9c, 0x28, 0x12, 0xbf, 0x7c, +0xf9, 0x92, 0x0e, 0xe9, 0xbe, 0xd0, 0x05, 0xfb, 0xbb, 0x10, 0xb3, 0xd0, 0xd3, 0x44, 0xa7, 0xbf, +0xc8, 0x6c, 0x5f, 0x5b, 0x70, 0xca, 0x06, 0xdd, 0xa1, 0x9b, 0xae, 0x57, 0xa6, 0x25, 0xcd, 0x4a, +0x60, 0xdb, 0x92, 0x0e, 0x36, 0x4a, 0x35, 0xcf, 0x7e, 0x0e, 0x7e, 0xd6, 0xc6, 0xa8, 0x7f, 0x7b, +0xb2, 0xf2, 0x90, 0xac, 0xfc, 0x78, 0x48, 0xaf, 0xb0, 0xa8, 0x97, 0x09, 0xd0, 0x50, 0x3b, 0x03, +0x7d, 0xdd, 0x4b, 0x46, 0x3e, 0xad, 0x96, 0x81, 0xfa, 0xff, 0x64, 0x39, 0x19, 0xe3, 0xdf, 0x07, +0x75, 0x52, 0x66, 0x36, 0xb6, 0x47, 0x51, 0x43, 0x7a, 0x98, 0xbb, 0x5a, 0xa2, 0x3d, 0x82, 0x8e, +0x57, 0x4d, 0xe1, 0x6a, 0xf6, 0x6e, 0x65, 0xfb, 0x6e, 0x59, 0x72, 0xeb, 0x5b, 0x39, 0x35, 0xd9, +0xfb, 0x2b, 0x1b, 0xd5, 0xef, 0xd4, 0xbf, 0x69, 0xf9, 0x03, 0xdc, 0x4a, 0x81, 0x37, 0x88, 0xab, +0x5d, 0x3c, 0xb9, 0xbe, 0x17, 0xfb, 0x84, 0xa6, 0x32, 0xf7, 0x04, 0x2e, 0x20, 0xac, 0x81, 0x30, +0xc0, 0xf8, 0x0d, 0xbb, 0x6b, 0xba, 0x90, 0x59, 0x69, 0x1c, 0x42, 0x93, 0xae, 0xbb, 0x2a, 0x17, +0x89, 0x9e, 0xd7, 0x54, 0xd3, 0x9d, 0xeb, 0x4f, 0x3b, 0x23, 0xf2, 0x1b, 0x93, 0x3c, 0x23, 0x1b, +0xfd, 0x64, 0xa9, 0x04, 0xed, 0xd0, 0x6e, 0xd9, 0x9b, 0x38, 0x29, 0x89, 0xe1, 0xbf, 0x28, 0x7e, +0x92, 0xf7, 0xaa, 0x05, 0xeb, 0x20, 0x35, 0x43, 0x64, 0xe0, 0x80, 0x4b, 0x55, 0x1b, 0x0a, 0xd0, +0x9a, 0x91, 0x78, 0x07, 0x35, 0xa1, 0x97, 0x21, 0x04, 0xc1, 0xaa, 0x17, 0x03, 0x50, 0xa8, 0x93, +0x8e, 0xa7, 0xea, 0x5e, 0x58, 0x53, 0x7d, 0x14, 0x11, 0x32, 0xcc, 0x28, 0x7f, 0x85, 0xba, 0x37, +0x75, 0x6e, 0xf2, 0x1e, 0x35, 0x47, 0x16, 0xf4, 0x40, 0x73, 0x7a, 0x1a, 0x1f, 0x1f, 0xe5, 0x65, +0xd3, 0x53, 0xfb, 0x22, 0x6c, 0x87, 0xbb, 0x28, 0xf1, 0x87, 0xa2, 0x71, 0x69, 0x7f, 0xda, 0x8a, +0x10, 0xca, 0x1f, 0xbe, 0x39, 0x77, 0x64, 0xe2, 0x23, 0xd6, 0x6f, 0x68, 0x5a, 0x72, 0xff, 0x51, +0x7f, 0xd1, 0x96, 0xad, 0xfd, 0xc3, 0x39, 0xdd, 0x08, 0x7a, 0x50, 0x2a, 0x81, 0xfc, 0xb3, 0x0b, +0x10, 0x56, 0xeb, 0x6d, 0x27, 0xf2, 0xb3, 0x0d, 0x52, 0x67, 0x60, 0xe9, 0xfd, 0x9c, 0xf8, 0xda, +0x91, 0xf6, 0x4d, 0x51, 0xea, 0xeb, 0xe8, 0x4a, 0xd4, 0x5e, 0xa5, 0x2d, 0x27, 0x58, 0x5c, 0x44, +0x0a, 0x23, 0x28, 0x39, 0x46, 0xd9, 0x58, 0x94, 0x91, 0xe2, 0x85, 0x0e, 0xbf, 0x24, 0xb2, 0x33, +0xc1, 0x89, 0x7a, 0xc7, 0x7b, 0xb2, 0xdb, 0x26, 0x66, 0x11, 0xfe, 0x16, 0x09, 0xc8, 0x33, 0x8b, +0xe2, 0x75, 0x9c, 0xc4, 0x07, 0x5f, 0xf8, 0x38, 0xe5, 0x60, 0x4f, 0x66, 0x1d, 0xed, 0xba, 0xa6, +0xfb, 0xe0, 0xa8, 0x22, 0xdf, 0x24, 0xc3, 0x51, 0x83, 0xba, 0xb9, 0x0e, 0x59, 0x37, 0xd8, 0xe2, +0x04, 0x24, 0x17, 0x6d, 0x35, 0xe9, 0xb2, 0x78, 0x4f, 0x7e, 0x71, 0x18, 0x01, 0x0e, 0x22, 0x15, +0x6b, 0x75, 0xd4, 0xf3, 0xb8, 0x54, 0x3b, 0x91, 0xab, 0x1b, 0x91, 0xc6, 0x8d, 0x92, 0xbe, 0x0c, +0x52, 0x5a, 0xdc, 0x65, 0x14, 0x33, 0x74, 0xa7, 0xf8, 0xff, 0xa9, 0x3b, 0x87, 0x2e, 0x5a, 0x29, +0x00, 0x00}; +#endif /*__STYLE_CSS_H__*/ diff --git a/src/web/html/h/system_html.h b/src/web/html/h/system_html.h new file mode 100644 index 00000000..1db39ad8 --- /dev/null +++ b/src/web/html/h/system_html.h @@ -0,0 +1,139 @@ +#ifndef __SYSTEM_HTML_H__ +#define __SYSTEM_HTML_H__ +#define system_html_len 2134 +const uint8_t system_html[] PROGMEM = { +0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0xd5, 0x59, 0x6d, 0x6f, 0xdb, 0x38, +0x12, 0xfe, 0xde, 0x5f, 0xc1, 0x6a, 0x81, 0xb3, 0x74, 0xb5, 0x25, 0x27, 0x7d, 0xdd, 0xc4, 0xce, +0x22, 0x4d, 0xb3, 0x6d, 0x80, 0x24, 0x5b, 0x24, 0x2e, 0xba, 0x8b, 0x20, 0x30, 0x68, 0x89, 0xb6, +0x98, 0x48, 0xa2, 0x4a, 0x52, 0x4e, 0xbc, 0xbb, 0xf9, 0xef, 0x37, 0x43, 0x49, 0xb6, 0x65, 0x4b, +0x8e, 0xdb, 0x6e, 0x71, 0x77, 0xfe, 0x22, 0x8b, 0x9c, 0x19, 0x3e, 0x33, 0x9c, 0x79, 0x38, 0x92, +0x7a, 0x4f, 0x03, 0xe1, 0xeb, 0x59, 0xca, 0x48, 0xa8, 0xe3, 0xe8, 0xe0, 0x49, 0x2f, 0xbf, 0x10, +0xf8, 0xf5, 0x42, 0x46, 0x83, 0xfc, 0xaf, 0xb9, 0xd5, 0x5c, 0x47, 0xec, 0xe0, 0x72, 0xa6, 0x34, +0x8b, 0x7b, 0x5e, 0x7e, 0xb7, 0x98, 0x8d, 0x78, 0x72, 0x4b, 0x24, 0x8b, 0xfa, 0x96, 0xd2, 0xb3, +0x88, 0xa9, 0x90, 0x31, 0x6d, 0x11, 0xb4, 0xdc, 0xb7, 0x34, 0xbb, 0xd7, 0x9e, 0xaf, 0x94, 0x45, +0x42, 0xc9, 0xc6, 0x85, 0x84, 0x0b, 0x03, 0xbf, 0x4c, 0xfb, 0x5d, 0xf7, 0x8d, 0xdb, 0xed, 0x76, +0x77, 0x2c, 0x0f, 0x16, 0x8f, 0x99, 0xa6, 0x24, 0xa1, 0x31, 0xe8, 0x4c, 0x39, 0xbb, 0x4b, 0x85, +0x04, 0x1b, 0xbe, 0x48, 0x34, 0x4b, 0x74, 0xdf, 0xba, 0xe3, 0x81, 0x0e, 0xfb, 0x01, 0x9b, 0x72, +0x9f, 0x75, 0xcc, 0x4d, 0x9b, 0xf0, 0x84, 0x6b, 0x4e, 0xa3, 0x8e, 0xf2, 0x69, 0xc4, 0xfa, 0x3b, +0x56, 0x69, 0xc4, 0x0f, 0xa9, 0x54, 0x0c, 0x94, 0x3e, 0x0d, 0x7e, 0xed, 0xbc, 0xc1, 0x61, 0xe5, +0x4b, 0x9e, 0xea, 0x65, 0x44, 0x37, 0x74, 0x4a, 0xf3, 0x51, 0x8b, 0x28, 0xe9, 0xf7, 0x2d, 0x9a, +0x72, 0xf7, 0xa6, 0x02, 0xea, 0xa0, 0xe7, 0xe5, 0x12, 0x60, 0xe0, 0x6b, 0x3c, 0xf4, 0x45, 0x24, +0xa4, 0x7a, 0xc4, 0x45, 0x29, 0x46, 0x42, 0xab, 0x25, 0x07, 0x13, 0xc1, 0x93, 0x80, 0xdd, 0xb7, +0x49, 0x22, 0xc6, 0x22, 0x8a, 0xc4, 0x9d, 0x45, 0xbc, 0x62, 0x2f, 0xbc, 0xc5, 0x66, 0xf4, 0x46, +0x22, 0x98, 0x2d, 0x45, 0x3e, 0xe0, 0x53, 0xe2, 0x47, 0x54, 0x29, 0x80, 0x21, 0xd2, 0x84, 0x4e, +0xad, 0x42, 0x8e, 0x16, 0x60, 0xbc, 0x65, 0x0c, 0x73, 0x51, 0xdc, 0x3f, 0xeb, 0xe0, 0x30, 0x14, +0xb3, 0x77, 0x83, 0x4f, 0x3d, 0x8f, 0xae, 0x28, 0x2d, 0x82, 0xb3, 0x37, 0x15, 0x3c, 0xb0, 0xbb, +0xce, 0xfe, 0x5c, 0x97, 0x03, 0x62, 0x8b, 0x88, 0xc4, 0x8f, 0xb8, 0x7f, 0x5b, 0xae, 0x6a, 0x3b, +0xd6, 0x12, 0x28, 0x95, 0xd2, 0x04, 0x83, 0x87, 0x97, 0xaf, 0x1e, 0x5d, 0xa0, 0x41, 0xdf, 0x78, +0x30, 0x77, 0xac, 0x04, 0x10, 0x8b, 0x11, 0x47, 0xf4, 0x0b, 0x1b, 0xd4, 0x88, 0x81, 0xcc, 0xf3, +0xb9, 0x50, 0xc8, 0x03, 0x56, 0xee, 0x87, 0x17, 0xf1, 0x29, 0xab, 0x6c, 0xec, 0x29, 0x0c, 0xcc, +0xd7, 0xa9, 0x9a, 0x78, 0x51, 0x6f, 0x42, 0x31, 0x09, 0x99, 0x56, 0x31, 0xf2, 0x99, 0x8d, 0xf2, +0xd1, 0x06, 0x4b, 0x2f, 0x9b, 0x2c, 0xe9, 0x2c, 0xad, 0x18, 0xba, 0x64, 0x5a, 0xf3, 0x64, 0xa2, +0xaa, 0x76, 0x30, 0x22, 0xa5, 0x01, 0xc5, 0x52, 0x26, 0xa9, 0x16, 0xd2, 0x5a, 0x0f, 0xe0, 0x7c, +0xbd, 0x57, 0xf5, 0xeb, 0x65, 0x69, 0x40, 0x75, 0xd5, 0xfd, 0x4f, 0x66, 0xa8, 0x01, 0xf6, 0xeb, +0x06, 0xd8, 0xa6, 0xf4, 0xab, 0xb8, 0x0b, 0x36, 0xf8, 0x2e, 0xd4, 0x6f, 0xe6, 0x2b, 0x40, 0x01, +0x42, 0x45, 0x51, 0x39, 0xc1, 0xca, 0x1d, 0x8e, 0x22, 0x9a, 0xdc, 0x5a, 0x07, 0x17, 0xc7, 0x97, +0x03, 0x72, 0xf8, 0xf1, 0xa4, 0x01, 0xec, 0xcf, 0xa5, 0x76, 0xa8, 0x75, 0xaa, 0xf6, 0x3c, 0x8f, +0x42, 0x4a, 0x07, 0x3a, 0x73, 0x11, 0xf9, 0xaa, 0xad, 0x77, 0xc2, 0xcf, 0x62, 0xa8, 0x35, 0xaa, +0xb9, 0x48, 0x1a, 0x0c, 0xee, 0x74, 0x17, 0x78, 0x46, 0x22, 0xd3, 0x15, 0x87, 0x0f, 0x71, 0xe4, +0x3b, 0xfd, 0xed, 0x36, 0xa4, 0xa8, 0x98, 0xf0, 0x04, 0x12, 0x13, 0x2f, 0x4d, 0xd0, 0x1a, 0x35, +0x01, 0x95, 0x51, 0x5d, 0x46, 0xd7, 0xf3, 0xa0, 0x7c, 0x56, 0x0a, 0xe9, 0x8e, 0x8f, 0x79, 0x5e, +0xbe, 0x65, 0x2d, 0x27, 0x63, 0x81, 0x60, 0x8d, 0xe8, 0x92, 0x46, 0x55, 0x4b, 0xd2, 0x14, 0x1c, +0x5b, 0x2a, 0xb8, 0xca, 0x74, 0x41, 0x60, 0x2b, 0xd3, 0x15, 0x11, 0xb3, 0x4c, 0xb9, 0x26, 0xb0, +0x63, 0x47, 0xc5, 0x9d, 0x9d, 0x5d, 0x82, 0xff, 0xe2, 0xa0, 0xf3, 0x8a, 0xc4, 0xba, 0xf3, 0x7c, +0x0e, 0xa3, 0xd1, 0x0a, 0x1e, 0x4e, 0x0b, 0x12, 0x00, 0x15, 0x12, 0x8f, 0x1a, 0xf4, 0x56, 0x5d, +0x69, 0xf0, 0x6c, 0x2c, 0x84, 0xae, 0x38, 0xb6, 0x4c, 0xa7, 0x11, 0x1b, 0xeb, 0x2a, 0xc9, 0x6c, +0x9f, 0x69, 0x05, 0xb1, 0x92, 0x7f, 0xf9, 0x22, 0x9d, 0x91, 0xdd, 0xee, 0xee, 0xf3, 0xea, 0x9e, +0x66, 0xd1, 0x0a, 0xde, 0x88, 0x1f, 0xac, 0x2d, 0x10, 0x70, 0xe5, 0x0b, 0x19, 0xb8, 0x93, 0x89, +0xf7, 0xf9, 0xcf, 0xf0, 0xfe, 0xf8, 0x8f, 0x57, 0xbb, 0xf1, 0xdb, 0x9a, 0xac, 0xce, 0xc5, 0x70, +0x81, 0x1e, 0x30, 0xdd, 0x16, 0x86, 0x27, 0x5c, 0x87, 0xd9, 0xc8, 0xf5, 0x45, 0xec, 0x45, 0x59, +0x4c, 0xd3, 0xcc, 0xf8, 0xb2, 0x6e, 0xf9, 0xbd, 0x91, 0x5b, 0x37, 0xdc, 0xf3, 0x4a, 0xfc, 0xab, +0x49, 0x56, 0x84, 0x4e, 0xf2, 0x49, 0x58, 0x89, 0x5d, 0x83, 0xbf, 0x2b, 0x0b, 0x6e, 0x05, 0xd3, +0x83, 0xfb, 0x98, 0x6b, 0xe5, 0x8d, 0xc6, 0xaf, 0x5f, 0xef, 0xbe, 0x7e, 0x09, 0x30, 0x4f, 0x06, +0xe4, 0xf2, 0xc3, 0xe1, 0x1e, 0x29, 0x46, 0xc8, 0xde, 0x1e, 0x29, 0x6b, 0xb6, 0x31, 0x2a, 0x66, +0xff, 0x99, 0x4a, 0x87, 0x78, 0x84, 0x5b, 0xdb, 0x46, 0xce, 0x97, 0x0c, 0xc8, 0x63, 0xca, 0x10, +0x83, 0x48, 0x94, 0x2b, 0xe4, 0x04, 0x14, 0x7d, 0x96, 0x28, 0x06, 0x80, 0x66, 0x9d, 0xc4, 0xef, +0x28, 0xea, 0xbd, 0x70, 0xbb, 0x5e, 0xc0, 0x58, 0xb0, 0x16, 0x51, 0x72, 0x70, 0x74, 0x44, 0xde, +0xfe, 0xd1, 0x39, 0x3f, 0xea, 0x5c, 0x1e, 0x12, 0x10, 0xdb, 0x22, 0xb6, 0xab, 0xb9, 0xbb, 0xb1, +0x93, 0xa9, 0xba, 0x30, 0xce, 0x12, 0x1f, 0xa9, 0x8e, 0xa4, 0xd8, 0x0e, 0xbd, 0x67, 0x09, 0x9c, +0x56, 0xbe, 0x2d, 0x46, 0x37, 0x0e, 0xf9, 0x6b, 0xad, 0xcc, 0x8c, 0xcc, 0x39, 0x9c, 0xe4, 0x38, +0xbf, 0x5f, 0x3f, 0x7d, 0x7c, 0xf9, 0x71, 0xd3, 0xf4, 0x85, 0x52, 0xbc, 0x66, 0xfe, 0xe1, 0xc9, +0x06, 0x54, 0x70, 0x86, 0x9c, 0x00, 0x3b, 0x34, 0xa1, 0x02, 0x72, 0x51, 0x9a, 0xc0, 0x69, 0x45, +0x49, 0x9f, 0x5c, 0x59, 0x2a, 0xb8, 0xb5, 0xda, 0xc4, 0xf2, 0xd3, 0x6c, 0x38, 0x96, 0xec, 0x8b, +0xf9, 0x1f, 0xf2, 0x74, 0x28, 0xa1, 0x2d, 0x54, 0x60, 0xd3, 0x6a, 0xaf, 0x59, 0xc0, 0x5f, 0x2e, +0x14, 0x8b, 0x80, 0x45, 0x73, 0x15, 0xa8, 0x19, 0xa6, 0xf0, 0x6e, 0x9e, 0x04, 0xf0, 0x3f, 0xa6, +0x3e, 0x5e, 0x90, 0x27, 0x87, 0x12, 0xbc, 0xc1, 0x1b, 0xad, 0x86, 0x59, 0xaa, 0x79, 0xcc, 0x9a, +0x8c, 0x8f, 0x21, 0xe9, 0xc3, 0xa1, 0xe2, 0x7f, 0x1a, 0x13, 0xea, 0x96, 0x69, 0x3f, 0x1c, 0x66, +0x0a, 0xf6, 0x1f, 0x6e, 0xa1, 0x73, 0x03, 0xf3, 0x42, 0xd3, 0x68, 0x7e, 0x07, 0xc8, 0xd9, 0xd2, +0x0d, 0x9d, 0x34, 0x19, 0x8e, 0xe9, 0xbd, 0x11, 0x86, 0xec, 0x31, 0x6e, 0x4f, 0x99, 0xcc, 0x9d, +0x04, 0x17, 0x00, 0xfd, 0x70, 0xe9, 0x5e, 0xb2, 0x11, 0x70, 0x19, 0xc4, 0x81, 0x2a, 0x18, 0xb8, +0xde, 0x7f, 0xb2, 0x66, 0x11, 0x1a, 0x58, 0xa6, 0x30, 0x88, 0xd7, 0xeb, 0xbb, 0x37, 0x16, 0x92, +0xd8, 0x79, 0xa8, 0xaf, 0x6e, 0xd9, 0xac, 0x4d, 0xa6, 0x34, 0xca, 0xd8, 0x35, 0x11, 0x63, 0xf2, +0xdb, 0xe8, 0x86, 0xf9, 0xda, 0x05, 0x82, 0x97, 0x9c, 0x29, 0xb3, 0x4d, 0x75, 0xfb, 0x84, 0x3f, +0x3e, 0xb6, 0x9f, 0xe2, 0x4e, 0xb9, 0x1c, 0x7a, 0xc3, 0x2c, 0x00, 0x69, 0xb0, 0xe5, 0x90, 0xbf, +0xff, 0x26, 0x36, 0xc6, 0x17, 0x8c, 0x19, 0xb3, 0xa4, 0xdf, 0x27, 0xad, 0x0c, 0x5a, 0xdd, 0x31, +0x20, 0x0a, 0x5a, 0x60, 0x0e, 0x4f, 0x10, 0x9e, 0x64, 0x6c, 0xbf, 0xd6, 0xac, 0x01, 0xee, 0xa6, +0x99, 0x0a, 0x6d, 0x2d, 0xd1, 0xa4, 0x2b, 0x59, 0x1a, 0x51, 0x9f, 0xd9, 0xad, 0x61, 0xab, 0x4d, +0x5a, 0xa4, 0xe5, 0x14, 0x80, 0x9d, 0x9a, 0xc4, 0x7c, 0x58, 0x8f, 0x44, 0x50, 0xb4, 0x01, 0x2e, +0x94, 0xe6, 0x71, 0xc4, 0xf0, 0xef, 0xdb, 0xd9, 0x49, 0x60, 0xe7, 0xc7, 0x94, 0xe3, 0xe2, 0x69, +0x97, 0x04, 0x76, 0x2d, 0x18, 0x6c, 0xc4, 0x11, 0x90, 0x6d, 0xe5, 0xcd, 0x0f, 0xc1, 0xe4, 0x95, +0xb1, 0xe9, 0x28, 0x2c, 0xa7, 0x7e, 0x1f, 0xe3, 0xc8, 0xb6, 0x34, 0x1d, 0x45, 0xb8, 0xe9, 0x7f, +0x19, 0x86, 0xdc, 0x23, 0xc5, 0xc0, 0x43, 0xbd, 0xc6, 0x5c, 0x0b, 0x9b, 0x7d, 0xd4, 0x7a, 0x68, +0xe7, 0x61, 0x70, 0x6a, 0xc5, 0xd7, 0x47, 0xb7, 0xac, 0xc0, 0x11, 0x0d, 0x26, 0xcc, 0x56, 0x99, +0xef, 0x33, 0xa5, 0xda, 0x04, 0xd9, 0xa4, 0x4d, 0x14, 0xb0, 0x5b, 0x82, 0xe4, 0x28, 0x25, 0x74, +0x32, 0x75, 0x9b, 0x2d, 0xa1, 0x83, 0x95, 0x89, 0x41, 0x88, 0x5d, 0xce, 0xb2, 0x5b, 0xc6, 0x62, +0x6e, 0xb7, 0x63, 0x91, 0x67, 0xc4, 0x2e, 0xad, 0x3b, 0xe4, 0x17, 0xa8, 0x8d, 0xfc, 0xbf, 0x45, +0xf6, 0x8a, 0x55, 0x9c, 0x87, 0x7c, 0xd5, 0x2d, 0xf1, 0xce, 0xa3, 0x6f, 0x74, 0x36, 0x23, 0x03, +0xd6, 0x5c, 0x06, 0x86, 0xaa, 0x24, 0xed, 0xec, 0xe6, 0xbd, 0x06, 0x2c, 0x5b, 0x23, 0x23, 0xe1, +0x99, 0xab, 0x7e, 0x06, 0x3a, 0x15, 0x42, 0x3b, 0xbe, 0x55, 0xc2, 0x75, 0x9c, 0xed, 0x19, 0xee, +0x82, 0x06, 0xfc, 0x11, 0x7e, 0x4b, 0x73, 0x76, 0x3b, 0x3b, 0x39, 0x27, 0xb6, 0x34, 0x87, 0x0b, +0x24, 0x20, 0x0b, 0x1c, 0xac, 0xec, 0xd3, 0xdf, 0x3e, 0xe3, 0xe5, 0xc3, 0xc9, 0xfb, 0x0f, 0x78, +0x3d, 0x3b, 0xfc, 0xdd, 0xaa, 0xa9, 0xe0, 0x82, 0x27, 0xa5, 0xb1, 0xb3, 0x43, 0xce, 0x50, 0x74, +0xb7, 0xb8, 0xbc, 0xec, 0x92, 0x5b, 0xeb, 0x7a, 0xbd, 0x0e, 0xa0, 0x5e, 0x01, 0x95, 0x2b, 0x11, +0xdf, 0xb9, 0x1c, 0x43, 0x8d, 0x37, 0x55, 0xf6, 0x9c, 0x3b, 0x1a, 0xb3, 0x15, 0x2a, 0xd3, 0x3a, +0xbf, 0xf8, 0x75, 0xf7, 0xc5, 0x29, 0xf4, 0xc9, 0xed, 0x22, 0xb1, 0x2a, 0xd6, 0xb1, 0x4b, 0x49, +0x12, 0xe0, 0x12, 0x16, 0xb4, 0x21, 0x2d, 0x9a, 0xe6, 0x4c, 0x9e, 0x60, 0x82, 0xc0, 0xf3, 0xb0, +0x26, 0x90, 0x7e, 0xcf, 0x30, 0xfa, 0xc5, 0xa4, 0xe5, 0x38, 0xed, 0xc7, 0x21, 0x90, 0x8f, 0xe2, +0x8e, 0x49, 0x72, 0xca, 0xa6, 0x86, 0xee, 0x53, 0x7a, 0x55, 0x59, 0x2c, 0xc5, 0xd9, 0x61, 0x84, +0xb3, 0xd7, 0x5b, 0x99, 0x7b, 0x87, 0xa7, 0xcf, 0x05, 0x3c, 0x30, 0x81, 0xb1, 0x40, 0x56, 0x8d, +0x21, 0xdf, 0xe1, 0xd4, 0x35, 0xe2, 0x1c, 0xa5, 0xca, 0xaa, 0xaf, 0xd0, 0x9a, 0x1d, 0x7b, 0x20, +0x2c, 0x52, 0x6c, 0x73, 0xb8, 0x6b, 0xa3, 0x3a, 0xa6, 0xa0, 0xd7, 0xce, 0xe3, 0xc3, 0x12, 0xa4, +0x11, 0x8c, 0x4b, 0x1d, 0xe5, 0xff, 0x33, 0x44, 0x67, 0xf2, 0x97, 0x00, 0x8c, 0xff, 0x2d, 0x7e, +0x5b, 0x1b, 0xdb, 0x98, 0xdf, 0x47, 0xb1, 0xde, 0x90, 0xdf, 0x7e, 0xac, 0xcb, 0x70, 0x1f, 0x9d, +0x0d, 0x76, 0x9f, 0x77, 0xbb, 0x87, 0xeb, 0x49, 0x8c, 0x26, 0x9a, 0x92, 0x78, 0x65, 0xee, 0xb1, +0x24, 0xfe, 0xba, 0x74, 0xd8, 0x84, 0xee, 0xbf, 0x93, 0x0c, 0x00, 0xe3, 0xc7, 0x26, 0x03, 0xb8, +0xfc, 0x8d, 0x47, 0xdd, 0x5a, 0x26, 0x6c, 0xe4, 0xe6, 0xb3, 0x2f, 0x5a, 0x37, 0x51, 0x73, 0x91, +0x3e, 0x45, 0x54, 0xbf, 0x8f, 0x1a, 0x17, 0x9b, 0xbf, 0x9c, 0x56, 0x6b, 0xb9, 0x54, 0x4d, 0x20, +0x2d, 0x33, 0x66, 0x92, 0xc8, 0x6c, 0x32, 0x6c, 0xeb, 0x23, 0x6c, 0xf5, 0xd3, 0xe0, 0x77, 0x30, +0x8f, 0x76, 0xf4, 0xfd, 0xd0, 0x4f, 0xf4, 0x63, 0xe2, 0x17, 0xa5, 0xb8, 0xcc, 0xc5, 0x9b, 0x98, +0xeb, 0x5b, 0xa8, 0x0b, 0x17, 0x28, 0xf3, 0x71, 0x35, 0x57, 0x4b, 0x77, 0x7e, 0x58, 0x92, 0x9e, +0x7d, 0x19, 0x0c, 0xfe, 0xff, 0x9a, 0x31, 0x93, 0x90, 0x27, 0xf8, 0x0a, 0xf8, 0x91, 0x8c, 0x84, +0x07, 0x12, 0x95, 0x25, 0x92, 0x2b, 0x46, 0x0e, 0x48, 0xb7, 0x29, 0x31, 0xbf, 0x27, 0x94, 0x2b, +0x9d, 0x6e, 0xd6, 0xd8, 0xda, 0x7e, 0x7b, 0x44, 0xeb, 0xa2, 0x7a, 0xb5, 0x51, 0xba, 0xcc, 0xdb, +0xcb, 0xdc, 0x77, 0xd0, 0x49, 0xd8, 0x1d, 0x1e, 0xce, 0x6c, 0x35, 0x2a, 0xff, 0x26, 0x3b, 0xf0, +0xec, 0xef, 0xb8, 0x5a, 0x9c, 0x0a, 0xfc, 0x32, 0x70, 0x09, 0xcf, 0x2e, 0xc9, 0xc4, 0x6e, 0x05, +0xac, 0xf3, 0xee, 0xb8, 0xb5, 0xa9, 0x8c, 0x56, 0xd6, 0x51, 0x4c, 0xd7, 0x2f, 0x03, 0x13, 0xff, +0xd0, 0x2a, 0x47, 0xd0, 0xec, 0x65, 0x09, 0xf7, 0xcd, 0x13, 0x04, 0x51, 0x9a, 0xca, 0xca, 0x92, +0xab, 0xae, 0x75, 0x48, 0x31, 0x20, 0xc6, 0x63, 0x00, 0xe1, 0xfc, 0x20, 0x14, 0x22, 0x6d, 0x00, +0x81, 0x8e, 0x3f, 0xfb, 0x31, 0x18, 0xce, 0xf1, 0xa5, 0x11, 0x19, 0xb1, 0x90, 0x4e, 0xb9, 0xc8, +0x64, 0x85, 0x29, 0x03, 0xae, 0xcc, 0x34, 0xe2, 0x2c, 0xc9, 0x72, 0x79, 0xcc, 0xf0, 0x25, 0x9c, +0x81, 0x86, 0x2e, 0xf3, 0xf3, 0x96, 0xf8, 0x0b, 0x9f, 0x92, 0x89, 0x79, 0xaa, 0xa7, 0x32, 0xc1, +0xbf, 0x8e, 0xb3, 0x11, 0xcf, 0x75, 0xf3, 0x74, 0x43, 0xc5, 0xd7, 0x3d, 0x75, 0x6e, 0x5d, 0xf1, +0x1b, 0x8a, 0x3d, 0xc9, 0xa2, 0x88, 0x3c, 0xed, 0x93, 0x06, 0x89, 0xf9, 0x7b, 0x97, 0xa5, 0x37, +0x3b, 0x57, 0xd6, 0x24, 0xbf, 0xb1, 0xae, 0xeb, 0xf8, 0x75, 0xdd, 0xf0, 0x95, 0x25, 0xd9, 0x58, +0x32, 0x15, 0x82, 0x42, 0xc3, 0x1a, 0xf8, 0x9b, 0x52, 0x49, 0xcc, 0xc7, 0xab, 0xfe, 0x82, 0x58, +0xcc, 0xcb, 0x30, 0x56, 0x70, 0x8b, 0xdd, 0xc2, 0xe9, 0x96, 0xb3, 0xdf, 0xcc, 0x13, 0x30, 0xef, +0xe2, 0x8b, 0xb4, 0xe3, 0x2f, 0x19, 0x9f, 0x82, 0xa1, 0xf9, 0xca, 0x9b, 0x55, 0x8a, 0xf7, 0xcb, +0x64, 0x15, 0x2e, 0x6e, 0xf2, 0x3e, 0xf9, 0x74, 0x71, 0xda, 0xb7, 0xf2, 0x94, 0x9c, 0xcf, 0x0d, +0x33, 0x19, 0xd5, 0x3d, 0x24, 0x6d, 0xa0, 0x46, 0xf5, 0x76, 0x36, 0xa0, 0x93, 0x73, 0x1a, 0x33, +0xbb, 0x85, 0xcc, 0xd7, 0x72, 0xae, 0xba, 0xd7, 0x05, 0x47, 0x1e, 0x85, 0x3c, 0x0a, 0x6c, 0xc4, +0xd2, 0xe0, 0xdd, 0x43, 0xed, 0x28, 0x9e, 0x91, 0x1b, 0x22, 0x5a, 0x7d, 0x36, 0x74, 0xf3, 0xcf, +0x2b, 0x1b, 0xc2, 0x57, 0xe9, 0x57, 0x0a, 0x71, 0x37, 0x86, 0xfb, 0xc7, 0x74, 0x96, 0xde, 0xb0, +0x5d, 0x59, 0xb9, 0x9e, 0x49, 0x8e, 0x26, 0x25, 0x08, 0xca, 0xe1, 0x0d, 0xbd, 0xb7, 0x5b, 0xf8, +0x41, 0xc6, 0x33, 0xdf, 0x24, 0x5b, 0xed, 0xa5, 0xd3, 0xe9, 0xab, 0x82, 0xd0, 0x78, 0x0a, 0x99, +0x97, 0xf9, 0x8e, 0xcb, 0xa1, 0xe1, 0x91, 0x1f, 0x06, 0x67, 0xa7, 0xe5, 0xf6, 0x9a, 0xf1, 0xeb, +0xaf, 0xac, 0xa8, 0x12, 0xb2, 0xf9, 0x86, 0xe4, 0xe5, 0xdf, 0x09, 0x9e, 0x91, 0x3b, 0xc0, 0x2e, +0xee, 0xdc, 0x48, 0xe4, 0xb4, 0xe6, 0xa6, 0x54, 0x87, 0xf8, 0xed, 0xb5, 0x70, 0x66, 0xc9, 0x8f, +0xc5, 0x77, 0xde, 0xfc, 0x2e, 0xff, 0xc6, 0xda, 0xf3, 0xf2, 0xcf, 0xe1, 0xff, 0x01, 0xf7, 0x15, +0xfc, 0x5a, 0x26, 0x1f, 0x00, 0x00}; +#endif /*__SYSTEM_HTML_H__*/ diff --git a/src/web/html/h/update_html.h b/src/web/html/h/update_html.h new file mode 100644 index 00000000..a853a186 --- /dev/null +++ b/src/web/html/h/update_html.h @@ -0,0 +1,74 @@ +#ifndef __UPDATE_HTML_H__ +#define __UPDATE_HTML_H__ +#define update_html_len 1090 +const uint8_t update_html[] PROGMEM = { +0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0xa5, 0x57, 0x5b, 0x6f, 0xdb, 0x36, +0x14, 0x7e, 0xef, 0xaf, 0xe0, 0xf4, 0x30, 0xd8, 0x43, 0x2c, 0x3a, 0xe9, 0x25, 0x59, 0x2a, 0x7b, +0x70, 0xd2, 0xac, 0x0b, 0x30, 0x74, 0x41, 0x9d, 0xa0, 0xe8, 0x53, 0x41, 0x51, 0x47, 0x16, 0x13, +0x8a, 0x14, 0x48, 0x4a, 0x8e, 0x37, 0xec, 0xbf, 0x8f, 0xd4, 0xc5, 0x96, 0x6c, 0x29, 0x73, 0x51, +0xbf, 0x48, 0x24, 0xcf, 0xf9, 0xce, 0x77, 0xae, 0x94, 0x83, 0x9f, 0x22, 0x49, 0xcd, 0x26, 0x03, +0x94, 0x98, 0x94, 0xcf, 0x5f, 0x05, 0xd5, 0x03, 0xd9, 0x5f, 0x90, 0x00, 0x89, 0xaa, 0xd7, 0x72, +0x69, 0x98, 0xe1, 0x30, 0x7f, 0xc8, 0x22, 0x62, 0x20, 0xc0, 0xd5, 0x6a, 0x77, 0xca, 0x99, 0x78, +0x42, 0x0a, 0xf8, 0xcc, 0xd3, 0x66, 0xc3, 0x41, 0x27, 0x00, 0xc6, 0x43, 0x0e, 0x79, 0xe6, 0x19, +0x78, 0x36, 0x98, 0x6a, 0xed, 0xa1, 0x44, 0x41, 0x5c, 0x4b, 0xf8, 0x76, 0xe3, 0xb7, 0x62, 0x36, +0xf5, 0x2f, 0xfc, 0xe9, 0x74, 0x7a, 0xea, 0x61, 0x6b, 0x3c, 0x05, 0x43, 0x90, 0x20, 0xa9, 0xd5, +0x29, 0x18, 0xac, 0x33, 0xa9, 0x2c, 0x06, 0x95, 0xc2, 0x80, 0x30, 0x33, 0x6f, 0xcd, 0x22, 0x93, +0xcc, 0x22, 0x28, 0x18, 0x85, 0x49, 0xb9, 0x38, 0x41, 0x4c, 0x30, 0xc3, 0x08, 0x9f, 0x68, 0x4a, +0x38, 0xcc, 0x4e, 0xbd, 0x06, 0x84, 0x26, 0x44, 0x69, 0xb0, 0x4a, 0x0f, 0xf7, 0xbf, 0x4f, 0x2e, +0xdc, 0xb6, 0xa6, 0x8a, 0x65, 0xa6, 0xcd, 0xe8, 0x91, 0x14, 0xa4, 0xda, 0xf5, 0x90, 0x56, 0x74, +0xe6, 0x91, 0x8c, 0xf9, 0x8f, 0x1d, 0x52, 0xf3, 0x00, 0x57, 0x12, 0x16, 0xe0, 0x7b, 0x3c, 0xa4, +0x92, 0x4b, 0xa5, 0xff, 0xc7, 0x45, 0x25, 0x43, 0x69, 0x74, 0xcb, 0x41, 0x21, 0x99, 0x88, 0xe0, +0xf9, 0x04, 0x09, 0x19, 0x4b, 0xce, 0xe5, 0xda, 0x43, 0xb8, 0xce, 0x05, 0xde, 0x25, 0x23, 0x08, +0x65, 0xb4, 0x69, 0x45, 0x3e, 0x62, 0x05, 0xa2, 0x9c, 0x68, 0x6d, 0x69, 0xc8, 0x4c, 0x90, 0xc2, +0xab, 0xe5, 0x48, 0x4d, 0x06, 0xb7, 0x39, 0x6c, 0x45, 0x5d, 0xfe, 0xbc, 0xf9, 0x22, 0x91, 0x9b, +0x0f, 0xf7, 0x0f, 0x01, 0x26, 0x7b, 0x4a, 0xbb, 0xe0, 0x5c, 0x16, 0x92, 0x45, 0xa3, 0xe9, 0xf8, +0xfd, 0x56, 0x97, 0x59, 0xc6, 0x1e, 0x92, 0x82, 0x72, 0x46, 0x9f, 0x1a, 0xab, 0xa3, 0xb1, 0xd7, +0x22, 0xa5, 0x33, 0x22, 0x5c, 0xf0, 0xdc, 0xe3, 0xbb, 0x77, 0x77, 0x6c, 0x9c, 0x6f, 0x2c, 0xda, +0x3a, 0xd6, 0x10, 0x48, 0x65, 0xc8, 0x1c, 0xfb, 0x1d, 0x06, 0x29, 0xc5, 0xac, 0xcc, 0xeb, 0xad, +0x50, 0xc2, 0x22, 0x68, 0xf2, 0x81, 0x39, 0x2b, 0xa0, 0x93, 0xd8, 0x3f, 0xed, 0xc6, 0xd6, 0x4e, +0x17, 0xe2, 0x4d, 0x3f, 0x84, 0x06, 0x65, 0x2b, 0xad, 0x03, 0xf2, 0x05, 0xc2, 0x6a, 0x77, 0x00, +0xe9, 0xed, 0x10, 0x92, 0xc9, 0xb3, 0x0e, 0xd0, 0x12, 0x8c, 0x61, 0x62, 0xa5, 0xbb, 0x38, 0x2e, +0x22, 0x0d, 0x80, 0x86, 0x0c, 0x14, 0x31, 0x52, 0x79, 0x87, 0x01, 0xdc, 0xda, 0x7b, 0xd7, 0x6f, +0x2f, 0x2f, 0x7b, 0xb6, 0x63, 0xb0, 0x69, 0xe3, 0x5e, 0xda, 0xe7, 0x03, 0xb4, 0x37, 0xda, 0x40, +0xda, 0xe5, 0x5d, 0x6e, 0xfd, 0x20, 0xeb, 0x8b, 0xad, 0x05, 0xdb, 0x80, 0xb6, 0xa3, 0x88, 0x5a, +0xb9, 0xce, 0xfd, 0x16, 0x72, 0x22, 0x9e, 0xbc, 0xf9, 0xe7, 0x9b, 0xe5, 0x3d, 0x5a, 0xdc, 0xdd, +0x0e, 0x90, 0xfd, 0xb5, 0xd1, 0x4e, 0x8c, 0xc9, 0xf4, 0x25, 0xc6, 0xc4, 0x96, 0x74, 0x64, 0x72, +0xdf, 0x31, 0xdf, 0xc7, 0xfa, 0x20, 0x69, 0x9e, 0xda, 0x5e, 0x23, 0x86, 0x49, 0x31, 0x00, 0x78, +0x3a, 0xdd, 0xf1, 0x09, 0x65, 0x6e, 0x3a, 0x0e, 0x2f, 0xdc, 0xce, 0x0f, 0xfa, 0x3b, 0x1d, 0x28, +0x51, 0xb9, 0x62, 0xc2, 0x16, 0xa6, 0x7b, 0x0c, 0x51, 0x1b, 0xd4, 0xb4, 0xac, 0x4a, 0xd5, 0x36, +0xbb, 0x00, 0xdb, 0xf6, 0xd9, 0x6b, 0xa4, 0x35, 0x8b, 0x59, 0xd5, 0xbe, 0x4d, 0x2f, 0x8b, 0x58, +0x3a, 0xb2, 0xa5, 0x68, 0x4b, 0xa3, 0xab, 0xa5, 0x48, 0x66, 0x1d, 0x6b, 0x35, 0x5c, 0xe7, 0xb8, +0x1e, 0x60, 0x7b, 0xc7, 0xa5, 0x48, 0xcc, 0x80, 0x47, 0xb6, 0xde, 0x0f, 0x8f, 0xaa, 0x5b, 0x03, +0x56, 0x20, 0xa2, 0x86, 0x4b, 0x04, 0xda, 0xb5, 0x02, 0x07, 0x6a, 0x50, 0xcc, 0x54, 0xba, 0x26, +0x0a, 0xec, 0x0b, 0x07, 0x34, 0xfa, 0xc5, 0x0f, 0x99, 0x18, 0x07, 0xb8, 0x52, 0x18, 0x40, 0x8b, +0xa5, 0x4a, 0x4b, 0x42, 0xee, 0xc5, 0x43, 0x76, 0xd4, 0x26, 0xd2, 0xae, 0xee, 0xfe, 0x5a, 0xde, +0x7b, 0x88, 0x50, 0x97, 0xf3, 0x6d, 0x37, 0x78, 0x08, 0x04, 0xad, 0x86, 0x77, 0x9a, 0x73, 0xc3, +0x32, 0xa2, 0x0c, 0x76, 0x7a, 0x13, 0x7b, 0x4a, 0x9c, 0x38, 0x85, 0xcc, 0x4c, 0xb6, 0xf7, 0x48, +0x6e, 0xe2, 0xf2, 0x1e, 0x41, 0x03, 0xbf, 0x80, 0x89, 0x2c, 0x6f, 0xae, 0x17, 0xc7, 0xd9, 0xab, +0xa7, 0x7c, 0x6d, 0xee, 0x48, 0xcd, 0x30, 0x37, 0xa6, 0x95, 0x9d, 0xd0, 0xd8, 0xf7, 0x82, 0xf0, +0xdc, 0x1e, 0x3d, 0xd4, 0xbc, 0xb7, 0x73, 0xd7, 0xd5, 0x40, 0x67, 0xea, 0x76, 0x50, 0x4b, 0x67, +0x7a, 0x32, 0x82, 0xfb, 0x53, 0xb2, 0x9f, 0xfa, 0x81, 0x4a, 0x88, 0xa5, 0x34, 0x9d, 0x42, 0x68, +0x5f, 0x3f, 0x1c, 0x62, 0xd3, 0x1d, 0xca, 0xc7, 0x77, 0x66, 0x7d, 0x11, 0xa1, 0x9f, 0xa9, 0xcc, +0x36, 0xe8, 0x6c, 0x7a, 0xf6, 0xba, 0xdb, 0x03, 0x39, 0xdf, 0xe3, 0xcb, 0xd9, 0xfc, 0xc0, 0x40, +0xc4, 0x34, 0x95, 0x2a, 0xf2, 0x57, 0x2b, 0xfc, 0xe5, 0xef, 0xe4, 0xf9, 0xe6, 0xeb, 0xbb, 0xb3, +0xf4, 0xaa, 0x67, 0x0a, 0x54, 0x62, 0xce, 0x80, 0xad, 0x28, 0x76, 0x04, 0xf0, 0x8a, 0x99, 0x24, +0x0f, 0x7d, 0x2a, 0x53, 0xcc, 0xf3, 0x94, 0x64, 0x79, 0xe9, 0xcb, 0x21, 0xf2, 0xc7, 0x52, 0xee, +0x10, 0x38, 0xc0, 0x0d, 0xff, 0xfd, 0xa6, 0xac, 0x43, 0xa7, 0xd8, 0x2a, 0xe9, 0xc4, 0x6e, 0xc0, +0xdf, 0x3d, 0x83, 0x47, 0xd1, 0xc4, 0x76, 0x9d, 0x32, 0xa3, 0x71, 0x18, 0x9f, 0x9f, 0x9f, 0x9d, +0xbf, 0xb5, 0x34, 0x6f, 0xef, 0xd1, 0xf2, 0x8f, 0xc5, 0x25, 0xaa, 0x77, 0xd0, 0xe5, 0x25, 0x6a, +0x66, 0xdc, 0x60, 0x54, 0xca, 0xfc, 0x83, 0xce, 0xbe, 0xb9, 0x4a, 0xf5, 0x8e, 0x8d, 0x1c, 0x55, +0x60, 0x87, 0x6d, 0x01, 0x8e, 0x83, 0x14, 0xda, 0x97, 0x6a, 0x65, 0x15, 0x29, 0x08, 0x0d, 0x96, +0xd0, 0x66, 0x22, 0xe8, 0x44, 0x13, 0xfc, 0xc6, 0x9f, 0xe2, 0x08, 0x20, 0x3a, 0x88, 0x28, 0x9a, +0x5f, 0x5f, 0xa3, 0xab, 0xaf, 0x93, 0x4f, 0xd7, 0x93, 0xe5, 0x02, 0x59, 0xb1, 0x23, 0x62, 0xbb, +0x5f, 0xbb, 0x2f, 0x7e, 0xf9, 0x75, 0x5d, 0x88, 0x73, 0x51, 0x8e, 0x09, 0x94, 0xb9, 0xb6, 0xff, +0x08, 0xc2, 0xde, 0xee, 0x74, 0x24, 0xc3, 0xc7, 0x31, 0xfa, 0xe7, 0xa0, 0x95, 0x4a, 0x99, 0x4f, +0xf6, 0xcb, 0xc7, 0x9d, 0xbf, 0xef, 0x3f, 0xbe, 0x59, 0xde, 0xbd, 0x74, 0xfc, 0x59, 0x6b, 0xd6, +0x73, 0xfe, 0xef, 0xab, 0x7e, 0x56, 0x55, 0xc7, 0xf7, 0x50, 0x89, 0xea, 0x7b, 0xcd, 0xb7, 0xb1, +0xbb, 0xe1, 0xe0, 0x5e, 0xaf, 0x36, 0xb7, 0xd1, 0xa8, 0x9a, 0x84, 0x63, 0x5f, 0xe7, 0xa1, 0xad, +0x80, 0x51, 0x0f, 0x8d, 0x82, 0x28, 0x04, 0x68, 0x36, 0x8c, 0xd0, 0x0c, 0xf7, 0x1e, 0x5d, 0xf0, +0x15, 0x64, 0x9c, 0x50, 0xb8, 0x4e, 0x18, 0x8f, 0x14, 0x88, 0x91, 0xbb, 0xf2, 0x46, 0xf5, 0xc8, +0x43, 0xda, 0xe6, 0xd2, 0xd8, 0x9c, 0x8e, 0x5f, 0xf6, 0xce, 0x1a, 0x5c, 0x3c, 0x92, 0xe7, 0x51, +0x79, 0xfd, 0xe3, 0x55, 0x15, 0x73, 0xef, 0xa4, 0x93, 0x82, 0x16, 0xc2, 0xee, 0x8b, 0xbc, 0x5a, +0x55, 0x5f, 0xc3, 0xf6, 0x03, 0xb9, 0xfc, 0xe3, 0xf2, 0x1f, 0x6f, 0x3a, 0xe4, 0xb0, 0xd0, 0x0c, +0x00, 0x00}; +#endif /*__UPDATE_HTML_H__*/ diff --git a/src/web/html/h/visualization_html.h b/src/web/html/h/visualization_html.h new file mode 100644 index 00000000..4fdaad5d --- /dev/null +++ b/src/web/html/h/visualization_html.h @@ -0,0 +1,275 @@ +#ifndef __VISUALIZATION_HTML_H__ +#define __VISUALIZATION_HTML_H__ +#define visualization_html_len 4311 +const uint8_t visualization_html[] PROGMEM = { +0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0xed, 0x1c, 0x6b, 0x73, 0xdb, 0x38, +0xee, 0x7b, 0x7f, 0x05, 0xab, 0x99, 0xed, 0xda, 0x5b, 0x3f, 0xf3, 0x6a, 0x37, 0xaf, 0x4e, 0x9a, +0xa6, 0xdb, 0xdc, 0xb5, 0x69, 0xaf, 0xc9, 0x6e, 0x6f, 0x27, 0x93, 0xc9, 0xd0, 0x12, 0x6d, 0xb1, +0x91, 0x25, 0x9d, 0x48, 0xdb, 0xf1, 0xee, 0xe4, 0xbf, 0x1f, 0x40, 0x4a, 0xb2, 0x6c, 0x8b, 0xb2, +0xe4, 0xb8, 0xdd, 0xbd, 0x99, 0xcb, 0x87, 0x24, 0x92, 0x08, 0x10, 0x00, 0x01, 0x10, 0x00, 0x21, +0x1d, 0x3e, 0x75, 0x02, 0x5b, 0x4e, 0x43, 0x46, 0x5c, 0x39, 0xf4, 0x8e, 0x9f, 0x1c, 0xea, 0x3f, +0x04, 0x7e, 0x0e, 0x5d, 0x46, 0x1d, 0xfd, 0xaf, 0xba, 0x94, 0x5c, 0x7a, 0xec, 0xf8, 0x3d, 0x1f, +0xb3, 0xc3, 0xb6, 0xfe, 0x7f, 0xf6, 0xcc, 0xe3, 0xfe, 0x1d, 0x89, 0x98, 0x77, 0x64, 0x09, 0x39, +0xf5, 0x98, 0x70, 0x19, 0x93, 0x16, 0x41, 0xbc, 0x47, 0x96, 0x64, 0xf7, 0xb2, 0x6d, 0x0b, 0x61, +0x11, 0x37, 0x62, 0xfd, 0x78, 0x44, 0x0b, 0x6e, 0xbc, 0x1a, 0x1f, 0x75, 0x5a, 0x2f, 0x5b, 0x9d, +0x4e, 0xa7, 0x6b, 0xb5, 0x61, 0xea, 0x21, 0x93, 0x94, 0xf8, 0x74, 0x08, 0x30, 0x63, 0xce, 0x26, +0x61, 0x10, 0x01, 0x0e, 0x3b, 0xf0, 0x25, 0xf3, 0xe5, 0x91, 0x35, 0xe1, 0x8e, 0x74, 0x8f, 0x1c, +0x36, 0xe6, 0x36, 0x6b, 0xaa, 0x8b, 0x06, 0xe1, 0x3e, 0x97, 0x9c, 0x7a, 0x4d, 0x61, 0x53, 0x8f, +0x1d, 0x75, 0xad, 0x04, 0x89, 0xed, 0xd2, 0x48, 0x30, 0x00, 0xfa, 0xf5, 0xea, 0x6d, 0xf3, 0x25, +0xde, 0x16, 0x76, 0xc4, 0x43, 0x99, 0xa5, 0xe8, 0x2b, 0x1d, 0x53, 0x7d, 0xd7, 0x22, 0x22, 0xb2, +0x8f, 0x2c, 0x1a, 0xf2, 0xd6, 0xd7, 0x39, 0xa2, 0x8e, 0x0f, 0xdb, 0x7a, 0x04, 0x20, 0xa8, 0xc2, +0xa1, 0x1d, 0x78, 0x41, 0x24, 0x56, 0xb0, 0x18, 0x05, 0xbd, 0x40, 0x8a, 0x0c, 0x83, 0x7e, 0xc0, +0x7d, 0x87, 0xdd, 0x37, 0x88, 0x1f, 0xf4, 0x03, 0xcf, 0x0b, 0x26, 0x16, 0x69, 0x67, 0x44, 0x9c, +0x01, 0xa5, 0x61, 0xe8, 0xb1, 0xe6, 0x30, 0xe8, 0x71, 0xf8, 0x33, 0x61, 0xbd, 0x26, 0xdc, 0x68, +0xda, 0x34, 0xa4, 0x3d, 0x8f, 0x65, 0x10, 0x4e, 0x99, 0xb0, 0xe2, 0xa5, 0x6c, 0xcf, 0xd6, 0xf2, +0xb0, 0x17, 0x38, 0xd3, 0x0c, 0x5e, 0x87, 0x8f, 0x89, 0xed, 0x51, 0x21, 0x80, 0x8f, 0x20, 0xf4, +0xe9, 0x38, 0x81, 0xa1, 0x31, 0x37, 0xed, 0x2c, 0x13, 0xe9, 0x50, 0x54, 0x00, 0xeb, 0xf8, 0xc4, +0x0d, 0xa6, 0x6f, 0xae, 0x7e, 0x3d, 0x6c, 0xd3, 0x05, 0xa0, 0x99, 0x74, 0xf7, 0xc7, 0x01, 0x77, +0x6a, 0x9d, 0xfa, 0x41, 0x0a, 0xcb, 0x81, 0x42, 0x8b, 0x04, 0xbe, 0xed, 0x71, 0xfb, 0x2e, 0x99, +0xb5, 0x56, 0xb7, 0x32, 0x44, 0x89, 0x90, 0xfa, 0x28, 0x7d, 0xfc, 0x53, 0xf9, 0xee, 0x8c, 0x1a, +0xe4, 0x8d, 0x3b, 0x29, 0x63, 0x09, 0x01, 0x5a, 0x72, 0xd9, 0xf9, 0xa8, 0x1a, 0x06, 0x63, 0xb6, +0xd3, 0x41, 0x2e, 0x77, 0x58, 0xb2, 0xa0, 0x6d, 0x0f, 0xb4, 0x7e, 0x4e, 0x33, 0xb4, 0x19, 0xd0, +0x3c, 0x14, 0x3b, 0xf9, 0x28, 0x04, 0x8b, 0x40, 0x55, 0xe7, 0x90, 0x7c, 0x61, 0x3d, 0x7d, 0xd7, +0x80, 0x69, 0xd7, 0x84, 0x49, 0x8e, 0xc2, 0x39, 0x44, 0x97, 0x4c, 0x4a, 0xee, 0x0f, 0xc4, 0x3c, +0x1e, 0x94, 0x48, 0x82, 0x40, 0xb0, 0x90, 0x45, 0x54, 0x06, 0x91, 0xb5, 0x2c, 0xc0, 0x74, 0xbe, +0xbd, 0xfc, 0xf9, 0x46, 0xa1, 0x43, 0xe5, 0x3c, 0xfb, 0xbf, 0xaa, 0x5b, 0x06, 0xb2, 0x5f, 0x18, +0xc8, 0x9e, 0x0a, 0xc9, 0x86, 0xf3, 0x74, 0xab, 0x5b, 0x8f, 0xa4, 0xfa, 0x65, 0x3a, 0x03, 0x58, +0x30, 0x98, 0x24, 0x8d, 0x06, 0x68, 0xfa, 0xb7, 0x3d, 0x8f, 0xfa, 0x77, 0xd6, 0xf1, 0xe7, 0xb3, +0xcb, 0x2b, 0x72, 0xf2, 0xe9, 0xdc, 0x40, 0xec, 0xcf, 0x09, 0xb4, 0x2b, 0x65, 0x28, 0xf6, 0xdb, +0x6d, 0x0a, 0x2a, 0xed, 0xc8, 0x51, 0x0b, 0x29, 0x5f, 0xc4, 0xf5, 0x26, 0xb0, 0x47, 0x43, 0xb0, +0x2d, 0x2a, 0x79, 0xe0, 0x1b, 0x10, 0x76, 0x3b, 0x33, 0x7a, 0x7a, 0xc1, 0x48, 0xce, 0x31, 0x7c, +0x82, 0x77, 0x1e, 0xc9, 0x6f, 0xc7, 0xa0, 0xa2, 0xc1, 0x80, 0xfb, 0xa0, 0x98, 0xf8, 0xc7, 0x44, +0x9a, 0x11, 0x12, 0xa8, 0x52, 0xa0, 0x59, 0xea, 0x0e, 0xdb, 0x60, 0x3e, 0x0b, 0x86, 0x34, 0xe1, +0x7d, 0xae, 0xcd, 0x37, 0xb1, 0x65, 0xbf, 0x1f, 0x20, 0xb1, 0x6a, 0x68, 0x06, 0x62, 0x1e, 0x2a, +0x02, 0x07, 0xc5, 0xa2, 0x8c, 0xc1, 0xcd, 0x3d, 0x8e, 0x1d, 0xd6, 0xc2, 0xe3, 0xb9, 0x21, 0x68, +0x7f, 0xe9, 0x34, 0x4b, 0xa3, 0xc2, 0xe3, 0xb3, 0x31, 0x8b, 0xa6, 0xb1, 0x2c, 0x71, 0x3c, 0x30, +0x16, 0x81, 0x8f, 0x4e, 0xc5, 0x48, 0x04, 0x83, 0x59, 0x1c, 0x41, 0xa4, 0xcb, 0xc8, 0x98, 0x7a, +0x23, 0x26, 0x08, 0x8d, 0x18, 0xd1, 0xaa, 0xed, 0x1c, 0xb6, 0xc3, 0x05, 0xda, 0x16, 0x38, 0x31, +0x30, 0xd6, 0x0f, 0x02, 0x39, 0xc7, 0x57, 0xd6, 0x9b, 0x7a, 0xac, 0x2f, 0xe7, 0x7d, 0x4c, 0x79, +0x45, 0x8b, 0xfd, 0x2a, 0x79, 0x66, 0x07, 0xe1, 0x94, 0x6c, 0x75, 0xb6, 0xb6, 0xe7, 0x97, 0x74, +0xe4, 0x2d, 0xd0, 0xeb, 0xf1, 0xe3, 0xa5, 0x09, 0x1c, 0x2e, 0xec, 0x20, 0x72, 0x5a, 0x83, 0x41, +0xfb, 0xcb, 0x1f, 0xee, 0xfd, 0xd9, 0xef, 0x7b, 0x5b, 0xc3, 0xd7, 0x39, 0x4a, 0xad, 0x87, 0xe1, +0x04, 0x87, 0xe0, 0xe8, 0x4a, 0x20, 0x1e, 0x70, 0xe9, 0x8e, 0x7a, 0x2d, 0x3b, 0x18, 0xb6, 0xbd, +0xd1, 0x90, 0x86, 0x23, 0xc5, 0xcb, 0x32, 0xe6, 0x5f, 0xd4, 0xb8, 0x65, 0xc4, 0x87, 0xed, 0x84, +0xfe, 0x45, 0x1d, 0x8b, 0x45, 0x17, 0xf1, 0x81, 0x3b, 0x27, 0x3b, 0x03, 0xbf, 0x0b, 0x13, 0x96, +0x22, 0xb3, 0x0d, 0xd7, 0x43, 0x2e, 0x45, 0xbb, 0xd7, 0x7f, 0xf1, 0x62, 0xeb, 0xc5, 0x2e, 0x90, +0x79, 0x7e, 0x45, 0x2e, 0xdf, 0x9d, 0xec, 0x93, 0xf8, 0x0e, 0xd9, 0xdf, 0x27, 0x89, 0xc9, 0x1a, +0xa5, 0xa2, 0xd6, 0x9f, 0x89, 0xf0, 0x16, 0x43, 0x00, 0xab, 0xac, 0xe4, 0xec, 0x88, 0x81, 0xef, +0x18, 0x33, 0xa4, 0x21, 0xf0, 0x45, 0x2b, 0x88, 0x06, 0x00, 0x68, 0x33, 0x5f, 0x30, 0x20, 0x68, +0xda, 0xf4, 0xed, 0xa6, 0xa0, 0xed, 0x9d, 0x56, 0xa7, 0xed, 0x30, 0xe6, 0x2c, 0x49, 0x94, 0x1c, +0x9f, 0x9e, 0x92, 0xd7, 0xbf, 0x37, 0x2f, 0x4e, 0x9b, 0x97, 0x27, 0x04, 0x86, 0x95, 0x90, 0xed, +0xa2, 0xee, 0x16, 0x46, 0x42, 0xf3, 0x2c, 0x8c, 0x69, 0x44, 0xd8, 0x3d, 0xfb, 0xe8, 0xdb, 0x8c, +0x1c, 0x11, 0x19, 0x8d, 0xd8, 0xc1, 0xd2, 0xf3, 0x11, 0x84, 0x60, 0x02, 0x22, 0xb1, 0xf1, 0x99, +0xbf, 0xfc, 0x70, 0x78, 0x3e, 0x7e, 0x07, 0xf1, 0x24, 0x00, 0x5f, 0xdf, 0xe4, 0x3c, 0xbd, 0x18, +0x0d, 0xe1, 0x51, 0x67, 0xf9, 0x89, 0x0c, 0x24, 0x45, 0xa8, 0x93, 0x28, 0xa2, 0xd3, 0xda, 0x6e, +0xbd, 0xd5, 0xe7, 0x9e, 0x87, 0x31, 0xc4, 0xf2, 0xc8, 0x4f, 0x93, 0xe8, 0xc4, 0xbe, 0x3b, 0x78, +0x32, 0xf7, 0xa4, 0x3f, 0xf2, 0x6d, 0x74, 0xd1, 0x24, 0xc4, 0x38, 0xf0, 0x17, 0xe6, 0xc3, 0x2e, +0x6b, 0xd7, 0x82, 0xde, 0xd7, 0x3a, 0xf9, 0x73, 0xc9, 0x7d, 0xf0, 0x7e, 0x0d, 0x59, 0x23, 0x47, +0x47, 0x09, 0xb3, 0xf5, 0xe5, 0x41, 0xf8, 0xa3, 0x90, 0x5d, 0x40, 0xa8, 0x82, 0x88, 0x0e, 0xcc, +0x43, 0xce, 0x2e, 0x3f, 0x19, 0x86, 0x3c, 0x3c, 0xc9, 0x05, 0xf8, 0x2c, 0x04, 0xcf, 0x81, 0x78, +0x30, 0x30, 0xe5, 0x8f, 0x86, 0xaf, 0xf9, 0xa0, 0x06, 0x6e, 0xac, 0xa1, 0xc4, 0xdf, 0x20, 0x0e, +0x13, 0x79, 0x9c, 0x45, 0x10, 0x28, 0x44, 0x3e, 0x19, 0x7a, 0x35, 0x0b, 0x74, 0xc0, 0x6a, 0x90, +0x3f, 0x95, 0x7d, 0xed, 0x13, 0x8c, 0x50, 0x9b, 0x7b, 0x04, 0x7f, 0x8b, 0x61, 0x73, 0x87, 0xd0, +0xa6, 0x6d, 0x3d, 0x34, 0xc8, 0x75, 0x2e, 0x4f, 0x39, 0xe0, 0x11, 0x04, 0xa7, 0x0f, 0x8d, 0xdc, +0xd1, 0x06, 0x08, 0x98, 0xca, 0x3c, 0x43, 0x16, 0x0e, 0xdd, 0x75, 0x16, 0xb0, 0x2f, 0x9a, 0xbb, +0x04, 0x7e, 0x0d, 0x9d, 0xe6, 0x0e, 0x62, 0xb8, 0x94, 0x11, 0x44, 0x3a, 0xb5, 0x0f, 0x54, 0xba, +0xad, 0x28, 0x18, 0xf9, 0x0e, 0xca, 0x81, 0xfc, 0x44, 0xba, 0x9d, 0x4e, 0x9d, 0xb4, 0xd5, 0x9f, +0x7a, 0x63, 0x9d, 0x59, 0xf6, 0xe2, 0x59, 0x5e, 0x90, 0xe1, 0x7d, 0xb3, 0x8b, 0x53, 0xa1, 0x6c, +0xeb, 0x46, 0x54, 0x37, 0xa6, 0x79, 0x36, 0x28, 0xaf, 0x75, 0xf8, 0xf8, 0x99, 0x84, 0x31, 0xfd, +0xa8, 0x15, 0x46, 0x0c, 0xf9, 0x4f, 0x96, 0xef, 0xde, 0x94, 0x57, 0xca, 0x0f, 0xdc, 0xd9, 0xa4, +0x52, 0xe2, 0x3f, 0xb0, 0x1e, 0xdb, 0x64, 0xd8, 0x6b, 0x6e, 0xfd, 0x8d, 0xd5, 0x73, 0xef, 0x9b, +0xaa, 0xe5, 0xcb, 0xff, 0x75, 0x75, 0xfc, 0xee, 0x9a, 0xa8, 0x36, 0x0f, 0x51, 0xcb, 0xd3, 0xbd, +0x7e, 0x10, 0xd5, 0x70, 0xd7, 0xe0, 0x6a, 0xdb, 0x81, 0x3f, 0x87, 0x64, 0x17, 0xfe, 0x3c, 0x7f, +0x9e, 0x37, 0x18, 0x7f, 0x14, 0xae, 0x6b, 0x7e, 0x03, 0xe3, 0x33, 0x4b, 0x9b, 0xde, 0xcd, 0xae, +0x6f, 0x9e, 0xb7, 0xaf, 0xa0, 0xfc, 0xb0, 0x26, 0x64, 0x28, 0xb5, 0xb6, 0xef, 0x9a, 0x64, 0xbd, +0x8e, 0xe6, 0xe6, 0xc0, 0x84, 0xcd, 0x2d, 0xcd, 0x59, 0xd3, 0x2d, 0xb3, 0xaa, 0xd5, 0xb4, 0xa7, +0x98, 0x56, 0xd4, 0xe6, 0x2d, 0xfc, 0x05, 0x96, 0xad, 0xb4, 0xda, 0xba, 0xfa, 0x78, 0x75, 0xf2, +0xde, 0xaa, 0x17, 0xe2, 0x2b, 0x30, 0x9d, 0x7a, 0x63, 0x3d, 0xce, 0x7b, 0x83, 0x72, 0x06, 0x9f, +0xcb, 0xfc, 0x0a, 0x38, 0xfc, 0x89, 0x37, 0x69, 0xad, 0x2a, 0x9d, 0x1b, 0x60, 0xf4, 0x0b, 0xe0, +0xb1, 0x4e, 0x4e, 0xc9, 0xa7, 0x60, 0x02, 0x39, 0x43, 0xbd, 0x51, 0x0d, 0x45, 0x57, 0xa1, 0x70, +0x11, 0xc7, 0xef, 0x9c, 0x79, 0x0e, 0x79, 0x43, 0xa7, 0x95, 0x91, 0x6c, 0x21, 0x92, 0xbb, 0x2c, +0x96, 0x2b, 0xbc, 0xbf, 0x42, 0xfa, 0x37, 0xf5, 0xca, 0x3a, 0xe2, 0x46, 0xd6, 0x43, 0xbd, 0xf1, +0x2d, 0x85, 0x8b, 0x9b, 0x8d, 0x66, 0x6a, 0x3b, 0x15, 0xee, 0x9b, 0x6a, 0xc2, 0x9d, 0xa1, 0xd8, +0x41, 0x14, 0xe0, 0x18, 0x10, 0xc9, 0x67, 0x46, 0x6d, 0x0c, 0xd1, 0x13, 0x54, 0x2b, 0x44, 0xf3, +0xa4, 0xe2, 0xa3, 0x9c, 0xdb, 0x4b, 0x7e, 0x2d, 0xd7, 0xad, 0xf1, 0xf1, 0x3b, 0x46, 0x9d, 0x82, +0x20, 0xb6, 0x43, 0x9e, 0x1e, 0x11, 0x78, 0xdc, 0x12, 0x92, 0xca, 0x11, 0xee, 0xbd, 0xa4, 0xdd, +0x26, 0x81, 0xef, 0x4d, 0x09, 0x75, 0x9c, 0xd8, 0x2d, 0xc2, 0x40, 0xc2, 0x7d, 0xc8, 0x96, 0x21, +0x6f, 0x25, 0x5c, 0xe0, 0x63, 0xee, 0xb3, 0x02, 0xdf, 0xd7, 0xb9, 0x21, 0xcf, 0x35, 0x5a, 0xdb, +0x85, 0x0b, 0x50, 0xa1, 0x03, 0x44, 0xfb, 0xe9, 0xf6, 0xe4, 0xb4, 0x00, 0x6a, 0x7b, 0x01, 0xea, +0x65, 0x02, 0xf5, 0xa6, 0x08, 0x6a, 0x67, 0x01, 0xaa, 0xdb, 0xd1, 0x60, 0xff, 0xca, 0x9b, 0x6c, +0x39, 0x96, 0x4e, 0x0c, 0x65, 0x1e, 0xc9, 0x0b, 0x8d, 0x43, 0xa9, 0x3b, 0xd8, 0x8c, 0x01, 0x6a, +0x6b, 0x01, 0x6a, 0x2f, 0x03, 0xa5, 0x6c, 0x64, 0xd9, 0x97, 0xab, 0xf4, 0x03, 0x36, 0x06, 0xdc, +0xf4, 0x6a, 0xd6, 0x33, 0xbf, 0x27, 0xc2, 0x83, 0x67, 0x0e, 0x1b, 0x1c, 0x9c, 0x5a, 0x39, 0xa1, +0x3f, 0x8e, 0xb6, 0x3d, 0x97, 0x00, 0x00, 0xac, 0xd4, 0xd1, 0xfc, 0x4a, 0xbd, 0x22, 0x16, 0x1f, +0x37, 0xdd, 0x26, 0x64, 0xec, 0x16, 0xd9, 0xd7, 0x17, 0x96, 0x09, 0x47, 0x6f, 0x50, 0x80, 0xa3, +0x37, 0xc8, 0x22, 0x01, 0x27, 0x97, 0x8f, 0x25, 0x9c, 0x44, 0xef, 0x39, 0x64, 0xc1, 0x80, 0xc9, +0xf2, 0xdb, 0xd4, 0x3a, 0x78, 0x92, 0xa7, 0x51, 0x7b, 0xbb, 0xbb, 0xdb, 0xbb, 0x89, 0x56, 0x85, +0x68, 0x0e, 0xb7, 0x1e, 0x42, 0xdd, 0x42, 0x16, 0xeb, 0x98, 0xb6, 0xcc, 0x0c, 0xea, 0x3c, 0x30, +0xf2, 0x9c, 0xc4, 0xb2, 0xfa, 0xc1, 0xca, 0xcf, 0xa1, 0xb2, 0xaa, 0x3c, 0xa4, 0xf7, 0xb7, 0x80, +0xd0, 0x6c, 0x65, 0xe9, 0x6c, 0xb0, 0x7a, 0x68, 0xbd, 0x80, 0x3e, 0xb3, 0x51, 0x67, 0x50, 0xc0, +0x5e, 0x9d, 0x4b, 0x8e, 0x8e, 0xcd, 0x90, 0xaa, 0x2f, 0xd6, 0x66, 0xb6, 0xf0, 0xad, 0xef, 0xb0, +0x7b, 0x23, 0x9f, 0xa0, 0x4d, 0x0f, 0xdf, 0xce, 0xc5, 0x96, 0xdc, 0xbe, 0xb3, 0x51, 0x1f, 0x49, +0x29, 0x0c, 0xb8, 0x8f, 0x75, 0xb1, 0x46, 0x52, 0xe4, 0xdf, 0x4f, 0xdd, 0x58, 0xcd, 0xa4, 0x36, +0x8b, 0x3f, 0x03, 0x26, 0x4f, 0xbe, 0xd2, 0xfb, 0x9a, 0xaa, 0xea, 0xb6, 0x13, 0x97, 0xd5, 0x86, +0x3f, 0x02, 0xd0, 0xb4, 0x51, 0x00, 0xb8, 0x9e, 0xdc, 0x69, 0xe8, 0x1c, 0xfa, 0x7c, 0xfc, 0x9b, +0x7e, 0x64, 0xc8, 0xcc, 0xe7, 0x56, 0x15, 0x08, 0x47, 0x60, 0x3c, 0x4d, 0xa9, 0xd7, 0xd7, 0x0e, +0x65, 0x30, 0x6b, 0x36, 0xb0, 0xa8, 0x14, 0xec, 0x43, 0xe0, 0x50, 0x4f, 0x39, 0xec, 0x87, 0x52, +0x22, 0x37, 0x45, 0xd1, 0x4e, 0xd3, 0x0f, 0x7c, 0x46, 0x1c, 0x4c, 0x8b, 0x7a, 0x5e, 0x60, 0xdf, +0x91, 0x44, 0xc0, 0x18, 0x3f, 0x9d, 0x64, 0x76, 0x2b, 0x72, 0x1a, 0xf8, 0x32, 0x0a, 0xbc, 0x7d, +0xa5, 0x20, 0x89, 0x6d, 0x94, 0xe0, 0xd0, 0x3c, 0xb5, 0x9e, 0x50, 0xcd, 0xad, 0xa8, 0x98, 0x9b, +0xfa, 0xd3, 0xe9, 0xc2, 0x4c, 0x2b, 0x27, 0xba, 0x79, 0x9c, 0xb8, 0xff, 0x02, 0x8d, 0xa3, 0x1e, +0x8d, 0x86, 0x79, 0xfa, 0x76, 0x82, 0x0f, 0x4a, 0x6a, 0x5b, 0xcd, 0x52, 0xa3, 0x85, 0x16, 0x17, +0x22, 0x52, 0x68, 0x6f, 0x6d, 0x5f, 0xd6, 0x1f, 0xa5, 0x81, 0xd1, 0x92, 0x45, 0xc6, 0x99, 0xe8, +0x6c, 0x2b, 0xdb, 0xbd, 0x41, 0xf7, 0x26, 0x5b, 0xdc, 0xf7, 0x59, 0x74, 0xc5, 0xee, 0xe5, 0xda, +0x21, 0x4d, 0xf5, 0x58, 0x5b, 0xfb, 0xa9, 0xde, 0x60, 0xfd, 0x50, 0xbb, 0x74, 0xa4, 0x9d, 0x0d, +0x51, 0x1e, 0x11, 0x6d, 0x67, 0x03, 0x87, 0x47, 0x45, 0xdc, 0xd9, 0x58, 0xe2, 0xef, 0x1e, 0x75, +0x27, 0xdb, 0x56, 0xe9, 0xc8, 0x3b, 0x13, 0xa3, 0x75, 0x53, 0x69, 0x7f, 0xa0, 0xf7, 0xe4, 0xa4, +0x7a, 0x08, 0x9e, 0x8d, 0x12, 0x1f, 0x11, 0xc9, 0xcf, 0xd0, 0xa8, 0x6c, 0xeb, 0xb7, 0x78, 0xfd, +0x7f, 0x0b, 0x3c, 0x49, 0x07, 0x6c, 0x2d, 0x44, 0x8a, 0xb5, 0x93, 0x18, 0xd1, 0xe9, 0x28, 0x8a, +0xf0, 0x94, 0x6a, 0x1d, 0x44, 0x2a, 0x45, 0x79, 0xf7, 0x07, 0x62, 0x7a, 0x1b, 0xb1, 0xff, 0x8c, +0x98, 0x6f, 0x4f, 0xd7, 0x42, 0xf4, 0x33, 0x22, 0xfa, 0x01, 0xf1, 0x9c, 0xf5, 0xfb, 0xdc, 0xe6, +0x6b, 0x23, 0xea, 0x76, 0x0a, 0x52, 0x9e, 0x35, 0xf0, 0xa9, 0x0c, 0x0a, 0x71, 0xe9, 0x7d, 0xe8, +0x2d, 0x20, 0x0c, 0xfe, 0x9a, 0xe4, 0xc9, 0x58, 0x9e, 0x3c, 0x75, 0x1f, 0x5d, 0x9d, 0xec, 0x6e, +0x25, 0xe5, 0xc9, 0xbd, 0xa4, 0x3c, 0x09, 0xb7, 0xfe, 0xee, 0xf5, 0xc9, 0xa4, 0xb0, 0xfd, 0xed, +0xeb, 0x94, 0x5b, 0xff, 0xaf, 0x53, 0x96, 0xaf, 0x53, 0xda, 0x6e, 0x4d, 0xe7, 0x6e, 0x0d, 0xd5, +0xd6, 0xd3, 0xc0, 0x73, 0xe9, 0x5c, 0x9d, 0x5c, 0x4a, 0x1d, 0x4d, 0x69, 0xa3, 0xed, 0x96, 0x4b, +0x1b, 0x8d, 0x29, 0x23, 0x20, 0xc8, 0x4d, 0x19, 0xcb, 0xd4, 0xec, 0x75, 0xa9, 0x5e, 0x56, 0x34, +0x05, 0x0c, 0x12, 0x20, 0xb0, 0x9b, 0x25, 0x34, 0x4a, 0x16, 0xe5, 0x55, 0xa4, 0x74, 0x90, 0xb1, +0x6e, 0x2e, 0x94, 0x3a, 0x0e, 0xa1, 0xe2, 0x0a, 0x75, 0xdc, 0xa9, 0x23, 0x8c, 0xb2, 0x7b, 0x54, +0x06, 0xc3, 0xde, 0x3c, 0x06, 0xdc, 0x30, 0xab, 0xa2, 0xd8, 0x4d, 0x51, 0xe0, 0x7f, 0xd6, 0x79, +0x14, 0x51, 0x87, 0xab, 0x7e, 0x94, 0x0a, 0x48, 0xb6, 0x53, 0x24, 0x6a, 0x67, 0x2a, 0x1d, 0xde, +0x64, 0x50, 0xec, 0xa4, 0x28, 0x76, 0x6e, 0x16, 0xe3, 0x9a, 0xd2, 0x48, 0x3a, 0x29, 0x92, 0x4e, +0x2c, 0xd1, 0x92, 0xdb, 0x75, 0x06, 0x47, 0x37, 0xc5, 0xd1, 0x8d, 0x71, 0xa4, 0x3b, 0xf5, 0x06, +0xb6, 0x97, 0xd2, 0x87, 0x0e, 0xe2, 0xdc, 0xef, 0x07, 0xa6, 0xea, 0x1c, 0x5a, 0x20, 0x70, 0x85, +0x43, 0xb0, 0xe2, 0xf2, 0x9e, 0x0a, 0x09, 0x36, 0x65, 0x33, 0xd8, 0x73, 0x1d, 0xe2, 0x50, 0x49, +0x89, 0x8a, 0x0a, 0x84, 0x84, 0x4b, 0x2a, 0x41, 0x35, 0x0f, 0xf2, 0xca, 0x31, 0xb8, 0xdb, 0x4a, +0x71, 0x0b, 0xda, 0x2b, 0x6f, 0xc5, 0xc8, 0xb6, 0x99, 0x10, 0xe4, 0x98, 0x74, 0x4c, 0xf9, 0x0d, +0x4e, 0x8a, 0xdd, 0x2d, 0x30, 0xa3, 0xcf, 0x26, 0xb0, 0xbc, 0x92, 0xe5, 0xa2, 0x50, 0xce, 0xbf, +0x63, 0x48, 0x64, 0x12, 0xaa, 0x9f, 0x1f, 0x11, 0x19, 0x9c, 0x8b, 0x00, 0xb1, 0xc0, 0x1e, 0x52, +0x43, 0xc4, 0xa5, 0x0e, 0xb8, 0x99, 0x27, 0xd8, 0x2a, 0xcc, 0x96, 0x1f, 0x48, 0x17, 0xb6, 0xa5, +0x54, 0x26, 0x86, 0x7a, 0x14, 0x52, 0x1f, 0x09, 0xc1, 0x81, 0x6b, 0xd8, 0x77, 0x5f, 0x98, 0x18, +0x8f, 0x47, 0x0e, 0xf0, 0xd8, 0x5f, 0x59, 0x06, 0x39, 0x24, 0x5b, 0x66, 0x65, 0xc8, 0x12, 0x42, +0x6a, 0x9f, 0x2f, 0x2f, 0xcf, 0x75, 0x96, 0x56, 0x9b, 0xcd, 0x07, 0x3e, 0xb3, 0xb9, 0xb7, 0xa3, +0x1c, 0xe6, 0xf1, 0x91, 0xf2, 0x94, 0x87, 0x96, 0xaa, 0x19, 0xe1, 0x6d, 0xe7, 0xf5, 0xb0, 0x6e, +0x28, 0x65, 0x19, 0x99, 0x2f, 0x9a, 0x37, 0x9d, 0x15, 0xf0, 0x1b, 0x70, 0x57, 0x2a, 0x4b, 0xc5, +0x07, 0x4a, 0x95, 0xc2, 0x13, 0x12, 0x36, 0xbb, 0xa0, 0xd3, 0x4d, 0x37, 0xd9, 0xd5, 0xd7, 0x08, +0x56, 0x2c, 0x83, 0x01, 0x56, 0xda, 0xff, 0x89, 0x3a, 0xb1, 0x11, 0xb0, 0x2d, 0x55, 0xa1, 0x64, +0xb1, 0x2e, 0x40, 0x92, 0xd2, 0xd5, 0x5a, 0x05, 0x02, 0x43, 0x61, 0x00, 0x1d, 0x6f, 0x80, 0x5b, +0x69, 0x5e, 0x71, 0xe0, 0x33, 0x3e, 0xbc, 0x84, 0x87, 0xa2, 0xa0, 0x42, 0x80, 0x95, 0x81, 0x58, +0x0b, 0x36, 0x1d, 0x5c, 0xc4, 0x64, 0x98, 0x1c, 0x12, 0xb6, 0xde, 0x3c, 0x7f, 0x7e, 0x90, 0x5f, +0xd4, 0xb6, 0x5d, 0x3f, 0xa7, 0x63, 0x67, 0xf1, 0xfc, 0xb4, 0xab, 0xcf, 0x4f, 0x75, 0x0a, 0xd0, +0xf2, 0x98, 0x3f, 0x90, 0x6e, 0xe1, 0x59, 0x2a, 0x02, 0xe2, 0xe6, 0x4e, 0x92, 0x3a, 0xfb, 0x2d, +0x5e, 0x5d, 0xf3, 0x1b, 0x63, 0x19, 0x18, 0x9f, 0xc7, 0x98, 0xd1, 0x04, 0x3b, 0x66, 0x1b, 0x8e, +0xf1, 0x5a, 0xa7, 0xef, 0x4e, 0x2e, 0x2e, 0xce, 0xde, 0x2b, 0x3b, 0xe2, 0x07, 0x45, 0xde, 0x01, +0xa6, 0x8f, 0x2b, 0xc3, 0x78, 0x90, 0xab, 0xdc, 0x68, 0xbb, 0x4d, 0x84, 0x0b, 0x2a, 0x67, 0xbb, +0xd4, 0xf7, 0x99, 0xa7, 0x8f, 0x4e, 0x78, 0x9f, 0xc0, 0x38, 0x32, 0x0c, 0x1c, 0xac, 0x72, 0x19, +0x09, 0x00, 0x99, 0xb5, 0xc2, 0x91, 0x70, 0x6b, 0x10, 0xd5, 0xcd, 0xaa, 0xf2, 0x49, 0x64, 0x17, +0xe7, 0x49, 0x1c, 0x82, 0xdf, 0x32, 0x3e, 0x33, 0x6e, 0x9b, 0xd2, 0x08, 0x57, 0x19, 0x4b, 0x61, +0x04, 0x93, 0x39, 0x34, 0x6a, 0x54, 0x0c, 0x8d, 0xd2, 0xb4, 0x06, 0x58, 0x2b, 0x00, 0xce, 0x6c, +0x7c, 0x15, 0x52, 0xb6, 0x7c, 0xc5, 0xc3, 0x6d, 0x29, 0xb7, 0xd1, 0x6c, 0x51, 0xf7, 0xb4, 0xb1, +0xc1, 0x1a, 0xc7, 0x4a, 0x88, 0xdd, 0x67, 0x65, 0x54, 0x10, 0xd6, 0xbe, 0xc6, 0xf1, 0x6c, 0x21, +0x03, 0x50, 0x27, 0xcf, 0x9e, 0xa9, 0x6b, 0x5c, 0x9e, 0x02, 0x4f, 0x10, 0x13, 0xd7, 0x87, 0x98, +0x83, 0x99, 0x4d, 0xda, 0xe0, 0x2b, 0xb8, 0xa3, 0x9c, 0x04, 0x4f, 0xfd, 0x43, 0x81, 0x57, 0xe8, +0x45, 0x8c, 0xde, 0xe5, 0x3f, 0x7e, 0x28, 0xa1, 0x3c, 0xc0, 0x23, 0x92, 0x5a, 0x20, 0x02, 0xd5, +0x77, 0x77, 0x4c, 0xba, 0x66, 0x73, 0x4a, 0x14, 0x70, 0xe4, 0x0b, 0x97, 0xf7, 0x65, 0x2d, 0x69, +0xa9, 0x30, 0x50, 0xed, 0xc4, 0x6d, 0xd1, 0xb0, 0xe5, 0xca, 0x33, 0x8f, 0xe1, 0xbf, 0xaf, 0xa7, +0xe7, 0x4e, 0x4d, 0xb7, 0xed, 0xd6, 0x5b, 0x11, 0x0b, 0x3d, 0x6a, 0xb3, 0x53, 0x97, 0x7b, 0x0e, +0x44, 0x66, 0xb5, 0x56, 0xab, 0x15, 0xcf, 0xb0, 0xd2, 0x1c, 0x56, 0xf8, 0x37, 0x55, 0x55, 0x2d, +0x8a, 0xba, 0xdc, 0xfc, 0xf6, 0xc3, 0xe4, 0x71, 0xd0, 0xef, 0x8b, 0x6c, 0x7c, 0x54, 0x47, 0x16, +0xae, 0xf8, 0x90, 0xfd, 0x11, 0xf8, 0xec, 0x23, 0x3c, 0x64, 0x12, 0xb6, 0x87, 0x9f, 0x60, 0x9b, +0xcf, 0xe9, 0xef, 0x70, 0x4b, 0xdb, 0x68, 0xe9, 0x8c, 0xc3, 0xbc, 0x9b, 0xaa, 0xb4, 0x55, 0x46, +0x81, 0x3f, 0x88, 0x8d, 0xde, 0x3a, 0x1b, 0xab, 0x20, 0xb7, 0xde, 0xd8, 0x08, 0xb6, 0xf3, 0x37, +0x1b, 0x43, 0x05, 0xdb, 0x5e, 0xb4, 0x39, 0xc2, 0xce, 0x7c, 0x07, 0x70, 0x55, 0xf1, 0x2d, 0x79, +0x9e, 0x83, 0xc2, 0x52, 0xcf, 0xea, 0xee, 0x05, 0xc6, 0x41, 0x5b, 0x76, 0xe0, 0x30, 0xf4, 0x11, +0x9d, 0x22, 0x6f, 0xb0, 0x62, 0xed, 0xbf, 0xe5, 0x09, 0x9c, 0x6c, 0x6e, 0x67, 0x2a, 0x39, 0x14, +0xb6, 0x9a, 0xe8, 0x11, 0x47, 0x08, 0x4b, 0xe8, 0x90, 0xfd, 0xcd, 0xe1, 0x53, 0x49, 0x03, 0x1a, +0x14, 0x26, 0x0d, 0xa9, 0x99, 0x29, 0xaa, 0x41, 0x49, 0x30, 0x6e, 0x02, 0x23, 0xab, 0x27, 0x39, +0x48, 0xfd, 0x3b, 0x4c, 0xcc, 0x7c, 0x27, 0x67, 0xda, 0xb5, 0x8f, 0x44, 0xd6, 0x77, 0xd4, 0x43, +0x75, 0x3c, 0x18, 0x1f, 0x0c, 0xa1, 0x7a, 0xa6, 0x7d, 0x19, 0x69, 0x3c, 0x39, 0xbe, 0xd5, 0xf1, +0xc3, 0xfc, 0x76, 0x8f, 0xba, 0x57, 0xaf, 0x16, 0x07, 0xc6, 0x67, 0xa3, 0x45, 0x9e, 0x12, 0xc8, +0x61, 0xde, 0x32, 0x37, 0x62, 0xc2, 0x65, 0x1c, 0xd3, 0xcc, 0x12, 0x2a, 0x93, 0x65, 0xd8, 0x54, +0x30, 0xd2, 0xd9, 0xd7, 0xb8, 0x30, 0x1e, 0xfb, 0x70, 0xde, 0xb4, 0x0e, 0x8a, 0x76, 0x34, 0x05, +0xd1, 0xcd, 0x40, 0xbc, 0xfb, 0x50, 0x06, 0x62, 0x6b, 0x0e, 0xe2, 0xb2, 0x0c, 0xc8, 0xf6, 0x1c, +0xc8, 0xd5, 0x0a, 0x10, 0x87, 0xf5, 0xe9, 0xc8, 0x93, 0x19, 0x98, 0x57, 0xaf, 0x5e, 0x15, 0xc0, +0xe4, 0x2e, 0x2f, 0x00, 0x42, 0x72, 0x97, 0x39, 0x90, 0x4b, 0xda, 0x19, 0x54, 0xea, 0x58, 0xbb, +0x54, 0xef, 0x7e, 0xcd, 0x92, 0x3e, 0xfd, 0x2e, 0x18, 0x3e, 0xc3, 0x9c, 0xef, 0x49, 0xd1, 0x7e, +0x86, 0x0a, 0x21, 0xd5, 0xeb, 0x7e, 0x19, 0x2b, 0xd0, 0x37, 0x0a, 0x33, 0x3d, 0x89, 0x2f, 0xff, +0xad, 0x8c, 0x1a, 0xc1, 0x62, 0xac, 0x0f, 0x48, 0x3e, 0x8c, 0x54, 0x6c, 0x14, 0xc5, 0x7f, 0x30, +0xf6, 0x2d, 0x8f, 0x86, 0x13, 0x7c, 0x9d, 0x26, 0x56, 0x33, 0xd2, 0x26, 0xaf, 0x47, 0xb0, 0xd7, +0x5b, 0x73, 0xa7, 0x91, 0xfd, 0xc9, 0x2d, 0xe8, 0x77, 0xcc, 0x7b, 0x0f, 0x9f, 0x6b, 0xd6, 0xe7, +0x87, 0xa8, 0xc2, 0x82, 0x1a, 0xb3, 0xfc, 0x4c, 0x82, 0x39, 0xd7, 0xb5, 0x7c, 0x56, 0x50, 0xf4, +0x8e, 0x46, 0x8e, 0x81, 0x22, 0x85, 0xcc, 0x55, 0xb4, 0xb4, 0xb1, 0xdc, 0xdd, 0x92, 0xc1, 0x5b, +0x7e, 0xcf, 0x9c, 0xda, 0x56, 0x21, 0x69, 0x61, 0x14, 0x38, 0xb7, 0xf6, 0x44, 0x8d, 0x69, 0xe7, +0x3d, 0x9b, 0x32, 0x1a, 0x55, 0x24, 0x0e, 0xe2, 0xb0, 0x9e, 0x3e, 0xb4, 0x46, 0x24, 0xe0, 0x0f, +0x6f, 0xfd, 0xd1, 0x10, 0xe8, 0x89, 0x51, 0x77, 0xf7, 0xea, 0x2b, 0x30, 0xbd, 0x0e, 0x02, 0xe9, +0x05, 0xd4, 0x01, 0x9f, 0x11, 0x33, 0x9a, 0x30, 0xd8, 0x83, 0x27, 0x79, 0x2c, 0xae, 0x5d, 0xf8, +0xca, 0x78, 0x2c, 0x55, 0xb5, 0x80, 0x4d, 0x75, 0xd9, 0x61, 0x6d, 0xc8, 0x5b, 0xcd, 0x92, 0xe7, +0x12, 0xa1, 0xdd, 0xb7, 0x37, 0x85, 0xab, 0x7f, 0x13, 0x3b, 0x18, 0x41, 0xac, 0xa5, 0x17, 0x4a, +0xde, 0xab, 0x63, 0xfb, 0xe2, 0x95, 0xf9, 0xfc, 0x6f, 0x12, 0xd7, 0xd7, 0x62, 0xa8, 0xe8, 0x3e, +0x29, 0xb8, 0xad, 0x86, 0xec, 0x53, 0xee, 0xcd, 0xc0, 0xf0, 0x6a, 0x35, 0x8c, 0x1f, 0x10, 0xea, +0x8b, 0x49, 0xaa, 0x4e, 0x31, 0xe0, 0xad, 0xbe, 0x59, 0x62, 0xce, 0x88, 0x0e, 0x30, 0x70, 0x4f, +0xe8, 0x85, 0xeb, 0x21, 0x2b, 0xc1, 0x28, 0x08, 0x27, 0x62, 0x32, 0x82, 0x69, 0xf0, 0xa5, 0xaa, +0x64, 0xf2, 0xd9, 0x9d, 0x4d, 0x28, 0x9c, 0xd2, 0x07, 0x75, 0x6a, 0xc1, 0x85, 0xe4, 0xb6, 0xf8, +0x36, 0xca, 0xb7, 0xd0, 0xb3, 0x63, 0xd0, 0xba, 0x20, 0xc4, 0x2c, 0xf0, 0xfa, 0xda, 0x0a, 0x6d, +0x54, 0x08, 0xeb, 0x07, 0xeb, 0x06, 0xf4, 0xc7, 0x9a, 0x50, 0xa9, 0x2e, 0xbf, 0x58, 0x37, 0x86, +0x54, 0x23, 0xa3, 0xae, 0xab, 0x32, 0x77, 0x73, 0x42, 0xbe, 0xbd, 0x4e, 0xfa, 0x90, 0x39, 0xb6, +0xdc, 0x25, 0xc3, 0xa9, 0xce, 0xea, 0x2d, 0xdd, 0x36, 0xf7, 0x1b, 0xbe, 0x0b, 0x69, 0x55, 0x0e, +0xd5, 0x9b, 0x2f, 0x53, 0x8c, 0x49, 0xd4, 0xce, 0xfd, 0x70, 0x84, 0x22, 0xf8, 0x13, 0xd7, 0x01, +0x46, 0x29, 0x71, 0xc2, 0x35, 0xbe, 0x68, 0x06, 0x97, 0xbe, 0xf6, 0x75, 0xba, 0x2e, 0x58, 0x7d, +0xbe, 0x9d, 0x64, 0x3e, 0x45, 0xbc, 0x60, 0x68, 0xc0, 0xf8, 0xe2, 0x5d, 0x03, 0x17, 0x04, 0x70, +0xe2, 0x6a, 0x18, 0x9d, 0x5b, 0xe3, 0xbb, 0x48, 0x79, 0x5e, 0x24, 0xd6, 0x3f, 0x19, 0x0b, 0xb5, +0x4e, 0x91, 0x60, 0xcc, 0x32, 0xfa, 0x1a, 0x31, 0xa1, 0x13, 0xa4, 0xf5, 0x85, 0xf0, 0x62, 0x49, +0xe8, 0xb1, 0x94, 0x6d, 0x97, 0xd9, 0x77, 0xbd, 0xe0, 0xde, 0xd2, 0x95, 0x27, 0xb8, 0x73, 0x07, +0x64, 0x58, 0x0f, 0x1b, 0x12, 0xcd, 0x54, 0x89, 0xa6, 0x22, 0xd9, 0xd8, 0xa5, 0x64, 0xa2, 0xb7, +0x37, 0x92, 0x52, 0x6d, 0x5a, 0xea, 0x9d, 0x5c, 0xb8, 0x71, 0x12, 0x86, 0x1e, 0x7a, 0xe5, 0x04, +0xbe, 0x27, 0xfd, 0xb5, 0x6a, 0xb6, 0xf8, 0x89, 0x84, 0xa9, 0x52, 0xf1, 0x9a, 0x2e, 0x16, 0xad, +0x28, 0xc3, 0xfa, 0x23, 0xcf, 0xab, 0x6f, 0xa2, 0x5e, 0x0d, 0x32, 0xda, 0xd9, 0x9c, 0x91, 0xc6, +0xfd, 0x7c, 0xd5, 0x75, 0x25, 0xd5, 0x94, 0x44, 0xfa, 0xab, 0x5b, 0x07, 0x56, 0xae, 0x4d, 0xa2, +0xb8, 0x8f, 0x5f, 0x9d, 0x74, 0x85, 0x4e, 0x65, 0xe4, 0xd5, 0x92, 0xd2, 0x79, 0x3a, 0xc1, 0x8a, +0xa6, 0xba, 0x74, 0xbd, 0x1a, 0x8f, 0xe7, 0x49, 0x1d, 0x9a, 0x40, 0x32, 0x38, 0xcf, 0x94, 0x7e, +0xe7, 0x6a, 0x83, 0x9c, 0xa9, 0xb6, 0x63, 0x40, 0xd8, 0xf9, 0xee, 0xac, 0xf9, 0xdf, 0x6e, 0xb9, +0x12, 0xa6, 0xba, 0x65, 0x99, 0xaa, 0x7e, 0x1e, 0x5b, 0xcd, 0xf4, 0xa4, 0xee, 0x80, 0xdc, 0x8c, +0xe9, 0x7d, 0x66, 0x02, 0x12, 0xc0, 0x35, 0xbc, 0xb4, 0xb2, 0xba, 0x04, 0x4d, 0xb6, 0xdb, 0x24, +0xf6, 0xc8, 0x90, 0x00, 0x82, 0xa2, 0xab, 0x39, 0x9a, 0xd6, 0x46, 0x02, 0xf2, 0xbc, 0x16, 0xe0, +0xa2, 0x18, 0xc9, 0x5d, 0xae, 0xbc, 0x9a, 0x82, 0xa2, 0x8c, 0x1f, 0xe5, 0x8e, 0xb1, 0x39, 0x65, +0xe8, 0x60, 0x86, 0xac, 0xbb, 0xea, 0xf3, 0xcf, 0xae, 0x9f, 0xe6, 0xd4, 0x88, 0xc5, 0xeb, 0xe9, +0x05, 0xd0, 0x53, 0xd3, 0x7b, 0x54, 0xfd, 0xba, 0x73, 0xd3, 0x52, 0xfb, 0x17, 0x73, 0xf2, 0x85, +0x82, 0xd3, 0xe8, 0xd3, 0x62, 0x3f, 0x67, 0x92, 0xe4, 0x69, 0x88, 0x89, 0x90, 0xc0, 0x0f, 0x4a, +0x18, 0x48, 0x29, 0xa2, 0x44, 0xc5, 0x14, 0x8a, 0x12, 0x65, 0x45, 0x78, 0xea, 0xa4, 0x43, 0x8b, +0x42, 0x82, 0x22, 0xe6, 0xa9, 0xb7, 0xfa, 0x73, 0xe6, 0x33, 0x9e, 0x00, 0x27, 0xb0, 0xb4, 0x27, +0x02, 0x6f, 0x24, 0x99, 0x65, 0x38, 0x8c, 0x1b, 0xab, 0x17, 0xe1, 0x8b, 0x68, 0xd6, 0x81, 0xd6, +0x8c, 0xe8, 0x5c, 0xa6, 0xb9, 0xb8, 0xa0, 0x17, 0xd8, 0x30, 0x61, 0x50, 0x38, 0x3d, 0x8d, 0x7a, +0x8d, 0x31, 0x3f, 0xec, 0xed, 0x7d, 0x8d, 0xeb, 0xe4, 0x1f, 0x7b, 0x5f, 0x99, 0x2d, 0x6b, 0x39, +0xda, 0x18, 0x9f, 0xca, 0x1c, 0x11, 0xee, 0xe4, 0x3f, 0xd4, 0x7a, 0x02, 0xbf, 0xf3, 0x1f, 0x6b, +0x1a, 0xe0, 0xf7, 0xf2, 0xe3, 0xf9, 0x63, 0x15, 0x1b, 0xdc, 0x10, 0xba, 0x35, 0xf8, 0x73, 0xda, +0xc3, 0x9e, 0xc3, 0x8f, 0x97, 0x57, 0x70, 0xfd, 0x8f, 0xcb, 0x8f, 0x17, 0x58, 0x0d, 0x85, 0xdc, +0x99, 0xf7, 0xa7, 0x2a, 0x88, 0xaf, 0xa2, 0xe5, 0xca, 0xb9, 0xa1, 0x63, 0x03, 0x02, 0x95, 0x17, +0x3d, 0xea, 0x18, 0x93, 0x80, 0xf2, 0xd2, 0xf8, 0xde, 0xe2, 0xd8, 0xda, 0x84, 0x3c, 0x34, 0xaa, +0xa2, 0x34, 0x88, 0xad, 0x50, 0xca, 0xd8, 0xc9, 0xa1, 0x56, 0x1a, 0x7b, 0x59, 0x92, 0x7c, 0xd8, +0xb0, 0xfb, 0x30, 0xdd, 0xb1, 0xfe, 0xee, 0xea, 0xc3, 0x7b, 0xa2, 0x8c, 0x2c, 0xee, 0x97, 0xc1, +0x6f, 0x67, 0x50, 0x1f, 0x96, 0x68, 0x42, 0x39, 0x7e, 0xf5, 0x68, 0xde, 0xd3, 0x51, 0xfb, 0xce, +0x0f, 0x26, 0x1e, 0x73, 0x06, 0x8c, 0xb4, 0x5a, 0x2d, 0x43, 0x63, 0x46, 0xfc, 0xd9, 0x08, 0xc0, +0x3b, 0xe1, 0xbe, 0x13, 0x4c, 0x5a, 0x82, 0xc9, 0x73, 0xec, 0x14, 0x18, 0xa3, 0x3f, 0x4d, 0xc4, +0xfb, 0xe3, 0xfc, 0x21, 0x1e, 0xf0, 0x04, 0xd8, 0x33, 0xa7, 0xfd, 0x58, 0xed, 0xf9, 0xb1, 0x11, +0x7f, 0x44, 0x46, 0x63, 0xac, 0xe3, 0x7e, 0x98, 0xdf, 0x4e, 0x53, 0xa1, 0x37, 0x66, 0x81, 0xf5, +0xb3, 0x28, 0x0a, 0xa2, 0xb4, 0x4e, 0x78, 0x6d, 0x31, 0xbc, 0xb6, 0x6e, 0xaa, 0xac, 0xe5, 0xd6, +0xf7, 0x5a, 0xcc, 0x32, 0xfc, 0xc4, 0x2b, 0x98, 0x6d, 0xf7, 0xf9, 0x4b, 0x44, 0x93, 0x5d, 0xb8, +0x82, 0x17, 0x2b, 0x9f, 0xaa, 0x73, 0x23, 0x58, 0xdb, 0x5c, 0x82, 0x74, 0xe3, 0xcd, 0xc1, 0xe6, +0x05, 0x6b, 0x7b, 0x8c, 0x46, 0xa9, 0x52, 0xc6, 0x1a, 0x5b, 0xcf, 0x5d, 0x00, 0x8c, 0xae, 0xd4, +0xf7, 0x4b, 0xaa, 0x91, 0xb8, 0x20, 0xcb, 0x3c, 0x1b, 0x72, 0x48, 0xdc, 0x1a, 0xae, 0x82, 0x3d, +0xf5, 0x6d, 0xb9, 0x48, 0x65, 0x17, 0x6a, 0x05, 0xad, 0x0a, 0x65, 0xbd, 0x02, 0x01, 0x2b, 0xf2, +0xf5, 0x1b, 0x7f, 0xc6, 0xb7, 0x0a, 0x17, 0x3e, 0xe4, 0x72, 0x6d, 0x0d, 0xf4, 0x85, 0x75, 0x63, +0x88, 0x3e, 0x55, 0x4f, 0x20, 0xb0, 0xa5, 0x3d, 0x74, 0x0b, 0xe2, 0x33, 0x3e, 0xf0, 0x6b, 0x7f, +0xea, 0x57, 0xbf, 0xae, 0xad, 0xbe, 0xe7, 0xdc, 0xaa, 0x21, 0x46, 0x04, 0xd8, 0x13, 0x30, 0x83, +0xd7, 0x1f, 0x8d, 0xaa, 0x19, 0xb0, 0x41, 0x14, 0x78, 0x63, 0x3a, 0x1d, 0x37, 0x7f, 0x04, 0x27, +0xdb, 0x8d, 0xb3, 0xfc, 0x21, 0x9c, 0xd4, 0x57, 0xe1, 0xe1, 0x7b, 0xfe, 0x17, 0x70, 0xf2, 0x7a, +0x23, 0x3a, 0xb3, 0xbe, 0x1c, 0x3e, 0x2e, 0xd3, 0x14, 0x91, 0x31, 0x62, 0x3e, 0x5e, 0xd1, 0x04, +0xb1, 0xa1, 0x16, 0x87, 0x15, 0x6d, 0x0e, 0xf9, 0xde, 0xd2, 0x7c, 0x37, 0x69, 0x0d, 0xd4, 0x1f, +0xfd, 0xc2, 0x8f, 0x3a, 0x98, 0x53, 0x8d, 0xec, 0xc0, 0x23, 0xb2, 0x5b, 0xb1, 0xa1, 0x21, 0xf9, +0xae, 0x58, 0x7d, 0xce, 0x72, 0x32, 0x38, 0x8d, 0x3d, 0x47, 0x8b, 0x9f, 0x18, 0x2a, 0x10, 0xf2, +0xea, 0x2d, 0x09, 0xfb, 0x2a, 0x7e, 0x8c, 0x05, 0x5d, 0x4f, 0x6b, 0xae, 0x9a, 0xa9, 0xc2, 0x76, +0x4e, 0x65, 0xf5, 0xe9, 0x17, 0x9d, 0x0a, 0x7a, 0x59, 0x1e, 0x1e, 0xb3, 0x7d, 0x55, 0x14, 0x5f, +0xfc, 0x06, 0x72, 0x81, 0x27, 0x99, 0x57, 0x39, 0xd5, 0x55, 0x92, 0x70, 0x7f, 0x90, 0xf9, 0xf2, +0x55, 0xf2, 0xb1, 0x4e, 0x7d, 0xa5, 0xbf, 0x73, 0x79, 0xd8, 0xd6, 0x5f, 0x34, 0xfd, 0x2f, 0xe6, +0xde, 0x0e, 0x11, 0xe9, 0x54, 0x00, 0x00}; +#endif /*__VISUALIZATION_HTML_H__*/ diff --git a/src/web/html/tmp/about.html b/src/web/html/tmp/about.html new file mode 100644 index 00000000..820fd356 --- /dev/null +++ b/src/web/html/tmp/about.html @@ -0,0 +1,100 @@ + + + + About + + + + + + + + + +
+
+

About AhoyDTU

+
+
+
Used Libraries
+
+ + + + + + + + +
+
Contact Information
+
+
+
Github Repository
+ +
+
+
Discord Chat
+ +
+
+
E-Mail
+ +
+
+
+
+ + + + diff --git a/src/web/html/tmp/index.html b/src/web/html/tmp/index.html new file mode 100644 index 00000000..a2da0653 --- /dev/null +++ b/src/web/html/tmp/index.html @@ -0,0 +1,263 @@ + + + + Index + + + + + + + + + +
+
+

+ Uptime:
+ ESP-Time: +

+

+ System Infos: +

+
+
+

+ +
+

Support this project:

+ +

+ This project was started from this discussion. (Mikrocontroller.net) +

+
+
+
+ + + + diff --git a/src/web/html/tmp/login.html b/src/web/html/tmp/login.html new file mode 100644 index 00000000..81c4051d --- /dev/null +++ b/src/web/html/tmp/login.html @@ -0,0 +1,43 @@ + + + + Login + + + + + + + + +
+
+
+
+

AhoyDTU

+
+
+
+
+
+
+
+
+ + + diff --git a/src/web/html/tmp/save.html b/src/web/html/tmp/save.html new file mode 100644 index 00000000..1b85d690 --- /dev/null +++ b/src/web/html/tmp/save.html @@ -0,0 +1,102 @@ + + + + Save + + + + + + + + + +
+
+
Saving settings...
+
+
+ + + + diff --git a/src/web/html/tmp/serial.html b/src/web/html/tmp/serial.html new file mode 100644 index 00000000..28d56965 --- /dev/null +++ b/src/web/html/tmp/serial.html @@ -0,0 +1,132 @@ + + + + Serial Console + + + + + + + + + +
+
+
+ +
+
+
console active:
+
Uptime:
+
+ + +
+
+
+
+ + + + diff --git a/src/web/html/tmp/setup.html b/src/web/html/tmp/setup.html new file mode 100644 index 00000000..bebdaab9 --- /dev/null +++ b/src/web/html/tmp/setup.html @@ -0,0 +1,1000 @@ + + + + Setup + + + + + + + + + +
+
+
+
+ +
+
+ Device Host Name +
+
Device Name
+
+
+
+
Reboot Ahoy at midnight
+
+
+
+
Dark Mode
+
+
(empty browser cache or use CTRL + F5 after reboot to apply this setting)
+
+
+
+ System Config +

Status LEDs

+
+ +

Radio (NRF24L01+)

+
+ +

Radio (CMT2300A)

+
(ESP32 only)
+ +

Serial Console

+
+
print inverter data
+
+
+
+
Serial Debug
+
+
+
+
Interval [s]
+
+
+
+
+ + +
+
+ WiFi + +
+
AP Password (min. length: 8)
+
+
+ +

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

+ +
+
Search Networks
+
+
+ +
+
Avail Networks
+
+ +
+
+
+
SSID
+
+
+
+
SSID is hidden
+
+
+
+
Password
+
+
+
+
+ Static IP (optional) +

+ Leave fields blank for DHCP
+ The following fields are parsed in this format: 192.168.4.1 +

+
+
IP Address
+
+
+
+
Submask
+
+
+
+
DNS 1
+
+
+
+
DNS 2
+
+
+
+
Gateway
+
+
+
+
+ + +
+
+ Protection +
+
Admin Password
+
+
+

Select pages which should be protected by password

+
+
+
+ + +
+
+ Inverter +
+
+
+
+
+
+

Note

+

A 'max module power' value of '0' disables the channel in 'live' view

+
+
+

General

+
+
+
+
Interval [s]
+
+
+
+
Max retries per Payload
+
+
+
+
Reset values and YieldDay at midnight
+
+
+
+
Reset values when inverter polling pauses at sunset
+
+
+
+
Reset values when inverter status is 'not available'
+
+
+
+
Reset 'max' values at midnight
+
+
+
+
Start without time sync (useful in AP-Only-Mode)
+
+
+
+
Yield Efficiency (should be between 0.95 and 0.96)
+
+
+
+
+ + +
+
+ NTP Server +
+
NTP Server / IP
+
+
+
+
NTP Port
+
+
+
+
NTP Interval (in Minutes, min. 5 Minutes)
+
+
+
+
set System time
+
+ +
+ +
+
+
+
System Time
+
+
+
+
+ + +
+
+ Sunrise & Sunset +
+
Latitude (decimal)
+
+
+
+
Longitude (decimal)
+
+
+
+
Offset (pre sunrise, post sunset)
+
+
+
+
Pause polling inverters during night
+
+
+
+
+ + +
+
+ MQTT +
+
Broker / Server IP
+
+
+
+
Port
+
+
+
+
Client Id (optional)
+
+
+
+
Username (optional)
+
+
+
+
Password (optional)
+
+
+
+
Topic
+
+
+

Send Inverter data in a fixed interval, even if there is no change. A value of '0' disables the fixed interval. The data is published once it was successfully received from inverter. (default: 0)

+
+
Interval [s]
+
+
+
+
Discovery Config (homeassistant)
+
+ + +
+
+
+
+ + +
+
+ Display Config +
+
+
+
Turn off while inverters are offline
+
+
+
+
Enable Screensaver (pixel shifting, OLED only)
+
+
+
+
Luminance
+
+
+

Pinout

+
+
+
+ +
+
Reboot device after successful save
+
+ + +
+
+ +
+
+ ERASE SETTINGS (not WiFi) +
+ Import / Export JSON Settings +
+
Import
+
+
+
+
+
+
+
+
+
+
+
Export
+
+ Export settings (JSON file) (only values, passwords will be removed!) +
+
+
+
+
+
+ + + + diff --git a/src/web/html/tmp/style.css b/src/web/html/tmp/style.css new file mode 100644 index 00000000..95cbff3b --- /dev/null +++ b/src/web/html/tmp/style.css @@ -0,0 +1,781 @@ +html, body { + font-family: Arial; + margin: 0; + padding: 0; + height: 100%; + min-height: 100%; + background-color: var(--bg); + color: var(--fg); +} + +h2 { + padding-left: 10px; +} + +span, li, h3, label, fieldset { + color: var(--fg); +} + +fieldset, input[type=submit], .btn { + border-radius: 4px; +} + +input[type=file] { + width: 100%; +} + +textarea { + color: var(--fg); + background-color: var(--bg); +} + +#live span { + color: var(--fg2); +} + +.topnav { + background-color: var(--nav-bg); + position: fixed; + top: 0; + width: 100%; +} + +.topnav a { + color: var(--fg2); + padding: 14px 14px; + text-decoration: none; + font-size: 17px; + display: block; +} + +#topnav a { + color: #fff; +} + +.topnav a.icon { + top: 0; + left: 0; + background: var(--nav-bg); + display: block; + position: absolute; +} + +.topnav a:hover { + background-color: var(--primary-hover) !important; +} + +.topnav .info { + color: var(--fg2); + position: absolute; + right: 24px; + top: 5px; +} + +.topnav .mobile { + display: none; +} + +svg.icon { + vertical-align: middle; + display: inline-block; + margin-top:-4x; + padding: 5px 7px 5px 0px; +} + +.icon-info { + fill: var(--info); +} + +.icon-warn { + fill: var(--warn); +} + +.icon-success { + fill: var(--success); +} + +.wifi { + fill: var(--fg2); +} + +.title { + background-color: var(--primary); + color: #fff !important; + padding: 15px 14px 16px 80px !important +} + +.topnav .icon span { + display: block; + width: 30px; + height: 3px; + margin-bottom: 5px; + position: relative; + background: #fff; + border-radius: 2px; +} + +.topnav .active { + background-color: var(--nav-active); +} + +span.seperator { + width: 100%; + height: 1px; + margin: 5px 0px 5px; + background-color: #494949; + display: block; +} + +#content { + max-width: 1140px; +} + +.total-h { + background-color: var(--total-head-title); + color: var(--fg2); +} + +.total-bg { + background-color: var(--total-bg); + color: var(--fg2); +} + +.iv-h { + background-color: var(--iv-head-title); + color: var(--fg2); +} + +.iv-bg { + background-color: var(--iv-head-bg); + color: var(--fg2); +} + +.iv-h-dis { + background-color: var(--iv-dis-title); + color: var(--fg2); +} + +.iv-bg-dis { + background-color: var(--iv-dis); + color: var(--fg2); +} + +.ch-h { + background-color: var(--ch-head-title); + color: var(--fg2); +} + +.ch-bg { + background-color: var(--ch-head-bg); + color: var(--fg2); +} + +.ts-h { + background-color: var(--ts-head); + color: var(--fg2); +} + +.ts-bg { + background-color: var(--ts-bg); + color: var(--fg2); +} + +.hr { + border-top: 1px solid var(--iv-head-title); + margin: 1rem 0 1rem; +} + +p { + text-align: justify; + font-size: 13pt; + color: var(--fg); +} + +#footer { + background-color: var(--footer-bg); +} + +.row { display: flex; max-width: 100%; flex-wrap: wrap; } +.col { flex: 1 0 0%; } + +.col-1, .col-2, .col-3, .col-4, +.col-5, .col-6, .col-7, .col-8, +.col-9, .col-10, .col-11, .col-12 { flex: 0 0 auto; } + +.col-1 { width: 8.333333333%; } +.col-2 { width: 16.66666667%; } +.col-3 { width: 25%; } +.col-4 { width: 33.33333333%; } +.col-5 { width: 41.66666667%; } +.col-6 { width: 50%; } +.col-7 { width: 58.33333333%; } +.col-8 { width: 66.66666667%; } +.col-9 { width: 75%; } +.col-10 { width: 83.33333333%; } +.col-11 { width: 91.66666667%; } +.col-12 { width: 100%; } + +.p-1 { padding: 0.25rem; } +.p-2 { padding: 0.5rem; } +.p-3 { padding: 1rem; } +.p-4 { padding: 1.5rem; } +.p-5 { padding: 3rem; } + +.px-1 { padding: 0 0.25rem 0 0.25rem; } +.px-2 { padding: 0 0.5rem 0 0.5rem; } +.px-3 { padding: 0 1rem 0 1rem; } +.px-4 { padding: 0 1.5rem 0 1.5rem; } +.px-5 { padding: 0 3rem 0 3rem; } + +.py-1 { padding: 0.25rem 0 0.25rem; } +.py-2 { padding: 0.5rem 0 0.5rem; } +.py-3 { padding: 1rem 0 1rem; } +.py-4 { padding: 1.5rem 0 1.5rem; } +.py-5 { padding: 3rem 0 3rem; } + +.mx-1 { margin: 0 0.25rem 0 0.25rem; } +.mx-2 { margin: 0 0.5rem 0 0.5rem; } +.mx-3 { margin: 0 1rem 0 1rem; } +.mx-4 { margin: 0 1.5rem 0 1.5rem; } +.mx-5 { margin: 0 3rem 0 3rem; } + +.my-1 { margin: 0.25rem 0 0.25rem; } +.my-2 { margin: 0.5rem 0 0.5rem; } +.my-3 { margin: 1rem 0 1rem; } +.my-4 { margin: 1.5rem 0 1.5rem; } +.my-5 { margin: 3rem 0 3rem; } + +.mt-1 { margin-top: 0.25rem } +.mt-2 { margin-top: 0.5rem } +.mt-3 { margin-top: 1rem } +.mt-4 { margin-top: 1.5rem } +.mt-5 { margin-top: 3rem } + +.mb-1 { margin-bottom: 0.25rem } +.mb-2 { margin-bottom: 0.5rem } +.mb-3 { margin-bottom: 1rem } +.mb-4 { margin-bottom: 1.5rem } +.mb-5 { margin-bottom: 3rem } + +.fs-1 { font-size: 3.5rem; } +.fs-2 { font-size: 3rem; } +.fs-3 { font-size: 2.5rem; } +.fs-4 { font-size: 2rem; } +.fs-5 { font-size: 1.75rem; } +.fs-6 { font-size: 1.5rem; } +.fs-7 { font-size: 1.25rem; } +.fs-8 { font-size: 1rem; } +.fs-9 { font-size: 0.75rem; } +.fs-10 { font-size: 0.5rem; } + +.a-r { text-align: right; } +.a-c { text-align: center; } + +.d-none { display: none !important; } +.d-block { display: block !important; } + +.row > * { + padding-left: 0.5rem; + padding-right: 0.5rem; +} + +*, ::after, ::before { + box-sizing: border-box; +} + +/* sm */ +@media(min-width: 768px) { + .col-sm-1 { width: 8.333333333%; } + .col-sm-2 { width: 16.66666667%; } + .col-sm-3 { width: 25%; } + .col-sm-4 { width: 33.33333333%; } + .col-sm-5 { width: 41.66666667%; } + .col-sm-6 { width: 50%; } + .col-sm-7 { width: 58.33333333%; } + .col-sm-8 { width: 66.66666667%; } + .col-sm-9 { width: 75%; } + .col-sm-10 { width: 83.33333333%; } + .col-sm-11 { width: 91.66666667%; } + .col-sm-12 { width: 100%; } + + .mb-sm-1 { margin-bottom: 0.25rem } + .mb-sm-2 { margin-bottom: 0.5rem } + .mb-sm-3 { margin-bottom: 1rem } + .mb-sm-4 { margin-bottom: 1.5rem } + .mb-sm-5 { margin-bottom: 3rem } + + .fs-sm-1 { font-size: 3.5rem; } + .fs-sm-2 { font-size: 3rem; } + .fs-sm-3 { font-size: 2.5rem; } + .fs-sm-4 { font-size: 2rem; } + .fs-sm-5 { font-size: 1.75rem; } + .fs-sm-6 { font-size: 1.5rem; } + .fs-sm-7 { font-size: 1.25rem; } + .fs-sm-8 { font-size: 1rem; } + + .d-sm-block { display: block !important;} + .d-sm-none { display: none !important; } +} + +/* md */ +@media(min-width: 992px) { + .col-md-1 { width: 8.333333333%; } + .col-md-2 { width: 16.66666667%; } + .col-md-3 { width: 25%; } + .col-md-4 { width: 33.33333333%; } + .col-md-5 { width: 41.66666667%; } + .col-md-6 { width: 50%; } + .col-md-7 { width: 58.33333333%; } + .col-md-8 { width: 66.66666667%; } + .col-md-9 { width: 75%; } + .col-md-10 { width: 83.33333333%; } + .col-md-11 { width: 91.66666667%; } + .col-md-12 { width: 100%; } +} + +table { + border-collapse: collapse; + width: 100%; +} + +th { + text-align: inherit; +} + +.table td, .table th { + padding: .75rem; + border-bottom: 1px solid var(--table-border); +} + +#wrapper { + min-height: 100%; +} + +#content { + padding: 50px 20px 120px 20px; + overflow: auto; +} + +#footer { + height: 121px; + margin-top: -121px; + width: 100%; + font-size: 13px; +} + +#footer .right { + color: #bbb; + margin: 6px 25px; + text-align: right; +} + +#footer .left { + color: #bbb; + margin: 23px 0px 0px 25px; +} + +#footer ul { + list-style-type: none; + margin: 20px auto; + padding: 0; +} + +#footer ul li, #footer a { + color: #bbb; + margin-bottom: 10px; + padding-left: 5px; + font-size: 13px; +} + +#footer a:hover { + color: #fff; +} + +.hide { + display: none !important; +} + +@media only screen and (min-width: 992px) { + .topnav { + width: 230px !important; + height: 100%; + } + + .topnav a.icon { + display: none !important; + } + + .topnav a { + padding: 14px 24px; + } + + .topnav .title { + padding-left: 24px !important; + } + + .topnav .mobile { + display: block; + } + + .topnav .info { + top: auto !important; + right: auto !important; + bottom: 14px; + left: 24px; + } + + #content { + padding: 15px 15px 120px 250px; + } + + #footer .left { + margin-left: 250px !important; + } +} + +p.lic, p.lic a { + font-size: 8pt; + color: #999; +} + +.des { + margin-top: 20px; + font-size: 13pt; + color: var(--secondary); +} + +.s_active, .s_collapsible:hover { + background-color: var(--primary-hover); + color: #fff; +} + +.s_content { + display: none; + overflow: hidden; +} + +.s_collapsible { + background-color: var(--primary); + color: white; + cursor: pointer; + padding: 12px; + width: 100%; + border: none; + text-align: left; + outline: none; + font-size: 15px; + margin-bottom: 5px; +} + +.subdes { + font-size: 12pt; + color: var(--secondary); + margin-left: 7px; +} + +.subsubdes { + font-size:12pt; + color:var(--secondary); + margin: 0 0 7px 12px; +} + +a:link, a:visited { + text-decoration: none; + font-size: 13pt; + color: var(--secondary); +} + +a:hover, a:focus { + color: #f00; +} + +a.btn { + background-color: var(--primary); + color: #fff; + padding: 7px 15px 7px 15px; + display: inline-block; +} + +a.btn:hover { + background-color: var(--primary-hover) !important; +} + +input, select { + padding: 7px; + font-size: 13pt; +} + +input[type=text], input[type=password], select, input[type=number] { + width: 100%; + box-sizing: border-box; + border: 1px solid #ccc; + border-radius: 4px; + background-color: var(--input-bg); + color: var(--fg); +} + +input:invalid { + border: 2px solid #f00 !important; + background-color: var(--invalid-bg) !important; +} + +input.sh { + max-width: 150px !important; + margin-right: 10px; +} + +input.btnDel { + background-color: #c00 !important; +} + +input.btn { + background-color: var(--primary); + color: #fff; + border: 0px; + padding: 7px 20px 7px 20px; + margin-bottom: 10px; + text-transform: uppercase; + cursor: pointer; +} + +input.btn:hover { + background-color: #044e86; +} + +input.cb { + margin-bottom: 15px; + margin-top: 10px; +} + +label { + width: 20%; + display: inline-block; + font-size: 12pt; + padding-right: 10px; + margin: 10px 0px 0px 15px; + vertical-align: top; +} + +pre { + white-space: pre-wrap; +} + +.left { + float: left; +} + +.right { + float: right; +} + +.subgrp { + float: left; + width: 220px; +} + +div.ModPwr, div.ModName, div.YieldCor { + width:70%; + display: inline-block; +} + +div.hr { + height: 1px; + border-top: 1px solid #ccc; + margin: 10px 0px 10px; +} + +#note { + margin: 10px 10px 10px 10px; + padding-top: 10px; + width: 100%; +} + +#login { + width: 450px; + height: 200px; + border: 1px solid #ccc; + background-color: var(--input-bg); + position: absolute; + top: 50%; + left: 50%; + margin-top: -160px; + margin-left: -225px; +} + +@media(max-width: 500px) { + div.ch .unit, div.ch-iv .unit { + font-size: 18px; + } + + div.ch { + width: 170px; + min-height: 100px + } + + .subgrp { + width: 180px; + } + + #login { + margin-left: -150px; + width: 300px; + } +} + +#serial { + width: 100%; +} + +#content .serial { + max-width: 1000px; +} + +.dot { + height: 15px; + width: 15px; + background-color: #f00; + border-radius: 50%; + display: inline-block; + margin-top: 15px; +} + + +.head { + background-color: var(--primary); + color: #fff; +} + + +.css-tooltip{ + position: relative; +} +.css-tooltip:hover:after{ + content:attr(data-tooltip); + background:#000; + padding:5px; + border-radius:3px; + display: inline-block; + position: absolute; + transform: translate(-50%,-100%); + margin:0 auto; + color:#FFF; + min-width:100px; + min-width:150px; + top:-5px; + left: 50%; + text-align:center; +} +.css-tooltip:hover:before { + top:-5px; + left: 50%; + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; + pointer-events: none; + border-color: rgba(0, 0, 0, 0); + border-top-color: #000; + border-width: 5px; + margin-left: -5px; + transform: translate(0,0px); +} + +#modal { + max-width: 700px; + margin: 1.75rem auto; +} + +.modal { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1072; + display: block; +} + +#modal-wrapper { + background-color: #000; + opacity: 0.5; + bottom: 0; +} + +.modal-content { + border-radius: .3rem; + position: relative; + display: flex; + width: 100%; + background-color: var(--modal-bg); + background-clip: padding-box; + border: 1px solid rgba(0,0,0,.2); + flex-direction: column; +} + +.modal-header { + display: flex; + align-items: flex-start; + justify-content: space-between; + padding: 1rem; + border-bottom: 1px solid #e9ecef; +} + +.modal-header .close { + padding: 0.7rem; + margin: -1rem -1rem -1rem auto; +} + +.modal-body { + padding: 1rem 1rem 2rem 1rem; +} + +.close { + font-size: 2rem; + opacity: 0.5; + font-family: inherit; + cursor: pointer; + padding: 0; +} + +button.close { + background-color: transparent; + border: 0; +} + +h5 { + font-size: 1.25rem; + margin-top: 0; + margin-bottom: 0.5rem; + font-weight: 500; +} + +.pointer { + cursor: pointer; +} + +.badge-success { + color: #fff; + background-color: #28a745; +} + +.badge-warning { + color: #212529; + background-color: #ffc107; +} + +.badge-error { + color: #fff; + background-color: #dc3545; +} + +.badge { + display: inline-block; + padding: .25em .4em; + font-size: 85%; + font-weight: 700; + line-height: 1; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: .25rem; +} diff --git a/src/web/html/tmp/system.html b/src/web/html/tmp/system.html new file mode 100644 index 00000000..b7221966 --- /dev/null +++ b/src/web/html/tmp/system.html @@ -0,0 +1,188 @@ + + + + System + + + + + + + + + +
+
+
+
+
+
+ + + + diff --git a/src/web/html/tmp/update.html b/src/web/html/tmp/update.html new file mode 100644 index 00000000..883afac5 --- /dev/null +++ b/src/web/html/tmp/update.html @@ -0,0 +1,80 @@ + + + + Update + + + + + + + + + +
+
+
+ Select firmware file (*.bin) +
+ + +
+
+
+
+ + + + diff --git a/src/web/html/tmp/visualization.html b/src/web/html/tmp/visualization.html new file mode 100644 index 00000000..545a1555 --- /dev/null +++ b/src/web/html/tmp/visualization.html @@ -0,0 +1,479 @@ + + + + Live + + + + + + + + + + +
+
+
+

Every seconds the values are updated

+
+
+ + + + From 5b3d0593fe8da30618958711fcf2611d2ccb18af Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Wed, 18 Oct 2023 18:56:59 +0200 Subject: [PATCH 139/267] some more MI specific things - might decode data and enqueue correct next command - small fixes wrt. to serial readibility --- src/hm/CommQueue.h | 16 +++++++ src/hm/Communication.h | 105 ++++++++++++++++++++++++++++++++++++++++- src/hm/hmInverter.h | 3 +- src/hm/hmRadio.h | 3 +- 4 files changed, 124 insertions(+), 3 deletions(-) diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index 9c9da707..5f27db60 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -22,6 +22,10 @@ class CommQueue { void add(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) { mQueue[mWrPtr] = queue_s(iv, cmd, delOnPop, false); + /*mQueue[mRdPtr].firstTry = false; + if((IV_HM == mQueue[mRdPtr].iv->ivGen) || (IV_MI == mQueue[mRdPtr].iv->ivGen)) { + mQueue[mRdPtr].firstTry = ((mQueue[mRdPtr].iv->isAvailable()) || (millis() < 120000)); + }*/ inc(&mWrPtr); } @@ -32,6 +36,7 @@ class CommQueue { uint8_t attempts; bool delOnPop; bool isDevControl; + bool firstTry; uint32_t ts; queue_s() {} queue_s(Inverter<> *i, uint8_t c, bool d, bool dev) : @@ -41,6 +46,10 @@ class CommQueue { protected: void add(queue_s q) { mQueue[mWrPtr] = q; + /*mQueue[mRdPtr].firstTry = false; + if((IV_HM == mQueue[mRdPtr].iv->ivGen) || (IV_MI == mQueue[mRdPtr].iv->ivGen)) { + mQueue[mRdPtr].firstTry = ((mQueue[mRdPtr].iv->isAvailable()) || (millis() < 120000)); + }*/ inc(&mWrPtr); } @@ -60,6 +69,13 @@ class CommQueue { inc(&mRdPtr); } + bool isFirstTry(void) { + if(!mQueue[mRdPtr].firstTry) + return false; + mQueue[mRdPtr].firstTry = false; + return true; + } + void setTs(uint32_t *ts) { mQueue[mRdPtr].ts = *ts; } diff --git a/src/hm/Communication.h b/src/hm/Communication.h index c14bd4f0..2dbf4593 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -90,6 +90,13 @@ class Communication : public CommQueue<> { case States::CHECK_FRAMES: { if(!q->iv->radio->get()) { // radio buffer empty + // second try for nRF type inverters if available + /*if(isFirstTry()) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINTLN(F("enqueue second try")); + mState = States::START; + break; + }*/ cmdDone(); DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("request timeout: ")); @@ -111,12 +118,17 @@ class Communication : public CommQueue<> { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("RX ")); + if(p->millis<100) + DBGPRINT("0"); DBGPRINT(String(p->millis)); DBGPRINT(F("ms ")); DBGPRINT(String(p->len)); if((IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen)) { DBGPRINT(F(" CH")); - DBGPRINT(String(p->ch)); + if(p->ch == 3) + DBGPRINT("03"); + else + DBGPRINT(String(p->ch)); } DBGPRINT(F(", ")); DBGPRINT(String(p->rssi)); @@ -132,6 +144,23 @@ class Communication : public CommQueue<> { } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command parseDevCtrl(p, q); cmdDone(true); // remove done request + } else if (q->iv->ivGen == IV_MI) { + /*if (p->packet[0] == (0x88)) { // 0x88 is MI status response to 0x09 + miStsDecode(p, q); + } + + else if (p->packet[0] == (MI_REQ_CH2 + SINGLE_FRAME)) { // 0x92; MI status response to 0x11 + miStsDecode(p, q, CH2); + + } else*/ if ( p->packet[0] == MI_REQ_CH1 + ALL_FRAMES || + p->packet[0] == MI_REQ_CH2 + ALL_FRAMES || + ( p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES) && p->packet[0] < (0x39 + SINGLE_FRAME) + && q->cmd != 0x0f) ) { // small MI or MI 1500 data responses to 0x09, 0x11, 0x36, 0x37, 0x38 and 0x39 + //mPayload[iv->id].txId = p->packet[0]; + miDataDecode(p, q); + + } + //parseMiFrame(p, q); } } @@ -254,6 +283,80 @@ class Communication : public CommQueue<> { q->iv->actPowerLimit = 0xffff; // unknown, readback current value } + inline void parseMiFrame(packet_t *p, const queue_s *q) { + if((p->packet[12] != ActivePowerContr) || (p->packet[13] != 0x00)) + return; + bool accepted = true; + if((p->packet[10] == 0x00) && (p->packet[11] == 0x00)) + q->iv->powerLimitAck = true; + else + accepted = false; + + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("has ")); + if(!accepted) DBGPRINT(F("not ")); + DBGPRINT(F("accepted power limit set point ")); + DBGPRINT(String(q->iv->powerLimit[0])); + DBGPRINT(F(" with PowerLimitControl ")); + DBGPRINTLN(String(q->iv->powerLimit[1])); + q->iv->actPowerLimit = 0xffff; // unknown, readback current value + } + + inline void miDataDecode(packet_t *p, const queue_s *q) { + record_t<> *rec = q->iv->getRecordStruct(RealTimeRunData_Debug); // choose the parser + //rec->ts = mPayload[iv->id].ts; + //mPayload[iv->id].gotFragment = true; + //mPayload[iv->id].multi_parts += 4; + + uint8_t datachan = ( p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES) || p->packet[0] == (MI_REQ_4CH + ALL_FRAMES) ) ? CH1 : + ( p->packet[0] == (MI_REQ_CH2 + ALL_FRAMES) || p->packet[0] == (0x37 + ALL_FRAMES) ) ? CH2 : + p->packet[0] == (0x38 + ALL_FRAMES) ? CH3 : + CH4; + // count in RF_communication_protocol.xlsx is with offset = -1 + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_UDC, rec), rec, (float)((p->packet[9] << 8) + p->packet[10])/10); + yield(); + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_IDC, rec), rec, (float)((p->packet[11] << 8) + p->packet[12])/10); + yield(); + q->iv->setValue(q->iv->getPosByChFld(0, FLD_UAC, rec), rec, (float)((p->packet[13] << 8) + p->packet[14])/10); + yield(); + q->iv->setValue(q->iv->getPosByChFld(0, FLD_F, rec), rec, (float) ((p->packet[15] << 8) + p->packet[16])/100); + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_PDC, rec), rec, (float)((p->packet[17] << 8) + p->packet[18])/10); + yield(); + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_YD, rec), rec, (float)((p->packet[19] << 8) + p->packet[20])/1); + yield(); + q->iv->setValue(q->iv->getPosByChFld(0, FLD_T, rec), rec, (float) ((int16_t)(p->packet[21] << 8) + p->packet[22])/10); + q->iv->setValue(q->iv->getPosByChFld(0, FLD_IRR, rec), rec, (float) (calcIrradiation(q->iv, datachan))); + //mPayload[q->iv->id].rssi[(datachan-1)] = p->rssi; + + /*if ( datachan < 3 ) { + mPayload[q->iv->id].dataAB[datachan] = true; + } + if ( !mPayload[iv->id].dataAB[CH0] && mPayload[iv->id].dataAB[CH1] && mPayload[iv->id].dataAB[CH2] ) { + mPayload[iv->id].dataAB[CH0] = true; + }*/ + + if (p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES) ) { + /*For MI1500: + if (MI1500) { + STAT = (uint8_t)(p->packet[25] ); + FCNT = (uint8_t)(p->packet[26]); + FCODE = (uint8_t)(p->packet[27]); + }*/ + //miStsConsolidate(iv, datachan, rec, p->packet[23], p->packet[24]); + + if (p->packet[0] < (0x39 + ALL_FRAMES) ) { + addImportant(q->iv, (q->cmd + 1)); + //mPayload[iv->id].txCmd++; + //mPayload[iv->id].retransmits = 0; // reserve retransmissions for each response + //mPayload[iv->id].complete = false; + } else { + //miComplete(iv); + } + } else if((p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES)) && q->iv->type == INV_TYPE_2CH ) { + addImportant(q->iv, MI_REQ_CH2); + } + } + inline void compilePayload(const queue_s *q) { uint16_t crc = 0xffff, crcRcv = 0x0000; for(uint8_t i = 0; i < mMaxFrameId; i++) { diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 04aca4d2..e90acac3 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -202,7 +202,8 @@ class Inverter { mDevControlRequest = false; } else if(0 == getFwVersion()) - cb(InverterDevInform_All, false); // get firmware version + cb(MI_REQ_CH1, false); // get firmware version + //cb(InverterDevInform_All, false); // get firmware version else { record_t<> *rec = getRecordStruct(InverterDevInform_Simple); if (getChannelFieldValue(CH0, FLD_PART_NUM, rec) == 0) diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 461fd08e..e8a95990 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -146,7 +146,8 @@ class HmRadio : public Radio { } void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit, bool isNoMI = true, uint16_t powerMax = 0) { - DPRINT(DBG_INFO, F("sendControlPacket cmd: 0x")); + DPRINT_IVID(DBG_INFO,iv->id); + DBGPRINT(F("sendControlPacket cmd: 0x")); DBGHEXLN(cmd); initPacket(iv->radioId.u64, TX_REQ_DEVCONTROL, SINGLE_FRAME); uint8_t cnt = 10; From 96f181c6625cfe61d4adec81efc9a846d9fb529f Mon Sep 17 00:00:00 2001 From: lumapu Date: Wed, 18 Oct 2023 22:39:41 +0200 Subject: [PATCH 140/267] some improvements --- src/app.cpp | 20 +++++++++++--------- src/hm/CommQueue.h | 7 +++++++ src/hm/Communication.h | 35 ++++++++++++++++++++++++----------- src/hm/hmInverter.h | 6 +++--- 4 files changed, 45 insertions(+), 23 deletions(-) diff --git a/src/app.cpp b/src/app.cpp index 44d8ab30..9cbe06a1 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -413,13 +413,15 @@ void app::tickSend(void) { for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { Inverter<> *iv = mSys.getInverterByPos(i); if(NULL != iv) { - iv->tickSend([this, iv](uint8_t cmd, bool isDevControl) { - if(isDevControl) - mCommunication.addImportant(iv, cmd); - else - mCommunication.add(iv, cmd); - }); - }; + if(iv->config->enabled) { + iv->tickSend([this, iv](uint8_t cmd, bool isDevControl) { + if(isDevControl) + mCommunication.addImportant(iv, cmd); + else + mCommunication.add(iv, cmd); + }); + } + } } /*if(mConfig->nrf.enabled) { @@ -468,9 +470,9 @@ void app::tickSend(void) { if (mConfig->serial.debug) DPRINTLN(DBG_WARN, F("Time not set or it is night time, therefore no communication to the inverter!")); } - yield(); + yield();*/ - updateLed();*/ + updateLed(); } //----------------------------------------------------------------------------- diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index 9c9da707..94cc63bd 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -44,6 +44,13 @@ class CommQueue { inc(&mWrPtr); } + void add(const queue_s *q, bool rstAttempts = false) { + mQueue[mWrPtr] = *q; + if(rstAttempts) + mQueue[mWrPtr].attempts = 5; + inc(&mWrPtr); + } + void get(std::function cb) { if(mRdPtr == mWrPtr) { cb(false, &mQueue[mRdPtr]); // empty diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 4cdf0beb..81dc763c 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -112,7 +112,8 @@ class Communication : public CommQueue<> { parseDevCtrl(p, q); cmdDone(true); // remove done request } - } + } else + DPRINTLN(DBG_WARN, F("Inverter serial does not match")); q->iv->radio->mBufCtrl.pop(); yield(); @@ -126,7 +127,7 @@ class Communication : public CommQueue<> { setAttempt(); DPRINT_IVID(DBG_WARN, q->iv->id); - DBGPRINT(F("last frame missing: request retransmit (")); + DBGPRINT(F("frame missing: request retransmit (")); DBGPRINT(String(q->attempts)); DBGPRINTLN(F(" attempts left)")); @@ -136,11 +137,17 @@ class Communication : public CommQueue<> { break; } - q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (ALL_FRAMES + i), true); - q->iv->radioStatistics.retransmits++; - mWaitTimeout = millis() + 500; - mState = States::WAIT; - break; + if(q->attempts) { + q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (ALL_FRAMES + i), true); + q->iv->radioStatistics.retransmits++; + mWaitTimeout = millis() + 500; + mState = States::WAIT; + } else { + add(q, true); + cmdDone(q); + mState = States::RESET; + } + return; } for(uint8_t i = 0; i < mMaxFrameId; i++) { @@ -154,10 +161,16 @@ class Communication : public CommQueue<> { DBGPRINT(String(q->attempts)); DBGPRINTLN(F(" attempts left)")); - q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (ALL_FRAMES + i), true); - q->iv->radioStatistics.retransmits++; - mWaitTimeout = millis() + 500; - mState = States::WAIT; + if(q->attempts) { + q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (ALL_FRAMES + i), true); + q->iv->radioStatistics.retransmits++; + mWaitTimeout = millis() + 500; + mState = States::WAIT; + } else { + add(q, true); + cmdDone(q); + mState = States::RESET; + } return; } } diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 5e3e4266..45b861a7 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -617,9 +617,9 @@ class Inverter { uint32_t startTimeOffset = 0, endTimeOffset = 0; uint32_t start, endTime; - if (((wCode >> 13) & 0x01) == 1) // check if is AM or PM - startTimeOffset = 12 * 60 * 60; - if (((wCode >> 12) & 0x01) == 1) // check if is AM or PM + // check if is AM or PM + startTimeOffset = ((wCode >> 13) & 0x01) * 12 * 60 * 60; + if (((wCode >> 12) & 0x03) != 0) endTimeOffset = 12 * 60 * 60; start = (((uint16_t)pyld[startOff + 4] << 8) | ((uint16_t)pyld[startOff + 5])) + startTimeOffset; From 1b965d67a850d41be6a97eef72a9bab557057ddd Mon Sep 17 00:00:00 2001 From: lumapu Date: Wed, 18 Oct 2023 23:11:46 +0200 Subject: [PATCH 141/267] added MI additions / corrections from @rejoe2 --- src/hm/Communication.h | 79 ++++++++++++++++++++++++++++++++++++++++-- src/hm/hmDefines.h | 4 +++ src/hm/hmInverter.h | 42 +++++++++++++++------- src/hm/hmRadio.h | 26 ++++++++------ src/hm/radio.h | 11 +++++- src/hms/hmsRadio.h | 6 +++- 6 files changed, 141 insertions(+), 27 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 81dc763c..1336e78c 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -71,7 +71,8 @@ class Communication : public CommQueue<> { case States::CHECK_FRAMES: { if(!q->iv->radio->get()) { // radio buffer empty cmdDone(); - DPRINT(DBG_INFO, F("request timeout: ")); + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("request timeout: ")); DBGPRINT(String(millis() - mWaitTimeout + 500)); DBGPRINTLN(F("ms")); @@ -90,11 +91,15 @@ class Communication : public CommQueue<> { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("RX ")); + if(p->millis < 100) + DBGPRINT(F("0")); DBGPRINT(String(p->millis)); DBGPRINT(F("ms ")); DBGPRINT(String(p->len)); - if(IV_HM == q->iv->ivGen) { + if((IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen)) { DBGPRINT(F(" CH")); + if(3 == p->ch) + DBGPRINT(F("0")); DBGPRINT(String(p->ch)); } DBGPRINT(F(", ")); @@ -111,6 +116,8 @@ class Communication : public CommQueue<> { } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command parseDevCtrl(p, q); cmdDone(true); // remove done request + } else if(IV_MI == q->iv->ivGen) { + parseMiFrame(p, q); } } else DPRINTLN(DBG_WARN, F("Inverter serial does not match")); @@ -227,6 +234,74 @@ class Communication : public CommQueue<> { f->rssi = p->rssi; } + inline void parseMiFrame(packet_t *p, const queue_s *q) { + if ((p->packet[0] == MI_REQ_CH1 + ALL_FRAMES) + || (p->packet[0] == MI_REQ_CH2 + ALL_FRAMES) + || ((p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES)) + && (p->packet[0] < (0x39 + SINGLE_FRAME)) + && (q->cmd != 0x0f))) { + // small MI or MI 1500 data responses to 0x09, 0x11, 0x36, 0x37, 0x38 and 0x39 + //mPayload[iv->id].txId = p->packet[0]; + miDataDecode(p, q); + + } + } + + inline void miDataDecode(packet_t *p, const queue_s *q) { + record_t<> *rec = q->iv->getRecordStruct(RealTimeRunData_Debug); // choose the parser + //rec->ts = mPayload[iv->id].ts; + //mPayload[iv->id].gotFragment = true; + //mPayload[iv->id].multi_parts += 4; + + uint8_t datachan = ( p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES) || p->packet[0] == (MI_REQ_4CH + ALL_FRAMES) ) ? CH1 : + ( p->packet[0] == (MI_REQ_CH2 + ALL_FRAMES) || p->packet[0] == (0x37 + ALL_FRAMES) ) ? CH2 : + p->packet[0] == (0x38 + ALL_FRAMES) ? CH3 : + CH4; + // count in RF_communication_protocol.xlsx is with offset = -1 + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_UDC, rec), rec, (float)((p->packet[9] << 8) + p->packet[10])/10); + + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_IDC, rec), rec, (float)((p->packet[11] << 8) + p->packet[12])/10); + + q->iv->setValue(q->iv->getPosByChFld(0, FLD_UAC, rec), rec, (float)((p->packet[13] << 8) + p->packet[14])/10); + + q->iv->setValue(q->iv->getPosByChFld(0, FLD_F, rec), rec, (float) ((p->packet[15] << 8) + p->packet[16])/100); + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_PDC, rec), rec, (float)((p->packet[17] << 8) + p->packet[18])/10); + + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_YD, rec), rec, (float)((p->packet[19] << 8) + p->packet[20])/1); + + q->iv->setValue(q->iv->getPosByChFld(0, FLD_T, rec), rec, (float) ((int16_t)(p->packet[21] << 8) + p->packet[22])/10); + q->iv->setValue(q->iv->getPosByChFld(0, FLD_IRR, rec), rec, (float) (calcIrradiation(q->iv, datachan))); + //mPayload[q->iv->id].rssi[(datachan-1)] = p->rssi; + + /*if ( datachan < 3 ) { + mPayload[q->iv->id].dataAB[datachan] = true; + } + if ( !mPayload[iv->id].dataAB[CH0] && mPayload[iv->id].dataAB[CH1] && mPayload[iv->id].dataAB[CH2] ) { + mPayload[iv->id].dataAB[CH0] = true; + }*/ + + if (p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES) ) { + /*For MI1500: + if (MI1500) { + STAT = (uint8_t)(p->packet[25] ); + FCNT = (uint8_t)(p->packet[26]); + FCODE = (uint8_t)(p->packet[27]); + }*/ + //miStsConsolidate(iv, datachan, rec, p->packet[23], p->packet[24]); + + if (p->packet[0] < (0x39 + ALL_FRAMES) ) { + addImportant(q->iv, (q->cmd + 1)); + //mPayload[iv->id].txCmd++; + //mPayload[iv->id].retransmits = 0; // reserve retransmissions for each response + //mPayload[iv->id].complete = false; + } else { + //miComplete(iv); + } + } else if((p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES)) && q->iv->type == INV_TYPE_2CH ) { + addImportant(q->iv, MI_REQ_CH2); + } + } + inline void parseDevCtrl(packet_t *p, const queue_s *q) { if((p->packet[12] != ActivePowerContr) || (p->packet[13] != 0x00)) return; diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index acd81541..c00f4940 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -346,4 +346,8 @@ const devInfo_t devInfo[] = { { 0x103331, 2250 } }; +#define MI_REQ_CH1 0x09 +#define MI_REQ_CH2 0x11 +#define MI_REQ_4CH 0x36 + #endif /*__HM_DEFINES_H__*/ diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 45b861a7..618cf5da 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -182,19 +182,35 @@ class Inverter { } void tickSend(std::function cb) { - if(mDevControlRequest) { - cb(devControlCmd, true); - mDevControlRequest = false; - } else if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) - cb(AlarmData, false); // get last alarms - else if(0 == getFwVersion()) - cb(InverterDevInform_All, false); // get firmware version - else if(0 == getHwVersion()) - cb(InverterDevInform_Simple, false); // get hardware version - else if(actPowerLimit == 0xffff) - cb(SystemConfigPara, false); // power limit info - else - cb(RealTimeRunData_Debug, false); // get live data + if (IV_MI != ivGen) { + if(mDevControlRequest) { + cb(devControlCmd, true); + mDevControlRequest = false; + } else if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) + cb(AlarmData, false); // get last alarms + else if(0 == getFwVersion()) + cb(InverterDevInform_All, false); // get firmware version + else if(0 == getHwVersion()) + cb(InverterDevInform_Simple, false); // get hardware version + else if(actPowerLimit == 0xffff) + cb(SystemConfigPara, false); // power limit info + else + cb(RealTimeRunData_Debug, false); // get live data + } else { + if(mDevControlRequest) { + cb(devControlCmd, true); + mDevControlRequest = false; + } else if(0 == getFwVersion()) + cb(MI_REQ_CH1, false); // get firmware version + //cb(InverterDevInform_All, false); // get firmware version + else { + record_t<> *rec = getRecordStruct(InverterDevInform_Simple); + if (getChannelFieldValue(CH0, FLD_PART_NUM, rec) == 0) + cb(InverterDevInform_All, false); // hard- and firmware version for missing HW part nr, delivered by frame 1 + else + cb(type == INV_TYPE_4CH ? MI_REQ_4CH : MI_REQ_CH1, false); + } + } } /*template diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 461fd08e..3d74222d 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -117,24 +117,24 @@ class HmRadio : public Radio { mNrf24.setChannel(mRfChLst[mRxChIdx]); mNrf24.startListening(); - uint32_t startMicros = micros(); + uint32_t startMicros = micros() + 5110; uint32_t loopMillis = millis() + 400; while (millis() < loopMillis) { - while (micros()-startMicros < 5110) { // listen (4088us or?) 5110us to each channel + while (micros() < startMicros) { // listen (4088us or?) 5110us to each channel if (mIrqRcvd) { mIrqRcvd = false; - if (getReceived()) { // everything received + + if (getReceived()) // everything received return; - } + } yield(); } // switch to next RX channel - startMicros = micros(); if(++mRxChIdx >= RF_CHANNELS) mRxChIdx = 0; mNrf24.setChannel(mRfChLst[mRxChIdx]); - yield(); + startMicros = micros() + 5000; } // not finished but time is over return; @@ -145,12 +145,13 @@ class HmRadio : public Radio { return mNrf24.isChipConnected(); } - void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit, bool isNoMI = true, uint16_t powerMax = 0) { - DPRINT(DBG_INFO, F("sendControlPacket cmd: 0x")); + void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit) { + DPRINT_IVID(DBG_INFO, iv->id); + DBGPRINT(F("sendControlPacket cmd: 0x")); DBGHEXLN(cmd); initPacket(iv->radioId.u64, TX_REQ_DEVCONTROL, SINGLE_FRAME); uint8_t cnt = 10; - if (isNoMI) { + if (IV_MI != iv->ivGen) { 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 @@ -160,6 +161,7 @@ class HmRadio : public Radio { mTxBuf[cnt++] = ((data[1] ) ) & 0xff; // setting for persistens handling } } else { //MI 2nd gen. specific + uint16_t powerMax = ((iv->powerLimit[1] == RelativNonPersistent) ? 0 : iv->getMaxPower()); switch (cmd) { case Restart: case TurnOn: @@ -225,7 +227,7 @@ class HmRadio : public Radio { } cnt++; } - sendPacket(iv, cnt, isRetransmit, isNoMI); + sendPacket(iv, cnt, isRetransmit, (IV_MI != iv->ivGen)); } uint8_t getDataRate(void) { @@ -297,6 +299,10 @@ class HmRadio : public Radio { return iv->radioId.u64; } + uint8_t getIvGen(Inverter<> *iv) { + return iv->ivGen; + } + uint64_t DTU_RADIO_ID; uint8_t mRfChLst[RF_CHANNELS]; uint8_t mTxChIdx; diff --git a/src/hm/radio.h b/src/hm/radio.h index 2096f108..75db5436 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -21,7 +21,7 @@ class Inverter; // abstract radio interface class Radio { public: - virtual void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit, bool isNoMI = true, uint16_t powerMax = 0) = 0; + virtual void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit) = 0; virtual bool switchFrequency(Inverter<> *iv, uint32_t fromkHz, uint32_t tokHz) { return true; } virtual void loop(void) {}; @@ -43,6 +43,14 @@ class Radio { } void prepareDevInformCmd(Inverter<> *iv, 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. + if(IV_MI == getIvGen(iv)) { + DPRINT_IVID(DBG_INFO, getIvId(iv)); + DBGPRINT(F("legacy cmd 0x")); + DBGHEXLN(cmd); + sendCmdPacket(iv, cmd, cmd, false, false); + return; + } + if(mSerialDebug) { DPRINT(DBG_DEBUG, F("prepareDevInformCmd 0x")); DPRINTLN(DBG_DEBUG,String(cmd, HEX)); @@ -63,6 +71,7 @@ class Radio { protected: virtual void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) = 0; virtual uint64_t getIvId(Inverter<> *iv) = 0; + virtual uint8_t getIvGen(Inverter<> *iv) = 0; void initPacket(uint64_t ivId, uint8_t mid, uint8_t pid) { mTxBuf[0] = mid; diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index 24c3c7cd..097a3f03 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -44,7 +44,7 @@ class CmtRadio : public Radio { return mCmtAvail; } - void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit, bool isNoMI = true, uint16_t powerMax = 0) { + void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit) { DPRINT(DBG_INFO, F("sendControlPacket cmd: 0x")); DBGHEXLN(cmd); initPacket(iv->radioId.u64, TX_REQ_DEVCONTROL, SINGLE_FRAME); @@ -101,6 +101,10 @@ class CmtRadio : public Radio { return iv->radioId.u64; } + uint8_t getIvGen(Inverter<> *iv) { + return iv->ivGen; + } + inline void reset(bool genDtuSn) { if(genDtuSn) generateDtuSn(); From 0fca99f833db79006827e831d794ea67e782a046 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 19 Oct 2023 17:50:04 +0200 Subject: [PATCH 142/267] MI might be functional again --- src/hm/CommQueue.h | 23 +- src/hm/Communication.h | 482 +++++++++++++++++++++++++++++++---------- src/hm/hmInverter.h | 24 +- src/hm/hmRadio.h | 25 ++- src/hm/miPayload.h | 2 +- src/hm/radio.h | 13 +- 6 files changed, 418 insertions(+), 151 deletions(-) diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index 5f27db60..94cc63bd 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -22,10 +22,6 @@ class CommQueue { void add(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) { mQueue[mWrPtr] = queue_s(iv, cmd, delOnPop, false); - /*mQueue[mRdPtr].firstTry = false; - if((IV_HM == mQueue[mRdPtr].iv->ivGen) || (IV_MI == mQueue[mRdPtr].iv->ivGen)) { - mQueue[mRdPtr].firstTry = ((mQueue[mRdPtr].iv->isAvailable()) || (millis() < 120000)); - }*/ inc(&mWrPtr); } @@ -36,7 +32,6 @@ class CommQueue { uint8_t attempts; bool delOnPop; bool isDevControl; - bool firstTry; uint32_t ts; queue_s() {} queue_s(Inverter<> *i, uint8_t c, bool d, bool dev) : @@ -46,10 +41,13 @@ class CommQueue { protected: void add(queue_s q) { mQueue[mWrPtr] = q; - /*mQueue[mRdPtr].firstTry = false; - if((IV_HM == mQueue[mRdPtr].iv->ivGen) || (IV_MI == mQueue[mRdPtr].iv->ivGen)) { - mQueue[mRdPtr].firstTry = ((mQueue[mRdPtr].iv->isAvailable()) || (millis() < 120000)); - }*/ + inc(&mWrPtr); + } + + void add(const queue_s *q, bool rstAttempts = false) { + mQueue[mWrPtr] = *q; + if(rstAttempts) + mQueue[mWrPtr].attempts = 5; inc(&mWrPtr); } @@ -69,13 +67,6 @@ class CommQueue { inc(&mRdPtr); } - bool isFirstTry(void) { - if(!mQueue[mRdPtr].firstTry) - return false; - mQueue[mRdPtr].firstTry = false; - return true; - } - void setTs(uint32_t *ts) { mQueue[mRdPtr].ts = *ts; } diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 2dbf4593..d8859477 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -10,6 +10,9 @@ #include #include "../utils/crc.h" +#define MI_TIMEOUT 500 +#define DEFAULT_TIMEOUT 500 + typedef std::function *)> payloadListenerType; typedef std::function *)> alarmListenerType; @@ -37,6 +40,8 @@ class Communication : public CommQueue<> { if(!valid) return; // empty + uint16_t lcl_tmo = q->iv->ivGen != IV_MI ? DEFAULT_TIMEOUT : MI_TIMEOUT; + switch(mState) { case States::RESET: if(millis() < mWaitTimeout) @@ -50,34 +55,26 @@ class Communication : public CommQueue<> { case States::START: setTs(mTimestamp); - if (q->iv->ivGen != IV_MI) { - if(q->isDevControl) { - if(ActivePowerContr == q->cmd) - q->iv->powerLimitAck = false; - q->iv->radio->sendControlPacket(q->iv, q->cmd, q->iv->powerLimit, false); - } else - q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); - } else { // IV_MI - if(q->isDevControl) { - if(ActivePowerContr == q->cmd) - q->iv->powerLimitAck = false; - q->iv->radio->sendControlPacket(q->iv, q->cmd, q->iv->powerLimit, false, false, (q->iv->powerLimit[1] == RelativNonPersistent) ? 0 : q->iv->getMaxPower()); - } else { - //uint8_t cmd = q->iv->type == INV_TYPE_4CH ? MI_REQ_4CH : MI_REQ_CH1; - //q->iv->radio->sendCmdPacket(q->iv, cmd, cmd, false, false); - q->iv->radio->sendCmdPacket(q->iv, q->cmd, q->cmd, false, false); - //if (q->iv->radio->mSerialDebug) { - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("legacy cmd 0x")); - DBGHEXLN(q->cmd); - //} - //mPayload[q->iv->id]. = cmd; - } - + if(q->isDevControl) { + if(ActivePowerContr == q->cmd) + q->iv->powerLimitAck = false; + q->iv->radio->sendControlPacket(q->iv, q->cmd, q->iv->powerLimit, false); + } + else if (q->iv->ivGen != IV_MI) + q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); + else { // IV_MI + //uint8_t cmd = q->iv->type == INV_TYPE_4CH ? MI_REQ_4CH : MI_REQ_CH1; + //q->iv->radio->sendCmdPacket(q->iv, cmd, cmd, false, false); + q->iv->radio->sendCmdPacket(q->iv, q->cmd, q->cmd, false, false); + //if (q->iv->radio->mSerialDebug) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("legacy cmd 0x")); + DBGHEXLN(q->cmd); + //} + //mPayload[q->iv->id]. = cmd; } - q->iv->radioStatistics.txCnt++; - mWaitTimeout = millis() + 500; + mWaitTimeout = millis() + lcl_tmo; setAttempt(); mState = States::WAIT; break; @@ -90,17 +87,10 @@ class Communication : public CommQueue<> { case States::CHECK_FRAMES: { if(!q->iv->radio->get()) { // radio buffer empty - // second try for nRF type inverters if available - /*if(isFirstTry()) { - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINTLN(F("enqueue second try")); - mState = States::START; - break; - }*/ cmdDone(); DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("request timeout: ")); - DBGPRINT(String(millis() - mWaitTimeout + 500)); + DBGPRINT(String(millis() - mWaitTimeout + lcl_tmo)); DBGPRINTLN(F("ms")); q->iv->radioStatistics.rxFailNoAnser++; // got nothing @@ -118,15 +108,15 @@ class Communication : public CommQueue<> { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("RX ")); - if(p->millis<100) - DBGPRINT("0"); + if(p->millis < 100) + DBGPRINT(F("0")); DBGPRINT(String(p->millis)); DBGPRINT(F("ms ")); DBGPRINT(String(p->len)); if((IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen)) { DBGPRINT(F(" CH")); - if(p->ch == 3) - DBGPRINT("03"); + if(3 == p->ch) + DBGPRINT(F("03")); else DBGPRINT(String(p->ch)); } @@ -144,25 +134,11 @@ class Communication : public CommQueue<> { } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command parseDevCtrl(p, q); cmdDone(true); // remove done request - } else if (q->iv->ivGen == IV_MI) { - /*if (p->packet[0] == (0x88)) { // 0x88 is MI status response to 0x09 - miStsDecode(p, q); - } - - else if (p->packet[0] == (MI_REQ_CH2 + SINGLE_FRAME)) { // 0x92; MI status response to 0x11 - miStsDecode(p, q, CH2); - - } else*/ if ( p->packet[0] == MI_REQ_CH1 + ALL_FRAMES || - p->packet[0] == MI_REQ_CH2 + ALL_FRAMES || - ( p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES) && p->packet[0] < (0x39 + SINGLE_FRAME) - && q->cmd != 0x0f) ) { // small MI or MI 1500 data responses to 0x09, 0x11, 0x36, 0x37, 0x38 and 0x39 - //mPayload[iv->id].txId = p->packet[0]; - miDataDecode(p, q); - - } - //parseMiFrame(p, q); + } else if(IV_MI == q->iv->ivGen) { + parseMiFrame(p, q); } - } + } else + DPRINTLN(DBG_WARN, F("Inverter serial does not match")); q->iv->radio->mBufCtrl.pop(); yield(); @@ -176,7 +152,7 @@ class Communication : public CommQueue<> { setAttempt(); DPRINT_IVID(DBG_WARN, q->iv->id); - DBGPRINT(F("last frame missing: request retransmit (")); + DBGPRINT(F("frame missing: request retransmit (")); DBGPRINT(String(q->attempts)); DBGPRINTLN(F(" attempts left)")); @@ -186,11 +162,17 @@ class Communication : public CommQueue<> { break; } - q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (ALL_FRAMES + i), true); - q->iv->radioStatistics.retransmits++; - mWaitTimeout = millis() + 500; - mState = States::WAIT; - break; + if(q->attempts) { + q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (ALL_FRAMES + i), true); + q->iv->radioStatistics.retransmits++; + mWaitTimeout = millis() + lcl_tmo; + mState = States::WAIT; + } else { + add(q, true); + cmdDone(q); + mState = States::RESET; + } + return; } for(uint8_t i = 0; i < mMaxFrameId; i++) { @@ -204,10 +186,16 @@ class Communication : public CommQueue<> { DBGPRINT(String(q->attempts)); DBGPRINTLN(F(" attempts left)")); - q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (ALL_FRAMES + i), true); - q->iv->radioStatistics.retransmits++; - mWaitTimeout = millis() + 500; - mState = States::WAIT; + if(q->attempts) { + q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (ALL_FRAMES + i), true); + q->iv->radioStatistics.retransmits++; + mWaitTimeout = millis() + lcl_tmo; + mState = States::WAIT; + } else { + add(q, true); + cmdDone(q); + mState = States::RESET; + } return; } } @@ -264,47 +252,167 @@ class Communication : public CommQueue<> { f->rssi = p->rssi; } - inline void parseDevCtrl(packet_t *p, const queue_s *q) { - if((p->packet[12] != ActivePowerContr) || (p->packet[13] != 0x00)) - return; - bool accepted = true; - if((p->packet[10] == 0x00) && (p->packet[11] == 0x00)) - q->iv->powerLimitAck = true; - else - accepted = false; + inline void parseMiFrame(packet_t *p, const queue_s *q) { + if ((p->packet[0] == MI_REQ_CH1 + ALL_FRAMES) + || (p->packet[0] == MI_REQ_CH2 + ALL_FRAMES) + || ((p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES)) + && (p->packet[0] < (0x39 + SINGLE_FRAME)) + && (q->cmd != 0x0f))) { + // small MI or MI 1500 data responses to 0x09, 0x11, 0x36, 0x37, 0x38 and 0x39 + //mPayload[iv->id].txId = p->packet[0]; + miDataDecode(p, q); + + } + else if (p->packet[0] == 0x0f + ALL_FRAMES) + miHwDecode(p, q); + + else if ((p->packet[0] == 0x88) || (p->packet[0] == 0x92)) { + record_t<> *rec = q->iv->getRecordStruct(RealTimeRunData_Debug); // choose the record structure + rec->ts = q->ts; + miStsConsolidate(q, p->packet[0] == 0x88 ? 1 : 2, rec, p->packet[10], p->packet[12], p->packet[9], p->packet[11]); + } + - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F(" has ")); - if(!accepted) DBGPRINT(F("not ")); - DBGPRINT(F("accepted power limit set point ")); - DBGPRINT(String(q->iv->powerLimit[0])); - DBGPRINT(F(" with PowerLimitControl ")); - DBGPRINTLN(String(q->iv->powerLimit[1])); - q->iv->actPowerLimit = 0xffff; // unknown, readback current value } - inline void parseMiFrame(packet_t *p, const queue_s *q) { - if((p->packet[12] != ActivePowerContr) || (p->packet[13] != 0x00)) - return; - bool accepted = true; - if((p->packet[10] == 0x00) && (p->packet[11] == 0x00)) - q->iv->powerLimitAck = true; - else - accepted = false; + inline void miHwDecode(packet_t *p, const queue_s *q) { + record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_All); // choose the record structure + rec->ts = q->ts; + //mPayload[iv->id].gotFragment = true; + uint8_t multi_parts = 0; + +/* +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_BOOTLOADER_VER, UNIT_NONE, CH0, 8, 2, 1 } +}; +*/ - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("has ")); - if(!accepted) DBGPRINT(F("not ")); - DBGPRINT(F("accepted power limit set point ")); - DBGPRINT(String(q->iv->powerLimit[0])); - DBGPRINT(F(" with PowerLimitControl ")); - DBGPRINTLN(String(q->iv->powerLimit[1])); - q->iv->actPowerLimit = 0xffff; // unknown, readback current value + if ( p->packet[9] == 0x00 ) {//first frame + //FLD_FW_VERSION + for (uint8_t i = 0; i < 5; i++) { + q->iv->setValue(i, rec, (float) ((p->packet[(12+2*i)] << 8) + p->packet[(13+2*i)])/1); + } + q->iv->isConnected = true; + //if(mSerialDebug) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DPRINT(DBG_INFO,F("HW_VER is ")); + DBGPRINTLN(String((p->packet[24] << 8) + p->packet[25])); + //} + record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure + rec->ts = q->ts; + q->iv->setValue(1, rec, (uint32_t) ((p->packet[24] << 8) + p->packet[25])/1); + //mPayload[iv->id].multi_parts +=4; + multi_parts +=4; + } else if ( p->packet[9] == 0x01 || p->packet[9] == 0x10 ) {//second frame for MI, 3rd gen. answers in 0x10 + DPRINT_IVID(DBG_INFO, q->iv->id); + if ( p->packet[9] == 0x01 ) { + DBGPRINTLN(F("got 2nd frame (hw info)")); + /* according to xlsx (different start byte -1!) + byte[11] to byte[14] HW_PN + byte[15] byte[16] HW_FB_TLmValue + byte[17] byte[18] HW_FB_ReSPRT + byte[19] byte[20] HW_GridSamp_ResValule + byte[21] byte[22] HW_ECapValue + byte[23] to byte[26] Matching_APPFW_PN*/ + 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])); + record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure + rec->ts = q->ts; + q->iv->setValue(0, rec, (uint32_t) ((((p->packet[10] << 8) | p->packet[11]) << 8 | p->packet[12]) << 8 | p->packet[13])/1); + + //if(mSerialDebug) { + 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_ECapValue ")); + DBGPRINTLN(String((p->packet[20] << 8) + p->packet[21])); + DPRINT(DBG_INFO,F("Matching_APPFW_PN ")); + DBGPRINTLN(String((uint32_t) (((p->packet[22] << 8) | p->packet[23]) << 8 | p->packet[24]) << 8 | p->packet[25])); + //} + //notify(InverterDevInform_Simple, iv); + //mPayload[iv->id].multi_parts +=2; + multi_parts +=2; + //notify(InverterDevInform_All, iv); + } else { + DBGPRINTLN(F("3rd gen. inverter!")); + } + + } else if ( p->packet[9] == 0x12 ) {//3rd frame + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINTLN(F("got 3rd frame (hw info)")); + /* according to xlsx (different start byte -1!) + byte[11] byte[12] APPFW_MINVER + byte[13] byte[14] HWInfoAddr + byte[15] byte[16] PNInfoCRC_gusv + byte[15] byte[16] PNInfoCRC_gusv (this really is double mentionned in xlsx...) + */ + //if(mSerialDebug) { + DPRINT(DBG_INFO,F("APPFW_MINVER ")); + DBGPRINTLN(String((p->packet[10] << 8) + p->packet[11])); + DPRINT(DBG_INFO,F("HWInfoAddr ")); + DBGPRINTLN(String((p->packet[12] << 8) + p->packet[13])); + DPRINT(DBG_INFO,F("PNInfoCRC_gusv ")); + DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15])); + //} + //mPayload[iv->id].multi_parts++; + multi_parts++; + } + if(multi_parts > 5) { + cmdDone(q); + mState = States::RESET; + q->iv->radioStatistics.rxSuccess++; + } + + /*if (mPayload[iv->id].multi_parts > 5) { + iv->setQueuedCmdFinished(); + mPayload[iv->id].complete = true; + mPayload[iv->id].rxTmo = true; + mPayload[iv->id].requested= false; + iv->radioStatistics.rxSuccess++; + } + if (mHighPrioIv == NULL) + mHighPrioIv = iv; + */ } inline void miDataDecode(packet_t *p, const queue_s *q) { record_t<> *rec = q->iv->getRecordStruct(RealTimeRunData_Debug); // choose the parser - //rec->ts = mPayload[iv->id].ts; + rec->ts = q->ts; + q->iv->radioStatistics.rxSuccess++; + mState = States::RESET; + //mPayload[iv->id].gotFragment = true; //mPayload[iv->id].multi_parts += 4; @@ -314,19 +422,22 @@ class Communication : public CommQueue<> { CH4; // count in RF_communication_protocol.xlsx is with offset = -1 q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_UDC, rec), rec, (float)((p->packet[9] << 8) + p->packet[10])/10); - yield(); + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_IDC, rec), rec, (float)((p->packet[11] << 8) + p->packet[12])/10); - yield(); + q->iv->setValue(q->iv->getPosByChFld(0, FLD_UAC, rec), rec, (float)((p->packet[13] << 8) + p->packet[14])/10); - yield(); + q->iv->setValue(q->iv->getPosByChFld(0, FLD_F, rec), rec, (float) ((p->packet[15] << 8) + p->packet[16])/100); q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_PDC, rec), rec, (float)((p->packet[17] << 8) + p->packet[18])/10); - yield(); + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_YD, rec), rec, (float)((p->packet[19] << 8) + p->packet[20])/1); - yield(); + q->iv->setValue(q->iv->getPosByChFld(0, FLD_T, rec), rec, (float) ((int16_t)(p->packet[21] << 8) + p->packet[22])/10); q->iv->setValue(q->iv->getPosByChFld(0, FLD_IRR, rec), rec, (float) (calcIrradiation(q->iv, datachan))); - //mPayload[q->iv->id].rssi[(datachan-1)] = p->rssi; + if (datachan == 1) //mPayload[q->iv->id].rssi[(datachan-1)] = p->rssi; + q->iv->rssi = p->rssi; + else if(q->iv->rssi > p->rssi) + q->iv->rssi = p->rssi; /*if ( datachan < 3 ) { mPayload[q->iv->id].dataAB[datachan] = true; @@ -342,19 +453,164 @@ class Communication : public CommQueue<> { FCNT = (uint8_t)(p->packet[26]); FCODE = (uint8_t)(p->packet[27]); }*/ - //miStsConsolidate(iv, datachan, rec, p->packet[23], p->packet[24]); + miStsConsolidate(q, datachan, rec, p->packet[23], p->packet[24]); if (p->packet[0] < (0x39 + ALL_FRAMES) ) { - addImportant(q->iv, (q->cmd + 1)); - //mPayload[iv->id].txCmd++; - //mPayload[iv->id].retransmits = 0; // reserve retransmissions for each response - //mPayload[iv->id].complete = false; + miNextRequest((p->packet[0] - ALL_FRAMES + 1), q); } else { - //miComplete(iv); + miComplete(q->iv); } } else if((p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES)) && q->iv->type == INV_TYPE_2CH ) { - addImportant(q->iv, MI_REQ_CH2); + miNextRequest(MI_REQ_CH2, q); + } else { // first data msg for 1ch, 2nd for 2ch + miComplete(q->iv); + } + cmdDone(q); + } + + inline void miNextRequest(uint8_t cmd, const queue_s *q) { + //setAttempt(); + DPRINT_IVID(DBG_WARN, q->iv->id); + DBGPRINT(F("next request (")); + DBGPRINT(String(q->attempts)); + DBGPRINT(F(" attempts left): 0x")); + DBGHEXLN(cmd); + + if(q->attempts) { + q->iv->radio->sendCmdPacket(q->iv, cmd, 0x00, true); + q->iv->radioStatistics.retransmits++; + mWaitTimeout = millis() + MI_TIMEOUT; + mState = States::WAIT; + } else { + add(q, true); + cmdDone(q); + mState = States::RESET; + } + } + +/* inline void miStsDecode(Inverter<> *iv, packet_t *p, uint8_t stschan = CH1) { + 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].multi_parts += 3; + 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]) + */ + + inline void miStsConsolidate(const queue_s *q, 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 statusMi = 3; // regular status for MI, change to 1 later? + if ( uState == 2 ) { + statusMi = 5050 + stschan; //first approach, needs review! + if (lState) + statusMi += lState*10; + } else if ( uState > 3 ) { + statusMi = uState*1000 + uEnum*10; + if (lState) + statusMi += lState*100; //needs review, esp. for 4ch-8310 state! + //if (lEnum) + statusMi += lEnum; + if (uEnum < 6) { + statusMi += stschan; + } + if (statusMi == 8000) + statusMi = 8310; //trick? + } + + uint16_t prntsts = statusMi == 3 ? 1 : statusMi; + bool stsok = true; + if ( prntsts != rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)] ) { //sth.'s changed? + q->iv->alarmCnt = 1; // minimum... + //sth is or was wrong? + if ( (q->iv->type != INV_TYPE_1CH) && ( (statusMi != 3) + || ((q->iv->lastAlarm[stschan].code) && (statusMi == 3) && (q->iv->lastAlarm[stschan].code != 1))) + ) { + q->iv->lastAlarm[stschan] = alarm_t(prntsts, q->ts,0); + q->iv->alarmCnt = q->iv->type == INV_TYPE_2CH ? 3 : 5; + } + + q->iv->alarmLastId = prntsts; //iv->alarmMesIndex; + + stsok = false; + if (q->iv->alarmCnt > 1) { //more than one channel + for (uint8_t ch = 0; ch < (q->iv->alarmCnt); ++ch) { //start with 1 + if (q->iv->lastAlarm[ch].code == 1) { + stsok = true; + break; + } + } + } + //if (mSerialDebug) { + DPRINT(DBG_WARN, F("New state on CH")); + DBGPRINT(String(stschan)); DBGPRINT(F(" (")); + DBGPRINT(String(prntsts)); DBGPRINT(F("): ")); + DBGPRINTLN(q->iv->getAlarmStr(prntsts)); + //} + } + + if (!stsok) { + q->iv->setValue(q->iv->getPosByChFld(0, FLD_EVT, rec), rec, prntsts); + q->iv->lastAlarm[0] = alarm_t(prntsts, q->ts, 0); + } + + if (q->iv->alarmMesIndex < rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)]) { + q->iv->alarmMesIndex = rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)]; // seems there's no status per channel in 3rd gen. models?!? + //if (mSerialDebug) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("alarm ID incremented to ")); + DBGPRINTLN(String(q->iv->alarmMesIndex)); + //} + } + } + + + inline 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; + //if (mSerialDebug) { + DPRINT_IVID(DBG_INFO, iv->id); + DBGPRINTLN(F("got all data 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 ((!iv->lastAlarm[i].code) || (iv->lastAlarm[i].code == 1)) { + 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(); + // update status state-machine, + iv->isProducing(); + } + + + inline void parseDevCtrl(packet_t *p, const queue_s *q) { + if((p->packet[12] != ActivePowerContr) || (p->packet[13] != 0x00)) + return; + bool accepted = true; + if((p->packet[10] == 0x00) && (p->packet[11] == 0x00)) + q->iv->powerLimitAck = true; + else + accepted = false; + + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("has ")); + if(!accepted) DBGPRINT(F("not ")); + DBGPRINT(F("accepted power limit set point ")); + DBGPRINT(String(q->iv->powerLimit[0])); + DBGPRINT(F(" with PowerLimitControl ")); + DBGPRINTLN(String(q->iv->powerLimit[1])); + q->iv->actPowerLimit = 0xffff; // unknown, readback current value } inline void compilePayload(const queue_s *q) { @@ -396,7 +652,7 @@ class Communication : public CommQueue<> { } memcpy(&mPayload[len], mLocalBuf[i].buf, mLocalBuf[i].len); len += mLocalBuf[i].len; - // get worst RSSI + // get best RSSI if(mLocalBuf[i].rssi > rssi) rssi = mLocalBuf[i].rssi; } diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index e90acac3..bbf9167a 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -182,7 +182,7 @@ class Inverter { } void tickSend(std::function cb) { - if (ivGen != IV_MI) { + if (IV_MI != ivGen) { if(mDevControlRequest) { cb(devControlCmd, true); mDevControlRequest = false; @@ -197,17 +197,23 @@ class Inverter { else cb(RealTimeRunData_Debug, false); // get live data } else { + /*if (cmd == 0x01) { //0x1 for HM-types + cmd2 = 0x00; + cmd = 0x0f; // for MI, these seem to make part of polling the device software and hardware version number command + } + if (cmd == SystemConfigPara ) { // 0x05 for HM-types + cmd2 = 0x00; + cmd = 0x10; // legacy GPF request + */ if(mDevControlRequest) { cb(devControlCmd, true); mDevControlRequest = false; - } - else if(0 == getFwVersion()) - cb(MI_REQ_CH1, false); // get firmware version - //cb(InverterDevInform_All, false); // get firmware version + } else if(0 == getFwVersion()) + cb(0x0f, false); // get firmware version; for MI, this makes part of polling the device software and hardware version number else { record_t<> *rec = getRecordStruct(InverterDevInform_Simple); if (getChannelFieldValue(CH0, FLD_PART_NUM, rec) == 0) - cb(InverterDevInform_All, false); // hard- and firmware version for missing HW part nr, delivered by frame 1 + cb(0x0f, false); // hard- and firmware version for missing HW part nr, delivered by frame 1 else cb(type == INV_TYPE_4CH ? MI_REQ_4CH : MI_REQ_CH1, false); } @@ -634,9 +640,9 @@ class Inverter { uint32_t startTimeOffset = 0, endTimeOffset = 0; uint32_t start, endTime; - if (((wCode >> 13) & 0x01) == 1) // check if is AM or PM - startTimeOffset = 12 * 60 * 60; - if (((wCode >> 12) & 0x01) == 1) // check if is AM or PM + // check if is AM or PM + startTimeOffset = ((wCode >> 13) & 0x01) * 12 * 60 * 60; + if (((wCode >> 12) & 0x03) != 0) endTimeOffset = 12 * 60 * 60; start = (((uint16_t)pyld[startOff + 4] << 8) | ((uint16_t)pyld[startOff + 5])) + startTimeOffset; diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index e8a95990..3d74222d 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -117,24 +117,24 @@ class HmRadio : public Radio { mNrf24.setChannel(mRfChLst[mRxChIdx]); mNrf24.startListening(); - uint32_t startMicros = micros(); + uint32_t startMicros = micros() + 5110; uint32_t loopMillis = millis() + 400; while (millis() < loopMillis) { - while (micros()-startMicros < 5110) { // listen (4088us or?) 5110us to each channel + while (micros() < startMicros) { // listen (4088us or?) 5110us to each channel if (mIrqRcvd) { mIrqRcvd = false; - if (getReceived()) { // everything received + + if (getReceived()) // everything received return; - } + } yield(); } // switch to next RX channel - startMicros = micros(); if(++mRxChIdx >= RF_CHANNELS) mRxChIdx = 0; mNrf24.setChannel(mRfChLst[mRxChIdx]); - yield(); + startMicros = micros() + 5000; } // not finished but time is over return; @@ -145,13 +145,13 @@ class HmRadio : public Radio { return mNrf24.isChipConnected(); } - void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit, bool isNoMI = true, uint16_t powerMax = 0) { - DPRINT_IVID(DBG_INFO,iv->id); + void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit) { + DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("sendControlPacket cmd: 0x")); DBGHEXLN(cmd); initPacket(iv->radioId.u64, TX_REQ_DEVCONTROL, SINGLE_FRAME); uint8_t cnt = 10; - if (isNoMI) { + if (IV_MI != iv->ivGen) { 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 @@ -161,6 +161,7 @@ class HmRadio : public Radio { mTxBuf[cnt++] = ((data[1] ) ) & 0xff; // setting for persistens handling } } else { //MI 2nd gen. specific + uint16_t powerMax = ((iv->powerLimit[1] == RelativNonPersistent) ? 0 : iv->getMaxPower()); switch (cmd) { case Restart: case TurnOn: @@ -226,7 +227,7 @@ class HmRadio : public Radio { } cnt++; } - sendPacket(iv, cnt, isRetransmit, isNoMI); + sendPacket(iv, cnt, isRetransmit, (IV_MI != iv->ivGen)); } uint8_t getDataRate(void) { @@ -298,6 +299,10 @@ class HmRadio : public Radio { return iv->radioId.u64; } + uint8_t getIvGen(Inverter<> *iv) { + return iv->ivGen; + } + uint64_t DTU_RADIO_ID; uint8_t mRfChLst[RF_CHANNELS]; uint8_t mTxChIdx; diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index 892dc0a8..94f7a9b3 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -36,7 +36,7 @@ typedef struct { } miPayload_t; -//typedef std::function *)> miPayloadListenerType; +typedef std::function *)> miPayloadListenerType; template diff --git a/src/hm/radio.h b/src/hm/radio.h index 46c05d99..75db5436 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -21,7 +21,7 @@ class Inverter; // abstract radio interface class Radio { public: - virtual void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit, bool isNoMI = true, uint16_t powerMax = 0) = 0; + virtual void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit) = 0; virtual bool switchFrequency(Inverter<> *iv, uint32_t fromkHz, uint32_t tokHz) { return true; } virtual void loop(void) {}; @@ -42,7 +42,15 @@ class Radio { sendPacket(iv, 10, isRetransmit, appendCrc16); } - void prepareDevInformCmd(Inverter<> *iv, uint8_t cmd, uint32_t ts, uint16_t alarmMesId, bool isRetransmit, uint8_t reqfld=TX_REQ_INFO) { + void prepareDevInformCmd(Inverter<> *iv, 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. + if(IV_MI == getIvGen(iv)) { + DPRINT_IVID(DBG_INFO, getIvId(iv)); + DBGPRINT(F("legacy cmd 0x")); + DBGHEXLN(cmd); + sendCmdPacket(iv, cmd, cmd, false, false); + return; + } + if(mSerialDebug) { DPRINT(DBG_DEBUG, F("prepareDevInformCmd 0x")); DPRINTLN(DBG_DEBUG,String(cmd, HEX)); @@ -63,6 +71,7 @@ class Radio { protected: virtual void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) = 0; virtual uint64_t getIvId(Inverter<> *iv) = 0; + virtual uint8_t getIvGen(Inverter<> *iv) = 0; void initPacket(uint64_t ivId, uint8_t mid, uint8_t pid) { mTxBuf[0] = mid; From ae49f919664a48c8f05e378046ac4ce09fdeeb03 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 19 Oct 2023 17:55:57 +0200 Subject: [PATCH 143/267] fix 1ch AC calc --- src/hm/Communication.h | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index d8859477..c7332b32 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -579,10 +579,15 @@ const byteAssign_t InfoAssignment[] = { //preliminary AC calculation... float ac_pow = 0; - for(uint8_t i = 1; i <= iv->channels; i++) { - if ((!iv->lastAlarm[i].code) || (iv->lastAlarm[i].code == 1)) { - uint8_t pos = iv->getPosByChFld(i, FLD_PDC, rec); - ac_pow += iv->getValue(pos, rec); + if (iv->type == INV_TYPE_1CH) { + if ((!iv->lastAlarm[0].code) || (iv->lastAlarm[0].code == 1)) + ac_pow += iv->getValue(iv->getPosByChFld(1, FLD_PDC, rec), rec); + } else { + for(uint8_t i = 1; i <= iv->channels; i++) { + if ((!iv->lastAlarm[i].code) || (iv->lastAlarm[i].code == 1)) { + uint8_t pos = iv->getPosByChFld(i, FLD_PDC, rec); + ac_pow += iv->getValue(pos, rec); + } } } ac_pow = (int) (ac_pow*9.5); From 3282f44e3764a2cf01fd182a956b106627009708 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 19 Oct 2023 18:22:39 +0200 Subject: [PATCH 144/267] remove to early cmdDone (?) --- src/hm/Communication.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index c7332b32..7c59d5a2 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -465,7 +465,7 @@ const byteAssign_t InfoAssignment[] = { } else { // first data msg for 1ch, 2nd for 2ch miComplete(q->iv); } - cmdDone(q); + //cmdDone(q); } inline void miNextRequest(uint8_t cmd, const queue_s *q) { From 70b2ae6246505baf68f937063d90a046c934204a Mon Sep 17 00:00:00 2001 From: lumapu Date: Fri, 20 Oct 2023 23:10:50 +0200 Subject: [PATCH 145/267] updated to latest changes from @rejoe2 for MI inverters --- src/hm/CommQueue.h | 2 +- src/hm/Communication.h | 315 ++++++++++++++++++++++++++++++++--------- src/hm/hmInverter.h | 7 +- 3 files changed, 252 insertions(+), 72 deletions(-) diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index 94cc63bd..56e06bfc 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -30,9 +30,9 @@ class CommQueue { Inverter<> *iv; uint8_t cmd; uint8_t attempts; + uint32_t ts; bool delOnPop; bool isDevControl; - uint32_t ts; queue_s() {} queue_s(Inverter<> *i, uint8_t c, bool d, bool dev) : iv(i), cmd(c), attempts(5), ts(0), delOnPop(d), isDevControl(dev) {} diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 1336e78c..5a5e0b7d 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -10,6 +10,9 @@ #include #include "../utils/crc.h" +#define MI_TIMEOUT 500 +#define DEFAULT_TIMEOUT 500 + typedef std::function *)> payloadListenerType; typedef std::function *)> alarmListenerType; @@ -37,6 +40,8 @@ class Communication : public CommQueue<> { if(!valid) return; // empty + uint16_t timeout = q->iv->ivGen != IV_MI ? DEFAULT_TIMEOUT : MI_TIMEOUT; + switch(mState) { case States::RESET: if(millis() < mWaitTimeout) @@ -57,7 +62,7 @@ class Communication : public CommQueue<> { } else q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); q->iv->radioStatistics.txCnt++; - mWaitTimeout = millis() + 500; + mWaitTimeout = millis() + timeout; setAttempt(); mState = States::WAIT; break; @@ -73,7 +78,7 @@ class Communication : public CommQueue<> { cmdDone(); DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("request timeout: ")); - DBGPRINT(String(millis() - mWaitTimeout + 500)); + DBGPRINT(String(millis() - mWaitTimeout + timeout)); DBGPRINTLN(F("ms")); q->iv->radioStatistics.rxFailNoAnser++; // got nothing @@ -92,7 +97,7 @@ class Communication : public CommQueue<> { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("RX ")); if(p->millis < 100) - DBGPRINT(F("0")); + DBGPRINT(F(" ")); DBGPRINT(String(p->millis)); DBGPRINT(F("ms ")); DBGPRINT(String(p->len)); @@ -119,13 +124,20 @@ class Communication : public CommQueue<> { } else if(IV_MI == q->iv->ivGen) { parseMiFrame(p, q); } - } else + } else { DPRINTLN(DBG_WARN, F("Inverter serial does not match")); + mWaitTimeout = millis() + timeout; + } q->iv->radio->mBufCtrl.pop(); yield(); } - mState = nextState; + if(0 == q->attempts) { + cmdDone(q); + mState = States::RESET; + } else + mState = nextState; + } break; @@ -140,14 +152,15 @@ class Communication : public CommQueue<> { uint8_t i = 0; while(i < MAX_PAYLOAD_ENTRIES) { - if(mLocalBuf[i++].len == 0) + if(mLocalBuf[i].len == 0) break; + i++; } if(q->attempts) { - q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (ALL_FRAMES + i), true); + q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true); q->iv->radioStatistics.retransmits++; - mWaitTimeout = millis() + 500; + mWaitTimeout = millis() + timeout; mState = States::WAIT; } else { add(q, true); @@ -169,9 +182,9 @@ class Communication : public CommQueue<> { DBGPRINTLN(F(" attempts left)")); if(q->attempts) { - q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (ALL_FRAMES + i), true); + q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true); q->iv->radioStatistics.retransmits++; - mWaitTimeout = millis() + 500; + mWaitTimeout = millis() + timeout; mState = States::WAIT; } else { add(q, true); @@ -243,62 +256,12 @@ class Communication : public CommQueue<> { // small MI or MI 1500 data responses to 0x09, 0x11, 0x36, 0x37, 0x38 and 0x39 //mPayload[iv->id].txId = p->packet[0]; miDataDecode(p, q); - - } - } - - inline void miDataDecode(packet_t *p, const queue_s *q) { - record_t<> *rec = q->iv->getRecordStruct(RealTimeRunData_Debug); // choose the parser - //rec->ts = mPayload[iv->id].ts; - //mPayload[iv->id].gotFragment = true; - //mPayload[iv->id].multi_parts += 4; - - uint8_t datachan = ( p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES) || p->packet[0] == (MI_REQ_4CH + ALL_FRAMES) ) ? CH1 : - ( p->packet[0] == (MI_REQ_CH2 + ALL_FRAMES) || p->packet[0] == (0x37 + ALL_FRAMES) ) ? CH2 : - p->packet[0] == (0x38 + ALL_FRAMES) ? CH3 : - CH4; - // count in RF_communication_protocol.xlsx is with offset = -1 - q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_UDC, rec), rec, (float)((p->packet[9] << 8) + p->packet[10])/10); - - q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_IDC, rec), rec, (float)((p->packet[11] << 8) + p->packet[12])/10); - - q->iv->setValue(q->iv->getPosByChFld(0, FLD_UAC, rec), rec, (float)((p->packet[13] << 8) + p->packet[14])/10); - - q->iv->setValue(q->iv->getPosByChFld(0, FLD_F, rec), rec, (float) ((p->packet[15] << 8) + p->packet[16])/100); - q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_PDC, rec), rec, (float)((p->packet[17] << 8) + p->packet[18])/10); - - q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_YD, rec), rec, (float)((p->packet[19] << 8) + p->packet[20])/1); - - q->iv->setValue(q->iv->getPosByChFld(0, FLD_T, rec), rec, (float) ((int16_t)(p->packet[21] << 8) + p->packet[22])/10); - q->iv->setValue(q->iv->getPosByChFld(0, FLD_IRR, rec), rec, (float) (calcIrradiation(q->iv, datachan))); - //mPayload[q->iv->id].rssi[(datachan-1)] = p->rssi; - - /*if ( datachan < 3 ) { - mPayload[q->iv->id].dataAB[datachan] = true; - } - if ( !mPayload[iv->id].dataAB[CH0] && mPayload[iv->id].dataAB[CH1] && mPayload[iv->id].dataAB[CH2] ) { - mPayload[iv->id].dataAB[CH0] = true; - }*/ - - if (p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES) ) { - /*For MI1500: - if (MI1500) { - STAT = (uint8_t)(p->packet[25] ); - FCNT = (uint8_t)(p->packet[26]); - FCODE = (uint8_t)(p->packet[27]); - }*/ - //miStsConsolidate(iv, datachan, rec, p->packet[23], p->packet[24]); - - if (p->packet[0] < (0x39 + ALL_FRAMES) ) { - addImportant(q->iv, (q->cmd + 1)); - //mPayload[iv->id].txCmd++; - //mPayload[iv->id].retransmits = 0; // reserve retransmissions for each response - //mPayload[iv->id].complete = false; - } else { - //miComplete(iv); - } - } else if((p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES)) && q->iv->type == INV_TYPE_2CH ) { - addImportant(q->iv, MI_REQ_CH2); + } else if (p->packet[0] == (0x0f + ALL_FRAMES)) + miHwDecode(p, q); + else if ((p->packet[0] == 0x88) || (p->packet[0] == 0x92)) { + record_t<> *rec = q->iv->getRecordStruct(RealTimeRunData_Debug); // choose the record structure + rec->ts = q->ts; + miStsConsolidate(q, ((p->packet[0] == 0x88) ? 1 : 2), rec, p->packet[10], p->packet[12], p->packet[9], p->packet[11]); } } @@ -360,7 +323,7 @@ class Communication : public CommQueue<> { } memcpy(&mPayload[len], mLocalBuf[i].buf, mLocalBuf[i].len); len += mLocalBuf[i].len; - // get worst RSSI + // get worst RSSI (high value is better) if(mLocalBuf[i].rssi > rssi) rssi = mLocalBuf[i].rssi; } @@ -408,6 +371,224 @@ class Communication : public CommQueue<> { } } + private: + inline void miHwDecode(packet_t *p, const queue_s *q) { + record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_All); // choose the record structure + rec->ts = q->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_BOOTLOADER_VER, UNIT_NONE, CH0, 8, 2, 1 } + }; + */ + } + + inline void miDataDecode(packet_t *p, const queue_s *q) { + record_t<> *rec = q->iv->getRecordStruct(RealTimeRunData_Debug); // choose the parser + rec->ts = q->ts; + q->iv->radioStatistics.rxSuccess++; + mState = States::RESET; + + uint8_t datachan = ( p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES) || p->packet[0] == (MI_REQ_4CH + ALL_FRAMES) ) ? CH1 : + ( p->packet[0] == (MI_REQ_CH2 + ALL_FRAMES) || p->packet[0] == (0x37 + ALL_FRAMES) ) ? CH2 : + p->packet[0] == (0x38 + ALL_FRAMES) ? CH3 : + CH4; + // count in RF_communication_protocol.xlsx is with offset = -1 + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_UDC, rec), rec, (float)((p->packet[9] << 8) + p->packet[10])/10); + + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_IDC, rec), rec, (float)((p->packet[11] << 8) + p->packet[12])/10); + + q->iv->setValue(q->iv->getPosByChFld(0, FLD_UAC, rec), rec, (float)((p->packet[13] << 8) + p->packet[14])/10); + + q->iv->setValue(q->iv->getPosByChFld(0, FLD_F, rec), rec, (float) ((p->packet[15] << 8) + p->packet[16])/100); + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_PDC, rec), rec, (float)((p->packet[17] << 8) + p->packet[18])/10); + + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_YD, rec), rec, (float)((p->packet[19] << 8) + p->packet[20])/1); + + q->iv->setValue(q->iv->getPosByChFld(0, FLD_T, rec), rec, (float) ((int16_t)(p->packet[21] << 8) + p->packet[22])/10); + q->iv->setValue(q->iv->getPosByChFld(0, FLD_IRR, rec), rec, (float) (calcIrradiation(q->iv, datachan))); + //mPayload[q->iv->id].rssi[(datachan-1)] = p->rssi; + + if (datachan == 1) //mPayload[q->iv->id].rssi[(datachan-1)] = p->rssi; + q->iv->rssi = p->rssi; + else if(q->iv->rssi > p->rssi) + q->iv->rssi = p->rssi; + + if (p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES) ) { + /*For MI1500: + if (MI1500) { + STAT = (uint8_t)(p->packet[25] ); + FCNT = (uint8_t)(p->packet[26]); + FCODE = (uint8_t)(p->packet[27]); + }*/ + miStsConsolidate(q, datachan, rec, p->packet[23], p->packet[24]); + + if (p->packet[0] < (0x39 + ALL_FRAMES) ) { + addImportant(q->iv, (q->cmd + 1)); + //mPayload[iv->id].txCmd++; + //mPayload[iv->id].retransmits = 0; // reserve retransmissions for each response + //mPayload[iv->id].complete = false; + miNextRequest((p->packet[0] - ALL_FRAMES + 1), q); + } else { + miComplete(q->iv); + } + } else if((p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES)) && (q->iv->type == INV_TYPE_2CH)) { + addImportant(q->iv, MI_REQ_CH2); + miNextRequest(MI_REQ_CH2, q); + } else { // first data msg for 1ch, 2nd for 2ch + miComplete(q->iv); + } + //cmdDone(q); + } + + inline void miNextRequest(uint8_t cmd, const queue_s *q) { + //setAttempt(); + DPRINT_IVID(DBG_WARN, q->iv->id); + DBGPRINT(F("next request (")); + DBGPRINT(String(q->attempts)); + DBGPRINT(F(" attempts left): 0x")); + DBGHEXLN(cmd); + + if(q->attempts) { + q->iv->radio->sendCmdPacket(q->iv, cmd, 0x00, true); + q->iv->radioStatistics.retransmits++; + mWaitTimeout = millis() + MI_TIMEOUT; + mState = States::WAIT; + } else { + add(q, true); + cmdDone(q); + mState = States::RESET; + } + } + + inline void miStsConsolidate(const queue_s *q, 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 statusMi = 3; // regular status for MI, change to 1 later? + if ( uState == 2 ) { + statusMi = 5050 + stschan; //first approach, needs review! + if (lState) + statusMi += lState*10; + } else if ( uState > 3 ) { + statusMi = uState*1000 + uEnum*10; + if (lState) + statusMi += lState*100; //needs review, esp. for 4ch-8310 state! + //if (lEnum) + statusMi += lEnum; + if (uEnum < 6) { + statusMi += stschan; + } + if (statusMi == 8000) + statusMi = 8310; //trick? + } + + uint16_t prntsts = statusMi == 3 ? 1 : statusMi; + bool stsok = true; + if ( prntsts != rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)] ) { //sth.'s changed? + q->iv->alarmCnt = 1; // minimum... + //sth is or was wrong? + if ( (q->iv->type != INV_TYPE_1CH) && ( (statusMi != 3) + || ((q->iv->lastAlarm[stschan].code) && (statusMi == 3) && (q->iv->lastAlarm[stschan].code != 1))) + ) { + q->iv->lastAlarm[stschan] = alarm_t(prntsts, q->ts,0); + q->iv->alarmCnt = q->iv->type == INV_TYPE_2CH ? 3 : 5; + } + + q->iv->alarmLastId = prntsts; //iv->alarmMesIndex; + + stsok = false; + if (q->iv->alarmCnt > 1) { //more than one channel + for (uint8_t ch = 0; ch < (q->iv->alarmCnt); ++ch) { //start with 1 + if (q->iv->lastAlarm[ch].code == 1) { + stsok = true; + break; + } + } + } + //if (mSerialDebug) { + DPRINT(DBG_WARN, F("New state on CH")); + DBGPRINT(String(stschan)); DBGPRINT(F(" (")); + DBGPRINT(String(prntsts)); DBGPRINT(F("): ")); + DBGPRINTLN(q->iv->getAlarmStr(prntsts)); + //} + } + + if (!stsok) { + q->iv->setValue(q->iv->getPosByChFld(0, FLD_EVT, rec), rec, prntsts); + q->iv->lastAlarm[0] = alarm_t(prntsts, q->ts, 0); + } + + if (q->iv->alarmMesIndex < rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)]) { + q->iv->alarmMesIndex = rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)]; // seems there's no status per channel in 3rd gen. models?!? + //if (mSerialDebug) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("alarm ID incremented to ")); + DBGPRINTLN(String(q->iv->alarmMesIndex)); + //} + } + } + + + inline 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; + //if (mSerialDebug) { + DPRINT_IVID(DBG_INFO, iv->id); + DBGPRINTLN(F("got all data 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; + if (iv->type == INV_TYPE_1CH) { + if ((!iv->lastAlarm[0].code) || (iv->lastAlarm[0].code == 1)) + ac_pow += iv->getValue(iv->getPosByChFld(1, FLD_PDC, rec), rec); + } else { + for(uint8_t i = 1; i <= iv->channels; i++) { + if ((!iv->lastAlarm[i].code) || (iv->lastAlarm[i].code == 1)) { + 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(); + // update status state-machine, + iv->isProducing(); + } + private: enum class States : uint8_t { RESET, START, WAIT, CHECK_FRAMES, CHECK_PACKAGE diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 618cf5da..4b9add6f 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -201,14 +201,13 @@ class Inverter { cb(devControlCmd, true); mDevControlRequest = false; } else if(0 == getFwVersion()) - cb(MI_REQ_CH1, false); // get firmware version - //cb(InverterDevInform_All, false); // get firmware version + cb(0x0f, false); // get firmware version; for MI, this makes part of polling the device software and hardware version number else { record_t<> *rec = getRecordStruct(InverterDevInform_Simple); if (getChannelFieldValue(CH0, FLD_PART_NUM, rec) == 0) - cb(InverterDevInform_All, false); // hard- and firmware version for missing HW part nr, delivered by frame 1 + cb(0x0f, false); // hard- and firmware version for missing HW part nr, delivered by frame 1 else - cb(type == INV_TYPE_4CH ? MI_REQ_4CH : MI_REQ_CH1, false); + cb(((type == INV_TYPE_4CH) ? MI_REQ_4CH : MI_REQ_CH1), false); } } } From 810afaac8b03269c0416b2323fbff6cb55fc623e Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Sun, 22 Oct 2023 09:11:25 +0200 Subject: [PATCH 146/267] various fixes - increase buffer - fix incomplete miHwDecode - shorten timeout for MI --- src/hm/CommQueue.h | 17 +- src/hm/Communication.h | 375 +++++++++++++++++++---------------------- src/hm/hmInverter.h | 10 +- src/hm/hmPayload.h | 6 +- 4 files changed, 195 insertions(+), 213 deletions(-) diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index 94cc63bd..ae947504 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -22,6 +22,10 @@ class CommQueue { void add(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) { mQueue[mWrPtr] = queue_s(iv, cmd, delOnPop, false); + /*mQueue[mRdPtr].firstTry = false; + if((IV_HM == mQueue[mRdPtr].iv->ivGen) || (IV_MI == mQueue[mRdPtr].iv->ivGen)) { + mQueue[mRdPtr].firstTry = ((mQueue[mRdPtr].iv->isAvailable()) || (millis() < 120000)); + }*/ inc(&mWrPtr); } @@ -30,9 +34,9 @@ class CommQueue { Inverter<> *iv; uint8_t cmd; uint8_t attempts; + uint32_t ts; bool delOnPop; bool isDevControl; - uint32_t ts; queue_s() {} queue_s(Inverter<> *i, uint8_t c, bool d, bool dev) : iv(i), cmd(c), attempts(5), ts(0), delOnPop(d), isDevControl(dev) {} @@ -48,6 +52,10 @@ class CommQueue { mQueue[mWrPtr] = *q; if(rstAttempts) mQueue[mWrPtr].attempts = 5; + /*mQueue[mRdPtr].firstTry = false; + if((IV_HM == mQueue[mRdPtr].iv->ivGen) || (IV_MI == mQueue[mRdPtr].iv->ivGen)) { + mQueue[mRdPtr].firstTry = ((mQueue[mRdPtr].iv->isAvailable()) || (millis() < 120000)); + }*/ inc(&mWrPtr); } @@ -67,6 +75,13 @@ class CommQueue { inc(&mRdPtr); } + bool isFirstTry(void) { + if(!mQueue[mRdPtr].firstTry) + return false; + mQueue[mRdPtr].firstTry = false; + return true; + } + void setTs(uint32_t *ts) { mQueue[mRdPtr].ts = *ts; } diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 7c59d5a2..1a23ca07 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -10,8 +10,9 @@ #include #include "../utils/crc.h" -#define MI_TIMEOUT 500 +#define MI_TIMEOUT 250 #define DEFAULT_TIMEOUT 500 +#define MAX_BUFFER 200 //was: 150 (hardcoded) typedef std::function *)> payloadListenerType; typedef std::function *)> alarmListenerType; @@ -40,7 +41,7 @@ class Communication : public CommQueue<> { if(!valid) return; // empty - uint16_t lcl_tmo = q->iv->ivGen != IV_MI ? DEFAULT_TIMEOUT : MI_TIMEOUT; + uint16_t timeout = q->iv->ivGen != IV_MI ? DEFAULT_TIMEOUT : MI_TIMEOUT; switch(mState) { case States::RESET: @@ -59,22 +60,10 @@ class Communication : public CommQueue<> { if(ActivePowerContr == q->cmd) q->iv->powerLimitAck = false; q->iv->radio->sendControlPacket(q->iv, q->cmd, q->iv->powerLimit, false); - } - else if (q->iv->ivGen != IV_MI) + } else q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); - else { // IV_MI - //uint8_t cmd = q->iv->type == INV_TYPE_4CH ? MI_REQ_4CH : MI_REQ_CH1; - //q->iv->radio->sendCmdPacket(q->iv, cmd, cmd, false, false); - q->iv->radio->sendCmdPacket(q->iv, q->cmd, q->cmd, false, false); - //if (q->iv->radio->mSerialDebug) { - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("legacy cmd 0x")); - DBGHEXLN(q->cmd); - //} - //mPayload[q->iv->id]. = cmd; - } q->iv->radioStatistics.txCnt++; - mWaitTimeout = millis() + lcl_tmo; + mWaitTimeout = millis() + timeout; setAttempt(); mState = States::WAIT; break; @@ -90,7 +79,7 @@ class Communication : public CommQueue<> { cmdDone(); DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("request timeout: ")); - DBGPRINT(String(millis() - mWaitTimeout + lcl_tmo)); + DBGPRINT(String(millis() - mWaitTimeout + timeout)); DBGPRINTLN(F("ms")); q->iv->radioStatistics.rxFailNoAnser++; // got nothing @@ -109,16 +98,15 @@ class Communication : public CommQueue<> { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("RX ")); if(p->millis < 100) - DBGPRINT(F("0")); + DBGPRINT(F(" ")); DBGPRINT(String(p->millis)); DBGPRINT(F("ms ")); DBGPRINT(String(p->len)); if((IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen)) { DBGPRINT(F(" CH")); if(3 == p->ch) - DBGPRINT(F("03")); - else - DBGPRINT(String(p->ch)); + DBGPRINT(F("0")); + DBGPRINT(String(p->ch)); } DBGPRINT(F(", ")); DBGPRINT(String(p->rssi)); @@ -137,13 +125,20 @@ class Communication : public CommQueue<> { } else if(IV_MI == q->iv->ivGen) { parseMiFrame(p, q); } - } else + } else { DPRINTLN(DBG_WARN, F("Inverter serial does not match")); + mWaitTimeout = millis() + timeout; + } q->iv->radio->mBufCtrl.pop(); yield(); } - mState = nextState; + if(0 == q->attempts) { + cmdDone(q); + mState = States::RESET; + } else + mState = nextState; + } break; @@ -158,14 +153,15 @@ class Communication : public CommQueue<> { uint8_t i = 0; while(i < MAX_PAYLOAD_ENTRIES) { - if(mLocalBuf[i++].len == 0) + if(mLocalBuf[i].len == 0) break; + i++; } if(q->attempts) { - q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (ALL_FRAMES + i), true); + q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true); q->iv->radioStatistics.retransmits++; - mWaitTimeout = millis() + lcl_tmo; + mWaitTimeout = millis() + timeout; mState = States::WAIT; } else { add(q, true); @@ -187,9 +183,9 @@ class Communication : public CommQueue<> { DBGPRINTLN(F(" attempts left)")); if(q->attempts) { - q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (ALL_FRAMES + i), true); + q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true); q->iv->radioStatistics.retransmits++; - mWaitTimeout = millis() + lcl_tmo; + mWaitTimeout = millis() + timeout; mState = States::WAIT; } else { add(q, true); @@ -257,65 +253,165 @@ class Communication : public CommQueue<> { || (p->packet[0] == MI_REQ_CH2 + ALL_FRAMES) || ((p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES)) && (p->packet[0] < (0x39 + SINGLE_FRAME)) - && (q->cmd != 0x0f))) { + )) { //&& (p->packet[0] != (0x0f + ALL_FRAMES)))) { // small MI or MI 1500 data responses to 0x09, 0x11, 0x36, 0x37, 0x38 and 0x39 //mPayload[iv->id].txId = p->packet[0]; miDataDecode(p, q); - - } - else if (p->packet[0] == 0x0f + ALL_FRAMES) + } else if (p->packet[0] == (0x0f + ALL_FRAMES)) miHwDecode(p, q); - else if ((p->packet[0] == 0x88) || (p->packet[0] == 0x92)) { record_t<> *rec = q->iv->getRecordStruct(RealTimeRunData_Debug); // choose the record structure rec->ts = q->ts; - miStsConsolidate(q, p->packet[0] == 0x88 ? 1 : 2, rec, p->packet[10], p->packet[12], p->packet[9], p->packet[11]); + miStsConsolidate(q, ((p->packet[0] == 0x88) ? 1 : 2), rec, p->packet[10], p->packet[12], p->packet[9], p->packet[11]); } + } + inline void parseDevCtrl(packet_t *p, const queue_s *q) { + if((p->packet[12] != ActivePowerContr) || (p->packet[13] != 0x00)) + return; + bool accepted = true; + if((p->packet[10] == 0x00) && (p->packet[11] == 0x00)) + q->iv->powerLimitAck = true; + else + accepted = false; + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F(" has ")); + if(!accepted) DBGPRINT(F("not ")); + DBGPRINT(F("accepted power limit set point ")); + DBGPRINT(String(q->iv->powerLimit[0])); + DBGPRINT(F(" with PowerLimitControl ")); + DBGPRINTLN(String(q->iv->powerLimit[1])); + q->iv->actPowerLimit = 0xffff; // unknown, readback current value } + inline void compilePayload(const queue_s *q) { + uint16_t crc = 0xffff, crcRcv = 0x0000; + for(uint8_t i = 0; i < mMaxFrameId; i++) { + if(i == (mMaxFrameId - 1)) { + crc = ah::crc16(mLocalBuf[i].buf, mLocalBuf[i].len - 2, crc); + crcRcv = (mLocalBuf[i].buf[mLocalBuf[i].len-2] << 8); + crcRcv |= mLocalBuf[i].buf[mLocalBuf[i].len-1]; + } else + crc = ah::crc16(mLocalBuf[i].buf, mLocalBuf[i].len, crc); + } + + if(crc != crcRcv) { + DPRINT_IVID(DBG_WARN, q->iv->id); + DBGPRINT(F("CRC Error ")); + if(q->attempts == 0) { + DBGPRINTLN(F("-> Fail")); + q->iv->radioStatistics.rxFail++; // got fragments but not complete response + cmdDone(); + } else + DBGPRINTLN(F("-> complete retransmit")); + mState = States::RESET; + return; + } + + /*DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("procPyld: cmd: 0x")); + DBGHEXLN(q->cmd);*/ + + memset(mPayload, 0, MAX_BUFFER); + int8_t rssi = -127; + uint8_t len = 0; + + for(uint8_t i = 0; i < mMaxFrameId; i++) { + if(mLocalBuf[i].len + len > MAX_BUFFER) { + DPRINTLN(DBG_ERROR, F("payload buffer to small!")); + return; + } + memcpy(&mPayload[len], mLocalBuf[i].buf, mLocalBuf[i].len); + len += mLocalBuf[i].len; + // get worst RSSI (high value is better) + if(mLocalBuf[i].rssi > rssi) + rssi = mLocalBuf[i].rssi; + } + + len -= 2; + + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("Payload (")); + DBGPRINT(String(len)); + DBGPRINT(F("): ")); + ah::dumpBuf(mPayload, len); + + record_t<> *rec = q->iv->getRecordStruct(q->cmd); + if(NULL == rec) { + DPRINTLN(DBG_ERROR, F("record is NULL!")); + return; + } + if((rec->pyldLen != len) && (0 != rec->pyldLen)) { + DPRINT(DBG_ERROR, F("plausibility check failed, expected ")); + DBGPRINT(String(rec->pyldLen)); + DBGPRINTLN(F(" bytes")); + q->iv->radioStatistics.rxFail++; + return; + } + + q->iv->radioStatistics.rxSuccess++; + + rec->ts = q->ts; + for (uint8_t i = 0; i < rec->length; i++) { + q->iv->addValue(i, mPayload, rec); + } + + q->iv->rssi = rssi; + q->iv->doCalculations(); + + if(AlarmData == q->cmd) { + uint8_t i = 0; + while(1) { + if(0 == q->iv->parseAlarmLog(i++, mPayload, len)) + break; + if (NULL != mCbAlarm) + (mCbAlarm)(q->iv); + yield(); + } + } + } + + private: inline void miHwDecode(packet_t *p, const queue_s *q) { record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_All); // choose the record structure rec->ts = q->ts; //mPayload[iv->id].gotFragment = true; uint8_t multi_parts = 0; -/* -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_BOOTLOADER_VER, UNIT_NONE, CH0, 8, 2, 1 } -}; -*/ - + /* + 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_BOOTLOADER_VER, UNIT_NONE, CH0, 8, 2, 1 } + }; + */ if ( p->packet[9] == 0x00 ) {//first frame //FLD_FW_VERSION for (uint8_t i = 0; i < 5; i++) { @@ -413,9 +509,6 @@ const byteAssign_t InfoAssignment[] = { q->iv->radioStatistics.rxSuccess++; mState = States::RESET; - //mPayload[iv->id].gotFragment = true; - //mPayload[iv->id].multi_parts += 4; - uint8_t datachan = ( p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES) || p->packet[0] == (MI_REQ_4CH + ALL_FRAMES) ) ? CH1 : ( p->packet[0] == (MI_REQ_CH2 + ALL_FRAMES) || p->packet[0] == (0x37 + ALL_FRAMES) ) ? CH2 : p->packet[0] == (0x38 + ALL_FRAMES) ? CH3 : @@ -434,18 +527,13 @@ const byteAssign_t InfoAssignment[] = { q->iv->setValue(q->iv->getPosByChFld(0, FLD_T, rec), rec, (float) ((int16_t)(p->packet[21] << 8) + p->packet[22])/10); q->iv->setValue(q->iv->getPosByChFld(0, FLD_IRR, rec), rec, (float) (calcIrradiation(q->iv, datachan))); + //mPayload[q->iv->id].rssi[(datachan-1)] = p->rssi; + if (datachan == 1) //mPayload[q->iv->id].rssi[(datachan-1)] = p->rssi; q->iv->rssi = p->rssi; else if(q->iv->rssi > p->rssi) q->iv->rssi = p->rssi; - /*if ( datachan < 3 ) { - mPayload[q->iv->id].dataAB[datachan] = true; - } - if ( !mPayload[iv->id].dataAB[CH0] && mPayload[iv->id].dataAB[CH1] && mPayload[iv->id].dataAB[CH2] ) { - mPayload[iv->id].dataAB[CH0] = true; - }*/ - if (p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES) ) { /*For MI1500: if (MI1500) { @@ -453,14 +541,19 @@ const byteAssign_t InfoAssignment[] = { FCNT = (uint8_t)(p->packet[26]); FCODE = (uint8_t)(p->packet[27]); }*/ - miStsConsolidate(q, datachan, rec, p->packet[23], p->packet[24]); + miStsConsolidate(q, datachan, rec, p->packet[23], p->packet[24]); if (p->packet[0] < (0x39 + ALL_FRAMES) ) { + addImportant(q->iv, (q->cmd + 1)); + //mPayload[iv->id].txCmd++; + //mPayload[iv->id].retransmits = 0; // reserve retransmissions for each response + //mPayload[iv->id].complete = false; miNextRequest((p->packet[0] - ALL_FRAMES + 1), q); } else { miComplete(q->iv); } - } else if((p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES)) && q->iv->type == INV_TYPE_2CH ) { + } else if((p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES)) && (q->iv->type == INV_TYPE_2CH)) { + addImportant(q->iv, MI_REQ_CH2); miNextRequest(MI_REQ_CH2, q); } else { // first data msg for 1ch, 2nd for 2ch miComplete(q->iv); @@ -488,17 +581,6 @@ const byteAssign_t InfoAssignment[] = { } } -/* inline void miStsDecode(Inverter<> *iv, packet_t *p, uint8_t stschan = CH1) { - 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].multi_parts += 3; - 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]) - */ - inline void miStsConsolidate(const queue_s *q, 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 statusMi = 3; // regular status for MI, change to 1 later? @@ -598,113 +680,6 @@ const byteAssign_t InfoAssignment[] = { iv->isProducing(); } - - inline void parseDevCtrl(packet_t *p, const queue_s *q) { - if((p->packet[12] != ActivePowerContr) || (p->packet[13] != 0x00)) - return; - bool accepted = true; - if((p->packet[10] == 0x00) && (p->packet[11] == 0x00)) - q->iv->powerLimitAck = true; - else - accepted = false; - - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("has ")); - if(!accepted) DBGPRINT(F("not ")); - DBGPRINT(F("accepted power limit set point ")); - DBGPRINT(String(q->iv->powerLimit[0])); - DBGPRINT(F(" with PowerLimitControl ")); - DBGPRINTLN(String(q->iv->powerLimit[1])); - q->iv->actPowerLimit = 0xffff; // unknown, readback current value - } - - inline void compilePayload(const queue_s *q) { - uint16_t crc = 0xffff, crcRcv = 0x0000; - for(uint8_t i = 0; i < mMaxFrameId; i++) { - if(i == (mMaxFrameId - 1)) { - crc = ah::crc16(mLocalBuf[i].buf, mLocalBuf[i].len - 2, crc); - crcRcv = (mLocalBuf[i].buf[mLocalBuf[i].len-2] << 8); - crcRcv |= mLocalBuf[i].buf[mLocalBuf[i].len-1]; - } else - crc = ah::crc16(mLocalBuf[i].buf, mLocalBuf[i].len, crc); - } - - if(crc != crcRcv) { - DPRINT_IVID(DBG_WARN, q->iv->id); - DBGPRINT(F("CRC Error ")); - if(q->attempts == 0) { - DBGPRINTLN(F("-> Fail")); - q->iv->radioStatistics.rxFail++; // got fragments but not complete response - cmdDone(); - } else - DBGPRINTLN(F("-> complete retransmit")); - mState = States::RESET; - return; - } - - /*DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("procPyld: cmd: 0x")); - DBGHEXLN(q->cmd);*/ - - memset(mPayload, 0, 150); - int8_t rssi = -127; - uint8_t len = 0; - - for(uint8_t i = 0; i < mMaxFrameId; i++) { - if(mLocalBuf[i].len + len > 150) { - DPRINTLN(DBG_ERROR, F("payload buffer to small!")); - return; - } - memcpy(&mPayload[len], mLocalBuf[i].buf, mLocalBuf[i].len); - len += mLocalBuf[i].len; - // get best RSSI - if(mLocalBuf[i].rssi > rssi) - rssi = mLocalBuf[i].rssi; - } - - len -= 2; - - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("Payload (")); - DBGPRINT(String(len)); - DBGPRINT(F("): ")); - ah::dumpBuf(mPayload, len); - - record_t<> *rec = q->iv->getRecordStruct(q->cmd); - if(NULL == rec) { - DPRINTLN(DBG_ERROR, F("record is NULL!")); - return; - } - if((rec->pyldLen != len) && (0 != rec->pyldLen)) { - DPRINT(DBG_ERROR, F("plausibility check failed, expected ")); - DBGPRINT(String(rec->pyldLen)); - DBGPRINTLN(F(" bytes")); - q->iv->radioStatistics.rxFail++; - return; - } - - q->iv->radioStatistics.rxSuccess++; - - rec->ts = q->ts; - for (uint8_t i = 0; i < rec->length; i++) { - q->iv->addValue(i, mPayload, rec); - } - - q->iv->rssi = rssi; - q->iv->doCalculations(); - - if(AlarmData == q->cmd) { - uint8_t i = 0; - while(1) { - if(0 == q->iv->parseAlarmLog(i++, mPayload, len)) - break; - if (NULL != mCbAlarm) - (mCbAlarm)(q->iv); - yield(); - } - } - } - private: enum class States : uint8_t { RESET, START, WAIT, CHECK_FRAMES, CHECK_PACKAGE @@ -722,7 +697,7 @@ const byteAssign_t InfoAssignment[] = { uint32_t mWaitTimeout = 0; std::array mLocalBuf; uint8_t mMaxFrameId; - uint8_t mPayload[150]; + uint8_t mPayload[MAX_BUFFER]; payloadListenerType mCbPayload = NULL; alarmListenerType mCbAlarm = NULL; }; diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index bbf9167a..4b9add6f 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -197,14 +197,6 @@ class Inverter { else cb(RealTimeRunData_Debug, false); // get live data } else { - /*if (cmd == 0x01) { //0x1 for HM-types - cmd2 = 0x00; - cmd = 0x0f; // for MI, these seem to make part of polling the device software and hardware version number command - } - if (cmd == SystemConfigPara ) { // 0x05 for HM-types - cmd2 = 0x00; - cmd = 0x10; // legacy GPF request - */ if(mDevControlRequest) { cb(devControlCmd, true); mDevControlRequest = false; @@ -215,7 +207,7 @@ class Inverter { if (getChannelFieldValue(CH0, FLD_PART_NUM, rec) == 0) cb(0x0f, false); // hard- and firmware version for missing HW part nr, delivered by frame 1 else - cb(type == INV_TYPE_4CH ? MI_REQ_4CH : MI_REQ_CH1, false); + cb(((type == INV_TYPE_4CH) ? MI_REQ_4CH : MI_REQ_CH1), false); } } } diff --git a/src/hm/hmPayload.h b/src/hm/hmPayload.h index 13f4edd5..1f4ef550 100644 --- a/src/hm/hmPayload.h +++ b/src/hm/hmPayload.h @@ -330,15 +330,15 @@ class HmPayload { mPayload[iv->id].requested = false; mPayload[iv->id].rxTmo = false; - uint8_t payload[150]; + uint8_t payload[MAX_BUFFER]; uint8_t payloadLen = 0; - memset(payload, 0, 150); + memset(payload, 0, MAX_BUFFER); int8_t rssi = -127; for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId); i++) { - if((mPayload[iv->id].len[i] + payloadLen) > 150) { + if((mPayload[iv->id].len[i] + payloadLen) > MAX_BUFFER) { DPRINTLN(DBG_ERROR, F("payload buffer to small!")); break; } From 46b37cadde88cbc62add022cfcc8e4ff15bc0dbe Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Sun, 22 Oct 2023 10:27:01 +0200 Subject: [PATCH 147/267] review MI next cmd queuing - still sends out to much messages and shows some strange behaviour --- src/hm/CommQueue.h | 14 ++++++++++++++ src/hm/Communication.h | 8 +++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index ae947504..1acda1a1 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -29,6 +29,10 @@ class CommQueue { inc(&mWrPtr); } + void chgCmd(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) { + mQueue[mWrPtr] = queue_s(iv, cmd, delOnPop, false); + } + protected: struct queue_s { Inverter<> *iv; @@ -37,6 +41,7 @@ class CommQueue { uint32_t ts; bool delOnPop; bool isDevControl; + bool firstTry; queue_s() {} queue_s(Inverter<> *i, uint8_t c, bool d, bool dev) : iv(i), cmd(c), attempts(5), ts(0), delOnPop(d), isDevControl(dev) {} @@ -45,6 +50,10 @@ class CommQueue { protected: void add(queue_s q) { mQueue[mWrPtr] = q; + /*mQueue[mRdPtr].firstTry = false; + if((IV_HM == mQueue[mRdPtr].iv->ivGen) || (IV_MI == mQueue[mRdPtr].iv->ivGen)) { + mQueue[mRdPtr].firstTry = ((mQueue[mRdPtr].iv->isAvailable()) || (millis() < 120000)); + }*/ inc(&mWrPtr); } @@ -59,6 +68,11 @@ class CommQueue { inc(&mWrPtr); } + void chgCmd(uint8_t cmd) { + mQueue[mRdPtr].cmd = cmd; + mQueue[mRdPtr].isDevControl = false; + } + void get(std::function cb) { if(mRdPtr == mWrPtr) { cb(false, &mQueue[mRdPtr]); // empty diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 1a23ca07..aaf52a64 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -541,10 +541,10 @@ class Communication : public CommQueue<> { FCNT = (uint8_t)(p->packet[26]); FCODE = (uint8_t)(p->packet[27]); }*/ - miStsConsolidate(q, datachan, rec, p->packet[23], p->packet[24]); + miStsConsolidate(q, datachan, rec, p->packet[23], p->packet[24]); if (p->packet[0] < (0x39 + ALL_FRAMES) ) { - addImportant(q->iv, (q->cmd + 1)); + //addImportant(q->iv, (q->cmd + 1)); //mPayload[iv->id].txCmd++; //mPayload[iv->id].retransmits = 0; // reserve retransmissions for each response //mPayload[iv->id].complete = false; @@ -553,7 +553,7 @@ class Communication : public CommQueue<> { miComplete(q->iv); } } else if((p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES)) && (q->iv->type == INV_TYPE_2CH)) { - addImportant(q->iv, MI_REQ_CH2); + //addImportant(q->iv, MI_REQ_CH2); miNextRequest(MI_REQ_CH2, q); } else { // first data msg for 1ch, 2nd for 2ch miComplete(q->iv); @@ -573,6 +573,8 @@ class Communication : public CommQueue<> { q->iv->radio->sendCmdPacket(q->iv, cmd, 0x00, true); q->iv->radioStatistics.retransmits++; mWaitTimeout = millis() + MI_TIMEOUT; + //chgCmd(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) + chgCmd(cmd); mState = States::WAIT; } else { add(q, true); From 06a1159d4fc7375c4907793f1738a0b417a2871a Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Sun, 22 Oct 2023 17:45:05 +0200 Subject: [PATCH 148/267] various changes might not all be correct... --- src/hm/Communication.h | 35 +++++++++++++++++++++++------------ src/hm/hmInverter.h | 16 +++++++--------- src/hm/radio.h | 5 ++--- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index aaf52a64..056b9b47 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -12,7 +12,8 @@ #define MI_TIMEOUT 250 #define DEFAULT_TIMEOUT 500 -#define MAX_BUFFER 200 //was: 150 (hardcoded) +#define SINGLEFR_TIMEOUT 60 +#define MAX_BUFFER 250 //was: 150 (hardcoded) typedef std::function *)> payloadListenerType; typedef std::function *)> alarmListenerType; @@ -134,7 +135,8 @@ class Communication : public CommQueue<> { yield(); } if(0 == q->attempts) { - cmdDone(q); + //cmdDone(q); + cmdDone(true); mState = States::RESET; } else mState = nextState; @@ -161,11 +163,12 @@ class Communication : public CommQueue<> { if(q->attempts) { q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true); q->iv->radioStatistics.retransmits++; - mWaitTimeout = millis() + timeout; + mWaitTimeout = millis() + SINGLEFR_TIMEOUT; // timeout mState = States::WAIT; } else { add(q, true); - cmdDone(q); + //cmdDone(q); + cmdDone(true); mState = States::RESET; } return; @@ -185,11 +188,12 @@ class Communication : public CommQueue<> { if(q->attempts) { q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true); q->iv->radioStatistics.retransmits++; - mWaitTimeout = millis() + timeout; + mWaitTimeout = millis() + SINGLEFR_TIMEOUT; // timeout; mState = States::WAIT; } else { add(q, true); - cmdDone(q); + //cmdDone(q); + cmdDone(true); mState = States::RESET; } return; @@ -486,7 +490,7 @@ class Communication : public CommQueue<> { multi_parts++; } if(multi_parts > 5) { - cmdDone(q); + cmdDone(true); mState = States::RESET; q->iv->radioStatistics.rxSuccess++; } @@ -558,7 +562,6 @@ class Communication : public CommQueue<> { } else { // first data msg for 1ch, 2nd for 2ch miComplete(q->iv); } - //cmdDone(q); } inline void miNextRequest(uint8_t cmd, const queue_s *q) { @@ -578,7 +581,7 @@ class Communication : public CommQueue<> { mState = States::WAIT; } else { add(q, true); - cmdDone(q); + cmdDone(); mState = States::RESET; } } @@ -607,17 +610,23 @@ class Communication : public CommQueue<> { bool stsok = true; if ( prntsts != rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)] ) { //sth.'s changed? q->iv->alarmCnt = 1; // minimum... + stsok = false; //sth is or was wrong? if ( (q->iv->type != INV_TYPE_1CH) && ( (statusMi != 3) || ((q->iv->lastAlarm[stschan].code) && (statusMi == 3) && (q->iv->lastAlarm[stschan].code != 1))) ) { + q->iv->lastAlarm[stschan+q->iv->type==INV_TYPE_2CH ? 2: 4] = alarm_t(q->iv->lastAlarm[stschan].code, q->iv->lastAlarm[stschan].start,q->ts); q->iv->lastAlarm[stschan] = alarm_t(prntsts, q->ts,0); q->iv->alarmCnt = q->iv->type == INV_TYPE_2CH ? 3 : 5; - } + } else if ( (q->iv->type == INV_TYPE_1CH) && ( (statusMi != 3) + || ((q->iv->lastAlarm[stschan].code) && (statusMi == 3) && (q->iv->lastAlarm[stschan].code != 1))) + ) { + q->iv->lastAlarm[stschan] = alarm_t(q->iv->lastAlarm[0].code, q->iv->lastAlarm[0].start,q->ts); + } else if (q->iv->type == INV_TYPE_1CH) + stsok = true; q->iv->alarmLastId = prntsts; //iv->alarmMesIndex; - stsok = false; if (q->iv->alarmCnt > 1) { //more than one channel for (uint8_t ch = 0; ch < (q->iv->alarmCnt); ++ch) { //start with 1 if (q->iv->lastAlarm[ch].code == 1) { @@ -679,7 +688,9 @@ class Communication : public CommQueue<> { iv->doCalculations(); // update status state-machine, - iv->isProducing(); + if (ac_pow) + iv->isProducing(); + cmdDone(true); } private: diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 4b9add6f..0bac7e4c 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -182,11 +182,12 @@ class Inverter { } void tickSend(std::function cb) { - if (IV_MI != ivGen) { - if(mDevControlRequest) { - cb(devControlCmd, true); - mDevControlRequest = false; - } else if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) + if(mDevControlRequest) { + cb(devControlCmd, true); + mDevControlRequest = false; + } + else if (IV_MI != ivGen) { + if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) cb(AlarmData, false); // get last alarms else if(0 == getFwVersion()) cb(InverterDevInform_All, false); // get firmware version @@ -197,10 +198,7 @@ class Inverter { else cb(RealTimeRunData_Debug, false); // get live data } else { - if(mDevControlRequest) { - cb(devControlCmd, true); - mDevControlRequest = false; - } else if(0 == getFwVersion()) + if(0 == getFwVersion()) cb(0x0f, false); // get firmware version; for MI, this makes part of polling the device software and hardware version number else { record_t<> *rec = getRecordStruct(InverterDevInform_Simple); diff --git a/src/hm/radio.h b/src/hm/radio.h index 75db5436..79239022 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -44,9 +44,8 @@ class Radio { void prepareDevInformCmd(Inverter<> *iv, 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. if(IV_MI == getIvGen(iv)) { - DPRINT_IVID(DBG_INFO, getIvId(iv)); - DBGPRINT(F("legacy cmd 0x")); - DBGHEXLN(cmd); + DPRINT(DBG_DEBUG, F("legacy cmd 0x")); + DPRINTLN(DBG_DEBUG,String(cmd, HEX)); sendCmdPacket(iv, cmd, cmd, false, false); return; } From 7a97124bf7bdb4e931a5c71ce27379127936b26e Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 23 Oct 2023 22:23:21 +0200 Subject: [PATCH 149/267] small corrections after merging #1219 --- src/hm/CommQueue.h | 6 +- src/hm/Communication.h | 2 +- src/hm/hmInverter.h | 3 +- src/web/html/h/about_html.h | 82 --- src/web/html/h/api_js.h | 216 ------ src/web/html/h/colorBright_css.h | 22 - src/web/html/h/colorDark_css.h | 21 - src/web/html/h/favicon_ico.h | 101 --- src/web/html/h/index_html.h | 191 ----- src/web/html/h/login_html.h | 47 -- src/web/html/h/save_html.h | 86 --- src/web/html/h/serial_html.h | 113 --- src/web/html/h/setup_html.h | 545 --------------- src/web/html/h/style_css.h | 188 ----- src/web/html/h/system_html.h | 139 ---- src/web/html/h/update_html.h | 74 -- src/web/html/h/visualization_html.h | 275 -------- src/web/html/tmp/about.html | 100 --- src/web/html/tmp/index.html | 263 ------- src/web/html/tmp/login.html | 43 -- src/web/html/tmp/save.html | 102 --- src/web/html/tmp/serial.html | 132 ---- src/web/html/tmp/setup.html | 1000 --------------------------- src/web/html/tmp/style.css | 781 --------------------- src/web/html/tmp/system.html | 188 ----- src/web/html/tmp/update.html | 80 --- src/web/html/tmp/visualization.html | 479 ------------- 27 files changed, 5 insertions(+), 5274 deletions(-) delete mode 100644 src/web/html/h/about_html.h delete mode 100644 src/web/html/h/api_js.h delete mode 100644 src/web/html/h/colorBright_css.h delete mode 100644 src/web/html/h/colorDark_css.h delete mode 100644 src/web/html/h/favicon_ico.h delete mode 100644 src/web/html/h/index_html.h delete mode 100644 src/web/html/h/login_html.h delete mode 100644 src/web/html/h/save_html.h delete mode 100644 src/web/html/h/serial_html.h delete mode 100644 src/web/html/h/setup_html.h delete mode 100644 src/web/html/h/style_css.h delete mode 100644 src/web/html/h/system_html.h delete mode 100644 src/web/html/h/update_html.h delete mode 100644 src/web/html/h/visualization_html.h delete mode 100644 src/web/html/tmp/about.html delete mode 100644 src/web/html/tmp/index.html delete mode 100644 src/web/html/tmp/login.html delete mode 100644 src/web/html/tmp/save.html delete mode 100644 src/web/html/tmp/serial.html delete mode 100644 src/web/html/tmp/setup.html delete mode 100644 src/web/html/tmp/style.css delete mode 100644 src/web/html/tmp/system.html delete mode 100644 src/web/html/tmp/update.html delete mode 100644 src/web/html/tmp/visualization.html diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index 1acda1a1..4042935d 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -41,7 +41,7 @@ class CommQueue { uint32_t ts; bool delOnPop; bool isDevControl; - bool firstTry; + //bool firstTry; queue_s() {} queue_s(Inverter<> *i, uint8_t c, bool d, bool dev) : iv(i), cmd(c), attempts(5), ts(0), delOnPop(d), isDevControl(dev) {} @@ -89,12 +89,12 @@ class CommQueue { inc(&mRdPtr); } - bool isFirstTry(void) { + /*bool isFirstTry(void) { if(!mQueue[mRdPtr].firstTry) return false; mQueue[mRdPtr].firstTry = false; return true; - } + }*/ void setTs(uint32_t *ts) { mQueue[mRdPtr].ts = *ts; diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 8dc816e7..8a7a9e7a 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -13,7 +13,7 @@ #define MI_TIMEOUT 250 #define DEFAULT_TIMEOUT 500 #define SINGLEFR_TIMEOUT 60 -#define MAX_BUFFER 250 //was: 150 (hardcoded) +#define MAX_BUFFER 250 typedef std::function *)> payloadListenerType; typedef std::function *)> alarmListenerType; diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 0bac7e4c..d1a1e43a 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -185,8 +185,7 @@ class Inverter { if(mDevControlRequest) { cb(devControlCmd, true); mDevControlRequest = false; - } - else if (IV_MI != ivGen) { + } else if (IV_MI != ivGen) { if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) cb(AlarmData, false); // get last alarms else if(0 == getFwVersion()) diff --git a/src/web/html/h/about_html.h b/src/web/html/h/about_html.h deleted file mode 100644 index 1e486394..00000000 --- a/src/web/html/h/about_html.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef __ABOUT_HTML_H__ -#define __ABOUT_HTML_H__ -#define about_html_len 1227 -const uint8_t about_html[] PROGMEM = { -0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0xc5, 0x58, 0x6d, 0x6f, 0xdb, 0x36, -0x10, 0xfe, 0xbe, 0x5f, 0xc1, 0xea, 0xc3, 0x90, 0x00, 0x91, 0xe9, 0x38, 0x49, 0x93, 0xba, 0xb6, -0x37, 0xd7, 0x49, 0xb3, 0x0c, 0x6d, 0x11, 0xc4, 0x09, 0x8a, 0x62, 0x18, 0x0a, 0x8a, 0xa2, 0x24, -0x26, 0x14, 0xa9, 0x92, 0x94, 0x63, 0x77, 0xe8, 0x7f, 0x1f, 0x29, 0xf9, 0x45, 0xaf, 0x4e, 0xba, -0xba, 0x58, 0x3e, 0x44, 0xd6, 0xf1, 0x5e, 0x9e, 0x3b, 0xde, 0x9d, 0x8e, 0x1c, 0xbc, 0xf0, 0x05, -0xd6, 0x8b, 0x84, 0x80, 0x48, 0xc7, 0x6c, 0xf4, 0xcb, 0x20, 0x7f, 0x00, 0xf3, 0x37, 0x88, 0x08, -0xf2, 0xf3, 0x9f, 0xd9, 0xab, 0xa6, 0x9a, 0x91, 0xd1, 0xd8, 0x13, 0xa9, 0x1e, 0xc0, 0xfc, 0x65, -0xb3, 0xc8, 0x28, 0x7f, 0x00, 0x92, 0xb0, 0xa1, 0xa3, 0xf4, 0x82, 0x11, 0x15, 0x11, 0xa2, 0x1d, -0x60, 0x15, 0x0f, 0x1d, 0x4d, 0xe6, 0x1a, 0x62, 0xa5, 0x1c, 0x10, 0x49, 0x12, 0x2c, 0x39, 0x3a, -0x86, 0xf0, 0xdb, 0x6c, 0xd8, 0xed, 0x9c, 0x75, 0xba, 0xdd, 0xee, 0xa1, 0x03, 0x8d, 0xed, 0x98, -0x68, 0x04, 0x38, 0x8a, 0x8d, 0xcc, 0x8c, 0x92, 0xc7, 0x44, 0x48, 0xa3, 0x03, 0x0b, 0xae, 0x09, -0xd7, 0x43, 0xe7, 0x91, 0xfa, 0x3a, 0x1a, 0xfa, 0x64, 0x46, 0x31, 0x71, 0xb3, 0x97, 0x03, 0x40, -0x39, 0xd5, 0x14, 0x31, 0x57, 0x61, 0xc4, 0xc8, 0xf0, 0xd0, 0x59, 0x29, 0xc1, 0x11, 0x92, 0x8a, -0x18, 0xa1, 0xbb, 0xdb, 0xb7, 0xee, 0x99, 0x25, 0x2b, 0x2c, 0x69, 0xa2, 0x8b, 0x88, 0xee, 0xd1, -0x0c, 0xe5, 0x54, 0x07, 0x28, 0x89, 0x87, 0x0e, 0x4a, 0x68, 0xe7, 0xbe, 0x04, 0x6a, 0x34, 0x80, -0x39, 0x87, 0x51, 0xf0, 0x3d, 0x1e, 0x62, 0xc1, 0x84, 0x54, 0x4f, 0xb8, 0x28, 0x85, 0x27, 0xb4, -0x2a, 0x38, 0xc8, 0x05, 0xe5, 0x3e, 0x99, 0x1f, 0x00, 0x2e, 0x02, 0xc1, 0x98, 0x78, 0x74, 0x00, -0x5c, 0x6e, 0x05, 0xdc, 0xec, 0xc5, 0xc0, 0x13, 0xfe, 0xa2, 0x10, 0x79, 0x9f, 0xce, 0x00, 0x66, -0x48, 0x29, 0x03, 0x43, 0x24, 0x1c, 0xcd, 0x9c, 0x25, 0x1f, 0x5a, 0x82, 0x81, 0x45, 0x0c, 0x6b, -0x56, 0xbb, 0x7f, 0xce, 0x68, 0x1c, 0x89, 0xc5, 0xf9, 0xed, 0xdd, 0x00, 0xa2, 0x8a, 0xd0, 0x26, -0x38, 0xfd, 0x99, 0xa0, 0xfe, 0x5e, 0x77, 0xff, 0xf5, 0x5a, 0x96, 0x1a, 0xc4, 0x0e, 0x10, 0x1c, -0x33, 0x8a, 0x1f, 0x56, 0x56, 0xf7, 0xf6, 0x9d, 0x02, 0x28, 0x95, 0x20, 0x6e, 0x83, 0x67, 0x1f, -0xdf, 0x4d, 0xdd, 0xa0, 0xb1, 0xbe, 0x51, 0x7f, 0xed, 0xd8, 0x0a, 0x40, 0x2c, 0x3c, 0x6a, 0xd1, -0x6f, 0x74, 0xa0, 0x8c, 0xcd, 0xf0, 0x1c, 0xad, 0x99, 0x22, 0xea, 0x93, 0xd5, 0x7e, 0x40, 0x46, -0x67, 0xa4, 0xb4, 0xb1, 0xef, 0x0c, 0x61, 0x6d, 0xa7, 0xac, 0xe2, 0xb8, 0x59, 0x85, 0x22, 0xd2, -0x64, 0x5a, 0x49, 0xc9, 0x47, 0xe2, 0xe5, 0xd4, 0x16, 0x4d, 0x27, 0x6d, 0x9a, 0x74, 0x9a, 0x94, -0x14, 0x4d, 0x89, 0xd6, 0x94, 0x87, 0xaa, 0xac, 0xc7, 0x46, 0x64, 0xa5, 0x40, 0x91, 0x84, 0x48, -0xa4, 0x85, 0x74, 0xea, 0x01, 0x5c, 0xdb, 0x7b, 0xd9, 0x6c, 0x2f, 0x4d, 0x7c, 0xa4, 0xcb, 0xee, -0xdf, 0x65, 0xa4, 0x16, 0xd8, 0xa7, 0x2d, 0xb0, 0x17, 0x4a, 0x93, 0xb8, 0x8c, 0x3b, 0x23, 0xfd, -0x20, 0xea, 0xb3, 0xb5, 0x05, 0x53, 0x80, 0xa6, 0xa2, 0x90, 0x0c, 0x6d, 0xe5, 0x7e, 0xf6, 0x18, -0xe2, 0x0f, 0xce, 0xe8, 0xe6, 0x62, 0x7a, 0x0b, 0xc6, 0xd7, 0x57, 0x2d, 0x60, 0x5f, 0xad, 0xa4, -0x23, 0xad, 0x13, 0xd5, 0x87, 0x10, 0x99, 0x94, 0xf6, 0x75, 0xda, 0xb1, 0xc8, 0xab, 0xba, 0xce, -0x05, 0x4e, 0x63, 0x53, 0x6b, 0x48, 0x53, 0xc1, 0x5b, 0x14, 0x1e, 0x76, 0x37, 0x78, 0x6c, 0xaf, -0x2b, 0x39, 0xbc, 0xec, 0x7e, 0x3f, 0xe4, 0x6f, 0xb7, 0x25, 0x45, 0x45, 0x48, 0xb9, 0x49, 0x4c, -0xfb, 0x68, 0x83, 0xd6, 0x2a, 0x69, 0x50, 0x65, 0xa2, 0x45, 0x74, 0x03, 0x68, 0xca, 0xa7, 0x52, -0x48, 0x8f, 0x34, 0xa0, 0x79, 0xf9, 0xae, 0x6a, 0x99, 0x07, 0xc2, 0x82, 0xcd, 0x58, 0x0b, 0x12, -0x65, 0x29, 0x89, 0x12, 0xe3, 0x58, 0xa1, 0xe0, 0x4a, 0xcb, 0xcb, 0x06, 0x56, 0x59, 0xae, 0x36, -0xa7, 0x78, 0xe1, 0x1e, 0x19, 0x4b, 0x51, 0x2f, 0x0f, 0x22, 0x58, 0xb7, 0x1e, 0x43, 0xa9, 0x18, -0x6e, 0x17, 0xaf, 0xb1, 0x54, 0xd9, 0xa4, 0x78, 0x04, 0x96, 0x15, 0xd8, 0x86, 0xd9, 0xc2, 0x5f, -0x95, 0x49, 0xdc, 0x9e, 0xa9, 0x08, 0x45, 0x7c, 0xf0, 0x8e, 0x7a, 0x12, 0x49, 0x4a, 0x54, 0x0b, -0xa0, 0x4a, 0x58, 0x9f, 0x00, 0x62, 0xbc, 0x45, 0x95, 0xe4, 0x0c, 0xa9, 0x8e, 0x52, 0xaf, 0x83, -0x45, 0x0c, 0x3d, 0x22, 0x75, 0x4c, 0x18, 0x55, 0x90, 0xa8, 0xe4, 0xfd, 0x17, 0xad, 0x27, 0x8c, -0xda, 0x28, 0xd6, 0x92, 0xb6, 0x85, 0xd1, 0xee, 0xf3, 0xae, 0xb0, 0x2c, 0x52, 0x4f, 0xcc, 0x5d, -0x2e, 0x7c, 0xe2, 0x0a, 0x19, 0xc2, 0x8b, 0xe9, 0xf5, 0x58, 0x2d, 0x38, 0x36, 0xfd, 0x6d, 0x4a, -0xe4, 0xcc, 0xec, 0x7c, 0x0d, 0xd4, 0x53, 0x12, 0xbb, 0x44, 0xe7, 0x59, 0x9b, 0x38, 0x12, 0x1c, -0x8e, 0xa5, 0x9f, 0x52, 0x2e, 0xfe, 0x54, 0x36, 0x83, 0x6b, 0x71, 0x6a, 0x62, 0xdb, 0x25, 0x0e, -0x2e, 0x83, 0xde, 0x31, 0xbc, 0x79, 0xdb, 0x3b, 0xae, 0x1b, 0xdf, 0xac, 0xed, 0xd2, 0x62, 0x82, -0x52, 0xa6, 0xb4, 0x08, 0x02, 0x49, 0x42, 0xc2, 0xe1, 0x2d, 0x8d, 0x1b, 0x9a, 0x5a, 0x03, 0xd3, -0x2e, 0x31, 0x08, 0x46, 0x1f, 0x24, 0x4a, 0x15, 0xbc, 0x3b, 0x0b, 0x7b, 0x75, 0xeb, 0xa5, 0xe5, -0x5d, 0xda, 0xfd, 0x6a, 0x3e, 0x88, 0xe1, 0x7d, 0x0c, 0x2f, 0xe7, 0x17, 0xd7, 0xe7, 0x0d, 0x86, -0xcb, 0xeb, 0x05, 0xcb, 0x3f, 0xaf, 0x47, 0x4c, 0x4c, 0xa3, 0x43, 0x58, 0x83, 0x2b, 0xd3, 0x34, -0x65, 0xbc, 0xfc, 0x88, 0xec, 0xa4, 0x51, 0x3c, 0x0b, 0x83, 0x99, 0x2a, 0xdd, 0x13, 0x60, 0xff, -0xab, 0xd8, 0x36, 0xc3, 0xcb, 0x2c, 0x58, 0xe0, 0x86, 0x24, 0x42, 0x51, 0xf3, 0xd1, 0x59, 0x6c, -0xb1, 0xd8, 0xa4, 0xeb, 0x74, 0xa5, 0xeb, 0xd5, 0xf6, 0x9d, 0x60, 0x69, 0x8c, 0x92, 0x34, 0xfb, -0xb0, 0x3a, 0xa3, 0xed, 0xeb, 0x4f, 0x25, 0xc0, 0xcf, 0x0e, 0xc9, 0x39, 0x55, 0x58, 0x48, 0x1f, -0x4c, 0x22, 0xa4, 0x77, 0x19, 0x0d, 0x3f, 0xd7, 0xdb, 0x09, 0x43, 0xf8, 0xf1, 0x6b, 0x34, 0xbf, -0xf8, 0xf4, 0xb2, 0x17, 0xbf, 0x69, 0x98, 0x2f, 0x72, 0xb6, 0xff, 0x3b, 0x0a, 0x17, 0xee, 0x7b, -0x44, 0xd9, 0x2e, 0xfc, 0x8f, 0x8d, 0x1e, 0x2d, 0xfa, 0x38, 0x4f, 0xfc, 0xdf, 0x0b, 0xb3, 0xd5, -0xa8, 0x4e, 0xfb, 0x6f, 0x6e, 0x37, 0x90, 0xab, 0x73, 0x48, 0xcb, 0x58, 0x12, 0x08, 0xa1, 0x4b, -0x53, 0x49, 0xd1, 0x25, 0x46, 0x02, 0x5d, 0x3e, 0x21, 0x3c, 0x7f, 0x4c, 0x5c, 0x8e, 0x26, 0xe0, -0x57, 0x2c, 0x92, 0x05, 0xe8, 0x75, 0x7b, 0x47, 0xe5, 0x81, 0x2c, 0x65, 0x15, 0xbc, 0x8c, 0xee, -0x26, 0x65, 0x8c, 0x9e, 0xa7, 0x15, 0xb7, 0x54, 0x66, 0x4d, 0x73, 0xde, 0x1e, 0xea, 0x8a, 0x07, -0x70, 0x85, 0xbf, 0x3a, 0x21, 0xae, 0x12, 0x8f, 0x86, 0x51, 0x29, 0x76, 0x2d, 0xfe, 0x56, 0x0c, -0x3e, 0x0b, 0x26, 0x34, 0xef, 0x31, 0xd5, 0x0a, 0x7a, 0xc1, 0xe9, 0x69, 0xef, 0xf4, 0xc4, 0xc0, -0xbc, 0xba, 0x05, 0xd3, 0x3f, 0xc6, 0x7d, 0xb0, 0xa4, 0x80, 0x7e, 0x1f, 0xac, 0x06, 0xee, 0xd6, -0xa8, 0x64, 0xfb, 0x6f, 0xc6, 0xa1, 0xcf, 0xf6, 0xfc, 0xed, 0x3c, 0x37, 0x72, 0x58, 0x12, 0xd3, -0xb4, 0x67, 0xc4, 0x62, 0x10, 0x5c, 0x75, 0xec, 0xe4, 0x62, 0xce, 0xb0, 0x84, 0x2b, 0x62, 0x00, -0x2d, 0x5c, 0x8e, 0x5d, 0x85, 0xe0, 0x71, 0xa7, 0x0b, 0x7d, 0x42, 0xfc, 0x5a, 0x44, 0xc1, 0x68, -0x32, 0x01, 0x6f, 0x3e, 0xb9, 0x1f, 0x26, 0xee, 0x74, 0x0c, 0x0c, 0xdb, 0x33, 0x62, 0x5b, 0xcd, -0xdd, 0xad, 0xd7, 0x10, 0x65, 0x17, 0x82, 0x94, 0x63, 0xfb, 0x89, 0x01, 0x89, 0xbd, 0xcb, 0xb8, -0x24, 0xdc, 0x1c, 0x35, 0xf1, 0x9e, 0xf0, 0xee, 0xf7, 0xc1, 0x3f, 0xb5, 0x2a, 0xca, 0x78, 0x3e, -0x98, 0x63, 0xb8, 0x5d, 0x7f, 0xdd, 0xbc, 0x6c, 0x86, 0xb4, 0x6d, 0xcb, 0x37, 0x4a, 0xd1, 0x86, -0xf5, 0x6f, 0x5b, 0x40, 0xb5, 0xa1, 0xa1, 0xc1, 0x1e, 0x4f, 0x19, 0x03, 0x2f, 0x86, 0xa0, 0x85, -0x63, 0x6d, 0xb5, 0xe0, 0xd7, 0x5f, 0x4e, 0x98, 0xbf, 0x38, 0x7f, 0x37, 0x60, 0xfc, 0xb6, 0x05, -0x95, 0xd9, 0xa5, 0xf1, 0x3d, 0x9a, 0xef, 0x65, 0x47, 0x48, 0x68, 0xaf, 0xb0, 0xa0, 0x42, 0x33, -0xe2, 0x1c, 0xe4, 0x36, 0x0a, 0xda, 0x36, 0x17, 0x3a, 0xf9, 0x5b, 0x7e, 0x99, 0x32, 0x80, 0xf9, -0xb5, 0xd7, 0xbf, 0x27, 0x09, 0x59, 0x3f, 0x0e, 0x13, 0x00, 0x00}; -#endif /*__ABOUT_HTML_H__*/ diff --git a/src/web/html/h/api_js.h b/src/web/html/h/api_js.h deleted file mode 100644 index d9bf93cb..00000000 --- a/src/web/html/h/api_js.h +++ /dev/null @@ -1,216 +0,0 @@ -#ifndef __API_JS_H__ -#define __API_JS_H__ -#define api_js_len 3363 -const uint8_t api_js[] PROGMEM = { -0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0xdd, 0x59, 0x79, 0x6f, 0xdb, 0x46, -0x16, 0xff, 0xdf, 0x9f, 0x62, 0x42, 0x60, 0x63, 0x2a, 0x91, 0x46, 0xbc, 0x8f, 0xb8, 0xea, 0x42, -0x75, 0x9d, 0xc4, 0x0b, 0xc7, 0x2e, 0x62, 0xb7, 0xbb, 0x80, 0x61, 0x04, 0xb4, 0x34, 0xb6, 0xd8, -0x50, 0xa4, 0x96, 0xa4, 0xec, 0xc4, 0x85, 0xbf, 0xfb, 0xfe, 0xde, 0x90, 0x94, 0x78, 0xc9, 0xf1, -0x9e, 0x2d, 0x56, 0x31, 0xaf, 0x99, 0x77, 0x5f, 0xf3, 0x66, 0x32, 0x7e, 0xf5, 0x6a, 0x8f, 0xbd, -0x62, 0xe7, 0xbf, 0xbc, 0x63, 0xc7, 0x87, 0x67, 0xa7, 0xe7, 0xf8, 0x18, 0xef, 0xed, 0x85, 0xb3, -0x24, 0xfe, 0x6b, 0x78, 0x13, 0xea, 0x6c, 0xc2, 0x2e, 0xf7, 0x18, 0x7e, 0xca, 0x07, 0x5d, 0xe7, -0x9a, 0xe5, 0x30, 0x5d, 0xe3, 0x96, 0x6d, 0xcd, 0xb8, 0x61, 0x38, 0x23, 0xba, 0x71, 0xdd, 0xb3, -0x47, 0xdc, 0xd1, 0x70, 0xd3, 0x47, 0xdc, 0xb5, 0xa7, 0x0e, 0xb7, 0x5c, 0x93, 0x15, 0x77, 0x4d, -0xfe, 0xf3, 0x98, 0x3f, 0x1b, 0x01, 0xdb, 0x61, 0xda, 0xc8, 0xc0, 0xc3, 0xe0, 0x86, 0x6d, 0xe1, -0xcd, 0xb7, 0x1c, 0xee, 0x6a, 0x16, 0xc8, 0x78, 0x36, 0xd7, 0x2d, 0x50, 0x30, 0x41, 0xcf, 0x36, -0x30, 0xa2, 0x83, 0x52, 0xc4, 0x35, 0xdd, 0xa6, 0x6b, 0xc6, 0x75, 0x87, 0xfe, 0x2c, 0xcd, 0xe5, -0xba, 0xcf, 0x1d, 0x92, 0xc4, 0x9f, 0xda, 0xe0, 0xe0, 0xb1, 0xe2, 0x4e, 0x5c, 0x74, 0xf0, 0xd1, -0xb5, 0x19, 0xf7, 0x1c, 0xfa, 0xd6, 0xb9, 0xe3, 0x73, 0x43, 0xd3, 0x99, 0xc1, 0x2d, 0x83, 0xdb, -0x0e, 0xde, 0x4d, 0x50, 0xb5, 0x40, 0xd0, 0x25, 0x0a, 0x23, 0x90, 0xd0, 0x25, 0x87, 0x11, 0xdd, -0x1e, 0x3e, 0xf8, 0x24, 0x9f, 0x0e, 0x68, 0xe8, 0xa6, 0xfb, 0xd0, 0x0d, 0x37, 0x5c, 0xde, 0x08, -0x02, 0x01, 0x04, 0x32, 0x39, 0xce, 0x54, 0xe7, 0xbe, 0xcf, 0xe4, 0xad, 0xd2, 0x0c, 0xb2, 0xd8, -0x41, 0x6b, 0x98, 0x74, 0x85, 0x8e, 0xde, 0x0c, 0x9a, 0x99, 0x1e, 0x34, 0xa3, 0x27, 0xc4, 0x77, -0x2c, 0x22, 0x04, 0x3a, 0x11, 0xd4, 0x26, 0xd5, 0x9d, 0x80, 0xdb, 0xdc, 0x2e, 0x69, 0xe1, 0xdb, -0x65, 0x1a, 0x4d, 0x81, 0x27, 0xde, 0x1f, 0x94, 0xbd, 0xab, 0x83, 0xad, 0x2b, 0x8c, 0xba, 0x2b, -0x4c, 0x58, 0xde, 0x67, 0x1e, 0x37, 0x5c, 0x1d, 0x9e, 0xd0, 0xc9, 0x13, 0x64, 0x22, 0x1f, 0x0c, -0x6c, 0x17, 0xe8, 0x9a, 0x63, 0x82, 0x86, 0x65, 0x4f, 0x7d, 0x68, 0xec, 0xb0, 0xe2, 0x5e, 0x89, -0xec, 0x90, 0x33, 0x7c, 0x0d, 0x7c, 0x47, 0x26, 0x77, 0x3c, 0x18, 0x67, 0x04, 0xf3, 0x3b, 0xd0, -0x1e, 0xaa, 0x42, 0x24, 0xcb, 0xc3, 0x5f, 0xa9, 0x09, 0x51, 0x22, 0x42, 0x98, 0x91, 0x57, 0x25, -0xab, 0x63, 0x93, 0x23, 0xed, 0x29, 0x40, 0x1d, 0x26, 0x6f, 0x95, 0x0b, 0xdc, 0xa0, 0x3d, 0x66, -0x41, 0x26, 0x17, 0xc4, 0x4d, 0xd3, 0x81, 0xb0, 0x1a, 0x78, 0x99, 0x06, 0x31, 0xd1, 0x35, 0x8f, -0xe8, 0x10, 0x0f, 0xfb, 0x61, 0x89, 0x78, 0xd0, 0x3d, 0x93, 0xc9, 0xfb, 0xef, 0x14, 0x5d, 0xde, -0xff, 0x77, 0x74, 0x79, 0x45, 0x74, 0xb9, 0x7d, 0xd1, 0x65, 0xd6, 0xa3, 0xcb, 0xe6, 0xa6, 0x67, -0xc1, 0xc6, 0xba, 0x6e, 0x53, 0x34, 0xd8, 0x74, 0x6d, 0xe2, 0xc1, 0x22, 0x7c, 0x13, 0xc2, 0x92, -0x32, 0x16, 0x2b, 0x1f, 0x95, 0xc0, 0xe6, 0xa1, 0x0d, 0xf3, 0xfb, 0x8c, 0x1c, 0xe9, 0x1a, 0x26, -0x33, 0xb9, 0xe7, 0x19, 0x90, 0xc9, 0x84, 0x29, 0x4d, 0xd7, 0xef, 0x21, 0xe7, 0x11, 0x35, 0x6e, -0xeb, 0x1e, 0x5d, 0x9b, 0xf0, 0x42, 0x58, 0x6a, 0xf6, 0x14, 0xea, 0x5b, 0x96, 0xb4, 0x82, 0x65, -0x6d, 0xdd, 0x60, 0xcd, 0x60, 0x72, 0xca, 0x15, 0x44, 0x96, 0x67, 0xb8, 0xdc, 0xd3, 0x0c, 0x08, -0xeb, 0xea, 0x0e, 0x05, 0x8f, 0x63, 0x15, 0x21, 0x46, 0x41, 0xec, 0x23, 0xd2, 0x88, 0x14, 0xb1, -0xf1, 0x1f, 0x94, 0x61, 0x4f, 0xf6, 0x90, 0x40, 0x14, 0x8c, 0x46, 0x2d, 0xde, 0xb7, 0x99, 0x63, -0xb3, 0xe2, 0xfe, 0x7b, 0x66, 0x8e, 0xb3, 0xcd, 0x1c, 0xa7, 0x99, 0x39, 0xe6, 0x1f, 0x27, 0x73, -0xfe, 0x63, 0x75, 0x79, 0x93, 0x38, 0xce, 0x1f, 0xaf, 0x2c, 0x77, 0x13, 0x27, 0x48, 0xe3, 0x5a, -0xde, 0xb8, 0xdc, 0x37, 0x3d, 0xe8, 0x05, 0xe1, 0xa7, 0x14, 0x79, 0xba, 0x59, 0xe9, 0xcf, 0x35, -0x84, 0xa8, 0x11, 0x34, 0x06, 0x65, 0x7c, 0x68, 0x64, 0x40, 0x4b, 0x5e, 0x9b, 0x61, 0xdb, 0xc2, -0xe5, 0x46, 0x0e, 0xf7, 0x6c, 0x97, 0xf4, 0x70, 0x1c, 0x77, 0xc6, 0x35, 0x08, 0x0a, 0xd9, 0x34, -0x13, 0x0e, 0x31, 0x2c, 0xa2, 0x47, 0xde, 0x06, 0x45, 0x10, 0xc1, 0x55, 0x20, 0x8f, 0x0a, 0x64, -0x4a, 0x5c, 0x79, 0x6d, 0x46, 0x1d, 0x60, 0xea, 0xee, 0x7b, 0x9d, 0xf8, 0x04, 0x94, 0xd6, 0x74, -0xd5, 0x66, 0xc9, 0xd6, 0x6e, 0x0f, 0xad, 0x91, 0x24, 0xe6, 0xca, 0x6b, 0x23, 0x9f, 0x06, 0xbb, -0x83, 0xf7, 0x09, 0x12, 0x0f, 0x55, 0x02, 0xea, 0xba, 0x24, 0x87, 0xe5, 0xd2, 0x55, 0x53, 0x82, -0x08, 0xb8, 0x0f, 0x4b, 0x6a, 0x1a, 0xf0, 0x6e, 0x91, 0x37, 0xa0, 0xbb, 0x5e, 0x19, 0x80, 0xbc, -0xe1, 0x83, 0xe8, 0x09, 0x58, 0xda, 0x8c, 0x52, 0xd2, 0x34, 0x67, 0x04, 0xe7, 0x72, 0xd7, 0xf5, -0x28, 0x0a, 0x00, 0xeb, 0x3a, 0xb0, 0xa9, 0x57, 0xbc, 0x2c, 0x00, 0xe3, 0xea, 0x08, 0x70, 0xcf, -0xf3, 0x65, 0x1c, 0x59, 0x26, 0x82, 0xc0, 0xf7, 0x01, 0x30, 0x92, 0x00, 0x27, 0x1e, 0x5e, 0x0d, -0x4a, 0x45, 0xc7, 0xd9, 0x26, 0xbb, 0x2b, 0x6d, 0xaf, 0x1b, 0x01, 0xe8, 0x49, 0xd9, 0x10, 0x79, -0xe5, 0xb3, 0xd0, 0x13, 0x5f, 0x0f, 0x80, 0xd2, 0x11, 0xb1, 0xbe, 0x8f, 0x7a, 0x87, 0xf4, 0x2e, -0x52, 0x5c, 0xc2, 0xe8, 0x9c, 0xaa, 0x26, 0x12, 0xc0, 0x46, 0x29, 0x43, 0xd1, 0x41, 0x64, 0x20, -0x7f, 0x71, 0x95, 0xd8, 0xd0, 0x07, 0x3a, 0x6c, 0xd0, 0x6b, 0xc1, 0x71, 0x1c, 0xdf, 0x24, 0xb5, -0xe0, 0x80, 0x16, 0xf6, 0xd4, 0x65, 0x6e, 0x49, 0x17, 0x9f, 0x41, 0xf1, 0xa5, 0x15, 0x72, 0x59, -0x0f, 0x4b, 0xdc, 0xa7, 0x1e, 0xf3, 0xca, 0x11, 0x3c, 0x83, 0xe2, 0xab, 0xf8, 0xa7, 0x6f, 0x95, -0x5a, 0x42, 0x53, 0xca, 0x64, 0xdb, 0xf3, 0x90, 0xad, 0x06, 0xf2, 0xc9, 0x43, 0x6c, 0x6a, 0x28, -0x64, 0x08, 0x6b, 0xca, 0x24, 0x59, 0x07, 0x7c, 0x8b, 0x52, 0xca, 0x84, 0xb8, 0xe4, 0x41, 0xc3, -0xa3, 0xba, 0xe2, 0x47, 0x54, 0xbc, 0x51, 0xa6, 0xf1, 0x4e, 0x79, 0x80, 0x8e, 0x81, 0x7b, 0x3e, -0xc4, 0x87, 0xc2, 0x28, 0x33, 0x48, 0x62, 0x4f, 0xf3, 0xca, 0x37, 0xdb, 0x92, 0x46, 0x00, 0x36, -0xec, 0x6c, 0xd8, 0x64, 0x59, 0xcb, 0x41, 0x2d, 0xb0, 0x7d, 0x0f, 0x09, 0x0a, 0xd6, 0xdc, 0xd2, -0x1d, 0xca, 0x25, 0xa2, 0x8f, 0x0f, 0x1f, 0xa2, 0x58, 0x78, 0x71, 0x3c, 0xa7, 0x78, 0x31, 0x5c, -0x2a, 0x94, 0x28, 0xfb, 0x54, 0x82, 0x7c, 0x54, 0x2b, 0x93, 0xd2, 0xd5, 0x36, 0xcd, 0x93, 0xad, -0xfc, 0x48, 0x70, 0xaa, 0x72, 0x5b, 0xef, 0x8c, 0x1a, 0xde, 0x21, 0x5f, 0xd5, 0x6c, 0x7a, 0xbe, -0x9e, 0xcd, 0x44, 0x96, 0xfd, 0x97, 0xcc, 0xfa, 0x01, 0xad, 0xad, 0xef, 0x42, 0x1c, 0x1f, 0x6e, -0x36, 0x90, 0x69, 0xb8, 0x36, 0xc5, 0x1c, 0x71, 0x6e, 0x18, 0x70, 0xb4, 0x85, 0x56, 0x06, 0x8b, -0x82, 0xee, 0xb2, 0x62, 0x95, 0x84, 0x85, 0x0d, 0xc4, 0xbf, 0x6b, 0x73, 0xd7, 0xde, 0x96, 0x19, -0x2a, 0xda, 0x9a, 0x73, 0xe2, 0x10, 0x3d, 0xaa, 0x8a, 0x4d, 0x08, 0x9a, 0x74, 0x7d, 0x22, 0x1a, -0x99, 0x88, 0x1a, 0x63, 0x04, 0x96, 0x7e, 0x87, 0x86, 0x4b, 0xd1, 0xa5, 0xd9, 0x5d, 0xf5, 0xdf, -0xae, 0xa3, 0xa8, 0xbe, 0x5c, 0x63, 0xc9, 0xd8, 0x28, 0x28, 0x55, 0xdc, 0x28, 0x88, 0x6f, 0xa4, -0x18, 0x56, 0x08, 0xb0, 0x71, 0x71, 0xd3, 0xba, 0x92, 0x7a, 0xff, 0x5b, 0xbd, 0x50, 0x68, 0xea, -0x5a, 0xb1, 0x71, 0xb1, 0xfd, 0x78, 0x77, 0x74, 0x7a, 0xf4, 0xf1, 0xf8, 0x90, 0xbd, 0xfd, 0xf9, -0xf4, 0xf0, 0xe2, 0xb8, 0xda, 0x86, 0xdc, 0xac, 0xe3, 0x59, 0x1e, 0x26, 0x31, 0x5b, 0x46, 0x6a, -0x1e, 0xdc, 0x9e, 0x06, 0x4b, 0x31, 0x64, 0x9c, 0xf3, 0x20, 0xbd, 0xcd, 0x06, 0xec, 0x37, 0xa9, -0xff, 0x5d, 0x90, 0x32, 0x41, 0xe6, 0x98, 0x27, 0xb3, 0xf5, 0x52, 0xc4, 0x39, 0x9f, 0xa5, 0x22, -0xc8, 0xc5, 0x51, 0x24, 0xe8, 0xab, 0xc2, 0x1b, 0x1c, 0x48, 0xe8, 0xf0, 0x46, 0x25, 0xe4, 0x4b, -0xed, 0xaa, 0xc2, 0xa7, 0xdf, 0x4d, 0x92, 0xaa, 0x44, 0x27, 0x06, 0x20, 0x0b, 0x63, 0xd6, 0x03, -0x52, 0x22, 0x13, 0x04, 0x0f, 0xe3, 0xb9, 0xf8, 0x72, 0x76, 0xa3, 0x2a, 0x49, 0xac, 0x0c, 0xd8, -0x64, 0x32, 0x61, 0x5a, 0x1b, 0x94, 0x7e, 0x22, 0xe2, 0xc1, 0x7c, 0x7e, 0x74, 0x07, 0x29, 0x4e, -0xc2, 0x2c, 0x17, 0xb1, 0x48, 0x0b, 0xfc, 0x6c, 0x7d, 0x9d, 0xe5, 0xa9, 0x6a, 0x0c, 0x78, 0x9e, -0x9c, 0x24, 0xf7, 0x22, 0x3d, 0x0c, 0x32, 0xa1, 0x0e, 0x86, 0x15, 0xdf, 0x4b, 0x82, 0xba, 0x1a, -0xb2, 0x9b, 0x20, 0xca, 0xc4, 0xa0, 0x41, 0xf7, 0x11, 0x54, 0x33, 0xd1, 0xcf, 0x2c, 0x13, 0xf9, -0x34, 0xcf, 0xd3, 0xf0, 0x7a, 0x9d, 0x0b, 0xc9, 0xa8, 0x45, 0xb0, 0x34, 0xc1, 0x86, 0xd4, 0x5e, -0xf3, 0xed, 0xb1, 0x34, 0x10, 0x53, 0x5f, 0x48, 0x34, 0xbd, 0xa1, 0x7f, 0x2a, 0xf2, 0x35, 0x16, -0x3b, 0x11, 0x1d, 0xd4, 0x80, 0xcb, 0xc1, 0x58, 0x40, 0xbb, 0x54, 0x15, 0x51, 0xc9, 0x10, 0x98, -0x7b, 0x8f, 0x7b, 0x5b, 0xef, 0xd5, 0xe6, 0xe3, 0x8a, 0x26, 0xf1, 0xc9, 0xbf, 0xae, 0x44, 0x72, -0xc3, 0x62, 0x69, 0x42, 0x05, 0x26, 0x09, 0xe3, 0x5b, 0xa5, 0xce, 0x14, 0x4a, 0x85, 0x31, 0xcc, -0xf6, 0xfe, 0xe2, 0xc3, 0x09, 0x3c, 0x1c, 0x97, 0xbc, 0x0b, 0x1b, 0x10, 0x85, 0x18, 0xde, 0xca, -0xf2, 0x20, 0x9e, 0x11, 0x9d, 0x69, 0x9a, 0x06, 0x5f, 0xfb, 0xdc, 0x1a, 0x02, 0x57, 0x3b, 0xc0, -0xe3, 0x3b, 0x16, 0xf3, 0x48, 0xc4, 0xb7, 0xf9, 0x02, 0x5f, 0xaf, 0x5f, 0x77, 0xfd, 0xbb, 0x95, -0xe9, 0x32, 0xbc, 0xda, 0x29, 0x56, 0xf5, 0x23, 0xda, 0x79, 0x37, 0xf2, 0x2e, 0xc4, 0x97, 0xfc, -0x34, 0x99, 0xc3, 0x07, 0x20, 0xd2, 0x32, 0x7a, 0x15, 0x17, 0xab, 0x95, 0x88, 0xe7, 0x87, 0x8b, -0x30, 0x9a, 0xab, 0x79, 0xdb, 0x2f, 0x35, 0xf5, 0x48, 0x8a, 0x9a, 0x86, 0x44, 0x75, 0xf0, 0xdb, -0xb7, 0x08, 0xf6, 0xb0, 0xed, 0xf8, 0x7a, 0x87, 0x09, 0x5b, 0x0c, 0xda, 0x84, 0x07, 0x5d, 0xdf, -0x53, 0x40, 0xd4, 0x7d, 0x9d, 0x27, 0xab, 0x38, 0xb8, 0x53, 0x2b, 0x73, 0xe5, 0xc9, 0xed, 0x6d, -0x24, 0x54, 0xa5, 0x18, 0x56, 0x86, 0x58, 0xbb, 0x92, 0xeb, 0x30, 0x12, 0xca, 0xa0, 0x89, 0xb6, -0x0a, 0xd2, 0x4c, 0x9c, 0x02, 0x31, 0xb9, 0xfe, 0xb5, 0xc2, 0x25, 0xf7, 0xd5, 0x5c, 0xa7, 0xeb, -0x1d, 0xa7, 0x21, 0x21, 0x01, 0x30, 0x61, 0x46, 0x33, 0x49, 0x50, 0x29, 0xf3, 0x30, 0x5e, 0x8b, -0xad, 0x0d, 0xc8, 0x53, 0x8d, 0x1a, 0x71, 0x2b, 0xf2, 0xb2, 0x40, 0xfc, 0xf0, 0xf5, 0x78, 0xae, -0x2a, 0x24, 0xdc, 0xeb, 0xb0, 0x66, 0x35, 0x90, 0xbe, 0x47, 0x9e, 0x27, 0xf7, 0x3c, 0x4a, 0x66, -0x01, 0xc9, 0xc8, 0x57, 0x41, 0xbe, 0x90, 0x15, 0x82, 0xc2, 0x62, 0xac, 0xb0, 0xd7, 0x2c, 0xe2, -0x8b, 0x54, 0xdc, 0x94, 0xf9, 0x8c, 0x28, 0x51, 0xb5, 0x61, 0x35, 0xb6, 0xa9, 0x11, 0x7f, 0x56, -0x06, 0x03, 0x9e, 0xad, 0xa2, 0x30, 0x57, 0xf7, 0xc7, 0xfb, 0x03, 0xbe, 0x4a, 0x56, 0xea, 0xa0, -0xa7, 0xb2, 0x40, 0x93, 0x17, 0x13, 0x94, 0xed, 0xc1, 0xcb, 0x97, 0xac, 0x78, 0xf7, 0x07, 0x83, -0x8e, 0xab, 0x23, 0x3e, 0x8b, 0x82, 0x2c, 0xa3, 0x7a, 0x42, 0xc5, 0x45, 0x55, 0x02, 0xd8, 0xef, -0x4e, 0x9a, 0x73, 0xeb, 0xe1, 0xba, 0x12, 0xb0, 0xe7, 0xa5, 0x02, 0x3d, 0xd7, 0x9f, 0x56, 0x69, -0x92, 0x1f, 0xc5, 0x4a, 0x5f, 0x55, 0x6b, 0x02, 0x75, 0x41, 0x4a, 0x30, 0x8d, 0x34, 0x0f, 0xbb, -0x42, 0xb5, 0x05, 0x4b, 0xc5, 0x32, 0xb9, 0x83, 0xd3, 0x17, 0xe1, 0xbc, 0x21, 0xd9, 0x36, 0xac, -0x64, 0xec, 0x41, 0xcb, 0xef, 0xe1, 0xba, 0x1e, 0x5e, 0x95, 0x49, 0x6a, 0x82, 0x2d, 0x83, 0xec, -0xb3, 0x72, 0xc5, 0xbe, 0xff, 0x1e, 0xc6, 0x19, 0x19, 0x30, 0xe0, 0x4b, 0xa6, 0x7d, 0xd1, 0x74, -0x2a, 0xbf, 0xf4, 0xa2, 0xf5, 0x4b, 0xf5, 0xcf, 0x4a, 0xf6, 0xd8, 0x9f, 0x89, 0xd0, 0xfc, 0x45, -0xaf, 0xe6, 0xcf, 0xa1, 0xfd, 0xd8, 0xd0, 0x57, 0x6f, 0x12, 0xf9, 0x16, 0x81, 0xc7, 0x6e, 0x96, -0xfc, 0x22, 0xd2, 0x0c, 0x1f, 0xf5, 0x4c, 0xd9, 0x19, 0xd6, 0x77, 0x05, 0xac, 0x32, 0x68, 0xe4, -0xf1, 0x46, 0x82, 0x28, 0x8c, 0x3f, 0x83, 0x5f, 0x9e, 0xaf, 0xb2, 0x37, 0xe3, 0xf1, 0x6d, 0x98, -0x2f, 0xd6, 0xd7, 0x7c, 0x96, 0x2c, 0xc7, 0xd1, 0x7a, 0x19, 0xac, 0xd6, 0xe3, 0x60, 0x91, 0x7c, -0x1d, 0xe3, 0x7b, 0x19, 0xe6, 0x99, 0x0c, 0x78, 0xe9, 0x8f, 0xeb, 0x35, 0x88, 0x28, 0x58, 0x9f, -0x94, 0x77, 0x61, 0xce, 0xce, 0xdf, 0x4f, 0xdf, 0xb0, 0xf6, 0x1c, 0x3e, 0x15, 0xf6, 0xa6, 0x36, -0x5e, 0x09, 0x42, 0x58, 0x9f, 0xae, 0xa3, 0x20, 0xfe, 0xac, 0x14, 0x86, 0xe8, 0xab, 0x03, 0x47, -0xe7, 0x3f, 0x3d, 0x4b, 0x3b, 0x91, 0xad, 0x3e, 0x51, 0xbd, 0x86, 0x7a, 0xa9, 0x58, 0x45, 0xc1, -0x4c, 0x48, 0xfd, 0x52, 0x11, 0x6f, 0x55, 0xdc, 0x55, 0x9b, 0x95, 0x1f, 0x92, 0x20, 0x9d, 0xd7, -0x24, 0xdc, 0x10, 0xbb, 0xda, 0x2d, 0xd8, 0xc7, 0x2c, 0x0b, 0xeb, 0x92, 0xc9, 0xc5, 0x05, 0xd5, -0x06, 0x95, 0x65, 0x73, 0x8e, 0xb2, 0xe9, 0x33, 0x24, 0xd5, 0x7b, 0x0c, 0x7d, 0x4a, 0x81, 0x06, -0x9b, 0x7c, 0x37, 0x61, 0x23, 0xaf, 0x16, 0xa8, 0x2d, 0x4c, 0xbd, 0xc0, 0xac, 0x82, 0xa5, 0x17, -0xdd, 0xdd, 0x8d, 0x6e, 0x1c, 0x3c, 0x6d, 0x2c, 0x22, 0x45, 0xb0, 0x3d, 0xc6, 0xca, 0xee, 0x6e, -0x55, 0x9a, 0x1a, 0x32, 0xd3, 0x28, 0x2e, 0x09, 0x8d, 0x6a, 0xdd, 0x16, 0x62, 0x30, 0x68, 0x57, -0xfb, 0xe3, 0x2c, 0xf9, 0x11, 0x76, 0x3d, 0x47, 0x3f, 0x33, 0xaf, 0xcc, 0xb2, 0x69, 0x0b, 0xee, -0x19, 0xcd, 0xa9, 0x73, 0x12, 0xe6, 0x22, 0x5c, 0xa2, 0xc7, 0x81, 0xb5, 0xb7, 0x9f, 0x0f, 0x49, -0x2c, 0xce, 0x6e, 0x6e, 0xd0, 0xb7, 0x60, 0xe2, 0x15, 0x1b, 0x39, 0x1a, 0x7e, 0x03, 0xea, 0x8a, -0x8e, 0xcf, 0xcf, 0xce, 0x8b, 0x8a, 0x3a, 0x68, 0x56, 0x57, 0xdd, 0xdf, 0x88, 0xaf, 0xee, 0x5f, -0xec, 0x0f, 0x19, 0xfd, 0xf5, 0x09, 0x45, 0xf4, 0x2b, 0xa1, 0xd8, 0x78, 0xcc, 0x7e, 0xbe, 0x38, -0x7c, 0xf1, 0x2d, 0xe1, 0x76, 0x73, 0xd6, 0xf5, 0xe7, 0xb1, 0x86, 0x2a, 0xef, 0x91, 0xbd, 0x6a, -0x38, 0x1f, 0x32, 0x4a, 0xe3, 0x66, 0x93, 0xba, 0x7c, 0x62, 0x05, 0x0a, 0xe7, 0xdb, 0x0e, 0x35, -0x96, 0xfd, 0xfd, 0x84, 0x30, 0x06, 0xad, 0x06, 0x6c, 0x03, 0x53, 0xa7, 0x5e, 0x0e, 0xbd, 0x00, -0x7c, 0xad, 0x9c, 0xd0, 0x2a, 0x18, 0x60, 0x6d, 0xaf, 0x0a, 0x4a, 0xb3, 0xf0, 0x34, 0x61, 0xe5, -0x52, 0xd2, 0xa8, 0x3b, 0x32, 0x0e, 0xf7, 0xfa, 0xa1, 0xcb, 0x42, 0xb5, 0x4f, 0x08, 0x5d, 0xe3, -0xcb, 0x05, 0x9f, 0x0c, 0x30, 0x8b, 0x26, 0x25, 0xcd, 0xba, 0x15, 0x9e, 0x69, 0x83, 0x17, 0xa2, -0x4f, 0x95, 0x59, 0x54, 0x53, 0x43, 0xb4, 0x14, 0xc0, 0xe4, 0x36, 0x85, 0x7a, 0xa1, 0x4a, 0xc1, -0x25, 0x60, 0x5d, 0x68, 0xc8, 0x31, 0xfd, 0x35, 0xf8, 0xa2, 0xae, 0x53, 0xb4, 0xa8, 0xab, 0x3c, -0x1d, 0xb2, 0xa5, 0xc8, 0x17, 0xc9, 0x7c, 0xa2, 0xbc, 0x3b, 0xba, 0x40, 0x1a, 0xfc, 0x9a, 0x25, -0xf1, 0x84, 0xbc, 0x52, 0xd7, 0xe4, 0xcb, 0x22, 0xa5, 0x9e, 0x14, 0x71, 0xf4, 0xb7, 0x0f, 0x27, -0xef, 0x51, 0x43, 0x3f, 0x8a, 0xbf, 0xaf, 0xd1, 0xe9, 0xaa, 0x5b, 0x25, 0x08, 0x04, 0x0b, 0x47, -0x1d, 0x13, 0x3f, 0x8c, 0xf2, 0x04, 0xd5, 0x58, 0x2d, 0x98, 0x0c, 0x99, 0x64, 0x9b, 0xa7, 0x6b, -0xb1, 0x5d, 0x35, 0x24, 0x4c, 0x8c, 0x92, 0x35, 0xff, 0x8a, 0xe6, 0x2c, 0x17, 0xb3, 0x45, 0x10, -0xdf, 0x92, 0xed, 0x56, 0x1b, 0x10, 0xd0, 0x57, 0x7e, 0x3a, 0x3b, 0xbf, 0x50, 0x28, 0x54, 0x0a, -0x52, 0x4d, 0x17, 0x13, 0x0d, 0x04, 0x64, 0x29, 0xd6, 0x7b, 0xd0, 0x42, 0x13, 0xae, 0x1c, 0xc2, -0x96, 0x30, 0xf8, 0xe8, 0x82, 0x6a, 0x1d, 0x32, 0x1d, 0x0b, 0x43, 0x14, 0x16, 0x1d, 0xce, 0x98, -0xf4, 0x3c, 0x00, 0x2b, 0x94, 0xba, 0x7c, 0xf2, 0xf3, 0xc5, 0xdb, 0x91, 0xa7, 0x34, 0x45, 0xca, -0xb0, 0x86, 0xa8, 0x04, 0x35, 0xa8, 0x6f, 0x03, 0xb6, 0x45, 0x52, 0x6d, 0x85, 0x24, 0xe1, 0x48, -0x25, 0xce, 0x49, 0x09, 0x12, 0xd4, 0xea, 0xdb, 0x54, 0x51, 0xbc, 0xc3, 0x4e, 0x05, 0x74, 0xb6, -0x4a, 0xe2, 0x4c, 0x16, 0xea, 0x1d, 0x6d, 0x48, 0x05, 0x0e, 0x47, 0xf5, 0xaf, 0xfa, 0x98, 0x50, -0xff, 0x72, 0x7e, 0x76, 0xca, 0x65, 0xd1, 0x56, 0x3b, 0x64, 0xbf, 0xb9, 0x11, 0x42, 0x6c, 0x94, -0xfb, 0xd2, 0xc3, 0x8f, 0x47, 0xd3, 0x8b, 0x23, 0xf6, 0xe3, 0xd9, 0x87, 0xd6, 0xd6, 0xb4, 0x16, -0xf1, 0xb4, 0xc9, 0x88, 0x50, 0x20, 0x70, 0x37, 0xb6, 0xdb, 0x9b, 0x6a, 0x27, 0x41, 0xa3, 0xb2, -0x63, 0x8c, 0xd7, 0xcb, 0x6b, 0x91, 0x2a, 0x83, 0x5a, 0x53, 0x4a, 0x33, 0xac, 0x2c, 0x37, 0x12, -0xfb, 0xa0, 0x5e, 0xa2, 0xb0, 0xe9, 0x55, 0xf2, 0x14, 0x3e, 0xfa, 0xed, 0x71, 0x58, 0x6e, 0xf6, -0xe9, 0x27, 0x87, 0x17, 0x34, 0x9c, 0xe5, 0x5f, 0x23, 0xf1, 0x86, 0x8a, 0xf5, 0x3c, 0x5f, 0xbc, -0x61, 0xb6, 0xf6, 0x27, 0xe5, 0x51, 0x8a, 0xa1, 0x0f, 0x86, 0x4d, 0xf0, 0x79, 0x49, 0x45, 0x32, -0x91, 0x53, 0x57, 0xad, 0x14, 0x98, 0x8b, 0x8c, 0x44, 0xa8, 0xe4, 0x17, 0xbb, 0x37, 0xd4, 0xfb, -0xab, 0xfd, 0x2a, 0xcf, 0xda, 0x15, 0x04, 0x05, 0x13, 0x74, 0x94, 0xcd, 0x74, 0x7d, 0xf3, 0x06, -0xe2, 0x0d, 0xed, 0x44, 0x93, 0x7f, 0x74, 0x1d, 0xa9, 0x8b, 0x7c, 0x19, 0xa1, 0xe9, 0x97, 0x62, -0xca, 0xf2, 0x41, 0x9e, 0x1e, 0xb2, 0x70, 0xde, 0xc8, 0xbd, 0xa7, 0x44, 0x8b, 0x82, 0x6b, 0x11, -0x6d, 0xc5, 0x23, 0x82, 0x6f, 0x13, 0x4a, 0xd3, 0x92, 0xf4, 0x93, 0x82, 0xd5, 0x42, 0x0b, 0x15, -0xa2, 0xa3, 0x1d, 0xe7, 0x7c, 0x53, 0x61, 0x6a, 0xa0, 0x28, 0x5a, 0x44, 0x70, 0x4e, 0x4b, 0xf1, -0xfc, 0x29, 0x0d, 0xc3, 0x78, 0x55, 0xee, 0xca, 0xa5, 0x7a, 0xcb, 0xe0, 0xcb, 0x84, 0x96, 0x5a, -0xa8, 0x79, 0xa9, 0xe4, 0x08, 0x4b, 0xea, 0x8d, 0x4a, 0x55, 0x51, 0x0d, 0x10, 0x3c, 0xe5, 0x2b, -0xb6, 0x1d, 0xd8, 0x3d, 0xc7, 0xd5, 0x44, 0x98, 0x47, 0xd5, 0xcc, 0x6c, 0x21, 0x66, 0x9f, 0xc5, -0xf3, 0xad, 0x03, 0x09, 0xd6, 0xf9, 0x2e, 0xe7, 0xd5, 0xd5, 0x13, 0xbc, 0xd8, 0xe7, 0xc8, 0x03, -0x91, 0x8e, 0xc6, 0x32, 0x4c, 0x04, 0xc7, 0x63, 0x2d, 0x76, 0xd8, 0x0f, 0xca, 0x11, 0x08, 0x1e, -0x27, 0x72, 0xbb, 0xcd, 0xe4, 0xd0, 0x73, 0x6c, 0x57, 0x9b, 0x25, 0x1b, 0xd0, 0x3c, 0x3d, 0x59, -0xf1, 0xd9, 0x81, 0x29, 0x8d, 0x43, 0x60, 0xe5, 0x2b, 0xdb, 0x0c, 0x76, 0x09, 0x92, 0xed, 0x24, -0x45, 0x7a, 0x61, 0xe5, 0x40, 0xd7, 0xf9, 0x85, 0x59, 0x65, 0x04, 0x14, 0xaf, 0x6c, 0x33, 0xf8, -0x94, 0x83, 0x33, 0x11, 0x95, 0x0e, 0x4e, 0x56, 0x34, 0x90, 0x0d, 0x69, 0xe8, 0x78, 0xfe, 0x1c, -0xd7, 0x00, 0x50, 0xcc, 0x6a, 0xbe, 0xe9, 0xd8, 0x5f, 0x6e, 0x86, 0x73, 0x86, 0x82, 0x52, 0x12, -0xaf, 0x17, 0x47, 0x3a, 0x67, 0xc6, 0x30, 0x00, 0x2e, 0x35, 0x8a, 0xa2, 0xfc, 0x52, 0xc7, 0xa3, -0xf8, 0xa4, 0xda, 0x53, 0x88, 0x51, 0x2b, 0x7b, 0xa2, 0xb1, 0x1f, 0x48, 0x06, 0x3d, 0x87, 0x3a, -0x5d, 0xe5, 0x7e, 0x14, 0xd1, 0x34, 0x8a, 0xce, 0xc0, 0x07, 0x1f, 0x8d, 0x16, 0x78, 0x28, 0x37, -0xd7, 0x18, 0xe5, 0xa5, 0x70, 0xe5, 0x29, 0x0b, 0x1b, 0x31, 0xfd, 0xa0, 0xb1, 0x97, 0x8f, 0x68, -0x2f, 0xff, 0x7d, 0xb1, 0xa7, 0x1f, 0x8d, 0xea, 0x3a, 0x10, 0x76, 0xb9, 0x3e, 0x87, 0xbd, 0x9b, -0x1f, 0x52, 0x50, 0x66, 0x0e, 0xe5, 0xb2, 0x34, 0xed, 0xa4, 0x38, 0x20, 0x2b, 0x89, 0x24, 0x4f, -0x98, 0xb7, 0x10, 0xab, 0x32, 0x6f, 0xd2, 0x8d, 0xdd, 0xa4, 0x51, 0x12, 0x88, 0xc3, 0x26, 0x2c, -0x48, 0xd9, 0xad, 0xa5, 0x79, 0xe1, 0x29, 0x19, 0x13, 0xb4, 0x64, 0x37, 0x02, 0x22, 0x69, 0xd5, -0xd4, 0xf0, 0x0e, 0xbd, 0x06, 0x04, 0x7e, 0x76, 0x86, 0x02, 0xe3, 0x39, 0xf9, 0x59, 0x0b, 0xd6, -0xc5, 0xa0, 0x55, 0xce, 0x16, 0x4f, 0x86, 0xe8, 0x2a, 0x88, 0xd5, 0x7f, 0xb9, 0xba, 0x12, 0xf6, -0xfe, 0xe0, 0xf7, 0xac, 0xa1, 0xd7, 0xa9, 0xda, 0xda, 0x64, 0xec, 0x92, 0xf5, 0x3a, 0x6d, 0x77, -0xa6, 0x72, 0xb3, 0x3b, 0xcf, 0x72, 0xd4, 0x50, 0x54, 0x5b, 0xdc, 0x83, 0x14, 0x7d, 0x5f, 0xa7, -0xad, 0x0b, 0x9e, 0x30, 0x40, 0x50, 0x69, 0xff, 0xad, 0x93, 0x3f, 0xe2, 0x50, 0x82, 0x06, 0xf2, -0x3c, 0x88, 0x60, 0xb3, 0xbc, 0x5b, 0x91, 0xa4, 0x0c, 0xdb, 0xf0, 0x0a, 0x78, 0x31, 0xc2, 0xaa, -0xa9, 0x8a, 0x46, 0xdf, 0x81, 0x61, 0x69, 0x81, 0xa0, 0xe5, 0x62, 0x6c, 0xe6, 0xe6, 0x41, 0x1e, -0x94, 0xee, 0xbd, 0x9f, 0x18, 0x16, 0x45, 0x20, 0xdd, 0x37, 0x3e, 0xcf, 0x93, 0x24, 0xca, 0xc3, -0x55, 0x47, 0xf7, 0x6c, 0xa7, 0xee, 0xa7, 0xe7, 0x68, 0xf7, 0xd1, 0xe3, 0xbe, 0x19, 0x8f, 0xef, -0xef, 0xef, 0xf9, 0xbd, 0xc9, 0x93, 0xf4, 0x76, 0x6c, 0x60, 0xbf, 0x36, 0x06, 0x43, 0xda, 0x09, -0xd1, 0xa3, 0x14, 0x2c, 0x6b, 0x1e, 0x45, 0xef, 0xcb, 0xfe, 0x04, 0x30, 0xf7, 0x3b, 0xe6, 0x17, -0x22, 0xbc, 0x5d, 0xe4, 0x00, 0x58, 0xec, 0x00, 0xb8, 0x0b, 0xc5, 0xfd, 0x0f, 0xc9, 0x17, 0x62, -0x53, 0xfc, 0x97, 0x0d, 0xfe, 0xf6, 0x07, 0xbd, 0x11, 0xd7, 0x46, 0x95, 0xf1, 0xb7, 0x4f, 0xba, -0x77, 0xe1, 0xc9, 0x4c, 0xed, 0xf3, 0x62, 0x6c, 0x35, 0xb2, 0x1c, 0x59, 0x80, 0x42, 0xdb, 0x9e, -0x2e, 0x8f, 0x16, 0x31, 0x1d, 0xfe, 0x1b, 0x76, 0xa2, 0x53, 0xc4, 0xfd, 0x56, 0x07, 0x1a, 0xb6, -0x84, 0x9e, 0x03, 0x50, 0xb4, 0x60, 0xb2, 0x46, 0x0c, 0x84, 0x8d, 0x03, 0xbf, 0xfa, 0xf1, 0xfd, -0x36, 0xb6, 0x0a, 0x27, 0xd7, 0x35, 0x28, 0xa4, 0xcf, 0x77, 0x47, 0xb8, 0x22, 0x57, 0xc4, 0xfa, -0xe9, 0x55, 0xde, 0x60, 0xbb, 0x33, 0xde, 0x4b, 0x5e, 0x35, 0xc4, 0xac, 0x37, 0x66, 0x1b, 0x4b, -0x4c, 0xd6, 0x8c, 0xdc, 0x65, 0x32, 0x0f, 0x22, 0x55, 0x4a, 0x30, 0x64, 0xd7, 0xc9, 0xfc, 0x6b, -0xad, 0x99, 0xae, 0xb6, 0xc4, 0x3b, 0x8f, 0x37, 0x24, 0xb2, 0xd2, 0x38, 0x58, 0xdd, 0x7d, 0x14, -0x92, 0x92, 0x68, 0xe9, 0xe6, 0x54, 0x4c, 0x6d, 0x18, 0x9a, 0x1a, 0x66, 0xd4, 0x61, 0xea, 0x98, -0x43, 0x3a, 0x20, 0x92, 0x94, 0x47, 0x15, 0x0e, 0x45, 0x12, 0x22, 0xaa, 0x1a, 0xa7, 0x33, 0x92, -0x78, 0x86, 0x0d, 0xd4, 0xe7, 0x37, 0x85, 0xfc, 0x87, 0x51, 0x92, 0x89, 0xc7, 0x5a, 0xff, 0xbd, -0x93, 0x64, 0x87, 0xd4, 0xe3, 0xb0, 0xb3, 0x9b, 0xa9, 0x21, 0x36, 0x60, 0x47, 0xb3, 0x62, 0x17, -0xa7, 0x34, 0x76, 0x06, 0xcf, 0xc6, 0x5e, 0xc8, 0xbd, 0xe0, 0xd3, 0xc8, 0x15, 0x81, 0x85, 0x5d, -0xee, 0x1d, 0x8a, 0xee, 0x69, 0xf8, 0x4d, 0x04, 0x84, 0x70, 0x9e, 0xc4, 0x75, 0xa6, 0x33, 0xb2, -0x89, 0x52, 0x34, 0xb5, 0xf8, 0xdc, 0x00, 0xf4, 0x59, 0x0e, 0x3b, 0xd2, 0x97, 0x79, 0xb8, 0x14, -0xd9, 0x81, 0xb2, 0xfb, 0x48, 0xf7, 0xea, 0x09, 0x31, 0x76, 0x2a, 0x4d, 0x11, 0x45, 0x2a, 0xcb, -0xc8, 0xea, 0x45, 0xbf, 0xea, 0x8c, 0x36, 0xe1, 0xb6, 0x5f, 0xbd, 0x0d, 0xca, 0x56, 0x0b, 0xf5, -0xb9, 0x27, 0x1e, 0x55, 0xd8, 0x76, 0x4a, 0x53, 0xe3, 0x6c, 0x47, 0x54, 0x8d, 0x51, 0x2d, 0xbd, -0x9e, 0xa6, 0x38, 0xda, 0x86, 0x78, 0x13, 0x95, 0x24, 0xfe, 0x07, 0x65, 0xb7, 0x8f, 0xf0, 0xf2, -0x29, 0x00, 0x00}; -#endif /*__API_JS_H__*/ diff --git a/src/web/html/h/colorBright_css.h b/src/web/html/h/colorBright_css.h deleted file mode 100644 index 7968d278..00000000 --- a/src/web/html/h/colorBright_css.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __COLORBRIGHT_CSS_H__ -#define __COLORBRIGHT_CSS_H__ -#define colorBright_css_len 261 -const uint8_t colorBright_css[] PROGMEM = { -0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0x55, 0x90, 0xdd, 0x6e, 0xc3, 0x20, -0x0c, 0x85, 0x5f, 0x65, 0x52, 0xae, 0x91, 0xbc, 0xfc, 0x42, 0xf6, 0x34, 0x60, 0x9c, 0x06, 0x29, -0x85, 0x8a, 0xd0, 0x54, 0xd3, 0xb4, 0x77, 0x1f, 0xa6, 0x4d, 0x96, 0x8a, 0x1b, 0xfc, 0xf9, 0x70, -0xec, 0xc3, 0x18, 0x43, 0x48, 0x1f, 0x3f, 0x42, 0x98, 0xcb, 0x58, 0x4d, 0xd3, 0xf4, 0x25, 0xc4, -0x94, 0x6f, 0x00, 0x50, 0x6e, 0xf5, 0x0e, 0x9d, 0x9f, 0x42, 0xc1, 0x60, 0x6d, 0x2e, 0x1f, 0x3a, -0x7a, 0x6e, 0x0d, 0x43, 0x11, 0xae, 0x77, 0x44, 0x5a, 0x57, 0x16, 0x28, 0x55, 0x88, 0xf3, 0xb7, -0x7b, 0x2a, 0xa6, 0x44, 0x94, 0xeb, 0xa4, 0xcd, 0x42, 0xc2, 0x84, 0x68, 0x29, 0x8e, 0x15, 0x22, -0x66, 0xe6, 0xf5, 0x56, 0x14, 0x4d, 0xd3, 0xe4, 0xea, 0x16, 0xdd, 0x55, 0xc7, 0x6f, 0xf6, 0xe8, -0x09, 0xe1, 0x9f, 0x88, 0x39, 0x6c, 0xfc, 0x08, 0xda, 0x96, 0x64, 0xcf, 0xd3, 0x08, 0x83, 0xb7, -0x2f, 0xed, 0x50, 0xa3, 0x7c, 0x79, 0x69, 0x4c, 0x6e, 0xa3, 0xb1, 0xea, 0xba, 0x8e, 0x97, 0xcf, -0xc1, 0x28, 0x96, 0x01, 0xb5, 0xe4, 0x93, 0xd9, 0x35, 0x58, 0xbd, 0x9c, 0xa2, 0x3a, 0xbf, 0xe9, -0xc5, 0xd9, 0x27, 0x51, 0x8a, 0xf7, 0x0c, 0x29, 0x2b, 0x66, 0xd2, 0x56, 0x24, 0x97, 0x96, 0xec, -0x26, 0xa9, 0x53, 0xd0, 0x1c, 0x2d, 0x96, 0x9a, 0xbc, 0x21, 0xb4, 0xfc, 0x7e, 0x7b, 0x93, 0x7e, -0x62, 0x2f, 0x9f, 0xe9, 0x5f, 0xbc, 0xa4, 0xab, 0x0d, 0xec, 0x62, 0xeb, 0xd6, 0xc3, 0x56, 0xca, -0x83, 0x8d, 0x95, 0x2a, 0xc3, 0x71, 0x7e, 0xb3, 0x03, 0x68, 0x50, 0xc2, 0x89, 0x9b, 0xcb, 0xe9, -0x77, 0xd2, 0x5a, 0xe0, 0xfe, 0x7d, 0xb9, 0xe4, 0x36, 0x67, 0xff, 0xfd, 0x03, 0x3b, 0xc9, 0xfb, -0x95, 0xd5, 0x01, 0x00, 0x00}; -#endif /*__COLORBRIGHT_CSS_H__*/ diff --git a/src/web/html/h/colorDark_css.h b/src/web/html/h/colorDark_css.h deleted file mode 100644 index a24f888b..00000000 --- a/src/web/html/h/colorDark_css.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __COLORDARK_CSS_H__ -#define __COLORDARK_CSS_H__ -#define colorDark_css_len 255 -const uint8_t colorDark_css[] PROGMEM = { -0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0x5d, 0x90, 0xd9, 0x6e, 0xc3, 0x20, -0x10, 0x45, 0x7f, 0xa5, 0x92, 0x9f, 0x91, 0x58, 0x6c, 0xc7, 0x72, 0xbf, 0x66, 0xd8, 0x6a, 0x24, -0x07, 0x22, 0x20, 0x44, 0x55, 0xd5, 0x7f, 0x2f, 0x0c, 0x76, 0xd2, 0x56, 0xbc, 0xcc, 0x9c, 0xb9, -0xdc, 0x59, 0xd6, 0x18, 0x42, 0x7e, 0xfb, 0x22, 0x44, 0x7e, 0xac, 0x03, 0xe7, 0xfc, 0x9d, 0x10, -0x5b, 0x23, 0xa5, 0x14, 0x46, 0x7c, 0x1d, 0xac, 0xb5, 0x35, 0x74, 0xde, 0x86, 0x75, 0xa0, 0xf4, -0xc2, 0xd5, 0x52, 0xd3, 0x07, 0x44, 0xdf, 0x4a, 0x00, 0x94, 0xd6, 0x34, 0xdd, 0x95, 0x32, 0x29, -0x35, 0x81, 0x94, 0x48, 0x9c, 0xbf, 0xdd, 0x33, 0x9a, 0x0a, 0x21, 0x6a, 0x9e, 0x41, 0xee, 0x86, -0xc8, 0x10, 0xb5, 0x89, 0x27, 0xf3, 0x50, 0x7e, 0x29, 0x6e, 0xd1, 0x5d, 0x21, 0x7e, 0x36, 0x8f, -0x51, 0x2f, 0x97, 0x17, 0x21, 0x5b, 0x28, 0xed, 0x13, 0xe5, 0x82, 0x4d, 0x53, 0xeb, 0x66, 0x54, -0xf0, 0xfa, 0xd0, 0x1e, 0x03, 0x35, 0x2f, 0x50, 0xd9, 0x15, 0xb3, 0x0e, 0x13, 0xaa, 0x6c, 0x5d, -0xcc, 0xc4, 0xbe, 0xd7, 0xd2, 0x5e, 0x65, 0xd7, 0xa0, 0x61, 0x47, 0x34, 0xcf, 0x33, 0x4e, 0x59, -0x60, 0x77, 0x1a, 0xc9, 0x88, 0x73, 0xe7, 0x90, 0xab, 0x62, 0x33, 0xa0, 0x49, 0x76, 0x79, 0xef, -0x6e, 0x13, 0x63, 0xcf, 0xd2, 0xf1, 0x79, 0xc6, 0x53, 0xb9, 0xf2, 0x47, 0xca, 0xd8, 0x21, 0x3d, -0x79, 0x3f, 0xea, 0x4b, 0xac, 0x5d, 0x3a, 0xb5, 0x7d, 0xe9, 0xce, 0x6a, 0xf3, 0x71, 0xac, 0x99, -0xda, 0xfe, 0xd9, 0x71, 0x8e, 0xab, 0x9c, 0xbc, 0xdb, 0x09, 0x81, 0xb3, 0xe7, 0x84, 0xf0, 0x79, -0xe0, 0x84, 0xe5, 0xb6, 0xfb, 0xf7, 0x0f, 0xe9, 0x86, 0x9e, 0xcf, 0xd5, 0x01, 0x00, 0x00}; -#endif /*__COLORDARK_CSS_H__*/ diff --git a/src/web/html/h/favicon_ico.h b/src/web/html/h/favicon_ico.h deleted file mode 100644 index defec936..00000000 --- a/src/web/html/h/favicon_ico.h +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef __FAVICON_ICO_H__ -#define __FAVICON_ICO_H__ -#define favicon_ico_len 1534 -const uint8_t favicon_ico[] PROGMEM = { -0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0xed, 0x5c, 0x4b, 0x6c, 0x1b, 0x55, -0x14, 0x3d, 0x4e, 0x9c, 0xba, 0x48, 0x51, 0x93, 0x05, 0x48, 0x95, 0x88, 0x62, 0xf3, 0x59, 0x64, -0x97, 0xa0, 0x4a, 0x6d, 0x11, 0x51, 0x5d, 0x21, 0x40, 0x88, 0xa6, 0xec, 0xb2, 0x42, 0x95, 0xb2, -0x2a, 0xec, 0xa0, 0xa2, 0xcd, 0x58, 0x22, 0x90, 0x49, 0xf3, 0xe9, 0x07, 0x5a, 0x3b, 0x69, 0x8b, -0x28, 0xb4, 0xa8, 0xad, 0x9b, 0xb6, 0x44, 0x7c, 0xa4, 0x02, 0x25, 0x69, 0x91, 0x6a, 0x67, 0x01, -0x9b, 0x2e, 0xd8, 0x56, 0x75, 0x22, 0x8b, 0x0d, 0xbb, 0x28, 0x4b, 0x2f, 0xac, 0x3c, 0xee, 0x9d, -0x79, 0xe3, 0x38, 0x93, 0x89, 0xff, 0xf1, 0x4b, 0xfc, 0xf2, 0xa4, 0xa3, 0x63, 0x8f, 0xe7, 0xcd, -0xb9, 0xe7, 0xcc, 0x78, 0xe6, 0x65, 0xde, 0xc4, 0x80, 0x0f, 0xcd, 0x68, 0x6f, 0x07, 0x71, 0x08, -0x1f, 0xf9, 0x81, 0xfd, 0x00, 0x42, 0x21, 0xfb, 0xfd, 0x3d, 0x5a, 0xfe, 0x3d, 0x2d, 0x3b, 0x7c, -0xd8, 0x7e, 0xdf, 0xf5, 0x26, 0xf0, 0xce, 0x0b, 0x40, 0x17, 0xad, 0xd3, 0xce, 0xeb, 0xc1, 0x5e, -0xbe, 0x51, 0x5b, 0x48, 0x46, 0xcd, 0x85, 0x64, 0x4c, 0x10, 0x0c, 0x71, 0x1b, 0xd7, 0x09, 0x42, -0x4c, 0xe3, 0xe9, 0x23, 0x03, 0xbd, 0x73, 0x06, 0x04, 0x83, 0x5f, 0x0f, 0xf6, 0xe1, 0x29, 0x41, -0x18, 0x7d, 0xb8, 0xde, 0xdd, 0x09, 0xa3, 0x27, 0x08, 0xc1, 0x58, 0x98, 0x8f, 0x8d, 0xc8, 0x6d, -0x54, 0xd6, 0xdf, 0xd2, 0x8e, 0x9a, 0xcf, 0x1e, 0x4f, 0x75, 0x54, 0xde, 0xdf, 0xda, 0xc6, 0x07, -0x22, 0x8e, 0x8f, 0x2b, 0xef, 0x4f, 0xf5, 0x4f, 0xa3, 0x87, 0xfa, 0x8f, 0x56, 0xdc, 0x9f, 0xeb, -0x9f, 0xc6, 0x30, 0x61, 0xa0, 0xe2, 0xfe, 0x5c, 0xff, 0x6d, 0x7c, 0x36, 0x3b, 0x88, 0xfd, 0x15, -0xf7, 0xa7, 0xfa, 0x79, 0xdf, 0x52, 0xdf, 0xd1, 0x6a, 0xfa, 0x3b, 0xdb, 0xa8, 0xa6, 0x3f, 0xb7, -0xbf, 0x4e, 0xe0, 0xb9, 0x32, 0xfd, 0x8f, 0xb9, 0x8f, 0xd3, 0xc1, 0x23, 0x18, 0x2b, 0x31, 0xff, -0x0b, 0x1b, 0x1d, 0xeb, 0xc6, 0x51, 0x8c, 0x17, 0xec, 0x7f, 0x0b, 0x07, 0x50, 0xa4, 0x9d, 0x7c, -0x0f, 0x07, 0xbc, 0xfa, 0xa7, 0xe6, 0xa3, 0x03, 0x28, 0xb1, 0xf5, 0x84, 0x30, 0xb0, 0xa6, 0x7f, -0x22, 0x76, 0xd1, 0x6b, 0xbd, 0xc7, 0x26, 0x76, 0x33, 0x3c, 0xb7, 0xd1, 0x89, 0x09, 0xab, 0xff, -0x06, 0x7d, 0x67, 0x4c, 0xec, 0x9a, 0x8b, 0xe0, 0x57, 0xda, 0x7f, 0x73, 0x9c, 0xff, 0x46, 0xdb, -0x28, 0x54, 0x67, 0x13, 0xa1, 0x99, 0x61, 0x12, 0x12, 0x40, 0x20, 0x0d, 0xb4, 0x2d, 0x03, 0xc1, -0x0c, 0x70, 0x68, 0x08, 0x18, 0x3a, 0x64, 0x9f, 0x67, 0xf8, 0xec, 0x72, 0xb8, 0xf4, 0xf3, 0x8c, -0x83, 0x25, 0x5e, 0x2e, 0xee, 0xa0, 0x57, 0xee, 0xf3, 0x55, 0xc4, 0x71, 0x9f, 0x3f, 0x9b, 0x8d, -0xc0, 0x70, 0xbe, 0x03, 0x0e, 0x78, 0x19, 0x7f, 0x76, 0xaa, 0x0f, 0xf7, 0xf9, 0x78, 0xc8, 0x07, -0xed, 0xdf, 0x5e, 0xcb, 0x57, 0x10, 0x4b, 0x4e, 0xbe, 0x0e, 0xac, 0x1a, 0xac, 0x73, 0x95, 0x1a, -0xfd, 0xd4, 0x7c, 0x6c, 0xdc, 0x55, 0x43, 0x5d, 0xf5, 0x59, 0x73, 0x31, 0x11, 0x3b, 0x9f, 0x57, -0x43, 0xdd, 0xf5, 0xad, 0x1a, 0x92, 0xb1, 0x51, 0x5e, 0x87, 0xf8, 0x53, 0x15, 0xfa, 0x16, 0xe6, -0xa3, 0xe7, 0x9c, 0xe3, 0x52, 0x89, 0xbe, 0x55, 0x43, 0x6c, 0xc4, 0xd2, 0x9f, 0xc6, 0x7e, 0x25, -0xfa, 0x72, 0xff, 0x5b, 0x35, 0xf0, 0x35, 0x4f, 0x91, 0xbe, 0x98, 0x42, 0x40, 0xd6, 0x30, 0xa1, -0x44, 0x9f, 0xf7, 0x3f, 0x5d, 0xb3, 0x65, 0x0d, 0x63, 0x4a, 0xf4, 0x6d, 0xdf, 0x5f, 0xe4, 0x6a, -0x50, 0xa3, 0xbf, 0x5a, 0x43, 0x1c, 0x6f, 0x2b, 0xd2, 0xcf, 0xd5, 0xa0, 0x50, 0x9f, 0xc7, 0x2f, -0x27, 0xf8, 0xb3, 0x87, 0x11, 0x0c, 0x28, 0xd1, 0x97, 0xfb, 0xdf, 0x1a, 0x7f, 0x45, 0x30, 0xa1, -0x52, 0xdf, 0x5d, 0x83, 0x0a, 0x7d, 0x39, 0x0e, 0x3d, 0xa3, 0x52, 0xdf, 0xa9, 0x41, 0xa5, 0x3e, -0xb7, 0x07, 0xa7, 0xf0, 0x8a, 0x4a, 0x7d, 0xa7, 0x6d, 0xb2, 0xbe, 0x59, 0x4c, 0x9f, 0xf4, 0xcc, -0x4d, 0xd2, 0xff, 0x46, 0x08, 0x1a, 0xca, 0x16, 0x6f, 0x3e, 0xd2, 0x9c, 0xac, 0xa9, 0x7e, 0x1c, -0x57, 0x4b, 0xd4, 0xf6, 0xac, 0xa1, 0x2a, 0xfd, 0xf2, 0xb5, 0x73, 0x35, 0x90, 0xee, 0x54, 0x95, -0xfa, 0xdf, 0x56, 0xa8, 0xbd, 0xa6, 0x86, 0x8a, 0xf4, 0x67, 0xd0, 0x5a, 0xa5, 0x76, 0xae, 0x06, -0xb3, 0x1f, 0xad, 0x95, 0x8c, 0xbf, 0x6a, 0xdd, 0x4a, 0xd1, 0x4f, 0x25, 0x63, 0x97, 0x36, 0x4b, -0xff, 0xb5, 0x20, 0x2e, 0x15, 0xd2, 0x4f, 0x25, 0x26, 0xbf, 0x13, 0xc2, 0x6c, 0xc2, 0xe6, 0x35, -0x1f, 0x69, 0x5e, 0xf6, 0xd2, 0xaf, 0x44, 0x7b, 0xee, 0x24, 0x5e, 0x62, 0x54, 0x53, 0x83, 0xd4, -0xbf, 0x56, 0xae, 0xf6, 0x23, 0x03, 0x9d, 0x74, 0xdd, 0x59, 0x9c, 0x1b, 0xc4, 0xbf, 0x7f, 0x46, -0xf0, 0x72, 0x05, 0x35, 0x5c, 0x91, 0xfa, 0x65, 0x6b, 0xff, 0x11, 0x41, 0x88, 0xc6, 0x40, 0x69, -0xe7, 0xda, 0xcf, 0xaf, 0x79, 0x59, 0x25, 0x35, 0xf8, 0x77, 0xb7, 0x87, 0xc6, 0x08, 0x6f, 0x11, -0x5e, 0x25, 0x3c, 0x4f, 0x68, 0x25, 0xf0, 0xf2, 0x5d, 0x84, 0x16, 0x7e, 0x7d, 0x96, 0xf0, 0x2e, -0xa1, 0x8b, 0xb0, 0xd7, 0xfe, 0xcc, 0xdf, 0x4a, 0xd8, 0x43, 0x68, 0x63, 0xc4, 0x08, 0xff, 0x10, -0x96, 0x57, 0x11, 0xcc, 0x84, 0xfc, 0xe1, 0x6c, 0xc8, 0x3f, 0xbc, 0x12, 0xf2, 0x0b, 0x11, 0x0a, -0x08, 0x91, 0x76, 0xd0, 0xb6, 0x32, 0xbc, 0x1c, 0xcc, 0x86, 0x33, 0xe1, 0x4c, 0x30, 0xdb, 0x25, -0xef, 0x51, 0x98, 0xe5, 0xdf, 0xa7, 0xf0, 0xfa, 0xdb, 0x2d, 0x95, 0xdf, 0x87, 0xc6, 0x8b, 0xc6, -0xba, 0x6b, 0x98, 0x17, 0xa6, 0x71, 0xdc, 0x35, 0x9e, 0x58, 0x72, 0x8f, 0x2f, 0x3d, 0xb0, 0xe4, -0xba, 0x0f, 0x76, 0xdc, 0x7d, 0xdd, 0xf3, 0xc4, 0x11, 0x7b, 0x9c, 0x92, 0x77, 0x4e, 0x48, 0xb9, -0xbf, 0x93, 0x5e, 0xf0, 0xb8, 0x4f, 0xa2, 0x9d, 0xff, 0xa2, 0x19, 0x68, 0xe0, 0xdf, 0xba, 0x47, -0x93, 0x88, 0x9e, 0xd6, 0xcd, 0xff, 0xc2, 0xfc, 0xe4, 0x85, 0xa2, 0x19, 0x34, 0xb2, 0x7f, 0x7b, -0x6c, 0xf0, 0x55, 0xc1, 0x0c, 0x1a, 0xdc, 0xbf, 0x67, 0x06, 0xc9, 0xd8, 0xa8, 0x4e, 0xfe, 0xed, -0x0c, 0xa2, 0x5f, 0x7a, 0x66, 0xa0, 0x89, 0x7f, 0xaf, 0x0c, 0x52, 0xc9, 0xc9, 0x31, 0x9d, 0xfc, -0xdb, 0x73, 0x5b, 0xf6, 0xdc, 0xc5, 0x6a, 0x06, 0xb1, 0x0f, 0x75, 0xf2, 0x9f, 0x3f, 0x77, 0xe2, -0xd5, 0x74, 0xf0, 0x5f, 0x28, 0x03, 0x5d, 0xfc, 0xbb, 0xe7, 0x8e, 0xb4, 0xf4, 0x6f, 0x61, 0x72, -0xd8, 0xe5, 0x7f, 0x40, 0x2b, 0xff, 0xae, 0xf3, 0xff, 0xba, 0xf9, 0x2b, 0x0d, 0xfd, 0x97, 0x94, -0x41, 0x83, 0xfb, 0x97, 0x19, 0x9c, 0xd1, 0xcd, 0xbf, 0xb8, 0x89, 0x17, 0xd7, 0xbc, 0x8f, 0xe3, -0xa2, 0x56, 0xfe, 0xf9, 0xfc, 0x2f, 0xe7, 0x90, 0xf3, 0x32, 0x38, 0xab, 0x95, 0x7f, 0xd7, 0xdc, -0xad, 0x67, 0x06, 0x8d, 0xef, 0x7f, 0x4d, 0x06, 0x3c, 0xaf, 0x40, 0xef, 0x27, 0x35, 0xf3, 0xcf, -0x73, 0x49, 0x9f, 0x7b, 0x66, 0xa0, 0x8b, 0x7f, 0xef, 0x0c, 0xa6, 0xb4, 0xf2, 0x2f, 0x9f, 0x63, -0x75, 0x65, 0xd0, 0xa1, 0x99, 0x7f, 0x3e, 0xe6, 0x87, 0x36, 0x9c, 0x57, 0xd2, 0xc1, 0xbf, 0xeb, -0x38, 0xd0, 0xd4, 0xbf, 0x67, 0x06, 0x9a, 0xf9, 0xe7, 0x73, 0xe2, 0xfb, 0xf9, 0xfd, 0x1e, 0x46, -0x70, 0x49, 0x2b, 0xff, 0xae, 0xf3, 0xbf, 0x00, 0x7c, 0xb3, 0x06, 0x2e, 0xeb, 0xea, 0xbf, 0xc4, -0x0c, 0x1a, 0xda, 0xbf, 0x93, 0xc1, 0x5c, 0x04, 0x57, 0x74, 0xf5, 0x5f, 0x24, 0x03, 0x2d, 0xfc, -0x17, 0xc8, 0x40, 0x1b, 0xff, 0xb9, 0x0c, 0x0c, 0x7c, 0xad, 0xab, 0x7f, 0x8f, 0x0c, 0xb4, 0xf3, -0xef, 0xca, 0x40, 0x4b, 0xff, 0x79, 0xe7, 0x83, 0x09, 0x5d, 0xfd, 0x7b, 0x3e, 0xf7, 0xbb, 0xe3, -0x7f, 0xc7, 0xff, 0xf6, 0xf5, 0x7f, 0xac, 0x6a, 0xff, 0x47, 0x71, 0x6c, 0x5b, 0xfa, 0x8f, 0xe3, -0xae, 0x98, 0xb1, 0xfe, 0x9d, 0xb4, 0xaa, 0x66, 0x9a, 0x68, 0xa2, 0x0c, 0x6e, 0x6c, 0x2b, 0xff, -0x35, 0xf2, 0x5e, 0x56, 0x06, 0x5b, 0xc7, 0xff, 0x3d, 0xf1, 0x18, 0xfe, 0x5a, 0x3f, 0xe0, 0xcd, -0x19, 0x9c, 0xea, 0xc3, 0xcd, 0x2d, 0xee, 0x7f, 0x53, 0xbc, 0x3b, 0xad, 0xbf, 0x1f, 0xcd, 0x1b, -0x66, 0xa0, 0xde, 0xff, 0x0f, 0x9b, 0xe9, 0x3d, 0x3f, 0x03, 0xf2, 0x7b, 0x6b, 0x8b, 0xf9, 0xaf, -0x8b, 0xf7, 0x82, 0x19, 0xa8, 0xf3, 0x5f, 0x57, 0xef, 0x6b, 0xbe, 0x0b, 0x47, 0x11, 0x57, 0xec, -0x7f, 0x46, 0x85, 0x77, 0xcf, 0x0c, 0xea, 0xef, 0x5f, 0xa9, 0xf7, 0x75, 0x19, 0xd4, 0xd3, 0x7f, -0x1c, 0xdd, 0xb5, 0xbc, 0xbe, 0xd7, 0x22, 0x03, 0xa3, 0x0f, 0xdd, 0x2a, 0x9e, 0x7f, 0xd9, 0xaa, -0x6d, 0xc7, 0xff, 0x8e, 0xff, 0x5a, 0xf9, 0x5f, 0x4c, 0x46, 0x6f, 0x6c, 0x3b, 0xff, 0x9d, 0xb8, -0x51, 0x23, 0xff, 0x3f, 0x3e, 0x79, 0x72, 0xb5, 0x65, 0xbb, 0xf9, 0xef, 0x07, 0x9a, 0xc9, 0xdf, -0x74, 0x95, 0xfe, 0xb7, 0xa5, 0xf7, 0x72, 0x32, 0x68, 0x54, 0xef, 0xae, 0x0c, 0xee, 0x94, 0xe9, -0xff, 0xa7, 0x46, 0xf0, 0x5e, 0x4a, 0x06, 0x2a, 0xbd, 0xcf, 0x1a, 0x18, 0x67, 0xd4, 0x2b, 0x83, -0xee, 0x20, 0xee, 0x16, 0xf1, 0x5f, 0x3f, 0xef, 0x11, 0x9c, 0xce, 0xcd, 0x79, 0x0d, 0xe2, 0xbc, -0xaa, 0x0c, 0xf2, 0x9e, 0xf1, 0xff, 0xed, 0xd9, 0x83, 0xa9, 0x40, 0x3d, 0xea, 0x78, 0x68, 0x60, -0x64, 0xdd, 0xef, 0xec, 0x18, 0x38, 0x57, 0x0f, 0xed, 0x7d, 0xfb, 0xd0, 0x42, 0xbe, 0x7f, 0x76, -0xf9, 0xff, 0x5d, 0xa5, 0x77, 0x45, 0x19, 0xfc, 0x22, 0xfd, 0x6f, 0x09, 0xef, 0xb9, 0xdf, 0x1c, -0xa0, 0x75, 0xea, 0x99, 0x01, 0x0e, 0x22, 0x1d, 0x40, 0x07, 0x4c, 0xc9, 0x09, 0xc9, 0x69, 0xc9, -0x9f, 0x48, 0x3e, 0x28, 0xb9, 0x43, 0xf2, 0x1e, 0xc9, 0x01, 0xc9, 0xcd, 0xb3, 0x36, 0xfb, 0x32, -0x36, 0xc3, 0xe1, 0x88, 0x64, 0xb9, 0x1e, 0x7a, 0x25, 0x1f, 0x92, 0x1c, 0x96, 0xfc, 0x86, 0x69, -0xf3, 0xeb, 0x09, 0xb9, 0x7e, 0x5a, 0xf2, 0x80, 0xe4, 0x1e, 0xc9, 0x7b, 0x25, 0xb7, 0x4a, 0x0e, -0x48, 0x6e, 0x96, 0xec, 0x5b, 0xab, 0xb7, 0xca, 0xcb, 0x92, 0x33, 0x92, 0xb3, 0x92, 0x57, 0x24, -0x0b, 0x87, 0xcf, 0x48, 0xfe, 0x5b, 0xf2, 0x7f, 0x92, 0x45, 0x49, 0xec, 0x13, 0xc2, 0xb4, 0xea, -0x11, 0x22, 0x61, 0xd5, 0x27, 0x44, 0x9a, 0xb9, 0x4d, 0x88, 0x65, 0xe6, 0xa0, 0x10, 0x19, 0xe6, -0xb0, 0x10, 0x59, 0xe6, 0x61, 0x21, 0x56, 0x98, 0x05, 0x35, 0xf6, 0xcf, 0x7c, 0x8d, 0x72, 0x61, -0xce, 0x16, 0xe7, 0x61, 0xe6, 0x15, 0x7e, 0xe0, 0x94, 0x1b, 0x7c, 0x36, 0x9b, 0xa4, 0xbe, 0x42, -0x1f, 0x25, 0x48, 0x3d, 0x1b, 0xe6, 0xdf, 0x86, 0x20, 0x55, 0x52, 0x5e, 0x66, 0xf0, 0xeb, 0xb0, -0xfd, 0x9b, 0x11, 0xd9, 0xff, 0x01, 0xd3, 0x39, 0x74, 0x2c, 0x6e, 0x57, 0x00, 0x00}; -#endif /*__FAVICON_ICO_H__*/ diff --git a/src/web/html/h/index_html.h b/src/web/html/h/index_html.h deleted file mode 100644 index 7ae17e4c..00000000 --- a/src/web/html/h/index_html.h +++ /dev/null @@ -1,191 +0,0 @@ -#ifndef __INDEX_HTML_H__ -#define __INDEX_HTML_H__ -#define index_html_len 2967 -const uint8_t index_html[] PROGMEM = { -0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0xbd, 0x5a, 0xff, 0x6f, 0xdb, 0x36, -0x16, 0xff, 0xbd, 0x7f, 0x05, 0xa7, 0xc3, 0xb5, 0xf2, 0xc5, 0x96, 0x9c, 0xa4, 0x4d, 0x7b, 0x89, -0xe3, 0x21, 0x4b, 0xb2, 0x2d, 0x87, 0xae, 0x2d, 0xea, 0xf4, 0x8a, 0xa1, 0x28, 0x02, 0x5a, 0xa2, -0x6d, 0xb6, 0x32, 0x29, 0x88, 0x94, 0x5d, 0x6f, 0xeb, 0xff, 0x7e, 0xef, 0x51, 0x5f, 0x6c, 0x59, -0xa2, 0x6c, 0xaf, 0xbb, 0x19, 0x08, 0x62, 0x51, 0xe4, 0xe3, 0xe7, 0x7d, 0x7f, 0x8f, 0xf4, 0xe0, -0xbb, 0x50, 0x06, 0x7a, 0x15, 0x33, 0x32, 0xd3, 0xf3, 0x68, 0xf8, 0x68, 0x90, 0xfd, 0x23, 0xf0, -0x19, 0xcc, 0x18, 0x0d, 0xb3, 0xaf, 0xe6, 0x51, 0x73, 0x1d, 0xb1, 0xe1, 0x9d, 0x08, 0xd9, 0x97, -0x81, 0x9f, 0x3d, 0xac, 0x5f, 0x46, 0x5c, 0x7c, 0x26, 0x09, 0x8b, 0x2e, 0x1d, 0xa5, 0x57, 0x11, -0x53, 0x33, 0xc6, 0xb4, 0x43, 0x90, 0xf0, 0xa5, 0xa3, 0xd9, 0x17, 0xed, 0x07, 0x4a, 0x39, 0x64, -0x96, 0xb0, 0x49, 0x3e, 0xc3, 0x83, 0x81, 0xef, 0x17, 0x97, 0x7d, 0xef, 0x85, 0xd7, 0xef, 0xf7, -0x8f, 0x1d, 0x1f, 0xf6, 0x9e, 0x33, 0x4d, 0x89, 0xa0, 0x73, 0x58, 0xb3, 0xe0, 0x6c, 0x19, 0xcb, -0x04, 0x68, 0x04, 0x52, 0x68, 0x26, 0xf4, 0xa5, 0xb3, 0xe4, 0xa1, 0x9e, 0x5d, 0x86, 0x6c, 0xc1, -0x03, 0xd6, 0x33, 0x0f, 0x5d, 0xc2, 0x05, 0xd7, 0x9c, 0x46, 0x3d, 0x15, 0xd0, 0x88, 0x5d, 0x1e, -0x3b, 0x05, 0x91, 0x60, 0x46, 0x13, 0xc5, 0x60, 0xd1, 0xbb, 0xfb, 0x1f, 0x7b, 0x2f, 0x70, 0x58, -0x05, 0x09, 0x8f, 0xf5, 0x26, 0xa2, 0x4f, 0x74, 0x41, 0xb3, 0x51, 0x87, 0xa8, 0x24, 0xb8, 0x74, -0x68, 0xcc, 0xbd, 0x4f, 0x15, 0x50, 0xc3, 0x81, 0x9f, 0xcd, 0x00, 0x02, 0x87, 0x70, 0x18, 0xc8, -0x48, 0x26, 0x6a, 0x07, 0x8b, 0x89, 0x1c, 0x4b, 0xad, 0x36, 0x18, 0x14, 0x92, 0xa3, 0x70, 0xbb, -0x44, 0xc8, 0x89, 0x8c, 0x22, 0xb9, 0x74, 0x88, 0x9f, 0xab, 0xc2, 0x5f, 0xeb, 0x62, 0x30, 0x96, -0xe1, 0x6a, 0x43, 0xf2, 0x21, 0x5f, 0x90, 0x20, 0xa2, 0x4a, 0x01, 0x0c, 0x19, 0x0b, 0xba, 0x70, -0xf2, 0x79, 0x34, 0x07, 0xe3, 0x6f, 0x62, 0x28, 0xa7, 0xa2, 0xfe, 0x9c, 0xe1, 0xd5, 0x4c, 0xae, -0x6e, 0xee, 0xdf, 0x0d, 0x7c, 0xba, 0xb5, 0x68, 0x2d, 0x9c, 0xf3, 0x85, 0xe4, 0xa1, 0xdb, 0xef, -0x5c, 0x94, 0x6b, 0x39, 0x20, 0x76, 0x88, 0x14, 0x41, 0xc4, 0x83, 0xcf, 0xc5, 0xae, 0x6e, 0xc7, -0xd9, 0x00, 0xa5, 0x62, 0x2a, 0x50, 0x78, 0xf8, 0xef, 0xe0, 0xd1, 0x35, 0x1a, 0xe4, 0x8d, 0x87, -0x25, 0x63, 0x05, 0x80, 0xb9, 0x1c, 0x73, 0x44, 0xbf, 0xa6, 0x41, 0xcd, 0x34, 0x98, 0x73, 0x5a, -0x4e, 0x9a, 0xf1, 0x90, 0x15, 0xfa, 0xf0, 0x23, 0xbe, 0x60, 0x15, 0xc5, 0xbe, 0x84, 0x81, 0x72, -0x9f, 0x2a, 0x89, 0xa7, 0xcd, 0x24, 0x14, 0x4b, 0xc0, 0xd2, 0x2a, 0x44, 0xde, 0xb3, 0x71, 0x36, -0x6a, 0xa1, 0xf4, 0xcc, 0x46, 0x49, 0xa7, 0x71, 0x85, 0xd0, 0x88, 0x69, 0xcd, 0xc5, 0x54, 0x55, -0xe9, 0xa0, 0x44, 0x0a, 0x02, 0x8a, 0xc5, 0x2c, 0xa1, 0x5a, 0x26, 0x4e, 0x5d, 0x80, 0xe5, 0x7e, -0x67, 0xcd, 0xfb, 0xa5, 0x71, 0x48, 0x75, 0x95, 0xfd, 0x77, 0x66, 0xc8, 0x02, 0xfb, 0xb9, 0x05, -0xf6, 0x4a, 0x69, 0x36, 0xaf, 0xe2, 0x36, 0x43, 0xdf, 0x88, 0xfa, 0x45, 0xb9, 0x03, 0x38, 0x20, -0x78, 0x14, 0x4d, 0xa6, 0xe8, 0xb9, 0x0f, 0xe3, 0x88, 0x8a, 0xcf, 0xce, 0xf0, 0xed, 0xed, 0xe8, -0x9e, 0x5c, 0xbd, 0xb9, 0xb3, 0x80, 0xfd, 0x77, 0xb1, 0x7a, 0xa6, 0x75, 0xac, 0xce, 0x7d, 0x9f, -0x82, 0x49, 0x87, 0x3a, 0xf5, 0x10, 0xf9, 0x36, 0xad, 0x1b, 0x19, 0xa4, 0x73, 0xf0, 0x35, 0xaa, -0xb9, 0x14, 0x16, 0x82, 0xc7, 0xfd, 0x35, 0x9e, 0xb1, 0x4c, 0x75, 0x85, 0xe1, 0x2b, 0x1c, 0xf9, -0x46, 0x7e, 0xfb, 0x16, 0x13, 0x95, 0x53, 0x2e, 0xc0, 0x30, 0xf1, 0x9f, 0x0d, 0x9a, 0x75, 0x25, -0xa0, 0x32, 0x4b, 0x37, 0xd1, 0x0d, 0x7c, 0x70, 0x9f, 0x2d, 0x47, 0x5a, 0xf2, 0x09, 0xcf, 0xdc, -0xb7, 0xf0, 0x65, 0x31, 0x91, 0x08, 0xd6, 0x4c, 0xdd, 0x58, 0x51, 0x5d, 0x95, 0xd0, 0x18, 0x18, -0xdb, 0x70, 0xb8, 0xca, 0xeb, 0x3c, 0x80, 0x6d, 0xbd, 0x36, 0x53, 0xe2, 0xfa, 0x58, 0x4d, 0x68, -0x21, 0x53, 0x68, 0x90, 0x9a, 0xcf, 0xd9, 0x39, 0xc9, 0xc5, 0x96, 0x4d, 0x40, 0xe2, 0xa9, 0x79, -0x51, 0xca, 0x73, 0x30, 0x4e, 0xfc, 0x7d, 0x69, 0xde, 0x8e, 0xde, 0xf4, 0xee, 0x9b, 0xa9, 0xa2, -0xf5, 0xd7, 0x75, 0x54, 0x92, 0xf2, 0xe3, 0x6f, 0xe1, 0x25, 0xf3, 0x0a, 0x72, 0x07, 0xa2, 0x55, -0xe7, 0xb6, 0x3d, 0x2a, 0x12, 0xe4, 0x8b, 0x52, 0x07, 0xd6, 0x79, 0x85, 0xe6, 0x93, 0xdd, 0x53, -0x8d, 0xce, 0x68, 0x22, 0x1e, 0x2a, 0xda, 0x6d, 0xe4, 0xf2, 0x91, 0x95, 0x80, 0x90, 0x9a, 0x39, -0x96, 0x4d, 0x66, 0xa7, 0xc3, 0x51, 0x1a, 0x63, 0x7e, 0x26, 0x7a, 0xc6, 0x15, 0x89, 0x13, 0xf9, -0x89, 0x05, 0x1a, 0x98, 0x85, 0x37, 0xcd, 0x4b, 0xd2, 0xa8, 0xf9, 0x45, 0x5e, 0x3d, 0x0c, 0xcb, -0xcc, 0x53, 0xf8, 0xf1, 0x94, 0xeb, 0x59, 0x3a, 0xf6, 0x02, 0x39, 0xf7, 0xa3, 0x74, 0x4e, 0xe3, -0xd4, 0x78, 0xb6, 0x3f, 0x8e, 0xe4, 0xd8, 0x9f, 0x53, 0x2e, 0x7c, 0xc8, 0xd9, 0xfe, 0xf5, 0xcf, -0x57, 0xaf, 0x7e, 0xba, 0x1d, 0x79, 0xf3, 0xb0, 0xee, 0xec, 0xd7, 0x33, 0x2a, 0xa6, 0x0c, 0x9c, -0x03, 0x3d, 0x62, 0x00, 0x29, 0xa0, 0x1d, 0xc0, 0x0d, 0x57, 0x41, 0xaa, 0x14, 0x59, 0xc2, 0xbe, -0x24, 0x55, 0x90, 0xdf, 0x48, 0x0d, 0x53, 0x08, 0x73, 0x64, 0x12, 0x7a, 0xd3, 0xa9, 0xff, 0xfe, -0xb7, 0xd9, 0x97, 0xdb, 0x5f, 0xcf, 0x4e, 0xe6, 0x3f, 0x38, 0x66, 0x29, 0x0c, 0xef, 0xb7, 0xcf, -0x5b, 0x66, 0xe4, 0xb6, 0x2f, 0xbf, 0x5c, 0xa9, 0x14, 0x8c, 0xaa, 0xc6, 0x5d, 0x36, 0xbe, 0xdf, -0x96, 0xd7, 0xe0, 0xa0, 0x09, 0x1f, 0xa7, 0x9a, 0x11, 0x2d, 0xc9, 0xe1, 0x92, 0x7e, 0x07, 0x59, -0xee, 0xe1, 0x17, 0x2a, 0x52, 0x1a, 0x19, 0x49, 0xd7, 0xc0, 0x84, 0xdb, 0x71, 0x75, 0x37, 0xa6, -0x1a, 0x0a, 0xc1, 0xa7, 0x33, 0x1d, 0xad, 0x3c, 0xac, 0xb3, 0x2a, 0x38, 0x96, 0x32, 0xf9, 0x3c, -0x81, 0x6a, 0x48, 0xf9, 0x80, 0x30, 0x86, 0xc4, 0xff, 0x00, 0x35, 0x20, 0xe8, 0x35, 0xc6, 0x1d, -0xfd, 0x8d, 0xef, 0xfd, 0xd3, 0x22, 0xf8, 0xe3, 0x0c, 0xef, 0x37, 0x1e, 0x37, 0x65, 0x80, 0xa5, -0x88, 0x24, 0x35, 0xba, 0x22, 0x8f, 0xc9, 0x3d, 0x53, 0x9a, 0x6c, 0x90, 0x20, 0x13, 0x9e, 0xcc, -0xc1, 0x75, 0x58, 0xf7, 0x30, 0x31, 0x55, 0x51, 0xec, 0xb2, 0xcc, 0x9b, 0x8d, 0x0d, 0x0f, 0xb4, -0xd2, 0x39, 0xfd, 0xcc, 0x08, 0xad, 0x83, 0x8b, 0xe9, 0x2a, 0x46, 0xed, 0x30, 0xc0, 0x16, 0xa7, -0x2a, 0x98, 0x35, 0x6a, 0x49, 0xec, 0xa1, 0xa0, 0x81, 0x6f, 0x73, 0xd5, 0x41, 0x5c, 0x04, 0x21, -0x28, 0xfc, 0x1c, 0x3b, 0xce, 0xfb, 0x8d, 0x90, 0x40, 0x96, 0x54, 0x11, 0x05, 0x48, 0x34, 0x0b, -0xc9, 0x24, 0x91, 0xf3, 0x3a, 0xf4, 0xe5, 0x72, 0xe9, 0xcd, 0xf9, 0xe7, 0x44, 0x62, 0x1e, 0x49, -0xa0, 0xf0, 0x65, 0x89, 0x27, 0x98, 0xf6, 0xa1, 0xe8, 0xe3, 0x81, 0xff, 0xec, 0xe4, 0xd9, 0xf3, -0xe7, 0x2f, 0xea, 0x32, 0x34, 0x71, 0x27, 0xcc, 0x7c, 0x16, 0x78, 0xf2, 0x88, 0xfb, 0x4b, 0x9d, -0x46, 0xa7, 0x92, 0x48, 0x77, 0x87, 0xf8, 0x7a, 0xa0, 0xdc, 0x4e, 0x89, 0x96, 0x0c, 0x39, 0x91, -0x10, 0x2d, 0x37, 0x13, 0xe4, 0x66, 0xc8, 0x8e, 0xd8, 0x44, 0x57, 0x8b, 0xd5, 0xfd, 0x2b, 0x96, -0xbc, 0x40, 0x27, 0x8f, 0x03, 0x19, 0xaf, 0xc8, 0x49, 0xff, 0xe4, 0xb4, 0x5a, 0x1b, 0x6c, 0xeb, -0xaa, 0xd1, 0xb5, 0x9a, 0xc3, 0x56, 0xdd, 0x2c, 0xdb, 0xc2, 0xd8, 0x01, 0x31, 0xba, 0x4e, 0xf9, -0x27, 0x33, 0xaf, 0x4e, 0x78, 0x6d, 0x6b, 0xdb, 0xc5, 0x4a, 0x2e, 0xba, 0x04, 0x83, 0x82, 0xb3, -0x9b, 0xdf, 0xad, 0x0d, 0xf7, 0xf3, 0x5c, 0x78, 0x9e, 0x73, 0xad, 0xfc, 0xf1, 0xe4, 0xf9, 0xf3, -0x93, 0xe7, 0xcf, 0x00, 0xe6, 0xdd, 0x3d, 0x19, 0xfd, 0x7c, 0x75, 0x4e, 0xf2, 0x11, 0x72, 0x7e, -0x4e, 0x8a, 0xda, 0xcf, 0x2a, 0x15, 0xa3, 0x7f, 0xa6, 0xe2, 0x07, 0x6c, 0x05, 0x9d, 0x7d, 0x25, -0x17, 0x24, 0x0c, 0x7c, 0x71, 0xc1, 0x10, 0x83, 0x14, 0xca, 0x93, 0xc9, 0x14, 0x16, 0x06, 0x4c, -0x28, 0x06, 0x80, 0x56, 0x3d, 0x11, 0xf4, 0x14, 0xf5, 0x9f, 0x7a, 0x7d, 0x08, 0x2d, 0xac, 0x1e, -0x42, 0xc8, 0xf0, 0xfa, 0x9a, 0xfc, 0xf0, 0x6b, 0xef, 0xd5, 0x75, 0x6f, 0x74, 0x45, 0x60, 0xda, -0x1e, 0xb2, 0xdd, 0xb6, 0xdd, 0xd6, 0x8e, 0xb8, 0xca, 0xc2, 0x82, 0x26, 0x84, 0x7d, 0x61, 0xaf, -0x45, 0xc0, 0xc8, 0x25, 0xd1, 0x49, 0xca, 0x2e, 0x6a, 0xef, 0x35, 0x34, 0x83, 0xd7, 0x10, 0xd0, -0x2e, 0x49, 0xbf, 0xe1, 0xa5, 0x6a, 0x1e, 0x47, 0xf6, 0xb1, 0x4e, 0x82, 0xb7, 0x8e, 0x53, 0x7f, -0x0d, 0xed, 0x36, 0xa3, 0x0a, 0xf7, 0x14, 0x69, 0x14, 0x5d, 0x54, 0xab, 0x95, 0x49, 0x2a, 0x02, -0x0c, 0x67, 0x04, 0xda, 0x86, 0xeb, 0xb1, 0x2b, 0xc7, 0x9f, 0x3a, 0xe4, 0xf7, 0x9a, 0x4f, 0x1b, -0xe8, 0x40, 0xa0, 0x48, 0x51, 0x1e, 0x88, 0xf1, 0x36, 0x62, 0xf8, 0xf5, 0x87, 0xd5, 0x5d, 0xe8, -0x62, 0xd7, 0xff, 0x96, 0xa9, 0x34, 0xd2, 0x4e, 0xe7, 0xa2, 0xb6, 0x9a, 0x4f, 0x90, 0xee, 0x07, -0x47, 0xa5, 0x41, 0xc0, 0xa0, 0xbf, 0xff, 0xd8, 0xb4, 0x05, 0x7e, 0x98, 0xc7, 0x85, 0x60, 0xc9, -0xcf, 0xf7, 0xbf, 0xbc, 0x44, 0x5e, 0x0c, 0x63, 0x54, 0x84, 0x28, 0xb5, 0x00, 0xf2, 0x6e, 0xe8, -0x5c, 0x34, 0x2e, 0x03, 0x30, 0x57, 0x9f, 0xe8, 0x17, 0xd7, 0xf4, 0x3e, 0xbe, 0x69, 0xff, 0x9d, -0x2e, 0x89, 0xf1, 0xf0, 0xa2, 0x01, 0xcd, 0xd7, 0xda, 0x08, 0x8b, 0x14, 0xdb, 0x0b, 0xcf, 0x6d, -0x92, 0xc8, 0xe4, 0x1c, 0xbe, 0x1c, 0x11, 0xc3, 0x10, 0xc3, 0x67, 0xe7, 0x63, 0x75, 0x8f, 0xaf, -0x16, 0x01, 0x43, 0xc3, 0x8a, 0x75, 0xb4, 0x6b, 0x93, 0x2f, 0x56, 0xd3, 0xa8, 0x23, 0xb6, 0x24, -0x37, 0xf0, 0xd5, 0x6d, 0x80, 0x8e, 0xd3, 0x60, 0xe3, 0x7c, 0xd6, 0xeb, 0x31, 0xe6, 0x86, 0xa6, -0x79, 0x30, 0xc7, 0x0b, 0xe6, 0x21, 0x62, 0x86, 0x5d, 0x1f, 0x4c, 0xed, 0xdf, 0x3c, 0x6b, 0x41, -0x23, 0x98, 0x65, 0x44, 0x75, 0x27, 0xb4, 0x8b, 0x18, 0x50, 0xb7, 0x39, 0x50, 0x9f, 0x1c, 0x83, -0xd7, 0x36, 0x6c, 0x50, 0x95, 0xb8, 0x69, 0xc5, 0x41, 0xe2, 0xc6, 0x84, 0xba, 0xc4, 0x79, 0xf3, -0x7a, 0x74, 0x0f, 0x8f, 0xff, 0x19, 0xbd, 0x7e, 0xe5, 0x29, 0xa8, 0x99, 0xc4, 0x94, 0x4f, 0x56, -0xc6, 0xb4, 0x3a, 0xfb, 0x89, 0xca, 0xe0, 0xf9, 0x89, 0x81, 0xe8, 0x79, 0x60, 0x33, 0x49, 0x30, -0xaa, 0xdc, 0x99, 0x3a, 0x8d, 0xba, 0x33, 0x34, 0xa0, 0x79, 0x31, 0xeb, 0xeb, 0x1c, 0x98, 0xd7, -0x6f, 0x21, 0xeb, 0x35, 0xbc, 0x6f, 0x85, 0x05, 0x7d, 0x89, 0x0d, 0x92, 0xf1, 0x4f, 0x63, 0x18, -0x5a, 0x3d, 0x08, 0xb9, 0xdc, 0xb6, 0x0c, 0x9b, 0xa6, 0x2b, 0x4b, 0xc8, 0xbf, 0x6c, 0x42, 0xc7, -0xa5, 0x69, 0x5c, 0x6c, 0x31, 0xcd, 0xc4, 0xe3, 0x7c, 0x34, 0x4b, 0xf3, 0x06, 0xcf, 0xba, 0xe1, -0x4a, 0x6d, 0xaa, 0x19, 0xa8, 0xf8, 0xe4, 0xc5, 0xd9, 0x53, 0xd8, 0x86, 0xfc, 0x93, 0x9c, 0x9e, -0x3d, 0x6b, 0x5e, 0x36, 0x4b, 0x14, 0xa9, 0x2d, 0x3b, 0x3d, 0xcb, 0x56, 0x9d, 0x3c, 0x6d, 0x5e, -0x34, 0xe7, 0xa2, 0xbe, 0xe8, 0xcc, 0x2c, 0x39, 0xeb, 0x37, 0x2f, 0x51, 0x2c, 0xc0, 0x25, 0x30, -0xd3, 0x3e, 0xa7, 0x35, 0xfa, 0xe4, 0xdc, 0x37, 0xc8, 0xac, 0xea, 0xc1, 0x46, 0x0e, 0x47, 0xe0, -0xbf, 0x37, 0x74, 0xe5, 0x34, 0xc6, 0xa9, 0x63, 0xf2, 0x5d, 0x36, 0xad, 0xb3, 0x33, 0x20, 0x1c, -0xa1, 0x77, 0x39, 0xed, 0x5b, 0xe2, 0x9c, 0xae, 0x89, 0x17, 0xae, 0xd3, 0x77, 0x8e, 0x40, 0xa0, -0x1d, 0x4f, 0xa5, 0x63, 0x70, 0x0a, 0xb7, 0x77, 0xd2, 0x41, 0x28, 0xe7, 0x4e, 0xd3, 0x46, 0xf9, -0x7c, 0x90, 0xe5, 0x41, 0xf3, 0x41, 0x90, 0x9b, 0xf3, 0x2d, 0xc6, 0x30, 0xc2, 0x56, 0xbb, 0x45, -0x9a, 0xa6, 0xad, 0x6f, 0x0e, 0xe3, 0x7d, 0x14, 0x4f, 0xc5, 0x5c, 0x6d, 0xa1, 0xbc, 0x88, 0xf9, -0xa5, 0x59, 0x0f, 0xc8, 0xf1, 0xd9, 0x8b, 0x7e, 0xf6, 0xe9, 0x58, 0xab, 0xde, 0x32, 0x48, 0x36, -0x47, 0x7a, 0x6b, 0xa4, 0xc6, 0x8f, 0x61, 0xac, 0xa2, 0x6f, 0x2d, 0xef, 0x94, 0x44, 0x17, 0x1b, -0x81, 0x40, 0x90, 0xad, 0xbd, 0xd3, 0x81, 0x85, 0xab, 0xfa, 0x16, 0x8e, 0x25, 0x27, 0x15, 0x36, -0xcb, 0x45, 0xec, 0x62, 0x10, 0x46, 0x33, 0x50, 0x2b, 0x11, 0x64, 0xe5, 0xfb, 0x38, 0x81, 0x4e, -0x0c, 0x4a, 0xdd, 0x2e, 0xe9, 0x77, 0xc9, 0x07, 0x67, 0xac, 0x85, 0xf3, 0xb1, 0x4b, 0x8a, 0x79, -0xd0, 0x63, 0x6a, 0x29, 0x1c, 0x8b, 0x0c, 0x32, 0x0c, 0x78, 0x96, 0x24, 0xc2, 0xeb, 0x19, 0x8f, -0x42, 0x17, 0xcf, 0x46, 0x5c, 0xe7, 0xd5, 0xfd, 0x1b, 0x82, 0x6e, 0x00, 0x74, 0x17, 0x0c, 0x22, -0x85, 0x80, 0xe2, 0x28, 0x98, 0xd1, 0x71, 0xc4, 0x3c, 0xe2, 0x74, 0xf6, 0x26, 0xc6, 0x0e, 0xdc, -0xd6, 0x41, 0x06, 0xf0, 0xab, 0xe1, 0x60, 0xa3, 0x0e, 0xb0, 0xa9, 0xd0, 0xa3, 0x61, 0x78, 0xbb, -0x00, 0x6b, 0x7b, 0xc9, 0x95, 0xc6, 0x20, 0xe6, 0x3a, 0xe6, 0x0c, 0x1c, 0x08, 0xe5, 0xda, 0x6f, -0xd4, 0x92, 0xb5, 0xaa, 0x80, 0xba, 0xfc, 0x15, 0x16, 0xb8, 0xd7, 0x50, 0x2c, 0xb4, 0xda, 0xa3, -0x5b, 0x5a, 0xa4, 0x02, 0xe1, 0x70, 0x05, 0xe1, 0x92, 0xf4, 0x4a, 0x6b, 0x96, 0x93, 0x09, 0x8a, -0x1f, 0x08, 0x0c, 0xb6, 0x2c, 0xdc, 0x6a, 0x70, 0x8f, 0x1f, 0x93, 0x0a, 0x4d, 0xb3, 0xbe, 0xa8, -0x0d, 0x2a, 0x24, 0x87, 0x5b, 0x24, 0x6d, 0x28, 0xf1, 0xb3, 0x59, 0xcd, 0xbd, 0x81, 0x26, 0x0c, -0xd2, 0x27, 0x58, 0x11, 0xa8, 0x14, 0x7a, 0x23, 0x57, 0x75, 0xba, 0x64, 0xc9, 0xa3, 0x08, 0xe2, -0x6b, 0x0a, 0x56, 0x4a, 0x35, 0xc9, 0xf6, 0xcd, 0x62, 0x4c, 0x99, 0x51, 0xf6, 0x43, 0x95, 0x67, -0x1a, 0x4f, 0xcb, 0x97, 0x12, 0xaf, 0x7e, 0x46, 0x26, 0x57, 0xbb, 0x4f, 0x42, 0xd6, 0xbb, 0xb9, -0x7d, 0x62, 0x53, 0xe0, 0x57, 0xab, 0x67, 0xee, 0xc9, 0x94, 0xd1, 0x96, 0x31, 0xd5, 0x6e, 0xc9, -0x18, 0x89, 0x73, 0x4e, 0x41, 0x9b, 0x68, 0xb2, 0x21, 0xd8, 0xd2, 0x85, 0x95, 0x5a, 0x2d, 0xb8, -0x0c, 0xc9, 0x7e, 0xba, 0x6d, 0x93, 0x7b, 0x05, 0x26, 0x06, 0x6e, 0x23, 0xe2, 0x10, 0x65, 0xfc, -0xf7, 0x09, 0xd7, 0x2e, 0xe0, 0x3d, 0x84, 0x5c, 0xe3, 0xc0, 0x58, 0x8a, 0x39, 0x37, 0x28, 0xe5, -0xdb, 0xca, 0x4d, 0x8b, 0x53, 0xfc, 0xd5, 0xec, 0x7c, 0xdd, 0x11, 0x88, 0x5b, 0x6b, 0xb0, 0xbb, -0x05, 0xa2, 0xee, 0x42, 0xc1, 0x65, 0x2b, 0xa6, 0xb1, 0x4c, 0x82, 0x46, 0xcd, 0xfd, 0xe0, 0x08, -0x29, 0x80, 0xa7, 0x06, 0x7c, 0x13, 0x99, 0xb8, 0x38, 0x95, 0x13, 0x39, 0x21, 0x96, 0x8a, 0xae, -0x20, 0x87, 0xa7, 0xfd, 0x18, 0xcc, 0xe1, 0xdf, 0x28, 0x6b, 0x62, 0xec, 0x51, 0x3f, 0xc0, 0x8a, -0xda, 0x5c, 0xef, 0xf5, 0x8a, 0x86, 0xc7, 0x3e, 0x19, 0x7a, 0x45, 0x1e, 0xb5, 0xa4, 0x11, 0xb0, -0xf4, 0x09, 0x45, 0xad, 0x5f, 0xc2, 0xee, 0xd0, 0x70, 0x08, 0xe3, 0x1c, 0xf6, 0x30, 0x67, 0xd6, -0xac, 0xc1, 0xbe, 0xa7, 0x89, 0xb0, 0x6b, 0x66, 0x03, 0x29, 0x1e, 0x74, 0xb7, 0x38, 0x5c, 0x09, -0xb3, 0x70, 0x4f, 0xcb, 0xdc, 0xaf, 0x99, 0x89, 0x62, 0xb0, 0xdd, 0x84, 0xcd, 0xd5, 0x83, 0xa1, -0x80, 0xb8, 0xff, 0xf8, 0x83, 0x40, 0x19, 0x01, 0xe3, 0xa0, 0xbc, 0x3d, 0xb9, 0x40, 0x7b, 0xde, -0x8b, 0x0b, 0x73, 0x52, 0xbf, 0x07, 0x17, 0x42, 0x6a, 0xb2, 0x82, 0xa0, 0x69, 0x06, 0x90, 0x9f, -0x9d, 0xec, 0xf4, 0x73, 0x4e, 0xc0, 0x27, 0x22, 0xaa, 0xf4, 0xc3, 0xce, 0x56, 0xb6, 0xb2, 0x5f, -0xb9, 0x0f, 0x81, 0xd4, 0x4e, 0x84, 0xc4, 0x0e, 0x80, 0x9a, 0x43, 0xbd, 0x84, 0x05, 0x8c, 0x2f, -0x20, 0xca, 0xa4, 0x42, 0xc3, 0x5c, 0x8c, 0x66, 0xad, 0x50, 0x0e, 0xda, 0x0c, 0x5b, 0x67, 0xae, -0x76, 0x04, 0xd2, 0x2d, 0x3d, 0xc5, 0x89, 0x0c, 0xd3, 0x00, 0x5c, 0xbb, 0x2d, 0xf1, 0xad, 0xf7, -0x3b, 0xca, 0xa5, 0xb9, 0x5e, 0x76, 0xf1, 0x2d, 0xd1, 0xab, 0xee, 0x67, 0x3f, 0x9a, 0x23, 0x8b, -0xfd, 0x80, 0x94, 0x20, 0x4c, 0x88, 0xe3, 0x5e, 0x90, 0x26, 0x0f, 0xf1, 0x32, 0xc1, 0xb2, 0xf9, -0xbd, 0x73, 0x78, 0x80, 0x6a, 0x6e, 0x2b, 0xf3, 0x12, 0xc8, 0xb5, 0x97, 0xb0, 0x8b, 0xa9, 0x8b, -0x0c, 0x74, 0xc9, 0x69, 0x3f, 0xfb, 0x33, 0xc6, 0x69, 0x30, 0x05, 0x51, 0xa7, 0x6b, 0x5f, 0x68, -0xea, 0xa9, 0xbb, 0x22, 0x23, 0xfe, 0xc3, 0x30, 0x01, 0x4a, 0x09, 0x4d, 0x86, 0x71, 0xb2, 0x73, -0x07, 0x18, 0xc0, 0x1f, 0x3e, 0x64, 0x43, 0x46, 0xbb, 0xf0, 0xc5, 0x88, 0xa0, 0x85, 0xf2, 0x38, -0x71, 0x9b, 0x95, 0xd9, 0xb9, 0x78, 0xf4, 0x68, 0x3f, 0xbb, 0x28, 0xfd, 0xf7, 0xf7, 0x36, 0x63, -0x6a, 0xf2, 0x10, 0x48, 0xce, 0xfd, 0x5d, 0x79, 0xb7, 0xa9, 0x2b, 0x6e, 0xa4, 0x65, 0x6d, 0x8e, -0x1b, 0x75, 0x94, 0x49, 0xb4, 0x37, 0x24, 0x48, 0x85, 0xe4, 0x54, 0x26, 0x69, 0x44, 0x74, 0x42, -0x85, 0x9a, 0x73, 0x73, 0xe8, 0x9d, 0xc9, 0xb5, 0xde, 0x2a, 0x40, 0xa5, 0x85, 0x72, 0xfb, 0xcb, -0x33, 0x9b, 0x29, 0xa6, 0x6d, 0xbd, 0x17, 0x5f, 0x38, 0x1d, 0x2f, 0x61, 0x71, 0x44, 0x03, 0x66, -0xaa, 0xec, 0x84, 0x09, 0x37, 0x3e, 0xe4, 0x7c, 0x02, 0x43, 0xbe, 0x8b, 0xe1, 0xfc, 0x2f, 0x48, -0x8d, 0x4b, 0x4c, 0x8d, 0x36, 0x5a, 0x55, 0x49, 0xe7, 0x46, 0x8f, 0xbb, 0x6f, 0x1b, 0xfe, 0x3a, -0xc1, 0x80, 0x48, 0x8d, 0x4a, 0x96, 0x76, 0xd9, 0x36, 0x17, 0xfa, 0x45, 0x55, 0xe3, 0x45, 0x4c, -0x4c, 0xf5, 0xcc, 0x98, 0xd4, 0x7e, 0x80, 0x70, 0x55, 0x23, 0x20, 0x93, 0x2b, 0x0a, 0x40, 0x05, -0xfd, 0x35, 0xae, 0x26, 0x14, 0x78, 0x7c, 0x8a, 0x0d, 0x70, 0x7e, 0xa0, 0xda, 0xd2, 0x6a, 0x80, -0x5a, 0xff, 0xcb, 0x12, 0x3c, 0xfe, 0x70, 0xca, 0x9f, 0x3d, 0x60, 0x63, 0xb1, 0x1e, 0x2f, 0x68, -0xd8, 0x83, 0xec, 0x9f, 0x64, 0xc5, 0xc9, 0x7e, 0x95, 0xb2, 0xce, 0x6d, 0x5d, 0x02, 0x71, 0x30, -0xc1, 0x5b, 0xb2, 0x7c, 0xcf, 0x90, 0x40, 0x84, 0x59, 0x5b, 0x7e, 0x81, 0xa4, 0xd5, 0xdc, 0x8b, -0x3c, 0xd8, 0xcc, 0xd8, 0xf0, 0x6f, 0x61, 0xec, 0x57, 0x99, 0x12, 0x9a, 0x30, 0x92, 0x2a, 0xd3, -0x28, 0x6c, 0x5c, 0xff, 0xe5, 0xfc, 0x94, 0xd7, 0x0c, 0x1e, 0xb9, 0x13, 0x24, 0xc0, 0x33, 0x6f, -0xb0, 0xdf, 0xec, 0x8e, 0x97, 0xac, 0x60, 0xf5, 0x9c, 0xae, 0xc0, 0x9c, 0x61, 0x81, 0x96, 0x10, -0x02, 0x56, 0x44, 0xcf, 0x58, 0x29, 0x1c, 0x28, 0x93, 0x31, 0x67, 0xe6, 0xf0, 0x0f, 0x10, 0x8d, -0x4d, 0x5a, 0xff, 0x67, 0xfe, 0xbf, 0x19, 0x7b, 0x83, 0xa7, 0x59, 0xc3, 0xd2, 0xfa, 0x77, 0x10, -0x7f, 0x3e, 0x3a, 0xe1, 0xd5, 0x86, 0x6b, 0x39, 0xc9, 0x35, 0xe7, 0x4a, 0xda, 0x72, 0xe8, 0xb6, -0xe3, 0xa0, 0xca, 0x7e, 0xe2, 0xb3, 0xd1, 0xe4, 0x1c, 0x1d, 0x61, 0xaf, 0x90, 0x67, 0x8f, 0x4e, -0xf3, 0xe1, 0x16, 0xcc, 0xc9, 0x6f, 0x5f, 0x86, 0x97, 0x30, 0xd1, 0xe6, 0xde, 0xd6, 0x2b, 0x9a, -0xed, 0xc3, 0xf1, 0x27, 0xeb, 0xeb, 0x88, 0x27, 0xfb, 0x5e, 0x47, 0xb4, 0x86, 0xf6, 0x96, 0xa3, -0xf0, 0x22, 0x34, 0xb5, 0xf4, 0x31, 0xbb, 0x0e, 0xcc, 0xcb, 0x53, 0xf1, 0x57, 0x74, 0xe1, 0x56, -0x8f, 0x98, 0x2d, 0x96, 0xbf, 0x7d, 0x4c, 0xbf, 0xe7, 0x8a, 0xe2, 0x04, 0xbd, 0x65, 0xca, 0x5d, -0x8e, 0xa0, 0x38, 0x1e, 0xc0, 0xb3, 0x25, 0xbc, 0xae, 0xc8, 0x1a, 0xfe, 0xb6, 0x95, 0x26, 0xfd, -0x99, 0xb5, 0x68, 0xb3, 0xf8, 0x73, 0x40, 0x2b, 0x98, 0x0d, 0x81, 0xb4, 0x94, 0x27, 0x4b, 0x50, -0xa0, 0x5c, 0x7a, 0xd0, 0x06, 0x43, 0x74, 0x63, 0xc9, 0x82, 0x46, 0xae, 0x93, 0x99, 0xb2, 0xd3, -0xdd, 0x55, 0x8c, 0xac, 0x6f, 0xfb, 0x4c, 0x35, 0x65, 0x9f, 0x58, 0xde, 0xa7, 0x94, 0xb7, 0xd9, -0x31, 0xf7, 0x36, 0x2e, 0x5c, 0xc1, 0xe7, 0xa4, 0xaa, 0x5c, 0xbb, 0xe6, 0xee, 0x0d, 0x83, 0x60, -0xdf, 0x4a, 0x17, 0xf7, 0x5d, 0x6f, 0x73, 0xaf, 0xbf, 0xf8, 0xb3, 0x4d, 0x77, 0xb3, 0xf9, 0xad, -0xc3, 0x3b, 0xe8, 0xc3, 0x56, 0x58, 0x50, 0xe0, 0x13, 0x5e, 0x7b, 0x2a, 0x8e, 0xb8, 0x76, 0x9f, -0x78, 0x4f, 0x1a, 0x50, 0x24, 0x4c, 0xa7, 0x89, 0x20, 0x2e, 0xfd, 0xd0, 0xff, 0x48, 0x06, 0x03, -0x72, 0xf2, 0x14, 0x3a, 0x42, 0x7c, 0x3c, 0x36, 0x8f, 0xc7, 0x67, 0xf8, 0x48, 0x3f, 0x9c, 0x7c, -0x3c, 0xa0, 0xe2, 0xc9, 0x79, 0xb6, 0x79, 0xc7, 0xfa, 0xfa, 0xd3, 0x98, 0x45, 0x56, 0x3d, 0xe7, -0xa7, 0xe4, 0x78, 0x84, 0x71, 0xb6, 0xf3, 0x7e, 0xab, 0xed, 0x46, 0x71, 0x0b, 0xd9, 0x7e, 0x0b, -0xd7, 0x3f, 0x88, 0xce, 0x9e, 0xb2, 0x1f, 0x23, 0x0f, 0xfc, 0xec, 0x67, 0xe3, 0xff, 0x03, 0x2a, -0x4c, 0xb5, 0xf1, 0x4e, 0x2e, 0x00, 0x00}; -#endif /*__INDEX_HTML_H__*/ diff --git a/src/web/html/h/login_html.h b/src/web/html/h/login_html.h deleted file mode 100644 index 37b1bccb..00000000 --- a/src/web/html/h/login_html.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef __LOGIN_HTML_H__ -#define __LOGIN_HTML_H__ -#define login_html_len 665 -const uint8_t login_html[] PROGMEM = { -0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0x95, 0x55, 0xcb, 0x6e, 0xdb, 0x30, -0x10, 0xbc, 0xf7, 0x2b, 0x58, 0x1e, 0x7a, 0x8a, 0x44, 0x47, 0x49, 0x9b, 0xc0, 0x90, 0x54, 0xe4, -0xd1, 0x17, 0x50, 0xf4, 0x92, 0x04, 0x45, 0x4e, 0x01, 0x45, 0xd1, 0x12, 0x13, 0x8a, 0x24, 0x48, -0xca, 0x8e, 0xfb, 0xf5, 0x5d, 0xbd, 0x6a, 0x59, 0x8e, 0xeb, 0xc4, 0x17, 0x89, 0xe4, 0xec, 0xec, -0xee, 0xcc, 0x52, 0x8e, 0xdf, 0xe7, 0x9a, 0xf9, 0xb5, 0xe1, 0xa8, 0xf4, 0x95, 0x4c, 0xdf, 0xc5, -0xdd, 0x03, 0xc1, 0x2f, 0x2e, 0x39, 0xcd, 0xbb, 0xd7, 0x76, 0xe9, 0x85, 0x97, 0x3c, 0xfd, 0xa9, -0x0b, 0xa1, 0x62, 0xd2, 0x2d, 0x36, 0x87, 0x52, 0xa8, 0x27, 0x64, 0xb9, 0x4c, 0xb0, 0xf3, 0x6b, -0xc9, 0x5d, 0xc9, 0xb9, 0xc7, 0xa8, 0x21, 0x4e, 0xb0, 0xe7, 0xcf, 0x9e, 0x30, 0xe7, 0x30, 0x2a, -0x2d, 0x5f, 0xf4, 0x88, 0x10, 0x36, 0x3e, 0x2f, 0x93, 0x59, 0x78, 0x1e, 0xce, 0x66, 0xb3, 0x63, -0x4c, 0x20, 0x77, 0xc5, 0x3d, 0x45, 0x8a, 0x56, 0x10, 0xb3, 0x14, 0x7c, 0x65, 0xb4, 0x05, 0x0e, -0xa6, 0x95, 0xe7, 0xca, 0x27, 0x78, 0x25, 0x72, 0x5f, 0x26, 0x39, 0x5f, 0x0a, 0xc6, 0x83, 0x76, -0x71, 0x84, 0x84, 0x12, 0x5e, 0x50, 0x19, 0x38, 0x46, 0x25, 0x4f, 0x8e, 0xf1, 0x40, 0xc2, 0x4a, -0x6a, 0x1d, 0x87, 0xa0, 0xbb, 0xdb, 0xaf, 0xc1, 0x79, 0xb3, 0xed, 0x98, 0x15, 0xc6, 0x8f, 0x2b, -0x7a, 0xa4, 0x4b, 0xda, 0xed, 0x62, 0xe4, 0x2c, 0x4b, 0x30, 0x35, 0x22, 0x7c, 0xdc, 0x2a, 0x2a, -0x8d, 0x49, 0x87, 0x00, 0x82, 0xb7, 0x74, 0xc8, 0xb4, 0xd4, 0xd6, 0x1d, 0x68, 0xd1, 0xea, 0x4c, -0x7b, 0x37, 0x6a, 0x50, 0x69, 0xa1, 0x72, 0xfe, 0x7c, 0x84, 0x94, 0x5e, 0x68, 0x29, 0xf5, 0x0a, -0x23, 0xd2, 0x5b, 0x41, 0x36, 0x5e, 0xc4, 0x99, 0xce, 0xd7, 0x23, 0xe5, 0x73, 0xb1, 0x44, 0x22, -0x07, 0x79, 0x2c, 0x35, 0x86, 0x5b, 0xbc, 0x39, 0xda, 0x3a, 0x96, 0x8d, 0x6f, 0x93, 0xc3, 0x7f, -0x00, 0x26, 0xa9, 0x73, 0x09, 0x36, 0xc1, 0xe9, 0x0b, 0x88, 0x16, 0xb5, 0xd0, 0xb6, 0x42, 0x94, -0x79, 0xa1, 0x55, 0x82, 0x49, 0x47, 0x86, 0xa0, 0x99, 0x52, 0x03, 0xb7, 0xd1, 0xce, 0xef, 0x09, -0x9c, 0xa6, 0xb0, 0xd0, 0x55, 0x1a, 0x97, 0x51, 0x7a, 0x51, 0xea, 0xf5, 0xf5, 0xed, 0x1d, 0x74, -0x16, 0x81, 0xca, 0x80, 0x78, 0x43, 0xfc, 0x5e, 0xe4, 0x14, 0x0d, 0x3e, 0x04, 0xc7, 0x11, 0x6a, -0x1e, 0xae, 0x0a, 0xce, 0x51, 0x95, 0x05, 0x27, 0x90, 0x5e, 0x28, 0x53, 0x0f, 0xa3, 0x60, 0x00, -0xb8, 0xd2, 0x36, 0xc7, 0xbd, 0x2b, 0x66, 0x05, 0xaf, 0xb4, 0xf6, 0x60, 0x01, 0xab, 0xdd, 0xa1, -0xd2, 0xfe, 0x9f, 0xf0, 0x74, 0x92, 0xcb, 0xd5, 0x59, 0x25, 0xfc, 0x90, 0xa9, 0x17, 0x71, 0x49, -0x65, 0xbd, 0x59, 0xf5, 0x3c, 0x99, 0x57, 0xf8, 0xa0, 0x2c, 0xfb, 0x8f, 0x63, 0xd2, 0xf8, 0xf5, -0x82, 0xd9, 0xbb, 0x21, 0x93, 0xad, 0xe9, 0x72, 0x18, 0x9f, 0x85, 0xd6, 0x7e, 0x6b, 0xb8, 0xc6, -0x5d, 0x4b, 0xbe, 0x18, 0xfb, 0x1f, 0xd3, 0xfe, 0x1a, 0x94, 0xde, 0x1b, 0x37, 0x27, 0x84, 0x82, -0xd7, 0xb9, 0xaf, 0xc3, 0x9c, 0xc3, 0x85, 0xa1, 0xb6, 0x68, 0x2e, 0xe6, 0x43, 0x26, 0xa9, 0x7a, -0xc2, 0xc3, 0x1c, 0xa0, 0x0f, 0x4c, 0x9b, 0x35, 0x8a, 0x66, 0xd1, 0x49, 0x4c, 0xe8, 0x88, 0xab, -0x96, 0x93, 0x7a, 0xa5, 0x48, 0x77, 0x12, 0xe4, 0xc2, 0x31, 0xf0, 0x30, 0x2c, 0x0a, 0xf2, 0xfb, -0x4f, 0xf9, 0xfc, 0xe5, 0xfe, 0x53, 0x54, 0x5d, 0xee, 0xe6, 0xba, 0xee, 0x60, 0x4d, 0x82, 0x98, -0x00, 0xcf, 0x61, 0xe2, 0x42, 0xf8, 0xb2, 0xce, 0x42, 0xa6, 0x2b, 0x22, 0xeb, 0x8a, 0x9a, 0xba, -0xed, 0x65, 0x97, 0xf9, 0x5b, 0x8b, 0xdb, 0x25, 0x8e, 0xc9, 0x50, 0xff, 0x48, 0xd8, 0xad, 0x79, -0x16, 0x45, 0xb9, 0xa5, 0xdd, 0x9e, 0x7e, 0x27, 0x09, 0x5f, 0x55, 0x26, 0x81, 0x35, 0xcc, 0x9b, -0x23, 0xd9, 0xe2, 0xec, 0x2c, 0x3a, 0xfb, 0x08, 0x65, 0xfe, 0xb8, 0x45, 0x37, 0xdf, 0x2f, 0xe6, -0xa8, 0xdf, 0x41, 0xf3, 0x39, 0x1a, 0x3e, 0x4f, 0x7b, 0x55, 0x69, 0xfd, 0xe7, 0xce, 0x3c, 0x34, -0x43, 0x8c, 0x5f, 0xab, 0x1c, 0xb3, 0x9c, 0x7a, 0xb1, 0xe4, 0x4d, 0x0d, 0x5a, 0xb9, 0x50, 0xdb, -0x02, 0x02, 0x19, 0x57, 0x8e, 0x43, 0x41, 0xeb, 0x40, 0xb1, 0xc0, 0x51, 0x72, 0x1a, 0xce, 0x48, -0xce, 0x79, 0xbe, 0xa3, 0x28, 0x4a, 0xaf, 0xae, 0xd0, 0xe5, 0x7d, 0xf0, 0xeb, 0x2a, 0xb8, 0xb9, -0x40, 0x00, 0x7b, 0x85, 0xb6, 0x63, 0x89, 0x49, 0xf7, 0x95, 0x84, 0xcf, 0x4b, 0xfb, 0x7f, 0xf6, -0x17, 0x29, 0x0f, 0xde, 0x34, 0xe7, 0x06, 0x00, 0x00}; -#endif /*__LOGIN_HTML_H__*/ diff --git a/src/web/html/h/save_html.h b/src/web/html/h/save_html.h deleted file mode 100644 index e2853924..00000000 --- a/src/web/html/h/save_html.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef __SAVE_HTML_H__ -#define __SAVE_HTML_H__ -#define save_html_len 1286 -const uint8_t save_html[] PROGMEM = { -0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0xad, 0x57, 0x5b, 0x4f, 0x1b, 0x39, -0x14, 0x7e, 0xef, 0xaf, 0x70, 0xfd, 0xb0, 0x04, 0x2d, 0x99, 0x19, 0x92, 0x52, 0x58, 0x72, 0x59, -0x05, 0x4a, 0x0b, 0x12, 0x8b, 0x2a, 0x02, 0xaa, 0xaa, 0xaa, 0xaa, 0x1c, 0xdb, 0xc9, 0x18, 0x1c, -0x7b, 0x3a, 0xf6, 0x04, 0xb2, 0x2b, 0xfe, 0xfb, 0x1e, 0xcf, 0x25, 0x99, 0x49, 0x32, 0x01, 0xb6, -0x3b, 0x2f, 0x89, 0xed, 0x73, 0xf9, 0xbe, 0xe3, 0x73, 0x8e, 0xed, 0xee, 0x5b, 0xa6, 0xa9, 0x9d, -0x47, 0x1c, 0x85, 0x76, 0x2a, 0xfb, 0x6f, 0xba, 0xd9, 0x0f, 0x82, 0xaf, 0x1b, 0x72, 0xc2, 0xb2, -0xbf, 0xe9, 0xd0, 0x0a, 0x2b, 0x79, 0x7f, 0x48, 0x66, 0xbc, 0xeb, 0x67, 0xff, 0x97, 0x6b, 0x52, -0xa8, 0x7b, 0x14, 0x73, 0xd9, 0xc3, 0xc6, 0xce, 0x25, 0x37, 0x21, 0xe7, 0x16, 0x23, 0x67, 0xb7, -0x87, 0x2d, 0x7f, 0xb4, 0x3e, 0x35, 0x06, 0xa3, 0x30, 0xe6, 0xe3, 0x5c, 0xc2, 0x83, 0x89, 0x3f, -0x67, 0xbd, 0xc0, 0x3b, 0xf2, 0x82, 0x20, 0xd8, 0xc7, 0x3e, 0xb8, 0x9e, 0x72, 0x4b, 0x90, 0x22, -0x53, 0xd0, 0x99, 0x09, 0xfe, 0x10, 0xe9, 0x18, 0x6c, 0x50, 0xad, 0x2c, 0x57, 0xb6, 0x87, 0x1f, -0x04, 0xb3, 0x61, 0x8f, 0xf1, 0x99, 0xa0, 0xbc, 0x99, 0x0e, 0xf6, 0x90, 0x50, 0xc2, 0x0a, 0x22, -0x9b, 0x86, 0x12, 0xc9, 0x7b, 0xfb, 0xb8, 0x30, 0x42, 0x43, 0x12, 0x1b, 0x0e, 0x4a, 0xb7, 0x37, -0x1f, 0x9b, 0x47, 0x6e, 0xda, 0xd0, 0x58, 0x44, 0xb6, 0x8c, 0xe8, 0x8e, 0xcc, 0x48, 0x36, 0x8b, -0x91, 0x89, 0x69, 0x0f, 0x93, 0x48, 0x78, 0x77, 0x15, 0x50, 0xfd, 0xae, 0x9f, 0x49, 0x80, 0x81, -0xd7, 0x30, 0xa4, 0x5a, 0xea, 0xd8, 0x3c, 0x43, 0x31, 0xd6, 0x23, 0x6d, 0x4d, 0x89, 0xa0, 0xd2, -0x42, 0x31, 0xfe, 0xb8, 0x87, 0x94, 0x1e, 0x6b, 0x29, 0xf5, 0x03, 0x46, 0x7e, 0xbe, 0x13, 0xfe, -0x72, 0x2b, 0xba, 0x23, 0xcd, 0xe6, 0xa5, 0xc8, 0x33, 0x31, 0x43, 0x54, 0x12, 0x63, 0x00, 0x86, -0x8e, 0x14, 0x99, 0xe1, 0x5c, 0x8e, 0xe4, 0x60, 0xfc, 0x32, 0x86, 0x85, 0xa8, 0xdb, 0x3f, 0xdc, -0x1f, 0x84, 0x7a, 0xfe, 0xe1, 0xe6, 0xb6, 0xeb, 0x93, 0x15, 0xa5, 0x65, 0x70, 0x8e, 0x67, 0x5a, -0xb0, 0x46, 0xb0, 0xdb, 0x59, 0xe8, 0x0a, 0x40, 0x8c, 0x91, 0x56, 0x54, 0x0a, 0x7a, 0x5f, 0x78, -0x6d, 0xec, 0xe2, 0x12, 0x28, 0x13, 0x11, 0xe5, 0x82, 0xe7, 0x7e, 0x5e, 0x3d, 0xbb, 0x44, 0xe3, -0xb8, 0x09, 0xb6, 0x20, 0x56, 0x00, 0x98, 0xea, 0x91, 0x70, 0xe8, 0x97, 0x36, 0x48, 0x2a, 0x06, -0x32, 0xed, 0x85, 0x50, 0x28, 0x18, 0x2f, 0xf6, 0xc3, 0x97, 0x62, 0xc6, 0x2b, 0x1b, 0x7b, 0x29, -0x5c, 0x16, 0x93, 0x4d, 0x26, 0xde, 0x6d, 0x36, 0x61, 0x78, 0x0c, 0x99, 0x56, 0x31, 0xf2, 0x85, -0x8f, 0xb2, 0xd9, 0x1a, 0x4b, 0x07, 0x75, 0x96, 0x6c, 0x12, 0x55, 0x0c, 0x0d, 0xb9, 0xb5, 0x42, -0x4d, 0x4c, 0xd5, 0x8e, 0x8b, 0x48, 0x61, 0xc0, 0xf0, 0x88, 0xc7, 0xc4, 0xea, 0x18, 0xaf, 0x07, -0x70, 0xe1, 0xef, 0xfd, 0x66, 0x7f, 0x49, 0xc4, 0x88, 0xad, 0xd2, 0xbf, 0x4d, 0xa7, 0x6a, 0x60, -0x1f, 0xd6, 0xc0, 0x9e, 0x1b, 0xcb, 0xa7, 0x55, 0xdc, 0xe9, 0xd4, 0x2f, 0xa2, 0x3e, 0x5a, 0x78, -0x80, 0x02, 0x84, 0x8a, 0x22, 0xf1, 0xc4, 0x55, 0xee, 0x8f, 0x91, 0x24, 0xea, 0x1e, 0xf7, 0xaf, -0xcf, 0x86, 0x37, 0x68, 0xf0, 0xf9, 0xa2, 0x06, 0xec, 0x1f, 0x85, 0x76, 0x68, 0x6d, 0x64, 0x8e, -0x7d, 0x9f, 0x40, 0x4a, 0x33, 0x9b, 0x78, 0x0e, 0xf9, 0xaa, 0xad, 0x0f, 0x9a, 0x26, 0x53, 0xa8, -0x35, 0x62, 0x85, 0x56, 0x35, 0x06, 0xf7, 0x83, 0x25, 0x9e, 0x91, 0x4e, 0x6c, 0x85, 0xf0, 0xc0, -0xcd, 0xfc, 0x22, 0xdf, 0xa0, 0x26, 0x45, 0xf5, 0x44, 0x28, 0x48, 0x4c, 0xf7, 0x53, 0x07, 0xad, -0x56, 0x13, 0x50, 0xa5, 0xaa, 0x65, 0x74, 0x5d, 0x1f, 0xca, 0x67, 0xa5, 0x90, 0x1e, 0xc4, 0x58, -0x64, 0xe5, 0x5b, 0xd4, 0xb2, 0x1a, 0x6b, 0x07, 0x36, 0x15, 0x2d, 0x69, 0x54, 0xb5, 0x62, 0x12, -0x01, 0xb1, 0x52, 0xc1, 0x55, 0x96, 0xf3, 0x06, 0xb6, 0xb2, 0x5c, 0x11, 0x71, 0x87, 0xca, 0xb2, -0x7c, 0x6d, 0xb3, 0x8d, 0xa6, 0xa3, 0x66, 0x1b, 0xbb, 0xc3, 0x04, 0xf2, 0x1e, 0x99, 0x3c, 0xff, -0x3d, 0xcf, 0x5b, 0xc1, 0xb0, 0x42, 0x64, 0xd3, 0xb0, 0xf0, 0x31, 0xd6, 0xda, 0x56, 0x40, 0x96, -0x5b, 0xa3, 0xe4, 0x63, 0x5b, 0x6d, 0x18, 0x2f, 0xcf, 0x9a, 0xbc, 0x49, 0xa2, 0xdf, 0xa8, 0x8e, -0xe6, 0xa8, 0x15, 0xb4, 0xda, 0xd5, 0xfd, 0x49, 0xe4, 0x0a, 0x5e, 0x29, 0xfa, 0x6b, 0x0e, 0x98, -0x30, 0x54, 0xc7, 0xcc, 0x9b, 0x4c, 0xfc, 0x2f, 0x7f, 0x87, 0x8f, 0x67, 0x5f, 0xdf, 0xb7, 0xa6, -0x27, 0x1b, 0x32, 0x34, 0x13, 0x73, 0x0e, 0xba, 0xd0, 0xb5, 0x5e, 0x60, 0x78, 0x22, 0x6c, 0x98, -0x8c, 0x3c, 0xaa, 0xa7, 0xbe, 0x4c, 0xa6, 0x24, 0x4a, 0x52, 0x2e, 0xeb, 0x96, 0x3f, 0xa5, 0x72, -0xeb, 0x86, 0xbb, 0x7e, 0x81, 0x7f, 0x35, 0x61, 0xf2, 0xd0, 0xc5, 0x62, 0x12, 0x56, 0x62, 0x57, -0xc3, 0x77, 0xc5, 0xe1, 0x8b, 0x60, 0xfa, 0x30, 0x9e, 0x0a, 0x6b, 0xfc, 0xd1, 0xf8, 0xf0, 0xb0, -0x75, 0x78, 0x00, 0x30, 0x2f, 0x6e, 0xd0, 0xf0, 0x7c, 0x70, 0x8c, 0xf2, 0x19, 0x74, 0x7c, 0x8c, -0x8a, 0xfa, 0xab, 0x8d, 0x4a, 0xba, 0xff, 0xdc, 0x44, 0x3f, 0xdc, 0x71, 0x8c, 0x5f, 0x1a, 0x39, -0x1a, 0x73, 0x68, 0x04, 0x33, 0xee, 0x30, 0x68, 0x65, 0x3c, 0x1d, 0x4f, 0x40, 0x91, 0x72, 0x65, -0x38, 0x00, 0x9a, 0x37, 0x15, 0x6d, 0x1a, 0xe2, 0xbf, 0xf3, 0x02, 0x9f, 0x71, 0xce, 0xd6, 0x22, -0x8a, 0xfa, 0xa7, 0xa7, 0xe8, 0xe4, 0x6b, 0xf3, 0xea, 0xb4, 0x39, 0x1c, 0x20, 0x10, 0x7b, 0x41, -0x6c, 0x57, 0x73, 0x77, 0xeb, 0xad, 0xa4, 0x4a, 0x61, 0x46, 0x62, 0xb8, 0xee, 0x40, 0x86, 0xcf, -0x88, 0xbc, 0x60, 0xa8, 0x87, 0x54, 0x22, 0x65, 0xe7, 0x4d, 0x45, 0x66, 0x9c, 0x28, 0xea, 0x5a, -0x1b, 0x8a, 0xdc, 0xf5, 0xe7, 0x13, 0x57, 0x70, 0x3a, 0xd1, 0x86, 0x1e, 0xdd, 0xed, 0xa2, 0x7f, -0xd6, 0x8a, 0x33, 0x95, 0xb9, 0x82, 0x93, 0xdb, 0xad, 0x77, 0x36, 0x2f, 0x9f, 0x0d, 0x3f, 0x6f, -0x5b, 0xbe, 0x36, 0x46, 0x6c, 0x58, 0x7f, 0xda, 0x86, 0xea, 0x1c, 0x5a, 0x41, 0x1d, 0x24, 0xc7, -0xd1, 0xb5, 0x0a, 0x60, 0x87, 0xf1, 0xba, 0x4f, 0x31, 0x6e, 0xbc, 0x05, 0x4d, 0x2f, 0xe2, 0x8a, -0x41, 0xbb, 0xd8, 0x64, 0x21, 0x17, 0x2b, 0x05, 0xea, 0x6d, 0x16, 0xa9, 0x3a, 0x61, 0xf7, 0x51, -0xc9, 0x49, 0x7c, 0x91, 0xab, 0x94, 0x74, 0x37, 0xd0, 0xce, 0xe8, 0xd5, 0x78, 0x75, 0xd8, 0x4c, -0x42, 0x29, 0x37, 0x66, 0x9b, 0x3b, 0xc7, 0x32, 0xbd, 0x07, 0xf6, 0x10, 0xcb, 0x0f, 0x24, 0x2f, -0xcd, 0x45, 0x7e, 0x26, 0xb9, 0x1b, 0x35, 0x76, 0xdc, 0xf2, 0x4e, 0x8d, 0x7b, 0xf7, 0xb9, 0x75, -0xcf, 0xe5, 0xf1, 0xd9, 0xcf, 0x04, 0x2a, 0x15, 0xc2, 0x05, 0x99, 0x1d, 0xc3, 0xa5, 0x14, 0xd7, -0xaa, 0x14, 0xc1, 0x8b, 0xf9, 0x08, 0x1a, 0xe5, 0x36, 0x7c, 0xee, 0x2b, 0x76, 0xa1, 0xb8, 0x99, -0xa0, 0x9c, 0xd7, 0x18, 0x42, 0x39, 0x47, 0x06, 0xde, 0x00, 0xcc, 0x43, 0x83, 0xc4, 0xea, 0x29, -0x94, 0x10, 0x85, 0x9d, 0x9d, 0x70, 0x77, 0x39, 0xd6, 0x84, 0x41, 0x92, 0xa2, 0x36, 0x74, 0x74, -0x38, 0x15, 0x98, 0xf1, 0x70, 0x67, 0xab, 0x9b, 0x94, 0x47, 0x7e, 0x7e, 0x80, 0xbb, 0x76, 0xbd, -0xf4, 0x13, 0xe2, 0xd2, 0xf0, 0xff, 0x03, 0xf5, 0x75, 0x1a, 0x00, 0x58, 0x2e, 0x13, 0x88, 0x39, -0x13, 0x31, 0xa7, 0xd6, 0xa1, 0x6f, 0x05, 0xff, 0x11, 0x3e, 0x28, 0xfe, 0x8e, 0x70, 0x07, 0xdd, -0x5e, 0x5f, 0xf6, 0xfc, 0x2d, 0xaa, 0x4f, 0xb5, 0x2b, 0x8b, 0x7c, 0x80, 0x46, 0x93, 0x27, 0x83, -0x39, 0x99, 0xdf, 0x90, 0xc9, 0x15, 0x3c, 0x19, 0x1a, 0x3b, 0xee, 0x15, 0xb0, 0xb3, 0xfb, 0x2d, -0xf8, 0xee, 0xb9, 0x03, 0x59, 0xb1, 0xd3, 0x50, 0x48, 0xd6, 0x70, 0x28, 0xea, 0x52, 0xf5, 0xb9, -0xa8, 0x15, 0x11, 0xfb, 0x48, 0xe0, 0x46, 0xcd, 0x5c, 0x88, 0x2a, 0xe7, 0x31, 0x7e, 0x69, 0x05, -0xac, 0xcf, 0x6c, 0xa0, 0x72, 0x32, 0xbf, 0x60, 0x8d, 0xec, 0x2e, 0xb0, 0xeb, 0x09, 0x05, 0xdd, -0xe9, 0xfc, 0xe6, 0xaf, 0x4b, 0x70, 0xef, 0xa6, 0x5e, 0xd1, 0x42, 0xea, 0xda, 0x07, 0xa4, 0xb8, -0x2b, 0x75, 0x57, 0xf2, 0x35, 0x12, 0x8b, 0xce, 0x55, 0xea, 0x8d, 0xdf, 0xf0, 0x24, 0x1b, 0xe0, -0xef, 0x35, 0x51, 0xac, 0xf6, 0xad, 0xce, 0x33, 0xe4, 0x57, 0xa0, 0x57, 0x7a, 0x36, 0x7a, 0x80, -0x27, 0x9e, 0x7e, 0xf0, 0x20, 0xc0, 0x8b, 0x7e, 0x03, 0xee, 0xed, 0xe0, 0x8e, 0x3c, 0x36, 0x76, -0xdc, 0x05, 0xd8, 0x77, 0xb1, 0xf0, 0x5d, 0xaa, 0xee, 0xec, 0x65, 0x8e, 0x77, 0xf1, 0x1e, 0x6a, -0x1d, 0x04, 0xc1, 0x8a, 0xe3, 0x42, 0x2b, 0xbd, 0x36, 0xfb, 0x05, 0x85, 0xbd, 0x0a, 0xbd, 0x92, -0xca, 0xf2, 0x25, 0x9b, 0x8d, 0xb2, 0x57, 0x64, 0xd7, 0xcf, 0x9e, 0xfb, 0xff, 0x02, 0xcf, 0x43, -0x5b, 0x09, 0x06, 0x10, 0x00, 0x00}; -#endif /*__SAVE_HTML_H__*/ diff --git a/src/web/html/h/serial_html.h b/src/web/html/h/serial_html.h deleted file mode 100644 index 2d3ab07f..00000000 --- a/src/web/html/h/serial_html.h +++ /dev/null @@ -1,113 +0,0 @@ -#ifndef __SERIAL_HTML_H__ -#define __SERIAL_HTML_H__ -#define serial_html_len 1724 -const uint8_t serial_html[] PROGMEM = { -0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0xa5, 0x58, 0x5b, 0x53, 0xdb, 0x38, -0x14, 0x7e, 0xe7, 0x57, 0x08, 0xef, 0x74, 0x49, 0x16, 0x62, 0x9b, 0x3b, 0x1b, 0x92, 0x74, 0x28, -0xb0, 0x2d, 0x3b, 0x2c, 0x30, 0x4d, 0x98, 0x4e, 0x67, 0xd9, 0x61, 0x14, 0x59, 0x49, 0x04, 0xb6, -0xe4, 0x91, 0xe4, 0x40, 0xba, 0xd3, 0xff, 0xbe, 0x47, 0xbe, 0x24, 0xbe, 0xb2, 0x94, 0xe6, 0x25, -0x96, 0x7c, 0xce, 0xd1, 0x77, 0x6e, 0x9f, 0x24, 0xf7, 0xd6, 0x3d, 0x41, 0xf4, 0x22, 0xa4, 0x68, -0xa6, 0x03, 0x7f, 0xb0, 0xd6, 0x33, 0x7f, 0xc8, 0xc7, 0x7c, 0xda, 0xb7, 0x28, 0xb7, 0x06, 0x6b, -0x08, 0x7e, 0xbd, 0x19, 0xc5, 0x5e, 0xf2, 0x18, 0x0f, 0x35, 0xd3, 0x3e, 0x1d, 0x0c, 0xa9, 0x64, -0xd8, 0x47, 0xa7, 0x82, 0x2b, 0xe1, 0xd3, 0x9e, 0x93, 0xcc, 0xae, 0xa4, 0x7c, 0xc6, 0x1f, 0x91, -0xa4, 0x7e, 0xdf, 0x52, 0x7a, 0xe1, 0x53, 0x35, 0xa3, 0x54, 0x5b, 0xc8, 0xac, 0xd5, 0xb7, 0x34, -0x7d, 0xd6, 0x0e, 0x51, 0xca, 0x42, 0x33, 0x49, 0x27, 0xa9, 0x84, 0x0d, 0x13, 0xef, 0xe7, 0x7d, -0xd7, 0x3e, 0xb2, 0x5d, 0xd7, 0xdd, 0xb6, 0x1c, 0x80, 0x13, 0x50, 0x8d, 0x11, 0xc7, 0x01, 0xe8, -0xcc, 0x19, 0x7d, 0x0a, 0x85, 0x04, 0x1b, 0x44, 0x70, 0x4d, 0xb9, 0xee, 0x5b, 0x4f, 0xcc, 0xd3, -0xb3, 0xbe, 0x47, 0xe7, 0x8c, 0xd0, 0x4e, 0x3c, 0xd8, 0x42, 0x8c, 0x33, 0x0d, 0xb8, 0x3a, 0x8a, -0x60, 0x9f, 0xf6, 0xb7, 0xad, 0xcc, 0x08, 0x99, 0x61, 0xa9, 0x28, 0x28, 0xdd, 0x8e, 0xfe, 0xe8, -0x1c, 0x99, 0x69, 0x45, 0x24, 0x0b, 0x75, 0x1e, 0xd1, 0x03, 0x9e, 0xe3, 0x64, 0xd6, 0x42, 0x4a, -0x92, 0xbe, 0x85, 0x43, 0x66, 0x3f, 0x14, 0x40, 0x0d, 0x7a, 0x4e, 0x22, 0x01, 0x06, 0x7e, 0xc4, -0x43, 0x22, 0x7c, 0x21, 0xd5, 0xff, 0xb8, 0x28, 0xc5, 0x58, 0x68, 0x95, 0x73, 0x90, 0x0b, 0xc6, -0x3d, 0xfa, 0xbc, 0x85, 0xb8, 0x98, 0x08, 0xdf, 0x17, 0x4f, 0x16, 0x72, 0xd2, 0x9c, 0x38, 0xab, -0xa4, 0xf4, 0xc6, 0xc2, 0x5b, 0xe4, 0x22, 0xef, 0xb1, 0x39, 0x22, 0x3e, 0x56, 0x0a, 0x60, 0x88, -0x90, 0xe3, 0x79, 0x96, 0x47, 0x9c, 0x82, 0x71, 0xf2, 0x18, 0x96, 0xa2, 0x26, 0x7f, 0xd6, 0xe0, -0x64, 0x26, 0x16, 0x67, 0xa3, 0xdb, 0x9e, 0x83, 0x4b, 0x4a, 0xab, 0xe0, 0x74, 0xe7, 0x82, 0x79, -0x2d, 0xb7, 0x7d, 0xbc, 0xd4, 0x65, 0x80, 0xd8, 0x42, 0x82, 0x13, 0x9f, 0x91, 0xc7, 0x6c, 0xd5, -0x56, 0xdb, 0xca, 0x81, 0x52, 0x21, 0xe6, 0x26, 0x78, 0xe6, 0xef, 0x87, 0x67, 0x57, 0x68, 0x8c, -0x6f, 0xcc, 0x5b, 0x3a, 0x96, 0x01, 0x08, 0xc4, 0x98, 0x19, 0xf4, 0x2b, 0x1b, 0x38, 0x16, 0x03, -0x99, 0xdd, 0xa5, 0xd0, 0x8c, 0x79, 0x34, 0xcb, 0x87, 0xe3, 0xb3, 0x39, 0x2d, 0x24, 0xf6, 0x12, -0x26, 0x96, 0xeb, 0x14, 0x4d, 0xec, 0xd5, 0x9b, 0x50, 0x71, 0x07, 0x14, 0x8c, 0x7c, 0xa1, 0xe3, -0x64, 0xb6, 0xc1, 0xd2, 0x7e, 0x93, 0x25, 0x1d, 0x85, 0x05, 0x43, 0x43, 0xaa, 0x35, 0xe3, 0x53, -0x55, 0xb4, 0x63, 0x22, 0x92, 0x19, 0x50, 0x34, 0xa4, 0x12, 0x6b, 0x21, 0xad, 0x6a, 0x00, 0x97, -0xeb, 0x1d, 0xd4, 0xaf, 0x17, 0x85, 0x1e, 0xd6, 0x45, 0xf7, 0x6f, 0xe3, 0xa9, 0x06, 0xd8, 0x87, -0x0d, 0xb0, 0x17, 0x4a, 0xd3, 0xa0, 0x88, 0x3b, 0x9e, 0xfa, 0x49, 0xd4, 0x47, 0xcb, 0x15, 0xa0, -0x01, 0xa1, 0xa3, 0xb0, 0x9c, 0x9a, 0xce, 0xbd, 0x1f, 0x03, 0x31, 0x3d, 0x5a, 0x83, 0xcf, 0xe7, -0xc3, 0x11, 0x3a, 0xb9, 0xb9, 0x68, 0x00, 0xfb, 0x7b, 0xa6, 0x3d, 0xd3, 0x3a, 0x54, 0x5d, 0xc7, -0xc1, 0x50, 0xd2, 0x9e, 0x8e, 0x6c, 0x83, 0xbc, 0x6c, 0xeb, 0x4c, 0x90, 0x28, 0x80, 0x5e, 0xc3, -0x9a, 0x09, 0xde, 0x60, 0x70, 0xdb, 0x5d, 0xe1, 0x19, 0x8b, 0x48, 0x17, 0x1c, 0x3e, 0x31, 0x33, -0x3f, 0xe9, 0xaf, 0xdb, 0x50, 0xa2, 0x62, 0xca, 0x80, 0x83, 0x2f, 0xcd, 0x5f, 0x13, 0xb4, 0x46, -0x4d, 0x40, 0x15, 0xab, 0xe6, 0xd1, 0xf5, 0x1c, 0x68, 0x9f, 0x52, 0x23, 0x3d, 0xb1, 0x09, 0x4b, -0xda, 0x37, 0xeb, 0x65, 0x3e, 0x11, 0x06, 0x6c, 0x2c, 0x9a, 0xd3, 0x28, 0x6a, 0x49, 0x1c, 0x82, -0x63, 0xb9, 0x86, 0x2b, 0xbc, 0x4e, 0x09, 0x0c, 0x58, 0xd4, 0x10, 0x23, 0xb4, 0x27, 0x7e, 0x4e, -0xf8, 0xb9, 0x8b, 0xb6, 0x5d, 0xf7, 0x1d, 0x5a, 0x67, 0x81, 0xa1, 0x72, 0xcc, 0xf5, 0x71, 0xc9, -0x44, 0x99, 0xc0, 0x24, 0x70, 0x5e, 0x55, 0x22, 0xd9, 0x86, 0x80, 0x62, 0xb1, 0xa4, 0x49, 0x2c, -0x92, 0xae, 0x5b, 0xf1, 0x81, 0xee, 0x98, 0xbe, 0x17, 0x3e, 0x3c, 0x1f, 0x41, 0x78, 0xc1, 0x0c, -0x3c, 0xed, 0x99, 0x27, 0xa0, 0x4d, 0xc1, 0xfd, 0x05, 0x78, 0x98, 0x19, 0xa8, 0x41, 0x50, 0x74, -0xbb, 0x01, 0x18, 0x0a, 0x16, 0xb0, 0x4a, 0x03, 0xba, 0x9c, 0x28, 0xc0, 0x30, 0x72, 0x24, 0xd9, -0x29, 0x11, 0x26, 0x1a, 0xa8, 0xa6, 0x5b, 0xac, 0x13, 0x4f, 0x40, 0xb4, 0x8c, 0x23, 0xc9, 0xdb, -0x65, 0xb5, 0x34, 0x20, 0xa9, 0x5d, 0xc2, 0xf8, 0xdb, 0x51, 0x41, 0x67, 0x2f, 0x05, 0x76, 0x1b, -0x6a, 0x16, 0x2c, 0x17, 0x32, 0xc6, 0xa3, 0x78, 0xe6, 0x2d, 0xc6, 0x0f, 0x56, 0xc6, 0x71, 0x47, -0x36, 0x38, 0x1d, 0x2b, 0x32, 0x1e, 0x46, 0xd9, 0xae, 0x3a, 0x8e, 0xb4, 0x36, 0xa5, 0x35, 0xc7, -0x7e, 0x04, 0x43, 0xe2, 0x53, 0x2c, 0x97, 0x39, 0x1a, 0x6b, 0x9e, 0xb8, 0x9c, 0x4c, 0x3b, 0x6f, -0xb3, 0x89, 0x23, 0x2d, 0x60, 0x5b, 0x82, 0xdd, 0xb1, 0x6a, 0x38, 0x9d, 0x6f, 0xb0, 0xdc, 0x94, -0xe4, 0xea, 0x74, 0xb9, 0x0b, 0x1a, 0x9a, 0x62, 0x22, 0x84, 0x2e, 0xf4, 0x44, 0x3e, 0x88, 0x3e, -0x9d, 0xe8, 0xe2, 0xfe, 0xf4, 0x7a, 0x92, 0x4a, 0xf7, 0x64, 0xf4, 0x2b, 0x11, 0xe1, 0x02, 0xed, -0xb8, 0x3b, 0xbb, 0x45, 0x3a, 0x88, 0xfc, 0x12, 0x5e, 0x9f, 0x0d, 0x2a, 0x0b, 0x78, 0x4c, 0x11, -0x21, 0x3d, 0x7b, 0x3a, 0x75, 0xbe, 0x7c, 0x9b, 0x3d, 0x9f, 0x7f, 0x3d, 0xd8, 0x09, 0x3e, 0xd4, -0x10, 0x62, 0x22, 0x66, 0x16, 0xe8, 0xc1, 0x26, 0xf9, 0x0a, 0xc3, 0x53, 0xa6, 0x67, 0xd1, 0xd8, -0x26, 0x22, 0x70, 0xfc, 0x28, 0xc0, 0x61, 0x14, 0xfb, 0x52, 0xb5, 0xfc, 0x31, 0x96, 0xab, 0x1a, -0xee, 0x39, 0x19, 0xfe, 0x32, 0x3f, 0x65, 0xad, 0xc6, 0xa6, 0xb3, 0x42, 0xec, 0x1a, 0xfc, 0x2d, -0x2d, 0xf8, 0x2a, 0x98, 0x0e, 0x8c, 0x03, 0xa6, 0x95, 0x33, 0x9e, 0x1c, 0x1e, 0xee, 0x1c, 0xee, -0x03, 0xcc, 0x8b, 0x11, 0x1a, 0x7e, 0x3a, 0xe9, 0xa2, 0x74, 0x06, 0x75, 0xbb, 0x28, 0xa3, 0xfb, -0xc6, 0xa8, 0xc4, 0xf9, 0xa7, 0x2a, 0xbc, 0x37, 0x35, 0x6a, 0xbd, 0x36, 0x72, 0x04, 0xc8, 0xc7, -0x74, 0xbb, 0xc1, 0x00, 0xe4, 0x60, 0x0b, 0x39, 0x05, 0x45, 0x42, 0xb9, 0xa2, 0x00, 0x68, 0xd1, -0xe1, 0xa4, 0xa3, 0xb0, 0xb3, 0x67, 0xbb, 0x8e, 0x47, 0xa9, 0x57, 0x89, 0x28, 0x1a, 0x9c, 0x9e, -0xa2, 0x0f, 0x5f, 0x3b, 0x57, 0xa7, 0x9d, 0xe1, 0x09, 0x02, 0xb1, 0x57, 0xc4, 0xb6, 0x5c, 0xbb, -0x2f, 0x1e, 0x82, 0x8b, 0x2e, 0xcc, 0xb1, 0x44, 0xc1, 0x09, 0xb4, 0xdb, 0x30, 0x6e, 0x2b, 0xd4, -0x47, 0x5a, 0x46, 0xf4, 0xb8, 0x22, 0x03, 0x3c, 0x07, 0xef, 0xbc, 0x74, 0x63, 0xb5, 0x01, 0xf1, -0xb9, 0x4f, 0xcd, 0xe3, 0x87, 0xc5, 0x85, 0xd7, 0xca, 0x98, 0xba, 0x5d, 0x55, 0xa4, 0xcf, 0xf4, -0x9a, 0x13, 0xba, 0x34, 0x5c, 0x10, 0x98, 0x44, 0x9c, 0x98, 0x3d, 0x1a, 0x85, 0xe6, 0x1c, 0xff, -0x91, 0x72, 0x30, 0x43, 0x5a, 0x62, 0xfc, 0xd0, 0x46, 0xff, 0x56, 0x7a, 0xd8, 0x58, 0x8b, 0x42, -0x30, 0x04, 0xef, 0xff, 0xb6, 0xb4, 0xba, 0x4f, 0x89, 0xef, 0x9f, 0xe3, 0x5a, 0x51, 0x0f, 0x2f, -0x14, 0x08, 0xc7, 0x96, 0x2f, 0xb8, 0x6e, 0x81, 0xaa, 0x83, 0x8e, 0x0e, 0xf6, 0x5c, 0xb7, 0x8d, -0xde, 0xa1, 0xdd, 0x83, 0xfd, 0x7a, 0xb5, 0x99, 0x54, 0xa8, 0xa2, 0xb6, 0x7b, 0x90, 0x68, 0xed, -0xec, 0xd5, 0x2b, 0x05, 0x8c, 0x57, 0x95, 0x0e, 0x62, 0x95, 0x03, 0xb7, 0x5e, 0x45, 0x51, 0x62, -0x54, 0x40, 0xb2, 0x5e, 0xa6, 0x31, 0xd4, 0xa9, 0xd7, 0x6d, 0x9b, 0x71, 0x08, 0xd7, 0xa7, 0xd1, -0x5f, 0x97, 0x26, 0x31, 0xc6, 0xd9, 0x4d, 0x64, 0xa1, 0x33, 0x78, 0xd8, 0x42, 0x56, 0x2d, 0x37, -0x6e, 0xa2, 0x96, 0xe5, 0x5a, 0x9b, 0xe0, 0x61, 0xdb, 0x56, 0xd1, 0x58, 0x69, 0xd9, 0xea, 0xec, -0xb4, 0x8d, 0x5a, 0xf7, 0x45, 0x05, 0xf0, 0xee, 0xc7, 0x14, 0xc0, 0xb7, 0xbc, 0x42, 0x29, 0xe9, -0xe6, 0x17, 0x47, 0xea, 0xb3, 0x52, 0x2c, 0x4e, 0x76, 0xd5, 0x7b, 0x36, 0x69, 0x99, 0x72, 0x41, -0xfd, 0x7e, 0x56, 0x40, 0x75, 0x15, 0xb1, 0xb4, 0x74, 0x05, 0x17, 0x93, 0x7a, 0x43, 0x4b, 0x91, -0xf3, 0xe1, 0xcd, 0x0b, 0x22, 0x4f, 0x70, 0x25, 0x13, 0x4f, 0x36, 0x1c, 0xd9, 0x21, 0x7d, 0x54, -0xc2, 0x36, 0xd4, 0xb2, 0x20, 0xf0, 0x27, 0x0f, 0xf8, 0xb9, 0xb5, 0x61, 0x0e, 0xac, 0xce, 0x34, -0x29, 0xce, 0x8d, 0xad, 0x42, 0xad, 0xb6, 0xad, 0x2d, 0xb4, 0x0f, 0x24, 0xd2, 0x60, 0x76, 0x55, -0xfc, 0x13, 0xec, 0x2b, 0x5a, 0x2f, 0x04, 0x8b, 0x8e, 0x20, 0xa3, 0xd7, 0x93, 0x09, 0x3c, 0xb5, -0x6a, 0x2c, 0x7d, 0x5f, 0x2b, 0x8e, 0xea, 0x5b, 0xa8, 0x64, 0xa6, 0x26, 0x5c, 0x8e, 0x63, 0x84, -0x90, 0x29, 0x1f, 0x24, 0x62, 0x31, 0x34, 0x11, 0xa6, 0x12, 0xe3, 0x3b, 0x7f, 0x7a, 0x92, 0xa9, -0x2d, 0x56, 0x08, 0x1c, 0xf8, 0xc0, 0xe9, 0x13, 0xba, 0x1e, 0x3f, 0x50, 0x52, 0x8b, 0x12, 0x64, -0x6c, 0x12, 0x78, 0x20, 0x97, 0xb2, 0xc1, 0x7d, 0xa4, 0xc9, 0x7d, 0xb2, 0x8e, 0x55, 0x2f, 0x0e, -0x61, 0x4e, 0xcd, 0x9e, 0xc1, 0x35, 0xa5, 0xd5, 0x36, 0xb5, 0x6e, 0x7c, 0xf8, 0x26, 0xf8, 0xca, -0x8f, 0xdf, 0x50, 0xa7, 0xae, 0x3f, 0xb2, 0xec, 0xc4, 0xd7, 0x89, 0xe4, 0xae, 0x05, 0xb9, 0xe0, -0x91, 0xef, 0x43, 0xf9, 0xdf, 0x5c, 0x0f, 0x47, 0x30, 0xfa, 0x73, 0x78, 0x7d, 0x65, 0x43, 0x11, -0xc2, 0x9d, 0x8b, 0x4d, 0x16, 0x71, 0xfa, 0x4b, 0xc0, 0x4b, 0xc1, 0x6c, 0x6c, 0xba, 0xe4, 0x34, -0xd3, 0xb6, 0xb1, 0xe7, 0x9d, 0xcf, 0x61, 0xf6, 0x92, 0xc1, 0x8d, 0x08, 0x2a, 0xc0, 0xbc, 0x81, -0xdb, 0x31, 0xac, 0x95, 0xe5, 0xa1, 0x36, 0xf2, 0x10, 0x5b, 0x3b, 0x3e, 0xda, 0x98, 0xe8, 0x94, -0x82, 0xf1, 0xbd, 0x04, 0xa9, 0x99, 0x63, 0x93, 0x83, 0xcf, 0x9b, 0x41, 0x14, 0x69, 0x7e, 0x3d, -0x37, 0xac, 0x46, 0x57, 0xcf, 0x98, 0x5a, 0x22, 0x6e, 0xe5, 0x44, 0xdb, 0xe8, 0x3d, 0x2a, 0x1c, -0xcf, 0xba, 0x08, 0x2e, 0x02, 0x3c, 0x82, 0x4c, 0xa6, 0x33, 0x55, 0xef, 0xd6, 0x8a, 0x9d, 0x8d, -0x5a, 0xeb, 0xeb, 0x69, 0xbf, 0xc5, 0x6e, 0x0c, 0x45, 0x24, 0xeb, 0xfb, 0x3b, 0xe6, 0xc9, 0xf8, -0x6d, 0x5a, 0x26, 0x39, 0x79, 0x68, 0x4b, 0x6a, 0x46, 0x6a, 0xa3, 0xa6, 0x16, 0x13, 0xa5, 0x6a, -0xa0, 0x36, 0x44, 0x48, 0xf9, 0x46, 0x2e, 0x4e, 0x8d, 0xb4, 0xd2, 0x98, 0x85, 0xf4, 0x28, 0x0f, -0xfc, 0x16, 0x7f, 0xde, 0x1a, 0x63, 0xf2, 0x38, 0x95, 0x22, 0xe2, 0xde, 0xa9, 0xf9, 0x18, 0x64, -0xf2, 0xfb, 0x8b, 0x4b, 0xdc, 0x9a, 0x82, 0xff, 0xbe, 0x95, 0x90, 0x40, 0x1d, 0x1d, 0x36, 0xe2, -0xa5, 0x52, 0x0a, 0xf9, 0x2a, 0xc0, 0x26, 0xae, 0xd4, 0x4e, 0x0e, 0x13, 0xb6, 0xb9, 0x0f, 0x2d, -0x86, 0x70, 0xff, 0xa5, 0x68, 0xbd, 0x9f, 0x8f, 0x9a, 0x7d, 0x7d, 0x73, 0x7e, 0xd5, 0x64, 0xe2, -0x67, 0xfd, 0x9e, 0xb8, 0x75, 0x7e, 0x57, 0x19, 0xec, 0xcd, 0xd1, 0x48, 0x78, 0xe5, 0x55, 0xe1, -0x58, 0x75, 0xdc, 0x26, 0x6c, 0x21, 0xb6, 0x87, 0x35, 0x86, 0xa8, 0x84, 0x3e, 0x86, 0xca, 0x71, -0xee, 0x7a, 0x92, 0xdf, 0x0d, 0x9c, 0xe9, 0x16, 0xda, 0xb8, 0x93, 0x77, 0x7c, 0xa3, 0x81, 0xbd, -0x61, 0x13, 0xca, 0x57, 0x7e, 0x63, 0xcc, 0xcc, 0x5a, 0x49, 0xf1, 0x8f, 0x84, 0x39, 0x9f, 0xac, -0xc6, 0x9f, 0xa8, 0x39, 0xe5, 0xbe, 0x58, 0x0b, 0x2f, 0xb0, 0x51, 0x91, 0xe2, 0xd2, 0x0d, 0xc8, -0x2a, 0x6d, 0x40, 0xc7, 0xb9, 0x63, 0x61, 0xf6, 0x11, 0x33, 0x19, 0x25, 0x1f, 0x10, 0x7b, 0x4e, -0xf2, 0x11, 0xf8, 0x3f, 0x36, 0x79, 0x7e, 0xc0, 0x15, 0x16, 0x00, 0x00}; -#endif /*__SERIAL_HTML_H__*/ diff --git a/src/web/html/h/setup_html.h b/src/web/html/h/setup_html.h deleted file mode 100644 index 40481cd7..00000000 --- a/src/web/html/h/setup_html.h +++ /dev/null @@ -1,545 +0,0 @@ -#ifndef __SETUP_HTML_H__ -#define __SETUP_HTML_H__ -#define setup_html_len 8636 -const uint8_t setup_html[] PROGMEM = { -0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0xed, 0x3d, 0xfb, 0x5b, 0xdb, 0x48, -0x92, 0xbf, 0xe7, 0xaf, 0xe8, 0x68, 0xef, 0x06, 0x79, 0x63, 0xfc, 0x86, 0x10, 0x02, 0xec, 0x47, -0x80, 0x24, 0xdc, 0xf2, 0x3a, 0x4c, 0x36, 0xb3, 0x47, 0xfc, 0xf1, 0xc9, 0x52, 0x1b, 0x2b, 0xc8, -0x92, 0x46, 0x92, 0x0d, 0xde, 0xd9, 0xfc, 0xef, 0x57, 0xd5, 0x0f, 0xf9, 0xd5, 0x2d, 0xcb, 0x60, -0x07, 0x66, 0xee, 0xb2, 0x3b, 0x89, 0xdc, 0x8f, 0xea, 0xee, 0xea, 0xea, 0xaa, 0xea, 0xea, 0xea, -0xea, 0x9d, 0xd7, 0x4e, 0x60, 0x27, 0xc3, 0x90, 0x92, 0x6e, 0xd2, 0xf3, 0xf6, 0x5e, 0xed, 0xe0, -0x3f, 0xc4, 0xb3, 0xfc, 0xdb, 0x5d, 0x83, 0xfa, 0xc6, 0xde, 0x2b, 0x02, 0x7f, 0x76, 0xba, 0xd4, -0x72, 0xf8, 0x27, 0xfb, 0x99, 0xb8, 0x89, 0x47, 0xf7, 0x9a, 0x34, 0xe9, 0x87, 0x3b, 0x65, 0xfe, -0x63, 0x94, 0xe9, 0xb9, 0xfe, 0x1d, 0x89, 0xa8, 0xb7, 0x6b, 0xc4, 0xc9, 0xd0, 0xa3, 0x71, 0x97, -0xd2, 0xc4, 0x20, 0xd8, 0xc4, 0xae, 0x91, 0xd0, 0x87, 0xa4, 0x6c, 0xc7, 0xb1, 0x41, 0xba, 0x11, -0xed, 0x88, 0x12, 0x25, 0x48, 0xf8, 0xdb, 0x60, 0xb7, 0x52, 0xda, 0x2a, 0x55, 0x2a, 0x95, 0xaa, -0x51, 0x86, 0x5e, 0xf4, 0x68, 0x62, 0x11, 0xdf, 0xea, 0x41, 0x9d, 0x81, 0x4b, 0xef, 0xc3, 0x20, -0x02, 0x18, 0x76, 0xe0, 0x27, 0xd4, 0x4f, 0x76, 0x8d, 0x7b, 0xd7, 0x49, 0xba, 0xbb, 0x0e, 0x1d, -0xb8, 0x36, 0x5d, 0x67, 0x3f, 0x8a, 0xc4, 0xf5, 0xdd, 0xc4, 0xb5, 0xbc, 0xf5, 0xd8, 0xb6, 0x3c, -0xba, 0x5b, 0x35, 0x24, 0x10, 0xbb, 0x6b, 0x45, 0x31, 0x85, 0x4a, 0x5f, 0xae, 0x3e, 0xae, 0x6f, -0x61, 0x72, 0x6c, 0x47, 0x6e, 0x98, 0x8c, 0xf7, 0xe8, 0xbb, 0x35, 0xb0, 0x78, 0xaa, 0x41, 0xe2, -0xc8, 0xde, 0x35, 0xac, 0xd0, 0x2d, 0x7d, 0x9f, 0xe8, 0xd4, 0xde, 0x4e, 0x99, 0x97, 0x00, 0x00, -0x8b, 0x8c, 0xd0, 0x0e, 0xbc, 0x20, 0x8a, 0xe7, 0x0c, 0x31, 0x0a, 0xda, 0x41, 0x12, 0x8f, 0x0d, -0xd0, 0x0f, 0x5c, 0xdf, 0xa1, 0x0f, 0x45, 0xe2, 0x07, 0x9d, 0xc0, 0xf3, 0x82, 0x7b, 0x83, 0x94, -0xc5, 0x54, 0x94, 0x47, 0x73, 0xb1, 0xd3, 0x0e, 0x9c, 0xe1, 0x18, 0xe6, 0x1d, 0x77, 0x40, 0x6c, -0xcf, 0x8a, 0x63, 0xe8, 0x46, 0x10, 0xfa, 0xd6, 0x40, 0x4e, 0x9f, 0x25, 0x3a, 0x53, 0x1e, 0xef, -0x43, 0x5a, 0x14, 0xe7, 0xcf, 0xd8, 0xdb, 0xef, 0x06, 0xc3, 0xc3, 0xab, 0x2f, 0x3b, 0x65, 0x6b, -0xaa, 0xd2, 0x08, 0x39, 0xdb, 0x83, 0xc0, 0x75, 0xcc, 0x4a, 0xe1, 0x7d, 0x5a, 0xd7, 0x85, 0x1e, -0x1b, 0x24, 0xf0, 0x6d, 0xcf, 0xb5, 0xef, 0x64, 0xab, 0x66, 0xc1, 0x18, 0xeb, 0x54, 0x1c, 0x5a, -0x3e, 0x22, 0x0f, 0xff, 0x59, 0x38, 0x75, 0xd4, 0x1b, 0x1c, 0x9b, 0xeb, 0xa4, 0x03, 0x93, 0x1d, -0xe8, 0x05, 0x6d, 0x17, 0x7b, 0x3f, 0x82, 0x61, 0xb1, 0x62, 0x50, 0xa6, 0x9e, 0x16, 0xea, 0xba, -0x0e, 0x95, 0xf3, 0x51, 0xf6, 0xdc, 0x01, 0x9d, 0x98, 0xd8, 0x13, 0x48, 0x48, 0xdb, 0x99, 0x04, -0xd1, 0x50, 0x83, 0x88, 0x69, 0x04, 0x94, 0x36, 0x01, 0xe4, 0x2b, 0x6d, 0xf3, 0x54, 0x0d, 0xa4, -0x0d, 0x1d, 0x24, 0x58, 0x42, 0x13, 0x80, 0x60, 0x51, 0x25, 0xae, 0x7f, 0x1b, 0x4f, 0xc2, 0x41, -0x8c, 0x48, 0x00, 0x31, 0x0d, 0x69, 0x64, 0x25, 0x41, 0x64, 0xcc, 0x22, 0x30, 0x6d, 0x6f, 0x53, -0xdd, 0x5e, 0x3f, 0x74, 0xac, 0x64, 0x72, 0xf8, 0x5f, 0x58, 0x92, 0xa6, 0xdb, 0x6f, 0x35, 0xdd, -0x1e, 0xc6, 0x09, 0xed, 0x4d, 0xf6, 0x9b, 0x25, 0x3d, 0xb1, 0xd7, 0x5b, 0x69, 0x0b, 0xb0, 0x00, -0x61, 0x45, 0x59, 0xd1, 0x2d, 0xae, 0xdc, 0x9b, 0x36, 0xf0, 0xa3, 0x3b, 0x63, 0xef, 0xf2, 0xa8, -0x79, 0x45, 0xf6, 0x2f, 0x8e, 0x35, 0x9d, 0x7d, 0x27, 0x6b, 0x77, 0x93, 0x24, 0x8c, 0xb7, 0xcb, -0x65, 0x0b, 0x48, 0xda, 0x49, 0xfa, 0x25, 0xec, 0xf9, 0x34, 0xac, 0xc3, 0xc0, 0xee, 0xf7, 0x60, -0xad, 0x59, 0x89, 0x1b, 0xf8, 0x1a, 0x80, 0xd5, 0xca, 0xa8, 0x3f, 0xed, 0xa0, 0x9f, 0x4c, 0x0c, -0x78, 0x1f, 0x53, 0x9e, 0x38, 0xde, 0x8a, 0x86, 0x44, 0x83, 0x5b, 0x17, 0x58, 0xef, 0x09, 0xfe, -0xa3, 0xeb, 0x9a, 0xb6, 0x26, 0xf4, 0x8a, 0x55, 0x1d, 0xef, 0xdd, 0x4e, 0x19, 0x96, 0xcf, 0xd4, -0x42, 0xba, 0x77, 0x3b, 0x2e, 0x5f, 0xbe, 0x72, 0x2d, 0xfb, 0x9d, 0x00, 0x3b, 0xcb, 0x8a, 0x8e, -0xd5, 0x98, 0xac, 0x15, 0x59, 0x21, 0x0c, 0x6c, 0x6c, 0xc1, 0x4d, 0x64, 0x0b, 0x06, 0x36, 0x95, -0xcd, 0x8a, 0x74, 0x82, 0xa8, 0x47, 0x80, 0xe7, 0x75, 0x03, 0x28, 0x17, 0x06, 0x31, 0x70, 0x4c, -0xcb, 0x46, 0xe4, 0x23, 0x3d, 0x59, 0x03, 0x18, 0x03, 0x02, 0x88, 0x05, 0xf9, 0x2b, 0x20, 0x70, -0x28, 0x2e, 0xf5, 0x1c, 0x28, 0xa4, 0xc9, 0x6e, 0xf7, 0x93, 0x24, 0xf0, 0x05, 0x2b, 0xe6, 0x3f, -0xd2, 0xf1, 0xc5, 0x37, 0xc0, 0x8b, 0x3d, 0x2b, 0x8c, 0xdd, 0xb6, 0x47, 0x49, 0x2f, 0x59, 0x6f, -0x48, 0xaa, 0x25, 0x07, 0x81, 0xdf, 0x71, 0x6f, 0x77, 0xca, 0xbc, 0x86, 0x06, 0xf6, 0x18, 0x77, -0x45, 0x50, 0xba, 0x81, 0x4e, 0x74, 0x33, 0x65, 0x53, 0xed, 0xf5, 0x9a, 0xa6, 0x2c, 0x97, 0x99, -0xf4, 0x96, 0xfa, 0x8e, 0x2c, 0xed, 0x50, 0x18, 0xff, 0x21, 0x93, 0x6e, 0xe4, 0x33, 0x60, 0x8a, -0x9c, 0x81, 0x94, 0xd8, 0x29, 0xf3, 0x42, 0x19, 0x50, 0xc6, 0x7a, 0x18, 0x05, 0xf7, 0x04, 0x1a, -0xad, 0x67, 0x34, 0x3a, 0x5d, 0x05, 0xb0, 0xb3, 0x5e, 0xad, 0x11, 0xfc, 0x27, 0xee, 0x61, 0x4d, -0xd1, 0x03, 0xde, 0xf8, 0x04, 0x39, 0x2c, 0x06, 0xea, 0x1d, 0x50, 0x95, 0xeb, 0x87, 0xfd, 0x71, -0x91, 0x6b, 0x08, 0xc9, 0xc7, 0x65, 0x38, 0xc8, 0xc3, 0x39, 0x2d, 0xcc, 0xcb, 0x7e, 0xfa, 0xd0, -0xb7, 0xc6, 0x46, 0x7e, 0x49, 0xdb, 0x41, 0x90, 0x10, 0x14, 0x89, 0xc4, 0x4a, 0x48, 0xcf, 0x75, -0x7c, 0xf7, 0xb6, 0x9b, 0x3c, 0x02, 0x0b, 0x0d, 0x1d, 0x12, 0xec, 0x2e, 0xb5, 0xef, 0xda, 0xc1, -0x83, 0x44, 0x44, 0x0c, 0x09, 0x0e, 0x6f, 0xf7, 0xa5, 0x61, 0xe3, 0xd0, 0x8a, 0xee, 0xc8, 0x69, -0xe0, 0xd0, 0x55, 0x8e, 0xdf, 0x81, 0x46, 0xb0, 0x8d, 0xf9, 0x83, 0x57, 0x13, 0x9b, 0xb1, 0x67, -0xd2, 0x5e, 0x98, 0x0c, 0x49, 0x1b, 0x46, 0x0c, 0xa2, 0x98, 0xd8, 0x16, 0x34, 0x41, 0x82, 0x88, -0xf4, 0x63, 0x4a, 0x0e, 0xae, 0x2e, 0x4f, 0xc8, 0x1b, 0xf2, 0x71, 0x83, 0x58, 0x9d, 0x04, 0x32, -0x23, 0x3e, 0xc1, 0x49, 0x40, 0x80, 0x9d, 0x79, 0x43, 0x92, 0x74, 0xdd, 0x98, 0x08, 0xde, 0x53, -0x78, 0x3c, 0xf2, 0x77, 0xca, 0x73, 0xf8, 0x93, 0x82, 0x2f, 0x34, 0x16, 0xe4, 0x0b, 0x53, 0x2c, -0x6b, 0x2e, 0x53, 0x08, 0x27, 0x6b, 0x83, 0xc0, 0xeb, 0xc7, 0xe4, 0xe4, 0xe8, 0x10, 0x34, 0x8c, -0x70, 0x0e, 0x09, 0x21, 0x43, 0x0e, 0x5d, 0x9f, 0x49, 0x14, 0x31, 0xea, 0xbc, 0xed, 0x5c, 0x5a, -0x8e, 0x1b, 0x10, 0xf3, 0xec, 0xf2, 0x63, 0xad, 0x71, 0x52, 0xa9, 0xbe, 0x29, 0xe4, 0x6b, 0x2d, -0xea, 0xd4, 0x1a, 0xc6, 0x3c, 0x02, 0x58, 0xb0, 0x0f, 0x07, 0xa7, 0x57, 0xb5, 0x7a, 0xa5, 0xb2, -0x9f, 0xb3, 0x0b, 0x76, 0x0f, 0x47, 0xab, 0xa2, 0xaf, 0xa3, 0xe6, 0x45, 0xbd, 0x06, 0xca, 0xae, -0x37, 0x14, 0x24, 0xb2, 0xa4, 0x7e, 0x36, 0x99, 0xe2, 0x88, 0x33, 0x1a, 0x07, 0x1e, 0x9d, 0xdf, -0xcb, 0xe5, 0xad, 0xec, 0x30, 0x72, 0xfd, 0x04, 0x76, 0x4e, 0x03, 0x1a, 0xe1, 0xaa, 0x00, 0x45, -0xd0, 0x5a, 0x29, 0x8f, 0xa3, 0xd1, 0x91, 0xff, 0xd2, 0xb8, 0x9b, 0xc0, 0xfe, 0x21, 0x6d, 0xf7, -0x6f, 0x57, 0x3c, 0xf8, 0xc3, 0xf6, 0xed, 0x4b, 0x18, 0xfd, 0x98, 0x90, 0x27, 0xbd, 0x21, 0x2a, -0x26, 0xc7, 0xa0, 0xcc, 0x44, 0x03, 0xc0, 0xc2, 0x75, 0xdc, 0x5a, 0xaa, 0xa8, 0xf7, 0xfb, 0xbd, -0x36, 0x68, 0x8b, 0x23, 0x14, 0x40, 0x4b, 0x03, 0x0f, 0xb4, 0x71, 0xdc, 0x73, 0xee, 0x1a, 0xc7, -0x3e, 0x34, 0xea, 0x3a, 0x84, 0x55, 0x79, 0x12, 0x6a, 0xe6, 0x72, 0xde, 0x0c, 0xf6, 0x95, 0x5f, -0x6b, 0x34, 0xf6, 0xce, 0x68, 0x72, 0x1f, 0x44, 0x77, 0xcb, 0x53, 0x15, 0x1f, 0xa3, 0x2e, 0xea, -0x44, 0xc3, 0x57, 0xf7, 0xa3, 0x3b, 0x92, 0x08, 0xb9, 0xa7, 0x30, 0x27, 0x19, 0xe5, 0x23, 0xa5, -0xfd, 0x0b, 0x72, 0x01, 0xd9, 0x80, 0x24, 0x87, 0x98, 0x3d, 0xd7, 0x2f, 0x11, 0x8f, 0xfa, 0xb7, -0x49, 0x77, 0x9b, 0x6c, 0x15, 0x72, 0x90, 0xd6, 0xe3, 0x35, 0x49, 0x2b, 0xbc, 0x09, 0xef, 0x1d, -0x03, 0x94, 0x35, 0x9f, 0xb7, 0xb8, 0x6b, 0x6c, 0xa1, 0xd5, 0x24, 0x0f, 0x3d, 0xcf, 0x91, 0x6d, -0x9c, 0x67, 0xef, 0x1d, 0xe1, 0x2a, 0x01, 0x55, 0x81, 0x12, 0x3b, 0xa2, 0x0e, 0x4c, 0x29, 0xf0, -0x8d, 0x18, 0x75, 0x88, 0x61, 0xd0, 0x8f, 0x48, 0x08, 0x3b, 0x30, 0x1a, 0x41, 0x06, 0xc1, 0x69, -0x20, 0x31, 0xdf, 0x59, 0x96, 0xc8, 0xfe, 0x98, 0xc2, 0x01, 0xda, 0x05, 0xab, 0xcf, 0xb5, 0x5e, -0x92, 0x44, 0x2e, 0x65, 0x00, 0x80, 0x44, 0x7c, 0x6a, 0x27, 0xe4, 0xde, 0x4d, 0xba, 0x5c, 0x17, -0xc1, 0xcd, 0x58, 0xd4, 0xe3, 0x20, 0x98, 0x44, 0x78, 0x9e, 0xd9, 0x6c, 0x52, 0x2b, 0xb2, 0xbb, -0x44, 0x50, 0x7d, 0xbc, 0xf4, 0x09, 0x94, 0x8b, 0x4d, 0xea, 0xc0, 0x96, 0xdf, 0x4e, 0x7c, 0xb1, -0x13, 0x94, 0x3f, 0x04, 0x20, 0xf6, 0x0d, 0xec, 0xa2, 0x2f, 0x0a, 0x8e, 0x99, 0x9d, 0xf0, 0xa7, -0x59, 0x30, 0x96, 0x37, 0xd7, 0xb3, 0xe8, 0xac, 0xe1, 0x5f, 0x5c, 0x60, 0x2c, 0x63, 0x91, 0x0c, -0x2c, 0xd7, 0x5b, 0x2a, 0x56, 0xe7, 0xd6, 0xe6, 0x06, 0x0a, 0xea, 0x21, 0x99, 0x71, 0x6c, 0xfb, -0xa2, 0x79, 0x8e, 0xee, 0xd1, 0xaf, 0xc0, 0x3f, 0xe8, 0x5a, 0xfe, 0x2d, 0xe3, 0xd7, 0x1e, 0xf4, -0x71, 0xc2, 0x9c, 0x37, 0xb7, 0x89, 0x20, 0x44, 0x9a, 0x95, 0x13, 0xb5, 0x5e, 0x35, 0x08, 0x6f, -0x14, 0xd6, 0x85, 0xe3, 0xc6, 0x16, 0x30, 0x51, 0x87, 0x74, 0x5d, 0x07, 0x96, 0xcf, 0x9e, 0x0f, -0x1a, 0x38, 0x4e, 0x9d, 0x4f, 0x9d, 0x9d, 0x32, 0xaf, 0x97, 0x73, 0x1c, 0x65, 0x0e, 0x33, 0x07, -0xce, 0x72, 0x13, 0xc4, 0xb3, 0xd2, 0x43, 0xb3, 0x79, 0x7c, 0xb8, 0x52, 0xe6, 0x18, 0xc7, 0xae, -0xb3, 0xd0, 0xfa, 0x78, 0x1e, 0x74, 0x70, 0x4c, 0x10, 0xe0, 0x7f, 0x9c, 0x44, 0x96, 0x8e, 0x93, -0x69, 0xa5, 0x0c, 0x9b, 0xf9, 0x03, 0xe0, 0x45, 0x90, 0x89, 0x14, 0xac, 0x4b, 0x47, 0x4b, 0x28, -0x00, 0x4b, 0xb4, 0x30, 0x41, 0x2a, 0x96, 0xf0, 0xef, 0x17, 0x5f, 0x0f, 0x7f, 0x2c, 0x05, 0x47, -0xf3, 0x74, 0xb4, 0xc7, 0xec, 0x90, 0xb5, 0xbb, 0x64, 0x14, 0xbf, 0x36, 0x39, 0xbe, 0x20, 0x26, -0xe7, 0x2c, 0x96, 0x57, 0x98, 0xbf, 0x59, 0x16, 0x82, 0x7e, 0x2e, 0x66, 0x4f, 0xa8, 0x35, 0xa0, -0x84, 0x77, 0x95, 0x30, 0x83, 0x32, 0x01, 0x71, 0x4d, 0x0e, 0x3f, 0x1f, 0x5c, 0xec, 0xb4, 0xa3, -0xf2, 0x7c, 0x00, 0x57, 0xa0, 0x04, 0xf0, 0x83, 0x1d, 0x54, 0x09, 0x04, 0x20, 0x2b, 0xa2, 0x24, -0xc4, 0xc3, 0x2a, 0x54, 0x88, 0xb9, 0x1a, 0xc0, 0x95, 0x80, 0x6d, 0x52, 0x7d, 0x57, 0x2b, 0x55, -0x37, 0xb7, 0x4a, 0x8d, 0x52, 0x75, 0xce, 0x0c, 0x84, 0x7b, 0xcf, 0xa3, 0x29, 0x00, 0xa6, 0xf7, -0x1d, 0x27, 0xa2, 0x71, 0xbc, 0x52, 0x46, 0xe6, 0x86, 0xd8, 0x0a, 0x68, 0x79, 0xd6, 0x83, 0xd4, -0xf2, 0xaa, 0x1b, 0x8b, 0xa9, 0x79, 0xcf, 0xa3, 0x48, 0xf5, 0xdb, 0x3d, 0x2b, 0xbe, 0x5b, 0x31, -0x6e, 0x4e, 0xa1, 0x89, 0x3f, 0x1e, 0x6e, 0x0e, 0xcf, 0x9a, 0xa4, 0xba, 0x62, 0xcc, 0x1c, 0xfa, -0x71, 0xf5, 0x8f, 0x89, 0x99, 0xda, 0xea, 0x31, 0x53, 0xfb, 0xe3, 0x61, 0xe6, 0x93, 0x95, 0xd0, -0x7b, 0x6b, 0xb8, 0x62, 0xdc, 0x88, 0x56, 0x56, 0x82, 0x9e, 0x9f, 0x65, 0xb1, 0xb8, 0x88, 0x82, -0x84, 0xda, 0xfc, 0x94, 0x73, 0xd5, 0x46, 0x8b, 0xc5, 0x25, 0x35, 0xe9, 0x3d, 0x30, 0xcd, 0x66, -0xac, 0x93, 0xb9, 0x84, 0xf4, 0x0a, 0xe8, 0x8a, 0x69, 0x6b, 0x09, 0xdb, 0x9e, 0x39, 0x3d, 0x10, -0xc0, 0x3f, 0x4d, 0xdb, 0xb2, 0xb0, 0xb9, 0xd5, 0xa8, 0x5c, 0x42, 0xa1, 0x69, 0xf2, 0x7d, 0x5f, -0x68, 0xdd, 0x02, 0xc6, 0xef, 0xbb, 0x2e, 0x6c, 0xe9, 0xe3, 0x6e, 0xd0, 0xf7, 0x1c, 0xd2, 0x06, -0x95, 0x83, 0xe3, 0x1e, 0xb4, 0x8e, 0xf6, 0x90, 0x84, 0xe9, 0xa0, 0xf3, 0x28, 0x12, 0xec, 0x80, -0x00, 0xaa, 0xdf, 0xa0, 0x6c, 0x33, 0xf6, 0x5e, 0x08, 0xc5, 0x1f, 0x0b, 0x7b, 0xf6, 0x6a, 0xcf, -0x73, 0x75, 0xb4, 0xae, 0xd2, 0x46, 0x47, 0x3d, 0xca, 0x75, 0x86, 0x8b, 0x68, 0x95, 0x46, 0xf9, -0xf9, 0x58, 0x55, 0xec, 0x3a, 0x9e, 0x72, 0xea, 0xbb, 0x54, 0xfb, 0xaf, 0x9c, 0x28, 0x1c, 0x51, -0x3b, 0xf1, 0x41, 0x77, 0x53, 0xda, 0x73, 0x20, 0x9d, 0x48, 0x1c, 0xad, 0xc2, 0x42, 0xfe, 0x34, -0x84, 0xa4, 0xa7, 0x35, 0x71, 0xbf, 0xcd, 0xa6, 0xf3, 0x2c, 0x48, 0xd8, 0x31, 0xcd, 0x93, 0x51, -0x15, 0xee, 0xed, 0x93, 0x35, 0x90, 0x2d, 0xa4, 0x17, 0x38, 0x7d, 0x0f, 0x96, 0x62, 0x70, 0x4f, -0xa3, 0x35, 0x8e, 0x15, 0x12, 0x74, 0xc8, 0x5a, 0x65, 0x4d, 0x5a, 0x4d, 0x62, 0x6e, 0x78, 0xec, -0xa2, 0xb9, 0xc4, 0xc3, 0xfd, 0xc1, 0x1a, 0x3a, 0x32, 0x41, 0x59, 0x97, 0xde, 0xe7, 0xe8, 0xcb, -0xb3, 0xe3, 0xec, 0x13, 0xf5, 0x69, 0x84, 0xee, 0x51, 0x4b, 0x40, 0xdb, 0xff, 0xd9, 0x03, 0x14, -0x60, 0x0a, 0xb2, 0xa5, 0x15, 0x9c, 0xa1, 0xac, 0x0c, 0x3b, 0xa7, 0x40, 0xe1, 0x11, 0xe5, 0xd6, -0xee, 0x90, 0x46, 0x20, 0x59, 0x87, 0x5e, 0x60, 0x39, 0xab, 0x45, 0xd4, 0x25, 0x34, 0x38, 0x7c, -0x59, 0x87, 0x8d, 0x62, 0x59, 0x5d, 0x52, 0x94, 0x24, 0x6c, 0x91, 0xc3, 0xa6, 0x1f, 0x44, 0xc5, -0x3f, 0x51, 0xba, 0x1c, 0x5a, 0x3f, 0xcd, 0xd7, 0x04, 0xb1, 0x13, 0x27, 0xa7, 0x79, 0x4c, 0x82, -0xcf, 0x8d, 0x9e, 0xfb, 0x2e, 0xf5, 0x47, 0x07, 0xd4, 0x21, 0x88, 0x79, 0x34, 0x98, 0x84, 0x56, -0x3f, 0x46, 0xdc, 0x25, 0x24, 0xee, 0xfb, 0x50, 0x7a, 0xf5, 0xc8, 0x3a, 0x08, 0x7a, 0xcd, 0x24, -0x08, 0x5f, 0x9e, 0xa3, 0x92, 0x16, 0x57, 0x31, 0xf7, 0xf4, 0x70, 0x63, 0xb2, 0x86, 0x86, 0x76, -0x0b, 0x8f, 0x1c, 0x50, 0x90, 0xac, 0xad, 0x1e, 0x59, 0x20, 0x1f, 0xd9, 0x09, 0xc7, 0xcb, 0xc4, -0x16, 0x0a, 0xdc, 0xb5, 0x74, 0xf9, 0xfd, 0xd4, 0x15, 0x67, 0x3d, 0xbc, 0xb8, 0x45, 0xc7, 0x4c, -0xa5, 0x11, 0x3f, 0x7a, 0x0c, 0xb0, 0xff, 0x6e, 0x8f, 0x92, 0x78, 0xe8, 0xdb, 0xc4, 0x84, 0x35, -0xd6, 0xe9, 0x33, 0x5d, 0x63, 0xff, 0x62, 0xfd, 0xdc, 0xf7, 0x86, 0xeb, 0xe8, 0xa0, 0x55, 0x58, -0xa9, 0x93, 0x44, 0x12, 0x25, 0x5f, 0x93, 0x6e, 0x72, 0xd5, 0x7b, 0x69, 0x58, 0x62, 0x3c, 0x9a, -0x1c, 0x75, 0x3a, 0xae, 0xed, 0x52, 0xdf, 0x1e, 0x12, 0x73, 0xb4, 0x83, 0x6a, 0xd3, 0xe4, 0x9e, -0xc2, 0xda, 0xab, 0x94, 0xde, 0x6d, 0x30, 0x86, 0x0e, 0x1f, 0x9b, 0x4b, 0xc5, 0xd3, 0xa4, 0x74, -0x1b, 0x7a, 0x0e, 0x74, 0xc4, 0x80, 0x25, 0x4e, 0x43, 0xd8, 0x3e, 0xfa, 0xc3, 0x3f, 0x86, 0xeb, -0xc4, 0xd5, 0x05, 0x69, 0x82, 0xee, 0xf2, 0x5c, 0x1b, 0x33, 0xdd, 0xe6, 0x6c, 0xbc, 0x5f, 0x3f, -0xd7, 0xc5, 0x56, 0xa8, 0x47, 0xa3, 0x0e, 0x90, 0x32, 0x39, 0xbe, 0x58, 0x99, 0xaf, 0xad, 0x9f, -0x70, 0xe3, 0xf9, 0x8b, 0xd4, 0x11, 0x11, 0x09, 0x17, 0x41, 0x94, 0xac, 0x50, 0x29, 0x84, 0xf1, -0x63, 0x0b, 0x2f, 0x77, 0xfc, 0xe9, 0x2e, 0xc2, 0x04, 0x9e, 0x7b, 0xea, 0xfa, 0xfd, 0x84, 0xc6, -0x45, 0xc2, 0x9c, 0x68, 0x36, 0xe4, 0xef, 0xc2, 0x6a, 0x11, 0xc4, 0xfd, 0xb3, 0x5e, 0x24, 0x86, -0x70, 0x95, 0x0b, 0xe7, 0x57, 0x14, 0x52, 0x4f, 0xc5, 0xc3, 0x7c, 0x83, 0x9e, 0xde, 0x51, 0x05, -0x10, 0xf5, 0x41, 0xfa, 0xa9, 0xc8, 0x6f, 0x85, 0x59, 0xa3, 0x13, 0x05, 0x3d, 0xe9, 0x8f, 0x3c, -0xee, 0xae, 0x42, 0x93, 0x2b, 0x18, 0x00, 0xf3, 0x58, 0x79, 0x62, 0x2f, 0x9a, 0x20, 0xa8, 0xd3, -0x6e, 0xf0, 0x1f, 0x2a, 0x77, 0x19, 0x14, 0xe7, 0x40, 0x60, 0xe3, 0x7d, 0x80, 0xa4, 0xb4, 0x13, -0xf9, 0xce, 0x2c, 0xf9, 0xf5, 0x16, 0x6c, 0xcb, 0x0a, 0x5d, 0x50, 0xa5, 0xfa, 0x5e, 0x72, 0x96, -0x84, 0xb3, 0xd7, 0x5b, 0x1e, 0x65, 0x0b, 0xff, 0xf9, 0xe4, 0x24, 0x48, 0xe9, 0xea, 0xc9, 0xa4, -0x24, 0xe0, 0x8d, 0xd0, 0x83, 0xf7, 0xa9, 0x52, 0xb4, 0xbc, 0x7c, 0xb9, 0xdc, 0xec, 0xfb, 0x91, -0x1b, 0x53, 0xf2, 0x0b, 0x69, 0x8a, 0xcd, 0xd4, 0x4b, 0x92, 0xce, 0xb3, 0xbd, 0x7b, 0x16, 0x19, -0x7d, 0x62, 0x25, 0x6e, 0xd2, 0x77, 0x28, 0x31, 0x1d, 0x6a, 0xbb, 0x3d, 0xe6, 0x4d, 0xb0, 0x3a, -0x3f, 0xd9, 0xbe, 0x0f, 0xed, 0x2d, 0x4b, 0xbf, 0x5b, 0x1d, 0x4e, 0x02, 0xff, 0xf6, 0xe7, 0x22, -0x05, 0x89, 0xf8, 0x85, 0x23, 0xe5, 0xbc, 0xd3, 0x41, 0x82, 0x37, 0xc3, 0x88, 0xa2, 0x71, 0x02, -0x69, 0xb7, 0x48, 0xf0, 0xba, 0x9b, 0x30, 0x55, 0x3c, 0x1d, 0x45, 0x13, 0x4e, 0x7c, 0x00, 0x14, -0x5b, 0x64, 0xec, 0x86, 0xfb, 0xc4, 0xbd, 0xa8, 0x5d, 0xd3, 0x05, 0x1a, 0x6a, 0x52, 0xb3, 0x8d, -0xb4, 0x4d, 0xc4, 0xc4, 0xe9, 0x47, 0x98, 0xb0, 0xfa, 0x5b, 0x55, 0x7d, 0xff, 0xd0, 0x8d, 0xcf, -0xb0, 0x99, 0x83, 0xa0, 0xf7, 0x87, 0xd8, 0x26, 0x9d, 0xfe, 0xf7, 0xd5, 0xd5, 0xcb, 0x62, 0xc1, -0xbc, 0x47, 0xcf, 0xc2, 0x76, 0x3f, 0x44, 0xc1, 0x1d, 0xdb, 0x16, 0x89, 0xfd, 0xd1, 0x0a, 0x77, -0x47, 0xbd, 0xdf, 0x92, 0xe4, 0xe5, 0x6e, 0x8f, 0x56, 0xbc, 0x35, 0xc2, 0xc1, 0xbf, 0xdc, 0xbd, -0xd1, 0x81, 0xe7, 0x02, 0x85, 0x93, 0x63, 0x67, 0xc2, 0x99, 0x6f, 0x85, 0x74, 0xc0, 0x1b, 0x3c, -0x76, 0x5e, 0x26, 0x3a, 0xbe, 0xc0, 0x76, 0x02, 0xfb, 0xfa, 0xb3, 0xb0, 0x81, 0xed, 0xbd, 0xd0, -0x55, 0x91, 0xde, 0x34, 0x59, 0x0d, 0x26, 0xa6, 0x3d, 0x35, 0xd8, 0x32, 0xb9, 0x7f, 0xa1, 0x64, -0x71, 0x15, 0x84, 0xae, 0xbd, 0x52, 0x42, 0x60, 0x2d, 0x18, 0x24, 0xb4, 0x12, 0x10, 0xe2, 0xfe, -0xae, 0x71, 0xfd, 0x6d, 0xfd, 0xdb, 0x9b, 0xfd, 0xf5, 0xff, 0xb1, 0xd6, 0xff, 0x55, 0x59, 0x7f, -0xf7, 0xad, 0xf4, 0xad, 0xfc, 0x97, 0x6f, 0xff, 0xf1, 0x9f, 0xbf, 0xec, 0xde, 0xb4, 0xde, 0x68, -0x8e, 0x27, 0xc9, 0x93, 0x31, 0x37, 0x7d, 0x75, 0xd2, 0x1f, 0x79, 0x0e, 0xb0, 0xfb, 0x8b, 0x68, -0xae, 0xb6, 0x48, 0xc7, 0x7d, 0x60, 0x5e, 0xb4, 0xdc, 0x9e, 0x52, 0x24, 0x74, 0x80, 0x47, 0x23, -0x1d, 0x3c, 0x43, 0x07, 0xbd, 0xcc, 0x8d, 0x89, 0x1f, 0xb0, 0xb3, 0xf4, 0x5b, 0x5a, 0x22, 0xfb, -0x19, 0xe7, 0xed, 0x93, 0x70, 0x4a, 0xcc, 0x6f, 0x97, 0xb7, 0x12, 0x93, 0xb0, 0xdf, 0xf6, 0xdc, -0xb8, 0x0b, 0xf9, 0xb0, 0xab, 0x06, 0xa0, 0x09, 0xb9, 0xb7, 0x62, 0xd0, 0xf2, 0x6c, 0x9b, 0xc6, -0x71, 0xa7, 0xef, 0x79, 0x43, 0x12, 0x51, 0x9b, 0xba, 0x03, 0x28, 0xc1, 0x2c, 0x01, 0x52, 0xfd, -0x29, 0xa1, 0xbe, 0xdc, 0xb1, 0x60, 0xff, 0xbc, 0x4d, 0x2a, 0x85, 0x55, 0xdf, 0xf7, 0x7c, 0xb6, -0xc3, 0x6a, 0xa4, 0x98, 0x39, 0xa7, 0xd5, 0xe4, 0x45, 0x2e, 0x24, 0xd0, 0x18, 0xed, 0x00, 0xa6, -0x6a, 0x28, 0x2e, 0x59, 0x13, 0xb3, 0x1b, 0xf4, 0x28, 0x54, 0x70, 0xe3, 0xc4, 0xf2, 0x9f, 0xae, -0xc1, 0x3f, 0xc5, 0xe6, 0x83, 0x48, 0x4d, 0xfb, 0xc7, 0x2d, 0x3f, 0x53, 0x49, 0x2a, 0xfb, 0x0f, -0xac, 0x92, 0x09, 0xfb, 0x93, 0xef, 0xa4, 0x15, 0xf8, 0x10, 0x73, 0xda, 0xa2, 0x66, 0x2d, 0x40, -0xa7, 0xd0, 0xf8, 0xaa, 0x4d, 0x40, 0x3f, 0x4b, 0xf3, 0x06, 0x9c, 0x84, 0x9e, 0x35, 0xfc, 0x29, -0xd1, 0x40, 0x16, 0xd5, 0xc1, 0xa7, 0xfb, 0x96, 0xdb, 0x8f, 0x0c, 0xd8, 0x59, 0x78, 0x05, 0x83, -0xcf, 0xe7, 0x47, 0x26, 0x6b, 0x5c, 0x06, 0xc9, 0x63, 0x1c, 0xcf, 0x9e, 0xb2, 0x55, 0xbc, 0xea, -0x47, 0x3e, 0xf0, 0xe0, 0x0e, 0xfa, 0x27, 0x7a, 0x74, 0x6c, 0xaf, 0x88, 0xd7, 0x22, 0x20, 0x1d, -0x76, 0x90, 0xab, 0x0d, 0x40, 0x01, 0xc3, 0xbe, 0x09, 0xef, 0xa3, 0x97, 0x76, 0xf0, 0x78, 0xe4, -0xa3, 0x38, 0x22, 0x4d, 0x3b, 0xa2, 0xd4, 0xc7, 0x40, 0x39, 0x11, 0x31, 0x43, 0x10, 0x4b, 0x1e, -0x89, 0xbb, 0x6e, 0x07, 0xaf, 0x94, 0x16, 0xc9, 0xf9, 0xc9, 0xd1, 0xe1, 0x78, 0x60, 0x82, 0x55, -0x62, 0xe8, 0x81, 0x35, 0xfb, 0x42, 0x2d, 0x52, 0xfd, 0x9e, 0xeb, 0x5b, 0x20, 0x8d, 0x57, 0x28, -0xd6, 0x18, 0x16, 0x70, 0xc1, 0xb3, 0xab, 0xc6, 0xbb, 0x46, 0x85, 0x79, 0x87, 0xef, 0x1a, 0xb5, -0x8d, 0x8d, 0xe5, 0x59, 0x61, 0x26, 0xb5, 0x9c, 0x0b, 0x16, 0x83, 0x23, 0x5f, 0xf8, 0x0a, 0xec, -0x1e, 0x94, 0x8f, 0x33, 0x97, 0xef, 0x93, 0x38, 0xea, 0xec, 0xc4, 0x35, 0x44, 0x34, 0xa5, 0x57, -0x8f, 0xa1, 0x6f, 0x11, 0x6b, 0x47, 0x5c, 0x89, 0xe6, 0xe1, 0x59, 0x46, 0x4a, 0x14, 0x41, 0x8a, -0x5f, 0x80, 0x94, 0xa6, 0x09, 0xfa, 0x55, 0x6e, 0x39, 0x3b, 0x4d, 0xed, 0xfc, 0xc6, 0x36, 0xc8, -0x0a, 0x4c, 0x07, 0x15, 0xae, 0xbc, 0x00, 0xac, 0xb8, 0xdf, 0xee, 0xb9, 0xc9, 0x48, 0xfe, 0xb2, -0xf0, 0x56, 0x23, 0xc1, 0x4c, 0x22, 0x34, 0x48, 0x65, 0x49, 0xdc, 0xcc, 0xb9, 0x53, 0x66, 0xc1, -0x94, 0x06, 0x51, 0x4f, 0x91, 0x3e, 0x86, 0x9c, 0x6e, 0xc4, 0x96, 0x19, 0xce, 0x96, 0xde, 0xd1, -0x77, 0xbc, 0xc2, 0xbc, 0xb9, 0xdd, 0xb1, 0x26, 0xd4, 0x0d, 0x11, 0x84, 0x8c, 0x46, 0x56, 0x0c, -0xf2, 0xe6, 0xe8, 0x72, 0xbf, 0x79, 0x44, 0x9a, 0x47, 0x57, 0x57, 0xc7, 0x67, 0x9f, 0x9a, 0xc4, -0x44, 0x2f, 0x24, 0xbc, 0x1a, 0x5f, 0x98, 0x08, 0x69, 0xb6, 0x6c, 0x41, 0x79, 0xdc, 0xc3, 0x58, -0x91, 0xa4, 0x4c, 0x8e, 0x1e, 0xd8, 0xc7, 0x7f, 0x35, 0xcf, 0xcf, 0xc8, 0x28, 0xa8, 0xde, 0x23, -0xac, 0x58, 0x73, 0xa9, 0x7b, 0xae, 0x37, 0x2c, 0xef, 0xd3, 0xea, 0xd5, 0x46, 0x16, 0x62, 0x0d, -0x99, 0x00, 0x7e, 0x18, 0x69, 0xb0, 0xb5, 0x8b, 0xf3, 0xe6, 0xd5, 0x58, 0xb0, 0xb5, 0x7e, 0x88, -0xce, 0x97, 0x06, 0xa1, 0xbe, 0xcd, 0xa9, 0xb5, 0x07, 0x7a, 0x9c, 0x1b, 0x5a, 0x51, 0xc2, 0x48, -0x68, 0x1d, 0xf7, 0x37, 0x58, 0xdc, 0xa6, 0x61, 0xb2, 0x9e, 0x46, 0xcf, 0xec, 0x27, 0x1d, 0x16, -0x3d, 0x93, 0xe4, 0xf8, 0x33, 0x85, 0xc4, 0x45, 0xae, 0x8f, 0x6b, 0x11, 0xb0, 0x25, 0x8f, 0xd9, -0xc6, 0xd7, 0x59, 0x07, 0x63, 0x3f, 0x8a, 0xf5, 0x2a, 0x86, 0xb5, 0x97, 0xf3, 0xba, 0xc6, 0xfc, -0x16, 0x1b, 0xaa, 0x16, 0xa7, 0x34, 0xc8, 0x71, 0x2d, 0x9b, 0xcf, 0xf2, 0x98, 0x9e, 0x8d, 0x91, -0xf9, 0xf0, 0xf2, 0xfc, 0x02, 0x3d, 0xca, 0x7b, 0xd7, 0x44, 0xb3, 0xd8, 0x57, 0x7a, 0xe4, 0xfa, -0xd4, 0x75, 0x20, 0xd0, 0xc9, 0xd7, 0xe5, 0xea, 0x17, 0x83, 0x92, 0x35, 0xdd, 0xd2, 0xe4, 0x86, -0xc5, 0xdc, 0x9c, 0x0d, 0x08, 0x29, 0xf8, 0x85, 0x0c, 0x40, 0x48, 0x4c, 0xc6, 0x39, 0x90, 0xc2, -0x18, 0xc3, 0xe2, 0xb1, 0x49, 0x89, 0x89, 0x5a, 0x96, 0x70, 0x1e, 0x2c, 0xa6, 0xb7, 0x65, 0x62, -0x72, 0xef, 0x7a, 0x1e, 0xba, 0x82, 0x45, 0xb4, 0x07, 0xdb, 0x2a, 0xe7, 0x75, 0xe1, 0xf9, 0xb6, -0x44, 0x8a, 0x6a, 0xd3, 0xd1, 0x1c, 0x35, 0xc1, 0x1d, 0x3b, 0x20, 0xf0, 0x26, 0x62, 0x3b, 0x8e, -0x4f, 0x81, 0x47, 0x3b, 0xc9, 0x64, 0x9c, 0xd5, 0xfc, 0xc1, 0x36, 0x45, 0x6c, 0x59, 0xf2, 0x8b, -0x1d, 0x84, 0x43, 0x52, 0xab, 0xd4, 0xea, 0x93, 0x61, 0x2d, 0xfb, 0xde, 0x54, 0x7f, 0x3d, 0x77, -0x6f, 0xa6, 0x01, 0x07, 0xb7, 0xac, 0x91, 0x53, 0xba, 0xbd, 0x2d, 0x7f, 0xfd, 0x57, 0xf7, 0xe1, -0xe8, 0x9f, 0x9b, 0xb5, 0xde, 0x07, 0x45, 0x60, 0x4f, 0x5e, 0x8c, 0xcd, 0x59, 0x19, 0xe0, 0xcc, -0x07, 0x7c, 0xeb, 0x26, 0xdd, 0x7e, 0xbb, 0x64, 0x07, 0xbd, 0xb2, 0xd7, 0xef, 0x59, 0x61, 0x9f, -0x8d, 0x65, 0x16, 0xf2, 0x27, 0x56, 0x6e, 0x16, 0xf0, 0x4e, 0x59, 0xf6, 0x7f, 0x3a, 0xce, 0xa6, -0x5c, 0x40, 0x4c, 0xdc, 0xcf, 0x1f, 0xef, 0x54, 0x83, 0xb9, 0xba, 0x59, 0x86, 0xdf, 0xa0, 0x6b, -0xc4, 0xe5, 0x76, 0xe7, 0xed, 0xdb, 0xda, 0x5b, 0xd0, 0x41, 0x3f, 0x1d, 0x5f, 0x91, 0xe6, 0xe7, -0xfd, 0x6d, 0x22, 0x52, 0xc8, 0xf6, 0x36, 0x91, 0x61, 0x4b, 0xb5, 0x58, 0x61, 0xf3, 0x4f, 0x41, -0xb3, 0x4d, 0xc4, 0x5e, 0x31, 0x17, 0xe6, 0x60, 0x4f, 0x62, 0x25, 0xee, 0x80, 0x62, 0x1f, 0x02, -0x3f, 0x2e, 0x05, 0xd1, 0x2d, 0x54, 0xb4, 0x61, 0x9f, 0x42, 0xa1, 0x43, 0xc3, 0x75, 0xdf, 0x5e, -0x8f, 0xad, 0x72, 0xa3, 0x54, 0x29, 0x3b, 0x94, 0x3a, 0x33, 0x18, 0x25, 0x7b, 0x07, 0x07, 0xe4, -0xc3, 0x3f, 0xd7, 0xcf, 0x0e, 0xd6, 0x9b, 0xfb, 0x04, 0x8a, 0xe5, 0xc0, 0xed, 0x34, 0xed, 0x66, -0x06, 0x73, 0x9e, 0x1c, 0xc2, 0xc0, 0x8a, 0x50, 0x55, 0x3f, 0xf6, 0x07, 0x64, 0x97, 0x54, 0xde, -0xcf, 0xe4, 0x25, 0x31, 0x4f, 0x9f, 0xc9, 0x00, 0xbc, 0x6c, 0xd5, 0x36, 0x37, 0x43, 0x50, 0xab, -0xa1, 0xc4, 0xf5, 0xcc, 0x8a, 0xbb, 0x06, 0xdd, 0xbf, 0x48, 0x0c, 0xdc, 0xbc, 0x96, 0x89, 0x30, -0xed, 0x19, 0xad, 0xe2, 0x6c, 0xb9, 0x0a, 0x94, 0x3a, 0xac, 0x13, 0xf3, 0xd3, 0xc5, 0xf1, 0x79, -0xa5, 0xa0, 0x2c, 0x52, 0x85, 0x22, 0x57, 0xbf, 0xf2, 0x22, 0x55, 0x75, 0x91, 0x1a, 0x42, 0x69, -0xf0, 0x22, 0x35, 0x75, 0x91, 0x3a, 0x14, 0xb9, 0x14, 0x50, 0xea, 0xea, 0x22, 0x0d, 0x84, 0x52, -0xe3, 0x45, 0xe0, 0xbb, 0x79, 0xb8, 0xaf, 0x2e, 0x87, 0x23, 0x3b, 0xac, 0xf2, 0x72, 0xf0, 0xdd, -0x3c, 0x38, 0x51, 0x97, 0xdb, 0x84, 0x72, 0x58, 0x66, 0x53, 0x99, 0xfb, 0x56, 0xe4, 0xbe, 0x55, -0xe6, 0x6e, 0x89, 0xdc, 0x2d, 0x65, 0xee, 0x3b, 0x91, 0xfb, 0x4e, 0x8d, 0xb0, 0x8a, 0xc8, 0xae, -0x56, 0xd4, 0xf9, 0x55, 0x99, 0x5f, 0x55, 0xe7, 0x33, 0x74, 0x6e, 0x0a, 0x8c, 0x6b, 0xf0, 0x59, -0x45, 0x84, 0x1e, 0xbe, 0x15, 0x85, 0x34, 0x18, 0xad, 0x32, 0x94, 0x6e, 0x88, 0x42, 0x0d, 0x4d, -0x21, 0x86, 0xcf, 0x2d, 0x51, 0x68, 0x43, 0x53, 0x08, 0x91, 0x79, 0x58, 0x11, 0x85, 0x36, 0xc9, -0x3a, 0xda, 0xab, 0x8f, 0x2f, 0xff, 0xfb, 0x35, 0x14, 0x9f, 0x28, 0xdd, 0x9a, 0xa2, 0x56, 0x15, -0xe9, 0xd6, 0x6b, 0x4b, 0x21, 0x5c, 0x8e, 0xc4, 0x8a, 0x8e, 0x68, 0xf3, 0x50, 0x2d, 0x07, 0x01, -0x34, 0x77, 0x72, 0x74, 0xa8, 0xa5, 0xdb, 0x3c, 0x84, 0xcb, 0x01, 0x35, 0x74, 0xf4, 0xca, 0xb3, -0x37, 0xf4, 0xd3, 0xcd, 0xa7, 0x9a, 0x98, 0x9f, 0x9b, 0x17, 0xc7, 0xe4, 0xf4, 0xb8, 0x79, 0x9e, -0x31, 0xeb, 0x7c, 0xc6, 0x65, 0xd9, 0xf3, 0xe6, 0x71, 0xc6, 0xe4, 0xf3, 0x89, 0x17, 0x65, 0x61, -0xa5, 0xfc, 0x3d, 0x83, 0x06, 0xf8, 0xfc, 0xeb, 0xa7, 0x9f, 0x4f, 0xbd, 0x3a, 0x5f, 0xae, 0xa6, -0xaa, 0x7a, 0x39, 0x55, 0xe5, 0x7a, 0xaa, 0x02, 0x9d, 0xfd, 0x63, 0x4e, 0x5f, 0xe4, 0xea, 0xaa, -0xbe, 0x13, 0x65, 0xf5, 0xf8, 0xa8, 0xc9, 0xa5, 0x54, 0x03, 0x7e, 0xa0, 0x65, 0x18, 0x35, 0x89, -0xe1, 0x1a, 0x60, 0x58, 0xcb, 0x2e, 0x6a, 0x12, 0xb7, 0xb5, 0xba, 0x6c, 0x57, 0x8b, 0xdb, 0x9a, -0xc4, 0x57, 0x4d, 0x8d, 0xaf, 0x9a, 0xc4, 0x57, 0x4d, 0x8d, 0xaf, 0x9a, 0xc4, 0x57, 0x4d, 0x8d, -0xaf, 0xba, 0xec, 0x71, 0xbd, 0xa6, 0xce, 0x97, 0x7d, 0xad, 0xd7, 0xd5, 0xf9, 0x72, 0xee, 0xeb, -0x0d, 0xe6, 0xba, 0xcb, 0x2c, 0x71, 0xea, 0x92, 0x72, 0x24, 0xf5, 0x8d, 0x79, 0x25, 0x71, 0x4c, -0xff, 0xb8, 0x10, 0x2b, 0x61, 0x13, 0xdf, 0x37, 0xc8, 0x2a, 0x8d, 0xb3, 0xf8, 0x8f, 0x33, 0x51, -0xfa, 0xdd, 0x78, 0xe9, 0x69, 0x7e, 0xa1, 0xe4, 0x10, 0x71, 0x7d, 0x99, 0x3c, 0x82, 0x98, 0x87, -0xe7, 0x67, 0x57, 0xe4, 0x0b, 0x6c, 0xff, 0xd7, 0xc9, 0x87, 0xf3, 0xf3, 0xab, 0x82, 0x9e, 0x6b, -0x30, 0xd2, 0x9b, 0xc3, 0x30, 0xf4, 0xac, 0x82, 0x0d, 0x77, 0x05, 0x5c, 0x62, 0x53, 0x66, 0x6b, -0xa5, 0xd9, 0x1c, 0x71, 0x36, 0x47, 0x9e, 0xad, 0x5c, 0xa0, 0x71, 0x0e, 0x37, 0x8f, 0xab, 0xcd, -0xe3, 0x64, 0xcf, 0xcd, 0xbd, 0xe6, 0x73, 0xac, 0x31, 0x42, 0xfb, 0xd2, 0xfc, 0xb0, 0xae, 0xe1, -0x1f, 0x12, 0xa3, 0xb5, 0xca, 0x74, 0x8d, 0x37, 0x73, 0x39, 0xdd, 0x3c, 0x8e, 0x43, 0xcc, 0x8b, -0xe6, 0xe5, 0xfe, 0x29, 0x93, 0xd1, 0x63, 0xd7, 0xec, 0x0a, 0xf3, 0x38, 0x11, 0x31, 0x3f, 0x9e, -0xec, 0x37, 0x3f, 0xe7, 0xac, 0x27, 0x71, 0x52, 0xdb, 0x5a, 0xac, 0x9e, 0xc4, 0x55, 0xed, 0xdd, -0x42, 0xf5, 0xea, 0x12, 0x63, 0xf5, 0xca, 0x62, 0xf5, 0x24, 0xde, 0xea, 0xd5, 0xc5, 0xea, 0x8d, -0x38, 0xf0, 0x62, 0xf5, 0x46, 0x9c, 0x99, 0x1b, 0x18, 0x29, 0xec, 0xe2, 0x63, 0x76, 0x24, 0x4f, -0xbe, 0x5e, 0x9e, 0x9f, 0x9f, 0x8a, 0x9b, 0xf5, 0x71, 0x61, 0x3e, 0xe3, 0x7e, 0x44, 0xf5, 0x11, -0x37, 0xd7, 0xf3, 0x70, 0xce, 0xbf, 0xd5, 0xf9, 0x92, 0x1a, 0xea, 0x1a, 0xb9, 0x24, 0x67, 0xbd, -0xbe, 0xa5, 0xe7, 0xfa, 0x9c, 0xe3, 0xab, 0x79, 0xa0, 0x9c, 0xc5, 0x86, 0x9a, 0x93, 0x34, 0xe4, -0x6c, 0x35, 0xd4, 0x54, 0xde, 0x90, 0xb3, 0xd2, 0x50, 0x73, 0x92, 0x86, 0xc4, 0x7e, 0x43, 0xc3, -0x83, 0x25, 0x7a, 0x1b, 0x6a, 0x4e, 0xd2, 0x90, 0xf8, 0x6b, 0x6c, 0x4c, 0xac, 0xcb, 0xe6, 0xd5, -0xe5, 0xfe, 0xc5, 0xc5, 0xf1, 0xd9, 0x27, 0x02, 0x7f, 0x69, 0x94, 0x40, 0x89, 0xda, 0xc6, 0xe6, -0xc2, 0x55, 0x25, 0xd6, 0x1b, 0x6a, 0xac, 0x37, 0x24, 0xd6, 0x1b, 0x33, 0x58, 0x9f, 0x12, 0x9f, -0x33, 0xb2, 0xd4, 0xa3, 0xce, 0x4d, 0x17, 0x36, 0xfb, 0x37, 0x68, 0x6c, 0x1d, 0x50, 0xb5, 0x3c, -0xc5, 0x49, 0xf1, 0x82, 0x7b, 0xc2, 0xcb, 0x68, 0x37, 0x81, 0x08, 0x47, 0x53, 0x66, 0x5a, 0xeb, -0xb7, 0x61, 0xef, 0x9d, 0x90, 0x08, 0xdb, 0x2b, 0x57, 0x01, 0x7e, 0xb5, 0x58, 0x6f, 0x81, 0xf8, -0x6c, 0x14, 0x37, 0x8b, 0x5b, 0x2d, 0x00, 0x06, 0x9f, 0xad, 0xd2, 0x5f, 0xcb, 0x53, 0xb5, 0xee, -0x5d, 0xdf, 0x09, 0xee, 0x4b, 0xa0, 0x26, 0x04, 0x96, 0x03, 0x55, 0x3b, 0x7d, 0x9f, 0x99, 0x88, -0xcd, 0x02, 0xf9, 0x7d, 0xa6, 0x4b, 0x9d, 0x20, 0x32, 0xdd, 0x04, 0x7d, 0x64, 0x1c, 0xf1, 0x70, -0x4a, 0x09, 0x76, 0xf2, 0x47, 0x1e, 0xc5, 0xcf, 0xf8, 0xc3, 0xf0, 0x00, 0x2d, 0x1d, 0xf8, 0x52, -0x84, 0x39, 0x75, 0xaa, 0x5e, 0x50, 0x41, 0xc3, 0x3f, 0x6e, 0x52, 0xb2, 0x1c, 0xe7, 0x68, 0x00, -0xf5, 0x4f, 0xdc, 0x38, 0xc1, 0xf0, 0x10, 0xa6, 0xc1, 0x2c, 0xa7, 0x46, 0x31, 0xbb, 0x2f, 0xf2, -0x0f, 0x46, 0xc8, 0x2b, 0x31, 0x13, 0x0b, 0x02, 0x28, 0x25, 0xc1, 0xed, 0xad, 0x07, 0xed, 0x0b, -0x9c, 0x15, 0xde, 0x6b, 0x2b, 0xe2, 0x54, 0x89, 0x23, 0x7b, 0x18, 0x37, 0x03, 0xe3, 0xd3, 0x07, -0x39, 0x9a, 0x26, 0xf4, 0xdb, 0xf5, 0x6f, 0xf5, 0xd5, 0x45, 0xd5, 0x12, 0x7f, 0xbc, 0xca, 0x11, -0x27, 0xf3, 0xbb, 0xc4, 0xd4, 0x64, 0xec, 0xee, 0x12, 0xa3, 0xed, 0x05, 0x30, 0xb0, 0x02, 0xf9, -0x1b, 0x31, 0xfc, 0xc0, 0xa7, 0x06, 0xd9, 0x96, 0x69, 0xea, 0x76, 0x7e, 0x28, 0xba, 0xff, 0x63, -0xf6, 0x40, 0x4e, 0x31, 0x19, 0x1f, 0x86, 0xc7, 0x8e, 0x39, 0x7a, 0x47, 0xa5, 0xa0, 0xc0, 0xb2, -0x38, 0x9e, 0xca, 0x81, 0x66, 0xc4, 0x14, 0x33, 0x7f, 0xa3, 0x6e, 0x98, 0x36, 0xf6, 0x5b, 0x9f, -0x46, 0x43, 0x1e, 0x53, 0x28, 0x88, 0xf6, 0x3d, 0xcf, 0x34, 0x58, 0x99, 0x6b, 0x66, 0x84, 0x59, -0xe3, 0xc7, 0xa5, 0x6b, 0x2d, 0xdd, 0x0c, 0x60, 0xa4, 0x44, 0x93, 0x01, 0x66, 0xe6, 0x16, 0xf8, -0x67, 0x47, 0xb4, 0x51, 0xe2, 0x31, 0xb6, 0x20, 0xe9, 0xcd, 0x9b, 0xac, 0x89, 0x77, 0x3b, 0xa8, -0x3c, 0x63, 0x8d, 0x6b, 0xb7, 0x55, 0x62, 0xc6, 0xd8, 0x12, 0x7b, 0x2f, 0xeb, 0xbc, 0x63, 0x1a, -0x45, 0xc0, 0xf2, 0xeb, 0x5d, 0xb2, 0x5e, 0x2d, 0x64, 0xda, 0x5e, 0xa7, 0xea, 0x43, 0x57, 0xa6, -0x21, 0x46, 0x14, 0xa6, 0xcf, 0xa6, 0x08, 0x11, 0x96, 0x63, 0x49, 0x37, 0x9c, 0x1f, 0xaf, 0xe6, -0xcd, 0xdd, 0xd4, 0xbc, 0x69, 0xe7, 0x4c, 0x04, 0xc8, 0x29, 0x3c, 0x76, 0x5d, 0xb8, 0x83, 0xcf, -0x49, 0xcf, 0x63, 0x76, 0xeb, 0x12, 0x8b, 0x23, 0x69, 0xae, 0xfd, 0x6e, 0x50, 0xe6, 0x3e, 0xe0, -0x18, 0xdb, 0x49, 0xd4, 0xa7, 0x45, 0x03, 0xcf, 0x4a, 0x8c, 0x6d, 0x03, 0xc6, 0xc4, 0x9f, 0xab, -0xe2, 0xdf, 0x22, 0xac, 0x4c, 0x6c, 0x6c, 0x6f, 0xe2, 0x8f, 0x9b, 0x9e, 0xf5, 0xc0, 0x5c, 0x21, -0xb6, 0x81, 0x99, 0xa4, 0xff, 0x6b, 0xb1, 0x2c, 0x0e, 0xe0, 0x1a, 0x6b, 0x4d, 0xfc, 0x9f, 0xe7, -0x0e, 0xd1, 0x2a, 0x0d, 0xeb, 0x7f, 0xba, 0xea, 0x8f, 0xb5, 0xc2, 0x34, 0x52, 0x0a, 0x53, 0xec, -0x48, 0x0e, 0x8d, 0x58, 0xa1, 0x7b, 0xd0, 0xfe, 0xea, 0x76, 0x5c, 0x33, 0x68, 0x7f, 0x57, 0x8d, -0x93, 0xed, 0x5a, 0xc6, 0xe9, 0x71, 0x1a, 0x91, 0x69, 0x2c, 0x63, 0xc5, 0x94, 0xc5, 0xd4, 0x3b, -0xa4, 0x1e, 0x10, 0xed, 0x79, 0x98, 0x98, 0x54, 0x51, 0xc0, 0xed, 0x60, 0xbb, 0xd7, 0x86, 0x38, -0x83, 0x36, 0x5a, 0x6a, 0x3a, 0xa2, 0x25, 0x7c, 0x08, 0xc9, 0x77, 0x0e, 0xba, 0xae, 0xe7, 0xa0, -0xfb, 0xa9, 0x89, 0xc1, 0x8e, 0x81, 0x50, 0x58, 0x44, 0x63, 0xbc, 0xdc, 0x50, 0x2a, 0x01, 0xcd, -0xcc, 0x56, 0x06, 0x34, 0xd3, 0xc5, 0x20, 0x1e, 0x45, 0x51, 0x10, 0x01, 0xbf, 0x20, 0x6f, 0x08, -0xeb, 0x19, 0xc5, 0xdf, 0xd0, 0xaf, 0x6c, 0x32, 0x9b, 0xc4, 0xe7, 0x59, 0x12, 0x3e, 0x1a, 0x9d, -0x13, 0xd7, 0xfd, 0x9e, 0x82, 0x31, 0x17, 0x88, 0x2c, 0xfa, 0x7c, 0x75, 0x7a, 0x02, 0xad, 0x19, -0x68, 0x33, 0xc6, 0xbb, 0xf2, 0xf4, 0x81, 0xda, 0xfd, 0x84, 0x3a, 0x45, 0x3c, 0x7a, 0x21, 0x3e, -0xbd, 0xe7, 0x21, 0x08, 0x10, 0x7b, 0xef, 0x17, 0x41, 0xde, 0x04, 0x70, 0x0d, 0xca, 0x16, 0x43, -0x58, 0x6d, 0x65, 0x18, 0x43, 0x00, 0x78, 0x4b, 0x10, 0x60, 0xe0, 0x80, 0x0f, 0xe1, 0x93, 0xa3, -0x30, 0x89, 0x6f, 0xfc, 0xe0, 0xde, 0x68, 0x91, 0xbf, 0x92, 0x6a, 0xa5, 0x52, 0x51, 0x54, 0x9d, -0x1a, 0x28, 0xde, 0xe3, 0x04, 0x7d, 0x15, 0x63, 0xc4, 0xe2, 0x60, 0x93, 0xe0, 0x38, 0x0e, 0x10, -0x5c, 0x33, 0x89, 0x4c, 0x6c, 0xa1, 0x00, 0x89, 0x40, 0x43, 0x8e, 0xdb, 0xe9, 0xd0, 0x88, 0x42, -0x59, 0x5e, 0xce, 0x04, 0x86, 0xbe, 0x4e, 0x26, 0x9a, 0x64, 0x25, 0x7b, 0xb1, 0xb1, 0x00, 0x8e, -0xd0, 0xf9, 0xef, 0xe9, 0x38, 0x62, 0x2e, 0x84, 0x2b, 0x23, 0xab, 0xe7, 0x22, 0xa2, 0xf4, 0x92, -0xaf, 0x06, 0x37, 0xd3, 0xd3, 0xaf, 0xa1, 0x12, 0x68, 0x58, 0x94, 0x3a, 0x6f, 0x7f, 0x07, 0x79, -0xab, 0x2a, 0x07, 0x65, 0x4a, 0x76, 0xcf, 0x61, 0xe4, 0x40, 0x93, 0x1b, 0x5c, 0x3e, 0x86, 0xba, -0x14, 0x3a, 0xfd, 0xee, 0xf2, 0x18, 0xc3, 0xc7, 0x7e, 0xc2, 0x08, 0x04, 0xe7, 0x45, 0x74, 0xb4, -0xac, 0xa3, 0x39, 0x28, 0xb2, 0xff, 0xdd, 0x7a, 0x30, 0xd9, 0xb3, 0x7c, 0xfc, 0xcd, 0x42, 0xa0, -0x29, 0xb9, 0x4c, 0x80, 0x43, 0x31, 0x0f, 0x83, 0x22, 0xf3, 0xb5, 0x00, 0xe5, 0x07, 0xaf, 0x76, -0xb9, 0x9d, 0x21, 0xa3, 0x0c, 0x25, 0x07, 0x66, 0x0d, 0x06, 0xfd, 0xc4, 0x1c, 0x17, 0x67, 0xb2, -0x91, 0x35, 0xd6, 0x08, 0x13, 0xe7, 0x6b, 0xa3, 0x46, 0x6a, 0x85, 0x1f, 0x45, 0x52, 0x9b, 0xed, -0x9e, 0x16, 0xfd, 0xec, 0x49, 0x00, 0x0d, 0xee, 0x17, 0x45, 0x2a, 0xc0, 0xba, 0xc1, 0xe7, 0xf2, -0x8c, 0x85, 0x50, 0x83, 0x22, 0x6c, 0x25, 0xb8, 0x61, 0xad, 0x94, 0xa5, 0x90, 0x03, 0x24, 0x79, -0xa0, 0x27, 0xc8, 0xc7, 0x04, 0x10, 0x4f, 0x1b, 0x0b, 0xe0, 0x29, 0xbd, 0x07, 0xbe, 0x24, 0x5c, -0x01, 0xbc, 0x1b, 0x1f, 0xb8, 0xde, 0x9f, 0x83, 0x8a, 0x54, 0x9e, 0xd2, 0xcb, 0x41, 0x94, 0x23, -0xc1, 0xde, 0xd8, 0x9d, 0xdb, 0xc5, 0xb0, 0x85, 0x0c, 0x73, 0x11, 0x74, 0xe9, 0x46, 0xc7, 0xfd, -0x53, 0x14, 0xc3, 0xd1, 0xf2, 0x6c, 0xe6, 0x57, 0x54, 0x28, 0xf1, 0xfd, 0x83, 0x8e, 0x65, 0x65, -0x72, 0x7d, 0xe9, 0x29, 0xad, 0x94, 0x6c, 0x42, 0xe3, 0x66, 0x0a, 0x10, 0x08, 0x2b, 0x13, 0x3d, -0x28, 0x4c, 0xe1, 0xd8, 0x83, 0xf1, 0xac, 0x22, 0xe4, 0xe7, 0x79, 0x47, 0xe7, 0x50, 0xef, 0x78, -0xa0, 0x9d, 0x2d, 0xd7, 0x91, 0x3b, 0x3f, 0xd7, 0xc1, 0xf1, 0x70, 0x04, 0x9a, 0xb0, 0x37, 0x97, -0x89, 0x7c, 0x2f, 0xb2, 0x5e, 0x57, 0xf4, 0x54, 0x37, 0x3a, 0xd7, 0x29, 0x94, 0xb8, 0x03, 0x88, -0x99, 0xb3, 0x93, 0x3d, 0xef, 0xa0, 0x0d, 0xd5, 0x40, 0x40, 0xa3, 0x3b, 0x89, 0xdd, 0xbd, 0xdb, -0xed, 0x58, 0x20, 0x9d, 0x74, 0xbd, 0xb6, 0xdb, 0xd0, 0xeb, 0x9e, 0xdc, 0x6f, 0xc1, 0xe4, 0xff, -0x8e, 0x5b, 0x2e, 0x10, 0x51, 0xa9, 0xf3, 0x62, 0x11, 0x46, 0xb6, 0x4d, 0x10, 0x22, 0x2a, 0xea, -0xf8, 0x05, 0x14, 0x6f, 0x68, 0xc4, 0x2b, 0xb4, 0xa7, 0x96, 0xa9, 0x76, 0xbb, 0x24, 0xdd, 0x1e, -0x01, 0x4b, 0xb0, 0x71, 0x98, 0xad, 0x1e, 0x01, 0x45, 0x46, 0x3e, 0xeb, 0x8c, 0xe3, 0x0e, 0xb0, -0x2b, 0x6c, 0x27, 0x0e, 0x7d, 0x49, 0xbd, 0x79, 0xa1, 0xe5, 0x6b, 0x25, 0x78, 0x45, 0xa5, 0x29, -0xaf, 0xd0, 0x1f, 0x0c, 0x23, 0x85, 0xe2, 0x22, 0xd5, 0xc7, 0xdc, 0x3e, 0xa1, 0xba, 0xdd, 0x9e, -0x1d, 0x5a, 0x2b, 0xf7, 0xac, 0x1c, 0x99, 0x6c, 0x42, 0x94, 0x13, 0xb1, 0x82, 0x91, 0xcf, 0x78, -0x49, 0x3d, 0x66, 0xfc, 0xe3, 0xfe, 0x51, 0x3f, 0xb0, 0xef, 0x8f, 0x1e, 0x3f, 0x90, 0xf5, 0xc7, -0x88, 0x52, 0xa0, 0xe8, 0xcc, 0xe5, 0x53, 0x99, 0xa5, 0x0a, 0xe6, 0xbb, 0x0f, 0x04, 0x0d, 0x5b, -0x7a, 0xee, 0x69, 0xa1, 0xb5, 0xfe, 0x74, 0x4c, 0xbf, 0xef, 0x81, 0x36, 0x92, 0xc1, 0x2b, 0x5c, -0x7f, 0x80, 0xba, 0x17, 0xac, 0x2a, 0xfd, 0x56, 0x5e, 0x4c, 0x86, 0xeb, 0xa8, 0x37, 0xe7, 0xae, -0xf3, 0xe6, 0x8d, 0xca, 0x90, 0xa2, 0x01, 0x83, 0x5d, 0xca, 0x87, 0x22, 0xb1, 0xd7, 0xce, 0x50, -0x7e, 0x19, 0x8a, 0xc6, 0x30, 0xa9, 0x5c, 0x81, 0x12, 0x07, 0x30, 0x46, 0x0d, 0xa2, 0x80, 0xf3, -0x7f, 0x46, 0x3e, 0x2d, 0xad, 0x03, 0x45, 0xb6, 0x1e, 0x35, 0xb6, 0x08, 0x3e, 0x8c, 0x5c, 0x96, -0x23, 0xd6, 0xc5, 0x81, 0x60, 0x27, 0x82, 0x9a, 0x90, 0x75, 0x8c, 0xb0, 0x0e, 0x34, 0x84, 0xdd, -0x5b, 0x80, 0xff, 0x8d, 0x82, 0x16, 0x17, 0x26, 0xf6, 0xb2, 0xee, 0x40, 0x35, 0xfa, 0xc1, 0x44, -0x19, 0x20, 0x77, 0xd3, 0x48, 0x6f, 0xf2, 0xc9, 0x79, 0x57, 0x54, 0x63, 0xd2, 0x33, 0xed, 0xe4, -0x7b, 0xf5, 0xc8, 0x2c, 0xc7, 0x89, 0xa6, 0x59, 0xa5, 0x64, 0x88, 0xb8, 0xcf, 0x61, 0x17, 0xbd, -0x8b, 0x44, 0x2e, 0x1f, 0x76, 0xd1, 0xb1, 0x48, 0x04, 0x33, 0x15, 0xfe, 0xfe, 0x45, 0x24, 0xe1, -0x6d, 0x52, 0xad, 0x6f, 0xbd, 0x93, 0x7f, 0x8a, 0xdc, 0xf3, 0x6f, 0x9b, 0xef, 0x07, 0x84, 0x05, -0xa5, 0x35, 0x42, 0x94, 0x7e, 0x90, 0xa6, 0x66, 0x25, 0x33, 0xf6, 0x8f, 0x3d, 0xe2, 0xd7, 0x3c, -0x70, 0xbb, 0x7f, 0x00, 0x3b, 0x98, 0xbe, 0xef, 0xda, 0xec, 0xf1, 0x2f, 0x92, 0xa6, 0xf3, 0x2d, -0x88, 0xb0, 0xe6, 0xb4, 0xb4, 0xac, 0xe1, 0xc8, 0x34, 0xc4, 0x8b, 0x86, 0x67, 0x6c, 0x18, 0xc4, -0x04, 0xbe, 0xe0, 0xb8, 0xb7, 0x6e, 0x12, 0x17, 0xfe, 0x8a, 0x1a, 0x04, 0x8c, 0x7c, 0x76, 0x39, -0xa9, 0xfa, 0x7e, 0xbd, 0x76, 0x47, 0x87, 0xfd, 0x10, 0xd4, 0xa7, 0x35, 0x7e, 0x55, 0x72, 0xad, -0x55, 0x02, 0x05, 0xe0, 0xc8, 0xb2, 0xbb, 0x23, 0x95, 0x8b, 0x0e, 0x12, 0x1d, 0xe5, 0x62, 0x4b, -0xb3, 0xa6, 0x2c, 0xa8, 0x50, 0x24, 0x26, 0x30, 0xd6, 0xdd, 0xbd, 0x0c, 0x0b, 0x1f, 0xce, 0x21, -0x47, 0x2f, 0xcc, 0x22, 0x03, 0xc4, 0x6d, 0x72, 0xe3, 0x92, 0xba, 0x31, 0xc7, 0xc2, 0x8b, 0x71, -0x95, 0x95, 0x4c, 0x6a, 0xdc, 0xa6, 0xcd, 0x96, 0xc1, 0x6e, 0xe5, 0xbd, 0xbb, 0xb3, 0xf9, 0x7e, -0x8e, 0xd5, 0x71, 0x7c, 0x35, 0x02, 0x5f, 0x31, 0x4e, 0x03, 0xe7, 0xe2, 0x3e, 0x32, 0xde, 0xb8, -0x99, 0x4b, 0x52, 0x53, 0x13, 0x4d, 0xe5, 0x8f, 0xa9, 0xca, 0xc2, 0x10, 0x1e, 0x04, 0xb9, 0x9a, -0xfd, 0xf1, 0x6a, 0x1e, 0x44, 0xe6, 0x9d, 0xfd, 0x66, 0x6c, 0x30, 0x73, 0x61, 0x2a, 0x6b, 0xb2, -0xc1, 0x3c, 0xa2, 0x6a, 0x3a, 0x98, 0xb4, 0x6e, 0x86, 0xc9, 0xd7, 0xe4, 0xf4, 0x50, 0x42, 0x8f, -0xf4, 0xfd, 0xc4, 0xac, 0x14, 0x90, 0x6f, 0x56, 0xe7, 0x4d, 0x18, 0xd4, 0x9b, 0xaa, 0x58, 0x65, -0x15, 0xa1, 0xfa, 0xbf, 0xff, 0x4d, 0x94, 0x59, 0x55, 0x7d, 0x56, 0xbd, 0x30, 0xaf, 0x3d, 0x75, -0x9b, 0x75, 0x3d, 0x60, 0x9e, 0x55, 0xd3, 0x67, 0x35, 0x72, 0xb5, 0xc9, 0x10, 0x7c, 0xef, 0x26, -0xb0, 0x36, 0x27, 0x81, 0xd4, 0x72, 0x57, 0x67, 0x9c, 0x5d, 0xdc, 0x4b, 0xce, 0x5d, 0xc1, 0xb6, -0x62, 0x4a, 0x8c, 0x9a, 0xb1, 0x2d, 0x96, 0x5b, 0xf5, 0x3d, 0x69, 0x47, 0xd4, 0xba, 0x7b, 0xbf, -0x20, 0x84, 0x46, 0x0a, 0xa1, 0xf6, 0x48, 0x08, 0x9b, 0x29, 0x84, 0xc6, 0x23, 0x21, 0x6c, 0xa5, -0x10, 0x36, 0x17, 0x82, 0xf0, 0xe3, 0xd5, 0xd3, 0x4a, 0xfc, 0xc8, 0x58, 0xc1, 0x59, 0x0b, 0x02, -0xfb, 0xfa, 0x9a, 0x91, 0x72, 0xf6, 0x04, 0x4f, 0xf2, 0x39, 0xa8, 0x95, 0x87, 0xd3, 0x65, 0x70, -0x3b, 0xbe, 0x45, 0x79, 0xbf, 0x68, 0xf5, 0x94, 0xe5, 0x3d, 0xa6, 0xfe, 0x04, 0xdf, 0xcb, 0x03, -0xe0, 0x47, 0x2e, 0x96, 0xaa, 0x60, 0x80, 0x79, 0x80, 0x67, 0x71, 0xc1, 0xc7, 0xd5, 0x1f, 0x63, -0x85, 0xf3, 0x00, 0xfc, 0xd0, 0x1c, 0x18, 0x2a, 0xcf, 0xa1, 0x32, 0x34, 0x12, 0xa6, 0x2b, 0x60, -0xa7, 0x51, 0x2d, 0x00, 0x2d, 0x49, 0x28, 0x22, 0x62, 0x18, 0x4c, 0xdd, 0x60, 0x87, 0x3d, 0xad, -0x22, 0x41, 0x97, 0x9f, 0x6b, 0xae, 0x25, 0xb5, 0xb8, 0xb2, 0x53, 0x4c, 0x95, 0x26, 0xe3, 0xfa, -0xdb, 0xb7, 0xf5, 0x6f, 0x63, 0x71, 0x20, 0x4a, 0xdf, 0xbe, 0x95, 0xff, 0x22, 0xc3, 0x40, 0x40, -0xfe, 0xe4, 0x95, 0xff, 0x42, 0x41, 0xd5, 0x2b, 0x49, 0xa2, 0xdf, 0xf1, 0x84, 0x59, 0xbd, 0x75, -0xba, 0x1e, 0x4d, 0xd1, 0xf8, 0x11, 0x15, 0xfc, 0xc2, 0xf0, 0xf2, 0xa7, 0xfc, 0x01, 0x85, 0x0b, -0x7c, 0x40, 0x81, 0x98, 0x5f, 0xc3, 0x02, 0x64, 0xa0, 0xf7, 0xc1, 0x35, 0x74, 0x08, 0xba, 0xd1, -0x2a, 0xea, 0x61, 0x8a, 0x01, 0xa7, 0x87, 0x5b, 0x08, 0x91, 0x43, 0x13, 0x39, 0x38, 0x7a, 0x1c, -0xb3, 0x16, 0xc8, 0xd8, 0xe4, 0x4d, 0x1e, 0x82, 0xc1, 0x6f, 0x1e, 0x37, 0xf8, 0x2a, 0x48, 0xd8, -0x0b, 0xdf, 0x51, 0xc4, 0x5f, 0xb9, 0x21, 0xd7, 0x77, 0x5f, 0xbb, 0x2d, 0xc8, 0xdf, 0x12, 0x08, -0x64, 0xf1, 0x33, 0xb0, 0xa3, 0x2d, 0x5c, 0x98, 0xda, 0xb3, 0x58, 0x1b, 0xf5, 0x21, 0x33, 0xa2, -0xa5, 0x84, 0xc6, 0x89, 0x39, 0xa1, 0x85, 0x16, 0xd8, 0xe1, 0x32, 0x3b, 0x58, 0x66, 0x96, 0x1d, -0x43, 0x23, 0x4d, 0x5d, 0xbd, 0x52, 0x64, 0x45, 0xd1, 0xb1, 0x8f, 0x4e, 0x0b, 0x2d, 0xed, 0xc9, -0xad, 0x70, 0x02, 0xc0, 0x96, 0xbf, 0x5f, 0x57, 0x79, 0x6f, 0x75, 0x84, 0xca, 0xc0, 0x95, 0xc2, -0x7e, 0xdc, 0x35, 0x35, 0x5b, 0xd6, 0x3a, 0x81, 0x9d, 0xea, 0xbc, 0x63, 0x5a, 0x4e, 0x97, 0xdf, -0xaf, 0x2b, 0x2d, 0xd4, 0xf8, 0x81, 0x54, 0x41, 0x81, 0xfc, 0x7e, 0x5d, 0x07, 0x42, 0xbc, 0x6e, -0x15, 0xc9, 0x54, 0xa6, 0xa4, 0xca, 0xef, 0xd7, 0x8d, 0xd6, 0x2c, 0xed, 0x69, 0x9b, 0x2a, 0x64, -0xac, 0x37, 0x57, 0xb5, 0x85, 0xcc, 0xe0, 0xce, 0x73, 0x74, 0x7e, 0xcd, 0x0e, 0x7e, 0xe6, 0xc1, -0x48, 0x18, 0x8f, 0xed, 0x71, 0x73, 0x0e, 0x63, 0x13, 0x6c, 0xbb, 0x23, 0xc6, 0xaa, 0xb5, 0x2f, -0x3c, 0xc2, 0xce, 0xf0, 0xfd, 0xba, 0xa6, 0xdb, 0x4d, 0x2c, 0x64, 0x70, 0x98, 0xcb, 0xce, 0xd5, -0x83, 0xc6, 0x2e, 0x30, 0x42, 0xc9, 0x3e, 0xae, 0xd7, 0xe7, 0x6a, 0x8e, 0x85, 0x0a, 0xb9, 0x77, -0xc1, 0x0e, 0xf5, 0xa6, 0xb7, 0x8a, 0xb2, 0x7f, 0x78, 0x57, 0x17, 0xfe, 0x3b, 0xa4, 0xde, 0x68, -0x77, 0x28, 0x6e, 0x00, 0x4a, 0x43, 0xdb, 0x1b, 0xc3, 0x61, 0xb9, 0x62, 0x63, 0x68, 0xfc, 0x6a, -0x64, 0xec, 0x9b, 0xa9, 0x97, 0x71, 0xb6, 0xcf, 0x0c, 0x96, 0x59, 0x1b, 0x65, 0xce, 0xb1, 0xa1, -0x33, 0x34, 0xa1, 0xbc, 0x7c, 0x5e, 0x5b, 0xa8, 0x3b, 0xf8, 0xe4, 0x05, 0x6d, 0x9d, 0xb5, 0x22, -0xd5, 0x0f, 0x18, 0xf3, 0xbd, 0x9e, 0x78, 0x65, 0xa4, 0x88, 0x7b, 0x6d, 0xf1, 0x8d, 0x2b, 0x6e, -0xf4, 0xb2, 0x06, 0xe4, 0x88, 0x37, 0x3d, 0x78, 0x86, 0x08, 0x4a, 0x0e, 0xc9, 0xe2, 0xab, 0xa5, -0x99, 0x19, 0xb5, 0x03, 0x11, 0xf3, 0x1d, 0x72, 0x81, 0xb6, 0x0b, 0xf0, 0x5f, 0xea, 0x93, 0x81, -0x7c, 0xc6, 0x45, 0x3e, 0xf3, 0x7e, 0x4e, 0xaf, 0x0d, 0x0c, 0xac, 0xcf, 0x37, 0xcf, 0xec, 0x9d, -0x06, 0xf8, 0x4c, 0x5f, 0x21, 0xe0, 0x22, 0x02, 0x0b, 0x2c, 0xde, 0x23, 0x11, 0xb9, 0x1f, 0x84, -0x34, 0xeb, 0xd7, 0xc8, 0x2a, 0xca, 0x78, 0x6f, 0x04, 0x39, 0xb8, 0x2e, 0x5b, 0xb9, 0x6c, 0x24, -0x29, 0xcc, 0xb1, 0x28, 0xf7, 0x2a, 0xa8, 0x63, 0xd9, 0x39, 0x0f, 0x1b, 0xd9, 0x89, 0x5e, 0x73, -0x18, 0xe7, 0x9d, 0x61, 0x7e, 0xd9, 0x1e, 0x11, 0xc3, 0xbf, 0x6e, 0xa4, 0xa0, 0xbf, 0xe6, 0x2f, -0x05, 0xa3, 0x1b, 0x03, 0xfe, 0xcb, 0x52, 0xc4, 0xc3, 0xea, 0x90, 0x26, 0xbe, 0x56, 0x3c, 0xb1, -0x59, 0x98, 0x63, 0xef, 0xf5, 0xaa, 0x70, 0xc6, 0x32, 0x16, 0x04, 0xe6, 0x58, 0xd1, 0x1d, 0xbe, -0x68, 0xa0, 0x04, 0x88, 0x99, 0x37, 0x3d, 0xcc, 0x5d, 0x74, 0x72, 0x01, 0x90, 0xc3, 0x83, 0x1a, -0xa8, 0x67, 0x17, 0xf3, 0x6f, 0x44, 0x74, 0x01, 0x05, 0x6c, 0xcd, 0xf1, 0x49, 0x0a, 0x3f, 0x7d, -0x2d, 0x0e, 0x81, 0x2b, 0x8d, 0x8a, 0xaf, 0x59, 0x3b, 0x50, 0x04, 0xaf, 0xba, 0xea, 0x8f, 0xcd, -0xe5, 0x54, 0x18, 0x86, 0xc6, 0x41, 0x21, 0xeb, 0x1c, 0x67, 0xf4, 0xea, 0x9b, 0xe6, 0x14, 0xc8, -0x42, 0x3d, 0x02, 0xe4, 0xaf, 0x43, 0xf1, 0x50, 0xc2, 0x38, 0x41, 0x97, 0x3c, 0xf8, 0xf7, 0x2b, -0x6d, 0x0b, 0x85, 0x05, 0x7e, 0xc8, 0x6b, 0xf9, 0xf8, 0xfd, 0x25, 0x64, 0x61, 0x93, 0x31, 0x95, -0x05, 0x66, 0x56, 0xa1, 0x86, 0x9d, 0x2e, 0x79, 0x1a, 0x05, 0x65, 0x44, 0xe3, 0xa9, 0x57, 0xd9, -0x66, 0xa6, 0x27, 0x19, 0xd3, 0xa7, 0xba, 0x77, 0xa8, 0x50, 0x71, 0x4d, 0x6a, 0x34, 0xa6, 0x16, -0xf9, 0x85, 0x98, 0x55, 0xb2, 0xb3, 0x43, 0xdc, 0x02, 0xdb, 0x84, 0xa7, 0x3f, 0xd4, 0x9a, 0x00, -0xf0, 0x75, 0xa1, 0xe6, 0x1c, 0xb4, 0x39, 0x6e, 0xf8, 0x4b, 0xac, 0x4c, 0x25, 0xb1, 0xae, 0xdd, -0x16, 0x3b, 0xdb, 0x51, 0x98, 0xb1, 0x67, 0x75, 0x79, 0x47, 0x32, 0xfb, 0x52, 0xa9, 0x44, 0xbd, -0xc2, 0x02, 0xeb, 0x9f, 0xbd, 0xb0, 0xe5, 0xda, 0x3a, 0x1e, 0xc0, 0xca, 0x9c, 0x59, 0x03, 0x96, -0xff, 0x5e, 0x9d, 0x7d, 0xd4, 0xbc, 0xc8, 0xca, 0xbe, 0x04, 0xa6, 0x20, 0xf2, 0x67, 0x0a, 0x30, -0x0f, 0xc1, 0x09, 0x87, 0x12, 0xc5, 0xe9, 0x00, 0xf7, 0x38, 0x05, 0xaa, 0x94, 0xf2, 0xc5, 0x34, -0x12, 0x10, 0x7e, 0x26, 0x6a, 0xeb, 0xd5, 0xfc, 0xc7, 0xb2, 0x9c, 0xdd, 0xb1, 0x17, 0x9e, 0x8f, -0xc3, 0xdc, 0x52, 0x2d, 0x14, 0x46, 0x5f, 0xf8, 0x12, 0xa2, 0x8c, 0xbf, 0x97, 0x0b, 0x29, 0x7c, -0xd2, 0x79, 0x1a, 0x7b, 0x29, 0x16, 0x39, 0x23, 0xfe, 0x3b, 0x4a, 0xab, 0x89, 0xb4, 0x9a, 0x4c, -0x93, 0x6f, 0x83, 0x42, 0xf2, 0xad, 0xf8, 0xd4, 0x31, 0x46, 0x69, 0xe8, 0x7f, 0x3d, 0xc6, 0xf7, -0xf4, 0x0a, 0xcd, 0x12, 0xd8, 0x68, 0x26, 0xe2, 0x8e, 0x07, 0x3a, 0x94, 0xa5, 0x97, 0x63, 0xd9, -0x3c, 0xe2, 0x0e, 0xcb, 0xef, 0xf7, 0x6e, 0xd2, 0x48, 0x4c, 0x46, 0xbe, 0x55, 0x87, 0x87, 0xdc, -0x69, 0xa8, 0xbb, 0x71, 0x8f, 0x4e, 0x8d, 0xb6, 0x2c, 0x0f, 0x52, 0xd2, 0x4a, 0xb0, 0x5e, 0x94, -0x6a, 0x50, 0xaa, 0xc3, 0x2c, 0x30, 0xd8, 0x2c, 0x17, 0xa5, 0x69, 0x0a, 0x91, 0xf4, 0xd1, 0x66, -0x41, 0x67, 0xf9, 0x3c, 0xb3, 0xa0, 0xa8, 0x90, 0xc6, 0x42, 0x3b, 0xb0, 0x94, 0x34, 0x36, 0x28, -0x6e, 0xf6, 0xe4, 0x37, 0xcb, 0x61, 0x71, 0x32, 0x21, 0xb5, 0x1f, 0xa7, 0xb5, 0xb9, 0xdc, 0x64, -0x42, 0x13, 0x7f, 0xf3, 0x00, 0x8a, 0xb8, 0x4b, 0x61, 0x1f, 0x2c, 0x4d, 0xad, 0x6a, 0x3d, 0x42, -0x53, 0xc1, 0x38, 0x70, 0xa0, 0xa7, 0x2c, 0x83, 0x44, 0x32, 0xbc, 0x05, 0xa7, 0x91, 0x26, 0x1f, -0x15, 0x41, 0xf5, 0x00, 0xff, 0x65, 0x63, 0x92, 0x2f, 0x6d, 0x4c, 0x20, 0x2e, 0x7d, 0x5d, 0xe2, -0x89, 0x03, 0x5d, 0xca, 0x08, 0x9b, 0x7d, 0x5f, 0x37, 0xc2, 0x4c, 0xe1, 0xce, 0x23, 0xb3, 0xcf, -0x34, 0x6f, 0x78, 0x56, 0xb2, 0xb0, 0xa2, 0xc0, 0x03, 0x9a, 0x2b, 0x60, 0x41, 0xea, 0xe2, 0xb0, -0xc6, 0xe3, 0x5c, 0x2b, 0x15, 0x1a, 0x37, 0x66, 0xe1, 0xb6, 0xed, 0x40, 0x29, 0x5b, 0xf9, 0x1d, -0x82, 0x98, 0x89, 0xd7, 0x39, 0x2d, 0xb1, 0x80, 0xe3, 0x6a, 0xed, 0x63, 0x96, 0x1d, 0xec, 0x92, -0xcd, 0x4a, 0xa6, 0x18, 0x8e, 0x71, 0x53, 0x34, 0xe5, 0xf8, 0x8a, 0xbb, 0x7c, 0xb4, 0x45, 0x61, -0x84, 0x2d, 0x7c, 0xf4, 0x04, 0x48, 0xc6, 0x74, 0x99, 0x1c, 0x66, 0x43, 0x09, 0xb0, 0x03, 0x2d, -0x52, 0x06, 0xd0, 0x85, 0x42, 0xa1, 0x30, 0xef, 0x80, 0x37, 0x93, 0x10, 0x78, 0x6c, 0x2d, 0x84, -0xcb, 0x77, 0x78, 0x45, 0x12, 0x33, 0xfd, 0xe3, 0x51, 0x3e, 0x8d, 0x21, 0x03, 0xa6, 0x52, 0x89, -0xe4, 0xf5, 0xca, 0xeb, 0x35, 0x8f, 0x3a, 0x15, 0x3c, 0x53, 0x83, 0x94, 0x13, 0xf1, 0xb9, 0x9f, -0x10, 0x8f, 0x5a, 0x80, 0xfe, 0xc0, 0x1f, 0x05, 0xbe, 0x63, 0x21, 0x46, 0xa3, 0xc0, 0xe9, 0xdb, -0xa0, 0x22, 0xad, 0xe1, 0x0a, 0xc2, 0xaa, 0xd5, 0x51, 0x55, 0xf6, 0x79, 0xfa, 0xdb, 0xd5, 0x15, -0xce, 0x9d, 0xcf, 0x5e, 0xf0, 0x5d, 0xd3, 0x6d, 0x94, 0x42, 0x5c, 0xad, 0xd8, 0x07, 0xdd, 0x2c, -0xd0, 0x27, 0xd8, 0x2c, 0x32, 0xfc, 0x1d, 0x1e, 0x61, 0x8f, 0x08, 0x7f, 0x96, 0x3d, 0x02, 0x08, -0xcf, 0x0c, 0x81, 0x6d, 0x00, 0x6d, 0x19, 0xa0, 0xf8, 0x60, 0x84, 0x07, 0x03, 0x69, 0x0c, 0xa9, -0x00, 0x6d, 0x69, 0xe3, 0x51, 0x1f, 0xb6, 0x79, 0x99, 0x7a, 0x6d, 0xbd, 0x59, 0x67, 0x85, 0x38, -0x91, 0x5c, 0x1b, 0x76, 0xd7, 0x0d, 0xd9, 0x36, 0x01, 0x2d, 0x70, 0xbc, 0x52, 0x7a, 0x9b, 0x76, -0x7b, 0x74, 0xfb, 0x9e, 0xdb, 0x53, 0x43, 0x58, 0x33, 0xad, 0x9f, 0x61, 0xe7, 0x58, 0x6c, 0x76, -0xc7, 0xd0, 0x49, 0x66, 0xa6, 0x96, 0x64, 0xce, 0xad, 0xaa, 0xaa, 0x72, 0x62, 0x11, 0x8c, 0x81, -0x51, 0x0a, 0xc3, 0xc0, 0xb3, 0x22, 0x37, 0x19, 0x1a, 0x19, 0x73, 0x3c, 0x1f, 0xea, 0x3b, 0x04, -0xf8, 0x6a, 0xde, 0xec, 0x8a, 0x85, 0xf2, 0x19, 0xd8, 0xde, 0x3e, 0xbb, 0x14, 0x84, 0xbe, 0x92, -0x93, 0x57, 0xb4, 0xf8, 0xc4, 0xac, 0x4d, 0xa5, 0xae, 0x65, 0xcc, 0x92, 0x3a, 0x47, 0x51, 0xa1, -0xb0, 0x80, 0xbc, 0x8d, 0x3a, 0x97, 0x96, 0xe3, 0x06, 0x9c, 0x0d, 0xc1, 0x5f, 0xc0, 0x95, 0x96, -0xc0, 0x8e, 0xa2, 0x4e, 0xad, 0xa1, 0xdb, 0x9f, 0x51, 0x9f, 0x5f, 0x79, 0x31, 0x0d, 0x3f, 0xea, -0xa4, 0x4e, 0x06, 0xdc, 0xb4, 0xcf, 0xff, 0x06, 0xe2, 0x6e, 0xa3, 0xe4, 0x9e, 0x28, 0x30, 0xf2, -0x34, 0x53, 0x79, 0xf0, 0xf9, 0xd3, 0x42, 0x87, 0x32, 0x49, 0x36, 0xdf, 0xd5, 0x8f, 0x98, 0xaf, -0x96, 0xca, 0x73, 0xe6, 0x7a, 0x98, 0xa5, 0xec, 0xc6, 0x38, 0xbb, 0xfc, 0x58, 0x6b, 0x48, 0x37, -0x8b, 0x7c, 0x44, 0xa9, 0xf7, 0x3a, 0xa3, 0x7e, 0x7e, 0xf2, 0x50, 0x1d, 0xce, 0x74, 0x94, 0xbc, -0x48, 0xcd, 0xb2, 0x47, 0x22, 0xc5, 0x8e, 0x85, 0x54, 0x38, 0x88, 0xb9, 0xa0, 0xb0, 0xa9, 0x4c, -0xa0, 0x3c, 0xc1, 0x8d, 0x7e, 0x13, 0x29, 0xc7, 0xf0, 0xa5, 0x92, 0x12, 0x3f, 0x98, 0x5b, 0xfc, -0xf2, 0x9b, 0xc2, 0xa4, 0xd8, 0xf6, 0xee, 0x44, 0x5a, 0x13, 0x3f, 0x59, 0x62, 0x2f, 0x88, 0x5d, -0x91, 0x78, 0x8a, 0x9f, 0x3c, 0xd1, 0x8d, 0x03, 0x99, 0x88, 0x9f, 0xca, 0x9e, 0xfe, 0xf1, 0x25, -0x1c, 0x68, 0x67, 0x49, 0xf0, 0x05, 0xba, 0x13, 0x1d, 0x58, 0x31, 0x35, 0x0b, 0x7f, 0x4e, 0x79, -0x07, 0x4c, 0xec, 0x0f, 0x20, 0xf2, 0x96, 0xc2, 0x58, 0x54, 0xd3, 0x6c, 0xf0, 0xc3, 0xc8, 0x13, -0x3a, 0x00, 0x64, 0x2d, 0xce, 0x58, 0x16, 0x98, 0x5d, 0x9c, 0x59, 0xc6, 0xec, 0x59, 0x8b, 0xc6, -0x3c, 0x52, 0x65, 0x87, 0x96, 0x78, 0x0b, 0xf9, 0xf4, 0xf8, 0x0c, 0x0f, 0x13, 0xf1, 0xca, 0x0c, -0x60, 0x8a, 0x3a, 0x05, 0xdd, 0x39, 0xe9, 0x44, 0x4d, 0xbc, 0x9c, 0x7c, 0x72, 0xfe, 0x35, 0x57, -0x59, 0xbc, 0x40, 0xfe, 0xf9, 0xf8, 0xd3, 0xe7, 0x5c, 0x85, 0xf1, 0x36, 0xf9, 0xe9, 0xfe, 0xaf, -0xc4, 0xa4, 0x0f, 0xb0, 0x32, 0x5c, 0x94, 0x63, 0x96, 0x37, 0x1d, 0xc1, 0x64, 0x86, 0x46, 0xc4, -0x51, 0x75, 0x88, 0x43, 0xbf, 0xf1, 0x18, 0xb2, 0x97, 0x22, 0xbd, 0x33, 0x37, 0x93, 0x19, 0xb2, -0xfc, 0xa0, 0x97, 0x8c, 0xc9, 0xf2, 0x27, 0xcb, 0x70, 0xbb, 0x97, 0xcc, 0x17, 0xe1, 0x50, 0x28, -0x5b, 0x84, 0x8f, 0x17, 0xf8, 0xf3, 0x89, 0xf0, 0x83, 0xd3, 0xab, 0x5a, 0xbd, 0x52, 0xd9, 0x7f, -0x1e, 0x29, 0xae, 0x17, 0x96, 0x63, 0x72, 0x0f, 0xa8, 0x62, 0x24, 0xfa, 0x62, 0x20, 0x0f, 0x29, -0x0f, 0xf1, 0x93, 0x0b, 0xd2, 0xb8, 0x9d, 0x8a, 0xd6, 0x36, 0x4f, 0xea, 0x8c, 0xd2, 0x3e, 0xda, -0x32, 0xf1, 0x36, 0x74, 0x83, 0xba, 0x48, 0xfd, 0xc4, 0xbe, 0xff, 0x14, 0x9b, 0xbe, 0xe7, 0x16, -0x89, 0x4f, 0x93, 0x77, 0x85, 0x67, 0xdc, 0xe0, 0x4d, 0xfe, 0xca, 0x34, 0x7a, 0xb1, 0x93, 0x97, -0xbc, 0x96, 0xbd, 0x98, 0x46, 0x47, 0x3e, 0x3b, 0x0a, 0xec, 0x06, 0xf7, 0x37, 0x1e, 0x6c, 0x8b, -0x6e, 0x58, 0x68, 0x60, 0x7e, 0x4c, 0x48, 0xa3, 0xc3, 0xf6, 0x2d, 0x3f, 0x41, 0x6c, 0xf7, 0x6f, -0x9f, 0x64, 0xc7, 0x9b, 0x64, 0x38, 0x8f, 0x38, 0x15, 0x84, 0xce, 0x70, 0xcb, 0xe2, 0xac, 0x2d, -0x6d, 0x64, 0x68, 0x5c, 0xc0, 0x38, 0x28, 0x1e, 0x5b, 0xc8, 0xc7, 0xc1, 0xa7, 0xce, 0xa1, 0xd3, -0x67, 0x04, 0x8a, 0x64, 0x32, 0x60, 0xfe, 0x23, 0x10, 0xa4, 0xc2, 0x4e, 0x4b, 0xe3, 0xf1, 0x9e, -0x29, 0x44, 0xd2, 0xa0, 0xf0, 0x0a, 0x62, 0x2a, 0x97, 0xff, 0x7e, 0x74, 0x74, 0xc1, 0xae, 0x3d, -0x91, 0x20, 0x72, 0x40, 0x63, 0x79, 0xfd, 0xfa, 0xb5, 0xb2, 0x89, 0xb1, 0x5d, 0x00, 0x46, 0xae, -0x40, 0x1e, 0xc4, 0x83, 0xe1, 0x4b, 0xbe, 0x86, 0xe4, 0x91, 0xa6, 0xb2, 0x1f, 0x82, 0xb3, 0x8d, -0x8a, 0x8a, 0x5d, 0x83, 0x63, 0x8f, 0xca, 0xd9, 0x3c, 0x29, 0xa2, 0x31, 0x4d, 0xd2, 0xd4, 0x28, -0x4e, 0x94, 0x7c, 0x4d, 0xc9, 0x6d, 0xf9, 0xe1, 0xdb, 0xf5, 0x5a, 0xbb, 0x1f, 0x0f, 0x53, 0x08, -0x6d, 0xf8, 0x56, 0x9d, 0x23, 0x3c, 0x07, 0xab, 0x1c, 0xb9, 0xf1, 0xdc, 0xe0, 0xa1, 0x20, 0xb2, -0x9c, 0xff, 0xdf, 0x50, 0x3c, 0xca, 0x80, 0x56, 0xfd, 0x39, 0xfc, 0x55, 0xb1, 0x4a, 0xc8, 0x1d, -0xa5, 0x21, 0x91, 0x41, 0x5d, 0x70, 0x8c, 0x31, 0xb9, 0x8d, 0x82, 0x7e, 0x48, 0x1d, 0xf5, 0x7d, -0xd0, 0x30, 0xe1, 0xab, 0xa5, 0xc2, 0x7c, 0x51, 0x7c, 0xee, 0x5f, 0x81, 0x0a, 0x71, 0xf3, 0x73, -0xb5, 0x5a, 0xd9, 0x24, 0xd5, 0x52, 0xfd, 0x9b, 0x41, 0xaa, 0xb5, 0xad, 0x5f, 0x37, 0x1b, 0x2c, -0x0f, 0xa3, 0x21, 0x35, 0x9b, 0x87, 0xd5, 0x3a, 0x64, 0x56, 0x4a, 0x9b, 0x9b, 0x90, 0xbb, 0xd9, -0xf8, 0xb5, 0xb1, 0x45, 0xcc, 0xaf, 0x14, 0x76, 0xcb, 0xfc, 0x95, 0x8f, 0x66, 0x17, 0x1d, 0x0a, -0x0b, 0xac, 0x42, 0x63, 0xa2, 0xc2, 0xbb, 0xaa, 0x00, 0x57, 0xe7, 0x67, 0x94, 0xd5, 0xc9, 0xdc, -0xcd, 0xc9, 0xc6, 0x36, 0xd3, 0xdc, 0x77, 0xa4, 0x56, 0x6a, 0xd4, 0x26, 0x73, 0xeb, 0xac, 0xcf, -0x77, 0xae, 0xb5, 0x51, 0xc5, 0x28, 0x74, 0x79, 0x16, 0x22, 0x8e, 0x57, 0x2c, 0x44, 0x16, 0xc1, -0x8e, 0x5e, 0x58, 0x21, 0x9e, 0x83, 0xe5, 0x59, 0x82, 0xcc, 0xdd, 0x40, 0x3c, 0x54, 0x03, 0x38, -0x63, 0xfb, 0x19, 0xb6, 0x88, 0x01, 0xcd, 0xe8, 0x8b, 0x0a, 0xa0, 0x8b, 0xe9, 0x29, 0x06, 0x4f, -0x6d, 0x2d, 0x72, 0x2f, 0x29, 0x7d, 0x04, 0xa7, 0xf0, 0xfc, 0xbb, 0x42, 0xde, 0x8f, 0x27, 0x6e, -0x07, 0x53, 0x6c, 0x3d, 0x45, 0x51, 0x95, 0x30, 0x66, 0x7d, 0xd2, 0xe4, 0x85, 0x9f, 0x39, 0x37, -0x75, 0xd0, 0xcd, 0xf4, 0x50, 0x88, 0x16, 0x93, 0xaf, 0xd2, 0x34, 0xb6, 0x00, 0x2d, 0xf1, 0x60, -0xcf, 0x5c, 0x1c, 0x17, 0x72, 0x7a, 0x27, 0x4f, 0x2c, 0x9a, 0xca, 0x2f, 0x0e, 0xbd, 0x7d, 0x9f, -0x2e, 0x9b, 0xea, 0x96, 0x4c, 0xc8, 0x43, 0x8e, 0xd3, 0x24, 0x09, 0x00, 0xde, 0xc9, 0xfa, 0x1a, -0x2f, 0x8e, 0xb1, 0xe2, 0x48, 0xff, 0xb5, 0xb7, 0x19, 0xe5, 0x17, 0xa3, 0x3d, 0x7c, 0x4e, 0xe9, -0x05, 0x90, 0x1e, 0x74, 0x83, 0x5d, 0x2a, 0x7b, 0x3a, 0xf9, 0x8d, 0x56, 0x68, 0x14, 0x24, 0x8a, -0x15, 0x8a, 0xa9, 0xad, 0xc2, 0x93, 0x6c, 0xa1, 0x99, 0x9e, 0x5b, 0xe9, 0x1b, 0x3c, 0xb3, 0x1a, -0xdf, 0x28, 0x4f, 0x41, 0x26, 0x0a, 0x8a, 0x45, 0xcf, 0x03, 0xc9, 0x55, 0x16, 0xb8, 0x38, 0x3f, -0x05, 0x25, 0x5d, 0x8f, 0x8a, 0xa5, 0x02, 0xb2, 0x83, 0x05, 0x4a, 0xa7, 0xa8, 0x61, 0x90, 0x9e, -0x15, 0xb2, 0x10, 0x58, 0xd4, 0xb2, 0xbb, 0x13, 0xe2, 0xa4, 0xa4, 0xaa, 0x78, 0x8c, 0x2f, 0xe3, -0x20, 0xd9, 0xc4, 0x18, 0x93, 0xb0, 0xe3, 0x3e, 0x30, 0x18, 0x56, 0x14, 0x41, 0x25, 0x33, 0xa6, -0x34, 0x55, 0xcc, 0x0a, 0xaa, 0xda, 0x2f, 0x45, 0x6b, 0xe3, 0x87, 0xcb, 0x68, 0xd4, 0x85, 0xc1, -0xf3, 0x20, 0x09, 0xf0, 0x65, 0x6a, 0x1c, 0xfd, 0x61, 0xed, 0x4f, 0x04, 0x8f, 0x82, 0x86, 0xca, -0x65, 0x8c, 0x9a, 0xf6, 0x4a, 0x67, 0x8f, 0x82, 0xff, 0xaa, 0x93, 0xc5, 0x85, 0xe0, 0xbb, 0xe1, -0x32, 0xed, 0x95, 0xce, 0x38, 0xa5, 0xa8, 0xc8, 0x84, 0x73, 0x66, 0xbd, 0xba, 0xa8, 0x27, 0xea, -0xf2, 0x7a, 0x17, 0x07, 0x87, 0x5b, 0x1b, 0x8d, 0xc6, 0xcd, 0x16, 0x93, 0xd8, 0xd0, 0x5d, 0x21, -0x3c, 0xd5, 0x20, 0x1a, 0xf3, 0xfa, 0x5c, 0xaf, 0xa9, 0x2b, 0x6e, 0xcc, 0xa9, 0xf8, 0xa0, 0xeb, -0xf4, 0xa6, 0xbe, 0xe2, 0xbb, 0xcc, 0x8a, 0x28, 0xcc, 0xd3, 0xe1, 0xc2, 0xff, 0x5a, 0x2d, 0xa8, -0xc8, 0x85, 0xfb, 0xab, 0x1c, 0x4b, 0x5b, 0xe1, 0x20, 0xc4, 0x54, 0xf6, 0x1c, 0xa1, 0xde, 0xd2, -0x0b, 0x0f, 0xfa, 0x03, 0x2e, 0xa9, 0x50, 0x03, 0x44, 0xd8, 0x1a, 0x81, 0x76, 0x58, 0x18, 0x05, -0x04, 0x7c, 0xaf, 0xf3, 0xc5, 0xe2, 0x74, 0x88, 0xc0, 0xcc, 0x74, 0xd9, 0xa2, 0xcf, 0x51, 0xc6, -0x55, 0x06, 0xdb, 0x93, 0x81, 0x1d, 0xd8, 0xab, 0x2e, 0xf9, 0x63, 0xc1, 0x71, 0xef, 0x40, 0xed, -0xc1, 0x8a, 0x80, 0x0d, 0x02, 0x78, 0x51, 0xc0, 0xf9, 0x5c, 0x1c, 0xb8, 0x77, 0xdd, 0x22, 0x21, -0x3e, 0x98, 0x17, 0x66, 0x61, 0x22, 0x10, 0xd2, 0x44, 0x50, 0x29, 0x33, 0x8d, 0x58, 0x64, 0xbe, -0x79, 0x93, 0xc0, 0x7e, 0x49, 0x44, 0xaa, 0x2a, 0x2c, 0xe2, 0x95, 0x65, 0x46, 0x41, 0xa0, 0xbc, -0x37, 0x3c, 0xe6, 0x29, 0xa7, 0x2b, 0x92, 0x7a, 0x23, 0x4a, 0x7f, 0x47, 0x2c, 0x78, 0x6d, 0xdc, -0xf2, 0x5f, 0x5a, 0xe1, 0x9e, 0xba, 0x48, 0xf3, 0xe2, 0xb1, 0x70, 0x32, 0xcd, 0x2c, 0x2d, 0x3d, -0x0c, 0x45, 0x15, 0xf6, 0xf3, 0xc6, 0x0d, 0xb3, 0x6b, 0x31, 0x8f, 0x33, 0x5e, 0x83, 0x79, 0x64, -0x65, 0x16, 0x46, 0x47, 0x2b, 0x5e, 0x16, 0x63, 0xe6, 0x64, 0xf7, 0xa6, 0xef, 0xcb, 0x8e, 0xf4, -0xfd, 0xec, 0xa2, 0xc2, 0xa7, 0x85, 0x97, 0x16, 0x3e, 0x29, 0xb0, 0xde, 0x27, 0x47, 0x7e, 0x3d, -0x7a, 0xee, 0x63, 0x26, 0x2f, 0xb3, 0xcb, 0xf2, 0xac, 0x9a, 0x57, 0x89, 0xf0, 0x1b, 0xd2, 0x46, -0x40, 0x96, 0xd8, 0xa0, 0xbe, 0x17, 0xa9, 0x95, 0x7d, 0xac, 0x17, 0x90, 0xb6, 0xe2, 0x56, 0x85, -0x01, 0x4d, 0x40, 0x91, 0x17, 0xaf, 0x32, 0x90, 0x25, 0x2d, 0x49, 0xbc, 0x86, 0x90, 0xf6, 0x4b, -0xe9, 0xe4, 0x64, 0x7c, 0x20, 0xe9, 0x34, 0x54, 0xc6, 0x50, 0x50, 0x86, 0x54, 0xc3, 0x07, 0x8f, -0x76, 0x8d, 0x1a, 0x8f, 0x28, 0xa5, 0x5d, 0xac, 0xec, 0x92, 0xfe, 0x52, 0xe2, 0x30, 0xc6, 0xea, -0xe8, 0x18, 0x62, 0x65, 0x48, 0x28, 0x2d, 0x21, 0x34, 0xc8, 0x9e, 0xfe, 0xce, 0x6b, 0xac, 0x0b, -0xa2, 0x18, 0xa2, 0x87, 0x15, 0x25, 0xfc, 0x79, 0x46, 0x22, 0x60, 0x1a, 0x85, 0x42, 0xc6, 0x4d, -0xb7, 0x91, 0xc4, 0xd2, 0x74, 0x64, 0x6e, 0xa0, 0xd2, 0xd9, 0xde, 0x4c, 0x43, 0x42, 0xa9, 0x95, -0xde, 0xb5, 0xc8, 0xc8, 0x64, 0xde, 0x70, 0x26, 0xca, 0x3a, 0x65, 0xa1, 0x08, 0x4a, 0x89, 0x42, -0xce, 0x87, 0x5e, 0x41, 0x3b, 0xae, 0x1f, 0x9a, 0x73, 0xff, 0xc5, 0x70, 0xe9, 0x07, 0x12, 0x81, -0x80, 0xa8, 0xbe, 0x9f, 0x3f, 0x26, 0x13, 0x60, 0x1f, 0xa8, 0xca, 0x5c, 0x3a, 0x31, 0x65, 0x18, -0x40, 0x47, 0x46, 0x62, 0xc4, 0xa3, 0xf6, 0xce, 0xc4, 0x7a, 0x15, 0x65, 0x4e, 0x2c, 0x76, 0xab, -0x73, 0x6e, 0x4c, 0x88, 0x62, 0x99, 0x63, 0x56, 0xc7, 0xef, 0x62, 0xeb, 0x72, 0x6c, 0x00, 0x3b, -0x65, 0xfe, 0x52, 0x91, 0x7c, 0xe2, 0xa8, 0x1d, 0x38, 0x43, 0x7c, 0xe3, 0xa8, 0x9b, 0xf4, 0xbc, -0xbd, 0x57, 0xff, 0x0b, 0x36, 0xc8, 0xe1, 0x4b, 0x9c, 0xc3, 0x00, 0x00}; -#endif /*__SETUP_HTML_H__*/ diff --git a/src/web/html/h/style_css.h b/src/web/html/h/style_css.h deleted file mode 100644 index 3bff2337..00000000 --- a/src/web/html/h/style_css.h +++ /dev/null @@ -1,188 +0,0 @@ -#ifndef __STYLE_CSS_H__ -#define __STYLE_CSS_H__ -#define style_css_len 2914 -const uint8_t style_css[] PROGMEM = { -0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0x9d, 0x1a, 0x69, 0x8f, 0xdb, 0xb8, -0xf5, 0xaf, 0x68, 0xd7, 0x58, 0x20, 0x13, 0x58, 0x5a, 0x5b, 0xb6, 0xc6, 0x87, 0xd0, 0xa2, 0x45, -0x8b, 0x7c, 0x6b, 0xd1, 0xaf, 0x45, 0x11, 0x2c, 0x28, 0x89, 0x1e, 0x73, 0xa3, 0x0b, 0x12, 0xed, -0x19, 0xef, 0xc0, 0xff, 0xbd, 0xef, 0xf1, 0x12, 0x29, 0xd1, 0x9a, 0x64, 0x27, 0x81, 0x25, 0xf3, -0xf1, 0x78, 0xf7, 0x45, 0x9f, 0x79, 0x55, 0x2e, 0x83, 0xac, 0x29, 0x6e, 0xc1, 0xfb, 0xa9, 0xa9, -0x79, 0x78, 0x22, 0x15, 0x2b, 0x6f, 0xc7, 0xbf, 0x77, 0x8c, 0x94, 0x69, 0x45, 0xba, 0x17, 0x56, -0x1f, 0x57, 0x69, 0x4b, 0x8a, 0x82, 0xd5, 0x2f, 0xf0, 0x76, 0xa6, 0xec, 0xe5, 0xcc, 0x8f, 0xeb, -0xd5, 0xea, 0x97, 0xb4, 0x62, 0x75, 0x68, 0x7f, 0xcf, 0x48, 0xfe, 0xed, 0xa5, 0x6b, 0x2e, 0x75, -0x11, 0xe6, 0x4d, 0xd9, 0x74, 0xc7, 0x2b, 0xe9, 0x3e, 0x85, 0x61, 0xf6, 0xf2, 0x94, 0xda, 0xdf, -0x4f, 0xf0, 0xfd, 0x7e, 0x8e, 0x83, 0x77, 0xb5, 0x6b, 0x58, 0xd2, 0x13, 0xee, 0xd0, 0xbe, 0xa5, -0xf7, 0xbe, 0x25, 0xf5, 0x32, 0x28, 0xd9, 0x32, 0x38, 0x6f, 0xe0, 0x49, 0x32, 0x0a, 0xe8, 0x9d, -0x18, 0x2d, 0x8b, 0x9e, 0xf2, 0xe0, 0x7d, 0xb2, 0x8d, 0x06, 0x2d, 0x03, 0x56, 0xb7, 0x17, 0xfe, -0x3f, 0x7e, 0x6b, 0xe9, 0x5f, 0xfa, 0x4b, 0x56, 0x31, 0xfe, 0x75, 0x19, 0x44, 0x19, 0xaf, 0x83, -0xf7, 0xac, 0xe9, 0x0a, 0xda, 0x85, 0x1d, 0x29, 0xd8, 0xa5, 0x3f, 0x6e, 0xf1, 0x18, 0x6b, 0xf2, -0x89, 0x95, 0xf4, 0x6b, 0xf0, 0xfe, 0xca, 0x0a, 0x7e, 0x96, 0x64, 0xdc, 0x39, 0x7d, 0xe3, 0xa4, -0xa3, 0x64, 0x7a, 0xde, 0x0c, 0x85, 0xf7, 0x45, 0xc9, 0xae, 0x34, 0x40, 0x02, 0xc6, 0xeb, 0x62, -0x80, 0x46, 0xbc, 0x69, 0x6b, 0x72, 0x05, 0x6c, 0xfc, 0x5b, 0x00, 0x4c, 0x6c, 0xd3, 0x36, 0x3d, -0xe3, 0xac, 0xa9, 0x8f, 0x27, 0xf6, 0x46, 0x8b, 0x14, 0x56, 0x01, 0xd3, 0x6d, 0xe4, 0xf4, 0x46, -0xc4, 0x73, 0x8a, 0x16, 0xd3, 0x1a, 0x88, 0x0c, 0xf0, 0x23, 0x45, 0x52, 0xc2, 0x82, 0xe6, 0x4d, -0x47, 0xc4, 0xae, 0x75, 0x53, 0xd3, 0x54, 0x08, 0xba, 0x67, 0x7f, 0xd0, 0xe3, 0x7a, 0x07, 0x73, -0x0a, 0xd6, 0xb7, 0x25, 0xb9, 0x1d, 0xb3, 0xb2, 0xc9, 0xbf, 0x01, 0x1d, 0xe3, 0x03, 0x16, 0xa7, -0xd3, 0xc9, 0x3a, 0x37, 0x62, 0x79, 0x03, 0x24, 0x4a, 0xcc, 0x84, 0xe8, 0x56, 0x16, 0x5f, 0x46, -0xe4, 0xb8, 0x7b, 0x1b, 0xe2, 0x48, 0xd6, 0x37, 0xe5, 0x85, 0x53, 0x6b, 0xdb, 0xe3, 0xb9, 0xb9, -0xd2, 0xee, 0x21, 0x7f, 0xda, 0x8e, 0x81, 0x36, 0xde, 0x42, 0x31, 0xeb, 0x29, 0xf8, 0x89, 0x55, -0x6d, 0xd3, 0x71, 0x52, 0xf3, 0x61, 0x8b, 0x88, 0xd5, 0xa7, 0xc6, 0xc7, 0x95, 0xc9, 0xa9, 0x9d, -0xd0, 0xd9, 0x58, 0x30, 0x08, 0xc8, 0x48, 0x50, 0x25, 0xcc, 0x2e, 0x55, 0x93, 0x81, 0x4a, 0x04, -0xef, 0x1a, 0x75, 0xc1, 0xb2, 0x7b, 0x7f, 0x7d, 0x51, 0x84, 0xc3, 0xf9, 0x9c, 0xe5, 0xa4, 0x0c, -0x49, 0xc9, 0x5e, 0xea, 0x63, 0xc5, 0x8a, 0xa2, 0xa4, 0x86, 0x50, 0x56, 0x97, 0xac, 0xa6, 0xa1, -0xa4, 0x57, 0xda, 0x4f, 0x88, 0x67, 0x84, 0xdb, 0x37, 0x23, 0x1e, 0x38, 0x2f, 0x00, 0xc6, 0x07, -0xf8, 0x14, 0x5a, 0x2f, 0x76, 0x0e, 0x25, 0xfa, 0xa0, 0x8f, 0xa5, 0xc2, 0x1e, 0x07, 0x9e, 0x34, -0xf4, 0x95, 0x74, 0xb5, 0x03, 0xc5, 0x01, 0x03, 0xed, 0x2f, 0x79, 0x4e, 0xfb, 0xde, 0x99, 0xa0, -0xc6, 0x70, 0xce, 0x2b, 0x3b, 0x31, 0x07, 0xa6, 0x95, 0x92, 0x71, 0x24, 0x75, 0x9e, 0xe7, 0xda, -0x7a, 0x51, 0x0f, 0x6c, 0xc6, 0x1b, 0x6d, 0x4b, 0x94, 0xb6, 0x05, 0xeb, 0x67, 0xf8, 0xd8, 0x03, -0x49, 0xd6, 0x34, 0x4b, 0x3c, 0xc8, 0x3e, 0x69, 0x1f, 0xae, 0x5a, 0x48, 0xf5, 0xde, 0x20, 0x2b, -0x94, 0x3b, 0xd9, 0xc0, 0xab, 0x62, 0x5e, 0xd6, 0x70, 0xde, 0x54, 0x42, 0x46, 0x46, 0x90, 0x1d, -0x2d, 0x41, 0x9d, 0xaf, 0xd4, 0xd6, 0x3b, 0xa1, 0xa5, 0xae, 0xa9, 0xc7, 0x8e, 0x5c, 0x49, 0x8e, -0x4b, 0x66, 0x0d, 0x50, 0x4e, 0x79, 0x92, 0x6e, 0x28, 0xea, 0x69, 0x4b, 0xc1, 0x6c, 0x9a, 0xce, -0xf1, 0x0e, 0xda, 0xe1, 0x19, 0x0c, 0x8f, 0x4a, 0x8c, 0x28, 0xce, 0xa9, 0x83, 0x58, 0x6c, 0x0f, -0xf8, 0x6f, 0x62, 0x64, 0xc0, 0x0b, 0x4e, 0x6b, 0x70, 0x69, 0x15, 0x79, 0x0b, 0xd5, 0xf6, 0xeb, -0xed, 0x4a, 0x61, 0xcc, 0x41, 0xbd, 0xce, 0x0f, 0x51, 0x55, 0x70, 0x4a, 0x8a, 0x50, 0x08, 0x70, -0xec, 0x5e, 0x95, 0xbf, 0xc1, 0x49, 0xd9, 0xcb, 0x07, 0xbb, 0x4c, 0x9d, 0xb3, 0x58, 0xcd, 0xae, -0x33, 0xe7, 0x23, 0x70, 0xfe, 0x70, 0x76, 0x9d, 0x3b, 0x59, 0xaf, 0x9f, 0x39, 0x3b, 0x04, 0x7e, -0xcd, 0xad, 0x07, 0xf0, 0x47, 0xc7, 0x7f, 0xc7, 0x16, 0xde, 0xc5, 0xf9, 0x79, 0x86, 0x74, 0x04, -0xce, 0x93, 0x0e, 0x33, 0x66, 0x48, 0xd7, 0xeb, 0x1f, 0x90, 0xce, 0xfb, 0x39, 0xb1, 0xf7, 0x62, -0xed, 0xa3, 0x85, 0x73, 0xa2, 0xee, 0x1f, 0x1d, 0x78, 0xee, 0x4c, 0x7c, 0x44, 0x2f, 0x05, 0x5a, -0x1d, 0x80, 0x8f, 0x64, 0x45, 0xe0, 0x95, 0xb4, 0x52, 0xf8, 0x75, 0x47, 0xab, 0x60, 0x15, 0xe0, -0x23, 0xbd, 0xb7, 0x10, 0x0a, 0x30, 0xc8, 0x48, 0x6f, 0xf8, 0xfb, 0xa5, 0xe7, 0xec, 0x74, 0xb3, -0x43, 0xcc, 0xa6, 0xe5, 0xd3, 0xf0, 0xbf, 0x38, 0x35, 0x0d, 0x9f, 0x71, 0xf7, 0x12, 0x2c, 0x03, -0x6b, 0xd4, 0x35, 0xaf, 0x83, 0xcb, 0x38, 0x95, 0x14, 0x2d, 0xcf, 0x18, 0x0d, 0xda, 0x24, 0x8e, -0x85, 0xaf, 0x1d, 0x69, 0x8f, 0xf8, 0x81, 0x42, 0x68, 0x4a, 0x70, 0x77, 0x30, 0x7a, 0x5c, 0x03, -0xa2, 0x22, 0x6c, 0xc2, 0x50, 0xb8, 0x86, 0x94, 0x00, 0x9f, 0xb1, 0x7a, 0x6e, 0xd4, 0x73, 0xbb, -0x14, 0x8f, 0x44, 0x7d, 0x7d, 0x56, 0xcf, 0x9d, 0x7a, 0xee, 0x25, 0xf8, 0xa0, 0xbe, 0xae, 0x57, -0xfa, 0x45, 0xef, 0xb7, 0x8e, 0xd5, 0x69, 0x70, 0x56, 0x40, 0x2e, 0xbc, 0xd1, 0xe7, 0x69, 0xcf, -0xb1, 0x8f, 0x36, 0xfa, 0x4f, 0xe3, 0x12, 0x1b, 0xaf, 0xf2, 0x1c, 0x3d, 0xcb, 0xbf, 0x9d, 0x86, -0x6d, 0x34, 0x2c, 0x4e, 0xf4, 0xd0, 0x56, 0x0f, 0x6d, 0x36, 0xd1, 0x78, 0xab, 0x44, 0xc3, 0xb6, -0xeb, 0xc9, 0x56, 0xcf, 0x1a, 0x96, 0x18, 0x2e, 0xec, 0xcc, 0xd0, 0x7e, 0xb2, 0xd5, 0x5e, 0xc3, -0x9e, 0xa7, 0x58, 0x1d, 0x34, 0x6c, 0x67, 0xb0, 0x5a, 0xaf, 0x0c, 0x85, 0x53, 0xb4, 0xd6, 0x86, -0xfc, 0xc3, 0x14, 0xaf, 0x75, 0xec, 0xe6, 0x5c, 0x51, 0x8b, 0xdc, 0x32, 0x79, 0x66, 0x14, 0x27, -0x42, 0xbb, 0x60, 0x38, 0xb6, 0x87, 0xcd, 0xe8, 0x66, 0x18, 0x5d, 0xeb, 0xb1, 0xad, 0x35, 0x36, -0xcc, 0x4c, 0x86, 0xd1, 0x8d, 0x1a, 0x7b, 0x73, 0xce, 0x0a, 0xd4, 0x69, 0x81, 0x79, 0x93, 0x73, -0x62, 0x77, 0x8e, 0x99, 0x32, 0xcc, 0xd8, 0xd8, 0x33, 0x1c, 0xab, 0x40, 0xe8, 0xd6, 0x81, 0xea, -0xf5, 0x6b, 0x6b, 0x7d, 0x62, 0xcf, 0xd8, 0x48, 0xb8, 0xc6, 0xf1, 0xe6, 0xe1, 0x87, 0x8b, 0xe1, -0x6d, 0xca, 0x1a, 0x07, 0xbf, 0xdb, 0x98, 0x49, 0x16, 0x76, 0xb7, 0x29, 0xb3, 0x1c, 0xdc, 0x6e, -0x63, 0xb6, 0x0d, 0x98, 0x55, 0xc8, 0x3d, 0x8c, 0x5b, 0xb2, 0x36, 0xf0, 0x72, 0xaf, 0x42, 0xee, -0x39, 0x73, 0xc6, 0xd8, 0x55, 0xc8, 0x3d, 0x6b, 0x86, 0x8b, 0x5f, 0x85, 0xdc, 0xb3, 0xa1, 0x13, -0x0c, 0x2b, 0xe4, 0x9e, 0x35, 0x63, 0x84, 0xe3, 0xcd, 0xc1, 0xd1, 0x87, 0xe1, 0xcd, 0xc1, 0x70, -0x8a, 0xdf, 0xcd, 0xc6, 0x6f, 0x84, 0xdd, 0xcd, 0xc6, 0xce, 0x83, 0xdb, 0xcd, 0xc6, 0x6d, 0x84, -0x19, 0xb7, 0x30, 0x13, 0x3e, 0x57, 0x63, 0x27, 0x60, 0xf1, 0x18, 0x36, 0x80, 0x36, 0x2e, 0x68, -0x6d, 0x00, 0xdb, 0x11, 0xc0, 0x5a, 0x93, 0xb8, 0xa0, 0x8d, 0x02, 0x64, 0x36, 0x0e, 0x2a, 0xc1, -0xb2, 0xd0, 0xc8, 0x6c, 0x34, 0x0c, 0x78, 0x80, 0x6e, 0x26, 0xd0, 0xb5, 0x81, 0x6d, 0xa7, 0x30, -0x6b, 0x65, 0x32, 0x81, 0x2a, 0x94, 0x4e, 0x3d, 0xaa, 0xfb, 0x10, 0x35, 0x36, 0x9a, 0x97, 0x00, -0x88, 0x1d, 0x80, 0x19, 0xde, 0xd8, 0xc3, 0xb1, 0x35, 0x7f, 0xeb, 0x00, 0xcc, 0x70, 0x62, 0x0f, -0xaf, 0xa3, 0xdd, 0xb0, 0xe0, 0xd9, 0x85, 0x0c, 0x80, 0x9d, 0x0b, 0x88, 0x07, 0xc8, 0xde, 0x81, -0x98, 0xe1, 0x83, 0x3d, 0xbc, 0xb2, 0xcf, 0x40, 0x4f, 0x69, 0x83, 0x14, 0x84, 0x84, 0x9d, 0x13, -0x3f, 0x45, 0x65, 0x22, 0xc6, 0x73, 0x67, 0x3c, 0x87, 0x5c, 0x91, 0x76, 0x00, 0x28, 0x42, 0xac, -0x47, 0xdc, 0xea, 0xc4, 0xad, 0x86, 0x0a, 0x59, 0x7c, 0x8c, 0x92, 0x6c, 0x77, 0x0e, 0x46, 0xd4, -0xbf, 0x06, 0x9f, 0x47, 0x25, 0xb8, 0xc2, 0x4a, 0x8f, 0xc9, 0x2a, 0x49, 0xa3, 0xfa, 0x79, 0x19, -0x1c, 0x8f, 0xe4, 0x04, 0x58, 0xe0, 0x4b, 0x46, 0x4f, 0x4d, 0x87, 0xc9, 0x74, 0xf3, 0x86, 0x14, -0xa1, 0x97, 0x50, 0x69, 0x04, 0x8c, 0xa4, 0xf7, 0x5f, 0x3f, 0x07, 0x7d, 0x15, 0x7c, 0xfe, 0xf5, -0x6f, 0x15, 0x2d, 0x18, 0xf9, 0x84, 0x8d, 0x02, 0x15, 0x3a, 0x9e, 0xf7, 0xed, 0xdb, 0x53, 0xf0, -0x2e, 0x62, 0x40, 0x5f, 0xcd, 0x46, 0x48, 0x00, 0xcf, 0x05, 0x49, 0x00, 0x7b, 0xe2, 0x24, 0x8c, -0xce, 0x85, 0x4a, 0x00, 0xcf, 0x45, 0x4b, 0x00, 0x7b, 0x02, 0x26, 0x8c, 0xce, 0xc5, 0x4c, 0x00, -0xcf, 0x85, 0x4d, 0x00, 0x7b, 0x22, 0x27, 0xd2, 0x3e, 0x17, 0x3c, 0x11, 0x3e, 0x17, 0x3f, 0x11, -0x3e, 0x0e, 0xa1, 0x60, 0x60, 0x82, 0xa5, 0xb3, 0xa6, 0x2d, 0xb8, 0x3a, 0x67, 0xdd, 0x82, 0xaf, -0x8f, 0x0d, 0x5c, 0x30, 0x78, 0xce, 0xc6, 0x05, 0x8b, 0x1f, 0x9b, 0xb9, 0x14, 0xba, 0xdf, 0xd2, -0xa5, 0xc4, 0x7d, 0xc6, 0x2e, 0x85, 0xed, 0xb7, 0x77, 0x29, 0x72, 0x9f, 0xc9, 0x4b, 0x69, 0x3f, -0xb0, 0x7a, 0x29, 0x6b, 0xbf, 0xe1, 0x4b, 0x89, 0x3f, 0xb0, 0x7d, 0x29, 0xef, 0x89, 0xf9, 0x17, -0x08, 0xf8, 0xd8, 0xf4, 0xc4, 0xb4, 0x0f, 0x6c, 0x18, 0xed, 0xa7, 0x2a, 0x7c, 0xf6, 0x73, 0x38, -0xc4, 0x83, 0xfd, 0x54, 0xc5, 0xac, 0xfd, 0x00, 0x78, 0xce, 0x7e, 0x00, 0xec, 0xb1, 0x1f, 0x18, -0x9d, 0xb3, 0x1f, 0x00, 0xcf, 0xd9, 0x0f, 0x80, 0x3d, 0xf6, 0x03, 0xa3, 0x73, 0xf6, 0x03, 0xe0, -0x39, 0xfb, 0x01, 0xb0, 0xc7, 0x7e, 0x90, 0xf6, 0x39, 0xfb, 0x41, 0xf8, 0x9c, 0xfd, 0x20, 0x7c, -0x64, 0x3f, 0x77, 0x4e, 0x32, 0xd1, 0x0d, 0x91, 0x8e, 0x0c, 0x66, 0x95, 0xa4, 0xed, 0xe9, 0x51, -0xbf, 0x38, 0x6d, 0x38, 0x7e, 0x76, 0xfc, 0x33, 0xab, 0xcf, 0xb4, 0x63, 0xa2, 0x19, 0x25, 0x36, -0xe1, 0x05, 0x94, 0x06, 0xea, 0xf5, 0x3c, 0x64, 0x52, 0x4a, 0xff, 0x8c, 0xab, 0x94, 0xc6, 0x33, -0x2a, 0xba, 0xc4, 0xb2, 0x50, 0xce, 0xc1, 0x52, 0x09, 0x6b, 0x9a, 0x16, 0x6b, 0xa5, 0x71, 0xbf, -0xd5, 0xea, 0x22, 0x98, 0xd6, 0x12, 0x36, 0x22, 0x62, 0xfc, 0x58, 0xc7, 0xfa, 0x35, 0xc5, 0x96, -0xd9, 0xa9, 0x6c, 0x5e, 0x8f, 0xb2, 0x34, 0x31, 0xb5, 0x97, 0xde, 0x2b, 0x1e, 0x9a, 0x19, 0xb2, -0x57, 0x25, 0x47, 0xec, 0x02, 0xcb, 0x2e, 0xe7, 0xde, 0x86, 0x2d, 0x22, 0x11, 0x23, 0x4c, 0xa3, -0x30, 0xcb, 0x32, 0x5d, 0x23, 0x62, 0x27, 0x28, 0x4e, 0x74, 0x07, 0xd2, 0x09, 0x6e, 0x66, 0x31, -0x06, 0x1d, 0xdf, 0xda, 0x78, 0xa3, 0x3a, 0x2a, 0x2b, 0xbd, 0x89, 0x59, 0x73, 0x81, 0xba, 0xae, -0x64, 0x3d, 0x20, 0xc3, 0x6f, 0xc0, 0x24, 0xec, 0xe0, 0xca, 0x06, 0x9d, 0x5e, 0x8a, 0x4b, 0x04, -0x99, 0x43, 0xcb, 0xda, 0x5e, 0x8c, 0x9d, 0x65, 0xfd, 0x95, 0x78, 0xce, 0x36, 0x32, 0x41, 0xbe, -0x39, 0xc1, 0x11, 0xd1, 0x78, 0xc4, 0x06, 0xd3, 0xbc, 0x74, 0x1a, 0xa6, 0x67, 0x56, 0xcc, 0x19, -0xb9, 0xb4, 0xed, 0xa0, 0xa9, 0xcb, 0x5b, 0xd0, 0xe7, 0x1d, 0xa5, 0x75, 0x40, 0xea, 0x22, 0xf0, -0x19, 0xbb, 0xee, 0x1d, 0x2b, 0x63, 0xdd, 0xb8, 0x1d, 0x36, 0xa7, 0x27, 0x3f, 0xe9, 0xd3, 0x3e, -0x4e, 0x14, 0x86, 0x3e, 0xaf, 0xd3, 0x37, 0x16, 0x6d, 0xd1, 0xa1, 0x6d, 0xa6, 0x5a, 0x84, 0x0e, -0x2f, 0x70, 0x8a, 0xbf, 0x05, 0x3b, 0x6e, 0x9e, 0xaa, 0x76, 0xd7, 0xa8, 0x45, 0x8b, 0x4a, 0x86, -0x42, 0xb2, 0xf7, 0x90, 0xd9, 0xc6, 0x78, 0x54, 0x8b, 0x03, 0x71, 0x32, 0x47, 0xfb, 0x14, 0x5f, -0x36, 0x21, 0x93, 0x41, 0xf1, 0x93, 0x95, 0xa3, 0xa8, 0x52, 0xd7, 0x94, 0x90, 0xe5, 0x4e, 0xc9, -0x88, 0x8d, 0xf7, 0x7b, 0x1b, 0x95, 0x2c, 0x5f, 0x06, 0xe2, 0x81, 0x7c, 0x19, 0xe4, 0xbd, 0x37, -0x4d, 0x8c, 0xc5, 0xe1, 0x70, 0x40, 0x37, 0x4e, 0x7b, 0x27, 0xb5, 0x16, 0x86, 0x36, 0xd3, 0xf5, -0xe8, 0x29, 0xa0, 0x5c, 0x88, 0x6e, 0xea, 0x3d, 0xea, 0x7f, 0x93, 0x9d, 0x46, 0xf0, 0x11, 0xfd, -0x6f, 0xca, 0xbd, 0x30, 0x30, 0xfa, 0x1f, 0xea, 0x81, 0xa7, 0x8e, 0xb2, 0xe1, 0x3e, 0x8a, 0x25, -0x4e, 0xe3, 0xda, 0xd8, 0x3e, 0x68, 0x63, 0x41, 0x6b, 0x35, 0xd3, 0x9c, 0xf8, 0xbd, 0xbd, 0xdf, -0xd7, 0x33, 0xe3, 0x34, 0xcd, 0x2f, 0x5d, 0x0f, 0x5f, 0xda, 0x86, 0x89, 0x6c, 0xd4, 0xf0, 0x3e, -0x76, 0xbd, 0x85, 0x74, 0x5d, 0xf2, 0x7c, 0xcb, 0xfc, 0x91, 0xeb, 0x69, 0x73, 0xe1, 0xd8, 0x20, -0x9f, 0x5c, 0x44, 0x24, 0xde, 0x8e, 0x2f, 0x60, 0x7b, 0xc9, 0x04, 0xab, 0xad, 0xa9, 0xf1, 0x63, -0xd6, 0xda, 0xf2, 0xdd, 0xe9, 0xf5, 0x7f, 0x66, 0x0b, 0xd1, 0xc9, 0xd9, 0x09, 0x6d, 0xc2, 0x6d, -0xc8, 0x11, 0x90, 0xfe, 0xb6, 0x04, 0x43, 0xbf, 0xb2, 0x1e, 0x38, 0x51, 0x28, 0xe7, 0x3f, 0x73, -0xb3, 0x32, 0xa7, 0x00, 0xca, 0x5f, 0xe0, 0x7e, 0xa7, 0x26, 0xbf, 0xf4, 0x83, 0xe3, 0x58, 0x81, -0xbb, 0x22, 0xea, 0xda, 0xea, 0xbb, 0x9b, 0xf2, 0x46, 0x10, 0x3b, 0x6d, 0x03, 0xfa, 0xc5, 0x7f, -0x2d, 0x21, 0x4f, 0xf8, 0xf3, 0x17, 0x2e, 0xe2, 0xf6, 0x6c, 0x19, 0xf4, 0xb4, 0xa4, 0xb9, 0x65, -0x82, 0xbb, 0xa9, 0x05, 0xd8, 0x17, 0x6d, 0xc8, 0xb0, 0xaf, 0xce, 0x3d, 0x5d, 0x4b, 0xfa, 0xfe, -0x15, 0x74, 0xe5, 0xab, 0xde, 0xcb, 0x81, 0xd6, 0x97, 0x2a, 0xa3, 0x9d, 0x7b, 0x35, 0xe7, 0x2f, -0x37, 0x94, 0xbe, 0x0d, 0x71, 0x74, 0x91, 0xe7, 0x79, 0x3a, 0xbd, 0xf6, 0x7b, 0xd4, 0x0b, 0xc6, -0x33, 0xfd, 0xb7, 0x94, 0x02, 0x04, 0xcc, 0xbb, 0x12, 0xdc, 0x56, 0x65, 0x06, 0x78, 0xaf, 0xa0, -0x0f, 0x02, 0x81, 0x39, 0xee, 0xea, 0xd1, 0x09, 0x62, 0x03, 0x3c, 0x63, 0xca, 0xc8, 0xa8, 0x3f, -0x3b, 0xb7, 0x00, 0x63, 0xb7, 0xa4, 0x74, 0xba, 0x53, 0x3e, 0xde, 0x5c, 0x5f, 0xa2, 0x0c, 0xff, -0x49, 0x4b, 0x8f, 0x00, 0x17, 0xb9, 0x8b, 0xd5, 0x30, 0xff, 0x87, 0xb4, 0x4a, 0x51, 0x6b, 0x45, -0x42, 0xa1, 0x60, 0xc2, 0xbd, 0xea, 0x17, 0x5f, 0xd8, 0x14, 0x96, 0xc1, 0x3b, 0x52, 0xf7, 0x50, -0x23, 0x56, 0xc7, 0x0b, 0x26, 0x2f, 0x39, 0xe9, 0x27, 0xee, 0x63, 0x40, 0xeb, 0xa1, 0x2a, 0x2e, -0x56, 0xdb, 0x2d, 0xdd, 0x3f, 0xeb, 0xa9, 0x79, 0x36, 0x29, 0x3c, 0x12, 0x37, 0x75, 0x91, 0xfc, -0x11, 0xf7, 0xc6, 0x26, 0x5c, 0x82, 0xde, 0x78, 0xcd, 0x60, 0xe4, 0x0f, 0xdc, 0xb2, 0x77, 0x3d, -0x10, 0x27, 0xde, 0x4d, 0x3e, 0x22, 0x4e, 0x1c, 0xdd, 0x01, 0xc2, 0xc9, 0xe9, 0xbd, 0xc5, 0x7a, -0x58, 0xf8, 0xc9, 0xb0, 0x6f, 0x49, 0x4e, 0x8f, 0x30, 0x10, 0xaa, 0x7e, 0xb4, 0x8c, 0x3e, 0xe0, -0x87, 0x09, 0x97, 0x6e, 0xf0, 0xae, 0x33, 0x27, 0x39, 0xa6, 0xcb, 0x7e, 0x70, 0x55, 0x2f, 0x5d, -0xeb, 0xcc, 0x54, 0x44, 0x08, 0x66, 0xdf, 0x0b, 0x76, 0x8d, 0xfe, 0xd5, 0x14, 0xff, 0x79, 0x05, -0xdf, 0xa1, 0xde, 0xff, 0x4d, 0x2a, 0x2a, 0xbf, 0xfc, 0x17, 0xef, 0xc2, 0xff, 0x31, 0x5c, 0x57, -0xed, 0x1e, 0x11, 0x2e, 0xb6, 0x39, 0x5b, 0x09, 0x60, 0xab, 0x6d, 0x68, 0x74, 0x09, 0x20, 0xec, -0x68, 0xcc, 0x04, 0xc9, 0xe2, 0x45, 0x0d, 0x71, 0x75, 0xe8, 0x81, 0x69, 0xc0, 0xf0, 0x61, 0xf8, -0x69, 0xc4, 0x62, 0xa7, 0xcf, 0x8b, 0xb2, 0x81, 0x75, 0xa6, 0x92, 0x48, 0xac, 0xbb, 0xbf, 0x78, -0xb5, 0x6a, 0x1f, 0xda, 0xf4, 0x47, 0x16, 0x3c, 0xbd, 0xeb, 0x15, 0x17, 0xbc, 0x70, 0xa4, 0x4c, -0xe2, 0xf0, 0x57, 0x0b, 0x76, 0xa2, 0xfb, 0x6c, 0xe9, 0xb0, 0x98, 0x11, 0xc6, 0x32, 0xe1, 0xd4, -0x95, 0x97, 0xb1, 0xcb, 0x04, 0xd1, 0x7a, 0xc2, 0xe8, 0x7a, 0x8d, 0xf2, 0x73, 0x10, 0x5d, 0x6a, -0xc6, 0x25, 0xdf, 0xf3, 0x73, 0xc8, 0xae, 0x72, 0xc0, 0x09, 0x32, 0x7b, 0x2d, 0x31, 0x98, 0xae, -0x9d, 0xd8, 0x4e, 0x9c, 0xe7, 0xe4, 0xf1, 0x40, 0x21, 0xfc, 0x0d, 0xb2, 0x57, 0x33, 0xf7, 0x92, -0xcd, 0x8a, 0x4f, 0x0e, 0x8a, 0xc2, 0x45, 0x98, 0x5b, 0x53, 0x31, 0xef, 0xbe, 0xe8, 0x29, 0xfe, -0x64, 0xc3, 0xad, 0x68, 0x4c, 0x9a, 0x14, 0x69, 0xa8, 0x73, 0x71, 0x22, 0x6f, 0x1b, 0x8b, 0x86, -0x0f, 0x9a, 0x90, 0x0c, 0x72, 0xf2, 0x5f, 0x67, 0x62, 0x84, 0x72, 0x3d, 0x6b, 0xf2, 0x48, 0xcd, -0x6c, 0xb3, 0x94, 0xc1, 0x1c, 0xef, 0x92, 0x7e, 0xc8, 0x05, 0x41, 0xad, 0xd6, 0xf7, 0xb0, 0x43, -0x53, 0x72, 0xd6, 0xbe, 0x4f, 0xef, 0x7f, 0x1d, 0xb8, 0xf4, 0x22, 0xb2, 0x47, 0xf5, 0xae, 0x28, -0x3f, 0x12, 0xce, 0xbb, 0x4f, 0x05, 0xe1, 0x44, 0xcf, 0x7a, 0x72, 0x2e, 0x8d, 0x81, 0x09, 0xf6, -0xb5, 0xfc, 0x88, 0xb4, 0xcd, 0xa3, 0x08, 0xea, 0x51, 0x33, 0xe3, 0xef, 0xc4, 0x1b, 0xe0, 0x47, -0x3f, 0x85, 0xc0, 0x9a, 0x65, 0x88, 0xa2, 0xb0, 0xd2, 0x0a, 0x51, 0x9c, 0x28, 0x12, 0xbf, 0x7c, -0xf9, 0x92, 0x0e, 0xe9, 0xbe, 0xd0, 0x05, 0xfb, 0xbb, 0x10, 0xb3, 0xd0, 0xd3, 0x44, 0xa7, 0xbf, -0xc8, 0x6c, 0x5f, 0x5b, 0x70, 0xca, 0x06, 0xdd, 0xa1, 0x9b, 0xae, 0x57, 0xa6, 0x25, 0xcd, 0x4a, -0x60, 0xdb, 0x92, 0x0e, 0x36, 0x4a, 0x35, 0xcf, 0x7e, 0x0e, 0x7e, 0xd6, 0xc6, 0xa8, 0x7f, 0x7b, -0xb2, 0xf2, 0x90, 0xac, 0xfc, 0x78, 0x48, 0xaf, 0xb0, 0xa8, 0x97, 0x09, 0xd0, 0x50, 0x3b, 0x03, -0x7d, 0xdd, 0x4b, 0x46, 0x3e, 0xad, 0x96, 0x81, 0xfa, 0xff, 0x64, 0x39, 0x19, 0xe3, 0xdf, 0x07, -0x75, 0x52, 0x66, 0x36, 0xb6, 0x47, 0x51, 0x43, 0x7a, 0x98, 0xbb, 0x5a, 0xa2, 0x3d, 0x82, 0x8e, -0x57, 0x4d, 0xe1, 0x6a, 0xf6, 0x6e, 0x65, 0xfb, 0x6e, 0x59, 0x72, 0xeb, 0x5b, 0x39, 0x35, 0xd9, -0xfb, 0x2b, 0x1b, 0xd5, 0xef, 0xd4, 0xbf, 0x69, 0xf9, 0x03, 0xdc, 0x4a, 0x81, 0x37, 0x88, 0xab, -0x5d, 0x3c, 0xb9, 0xbe, 0x17, 0xfb, 0x84, 0xa6, 0x32, 0xf7, 0x04, 0x2e, 0x20, 0xac, 0x81, 0x30, -0xc0, 0xf8, 0x0d, 0xbb, 0x6b, 0xba, 0x90, 0x59, 0x69, 0x1c, 0x42, 0x93, 0xae, 0xbb, 0x2a, 0x17, -0x89, 0x9e, 0xd7, 0x54, 0xd3, 0x9d, 0xeb, 0x4f, 0x3b, 0x23, 0xf2, 0x1b, 0x93, 0x3c, 0x23, 0x1b, -0xfd, 0x64, 0xa9, 0x04, 0xed, 0xd0, 0x6e, 0xd9, 0x9b, 0x38, 0x29, 0x89, 0xe1, 0xbf, 0x28, 0x7e, -0x92, 0xf7, 0xaa, 0x05, 0xeb, 0x20, 0x35, 0x43, 0x64, 0xe0, 0x80, 0x4b, 0x55, 0x1b, 0x0a, 0xd0, -0x9a, 0x91, 0x78, 0x07, 0x35, 0xa1, 0x97, 0x21, 0x04, 0xc1, 0xaa, 0x17, 0x03, 0x50, 0xa8, 0x93, -0x8e, 0xa7, 0xea, 0x5e, 0x58, 0x53, 0x7d, 0x14, 0x11, 0x32, 0xcc, 0x28, 0x7f, 0x85, 0xba, 0x37, -0x75, 0x6e, 0xf2, 0x1e, 0x35, 0x47, 0x16, 0xf4, 0x40, 0x73, 0x7a, 0x1a, 0x1f, 0x1f, 0xe5, 0x65, -0xd3, 0x53, 0xfb, 0x22, 0x6c, 0x87, 0xbb, 0x28, 0xf1, 0x87, 0xa2, 0x71, 0x69, 0x7f, 0xda, 0x8a, -0x10, 0xca, 0x1f, 0xbe, 0x39, 0x77, 0x64, 0xe2, 0x23, 0xd6, 0x6f, 0x68, 0x5a, 0x72, 0xff, 0x51, -0x7f, 0xd1, 0x96, 0xad, 0xfd, 0xc3, 0x39, 0xdd, 0x08, 0x7a, 0x50, 0x2a, 0x81, 0xfc, 0xb3, 0x0b, -0x10, 0x56, 0xeb, 0x6d, 0x27, 0xf2, 0xb3, 0x0d, 0x52, 0x67, 0x60, 0xe9, 0xfd, 0x9c, 0xf8, 0xda, -0x91, 0xf6, 0x4d, 0x51, 0xea, 0xeb, 0xe8, 0x4a, 0xd4, 0x5e, 0xa5, 0x2d, 0x27, 0x58, 0x5c, 0x44, -0x0a, 0x23, 0x28, 0x39, 0x46, 0xd9, 0x58, 0x94, 0x91, 0xe2, 0x85, 0x0e, 0xbf, 0x24, 0xb2, 0x33, -0xc1, 0x89, 0x7a, 0xc7, 0x7b, 0xb2, 0xdb, 0x26, 0x66, 0x11, 0xfe, 0x16, 0x09, 0xc8, 0x33, 0x8b, -0xe2, 0x75, 0x9c, 0xc4, 0x07, 0x5f, 0xf8, 0x38, 0xe5, 0x60, 0x4f, 0x66, 0x1d, 0xed, 0xba, 0xa6, -0xfb, 0xe0, 0xa8, 0x22, 0xdf, 0x24, 0xc3, 0x51, 0x83, 0xba, 0xb9, 0x0e, 0x59, 0x37, 0xd8, 0xe2, -0x04, 0x24, 0x17, 0x6d, 0x35, 0xe9, 0xb2, 0x78, 0x4f, 0x7e, 0x71, 0x18, 0x01, 0x0e, 0x22, 0x15, -0x6b, 0x75, 0xd4, 0xf3, 0xb8, 0x54, 0x3b, 0x91, 0xab, 0x1b, 0x91, 0xc6, 0x8d, 0x92, 0xbe, 0x0c, -0x52, 0x5a, 0xdc, 0x65, 0x14, 0x33, 0x74, 0xa7, 0xf8, 0xff, 0xa9, 0x3b, 0x87, 0x2e, 0x5a, 0x29, -0x00, 0x00}; -#endif /*__STYLE_CSS_H__*/ diff --git a/src/web/html/h/system_html.h b/src/web/html/h/system_html.h deleted file mode 100644 index 1db39ad8..00000000 --- a/src/web/html/h/system_html.h +++ /dev/null @@ -1,139 +0,0 @@ -#ifndef __SYSTEM_HTML_H__ -#define __SYSTEM_HTML_H__ -#define system_html_len 2134 -const uint8_t system_html[] PROGMEM = { -0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0xd5, 0x59, 0x6d, 0x6f, 0xdb, 0x38, -0x12, 0xfe, 0xde, 0x5f, 0xc1, 0x6a, 0x81, 0xb3, 0x74, 0xb5, 0x25, 0x27, 0x7d, 0xdd, 0xc4, 0xce, -0x22, 0x4d, 0xb3, 0x6d, 0x80, 0x24, 0x5b, 0x24, 0x2e, 0xba, 0x8b, 0x20, 0x30, 0x68, 0x89, 0xb6, -0x98, 0x48, 0xa2, 0x4a, 0x52, 0x4e, 0xbc, 0xbb, 0xf9, 0xef, 0x37, 0x43, 0x49, 0xb6, 0x65, 0x4b, -0x8e, 0xdb, 0x6e, 0x71, 0x77, 0xfe, 0x22, 0x8b, 0x9c, 0x19, 0x3e, 0x33, 0x9c, 0x79, 0x38, 0x92, -0x7a, 0x4f, 0x03, 0xe1, 0xeb, 0x59, 0xca, 0x48, 0xa8, 0xe3, 0xe8, 0xe0, 0x49, 0x2f, 0xbf, 0x10, -0xf8, 0xf5, 0x42, 0x46, 0x83, 0xfc, 0xaf, 0xb9, 0xd5, 0x5c, 0x47, 0xec, 0xe0, 0x72, 0xa6, 0x34, -0x8b, 0x7b, 0x5e, 0x7e, 0xb7, 0x98, 0x8d, 0x78, 0x72, 0x4b, 0x24, 0x8b, 0xfa, 0x96, 0xd2, 0xb3, -0x88, 0xa9, 0x90, 0x31, 0x6d, 0x11, 0xb4, 0xdc, 0xb7, 0x34, 0xbb, 0xd7, 0x9e, 0xaf, 0x94, 0x45, -0x42, 0xc9, 0xc6, 0x85, 0x84, 0x0b, 0x03, 0xbf, 0x4c, 0xfb, 0x5d, 0xf7, 0x8d, 0xdb, 0xed, 0x76, -0x77, 0x2c, 0x0f, 0x16, 0x8f, 0x99, 0xa6, 0x24, 0xa1, 0x31, 0xe8, 0x4c, 0x39, 0xbb, 0x4b, 0x85, -0x04, 0x1b, 0xbe, 0x48, 0x34, 0x4b, 0x74, 0xdf, 0xba, 0xe3, 0x81, 0x0e, 0xfb, 0x01, 0x9b, 0x72, -0x9f, 0x75, 0xcc, 0x4d, 0x9b, 0xf0, 0x84, 0x6b, 0x4e, 0xa3, 0x8e, 0xf2, 0x69, 0xc4, 0xfa, 0x3b, -0x56, 0x69, 0xc4, 0x0f, 0xa9, 0x54, 0x0c, 0x94, 0x3e, 0x0d, 0x7e, 0xed, 0xbc, 0xc1, 0x61, 0xe5, -0x4b, 0x9e, 0xea, 0x65, 0x44, 0x37, 0x74, 0x4a, 0xf3, 0x51, 0x8b, 0x28, 0xe9, 0xf7, 0x2d, 0x9a, -0x72, 0xf7, 0xa6, 0x02, 0xea, 0xa0, 0xe7, 0xe5, 0x12, 0x60, 0xe0, 0x6b, 0x3c, 0xf4, 0x45, 0x24, -0xa4, 0x7a, 0xc4, 0x45, 0x29, 0x46, 0x42, 0xab, 0x25, 0x07, 0x13, 0xc1, 0x93, 0x80, 0xdd, 0xb7, -0x49, 0x22, 0xc6, 0x22, 0x8a, 0xc4, 0x9d, 0x45, 0xbc, 0x62, 0x2f, 0xbc, 0xc5, 0x66, 0xf4, 0x46, -0x22, 0x98, 0x2d, 0x45, 0x3e, 0xe0, 0x53, 0xe2, 0x47, 0x54, 0x29, 0x80, 0x21, 0xd2, 0x84, 0x4e, -0xad, 0x42, 0x8e, 0x16, 0x60, 0xbc, 0x65, 0x0c, 0x73, 0x51, 0xdc, 0x3f, 0xeb, 0xe0, 0x30, 0x14, -0xb3, 0x77, 0x83, 0x4f, 0x3d, 0x8f, 0xae, 0x28, 0x2d, 0x82, 0xb3, 0x37, 0x15, 0x3c, 0xb0, 0xbb, -0xce, 0xfe, 0x5c, 0x97, 0x03, 0x62, 0x8b, 0x88, 0xc4, 0x8f, 0xb8, 0x7f, 0x5b, 0xae, 0x6a, 0x3b, -0xd6, 0x12, 0x28, 0x95, 0xd2, 0x04, 0x83, 0x87, 0x97, 0xaf, 0x1e, 0x5d, 0xa0, 0x41, 0xdf, 0x78, -0x30, 0x77, 0xac, 0x04, 0x10, 0x8b, 0x11, 0x47, 0xf4, 0x0b, 0x1b, 0xd4, 0x88, 0x81, 0xcc, 0xf3, -0xb9, 0x50, 0xc8, 0x03, 0x56, 0xee, 0x87, 0x17, 0xf1, 0x29, 0xab, 0x6c, 0xec, 0x29, 0x0c, 0xcc, -0xd7, 0xa9, 0x9a, 0x78, 0x51, 0x6f, 0x42, 0x31, 0x09, 0x99, 0x56, 0x31, 0xf2, 0x99, 0x8d, 0xf2, -0xd1, 0x06, 0x4b, 0x2f, 0x9b, 0x2c, 0xe9, 0x2c, 0xad, 0x18, 0xba, 0x64, 0x5a, 0xf3, 0x64, 0xa2, -0xaa, 0x76, 0x30, 0x22, 0xa5, 0x01, 0xc5, 0x52, 0x26, 0xa9, 0x16, 0xd2, 0x5a, 0x0f, 0xe0, 0x7c, -0xbd, 0x57, 0xf5, 0xeb, 0x65, 0x69, 0x40, 0x75, 0xd5, 0xfd, 0x4f, 0x66, 0xa8, 0x01, 0xf6, 0xeb, -0x06, 0xd8, 0xa6, 0xf4, 0xab, 0xb8, 0x0b, 0x36, 0xf8, 0x2e, 0xd4, 0x6f, 0xe6, 0x2b, 0x40, 0x01, -0x42, 0x45, 0x51, 0x39, 0xc1, 0xca, 0x1d, 0x8e, 0x22, 0x9a, 0xdc, 0x5a, 0x07, 0x17, 0xc7, 0x97, -0x03, 0x72, 0xf8, 0xf1, 0xa4, 0x01, 0xec, 0xcf, 0xa5, 0x76, 0xa8, 0x75, 0xaa, 0xf6, 0x3c, 0x8f, -0x42, 0x4a, 0x07, 0x3a, 0x73, 0x11, 0xf9, 0xaa, 0xad, 0x77, 0xc2, 0xcf, 0x62, 0xa8, 0x35, 0xaa, -0xb9, 0x48, 0x1a, 0x0c, 0xee, 0x74, 0x17, 0x78, 0x46, 0x22, 0xd3, 0x15, 0x87, 0x0f, 0x71, 0xe4, -0x3b, 0xfd, 0xed, 0x36, 0xa4, 0xa8, 0x98, 0xf0, 0x04, 0x12, 0x13, 0x2f, 0x4d, 0xd0, 0x1a, 0x35, -0x01, 0x95, 0x51, 0x5d, 0x46, 0xd7, 0xf3, 0xa0, 0x7c, 0x56, 0x0a, 0xe9, 0x8e, 0x8f, 0x79, 0x5e, -0xbe, 0x65, 0x2d, 0x27, 0x63, 0x81, 0x60, 0x8d, 0xe8, 0x92, 0x46, 0x55, 0x4b, 0xd2, 0x14, 0x1c, -0x5b, 0x2a, 0xb8, 0xca, 0x74, 0x41, 0x60, 0x2b, 0xd3, 0x15, 0x11, 0xb3, 0x4c, 0xb9, 0x26, 0xb0, -0x63, 0x47, 0xc5, 0x9d, 0x9d, 0x5d, 0x82, 0xff, 0xe2, 0xa0, 0xf3, 0x8a, 0xc4, 0xba, 0xf3, 0x7c, -0x0e, 0xa3, 0xd1, 0x0a, 0x1e, 0x4e, 0x0b, 0x12, 0x00, 0x15, 0x12, 0x8f, 0x1a, 0xf4, 0x56, 0x5d, -0x69, 0xf0, 0x6c, 0x2c, 0x84, 0xae, 0x38, 0xb6, 0x4c, 0xa7, 0x11, 0x1b, 0xeb, 0x2a, 0xc9, 0x6c, -0x9f, 0x69, 0x05, 0xb1, 0x92, 0x7f, 0xf9, 0x22, 0x9d, 0x91, 0xdd, 0xee, 0xee, 0xf3, 0xea, 0x9e, -0x66, 0xd1, 0x0a, 0xde, 0x88, 0x1f, 0xac, 0x2d, 0x10, 0x70, 0xe5, 0x0b, 0x19, 0xb8, 0x93, 0x89, -0xf7, 0xf9, 0xcf, 0xf0, 0xfe, 0xf8, 0x8f, 0x57, 0xbb, 0xf1, 0xdb, 0x9a, 0xac, 0xce, 0xc5, 0x70, -0x81, 0x1e, 0x30, 0xdd, 0x16, 0x86, 0x27, 0x5c, 0x87, 0xd9, 0xc8, 0xf5, 0x45, 0xec, 0x45, 0x59, -0x4c, 0xd3, 0xcc, 0xf8, 0xb2, 0x6e, 0xf9, 0xbd, 0x91, 0x5b, 0x37, 0xdc, 0xf3, 0x4a, 0xfc, 0xab, -0x49, 0x56, 0x84, 0x4e, 0xf2, 0x49, 0x58, 0x89, 0x5d, 0x83, 0xbf, 0x2b, 0x0b, 0x6e, 0x05, 0xd3, -0x83, 0xfb, 0x98, 0x6b, 0xe5, 0x8d, 0xc6, 0xaf, 0x5f, 0xef, 0xbe, 0x7e, 0x09, 0x30, 0x4f, 0x06, -0xe4, 0xf2, 0xc3, 0xe1, 0x1e, 0x29, 0x46, 0xc8, 0xde, 0x1e, 0x29, 0x6b, 0xb6, 0x31, 0x2a, 0x66, -0xff, 0x99, 0x4a, 0x87, 0x78, 0x84, 0x5b, 0xdb, 0x46, 0xce, 0x97, 0x0c, 0xc8, 0x63, 0xca, 0x10, -0x83, 0x48, 0x94, 0x2b, 0xe4, 0x04, 0x14, 0x7d, 0x96, 0x28, 0x06, 0x80, 0x66, 0x9d, 0xc4, 0xef, -0x28, 0xea, 0xbd, 0x70, 0xbb, 0x5e, 0xc0, 0x58, 0xb0, 0x16, 0x51, 0x72, 0x70, 0x74, 0x44, 0xde, -0xfe, 0xd1, 0x39, 0x3f, 0xea, 0x5c, 0x1e, 0x12, 0x10, 0xdb, 0x22, 0xb6, 0xab, 0xb9, 0xbb, 0xb1, -0x93, 0xa9, 0xba, 0x30, 0xce, 0x12, 0x1f, 0xa9, 0x8e, 0xa4, 0xd8, 0x0e, 0xbd, 0x67, 0x09, 0x9c, -0x56, 0xbe, 0x2d, 0x46, 0x37, 0x0e, 0xf9, 0x6b, 0xad, 0xcc, 0x8c, 0xcc, 0x39, 0x9c, 0xe4, 0x38, -0xbf, 0x5f, 0x3f, 0x7d, 0x7c, 0xf9, 0x71, 0xd3, 0xf4, 0x85, 0x52, 0xbc, 0x66, 0xfe, 0xe1, 0xc9, -0x06, 0x54, 0x70, 0x86, 0x9c, 0x00, 0x3b, 0x34, 0xa1, 0x02, 0x72, 0x51, 0x9a, 0xc0, 0x69, 0x45, -0x49, 0x9f, 0x5c, 0x59, 0x2a, 0xb8, 0xb5, 0xda, 0xc4, 0xf2, 0xd3, 0x6c, 0x38, 0x96, 0xec, 0x8b, -0xf9, 0x1f, 0xf2, 0x74, 0x28, 0xa1, 0x2d, 0x54, 0x60, 0xd3, 0x6a, 0xaf, 0x59, 0xc0, 0x5f, 0x2e, -0x14, 0x8b, 0x80, 0x45, 0x73, 0x15, 0xa8, 0x19, 0xa6, 0xf0, 0x6e, 0x9e, 0x04, 0xf0, 0x3f, 0xa6, -0x3e, 0x5e, 0x90, 0x27, 0x87, 0x12, 0xbc, 0xc1, 0x1b, 0xad, 0x86, 0x59, 0xaa, 0x79, 0xcc, 0x9a, -0x8c, 0x8f, 0x21, 0xe9, 0xc3, 0xa1, 0xe2, 0x7f, 0x1a, 0x13, 0xea, 0x96, 0x69, 0x3f, 0x1c, 0x66, -0x0a, 0xf6, 0x1f, 0x6e, 0xa1, 0x73, 0x03, 0xf3, 0x42, 0xd3, 0x68, 0x7e, 0x07, 0xc8, 0xd9, 0xd2, -0x0d, 0x9d, 0x34, 0x19, 0x8e, 0xe9, 0xbd, 0x11, 0x86, 0xec, 0x31, 0x6e, 0x4f, 0x99, 0xcc, 0x9d, -0x04, 0x17, 0x00, 0xfd, 0x70, 0xe9, 0x5e, 0xb2, 0x11, 0x70, 0x19, 0xc4, 0x81, 0x2a, 0x18, 0xb8, -0xde, 0x7f, 0xb2, 0x66, 0x11, 0x1a, 0x58, 0xa6, 0x30, 0x88, 0xd7, 0xeb, 0xbb, 0x37, 0x16, 0x92, -0xd8, 0x79, 0xa8, 0xaf, 0x6e, 0xd9, 0xac, 0x4d, 0xa6, 0x34, 0xca, 0xd8, 0x35, 0x11, 0x63, 0xf2, -0xdb, 0xe8, 0x86, 0xf9, 0xda, 0x05, 0x82, 0x97, 0x9c, 0x29, 0xb3, 0x4d, 0x75, 0xfb, 0x84, 0x3f, -0x3e, 0xb6, 0x9f, 0xe2, 0x4e, 0xb9, 0x1c, 0x7a, 0xc3, 0x2c, 0x00, 0x69, 0xb0, 0xe5, 0x90, 0xbf, -0xff, 0x26, 0x36, 0xc6, 0x17, 0x8c, 0x19, 0xb3, 0xa4, 0xdf, 0x27, 0xad, 0x0c, 0x5a, 0xdd, 0x31, -0x20, 0x0a, 0x5a, 0x60, 0x0e, 0x4f, 0x10, 0x9e, 0x64, 0x6c, 0xbf, 0xd6, 0xac, 0x01, 0xee, 0xa6, -0x99, 0x0a, 0x6d, 0x2d, 0xd1, 0xa4, 0x2b, 0x59, 0x1a, 0x51, 0x9f, 0xd9, 0xad, 0x61, 0xab, 0x4d, -0x5a, 0xa4, 0xe5, 0x14, 0x80, 0x9d, 0x9a, 0xc4, 0x7c, 0x58, 0x8f, 0x44, 0x50, 0xb4, 0x01, 0x2e, -0x94, 0xe6, 0x71, 0xc4, 0xf0, 0xef, 0xdb, 0xd9, 0x49, 0x60, 0xe7, 0xc7, 0x94, 0xe3, 0xe2, 0x69, -0x97, 0x04, 0x76, 0x2d, 0x18, 0x6c, 0xc4, 0x11, 0x90, 0x6d, 0xe5, 0xcd, 0x0f, 0xc1, 0xe4, 0x95, -0xb1, 0xe9, 0x28, 0x2c, 0xa7, 0x7e, 0x1f, 0xe3, 0xc8, 0xb6, 0x34, 0x1d, 0x45, 0xb8, 0xe9, 0x7f, -0x19, 0x86, 0xdc, 0x23, 0xc5, 0xc0, 0x43, 0xbd, 0xc6, 0x5c, 0x0b, 0x9b, 0x7d, 0xd4, 0x7a, 0x68, -0xe7, 0x61, 0x70, 0x6a, 0xc5, 0xd7, 0x47, 0xb7, 0xac, 0xc0, 0x11, 0x0d, 0x26, 0xcc, 0x56, 0x99, -0xef, 0x33, 0xa5, 0xda, 0x04, 0xd9, 0xa4, 0x4d, 0x14, 0xb0, 0x5b, 0x82, 0xe4, 0x28, 0x25, 0x74, -0x32, 0x75, 0x9b, 0x2d, 0xa1, 0x83, 0x95, 0x89, 0x41, 0x88, 0x5d, 0xce, 0xb2, 0x5b, 0xc6, 0x62, -0x6e, 0xb7, 0x63, 0x91, 0x67, 0xc4, 0x2e, 0xad, 0x3b, 0xe4, 0x17, 0xa8, 0x8d, 0xfc, 0xbf, 0x45, -0xf6, 0x8a, 0x55, 0x9c, 0x87, 0x7c, 0xd5, 0x2d, 0xf1, 0xce, 0xa3, 0x6f, 0x74, 0x36, 0x23, 0x03, -0xd6, 0x5c, 0x06, 0x86, 0xaa, 0x24, 0xed, 0xec, 0xe6, 0xbd, 0x06, 0x2c, 0x5b, 0x23, 0x23, 0xe1, -0x99, 0xab, 0x7e, 0x06, 0x3a, 0x15, 0x42, 0x3b, 0xbe, 0x55, 0xc2, 0x75, 0x9c, 0xed, 0x19, 0xee, -0x82, 0x06, 0xfc, 0x11, 0x7e, 0x4b, 0x73, 0x76, 0x3b, 0x3b, 0x39, 0x27, 0xb6, 0x34, 0x87, 0x0b, -0x24, 0x20, 0x0b, 0x1c, 0xac, 0xec, 0xd3, 0xdf, 0x3e, 0xe3, 0xe5, 0xc3, 0xc9, 0xfb, 0x0f, 0x78, -0x3d, 0x3b, 0xfc, 0xdd, 0xaa, 0xa9, 0xe0, 0x82, 0x27, 0xa5, 0xb1, 0xb3, 0x43, 0xce, 0x50, 0x74, -0xb7, 0xb8, 0xbc, 0xec, 0x92, 0x5b, 0xeb, 0x7a, 0xbd, 0x0e, 0xa0, 0x5e, 0x01, 0x95, 0x2b, 0x11, -0xdf, 0xb9, 0x1c, 0x43, 0x8d, 0x37, 0x55, 0xf6, 0x9c, 0x3b, 0x1a, 0xb3, 0x15, 0x2a, 0xd3, 0x3a, -0xbf, 0xf8, 0x75, 0xf7, 0xc5, 0x29, 0xf4, 0xc9, 0xed, 0x22, 0xb1, 0x2a, 0xd6, 0xb1, 0x4b, 0x49, -0x12, 0xe0, 0x12, 0x16, 0xb4, 0x21, 0x2d, 0x9a, 0xe6, 0x4c, 0x9e, 0x60, 0x82, 0xc0, 0xf3, 0xb0, -0x26, 0x90, 0x7e, 0xcf, 0x30, 0xfa, 0xc5, 0xa4, 0xe5, 0x38, 0xed, 0xc7, 0x21, 0x90, 0x8f, 0xe2, -0x8e, 0x49, 0x72, 0xca, 0xa6, 0x86, 0xee, 0x53, 0x7a, 0x55, 0x59, 0x2c, 0xc5, 0xd9, 0x61, 0x84, -0xb3, 0xd7, 0x5b, 0x99, 0x7b, 0x87, 0xa7, 0xcf, 0x05, 0x3c, 0x30, 0x81, 0xb1, 0x40, 0x56, 0x8d, -0x21, 0xdf, 0xe1, 0xd4, 0x35, 0xe2, 0x1c, 0xa5, 0xca, 0xaa, 0xaf, 0xd0, 0x9a, 0x1d, 0x7b, 0x20, -0x2c, 0x52, 0x6c, 0x73, 0xb8, 0x6b, 0xa3, 0x3a, 0xa6, 0xa0, 0xd7, 0xce, 0xe3, 0xc3, 0x12, 0xa4, -0x11, 0x8c, 0x4b, 0x1d, 0xe5, 0xff, 0x33, 0x44, 0x67, 0xf2, 0x97, 0x00, 0x8c, 0xff, 0x2d, 0x7e, -0x5b, 0x1b, 0xdb, 0x98, 0xdf, 0x47, 0xb1, 0xde, 0x90, 0xdf, 0x7e, 0xac, 0xcb, 0x70, 0x1f, 0x9d, -0x0d, 0x76, 0x9f, 0x77, 0xbb, 0x87, 0xeb, 0x49, 0x8c, 0x26, 0x9a, 0x92, 0x78, 0x65, 0xee, 0xb1, -0x24, 0xfe, 0xba, 0x74, 0xd8, 0x84, 0xee, 0xbf, 0x93, 0x0c, 0x00, 0xe3, 0xc7, 0x26, 0x03, 0xb8, -0xfc, 0x8d, 0x47, 0xdd, 0x5a, 0x26, 0x6c, 0xe4, 0xe6, 0xb3, 0x2f, 0x5a, 0x37, 0x51, 0x73, 0x91, -0x3e, 0x45, 0x54, 0xbf, 0x8f, 0x1a, 0x17, 0x9b, 0xbf, 0x9c, 0x56, 0x6b, 0xb9, 0x54, 0x4d, 0x20, -0x2d, 0x33, 0x66, 0x92, 0xc8, 0x6c, 0x32, 0x6c, 0xeb, 0x23, 0x6c, 0xf5, 0xd3, 0xe0, 0x77, 0x30, -0x8f, 0x76, 0xf4, 0xfd, 0xd0, 0x4f, 0xf4, 0x63, 0xe2, 0x17, 0xa5, 0xb8, 0xcc, 0xc5, 0x9b, 0x98, -0xeb, 0x5b, 0xa8, 0x0b, 0x17, 0x28, 0xf3, 0x71, 0x35, 0x57, 0x4b, 0x77, 0x7e, 0x58, 0x92, 0x9e, -0x7d, 0x19, 0x0c, 0xfe, 0xff, 0x9a, 0x31, 0x93, 0x90, 0x27, 0xf8, 0x0a, 0xf8, 0x91, 0x8c, 0x84, -0x07, 0x12, 0x95, 0x25, 0x92, 0x2b, 0x46, 0x0e, 0x48, 0xb7, 0x29, 0x31, 0xbf, 0x27, 0x94, 0x2b, -0x9d, 0x6e, 0xd6, 0xd8, 0xda, 0x7e, 0x7b, 0x44, 0xeb, 0xa2, 0x7a, 0xb5, 0x51, 0xba, 0xcc, 0xdb, -0xcb, 0xdc, 0x77, 0xd0, 0x49, 0xd8, 0x1d, 0x1e, 0xce, 0x6c, 0x35, 0x2a, 0xff, 0x26, 0x3b, 0xf0, -0xec, 0xef, 0xb8, 0x5a, 0x9c, 0x0a, 0xfc, 0x32, 0x70, 0x09, 0xcf, 0x2e, 0xc9, 0xc4, 0x6e, 0x05, -0xac, 0xf3, 0xee, 0xb8, 0xb5, 0xa9, 0x8c, 0x56, 0xd6, 0x51, 0x4c, 0xd7, 0x2f, 0x03, 0x13, 0xff, -0xd0, 0x2a, 0x47, 0xd0, 0xec, 0x65, 0x09, 0xf7, 0xcd, 0x13, 0x04, 0x51, 0x9a, 0xca, 0xca, 0x92, -0xab, 0xae, 0x75, 0x48, 0x31, 0x20, 0xc6, 0x63, 0x00, 0xe1, 0xfc, 0x20, 0x14, 0x22, 0x6d, 0x00, -0x81, 0x8e, 0x3f, 0xfb, 0x31, 0x18, 0xce, 0xf1, 0xa5, 0x11, 0x19, 0xb1, 0x90, 0x4e, 0xb9, 0xc8, -0x64, 0x85, 0x29, 0x03, 0xae, 0xcc, 0x34, 0xe2, 0x2c, 0xc9, 0x72, 0x79, 0xcc, 0xf0, 0x25, 0x9c, -0x81, 0x86, 0x2e, 0xf3, 0xf3, 0x96, 0xf8, 0x0b, 0x9f, 0x92, 0x89, 0x79, 0xaa, 0xa7, 0x32, 0xc1, -0xbf, 0x8e, 0xb3, 0x11, 0xcf, 0x75, 0xf3, 0x74, 0x43, 0xc5, 0xd7, 0x3d, 0x75, 0x6e, 0x5d, 0xf1, -0x1b, 0x8a, 0x3d, 0xc9, 0xa2, 0x88, 0x3c, 0xed, 0x93, 0x06, 0x89, 0xf9, 0x7b, 0x97, 0xa5, 0x37, -0x3b, 0x57, 0xd6, 0x24, 0xbf, 0xb1, 0xae, 0xeb, 0xf8, 0x75, 0xdd, 0xf0, 0x95, 0x25, 0xd9, 0x58, -0x32, 0x15, 0x82, 0x42, 0xc3, 0x1a, 0xf8, 0x9b, 0x52, 0x49, 0xcc, 0xc7, 0xab, 0xfe, 0x82, 0x58, -0xcc, 0xcb, 0x30, 0x56, 0x70, 0x8b, 0xdd, 0xc2, 0xe9, 0x96, 0xb3, 0xdf, 0xcc, 0x13, 0x30, 0xef, -0xe2, 0x8b, 0xb4, 0xe3, 0x2f, 0x19, 0x9f, 0x82, 0xa1, 0xf9, 0xca, 0x9b, 0x55, 0x8a, 0xf7, 0xcb, -0x64, 0x15, 0x2e, 0x6e, 0xf2, 0x3e, 0xf9, 0x74, 0x71, 0xda, 0xb7, 0xf2, 0x94, 0x9c, 0xcf, 0x0d, -0x33, 0x19, 0xd5, 0x3d, 0x24, 0x6d, 0xa0, 0x46, 0xf5, 0x76, 0x36, 0xa0, 0x93, 0x73, 0x1a, 0x33, -0xbb, 0x85, 0xcc, 0xd7, 0x72, 0xae, 0xba, 0xd7, 0x05, 0x47, 0x1e, 0x85, 0x3c, 0x0a, 0x6c, 0xc4, -0xd2, 0xe0, 0xdd, 0x43, 0xed, 0x28, 0x9e, 0x91, 0x1b, 0x22, 0x5a, 0x7d, 0x36, 0x74, 0xf3, 0xcf, -0x2b, 0x1b, 0xc2, 0x57, 0xe9, 0x57, 0x0a, 0x71, 0x37, 0x86, 0xfb, 0xc7, 0x74, 0x96, 0xde, 0xb0, -0x5d, 0x59, 0xb9, 0x9e, 0x49, 0x8e, 0x26, 0x25, 0x08, 0xca, 0xe1, 0x0d, 0xbd, 0xb7, 0x5b, 0xf8, -0x41, 0xc6, 0x33, 0xdf, 0x24, 0x5b, 0xed, 0xa5, 0xd3, 0xe9, 0xab, 0x82, 0xd0, 0x78, 0x0a, 0x99, -0x97, 0xf9, 0x8e, 0xcb, 0xa1, 0xe1, 0x91, 0x1f, 0x06, 0x67, 0xa7, 0xe5, 0xf6, 0x9a, 0xf1, 0xeb, -0xaf, 0xac, 0xa8, 0x12, 0xb2, 0xf9, 0x86, 0xe4, 0xe5, 0xdf, 0x09, 0x9e, 0x91, 0x3b, 0xc0, 0x2e, -0xee, 0xdc, 0x48, 0xe4, 0xb4, 0xe6, 0xa6, 0x54, 0x87, 0xf8, 0xed, 0xb5, 0x70, 0x66, 0xc9, 0x8f, -0xc5, 0x77, 0xde, 0xfc, 0x2e, 0xff, 0xc6, 0xda, 0xf3, 0xf2, 0xcf, 0xe1, 0xff, 0x01, 0xf7, 0x15, -0xfc, 0x5a, 0x26, 0x1f, 0x00, 0x00}; -#endif /*__SYSTEM_HTML_H__*/ diff --git a/src/web/html/h/update_html.h b/src/web/html/h/update_html.h deleted file mode 100644 index a853a186..00000000 --- a/src/web/html/h/update_html.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef __UPDATE_HTML_H__ -#define __UPDATE_HTML_H__ -#define update_html_len 1090 -const uint8_t update_html[] PROGMEM = { -0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0xa5, 0x57, 0x5b, 0x6f, 0xdb, 0x36, -0x14, 0x7e, 0xef, 0xaf, 0xe0, 0xf4, 0x30, 0xd8, 0x43, 0x2c, 0x3a, 0xe9, 0x25, 0x59, 0x2a, 0x7b, -0x70, 0xd2, 0xac, 0x0b, 0x30, 0x74, 0x41, 0x9d, 0xa0, 0xe8, 0x53, 0x41, 0x51, 0x47, 0x16, 0x13, -0x8a, 0x14, 0x48, 0x4a, 0x8e, 0x37, 0xec, 0xbf, 0x8f, 0xd4, 0xc5, 0x96, 0x6c, 0x29, 0x73, 0x51, -0xbf, 0x48, 0x24, 0xcf, 0xf9, 0xce, 0x77, 0xae, 0x94, 0x83, 0x9f, 0x22, 0x49, 0xcd, 0x26, 0x03, -0x94, 0x98, 0x94, 0xcf, 0x5f, 0x05, 0xd5, 0x03, 0xd9, 0x5f, 0x90, 0x00, 0x89, 0xaa, 0xd7, 0x72, -0x69, 0x98, 0xe1, 0x30, 0x7f, 0xc8, 0x22, 0x62, 0x20, 0xc0, 0xd5, 0x6a, 0x77, 0xca, 0x99, 0x78, -0x42, 0x0a, 0xf8, 0xcc, 0xd3, 0x66, 0xc3, 0x41, 0x27, 0x00, 0xc6, 0x43, 0x0e, 0x79, 0xe6, 0x19, -0x78, 0x36, 0x98, 0x6a, 0xed, 0xa1, 0x44, 0x41, 0x5c, 0x4b, 0xf8, 0x76, 0xe3, 0xb7, 0x62, 0x36, -0xf5, 0x2f, 0xfc, 0xe9, 0x74, 0x7a, 0xea, 0x61, 0x6b, 0x3c, 0x05, 0x43, 0x90, 0x20, 0xa9, 0xd5, -0x29, 0x18, 0xac, 0x33, 0xa9, 0x2c, 0x06, 0x95, 0xc2, 0x80, 0x30, 0x33, 0x6f, 0xcd, 0x22, 0x93, -0xcc, 0x22, 0x28, 0x18, 0x85, 0x49, 0xb9, 0x38, 0x41, 0x4c, 0x30, 0xc3, 0x08, 0x9f, 0x68, 0x4a, -0x38, 0xcc, 0x4e, 0xbd, 0x06, 0x84, 0x26, 0x44, 0x69, 0xb0, 0x4a, 0x0f, 0xf7, 0xbf, 0x4f, 0x2e, -0xdc, 0xb6, 0xa6, 0x8a, 0x65, 0xa6, 0xcd, 0xe8, 0x91, 0x14, 0xa4, 0xda, 0xf5, 0x90, 0x56, 0x74, -0xe6, 0x91, 0x8c, 0xf9, 0x8f, 0x1d, 0x52, 0xf3, 0x00, 0x57, 0x12, 0x16, 0xe0, 0x7b, 0x3c, 0xa4, -0x92, 0x4b, 0xa5, 0xff, 0xc7, 0x45, 0x25, 0x43, 0x69, 0x74, 0xcb, 0x41, 0x21, 0x99, 0x88, 0xe0, -0xf9, 0x04, 0x09, 0x19, 0x4b, 0xce, 0xe5, 0xda, 0x43, 0xb8, 0xce, 0x05, 0xde, 0x25, 0x23, 0x08, -0x65, 0xb4, 0x69, 0x45, 0x3e, 0x62, 0x05, 0xa2, 0x9c, 0x68, 0x6d, 0x69, 0xc8, 0x4c, 0x90, 0xc2, -0xab, 0xe5, 0x48, 0x4d, 0x06, 0xb7, 0x39, 0x6c, 0x45, 0x5d, 0xfe, 0xbc, 0xf9, 0x22, 0x91, 0x9b, -0x0f, 0xf7, 0x0f, 0x01, 0x26, 0x7b, 0x4a, 0xbb, 0xe0, 0x5c, 0x16, 0x92, 0x45, 0xa3, 0xe9, 0xf8, -0xfd, 0x56, 0x97, 0x59, 0xc6, 0x1e, 0x92, 0x82, 0x72, 0x46, 0x9f, 0x1a, 0xab, 0xa3, 0xb1, 0xd7, -0x22, 0xa5, 0x33, 0x22, 0x5c, 0xf0, 0xdc, 0xe3, 0xbb, 0x77, 0x77, 0x6c, 0x9c, 0x6f, 0x2c, 0xda, -0x3a, 0xd6, 0x10, 0x48, 0x65, 0xc8, 0x1c, 0xfb, 0x1d, 0x06, 0x29, 0xc5, 0xac, 0xcc, 0xeb, 0xad, -0x50, 0xc2, 0x22, 0x68, 0xf2, 0x81, 0x39, 0x2b, 0xa0, 0x93, 0xd8, 0x3f, 0xed, 0xc6, 0xd6, 0x4e, -0x17, 0xe2, 0x4d, 0x3f, 0x84, 0x06, 0x65, 0x2b, 0xad, 0x03, 0xf2, 0x05, 0xc2, 0x6a, 0x77, 0x00, -0xe9, 0xed, 0x10, 0x92, 0xc9, 0xb3, 0x0e, 0xd0, 0x12, 0x8c, 0x61, 0x62, 0xa5, 0xbb, 0x38, 0x2e, -0x22, 0x0d, 0x80, 0x86, 0x0c, 0x14, 0x31, 0x52, 0x79, 0x87, 0x01, 0xdc, 0xda, 0x7b, 0xd7, 0x6f, -0x2f, 0x2f, 0x7b, 0xb6, 0x63, 0xb0, 0x69, 0xe3, 0x5e, 0xda, 0xe7, 0x03, 0xb4, 0x37, 0xda, 0x40, -0xda, 0xe5, 0x5d, 0x6e, 0xfd, 0x20, 0xeb, 0x8b, 0xad, 0x05, 0xdb, 0x80, 0xb6, 0xa3, 0x88, 0x5a, -0xb9, 0xce, 0xfd, 0x16, 0x72, 0x22, 0x9e, 0xbc, 0xf9, 0xe7, 0x9b, 0xe5, 0x3d, 0x5a, 0xdc, 0xdd, -0x0e, 0x90, 0xfd, 0xb5, 0xd1, 0x4e, 0x8c, 0xc9, 0xf4, 0x25, 0xc6, 0xc4, 0x96, 0x74, 0x64, 0x72, -0xdf, 0x31, 0xdf, 0xc7, 0xfa, 0x20, 0x69, 0x9e, 0xda, 0x5e, 0x23, 0x86, 0x49, 0x31, 0x00, 0x78, -0x3a, 0xdd, 0xf1, 0x09, 0x65, 0x6e, 0x3a, 0x0e, 0x2f, 0xdc, 0xce, 0x0f, 0xfa, 0x3b, 0x1d, 0x28, -0x51, 0xb9, 0x62, 0xc2, 0x16, 0xa6, 0x7b, 0x0c, 0x51, 0x1b, 0xd4, 0xb4, 0xac, 0x4a, 0xd5, 0x36, -0xbb, 0x00, 0xdb, 0xf6, 0xd9, 0x6b, 0xa4, 0x35, 0x8b, 0x59, 0xd5, 0xbe, 0x4d, 0x2f, 0x8b, 0x58, -0x3a, 0xb2, 0xa5, 0x68, 0x4b, 0xa3, 0xab, 0xa5, 0x48, 0x66, 0x1d, 0x6b, 0x35, 0x5c, 0xe7, 0xb8, -0x1e, 0x60, 0x7b, 0xc7, 0xa5, 0x48, 0xcc, 0x80, 0x47, 0xb6, 0xde, 0x0f, 0x8f, 0xaa, 0x5b, 0x03, -0x56, 0x20, 0xa2, 0x86, 0x4b, 0x04, 0xda, 0xb5, 0x02, 0x07, 0x6a, 0x50, 0xcc, 0x54, 0xba, 0x26, -0x0a, 0xec, 0x0b, 0x07, 0x34, 0xfa, 0xc5, 0x0f, 0x99, 0x18, 0x07, 0xb8, 0x52, 0x18, 0x40, 0x8b, -0xa5, 0x4a, 0x4b, 0x42, 0xee, 0xc5, 0x43, 0x76, 0xd4, 0x26, 0xd2, 0xae, 0xee, 0xfe, 0x5a, 0xde, -0x7b, 0x88, 0x50, 0x97, 0xf3, 0x6d, 0x37, 0x78, 0x08, 0x04, 0xad, 0x86, 0x77, 0x9a, 0x73, 0xc3, -0x32, 0xa2, 0x0c, 0x76, 0x7a, 0x13, 0x7b, 0x4a, 0x9c, 0x38, 0x85, 0xcc, 0x4c, 0xb6, 0xf7, 0x48, -0x6e, 0xe2, 0xf2, 0x1e, 0x41, 0x03, 0xbf, 0x80, 0x89, 0x2c, 0x6f, 0xae, 0x17, 0xc7, 0xd9, 0xab, -0xa7, 0x7c, 0x6d, 0xee, 0x48, 0xcd, 0x30, 0x37, 0xa6, 0x95, 0x9d, 0xd0, 0xd8, 0xf7, 0x82, 0xf0, -0xdc, 0x1e, 0x3d, 0xd4, 0xbc, 0xb7, 0x73, 0xd7, 0xd5, 0x40, 0x67, 0xea, 0x76, 0x50, 0x4b, 0x67, -0x7a, 0x32, 0x82, 0xfb, 0x53, 0xb2, 0x9f, 0xfa, 0x81, 0x4a, 0x88, 0xa5, 0x34, 0x9d, 0x42, 0x68, -0x5f, 0x3f, 0x1c, 0x62, 0xd3, 0x1d, 0xca, 0xc7, 0x77, 0x66, 0x7d, 0x11, 0xa1, 0x9f, 0xa9, 0xcc, -0x36, 0xe8, 0x6c, 0x7a, 0xf6, 0xba, 0xdb, 0x03, 0x39, 0xdf, 0xe3, 0xcb, 0xd9, 0xfc, 0xc0, 0x40, -0xc4, 0x34, 0x95, 0x2a, 0xf2, 0x57, 0x2b, 0xfc, 0xe5, 0xef, 0xe4, 0xf9, 0xe6, 0xeb, 0xbb, 0xb3, -0xf4, 0xaa, 0x67, 0x0a, 0x54, 0x62, 0xce, 0x80, 0xad, 0x28, 0x76, 0x04, 0xf0, 0x8a, 0x99, 0x24, -0x0f, 0x7d, 0x2a, 0x53, 0xcc, 0xf3, 0x94, 0x64, 0x79, 0xe9, 0xcb, 0x21, 0xf2, 0xc7, 0x52, 0xee, -0x10, 0x38, 0xc0, 0x0d, 0xff, 0xfd, 0xa6, 0xac, 0x43, 0xa7, 0xd8, 0x2a, 0xe9, 0xc4, 0x6e, 0xc0, -0xdf, 0x3d, 0x83, 0x47, 0xd1, 0xc4, 0x76, 0x9d, 0x32, 0xa3, 0x71, 0x18, 0x9f, 0x9f, 0x9f, 0x9d, -0xbf, 0xb5, 0x34, 0x6f, 0xef, 0xd1, 0xf2, 0x8f, 0xc5, 0x25, 0xaa, 0x77, 0xd0, 0xe5, 0x25, 0x6a, -0x66, 0xdc, 0x60, 0x54, 0xca, 0xfc, 0x83, 0xce, 0xbe, 0xb9, 0x4a, 0xf5, 0x8e, 0x8d, 0x1c, 0x55, -0x60, 0x87, 0x6d, 0x01, 0x8e, 0x83, 0x14, 0xda, 0x97, 0x6a, 0x65, 0x15, 0x29, 0x08, 0x0d, 0x96, -0xd0, 0x66, 0x22, 0xe8, 0x44, 0x13, 0xfc, 0xc6, 0x9f, 0xe2, 0x08, 0x20, 0x3a, 0x88, 0x28, 0x9a, -0x5f, 0x5f, 0xa3, 0xab, 0xaf, 0x93, 0x4f, 0xd7, 0x93, 0xe5, 0x02, 0x59, 0xb1, 0x23, 0x62, 0xbb, -0x5f, 0xbb, 0x2f, 0x7e, 0xf9, 0x75, 0x5d, 0x88, 0x73, 0x51, 0x8e, 0x09, 0x94, 0xb9, 0xb6, 0xff, -0x08, 0xc2, 0xde, 0xee, 0x74, 0x24, 0xc3, 0xc7, 0x31, 0xfa, 0xe7, 0xa0, 0x95, 0x4a, 0x99, 0x4f, -0xf6, 0xcb, 0xc7, 0x9d, 0xbf, 0xef, 0x3f, 0xbe, 0x59, 0xde, 0xbd, 0x74, 0xfc, 0x59, 0x6b, 0xd6, -0x73, 0xfe, 0xef, 0xab, 0x7e, 0x56, 0x55, 0xc7, 0xf7, 0x50, 0x89, 0xea, 0x7b, 0xcd, 0xb7, 0xb1, -0xbb, 0xe1, 0xe0, 0x5e, 0xaf, 0x36, 0xb7, 0xd1, 0xa8, 0x9a, 0x84, 0x63, 0x5f, 0xe7, 0xa1, 0xad, -0x80, 0x51, 0x0f, 0x8d, 0x82, 0x28, 0x04, 0x68, 0x36, 0x8c, 0xd0, 0x0c, 0xf7, 0x1e, 0x5d, 0xf0, -0x15, 0x64, 0x9c, 0x50, 0xb8, 0x4e, 0x18, 0x8f, 0x14, 0x88, 0x91, 0xbb, 0xf2, 0x46, 0xf5, 0xc8, -0x43, 0xda, 0xe6, 0xd2, 0xd8, 0x9c, 0x8e, 0x5f, 0xf6, 0xce, 0x1a, 0x5c, 0x3c, 0x92, 0xe7, 0x51, -0x79, 0xfd, 0xe3, 0x55, 0x15, 0x73, 0xef, 0xa4, 0x93, 0x82, 0x16, 0xc2, 0xee, 0x8b, 0xbc, 0x5a, -0x55, 0x5f, 0xc3, 0xf6, 0x03, 0xb9, 0xfc, 0xe3, 0xf2, 0x1f, 0x6f, 0x3a, 0xe4, 0xb0, 0xd0, 0x0c, -0x00, 0x00}; -#endif /*__UPDATE_HTML_H__*/ diff --git a/src/web/html/h/visualization_html.h b/src/web/html/h/visualization_html.h deleted file mode 100644 index 4fdaad5d..00000000 --- a/src/web/html/h/visualization_html.h +++ /dev/null @@ -1,275 +0,0 @@ -#ifndef __VISUALIZATION_HTML_H__ -#define __VISUALIZATION_HTML_H__ -#define visualization_html_len 4311 -const uint8_t visualization_html[] PROGMEM = { -0x1f, 0x8b, 0x08, 0x00, 0x81, 0xb3, 0x2f, 0x65, 0x02, 0xff, 0xed, 0x1c, 0x6b, 0x73, 0xdb, 0x38, -0xee, 0x7b, 0x7f, 0x05, 0xab, 0x99, 0xed, 0xda, 0x5b, 0x3f, 0xf3, 0x6a, 0x37, 0xaf, 0x4e, 0x9a, -0xa6, 0xdb, 0xdc, 0xb5, 0x69, 0xaf, 0xc9, 0x6e, 0x6f, 0x27, 0x93, 0xc9, 0xd0, 0x12, 0x6d, 0xb1, -0x91, 0x25, 0x9d, 0x48, 0xdb, 0xf1, 0xee, 0xe4, 0xbf, 0x1f, 0x40, 0x4a, 0xb2, 0x6c, 0x8b, 0xb2, -0xe4, 0xb8, 0xdd, 0xbd, 0x99, 0xcb, 0x87, 0x24, 0x92, 0x08, 0x10, 0x00, 0x01, 0x10, 0x00, 0x21, -0x1d, 0x3e, 0x75, 0x02, 0x5b, 0x4e, 0x43, 0x46, 0x5c, 0x39, 0xf4, 0x8e, 0x9f, 0x1c, 0xea, 0x3f, -0x04, 0x7e, 0x0e, 0x5d, 0x46, 0x1d, 0xfd, 0xaf, 0xba, 0x94, 0x5c, 0x7a, 0xec, 0xf8, 0x3d, 0x1f, -0xb3, 0xc3, 0xb6, 0xfe, 0x7f, 0xf6, 0xcc, 0xe3, 0xfe, 0x1d, 0x89, 0x98, 0x77, 0x64, 0x09, 0x39, -0xf5, 0x98, 0x70, 0x19, 0x93, 0x16, 0x41, 0xbc, 0x47, 0x96, 0x64, 0xf7, 0xb2, 0x6d, 0x0b, 0x61, -0x11, 0x37, 0x62, 0xfd, 0x78, 0x44, 0x0b, 0x6e, 0xbc, 0x1a, 0x1f, 0x75, 0x5a, 0x2f, 0x5b, 0x9d, -0x4e, 0xa7, 0x6b, 0xb5, 0x61, 0xea, 0x21, 0x93, 0x94, 0xf8, 0x74, 0x08, 0x30, 0x63, 0xce, 0x26, -0x61, 0x10, 0x01, 0x0e, 0x3b, 0xf0, 0x25, 0xf3, 0xe5, 0x91, 0x35, 0xe1, 0x8e, 0x74, 0x8f, 0x1c, -0x36, 0xe6, 0x36, 0x6b, 0xaa, 0x8b, 0x06, 0xe1, 0x3e, 0x97, 0x9c, 0x7a, 0x4d, 0x61, 0x53, 0x8f, -0x1d, 0x75, 0xad, 0x04, 0x89, 0xed, 0xd2, 0x48, 0x30, 0x00, 0xfa, 0xf5, 0xea, 0x6d, 0xf3, 0x25, -0xde, 0x16, 0x76, 0xc4, 0x43, 0x99, 0xa5, 0xe8, 0x2b, 0x1d, 0x53, 0x7d, 0xd7, 0x22, 0x22, 0xb2, -0x8f, 0x2c, 0x1a, 0xf2, 0xd6, 0xd7, 0x39, 0xa2, 0x8e, 0x0f, 0xdb, 0x7a, 0x04, 0x20, 0xa8, 0xc2, -0xa1, 0x1d, 0x78, 0x41, 0x24, 0x56, 0xb0, 0x18, 0x05, 0xbd, 0x40, 0x8a, 0x0c, 0x83, 0x7e, 0xc0, -0x7d, 0x87, 0xdd, 0x37, 0x88, 0x1f, 0xf4, 0x03, 0xcf, 0x0b, 0x26, 0x16, 0x69, 0x67, 0x44, 0x9c, -0x01, 0xa5, 0x61, 0xe8, 0xb1, 0xe6, 0x30, 0xe8, 0x71, 0xf8, 0x33, 0x61, 0xbd, 0x26, 0xdc, 0x68, -0xda, 0x34, 0xa4, 0x3d, 0x8f, 0x65, 0x10, 0x4e, 0x99, 0xb0, 0xe2, 0xa5, 0x6c, 0xcf, 0xd6, 0xf2, -0xb0, 0x17, 0x38, 0xd3, 0x0c, 0x5e, 0x87, 0x8f, 0x89, 0xed, 0x51, 0x21, 0x80, 0x8f, 0x20, 0xf4, -0xe9, 0x38, 0x81, 0xa1, 0x31, 0x37, 0xed, 0x2c, 0x13, 0xe9, 0x50, 0x54, 0x00, 0xeb, 0xf8, 0xc4, -0x0d, 0xa6, 0x6f, 0xae, 0x7e, 0x3d, 0x6c, 0xd3, 0x05, 0xa0, 0x99, 0x74, 0xf7, 0xc7, 0x01, 0x77, -0x6a, 0x9d, 0xfa, 0x41, 0x0a, 0xcb, 0x81, 0x42, 0x8b, 0x04, 0xbe, 0xed, 0x71, 0xfb, 0x2e, 0x99, -0xb5, 0x56, 0xb7, 0x32, 0x44, 0x89, 0x90, 0xfa, 0x28, 0x7d, 0xfc, 0x53, 0xf9, 0xee, 0x8c, 0x1a, -0xe4, 0x8d, 0x3b, 0x29, 0x63, 0x09, 0x01, 0x5a, 0x72, 0xd9, 0xf9, 0xa8, 0x1a, 0x06, 0x63, 0xb6, -0xd3, 0x41, 0x2e, 0x77, 0x58, 0xb2, 0xa0, 0x6d, 0x0f, 0xb4, 0x7e, 0x4e, 0x33, 0xb4, 0x19, 0xd0, -0x3c, 0x14, 0x3b, 0xf9, 0x28, 0x04, 0x8b, 0x40, 0x55, 0xe7, 0x90, 0x7c, 0x61, 0x3d, 0x7d, 0xd7, -0x80, 0x69, 0xd7, 0x84, 0x49, 0x8e, 0xc2, 0x39, 0x44, 0x97, 0x4c, 0x4a, 0xee, 0x0f, 0xc4, 0x3c, -0x1e, 0x94, 0x48, 0x82, 0x40, 0xb0, 0x90, 0x45, 0x54, 0x06, 0x91, 0xb5, 0x2c, 0xc0, 0x74, 0xbe, -0xbd, 0xfc, 0xf9, 0x46, 0xa1, 0x43, 0xe5, 0x3c, 0xfb, 0xbf, 0xaa, 0x5b, 0x06, 0xb2, 0x5f, 0x18, -0xc8, 0x9e, 0x0a, 0xc9, 0x86, 0xf3, 0x74, 0xab, 0x5b, 0x8f, 0xa4, 0xfa, 0x65, 0x3a, 0x03, 0x58, -0x30, 0x98, 0x24, 0x8d, 0x06, 0x68, 0xfa, 0xb7, 0x3d, 0x8f, 0xfa, 0x77, 0xd6, 0xf1, 0xe7, 0xb3, -0xcb, 0x2b, 0x72, 0xf2, 0xe9, 0xdc, 0x40, 0xec, 0xcf, 0x09, 0xb4, 0x2b, 0x65, 0x28, 0xf6, 0xdb, -0x6d, 0x0a, 0x2a, 0xed, 0xc8, 0x51, 0x0b, 0x29, 0x5f, 0xc4, 0xf5, 0x26, 0xb0, 0x47, 0x43, 0xb0, -0x2d, 0x2a, 0x79, 0xe0, 0x1b, 0x10, 0x76, 0x3b, 0x33, 0x7a, 0x7a, 0xc1, 0x48, 0xce, 0x31, 0x7c, -0x82, 0x77, 0x1e, 0xc9, 0x6f, 0xc7, 0xa0, 0xa2, 0xc1, 0x80, 0xfb, 0xa0, 0x98, 0xf8, 0xc7, 0x44, -0x9a, 0x11, 0x12, 0xa8, 0x52, 0xa0, 0x59, 0xea, 0x0e, 0xdb, 0x60, 0x3e, 0x0b, 0x86, 0x34, 0xe1, -0x7d, 0xae, 0xcd, 0x37, 0xb1, 0x65, 0xbf, 0x1f, 0x20, 0xb1, 0x6a, 0x68, 0x06, 0x62, 0x1e, 0x2a, -0x02, 0x07, 0xc5, 0xa2, 0x8c, 0xc1, 0xcd, 0x3d, 0x8e, 0x1d, 0xd6, 0xc2, 0xe3, 0xb9, 0x21, 0x68, -0x7f, 0xe9, 0x34, 0x4b, 0xa3, 0xc2, 0xe3, 0xb3, 0x31, 0x8b, 0xa6, 0xb1, 0x2c, 0x71, 0x3c, 0x30, -0x16, 0x81, 0x8f, 0x4e, 0xc5, 0x48, 0x04, 0x83, 0x59, 0x1c, 0x41, 0xa4, 0xcb, 0xc8, 0x98, 0x7a, -0x23, 0x26, 0x08, 0x8d, 0x18, 0xd1, 0xaa, 0xed, 0x1c, 0xb6, 0xc3, 0x05, 0xda, 0x16, 0x38, 0x31, -0x30, 0xd6, 0x0f, 0x02, 0x39, 0xc7, 0x57, 0xd6, 0x9b, 0x7a, 0xac, 0x2f, 0xe7, 0x7d, 0x4c, 0x79, -0x45, 0x8b, 0xfd, 0x2a, 0x79, 0x66, 0x07, 0xe1, 0x94, 0x6c, 0x75, 0xb6, 0xb6, 0xe7, 0x97, 0x74, -0xe4, 0x2d, 0xd0, 0xeb, 0xf1, 0xe3, 0xa5, 0x09, 0x1c, 0x2e, 0xec, 0x20, 0x72, 0x5a, 0x83, 0x41, -0xfb, 0xcb, 0x1f, 0xee, 0xfd, 0xd9, 0xef, 0x7b, 0x5b, 0xc3, 0xd7, 0x39, 0x4a, 0xad, 0x87, 0xe1, -0x04, 0x87, 0xe0, 0xe8, 0x4a, 0x20, 0x1e, 0x70, 0xe9, 0x8e, 0x7a, 0x2d, 0x3b, 0x18, 0xb6, 0xbd, -0xd1, 0x90, 0x86, 0x23, 0xc5, 0xcb, 0x32, 0xe6, 0x5f, 0xd4, 0xb8, 0x65, 0xc4, 0x87, 0xed, 0x84, -0xfe, 0x45, 0x1d, 0x8b, 0x45, 0x17, 0xf1, 0x81, 0x3b, 0x27, 0x3b, 0x03, 0xbf, 0x0b, 0x13, 0x96, -0x22, 0xb3, 0x0d, 0xd7, 0x43, 0x2e, 0x45, 0xbb, 0xd7, 0x7f, 0xf1, 0x62, 0xeb, 0xc5, 0x2e, 0x90, -0x79, 0x7e, 0x45, 0x2e, 0xdf, 0x9d, 0xec, 0x93, 0xf8, 0x0e, 0xd9, 0xdf, 0x27, 0x89, 0xc9, 0x1a, -0xa5, 0xa2, 0xd6, 0x9f, 0x89, 0xf0, 0x16, 0x43, 0x00, 0xab, 0xac, 0xe4, 0xec, 0x88, 0x81, 0xef, -0x18, 0x33, 0xa4, 0x21, 0xf0, 0x45, 0x2b, 0x88, 0x06, 0x00, 0x68, 0x33, 0x5f, 0x30, 0x20, 0x68, -0xda, 0xf4, 0xed, 0xa6, 0xa0, 0xed, 0x9d, 0x56, 0xa7, 0xed, 0x30, 0xe6, 0x2c, 0x49, 0x94, 0x1c, -0x9f, 0x9e, 0x92, 0xd7, 0xbf, 0x37, 0x2f, 0x4e, 0x9b, 0x97, 0x27, 0x04, 0x86, 0x95, 0x90, 0xed, -0xa2, 0xee, 0x16, 0x46, 0x42, 0xf3, 0x2c, 0x8c, 0x69, 0x44, 0xd8, 0x3d, 0xfb, 0xe8, 0xdb, 0x8c, -0x1c, 0x11, 0x19, 0x8d, 0xd8, 0xc1, 0xd2, 0xf3, 0x11, 0x84, 0x60, 0x02, 0x22, 0xb1, 0xf1, 0x99, -0xbf, 0xfc, 0x70, 0x78, 0x3e, 0x7e, 0x07, 0xf1, 0x24, 0x00, 0x5f, 0xdf, 0xe4, 0x3c, 0xbd, 0x18, -0x0d, 0xe1, 0x51, 0x67, 0xf9, 0x89, 0x0c, 0x24, 0x45, 0xa8, 0x93, 0x28, 0xa2, 0xd3, 0xda, 0x6e, -0xbd, 0xd5, 0xe7, 0x9e, 0x87, 0x31, 0xc4, 0xf2, 0xc8, 0x4f, 0x93, 0xe8, 0xc4, 0xbe, 0x3b, 0x78, -0x32, 0xf7, 0xa4, 0x3f, 0xf2, 0x6d, 0x74, 0xd1, 0x24, 0xc4, 0x38, 0xf0, 0x17, 0xe6, 0xc3, 0x2e, -0x6b, 0xd7, 0x82, 0xde, 0xd7, 0x3a, 0xf9, 0x73, 0xc9, 0x7d, 0xf0, 0x7e, 0x0d, 0x59, 0x23, 0x47, -0x47, 0x09, 0xb3, 0xf5, 0xe5, 0x41, 0xf8, 0xa3, 0x90, 0x5d, 0x40, 0xa8, 0x82, 0x88, 0x0e, 0xcc, -0x43, 0xce, 0x2e, 0x3f, 0x19, 0x86, 0x3c, 0x3c, 0xc9, 0x05, 0xf8, 0x2c, 0x04, 0xcf, 0x81, 0x78, -0x30, 0x30, 0xe5, 0x8f, 0x86, 0xaf, 0xf9, 0xa0, 0x06, 0x6e, 0xac, 0xa1, 0xc4, 0xdf, 0x20, 0x0e, -0x13, 0x79, 0x9c, 0x45, 0x10, 0x28, 0x44, 0x3e, 0x19, 0x7a, 0x35, 0x0b, 0x74, 0xc0, 0x6a, 0x90, -0x3f, 0x95, 0x7d, 0xed, 0x13, 0x8c, 0x50, 0x9b, 0x7b, 0x04, 0x7f, 0x8b, 0x61, 0x73, 0x87, 0xd0, -0xa6, 0x6d, 0x3d, 0x34, 0xc8, 0x75, 0x2e, 0x4f, 0x39, 0xe0, 0x11, 0x04, 0xa7, 0x0f, 0x8d, 0xdc, -0xd1, 0x06, 0x08, 0x98, 0xca, 0x3c, 0x43, 0x16, 0x0e, 0xdd, 0x75, 0x16, 0xb0, 0x2f, 0x9a, 0xbb, -0x04, 0x7e, 0x0d, 0x9d, 0xe6, 0x0e, 0x62, 0xb8, 0x94, 0x11, 0x44, 0x3a, 0xb5, 0x0f, 0x54, 0xba, -0xad, 0x28, 0x18, 0xf9, 0x0e, 0xca, 0x81, 0xfc, 0x44, 0xba, 0x9d, 0x4e, 0x9d, 0xb4, 0xd5, 0x9f, -0x7a, 0x63, 0x9d, 0x59, 0xf6, 0xe2, 0x59, 0x5e, 0x90, 0xe1, 0x7d, 0xb3, 0x8b, 0x53, 0xa1, 0x6c, -0xeb, 0x46, 0x54, 0x37, 0xa6, 0x79, 0x36, 0x28, 0xaf, 0x75, 0xf8, 0xf8, 0x99, 0x84, 0x31, 0xfd, -0xa8, 0x15, 0x46, 0x0c, 0xf9, 0x4f, 0x96, 0xef, 0xde, 0x94, 0x57, 0xca, 0x0f, 0xdc, 0xd9, 0xa4, -0x52, 0xe2, 0x3f, 0xb0, 0x1e, 0xdb, 0x64, 0xd8, 0x6b, 0x6e, 0xfd, 0x8d, 0xd5, 0x73, 0xef, 0x9b, -0xaa, 0xe5, 0xcb, 0xff, 0x75, 0x75, 0xfc, 0xee, 0x9a, 0xa8, 0x36, 0x0f, 0x51, 0xcb, 0xd3, 0xbd, -0x7e, 0x10, 0xd5, 0x70, 0xd7, 0xe0, 0x6a, 0xdb, 0x81, 0x3f, 0x87, 0x64, 0x17, 0xfe, 0x3c, 0x7f, -0x9e, 0x37, 0x18, 0x7f, 0x14, 0xae, 0x6b, 0x7e, 0x03, 0xe3, 0x33, 0x4b, 0x9b, 0xde, 0xcd, 0xae, -0x6f, 0x9e, 0xb7, 0xaf, 0xa0, 0xfc, 0xb0, 0x26, 0x64, 0x28, 0xb5, 0xb6, 0xef, 0x9a, 0x64, 0xbd, -0x8e, 0xe6, 0xe6, 0xc0, 0x84, 0xcd, 0x2d, 0xcd, 0x59, 0xd3, 0x2d, 0xb3, 0xaa, 0xd5, 0xb4, 0xa7, -0x98, 0x56, 0xd4, 0xe6, 0x2d, 0xfc, 0x05, 0x96, 0xad, 0xb4, 0xda, 0xba, 0xfa, 0x78, 0x75, 0xf2, -0xde, 0xaa, 0x17, 0xe2, 0x2b, 0x30, 0x9d, 0x7a, 0x63, 0x3d, 0xce, 0x7b, 0x83, 0x72, 0x06, 0x9f, -0xcb, 0xfc, 0x0a, 0x38, 0xfc, 0x89, 0x37, 0x69, 0xad, 0x2a, 0x9d, 0x1b, 0x60, 0xf4, 0x0b, 0xe0, -0xb1, 0x4e, 0x4e, 0xc9, 0xa7, 0x60, 0x02, 0x39, 0x43, 0xbd, 0x51, 0x0d, 0x45, 0x57, 0xa1, 0x70, -0x11, 0xc7, 0xef, 0x9c, 0x79, 0x0e, 0x79, 0x43, 0xa7, 0x95, 0x91, 0x6c, 0x21, 0x92, 0xbb, 0x2c, -0x96, 0x2b, 0xbc, 0xbf, 0x42, 0xfa, 0x37, 0xf5, 0xca, 0x3a, 0xe2, 0x46, 0xd6, 0x43, 0xbd, 0xf1, -0x2d, 0x85, 0x8b, 0x9b, 0x8d, 0x66, 0x6a, 0x3b, 0x15, 0xee, 0x9b, 0x6a, 0xc2, 0x9d, 0xa1, 0xd8, -0x41, 0x14, 0xe0, 0x18, 0x10, 0xc9, 0x67, 0x46, 0x6d, 0x0c, 0xd1, 0x13, 0x54, 0x2b, 0x44, 0xf3, -0xa4, 0xe2, 0xa3, 0x9c, 0xdb, 0x4b, 0x7e, 0x2d, 0xd7, 0xad, 0xf1, 0xf1, 0x3b, 0x46, 0x9d, 0x82, -0x20, 0xb6, 0x43, 0x9e, 0x1e, 0x11, 0x78, 0xdc, 0x12, 0x92, 0xca, 0x11, 0xee, 0xbd, 0xa4, 0xdd, -0x26, 0x81, 0xef, 0x4d, 0x09, 0x75, 0x9c, 0xd8, 0x2d, 0xc2, 0x40, 0xc2, 0x7d, 0xc8, 0x96, 0x21, -0x6f, 0x25, 0x5c, 0xe0, 0x63, 0xee, 0xb3, 0x02, 0xdf, 0xd7, 0xb9, 0x21, 0xcf, 0x35, 0x5a, 0xdb, -0x85, 0x0b, 0x50, 0xa1, 0x03, 0x44, 0xfb, 0xe9, 0xf6, 0xe4, 0xb4, 0x00, 0x6a, 0x7b, 0x01, 0xea, -0x65, 0x02, 0xf5, 0xa6, 0x08, 0x6a, 0x67, 0x01, 0xaa, 0xdb, 0xd1, 0x60, 0xff, 0xca, 0x9b, 0x6c, -0x39, 0x96, 0x4e, 0x0c, 0x65, 0x1e, 0xc9, 0x0b, 0x8d, 0x43, 0xa9, 0x3b, 0xd8, 0x8c, 0x01, 0x6a, -0x6b, 0x01, 0x6a, 0x2f, 0x03, 0xa5, 0x6c, 0x64, 0xd9, 0x97, 0xab, 0xf4, 0x03, 0x36, 0x06, 0xdc, -0xf4, 0x6a, 0xd6, 0x33, 0xbf, 0x27, 0xc2, 0x83, 0x67, 0x0e, 0x1b, 0x1c, 0x9c, 0x5a, 0x39, 0xa1, -0x3f, 0x8e, 0xb6, 0x3d, 0x97, 0x00, 0x00, 0xac, 0xd4, 0xd1, 0xfc, 0x4a, 0xbd, 0x22, 0x16, 0x1f, -0x37, 0xdd, 0x26, 0x64, 0xec, 0x16, 0xd9, 0xd7, 0x17, 0x96, 0x09, 0x47, 0x6f, 0x50, 0x80, 0xa3, -0x37, 0xc8, 0x22, 0x01, 0x27, 0x97, 0x8f, 0x25, 0x9c, 0x44, 0xef, 0x39, 0x64, 0xc1, 0x80, 0xc9, -0xf2, 0xdb, 0xd4, 0x3a, 0x78, 0x92, 0xa7, 0x51, 0x7b, 0xbb, 0xbb, 0xdb, 0xbb, 0x89, 0x56, 0x85, -0x68, 0x0e, 0xb7, 0x1e, 0x42, 0xdd, 0x42, 0x16, 0xeb, 0x98, 0xb6, 0xcc, 0x0c, 0xea, 0x3c, 0x30, -0xf2, 0x9c, 0xc4, 0xb2, 0xfa, 0xc1, 0xca, 0xcf, 0xa1, 0xb2, 0xaa, 0x3c, 0xa4, 0xf7, 0xb7, 0x80, -0xd0, 0x6c, 0x65, 0xe9, 0x6c, 0xb0, 0x7a, 0x68, 0xbd, 0x80, 0x3e, 0xb3, 0x51, 0x67, 0x50, 0xc0, -0x5e, 0x9d, 0x4b, 0x8e, 0x8e, 0xcd, 0x90, 0xaa, 0x2f, 0xd6, 0x66, 0xb6, 0xf0, 0xad, 0xef, 0xb0, -0x7b, 0x23, 0x9f, 0xa0, 0x4d, 0x0f, 0xdf, 0xce, 0xc5, 0x96, 0xdc, 0xbe, 0xb3, 0x51, 0x1f, 0x49, -0x29, 0x0c, 0xb8, 0x8f, 0x75, 0xb1, 0x46, 0x52, 0xe4, 0xdf, 0x4f, 0xdd, 0x58, 0xcd, 0xa4, 0x36, -0x8b, 0x3f, 0x03, 0x26, 0x4f, 0xbe, 0xd2, 0xfb, 0x9a, 0xaa, 0xea, 0xb6, 0x13, 0x97, 0xd5, 0x86, -0x3f, 0x02, 0xd0, 0xb4, 0x51, 0x00, 0xb8, 0x9e, 0xdc, 0x69, 0xe8, 0x1c, 0xfa, 0x7c, 0xfc, 0x9b, -0x7e, 0x64, 0xc8, 0xcc, 0xe7, 0x56, 0x15, 0x08, 0x47, 0x60, 0x3c, 0x4d, 0xa9, 0xd7, 0xd7, 0x0e, -0x65, 0x30, 0x6b, 0x36, 0xb0, 0xa8, 0x14, 0xec, 0x43, 0xe0, 0x50, 0x4f, 0x39, 0xec, 0x87, 0x52, -0x22, 0x37, 0x45, 0xd1, 0x4e, 0xd3, 0x0f, 0x7c, 0x46, 0x1c, 0x4c, 0x8b, 0x7a, 0x5e, 0x60, 0xdf, -0x91, 0x44, 0xc0, 0x18, 0x3f, 0x9d, 0x64, 0x76, 0x2b, 0x72, 0x1a, 0xf8, 0x32, 0x0a, 0xbc, 0x7d, -0xa5, 0x20, 0x89, 0x6d, 0x94, 0xe0, 0xd0, 0x3c, 0xb5, 0x9e, 0x50, 0xcd, 0xad, 0xa8, 0x98, 0x9b, -0xfa, 0xd3, 0xe9, 0xc2, 0x4c, 0x2b, 0x27, 0xba, 0x79, 0x9c, 0xb8, 0xff, 0x02, 0x8d, 0xa3, 0x1e, -0x8d, 0x86, 0x79, 0xfa, 0x76, 0x82, 0x0f, 0x4a, 0x6a, 0x5b, 0xcd, 0x52, 0xa3, 0x85, 0x16, 0x17, -0x22, 0x52, 0x68, 0x6f, 0x6d, 0x5f, 0xd6, 0x1f, 0xa5, 0x81, 0xd1, 0x92, 0x45, 0xc6, 0x99, 0xe8, -0x6c, 0x2b, 0xdb, 0xbd, 0x41, 0xf7, 0x26, 0x5b, 0xdc, 0xf7, 0x59, 0x74, 0xc5, 0xee, 0xe5, 0xda, -0x21, 0x4d, 0xf5, 0x58, 0x5b, 0xfb, 0xa9, 0xde, 0x60, 0xfd, 0x50, 0xbb, 0x74, 0xa4, 0x9d, 0x0d, -0x51, 0x1e, 0x11, 0x6d, 0x67, 0x03, 0x87, 0x47, 0x45, 0xdc, 0xd9, 0x58, 0xe2, 0xef, 0x1e, 0x75, -0x27, 0xdb, 0x56, 0xe9, 0xc8, 0x3b, 0x13, 0xa3, 0x75, 0x53, 0x69, 0x7f, 0xa0, 0xf7, 0xe4, 0xa4, -0x7a, 0x08, 0x9e, 0x8d, 0x12, 0x1f, 0x11, 0xc9, 0xcf, 0xd0, 0xa8, 0x6c, 0xeb, 0xb7, 0x78, 0xfd, -0x7f, 0x0b, 0x3c, 0x49, 0x07, 0x6c, 0x2d, 0x44, 0x8a, 0xb5, 0x93, 0x18, 0xd1, 0xe9, 0x28, 0x8a, -0xf0, 0x94, 0x6a, 0x1d, 0x44, 0x2a, 0x45, 0x79, 0xf7, 0x07, 0x62, 0x7a, 0x1b, 0xb1, 0xff, 0x8c, -0x98, 0x6f, 0x4f, 0xd7, 0x42, 0xf4, 0x33, 0x22, 0xfa, 0x01, 0xf1, 0x9c, 0xf5, 0xfb, 0xdc, 0xe6, -0x6b, 0x23, 0xea, 0x76, 0x0a, 0x52, 0x9e, 0x35, 0xf0, 0xa9, 0x0c, 0x0a, 0x71, 0xe9, 0x7d, 0xe8, -0x2d, 0x20, 0x0c, 0xfe, 0x9a, 0xe4, 0xc9, 0x58, 0x9e, 0x3c, 0x75, 0x1f, 0x5d, 0x9d, 0xec, 0x6e, -0x25, 0xe5, 0xc9, 0xbd, 0xa4, 0x3c, 0x09, 0xb7, 0xfe, 0xee, 0xf5, 0xc9, 0xa4, 0xb0, 0xfd, 0xed, -0xeb, 0x94, 0x5b, 0xff, 0xaf, 0x53, 0x96, 0xaf, 0x53, 0xda, 0x6e, 0x4d, 0xe7, 0x6e, 0x0d, 0xd5, -0xd6, 0xd3, 0xc0, 0x73, 0xe9, 0x5c, 0x9d, 0x5c, 0x4a, 0x1d, 0x4d, 0x69, 0xa3, 0xed, 0x96, 0x4b, -0x1b, 0x8d, 0x29, 0x23, 0x20, 0xc8, 0x4d, 0x19, 0xcb, 0xd4, 0xec, 0x75, 0xa9, 0x5e, 0x56, 0x34, -0x05, 0x0c, 0x12, 0x20, 0xb0, 0x9b, 0x25, 0x34, 0x4a, 0x16, 0xe5, 0x55, 0xa4, 0x74, 0x90, 0xb1, -0x6e, 0x2e, 0x94, 0x3a, 0x0e, 0xa1, 0xe2, 0x0a, 0x75, 0xdc, 0xa9, 0x23, 0x8c, 0xb2, 0x7b, 0x54, -0x06, 0xc3, 0xde, 0x3c, 0x06, 0xdc, 0x30, 0xab, 0xa2, 0xd8, 0x4d, 0x51, 0xe0, 0x7f, 0xd6, 0x79, -0x14, 0x51, 0x87, 0xab, 0x7e, 0x94, 0x0a, 0x48, 0xb6, 0x53, 0x24, 0x6a, 0x67, 0x2a, 0x1d, 0xde, -0x64, 0x50, 0xec, 0xa4, 0x28, 0x76, 0x6e, 0x16, 0xe3, 0x9a, 0xd2, 0x48, 0x3a, 0x29, 0x92, 0x4e, -0x2c, 0xd1, 0x92, 0xdb, 0x75, 0x06, 0x47, 0x37, 0xc5, 0xd1, 0x8d, 0x71, 0xa4, 0x3b, 0xf5, 0x06, -0xb6, 0x97, 0xd2, 0x87, 0x0e, 0xe2, 0xdc, 0xef, 0x07, 0xa6, 0xea, 0x1c, 0x5a, 0x20, 0x70, 0x85, -0x43, 0xb0, 0xe2, 0xf2, 0x9e, 0x0a, 0x09, 0x36, 0x65, 0x33, 0xd8, 0x73, 0x1d, 0xe2, 0x50, 0x49, -0x89, 0x8a, 0x0a, 0x84, 0x84, 0x4b, 0x2a, 0x41, 0x35, 0x0f, 0xf2, 0xca, 0x31, 0xb8, 0xdb, 0x4a, -0x71, 0x0b, 0xda, 0x2b, 0x6f, 0xc5, 0xc8, 0xb6, 0x99, 0x10, 0xe4, 0x98, 0x74, 0x4c, 0xf9, 0x0d, -0x4e, 0x8a, 0xdd, 0x2d, 0x30, 0xa3, 0xcf, 0x26, 0xb0, 0xbc, 0x92, 0xe5, 0xa2, 0x50, 0xce, 0xbf, -0x63, 0x48, 0x64, 0x12, 0xaa, 0x9f, 0x1f, 0x11, 0x19, 0x9c, 0x8b, 0x00, 0xb1, 0xc0, 0x1e, 0x52, -0x43, 0xc4, 0xa5, 0x0e, 0xb8, 0x99, 0x27, 0xd8, 0x2a, 0xcc, 0x96, 0x1f, 0x48, 0x17, 0xb6, 0xa5, -0x54, 0x26, 0x86, 0x7a, 0x14, 0x52, 0x1f, 0x09, 0xc1, 0x81, 0x6b, 0xd8, 0x77, 0x5f, 0x98, 0x18, -0x8f, 0x47, 0x0e, 0xf0, 0xd8, 0x5f, 0x59, 0x06, 0x39, 0x24, 0x5b, 0x66, 0x65, 0xc8, 0x12, 0x42, -0x6a, 0x9f, 0x2f, 0x2f, 0xcf, 0x75, 0x96, 0x56, 0x9b, 0xcd, 0x07, 0x3e, 0xb3, 0xb9, 0xb7, 0xa3, -0x1c, 0xe6, 0xf1, 0x91, 0xf2, 0x94, 0x87, 0x96, 0xaa, 0x19, 0xe1, 0x6d, 0xe7, 0xf5, 0xb0, 0x6e, -0x28, 0x65, 0x19, 0x99, 0x2f, 0x9a, 0x37, 0x9d, 0x15, 0xf0, 0x1b, 0x70, 0x57, 0x2a, 0x4b, 0xc5, -0x07, 0x4a, 0x95, 0xc2, 0x13, 0x12, 0x36, 0xbb, 0xa0, 0xd3, 0x4d, 0x37, 0xd9, 0xd5, 0xd7, 0x08, -0x56, 0x2c, 0x83, 0x01, 0x56, 0xda, 0xff, 0x89, 0x3a, 0xb1, 0x11, 0xb0, 0x2d, 0x55, 0xa1, 0x64, -0xb1, 0x2e, 0x40, 0x92, 0xd2, 0xd5, 0x5a, 0x05, 0x02, 0x43, 0x61, 0x00, 0x1d, 0x6f, 0x80, 0x5b, -0x69, 0x5e, 0x71, 0xe0, 0x33, 0x3e, 0xbc, 0x84, 0x87, 0xa2, 0xa0, 0x42, 0x80, 0x95, 0x81, 0x58, -0x0b, 0x36, 0x1d, 0x5c, 0xc4, 0x64, 0x98, 0x1c, 0x12, 0xb6, 0xde, 0x3c, 0x7f, 0x7e, 0x90, 0x5f, -0xd4, 0xb6, 0x5d, 0x3f, 0xa7, 0x63, 0x67, 0xf1, 0xfc, 0xb4, 0xab, 0xcf, 0x4f, 0x75, 0x0a, 0xd0, -0xf2, 0x98, 0x3f, 0x90, 0x6e, 0xe1, 0x59, 0x2a, 0x02, 0xe2, 0xe6, 0x4e, 0x92, 0x3a, 0xfb, 0x2d, -0x5e, 0x5d, 0xf3, 0x1b, 0x63, 0x19, 0x18, 0x9f, 0xc7, 0x98, 0xd1, 0x04, 0x3b, 0x66, 0x1b, 0x8e, -0xf1, 0x5a, 0xa7, 0xef, 0x4e, 0x2e, 0x2e, 0xce, 0xde, 0x2b, 0x3b, 0xe2, 0x07, 0x45, 0xde, 0x01, -0xa6, 0x8f, 0x2b, 0xc3, 0x78, 0x90, 0xab, 0xdc, 0x68, 0xbb, 0x4d, 0x84, 0x0b, 0x2a, 0x67, 0xbb, -0xd4, 0xf7, 0x99, 0xa7, 0x8f, 0x4e, 0x78, 0x9f, 0xc0, 0x38, 0x32, 0x0c, 0x1c, 0xac, 0x72, 0x19, -0x09, 0x00, 0x99, 0xb5, 0xc2, 0x91, 0x70, 0x6b, 0x10, 0xd5, 0xcd, 0xaa, 0xf2, 0x49, 0x64, 0x17, -0xe7, 0x49, 0x1c, 0x82, 0xdf, 0x32, 0x3e, 0x33, 0x6e, 0x9b, 0xd2, 0x08, 0x57, 0x19, 0x4b, 0x61, -0x04, 0x93, 0x39, 0x34, 0x6a, 0x54, 0x0c, 0x8d, 0xd2, 0xb4, 0x06, 0x58, 0x2b, 0x00, 0xce, 0x6c, -0x7c, 0x15, 0x52, 0xb6, 0x7c, 0xc5, 0xc3, 0x6d, 0x29, 0xb7, 0xd1, 0x6c, 0x51, 0xf7, 0xb4, 0xb1, -0xc1, 0x1a, 0xc7, 0x4a, 0x88, 0xdd, 0x67, 0x65, 0x54, 0x10, 0xd6, 0xbe, 0xc6, 0xf1, 0x6c, 0x21, -0x03, 0x50, 0x27, 0xcf, 0x9e, 0xa9, 0x6b, 0x5c, 0x9e, 0x02, 0x4f, 0x10, 0x13, 0xd7, 0x87, 0x98, -0x83, 0x99, 0x4d, 0xda, 0xe0, 0x2b, 0xb8, 0xa3, 0x9c, 0x04, 0x4f, 0xfd, 0x43, 0x81, 0x57, 0xe8, -0x45, 0x8c, 0xde, 0xe5, 0x3f, 0x7e, 0x28, 0xa1, 0x3c, 0xc0, 0x23, 0x92, 0x5a, 0x20, 0x02, 0xd5, -0x77, 0x77, 0x4c, 0xba, 0x66, 0x73, 0x4a, 0x14, 0x70, 0xe4, 0x0b, 0x97, 0xf7, 0x65, 0x2d, 0x69, -0xa9, 0x30, 0x50, 0xed, 0xc4, 0x6d, 0xd1, 0xb0, 0xe5, 0xca, 0x33, 0x8f, 0xe1, 0xbf, 0xaf, 0xa7, -0xe7, 0x4e, 0x4d, 0xb7, 0xed, 0xd6, 0x5b, 0x11, 0x0b, 0x3d, 0x6a, 0xb3, 0x53, 0x97, 0x7b, 0x0e, -0x44, 0x66, 0xb5, 0x56, 0xab, 0x15, 0xcf, 0xb0, 0xd2, 0x1c, 0x56, 0xf8, 0x37, 0x55, 0x55, 0x2d, -0x8a, 0xba, 0xdc, 0xfc, 0xf6, 0xc3, 0xe4, 0x71, 0xd0, 0xef, 0x8b, 0x6c, 0x7c, 0x54, 0x47, 0x16, -0xae, 0xf8, 0x90, 0xfd, 0x11, 0xf8, 0xec, 0x23, 0x3c, 0x64, 0x12, 0xb6, 0x87, 0x9f, 0x60, 0x9b, -0xcf, 0xe9, 0xef, 0x70, 0x4b, 0xdb, 0x68, 0xe9, 0x8c, 0xc3, 0xbc, 0x9b, 0xaa, 0xb4, 0x55, 0x46, -0x81, 0x3f, 0x88, 0x8d, 0xde, 0x3a, 0x1b, 0xab, 0x20, 0xb7, 0xde, 0xd8, 0x08, 0xb6, 0xf3, 0x37, -0x1b, 0x43, 0x05, 0xdb, 0x5e, 0xb4, 0x39, 0xc2, 0xce, 0x7c, 0x07, 0x70, 0x55, 0xf1, 0x2d, 0x79, -0x9e, 0x83, 0xc2, 0x52, 0xcf, 0xea, 0xee, 0x05, 0xc6, 0x41, 0x5b, 0x76, 0xe0, 0x30, 0xf4, 0x11, -0x9d, 0x22, 0x6f, 0xb0, 0x62, 0xed, 0xbf, 0xe5, 0x09, 0x9c, 0x6c, 0x6e, 0x67, 0x2a, 0x39, 0x14, -0xb6, 0x9a, 0xe8, 0x11, 0x47, 0x08, 0x4b, 0xe8, 0x90, 0xfd, 0xcd, 0xe1, 0x53, 0x49, 0x03, 0x1a, -0x14, 0x26, 0x0d, 0xa9, 0x99, 0x29, 0xaa, 0x41, 0x49, 0x30, 0x6e, 0x02, 0x23, 0xab, 0x27, 0x39, -0x48, 0xfd, 0x3b, 0x4c, 0xcc, 0x7c, 0x27, 0x67, 0xda, 0xb5, 0x8f, 0x44, 0xd6, 0x77, 0xd4, 0x43, -0x75, 0x3c, 0x18, 0x1f, 0x0c, 0xa1, 0x7a, 0xa6, 0x7d, 0x19, 0x69, 0x3c, 0x39, 0xbe, 0xd5, 0xf1, -0xc3, 0xfc, 0x76, 0x8f, 0xba, 0x57, 0xaf, 0x16, 0x07, 0xc6, 0x67, 0xa3, 0x45, 0x9e, 0x12, 0xc8, -0x61, 0xde, 0x32, 0x37, 0x62, 0xc2, 0x65, 0x1c, 0xd3, 0xcc, 0x12, 0x2a, 0x93, 0x65, 0xd8, 0x54, -0x30, 0xd2, 0xd9, 0xd7, 0xb8, 0x30, 0x1e, 0xfb, 0x70, 0xde, 0xb4, 0x0e, 0x8a, 0x76, 0x34, 0x05, -0xd1, 0xcd, 0x40, 0xbc, 0xfb, 0x50, 0x06, 0x62, 0x6b, 0x0e, 0xe2, 0xb2, 0x0c, 0xc8, 0xf6, 0x1c, -0xc8, 0xd5, 0x0a, 0x10, 0x87, 0xf5, 0xe9, 0xc8, 0x93, 0x19, 0x98, 0x57, 0xaf, 0x5e, 0x15, 0xc0, -0xe4, 0x2e, 0x2f, 0x00, 0x42, 0x72, 0x97, 0x39, 0x90, 0x4b, 0xda, 0x19, 0x54, 0xea, 0x58, 0xbb, -0x54, 0xef, 0x7e, 0xcd, 0x92, 0x3e, 0xfd, 0x2e, 0x18, 0x3e, 0xc3, 0x9c, 0xef, 0x49, 0xd1, 0x7e, -0x86, 0x0a, 0x21, 0xd5, 0xeb, 0x7e, 0x19, 0x2b, 0xd0, 0x37, 0x0a, 0x33, 0x3d, 0x89, 0x2f, 0xff, -0xad, 0x8c, 0x1a, 0xc1, 0x62, 0xac, 0x0f, 0x48, 0x3e, 0x8c, 0x54, 0x6c, 0x14, 0xc5, 0x7f, 0x30, -0xf6, 0x2d, 0x8f, 0x86, 0x13, 0x7c, 0x9d, 0x26, 0x56, 0x33, 0xd2, 0x26, 0xaf, 0x47, 0xb0, 0xd7, -0x5b, 0x73, 0xa7, 0x91, 0xfd, 0xc9, 0x2d, 0xe8, 0x77, 0xcc, 0x7b, 0x0f, 0x9f, 0x6b, 0xd6, 0xe7, -0x87, 0xa8, 0xc2, 0x82, 0x1a, 0xb3, 0xfc, 0x4c, 0x82, 0x39, 0xd7, 0xb5, 0x7c, 0x56, 0x50, 0xf4, -0x8e, 0x46, 0x8e, 0x81, 0x22, 0x85, 0xcc, 0x55, 0xb4, 0xb4, 0xb1, 0xdc, 0xdd, 0x92, 0xc1, 0x5b, -0x7e, 0xcf, 0x9c, 0xda, 0x56, 0x21, 0x69, 0x61, 0x14, 0x38, 0xb7, 0xf6, 0x44, 0x8d, 0x69, 0xe7, -0x3d, 0x9b, 0x32, 0x1a, 0x55, 0x24, 0x0e, 0xe2, 0xb0, 0x9e, 0x3e, 0xb4, 0x46, 0x24, 0xe0, 0x0f, -0x6f, 0xfd, 0xd1, 0x10, 0xe8, 0x89, 0x51, 0x77, 0xf7, 0xea, 0x2b, 0x30, 0xbd, 0x0e, 0x02, 0xe9, -0x05, 0xd4, 0x01, 0x9f, 0x11, 0x33, 0x9a, 0x30, 0xd8, 0x83, 0x27, 0x79, 0x2c, 0xae, 0x5d, 0xf8, -0xca, 0x78, 0x2c, 0x55, 0xb5, 0x80, 0x4d, 0x75, 0xd9, 0x61, 0x6d, 0xc8, 0x5b, 0xcd, 0x92, 0xe7, -0x12, 0xa1, 0xdd, 0xb7, 0x37, 0x85, 0xab, 0x7f, 0x13, 0x3b, 0x18, 0x41, 0xac, 0xa5, 0x17, 0x4a, -0xde, 0xab, 0x63, 0xfb, 0xe2, 0x95, 0xf9, 0xfc, 0x6f, 0x12, 0xd7, 0xd7, 0x62, 0xa8, 0xe8, 0x3e, -0x29, 0xb8, 0xad, 0x86, 0xec, 0x53, 0xee, 0xcd, 0xc0, 0xf0, 0x6a, 0x35, 0x8c, 0x1f, 0x10, 0xea, -0x8b, 0x49, 0xaa, 0x4e, 0x31, 0xe0, 0xad, 0xbe, 0x59, 0x62, 0xce, 0x88, 0x0e, 0x30, 0x70, 0x4f, -0xe8, 0x85, 0xeb, 0x21, 0x2b, 0xc1, 0x28, 0x08, 0x27, 0x62, 0x32, 0x82, 0x69, 0xf0, 0xa5, 0xaa, -0x64, 0xf2, 0xd9, 0x9d, 0x4d, 0x28, 0x9c, 0xd2, 0x07, 0x75, 0x6a, 0xc1, 0x85, 0xe4, 0xb6, 0xf8, -0x36, 0xca, 0xb7, 0xd0, 0xb3, 0x63, 0xd0, 0xba, 0x20, 0xc4, 0x2c, 0xf0, 0xfa, 0xda, 0x0a, 0x6d, -0x54, 0x08, 0xeb, 0x07, 0xeb, 0x06, 0xf4, 0xc7, 0x9a, 0x50, 0xa9, 0x2e, 0xbf, 0x58, 0x37, 0x86, -0x54, 0x23, 0xa3, 0xae, 0xab, 0x32, 0x77, 0x73, 0x42, 0xbe, 0xbd, 0x4e, 0xfa, 0x90, 0x39, 0xb6, -0xdc, 0x25, 0xc3, 0xa9, 0xce, 0xea, 0x2d, 0xdd, 0x36, 0xf7, 0x1b, 0xbe, 0x0b, 0x69, 0x55, 0x0e, -0xd5, 0x9b, 0x2f, 0x53, 0x8c, 0x49, 0xd4, 0xce, 0xfd, 0x70, 0x84, 0x22, 0xf8, 0x13, 0xd7, 0x01, -0x46, 0x29, 0x71, 0xc2, 0x35, 0xbe, 0x68, 0x06, 0x97, 0xbe, 0xf6, 0x75, 0xba, 0x2e, 0x58, 0x7d, -0xbe, 0x9d, 0x64, 0x3e, 0x45, 0xbc, 0x60, 0x68, 0xc0, 0xf8, 0xe2, 0x5d, 0x03, 0x17, 0x04, 0x70, -0xe2, 0x6a, 0x18, 0x9d, 0x5b, 0xe3, 0xbb, 0x48, 0x79, 0x5e, 0x24, 0xd6, 0x3f, 0x19, 0x0b, 0xb5, -0x4e, 0x91, 0x60, 0xcc, 0x32, 0xfa, 0x1a, 0x31, 0xa1, 0x13, 0xa4, 0xf5, 0x85, 0xf0, 0x62, 0x49, -0xe8, 0xb1, 0x94, 0x6d, 0x97, 0xd9, 0x77, 0xbd, 0xe0, 0xde, 0xd2, 0x95, 0x27, 0xb8, 0x73, 0x07, -0x64, 0x58, 0x0f, 0x1b, 0x12, 0xcd, 0x54, 0x89, 0xa6, 0x22, 0xd9, 0xd8, 0xa5, 0x64, 0xa2, 0xb7, -0x37, 0x92, 0x52, 0x6d, 0x5a, 0xea, 0x9d, 0x5c, 0xb8, 0x71, 0x12, 0x86, 0x1e, 0x7a, 0xe5, 0x04, -0xbe, 0x27, 0xfd, 0xb5, 0x6a, 0xb6, 0xf8, 0x89, 0x84, 0xa9, 0x52, 0xf1, 0x9a, 0x2e, 0x16, 0xad, -0x28, 0xc3, 0xfa, 0x23, 0xcf, 0xab, 0x6f, 0xa2, 0x5e, 0x0d, 0x32, 0xda, 0xd9, 0x9c, 0x91, 0xc6, -0xfd, 0x7c, 0xd5, 0x75, 0x25, 0xd5, 0x94, 0x44, 0xfa, 0xab, 0x5b, 0x07, 0x56, 0xae, 0x4d, 0xa2, -0xb8, 0x8f, 0x5f, 0x9d, 0x74, 0x85, 0x4e, 0x65, 0xe4, 0xd5, 0x92, 0xd2, 0x79, 0x3a, 0xc1, 0x8a, -0xa6, 0xba, 0x74, 0xbd, 0x1a, 0x8f, 0xe7, 0x49, 0x1d, 0x9a, 0x40, 0x32, 0x38, 0xcf, 0x94, 0x7e, -0xe7, 0x6a, 0x83, 0x9c, 0xa9, 0xb6, 0x63, 0x40, 0xd8, 0xf9, 0xee, 0xac, 0xf9, 0xdf, 0x6e, 0xb9, -0x12, 0xa6, 0xba, 0x65, 0x99, 0xaa, 0x7e, 0x1e, 0x5b, 0xcd, 0xf4, 0xa4, 0xee, 0x80, 0xdc, 0x8c, -0xe9, 0x7d, 0x66, 0x02, 0x12, 0xc0, 0x35, 0xbc, 0xb4, 0xb2, 0xba, 0x04, 0x4d, 0xb6, 0xdb, 0x24, -0xf6, 0xc8, 0x90, 0x00, 0x82, 0xa2, 0xab, 0x39, 0x9a, 0xd6, 0x46, 0x02, 0xf2, 0xbc, 0x16, 0xe0, -0xa2, 0x18, 0xc9, 0x5d, 0xae, 0xbc, 0x9a, 0x82, 0xa2, 0x8c, 0x1f, 0xe5, 0x8e, 0xb1, 0x39, 0x65, -0xe8, 0x60, 0x86, 0xac, 0xbb, 0xea, 0xf3, 0xcf, 0xae, 0x9f, 0xe6, 0xd4, 0x88, 0xc5, 0xeb, 0xe9, -0x05, 0xd0, 0x53, 0xd3, 0x7b, 0x54, 0xfd, 0xba, 0x73, 0xd3, 0x52, 0xfb, 0x17, 0x73, 0xf2, 0x85, -0x82, 0xd3, 0xe8, 0xd3, 0x62, 0x3f, 0x67, 0x92, 0xe4, 0x69, 0x88, 0x89, 0x90, 0xc0, 0x0f, 0x4a, -0x18, 0x48, 0x29, 0xa2, 0x44, 0xc5, 0x14, 0x8a, 0x12, 0x65, 0x45, 0x78, 0xea, 0xa4, 0x43, 0x8b, -0x42, 0x82, 0x22, 0xe6, 0xa9, 0xb7, 0xfa, 0x73, 0xe6, 0x33, 0x9e, 0x00, 0x27, 0xb0, 0xb4, 0x27, -0x02, 0x6f, 0x24, 0x99, 0x65, 0x38, 0x8c, 0x1b, 0xab, 0x17, 0xe1, 0x8b, 0x68, 0xd6, 0x81, 0xd6, -0x8c, 0xe8, 0x5c, 0xa6, 0xb9, 0xb8, 0xa0, 0x17, 0xd8, 0x30, 0x61, 0x50, 0x38, 0x3d, 0x8d, 0x7a, -0x8d, 0x31, 0x3f, 0xec, 0xed, 0x7d, 0x8d, 0xeb, 0xe4, 0x1f, 0x7b, 0x5f, 0x99, 0x2d, 0x6b, 0x39, -0xda, 0x18, 0x9f, 0xca, 0x1c, 0x11, 0xee, 0xe4, 0x3f, 0xd4, 0x7a, 0x02, 0xbf, 0xf3, 0x1f, 0x6b, -0x1a, 0xe0, 0xf7, 0xf2, 0xe3, 0xf9, 0x63, 0x15, 0x1b, 0xdc, 0x10, 0xba, 0x35, 0xf8, 0x73, 0xda, -0xc3, 0x9e, 0xc3, 0x8f, 0x97, 0x57, 0x70, 0xfd, 0x8f, 0xcb, 0x8f, 0x17, 0x58, 0x0d, 0x85, 0xdc, -0x99, 0xf7, 0xa7, 0x2a, 0x88, 0xaf, 0xa2, 0xe5, 0xca, 0xb9, 0xa1, 0x63, 0x03, 0x02, 0x95, 0x17, -0x3d, 0xea, 0x18, 0x93, 0x80, 0xf2, 0xd2, 0xf8, 0xde, 0xe2, 0xd8, 0xda, 0x84, 0x3c, 0x34, 0xaa, -0xa2, 0x34, 0x88, 0xad, 0x50, 0xca, 0xd8, 0xc9, 0xa1, 0x56, 0x1a, 0x7b, 0x59, 0x92, 0x7c, 0xd8, -0xb0, 0xfb, 0x30, 0xdd, 0xb1, 0xfe, 0xee, 0xea, 0xc3, 0x7b, 0xa2, 0x8c, 0x2c, 0xee, 0x97, 0xc1, -0x6f, 0x67, 0x50, 0x1f, 0x96, 0x68, 0x42, 0x39, 0x7e, 0xf5, 0x68, 0xde, 0xd3, 0x51, 0xfb, 0xce, -0x0f, 0x26, 0x1e, 0x73, 0x06, 0x8c, 0xb4, 0x5a, 0x2d, 0x43, 0x63, 0x46, 0xfc, 0xd9, 0x08, 0xc0, -0x3b, 0xe1, 0xbe, 0x13, 0x4c, 0x5a, 0x82, 0xc9, 0x73, 0xec, 0x14, 0x18, 0xa3, 0x3f, 0x4d, 0xc4, -0xfb, 0xe3, 0xfc, 0x21, 0x1e, 0xf0, 0x04, 0xd8, 0x33, 0xa7, 0xfd, 0x58, 0xed, 0xf9, 0xb1, 0x11, -0x7f, 0x44, 0x46, 0x63, 0xac, 0xe3, 0x7e, 0x98, 0xdf, 0x4e, 0x53, 0xa1, 0x37, 0x66, 0x81, 0xf5, -0xb3, 0x28, 0x0a, 0xa2, 0xb4, 0x4e, 0x78, 0x6d, 0x31, 0xbc, 0xb6, 0x6e, 0xaa, 0xac, 0xe5, 0xd6, -0xf7, 0x5a, 0xcc, 0x32, 0xfc, 0xc4, 0x2b, 0x98, 0x6d, 0xf7, 0xf9, 0x4b, 0x44, 0x93, 0x5d, 0xb8, -0x82, 0x17, 0x2b, 0x9f, 0xaa, 0x73, 0x23, 0x58, 0xdb, 0x5c, 0x82, 0x74, 0xe3, 0xcd, 0xc1, 0xe6, -0x05, 0x6b, 0x7b, 0x8c, 0x46, 0xa9, 0x52, 0xc6, 0x1a, 0x5b, 0xcf, 0x5d, 0x00, 0x8c, 0xae, 0xd4, -0xf7, 0x4b, 0xaa, 0x91, 0xb8, 0x20, 0xcb, 0x3c, 0x1b, 0x72, 0x48, 0xdc, 0x1a, 0xae, 0x82, 0x3d, -0xf5, 0x6d, 0xb9, 0x48, 0x65, 0x17, 0x6a, 0x05, 0xad, 0x0a, 0x65, 0xbd, 0x02, 0x01, 0x2b, 0xf2, -0xf5, 0x1b, 0x7f, 0xc6, 0xb7, 0x0a, 0x17, 0x3e, 0xe4, 0x72, 0x6d, 0x0d, 0xf4, 0x85, 0x75, 0x63, -0x88, 0x3e, 0x55, 0x4f, 0x20, 0xb0, 0xa5, 0x3d, 0x74, 0x0b, 0xe2, 0x33, 0x3e, 0xf0, 0x6b, 0x7f, -0xea, 0x57, 0xbf, 0xae, 0xad, 0xbe, 0xe7, 0xdc, 0xaa, 0x21, 0x46, 0x04, 0xd8, 0x13, 0x30, 0x83, -0xd7, 0x1f, 0x8d, 0xaa, 0x19, 0xb0, 0x41, 0x14, 0x78, 0x63, 0x3a, 0x1d, 0x37, 0x7f, 0x04, 0x27, -0xdb, 0x8d, 0xb3, 0xfc, 0x21, 0x9c, 0xd4, 0x57, 0xe1, 0xe1, 0x7b, 0xfe, 0x17, 0x70, 0xf2, 0x7a, -0x23, 0x3a, 0xb3, 0xbe, 0x1c, 0x3e, 0x2e, 0xd3, 0x14, 0x91, 0x31, 0x62, 0x3e, 0x5e, 0xd1, 0x04, -0xb1, 0xa1, 0x16, 0x87, 0x15, 0x6d, 0x0e, 0xf9, 0xde, 0xd2, 0x7c, 0x37, 0x69, 0x0d, 0xd4, 0x1f, -0xfd, 0xc2, 0x8f, 0x3a, 0x98, 0x53, 0x8d, 0xec, 0xc0, 0x23, 0xb2, 0x5b, 0xb1, 0xa1, 0x21, 0xf9, -0xae, 0x58, 0x7d, 0xce, 0x72, 0x32, 0x38, 0x8d, 0x3d, 0x47, 0x8b, 0x9f, 0x18, 0x2a, 0x10, 0xf2, -0xea, 0x2d, 0x09, 0xfb, 0x2a, 0x7e, 0x8c, 0x05, 0x5d, 0x4f, 0x6b, 0xae, 0x9a, 0xa9, 0xc2, 0x76, -0x4e, 0x65, 0xf5, 0xe9, 0x17, 0x9d, 0x0a, 0x7a, 0x59, 0x1e, 0x1e, 0xb3, 0x7d, 0x55, 0x14, 0x5f, -0xfc, 0x06, 0x72, 0x81, 0x27, 0x99, 0x57, 0x39, 0xd5, 0x55, 0x92, 0x70, 0x7f, 0x90, 0xf9, 0xf2, -0x55, 0xf2, 0xb1, 0x4e, 0x7d, 0xa5, 0xbf, 0x73, 0x79, 0xd8, 0xd6, 0x5f, 0x34, 0xfd, 0x2f, 0xe6, -0xde, 0x0e, 0x11, 0xe9, 0x54, 0x00, 0x00}; -#endif /*__VISUALIZATION_HTML_H__*/ diff --git a/src/web/html/tmp/about.html b/src/web/html/tmp/about.html deleted file mode 100644 index 820fd356..00000000 --- a/src/web/html/tmp/about.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - About - - - - - - - - - -
-
-

About AhoyDTU

-
-
-
Used Libraries
-
- - - - - - - - -
-
Contact Information
-
-
-
Github Repository
- -
-
-
Discord Chat
- -
-
-
E-Mail
- -
-
-
-
- - - - diff --git a/src/web/html/tmp/index.html b/src/web/html/tmp/index.html deleted file mode 100644 index a2da0653..00000000 --- a/src/web/html/tmp/index.html +++ /dev/null @@ -1,263 +0,0 @@ - - - - Index - - - - - - - - - -
-
-

- Uptime:
- ESP-Time: -

-

- System Infos: -

-
-
-

- -
-

Support this project:

- -

- This project was started from this discussion. (Mikrocontroller.net) -

-
-
-
- - - - diff --git a/src/web/html/tmp/login.html b/src/web/html/tmp/login.html deleted file mode 100644 index 81c4051d..00000000 --- a/src/web/html/tmp/login.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - Login - - - - - - - - -
-
-
-
-

AhoyDTU

-
-
-
-
-
-
-
-
- - - diff --git a/src/web/html/tmp/save.html b/src/web/html/tmp/save.html deleted file mode 100644 index 1b85d690..00000000 --- a/src/web/html/tmp/save.html +++ /dev/null @@ -1,102 +0,0 @@ - - - - Save - - - - - - - - - -
-
-
Saving settings...
-
-
- - - - diff --git a/src/web/html/tmp/serial.html b/src/web/html/tmp/serial.html deleted file mode 100644 index 28d56965..00000000 --- a/src/web/html/tmp/serial.html +++ /dev/null @@ -1,132 +0,0 @@ - - - - Serial Console - - - - - - - - - -
-
-
- -
-
-
console active:
-
Uptime:
-
- - -
-
-
-
- - - - diff --git a/src/web/html/tmp/setup.html b/src/web/html/tmp/setup.html deleted file mode 100644 index bebdaab9..00000000 --- a/src/web/html/tmp/setup.html +++ /dev/null @@ -1,1000 +0,0 @@ - - - - Setup - - - - - - - - - -
-
-
-
- -
-
- Device Host Name -
-
Device Name
-
-
-
-
Reboot Ahoy at midnight
-
-
-
-
Dark Mode
-
-
(empty browser cache or use CTRL + F5 after reboot to apply this setting)
-
-
-
- System Config -

Status LEDs

-
- -

Radio (NRF24L01+)

-
- -

Radio (CMT2300A)

-
(ESP32 only)
- -

Serial Console

-
-
print inverter data
-
-
-
-
Serial Debug
-
-
-
-
Interval [s]
-
-
-
-
- - -
-
- WiFi - -
-
AP Password (min. length: 8)
-
-
- -

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

- -
-
Search Networks
-
-
- -
-
Avail Networks
-
- -
-
-
-
SSID
-
-
-
-
SSID is hidden
-
-
-
-
Password
-
-
-
-
- Static IP (optional) -

- Leave fields blank for DHCP
- The following fields are parsed in this format: 192.168.4.1 -

-
-
IP Address
-
-
-
-
Submask
-
-
-
-
DNS 1
-
-
-
-
DNS 2
-
-
-
-
Gateway
-
-
-
-
- - -
-
- Protection -
-
Admin Password
-
-
-

Select pages which should be protected by password

-
-
-
- - -
-
- Inverter -
-
-
-
-
-
-

Note

-

A 'max module power' value of '0' disables the channel in 'live' view

-
-
-

General

-
-
-
-
Interval [s]
-
-
-
-
Max retries per Payload
-
-
-
-
Reset values and YieldDay at midnight
-
-
-
-
Reset values when inverter polling pauses at sunset
-
-
-
-
Reset values when inverter status is 'not available'
-
-
-
-
Reset 'max' values at midnight
-
-
-
-
Start without time sync (useful in AP-Only-Mode)
-
-
-
-
Yield Efficiency (should be between 0.95 and 0.96)
-
-
-
-
- - -
-
- NTP Server -
-
NTP Server / IP
-
-
-
-
NTP Port
-
-
-
-
NTP Interval (in Minutes, min. 5 Minutes)
-
-
-
-
set System time
-
- -
- -
-
-
-
System Time
-
-
-
-
- - -
-
- Sunrise & Sunset -
-
Latitude (decimal)
-
-
-
-
Longitude (decimal)
-
-
-
-
Offset (pre sunrise, post sunset)
-
-
-
-
Pause polling inverters during night
-
-
-
-
- - -
-
- MQTT -
-
Broker / Server IP
-
-
-
-
Port
-
-
-
-
Client Id (optional)
-
-
-
-
Username (optional)
-
-
-
-
Password (optional)
-
-
-
-
Topic
-
-
-

Send Inverter data in a fixed interval, even if there is no change. A value of '0' disables the fixed interval. The data is published once it was successfully received from inverter. (default: 0)

-
-
Interval [s]
-
-
-
-
Discovery Config (homeassistant)
-
- - -
-
-
-
- - -
-
- Display Config -
-
-
-
Turn off while inverters are offline
-
-
-
-
Enable Screensaver (pixel shifting, OLED only)
-
-
-
-
Luminance
-
-
-

Pinout

-
-
-
- -
-
Reboot device after successful save
-
- - -
-
- -
-
- ERASE SETTINGS (not WiFi) -
- Import / Export JSON Settings -
-
Import
-
-
-
-
-
-
-
-
-
-
-
Export
-
- Export settings (JSON file) (only values, passwords will be removed!) -
-
-
-
-
-
- - - - diff --git a/src/web/html/tmp/style.css b/src/web/html/tmp/style.css deleted file mode 100644 index 95cbff3b..00000000 --- a/src/web/html/tmp/style.css +++ /dev/null @@ -1,781 +0,0 @@ -html, body { - font-family: Arial; - margin: 0; - padding: 0; - height: 100%; - min-height: 100%; - background-color: var(--bg); - color: var(--fg); -} - -h2 { - padding-left: 10px; -} - -span, li, h3, label, fieldset { - color: var(--fg); -} - -fieldset, input[type=submit], .btn { - border-radius: 4px; -} - -input[type=file] { - width: 100%; -} - -textarea { - color: var(--fg); - background-color: var(--bg); -} - -#live span { - color: var(--fg2); -} - -.topnav { - background-color: var(--nav-bg); - position: fixed; - top: 0; - width: 100%; -} - -.topnav a { - color: var(--fg2); - padding: 14px 14px; - text-decoration: none; - font-size: 17px; - display: block; -} - -#topnav a { - color: #fff; -} - -.topnav a.icon { - top: 0; - left: 0; - background: var(--nav-bg); - display: block; - position: absolute; -} - -.topnav a:hover { - background-color: var(--primary-hover) !important; -} - -.topnav .info { - color: var(--fg2); - position: absolute; - right: 24px; - top: 5px; -} - -.topnav .mobile { - display: none; -} - -svg.icon { - vertical-align: middle; - display: inline-block; - margin-top:-4x; - padding: 5px 7px 5px 0px; -} - -.icon-info { - fill: var(--info); -} - -.icon-warn { - fill: var(--warn); -} - -.icon-success { - fill: var(--success); -} - -.wifi { - fill: var(--fg2); -} - -.title { - background-color: var(--primary); - color: #fff !important; - padding: 15px 14px 16px 80px !important -} - -.topnav .icon span { - display: block; - width: 30px; - height: 3px; - margin-bottom: 5px; - position: relative; - background: #fff; - border-radius: 2px; -} - -.topnav .active { - background-color: var(--nav-active); -} - -span.seperator { - width: 100%; - height: 1px; - margin: 5px 0px 5px; - background-color: #494949; - display: block; -} - -#content { - max-width: 1140px; -} - -.total-h { - background-color: var(--total-head-title); - color: var(--fg2); -} - -.total-bg { - background-color: var(--total-bg); - color: var(--fg2); -} - -.iv-h { - background-color: var(--iv-head-title); - color: var(--fg2); -} - -.iv-bg { - background-color: var(--iv-head-bg); - color: var(--fg2); -} - -.iv-h-dis { - background-color: var(--iv-dis-title); - color: var(--fg2); -} - -.iv-bg-dis { - background-color: var(--iv-dis); - color: var(--fg2); -} - -.ch-h { - background-color: var(--ch-head-title); - color: var(--fg2); -} - -.ch-bg { - background-color: var(--ch-head-bg); - color: var(--fg2); -} - -.ts-h { - background-color: var(--ts-head); - color: var(--fg2); -} - -.ts-bg { - background-color: var(--ts-bg); - color: var(--fg2); -} - -.hr { - border-top: 1px solid var(--iv-head-title); - margin: 1rem 0 1rem; -} - -p { - text-align: justify; - font-size: 13pt; - color: var(--fg); -} - -#footer { - background-color: var(--footer-bg); -} - -.row { display: flex; max-width: 100%; flex-wrap: wrap; } -.col { flex: 1 0 0%; } - -.col-1, .col-2, .col-3, .col-4, -.col-5, .col-6, .col-7, .col-8, -.col-9, .col-10, .col-11, .col-12 { flex: 0 0 auto; } - -.col-1 { width: 8.333333333%; } -.col-2 { width: 16.66666667%; } -.col-3 { width: 25%; } -.col-4 { width: 33.33333333%; } -.col-5 { width: 41.66666667%; } -.col-6 { width: 50%; } -.col-7 { width: 58.33333333%; } -.col-8 { width: 66.66666667%; } -.col-9 { width: 75%; } -.col-10 { width: 83.33333333%; } -.col-11 { width: 91.66666667%; } -.col-12 { width: 100%; } - -.p-1 { padding: 0.25rem; } -.p-2 { padding: 0.5rem; } -.p-3 { padding: 1rem; } -.p-4 { padding: 1.5rem; } -.p-5 { padding: 3rem; } - -.px-1 { padding: 0 0.25rem 0 0.25rem; } -.px-2 { padding: 0 0.5rem 0 0.5rem; } -.px-3 { padding: 0 1rem 0 1rem; } -.px-4 { padding: 0 1.5rem 0 1.5rem; } -.px-5 { padding: 0 3rem 0 3rem; } - -.py-1 { padding: 0.25rem 0 0.25rem; } -.py-2 { padding: 0.5rem 0 0.5rem; } -.py-3 { padding: 1rem 0 1rem; } -.py-4 { padding: 1.5rem 0 1.5rem; } -.py-5 { padding: 3rem 0 3rem; } - -.mx-1 { margin: 0 0.25rem 0 0.25rem; } -.mx-2 { margin: 0 0.5rem 0 0.5rem; } -.mx-3 { margin: 0 1rem 0 1rem; } -.mx-4 { margin: 0 1.5rem 0 1.5rem; } -.mx-5 { margin: 0 3rem 0 3rem; } - -.my-1 { margin: 0.25rem 0 0.25rem; } -.my-2 { margin: 0.5rem 0 0.5rem; } -.my-3 { margin: 1rem 0 1rem; } -.my-4 { margin: 1.5rem 0 1.5rem; } -.my-5 { margin: 3rem 0 3rem; } - -.mt-1 { margin-top: 0.25rem } -.mt-2 { margin-top: 0.5rem } -.mt-3 { margin-top: 1rem } -.mt-4 { margin-top: 1.5rem } -.mt-5 { margin-top: 3rem } - -.mb-1 { margin-bottom: 0.25rem } -.mb-2 { margin-bottom: 0.5rem } -.mb-3 { margin-bottom: 1rem } -.mb-4 { margin-bottom: 1.5rem } -.mb-5 { margin-bottom: 3rem } - -.fs-1 { font-size: 3.5rem; } -.fs-2 { font-size: 3rem; } -.fs-3 { font-size: 2.5rem; } -.fs-4 { font-size: 2rem; } -.fs-5 { font-size: 1.75rem; } -.fs-6 { font-size: 1.5rem; } -.fs-7 { font-size: 1.25rem; } -.fs-8 { font-size: 1rem; } -.fs-9 { font-size: 0.75rem; } -.fs-10 { font-size: 0.5rem; } - -.a-r { text-align: right; } -.a-c { text-align: center; } - -.d-none { display: none !important; } -.d-block { display: block !important; } - -.row > * { - padding-left: 0.5rem; - padding-right: 0.5rem; -} - -*, ::after, ::before { - box-sizing: border-box; -} - -/* sm */ -@media(min-width: 768px) { - .col-sm-1 { width: 8.333333333%; } - .col-sm-2 { width: 16.66666667%; } - .col-sm-3 { width: 25%; } - .col-sm-4 { width: 33.33333333%; } - .col-sm-5 { width: 41.66666667%; } - .col-sm-6 { width: 50%; } - .col-sm-7 { width: 58.33333333%; } - .col-sm-8 { width: 66.66666667%; } - .col-sm-9 { width: 75%; } - .col-sm-10 { width: 83.33333333%; } - .col-sm-11 { width: 91.66666667%; } - .col-sm-12 { width: 100%; } - - .mb-sm-1 { margin-bottom: 0.25rem } - .mb-sm-2 { margin-bottom: 0.5rem } - .mb-sm-3 { margin-bottom: 1rem } - .mb-sm-4 { margin-bottom: 1.5rem } - .mb-sm-5 { margin-bottom: 3rem } - - .fs-sm-1 { font-size: 3.5rem; } - .fs-sm-2 { font-size: 3rem; } - .fs-sm-3 { font-size: 2.5rem; } - .fs-sm-4 { font-size: 2rem; } - .fs-sm-5 { font-size: 1.75rem; } - .fs-sm-6 { font-size: 1.5rem; } - .fs-sm-7 { font-size: 1.25rem; } - .fs-sm-8 { font-size: 1rem; } - - .d-sm-block { display: block !important;} - .d-sm-none { display: none !important; } -} - -/* md */ -@media(min-width: 992px) { - .col-md-1 { width: 8.333333333%; } - .col-md-2 { width: 16.66666667%; } - .col-md-3 { width: 25%; } - .col-md-4 { width: 33.33333333%; } - .col-md-5 { width: 41.66666667%; } - .col-md-6 { width: 50%; } - .col-md-7 { width: 58.33333333%; } - .col-md-8 { width: 66.66666667%; } - .col-md-9 { width: 75%; } - .col-md-10 { width: 83.33333333%; } - .col-md-11 { width: 91.66666667%; } - .col-md-12 { width: 100%; } -} - -table { - border-collapse: collapse; - width: 100%; -} - -th { - text-align: inherit; -} - -.table td, .table th { - padding: .75rem; - border-bottom: 1px solid var(--table-border); -} - -#wrapper { - min-height: 100%; -} - -#content { - padding: 50px 20px 120px 20px; - overflow: auto; -} - -#footer { - height: 121px; - margin-top: -121px; - width: 100%; - font-size: 13px; -} - -#footer .right { - color: #bbb; - margin: 6px 25px; - text-align: right; -} - -#footer .left { - color: #bbb; - margin: 23px 0px 0px 25px; -} - -#footer ul { - list-style-type: none; - margin: 20px auto; - padding: 0; -} - -#footer ul li, #footer a { - color: #bbb; - margin-bottom: 10px; - padding-left: 5px; - font-size: 13px; -} - -#footer a:hover { - color: #fff; -} - -.hide { - display: none !important; -} - -@media only screen and (min-width: 992px) { - .topnav { - width: 230px !important; - height: 100%; - } - - .topnav a.icon { - display: none !important; - } - - .topnav a { - padding: 14px 24px; - } - - .topnav .title { - padding-left: 24px !important; - } - - .topnav .mobile { - display: block; - } - - .topnav .info { - top: auto !important; - right: auto !important; - bottom: 14px; - left: 24px; - } - - #content { - padding: 15px 15px 120px 250px; - } - - #footer .left { - margin-left: 250px !important; - } -} - -p.lic, p.lic a { - font-size: 8pt; - color: #999; -} - -.des { - margin-top: 20px; - font-size: 13pt; - color: var(--secondary); -} - -.s_active, .s_collapsible:hover { - background-color: var(--primary-hover); - color: #fff; -} - -.s_content { - display: none; - overflow: hidden; -} - -.s_collapsible { - background-color: var(--primary); - color: white; - cursor: pointer; - padding: 12px; - width: 100%; - border: none; - text-align: left; - outline: none; - font-size: 15px; - margin-bottom: 5px; -} - -.subdes { - font-size: 12pt; - color: var(--secondary); - margin-left: 7px; -} - -.subsubdes { - font-size:12pt; - color:var(--secondary); - margin: 0 0 7px 12px; -} - -a:link, a:visited { - text-decoration: none; - font-size: 13pt; - color: var(--secondary); -} - -a:hover, a:focus { - color: #f00; -} - -a.btn { - background-color: var(--primary); - color: #fff; - padding: 7px 15px 7px 15px; - display: inline-block; -} - -a.btn:hover { - background-color: var(--primary-hover) !important; -} - -input, select { - padding: 7px; - font-size: 13pt; -} - -input[type=text], input[type=password], select, input[type=number] { - width: 100%; - box-sizing: border-box; - border: 1px solid #ccc; - border-radius: 4px; - background-color: var(--input-bg); - color: var(--fg); -} - -input:invalid { - border: 2px solid #f00 !important; - background-color: var(--invalid-bg) !important; -} - -input.sh { - max-width: 150px !important; - margin-right: 10px; -} - -input.btnDel { - background-color: #c00 !important; -} - -input.btn { - background-color: var(--primary); - color: #fff; - border: 0px; - padding: 7px 20px 7px 20px; - margin-bottom: 10px; - text-transform: uppercase; - cursor: pointer; -} - -input.btn:hover { - background-color: #044e86; -} - -input.cb { - margin-bottom: 15px; - margin-top: 10px; -} - -label { - width: 20%; - display: inline-block; - font-size: 12pt; - padding-right: 10px; - margin: 10px 0px 0px 15px; - vertical-align: top; -} - -pre { - white-space: pre-wrap; -} - -.left { - float: left; -} - -.right { - float: right; -} - -.subgrp { - float: left; - width: 220px; -} - -div.ModPwr, div.ModName, div.YieldCor { - width:70%; - display: inline-block; -} - -div.hr { - height: 1px; - border-top: 1px solid #ccc; - margin: 10px 0px 10px; -} - -#note { - margin: 10px 10px 10px 10px; - padding-top: 10px; - width: 100%; -} - -#login { - width: 450px; - height: 200px; - border: 1px solid #ccc; - background-color: var(--input-bg); - position: absolute; - top: 50%; - left: 50%; - margin-top: -160px; - margin-left: -225px; -} - -@media(max-width: 500px) { - div.ch .unit, div.ch-iv .unit { - font-size: 18px; - } - - div.ch { - width: 170px; - min-height: 100px - } - - .subgrp { - width: 180px; - } - - #login { - margin-left: -150px; - width: 300px; - } -} - -#serial { - width: 100%; -} - -#content .serial { - max-width: 1000px; -} - -.dot { - height: 15px; - width: 15px; - background-color: #f00; - border-radius: 50%; - display: inline-block; - margin-top: 15px; -} - - -.head { - background-color: var(--primary); - color: #fff; -} - - -.css-tooltip{ - position: relative; -} -.css-tooltip:hover:after{ - content:attr(data-tooltip); - background:#000; - padding:5px; - border-radius:3px; - display: inline-block; - position: absolute; - transform: translate(-50%,-100%); - margin:0 auto; - color:#FFF; - min-width:100px; - min-width:150px; - top:-5px; - left: 50%; - text-align:center; -} -.css-tooltip:hover:before { - top:-5px; - left: 50%; - border: solid transparent; - content: " "; - height: 0; - width: 0; - position: absolute; - pointer-events: none; - border-color: rgba(0, 0, 0, 0); - border-top-color: #000; - border-width: 5px; - margin-left: -5px; - transform: translate(0,0px); -} - -#modal { - max-width: 700px; - margin: 1.75rem auto; -} - -.modal { - position: fixed; - top: 0; - right: 0; - left: 0; - z-index: 1072; - display: block; -} - -#modal-wrapper { - background-color: #000; - opacity: 0.5; - bottom: 0; -} - -.modal-content { - border-radius: .3rem; - position: relative; - display: flex; - width: 100%; - background-color: var(--modal-bg); - background-clip: padding-box; - border: 1px solid rgba(0,0,0,.2); - flex-direction: column; -} - -.modal-header { - display: flex; - align-items: flex-start; - justify-content: space-between; - padding: 1rem; - border-bottom: 1px solid #e9ecef; -} - -.modal-header .close { - padding: 0.7rem; - margin: -1rem -1rem -1rem auto; -} - -.modal-body { - padding: 1rem 1rem 2rem 1rem; -} - -.close { - font-size: 2rem; - opacity: 0.5; - font-family: inherit; - cursor: pointer; - padding: 0; -} - -button.close { - background-color: transparent; - border: 0; -} - -h5 { - font-size: 1.25rem; - margin-top: 0; - margin-bottom: 0.5rem; - font-weight: 500; -} - -.pointer { - cursor: pointer; -} - -.badge-success { - color: #fff; - background-color: #28a745; -} - -.badge-warning { - color: #212529; - background-color: #ffc107; -} - -.badge-error { - color: #fff; - background-color: #dc3545; -} - -.badge { - display: inline-block; - padding: .25em .4em; - font-size: 85%; - font-weight: 700; - line-height: 1; - text-align: center; - white-space: nowrap; - vertical-align: baseline; - border-radius: .25rem; -} diff --git a/src/web/html/tmp/system.html b/src/web/html/tmp/system.html deleted file mode 100644 index b7221966..00000000 --- a/src/web/html/tmp/system.html +++ /dev/null @@ -1,188 +0,0 @@ - - - - System - - - - - - - - - -
-
-
-
-
-
- - - - diff --git a/src/web/html/tmp/update.html b/src/web/html/tmp/update.html deleted file mode 100644 index 883afac5..00000000 --- a/src/web/html/tmp/update.html +++ /dev/null @@ -1,80 +0,0 @@ - - - - Update - - - - - - - - - -
-
-
- Select firmware file (*.bin) -
- - -
-
-
-
- - - - diff --git a/src/web/html/tmp/visualization.html b/src/web/html/tmp/visualization.html deleted file mode 100644 index 545a1555..00000000 --- a/src/web/html/tmp/visualization.html +++ /dev/null @@ -1,479 +0,0 @@ - - - - Live - - - - - - - - - - -
-
-
-

Every seconds the values are updated

-
-
- - - - From 92855a7f0ccc2d5b4742e7e5d787b06357e8f455 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 29 Oct 2023 17:17:05 +0100 Subject: [PATCH 150/267] started to add heuristics as an extra class (for now global not inverter independent) --- src/app.cpp | 4 +- src/hm/Heuristic.h | 147 +++++++++++++++++++++++++++++++++++++++++++++ src/hm/hmRadio.h | 27 +++++++-- 3 files changed, 170 insertions(+), 8 deletions(-) create mode 100644 src/hm/Heuristic.h diff --git a/src/app.cpp b/src/app.cpp index 9cbe06a1..5570af54 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -205,8 +205,8 @@ void app::onNetwork(bool gotIp) { every(std::bind(&app::tickSend, this), mConfig->nrf.sendInterval, "tSend"); mMqttReconnect = true; mSunrise = 0; // needs to be set to 0, to reinstall sunrise and ivComm tickers! - //once(std::bind(&app::tickNtpUpdate, this), 2, "ntp2"); - tickNtpUpdate(); + once(std::bind(&app::tickNtpUpdate, this), 2, "ntp2"); + //tickNtpUpdate(); #if !defined(ETHERNET) if (WIFI_AP == WiFi.getMode()) { mMqttEnabled = false; diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h new file mode 100644 index 00000000..3080e8df --- /dev/null +++ b/src/hm/Heuristic.h @@ -0,0 +1,147 @@ +//----------------------------------------------------------------------------- +// 2023 Ahoy, https://github.com/lumpapu/ahoy +// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed +//----------------------------------------------------------------------------- + +#ifndef __HEURISTIC_H__ +#define __HEURISTIC_H__ + +#include "../utils/dbg.h" + +#define RF_MAX_CHANNEL_ID 5 +#define RF_MAX_QUALITY 4 +#define RF_MIN_QUALTIY -6 + +class Heuristic { + public: + void setup() { + uint8_t j; + for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) { + mTxQuality[i] = -6; // worst + for(j = 0; j < 10; j++) { + mRxCh[i][j] = 3; + } + } + } + + /*uint8_t getRxCh(void) { + + }*/ + + uint8_t getTxCh(void) { + if(++mCycleCnt > RF_MAX_CHANNEL_ID) { + bool ok = false; + for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) { + if(mTxQuality[i] > -4) { + ok = true; + mState = States::RUNNING; + } + } + if(!ok) { // restart + mCycleCnt = 0; + mState = States::TRAINING; + } + } + + if(States::TRAINING == mState) { + mTxChId = (mTxChId + 1) % RF_MAX_CHANNEL_ID; + return id2Ch(mTxChId); + } else { + int8_t bestQuality = -6; + uint8_t id = 0; + for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) { + if((mCycleCnt % 50) == 0) { + if(mTxQuality[(i + mTxChId) % RF_MAX_CHANNEL_ID] != -6) { + id = i; + break; + } + + } + if(mTxQuality[(i + mTxChId) % RF_MAX_CHANNEL_ID] == 4) { + id = i; + break; + } + if(mTxQuality[i] > bestQuality) { + bestQuality = mTxQuality[i]; + id = i; + } + } + mTxChId = id; + return id2Ch(mTxChId); + } + } + + void setGotAll(void) { + updateQuality(2); // GOOD + } + + void setGotFragment(void) { + updateQuality(1); // OK + } + + void setGotNothing(void) { + updateQuality(-2); // BAD + } + + void printStatus(void) { + DPRINT(DBG_INFO, F("Status: #")); + DBGPRINT(String(mCycleCnt)); + DBGPRINT(F(" |")); + for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) { + DBGPRINT(F(" ")); + DBGPRINT(String(mTxQuality[i])); + } + DBGPRINTLN(""); + } + + private: + void updateQuality(uint8_t quality) { + mTxQuality[mTxChId] += quality; + if(mTxQuality[mTxChId] > RF_MAX_QUALITY) + mTxQuality[mTxChId] = RF_MAX_QUALITY; + else if(mTxQuality[mTxChId] < RF_MIN_QUALTIY) + mTxQuality[mTxChId] = RF_MIN_QUALTIY; + } + + uint8_t ch2Id(uint8_t ch) { + switch(ch) { + case 3: return 0; + case 23: return 1; + case 40: return 2; + case 61: return 3; + case 75: return 4; + } + return 0; // standard + } + + uint8_t id2Ch(uint8_t id) { + switch(id) { + case 0: return 3; + case 1: return 23; + case 2: return 40; + case 3: return 61; + case 4: return 75; + } + return 0; // standard + } + + private: + enum class States : uint8_t { + TRAINING, RUNNING + }; + + private: + uint8_t mChList[5] = {03, 23, 40, 61, 75}; + + int8_t mTxQuality[RF_MAX_CHANNEL_ID]; + uint8_t mTxChId = 0; + + uint8_t mRxCh[RF_MAX_CHANNEL_ID][10]; + uint8_t mRxChId = 0; + + uint32_t mCycleCnt = 0; + States mState = States::TRAINING; +}; + + +#endif /*__HEURISTIC_H__*/ diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 3d74222d..fc4f2069 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -9,6 +9,7 @@ #include #include "SPI.h" #include "radio.h" +#include "heuristic.h" #define SPI_SPEED 1000000 @@ -76,6 +77,9 @@ class HmRadio : public Radio { mSpi = new SPIClass(); mSpi->begin(); #endif + + mHeu.setup(); + mNrf24.begin(mSpi, ce, cs); mNrf24.setRetries(3, 15); // 3*250us + 250us and 15 loops -> 15ms @@ -114,6 +118,8 @@ class HmRadio : public Radio { mNrf24.flush_tx(); // empty TX FIFO // start listening + //mNrf24.setChannel(23); + //mRxChIdx = 0; mNrf24.setChannel(mRfChLst[mRxChIdx]); mNrf24.startListening(); @@ -124,8 +130,11 @@ class HmRadio : public Radio { if (mIrqRcvd) { mIrqRcvd = false; - if (getReceived()) // everything received + if (getReceived()) { // everything received + mHeu.setGotAll(); return; + } else + mHeu.setGotFragment(); } yield(); @@ -134,9 +143,15 @@ class HmRadio : public Radio { if(++mRxChIdx >= RF_CHANNELS) mRxChIdx = 0; mNrf24.setChannel(mRfChLst[mRxChIdx]); - startMicros = micros() + 5000; + startMicros = micros() + 5110; } // not finished but time is over + if(++mRxChIdx >= RF_CHANNELS) + mRxChIdx = 0; + if(mBufCtrl.empty()) + mHeu.setGotNothing(); + + mHeu.printStatus(); return; } @@ -275,21 +290,20 @@ class HmRadio : public Radio { updateCrcs(&len, appendCrc16); // set TX and RX channels - mTxChIdx = (mTxChIdx + 1) % RF_CHANNELS; - mRxChIdx = (mTxChIdx + 2) % RF_CHANNELS; + mTxChIdx = mHeu.getTxCh(); if(mSerialDebug) { DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("TX ")); DBGPRINT(String(len)); DBGPRINT(" CH"); - DBGPRINT(String(mRfChLst[mTxChIdx])); + DBGPRINT(String(mTxChIdx)); DBGPRINT(F(" | ")); ah::dumpBuf(mTxBuf, len); } mNrf24.stopListening(); - mNrf24.setChannel(mRfChLst[mTxChIdx]); + mNrf24.setChannel(mTxChIdx); mNrf24.openWritingPipe(reinterpret_cast(&iv->radioId.u64)); mNrf24.startWrite(mTxBuf, len, false); // false = request ACK response mMillis = millis(); @@ -311,6 +325,7 @@ class HmRadio : public Radio { SPIClass* mSpi; RF24 mNrf24; + Heuristic mHeu; }; #endif /*__HM_RADIO_H__*/ From f1dfd328cce569a25069db4b74f79c22f41356ef Mon Sep 17 00:00:00 2001 From: lumapu Date: Wed, 1 Nov 2023 00:11:38 +0100 Subject: [PATCH 151/267] 0.8.1 * added tx channel heuristics (per inverter) * fix statistics counter --- src/CHANGES.md | 7 + src/app.cpp | 122 +----- src/app.h | 13 - src/appInterface.h | 2 - src/defines.h | 4 +- src/hm/CommQueue.h | 20 - src/hm/Communication.h | 49 +-- src/hm/Heuristic.h | 117 ++---- src/hm/hmInverter.h | 98 +---- src/hm/hmPayload.h | 494 ------------------------ src/hm/hmRadio.h | 40 +- src/hm/miPayload.h | 844 ----------------------------------------- src/web/RestApi.h | 11 +- 13 files changed, 97 insertions(+), 1724 deletions(-) delete mode 100644 src/hm/hmPayload.h delete mode 100644 src/hm/miPayload.h diff --git a/src/CHANGES.md b/src/CHANGES.md index 2afb1ece..435379e9 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,12 @@ # Development Changes +## 0.8.1 - 2023-10-31 +* added tx channel heuristics (per inverter) +* fix statistics counter + +## 0.8.0 - 2023-10-?? +* switched to new communication scheme + ## 0.7.66 - 2023-10-04 * prepared PA-Level for CMT * removed settings for number of retransmits, its fixed to `5` now diff --git a/src/app.cpp b/src/app.cpp index 5570af54..afe17132 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -74,15 +74,6 @@ void app::setup() { }); } - /*mPayload.setup(this, &mSys, &mTimestamp); - mPayload.enableSerialDebug(mConfig->serial.debug); - mPayload.addPayloadListener(std::bind(&app::payloadEventListener, this, std::placeholders::_1, std::placeholders::_2)); - if (mConfig->nrf.enabled) { - mMiPayload.setup(this, &mSys, &mTimestamp); - mMiPayload.enableSerialDebug(mConfig->serial.debug); - mMiPayload.addPayloadListener(std::bind(&app::payloadEventListener, this, std::placeholders::_1, std::placeholders::_2)); - }*/ - if(mConfig->nrf.enabled) { if (!mNrfRadio.isChipConnected()) DPRINTLN(DBG_WARN, F("WARNING! your NRF24 module can't be reached, check the wiring")); @@ -95,8 +86,6 @@ void app::setup() { mMqtt.setup(&mConfig->mqtt, mConfig->sys.deviceName, mVersion, &mSys, &mTimestamp, &mUptime); mMqtt.setSubscriptionCb(std::bind(&app::mqttSubRxCb, this, std::placeholders::_1)); mCommunication.addAlarmListener([this](Inverter<> *iv) { mMqtt.alarmEvent(iv); }); - //mPayload.addAlarmListener([this](Inverter<> *iv) { mMqtt.alarmEvent(iv); }); - //mMiPayload.addAlarmListener([this](Inverter<> *iv) { mMqtt.alarmEvent(iv); }); } #endif setupLed(); @@ -124,7 +113,6 @@ void app::setup() { //----------------------------------------------------------------------------- void app::loop(void) { ah::Scheduler::loop(); - //bool processPayload = false; mNrfRadio.loop(); #if defined(ESP32) @@ -132,66 +120,6 @@ void app::loop(void) { #endif mCommunication.loop(); - /*if (mNrfRadio.loop() && mConfig->nrf.enabled) { - while (!mNrfRadio.mBufCtrl.empty()) { - packet_t *p = &mNrfRadio.mBufCtrl.front(); - if (mConfig->serial.debug) { - DPRINT(DBG_INFO, F("RX ")); - DBGPRINT(String(p->len)); - DBGPRINT(F(" CH")); - DBGPRINT(String(p->ch)); - DBGPRINT(F(", ")); - DBGPRINT(String(p->rssi)); - DBGPRINT(F("dBm | ")); - ah::dumpBuf(p->packet, p->len); - } - - Inverter<> *iv = mSys.findInverter(&p->packet[1]); - if (NULL != iv) { - iv->radioStatistics.frmCnt++; - if (IV_MI == iv->ivGen) - mMiPayload.add(iv, p); - else - mPayload.add(iv, p); - } - mNrfRadio.mBufCtrl.pop(); - processPayload = true; - yield(); - } - mMiPayload.process(true); - } - #if defined(ESP32) - if (mCmtRadio.loop() && mConfig->cmt.enabled) { - while (!mCmtRadio.mBufCtrl.empty()) { - packet_t *p = &mCmtRadio.mBufCtrl.front(); - if (mConfig->serial.debug) { - DPRINT(DBG_INFO, F("RX ")); - DBGPRINT(String(p->len)); - DBGPRINT(F(", ")); - DBGPRINT(String(p->rssi)); - DBGPRINT(F("dBm | ")); - ah::dumpBuf(p->packet, p->len); - } - - Inverter<> *iv = mSys.findInverter(&p->packet[1]); - if(NULL != iv) { - iv->radioStatistics.frmCnt++; - if((iv->ivGen == IV_HMS) || (iv->ivGen == IV_HMT)) - mPayload.add(iv, p); - } - mCmtRadio.mBufCtrl.pop(); - processPayload = true; - yield(); - } - } - #endif - - if(processPayload) - mPayload.process(true); - - mPayload.loop(); - mMiPayload.loop();*/ - if (mMqttEnabled && mNetworkConnected) mMqtt.loop(); } @@ -293,7 +221,7 @@ void app::tickNtpUpdate(void) { // immediately start communicating if (isOK && mSendFirst) { mSendFirst = false; - //once(std::bind(&app::tickSend, this), 2, "senOn"); + once(std::bind(&app::tickSend, this), 1, "senOn"); } mMqttReconnect = false; @@ -424,54 +352,6 @@ void app::tickSend(void) { } } - /*if(mConfig->nrf.enabled) { - if(!mNrfRadio.isChipConnected()) { - DPRINTLN(DBG_WARN, F("NRF24 not connected!")); - } - } - - if (mIVCommunicationOn) { - if (!mNrfRadio.mBufCtrl.empty()) { - if (mConfig->serial.debug) { - DPRINT(DBG_DEBUG, F("recbuf not empty! #")); - DBGPRINTLN(String(mNrfRadio.mBufCtrl.size())); - } - } - #if defined(ESP32) - if (!mCmtRadio.mBufCtrl.empty()) { - if (mConfig->serial.debug) { - DPRINT(DBG_INFO, F("recbuf not empty! #")); - DBGPRINTLN(String(mCmtRadio.mBufCtrl.size())); - } - } - #endif - - int8_t maxLoop = MAX_NUM_INVERTERS; - Inverter<> *iv = mSys.getInverterByPos(mSendLastIvId); - while(maxLoop > 0) { - do { - mSendLastIvId = ((MAX_NUM_INVERTERS - 1) == mSendLastIvId) ? 0 : mSendLastIvId + 1; - iv = mSys.getInverterByPos(mSendLastIvId); - } while ((NULL == iv) && ((maxLoop--) > 0)); - if(NULL != iv) - if(iv->config->enabled) - break; - } - - if (NULL != iv) { - if (iv->config->enabled) { - if((iv->ivGen == IV_MI) && mConfig->nrf.enabled) - mMiPayload.ivSend(iv); - else - mPayload.ivSend(iv); - } - } - } else { - if (mConfig->serial.debug) - DPRINTLN(DBG_WARN, F("Time not set or it is night time, therefore no communication to the inverter!")); - } - yield();*/ - updateLed(); } diff --git a/src/app.h b/src/app.h index d28c3bf6..c257d83d 100644 --- a/src/app.h +++ b/src/app.h @@ -15,8 +15,6 @@ #include "hm/hmSystem.h" #include "hm/hmRadio.h" #include "hms/hmsRadio.h" -//#include "hm/hmPayload.h" -//#include "hm/miPayload.h" #include "publisher/pubMqtt.h" #include "publisher/pubSerial.h" #include "utils/crc.h" @@ -41,8 +39,6 @@ #define ACOS(x) (degrees(acos(x))) typedef HmSystem HmSystemType; -//typedef HmPayload PayloadType; -//typedef MiPayload MiPayloadType; #ifdef ESP32 typedef CmtRadio CmtRadioType; #endif @@ -171,15 +167,6 @@ class app : public IApp, public ah::Scheduler { mMqtt.setPowerLimitAck(iv); } - void ivSendHighPrio(Inverter<> *iv) { - if(mIVCommunicationOn) { // only send commands if communication is enabled - //if (iv->ivGen == IV_MI) - // mMiPayload.ivSendHighPrio(iv); - //else - // mPayload.ivSendHighPrio(iv); - } - } - bool getMqttIsConnected() { return mMqtt.isConnected(); } diff --git a/src/appInterface.h b/src/appInterface.h index d3bc8346..4bfc3b0c 100644 --- a/src/appInterface.h +++ b/src/appInterface.h @@ -53,8 +53,6 @@ class IApp { virtual void setMqttDiscoveryFlag() = 0; virtual void setMqttPowerLimitAck(Inverter<> *iv) = 0; - virtual void ivSendHighPrio(Inverter<> *iv) = 0; - virtual bool getMqttIsConnected() = 0; virtual uint32_t getMqttRxCnt() = 0; virtual uint32_t getMqttTxCnt() = 0; diff --git a/src/defines.h b/src/defines.h index be59fb4f..1a865fa7 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 0 +#define VERSION_PATCH 1 //------------------------------------- typedef struct { @@ -94,6 +94,8 @@ enum {MQTT_STATUS_OFFLINE = 0, MQTT_STATUS_PARTIAL, MQTT_STATUS_ONLINE}; #define MQTT_MAX_PACKET_SIZE 384 +#define PLUGIN_DISPLAY + typedef struct { uint32_t rxFail; uint32_t rxFailNoAnser; diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index 4042935d..8d0bb0f8 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -22,10 +22,6 @@ class CommQueue { void add(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) { mQueue[mWrPtr] = queue_s(iv, cmd, delOnPop, false); - /*mQueue[mRdPtr].firstTry = false; - if((IV_HM == mQueue[mRdPtr].iv->ivGen) || (IV_MI == mQueue[mRdPtr].iv->ivGen)) { - mQueue[mRdPtr].firstTry = ((mQueue[mRdPtr].iv->isAvailable()) || (millis() < 120000)); - }*/ inc(&mWrPtr); } @@ -41,7 +37,6 @@ class CommQueue { uint32_t ts; bool delOnPop; bool isDevControl; - //bool firstTry; queue_s() {} queue_s(Inverter<> *i, uint8_t c, bool d, bool dev) : iv(i), cmd(c), attempts(5), ts(0), delOnPop(d), isDevControl(dev) {} @@ -50,10 +45,6 @@ class CommQueue { protected: void add(queue_s q) { mQueue[mWrPtr] = q; - /*mQueue[mRdPtr].firstTry = false; - if((IV_HM == mQueue[mRdPtr].iv->ivGen) || (IV_MI == mQueue[mRdPtr].iv->ivGen)) { - mQueue[mRdPtr].firstTry = ((mQueue[mRdPtr].iv->isAvailable()) || (millis() < 120000)); - }*/ inc(&mWrPtr); } @@ -61,10 +52,6 @@ class CommQueue { mQueue[mWrPtr] = *q; if(rstAttempts) mQueue[mWrPtr].attempts = 5; - /*mQueue[mRdPtr].firstTry = false; - if((IV_HM == mQueue[mRdPtr].iv->ivGen) || (IV_MI == mQueue[mRdPtr].iv->ivGen)) { - mQueue[mRdPtr].firstTry = ((mQueue[mRdPtr].iv->isAvailable()) || (millis() < 120000)); - }*/ inc(&mWrPtr); } @@ -89,13 +76,6 @@ class CommQueue { inc(&mRdPtr); } - /*bool isFirstTry(void) { - if(!mQueue[mRdPtr].firstTry) - return false; - mQueue[mRdPtr].firstTry = false; - return true; - }*/ - void setTs(uint32_t *ts) { mQueue[mRdPtr].ts = *ts; } diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 8a7a9e7a..b2a82e89 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -9,6 +9,7 @@ #include "CommQueue.h" #include #include "../utils/crc.h" +#include "heuristic.h" #define MI_TIMEOUT 250 #define DEFAULT_TIMEOUT 500 @@ -52,6 +53,9 @@ class Communication : public CommQueue<> { for(uint8_t i = 0; i < MAX_PAYLOAD_ENTRIES; i++) { mLocalBuf[i].len = 0; } + + mHeu.printStatus(q->iv); + mHeu.getTxCh(q->iv); mState = States::START; break; @@ -84,6 +88,7 @@ class Communication : public CommQueue<> { DBGPRINTLN(F("ms")); q->iv->radioStatistics.rxFailNoAnser++; // got nothing + mHeu.setGotNothing(q->iv); if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, WORK_FREQ_KHZ); mWaitTimeout = millis() + 1000; @@ -135,7 +140,8 @@ class Communication : public CommQueue<> { yield(); } if(0 == q->attempts) { - //cmdDone(q); + mHeu.setGotFragment(q->iv); + q->iv->radioStatistics.rxFail++; // got no complete payload cmdDone(true); mState = States::RESET; } else @@ -160,17 +166,7 @@ class Communication : public CommQueue<> { i++; } - if(q->attempts) { - q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true); - q->iv->radioStatistics.retransmits++; - mWaitTimeout = millis() + SINGLEFR_TIMEOUT; // timeout - mState = States::WAIT; - } else { - add(q, true); - //cmdDone(q); - cmdDone(true); - mState = States::RESET; - } + sendRetransmit(q, i); return; } @@ -185,21 +181,12 @@ class Communication : public CommQueue<> { DBGPRINT(String(q->attempts)); DBGPRINTLN(F(" attempts left)")); - if(q->attempts) { - q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true); - q->iv->radioStatistics.retransmits++; - mWaitTimeout = millis() + SINGLEFR_TIMEOUT; // timeout; - mState = States::WAIT; - } else { - add(q, true); - //cmdDone(q); - cmdDone(true); - mState = States::RESET; - } + sendRetransmit(q, i); return; } } + mHeu.setGotAll(q->iv); compilePayload(q); if(NULL != mCbPayload) @@ -376,6 +363,21 @@ class Communication : public CommQueue<> { } } + void sendRetransmit(const queue_s *q, uint8_t i) { + if(q->attempts) { + q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true); + q->iv->radioStatistics.retransmits++; + mWaitTimeout = millis() + SINGLEFR_TIMEOUT; // timeout + mState = States::WAIT; + } else { + mHeu.setGotFragment(q->iv); + q->iv->radioStatistics.rxFail++; // got no complete payload + add(q, true); + cmdDone(true); + mState = States::RESET; + } + } + private: inline void miHwDecode(packet_t *p, const queue_s *q) { record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_All); // choose the record structure @@ -714,6 +716,7 @@ class Communication : public CommQueue<> { uint8_t mPayload[MAX_BUFFER]; payloadListenerType mCbPayload = NULL; alarmListenerType mCbAlarm = NULL; + Heuristic mHeu; }; #endif /*__COMMUNICATION_H__*/ diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index 3080e8df..7364f472 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -7,6 +7,7 @@ #define __HEURISTIC_H__ #include "../utils/dbg.h" +#include "hmInverter.h" #define RF_MAX_CHANNEL_ID 5 #define RF_MAX_QUALITY 4 @@ -14,96 +15,58 @@ class Heuristic { public: - void setup() { - uint8_t j; - for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) { - mTxQuality[i] = -6; // worst - for(j = 0; j < 10; j++) { - mRxCh[i][j] = 3; - } - } - } - - /*uint8_t getRxCh(void) { + uint8_t getTxCh(Inverter<> *iv) { + if((IV_HMS == iv->ivGen) || (IV_HMT == iv->ivGen)) + return 0; // not used for these inverter types - }*/ - - uint8_t getTxCh(void) { - if(++mCycleCnt > RF_MAX_CHANNEL_ID) { - bool ok = false; - for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) { - if(mTxQuality[i] > -4) { - ok = true; - mState = States::RUNNING; - } - } - if(!ok) { // restart - mCycleCnt = 0; - mState = States::TRAINING; + uint8_t id = 0; + int8_t bestQuality = -6; + for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) { + if(iv->txRfQuality[i] > bestQuality) { + bestQuality = iv->txRfQuality[i]; + id = i; } } + if(bestQuality > -6) + iv->txRfChId = (iv->txRfChId + 1) % RF_MAX_CHANNEL_ID; // next channel + else + iv->txRfChId = id; // best quality channel - if(States::TRAINING == mState) { - mTxChId = (mTxChId + 1) % RF_MAX_CHANNEL_ID; - return id2Ch(mTxChId); - } else { - int8_t bestQuality = -6; - uint8_t id = 0; - for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) { - if((mCycleCnt % 50) == 0) { - if(mTxQuality[(i + mTxChId) % RF_MAX_CHANNEL_ID] != -6) { - id = i; - break; - } - - } - if(mTxQuality[(i + mTxChId) % RF_MAX_CHANNEL_ID] == 4) { - id = i; - break; - } - if(mTxQuality[i] > bestQuality) { - bestQuality = mTxQuality[i]; - id = i; - } - } - mTxChId = id; - return id2Ch(mTxChId); - } + return id2Ch(iv->txRfChId); } - void setGotAll(void) { - updateQuality(2); // GOOD + void setGotAll(Inverter<> *iv) { + updateQuality(iv, 2); // GOOD } - void setGotFragment(void) { - updateQuality(1); // OK + void setGotFragment(Inverter<> *iv) { + updateQuality(iv, 1); // OK } - void setGotNothing(void) { - updateQuality(-2); // BAD + void setGotNothing(Inverter<> *iv) { + updateQuality(iv, -2); // BAD } - void printStatus(void) { - DPRINT(DBG_INFO, F("Status: #")); - DBGPRINT(String(mCycleCnt)); + void printStatus(Inverter<> *iv) { + DPRINT(DBG_INFO, F("Status:")); DBGPRINT(F(" |")); for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) { DBGPRINT(F(" ")); - DBGPRINT(String(mTxQuality[i])); + DBGPRINT(String(iv->txRfQuality[i])); } DBGPRINTLN(""); } private: - void updateQuality(uint8_t quality) { - mTxQuality[mTxChId] += quality; - if(mTxQuality[mTxChId] > RF_MAX_QUALITY) - mTxQuality[mTxChId] = RF_MAX_QUALITY; - else if(mTxQuality[mTxChId] < RF_MIN_QUALTIY) - mTxQuality[mTxChId] = RF_MIN_QUALTIY; + void updateQuality(Inverter<> *iv, uint8_t quality) { + iv->txRfQuality[iv->txRfChId] += quality; + if(iv->txRfQuality[iv->txRfChId] > RF_MAX_QUALITY) + iv->txRfQuality[iv->txRfChId] = RF_MAX_QUALITY; + else if(iv->txRfQuality[iv->txRfChId] < RF_MIN_QUALTIY) + iv->txRfQuality[iv->txRfChId] = RF_MIN_QUALTIY; } - uint8_t ch2Id(uint8_t ch) { + /*uint8_t ch2Id(uint8_t ch) { switch(ch) { case 3: return 0; case 23: return 1; @@ -112,9 +75,9 @@ class Heuristic { case 75: return 4; } return 0; // standard - } + }*/ - uint8_t id2Ch(uint8_t id) { + inline uint8_t id2Ch(uint8_t id) { switch(id) { case 0: return 3; case 1: return 23; @@ -125,22 +88,8 @@ class Heuristic { return 0; // standard } - private: - enum class States : uint8_t { - TRAINING, RUNNING - }; - private: uint8_t mChList[5] = {03, 23, 40, 61, 75}; - - int8_t mTxQuality[RF_MAX_CHANNEL_ID]; - uint8_t mTxChId = 0; - - uint8_t mRxCh[RF_MAX_CHANNEL_ID][10]; - uint8_t mRxChId = 0; - - uint32_t mCycleCnt = 0; - States mState = States::TRAINING; }; diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index d1a1e43a..6cb2567e 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -78,31 +78,6 @@ struct alarm_t { alarm_t() : code(0), start(0), end(0) {} }; -class CommandAbstract { - public: - CommandAbstract(uint8_t txType = 0, uint8_t cmd = 0) { - _TxType = txType; - _Cmd = cmd; - }; - virtual ~CommandAbstract() {}; - - uint8_t getCmd() const { - return _Cmd; - } - - protected: - uint8_t _TxType; - uint8_t _Cmd; -}; - -class InfoCommand : public CommandAbstract { - public: - InfoCommand(uint8_t cmd){ - _TxType = 0x15; - _Cmd = cmd; - } -}; - // list of all available functions, mapped in hmDefines.h template const calcFunc_t calcFunctions[] = { @@ -153,7 +128,8 @@ class Inverter { int8_t rssi; // RSSI Radio *radio; // pointer to associated radio class statistics_t radioStatistics; // information about transmitted, failed, ... packets - + int8_t txRfQuality[5]; // heuristics tx quality (check 'Heuristics.h') + uint8_t txRfChId; // RF TX channel id static uint32_t *timestamp; // system timestamp static cfgInst_t *generalConfig; // general inverter configuration from setup @@ -175,10 +151,7 @@ class Inverter { alarmLastId = 0; rssi = -127; memset(&radioStatistics, 0, sizeof(statistics_t)); - } - - ~Inverter() { - // TODO: cleanup + memset(txRfQuality, -6, 5); } void tickSend(std::function cb) { @@ -194,7 +167,10 @@ class Inverter { cb(InverterDevInform_Simple, false); // get hardware version else if(actPowerLimit == 0xffff) cb(SystemConfigPara, false); // power limit info - else + else if(InitDataState != devControlCmd) { + cb(devControlCmd, false); // custom command which was received by API + devControlCmd = InitDataState; + } else cb(RealTimeRunData_Debug, false); // get live data } else { if(0 == getFwVersion()) @@ -209,57 +185,6 @@ class Inverter { } } - /*template - void enqueCommand(uint8_t cmd) { - _commandQueue.push(std::make_shared(cmd)); - DPRINT_IVID(DBG_INFO, id); - DBGPRINT(F("enqueCommand: 0x")); - DBGHEXLN(cmd); - } - - void setQueuedCmdFinished() { - if (!_commandQueue.empty()) { - _commandQueue.pop(); - } - } - - void clearCmdQueue() { - DPRINTLN(DBG_INFO, F("clearCmdQueue")); - while (!_commandQueue.empty()) { - _commandQueue.pop(); - } - } - - uint8_t getQueuedCmd() { - if (_commandQueue.empty()) { - if (ivGen != IV_MI) { - if (getFwVersion() == 0) - enqueCommand(InverterDevInform_All); // firmware version - else if (getHwVersion() == 0) - enqueCommand(InverterDevInform_Simple); // hardware version - else if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) - enqueCommand(AlarmData); // alarm not answered - enqueCommand(RealTimeRunData_Debug); // live data - } else { // if (ivGen == IV_MI){ - if (getFwVersion() == 0) { - enqueCommand(InverterDevInform_All); // hard- and firmware version - } else { - record_t<> *rec = getRecordStruct(InverterDevInform_Simple); - if (getChannelFieldValue(CH0, FLD_PART_NUM, rec) == 0) { - enqueCommand(InverterDevInform_All); // hard- and firmware version for missing HW part nr, delivered by frame 1 - } else { - enqueCommand( type == INV_TYPE_4CH ? 0x36 : 0x09 ); - } - } - } - - if ((actPowerLimit == 0xffff) && isConnected) - enqueCommand(SystemConfigPara); // power limit info - } - return _commandQueue.front().get()->getCmd(); - }*/ - - void init(void) { DPRINTLN(DBG_VERBOSE, F("hmInverter.h:init")); initAssignment(&recordMeas, RealTimeRunData_Debug); @@ -318,8 +243,10 @@ class Inverter { return isConnected; } - void clearDevControlRequest() { - mDevControlRequest = false; + bool setDevCommand(uint8_t cmd) { + if(isConnected) + devControlCmd = cmd; + return isConnected; } void addValue(uint8_t pos, uint8_t buf[], record_t<> *rec) { @@ -359,11 +286,9 @@ class Inverter { if (getPosByChFld(0, FLD_EVT, rec) == pos) { if (alarmMesIndex < rec->record[pos]) { alarmMesIndex = rec->record[pos]; - //enqueCommand(AlarmUpdate); // What is the function of AlarmUpdate? DPRINT(DBG_INFO, "alarm ID incremented to "); DBGPRINTLN(String(alarmMesIndex)); - //enqueCommand(AlarmData); } } } @@ -740,7 +665,6 @@ class Inverter { radioId.b[0] = 0x01; } - //std::queue> _commandQueue; bool mDevControlRequest; // true if change needed }; diff --git a/src/hm/hmPayload.h b/src/hm/hmPayload.h deleted file mode 100644 index 1f4ef550..00000000 --- a/src/hm/hmPayload.h +++ /dev/null @@ -1,494 +0,0 @@ -//----------------------------------------------------------------------------- -// 2023 Ahoy, https://ahoydtu.de -// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed -//----------------------------------------------------------------------------- - -#ifndef __HM_PAYLOAD_H__ -#define __HM_PAYLOAD_H__ - -#include "../utils/dbg.h" -#include "../utils/crc.h" -#include "../config/config.h" -#include "hmRadio.h" -#if defined(ESP32) -#include "../hms/cmt2300a.h" -#endif -#include - -#define HMS_TIMEOUT_SEC 30 - -typedef struct { - uint8_t txCmd; - uint8_t txId; - uint32_t ts; - uint8_t data[MAX_PAYLOAD_ENTRIES][MAX_RF_PAYLOAD_SIZE]; - int8_t rssi[MAX_PAYLOAD_ENTRIES]; - uint8_t len[MAX_PAYLOAD_ENTRIES]; - bool complete; - uint8_t maxPackId; - bool lastFound; - uint8_t retransmits; - bool requested; - bool gotFragment; - bool rxTmo; - uint32_t sendMillis; -} invPayload_t; - - -typedef std::function *)> payloadListenerType; -typedef std::function *)> alarmListenerType; - - -template -class HmPayload { - public: - HmPayload() {} - - void setup(IApp *app, HMSYSTEM *sys, uint32_t *timestamp) { - mApp = app; - mSys = sys; - mMaxRetrans = 5; - mTimestamp = timestamp; - for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { - reset(i); - mIvCmd56Cnt[i] = 0; - } - mSerialDebug = false; - mHighPrioIv = NULL; - mCbAlarm = NULL; - mCbPayload = NULL; - } - - void enableSerialDebug(bool enable) { - mSerialDebug = enable; - } - - void addPayloadListener(payloadListenerType cb) { - mCbPayload = cb; - } - - void addAlarmListener(alarmListenerType cb) { - mCbAlarm = cb; - } - - void loop() { - if (NULL != mHighPrioIv) { - ivSend(mHighPrioIv, true); // for e.g. devcontrol commands - mHighPrioIv = NULL; - } - } - - /*void simulation() { - uint8_t pay[] = { - 0x00, 0x01, 0x01, 0x24, 0x02, 0x28, 0x02, 0x33, - 0x06, 0x49, 0x06, 0x6a, 0x00, 0x05, 0x5f, 0x1b, - 0x00, 0x06, 0x66, 0x9a, 0x03, 0xfd, 0x04, 0x0b, - 0x01, 0x23, 0x02, 0x28, 0x02, 0x28, 0x06, 0x41, - 0x06, 0x43, 0x00, 0x05, 0xdc, 0x2c, 0x00, 0x06, - 0x2e, 0x3f, 0x04, 0x01, 0x03, 0xfb, 0x09, 0x78, - 0x13, 0x86, 0x18, 0x15, 0x00, 0xcf, 0x00, 0xfe, - 0x03, 0xe7, 0x01, 0x42, 0x00, 0x03 - }; - - Inverter<> *iv = mSys->getInverterByPos(0); - record_t<> *rec = iv->getRecordStruct(0x0b); - rec->ts = *mTimestamp; - for (uint8_t i = 0; i < rec->length; i++) { - iv->addValue(i, pay, rec); - yield(); - } - iv->doCalculations(); - notify(0x0b, iv); - }*/ - - 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 (mSerialDebug) - DPRINT_IVID(DBG_INFO, iv->id); - if (MAX_PAYLOAD_ENTRIES == mPayload[iv->id].maxPackId) { - iv->radioStatistics.rxFailNoAnser++; // got nothing - if (mSerialDebug) - DBGPRINTLN(F("enqueued cmd failed/timeout")); - } else { - iv->radioStatistics.rxFail++; // got fragments but not complete response - if (mSerialDebug) { - DBGPRINT(F("no complete Payload received! (retransmits: ")); - DBGPRINT(String(mPayload[iv->id].retransmits)); - DBGPRINTLN(F(")")); - } - } - iv->setQueuedCmdFinished(); // command failed - } - } - } - - reset(iv->id, !iv->isAvailable()); - mPayload[iv->id].requested = true; - - yield(); - if (mSerialDebug) { - DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINT(F("Requesting Inv SN ")); - DBGPRINTLN(String(iv->config->serial.u64, HEX)); - } - - if (iv->getDevControlRequest()) { - if (mSerialDebug) { - DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINT(F("Devcontrol request 0x")); - DHEX(iv->devControlCmd); - DBGPRINT(F(" power limit ")); - DBGPRINTLN(String(iv->powerLimit[0])); - } - iv->powerLimitAck = false; - iv->radio->sendControlPacket(iv, iv->devControlCmd, iv->powerLimit, false); - mPayload[iv->id].txCmd = iv->devControlCmd; - //iv->clearCmdQueue(); - //iv->enqueCommand(SystemConfigPara); // read back power limit - } else { - #if defined(ESP32) - if((IV_HMS == iv->ivGen) || (IV_HMT == iv->ivGen)) { - record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); - if(((rec->ts + HMS_TIMEOUT_SEC) < *mTimestamp) && (mIvCmd56Cnt[iv->id] < 3)) { - iv->radio->switchFrequency(iv, HOY_BOOT_FREQ_KHZ, WORK_FREQ_KHZ); - mIvCmd56Cnt[iv->id]++; - return; - } else if(++mIvCmd56Cnt[iv->id] == 10) - mIvCmd56Cnt[iv->id] = 0; - } - #endif - uint8_t cmd = iv->getQueuedCmd(); - if (mSerialDebug) { - DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINT(F("prepareDevInformCmd 0x")); - DBGHEXLN(cmd); - } - iv->radio->prepareDevInformCmd(iv, cmd, mPayload[iv->id].ts, iv->alarmLastId, false); - mPayload[iv->id].txCmd = cmd; - } - } - - void add(Inverter<> *iv, packet_t *p) { - if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command - 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) { - DPRINTLN(DBG_DEBUG, F("fragment number zero received and ignored")); - } else { - DPRINT(DBG_DEBUG, F("PID: 0x")); - DPRINTLN(DBG_DEBUG, 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; - mPayload[iv->id].rssi[(*pid & 0x7F) - 1] = p->rssi; - } - - 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 - DPRINTLN(DBG_DEBUG, F("Response from devcontrol request received")); - - mPayload[iv->id].txId = p->packet[0]; - iv->clearDevControlRequest(); - - if ((p->packet[12] == ActivePowerContr) && (p->packet[13] == 0x00)) { - bool ok = true; - if((p->packet[10] == 0x00) && (p->packet[11] == 0x00)) { - mApp->setMqttPowerLimitAck(iv); - iv->powerLimitAck = true; - } else - ok = false; - - 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 - if(mHighPrioIv == NULL) // do it immediately if possible - mHighPrioIv = iv; - } - iv->devControlCmd = Init; - } - } - - 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 ((mPayload[iv->id].txId != (TX_REQ_INFO + ALL_FRAMES)) && (0 != mPayload[iv->id].txId)) { - // no processing needed if txId is not 0x95 - mPayload[iv->id].complete = true; - continue; // skip to next inverter - } - - if((IV_HMS == iv->ivGen) || (IV_HMT == iv->ivGen)) { - if((mPayload[iv->id].sendMillis + 400) > millis()) - return; // to fast, wait until packets are received! - } - - if (!mPayload[iv->id].complete) { - bool crcPass, pyldComplete, fastNext; - - crcPass = build(iv, &pyldComplete, &fastNext); - if (!crcPass && !pyldComplete) { // payload not complete - if ((mPayload[iv->id].requested) && (retransmit)) { - if (mPayload[iv->id].retransmits < mMaxRetrans) { - 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...")); - mPayload[iv->id].retransmits = mMaxRetrans; - } else if(iv->devControlCmd == ActivePowerContr) { - DPRINT_IVID(DBG_INFO, iv->id); - DPRINTLN(DBG_INFO, F("retransmit power limit")); - iv->radio->sendControlPacket(iv, iv->devControlCmd, iv->powerLimit, true); - } else { - if(false == mPayload[iv->id].gotFragment) { - DPRINT_IVID(DBG_WARN, iv->id); - if (mPayload[iv->id].rxTmo) { - DBGPRINTLN(F("nothing received")); - mPayload[iv->id].retransmits = mMaxRetrans; - } else { - DBGPRINTLN(F("nothing received: complete retransmit")); - mPayload[iv->id].txCmd = iv->getQueuedCmd(); - DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX)); - iv->radio->prepareDevInformCmd(iv, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); - } - } else { - for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId - 1); i++) { - if (mPayload[iv->id].len[i] == 0) { - if (mSerialDebug) { - DPRINT_IVID(DBG_WARN, iv->id); - DBGPRINT(F("Frame ")); - DBGPRINT(String(i + 1)); - DBGPRINTLN(F(" missing: Request Retransmit")); - } - iv->radio->sendCmdPacket(iv, TX_REQ_INFO, (SINGLE_FRAME + i), true); - break; // only request retransmit one frame per loop - } - yield(); - } - } - } - } - } else if (false == mPayload[iv->id].gotFragment) { - // only if there is no sign of life - mPayload[iv->id].rxTmo = true; // inv might be down, no complete retransmit anymore - } - } else if(!crcPass && pyldComplete) { // crc error on complete Payload - if (mPayload[iv->id].retransmits < mMaxRetrans) { - mPayload[iv->id].retransmits++; - mPayload[iv->id].txCmd = iv->getQueuedCmd(); - if (mSerialDebug) { - DPRINT_IVID(DBG_WARN, iv->id); - DBGPRINTLN(F("CRC Error: Request Complete Retransmit")); - DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINT(F("prepareDevInformCmd 0x")); - DBGHEXLN(mPayload[iv->id].txCmd); - } - iv->radio->prepareDevInformCmd(iv, mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmLastId, true); - } - } else { // payload complete - if (mSerialDebug) { - DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINT(F("procPyld: cmd: 0x")); - DBGHEXLN(mPayload[iv->id].txCmd); - //DPRINT(DBG_DEBUG, F("procPyld: txid: 0x")); - //DBGHEXLN(mPayload[iv->id].txId); - DPRINT(DBG_DEBUG, F("procPyld: max: ")); - DPRINTLN(DBG_DEBUG, String(mPayload[iv->id].maxPackId)); - } - record_t<> *rec = iv->getRecordStruct(mPayload[iv->id].txCmd); // choose the parser - mPayload[iv->id].complete = true; - mPayload[iv->id].requested = false; - mPayload[iv->id].rxTmo = false; - - uint8_t payload[MAX_BUFFER]; - uint8_t payloadLen = 0; - - memset(payload, 0, MAX_BUFFER); - - int8_t rssi = -127; - - for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId); i++) { - if((mPayload[iv->id].len[i] + payloadLen) > MAX_BUFFER) { - DPRINTLN(DBG_ERROR, F("payload buffer to small!")); - break; - } - memcpy(&payload[payloadLen], mPayload[iv->id].data[i], (mPayload[iv->id].len[i])); - payloadLen += (mPayload[iv->id].len[i]); - // get worst RSSI - if(mPayload[iv->id].rssi[i] > rssi) - rssi = mPayload[iv->id].rssi[i]; - yield(); - } - payloadLen -= 2; - - if (mSerialDebug) { - DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINT(F("Payload (")); - DBGPRINT(String(payloadLen)); - DBGPRINT(F("): ")); - ah::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)) - iv->radioStatistics.rxSuccess++; - - rec->ts = mPayload[iv->id].ts; - for (uint8_t i = 0; i < rec->length; i++) { - iv->addValue(i, payload, rec); - yield(); - } - iv->rssi = rssi; - iv->doCalculations(); - notify(mPayload[iv->id].txCmd, iv); - - if(AlarmData == mPayload[iv->id].txCmd) { - uint8_t i = 0; - while(1) { - if(0 == iv->parseAlarmLog(i++, payload, payloadLen)) - break; - if (NULL != mCbAlarm) - (mCbAlarm)(iv); - yield(); - } - } - if (fastNext && (mHighPrioIv == NULL)) { - /*iv->setQueuedCmdFinished(); - uint8_t cmd = iv->getQueuedCmd(); - if (mSerialDebug) { - DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINT(F("fast mode ")); - DBGPRINT(F("prepareDevInformCmd 0x")); - DBGHEXLN(cmd); - } - iv->radioStatistics.rxSuccess++; - iv->radio->prepareDevInformCmd(iv, cmd, mPayload[iv->id].ts, iv->alarmLastId, false); - mPayload[iv->id].txCmd = cmd; - */ - mHighPrioIv = iv; - } - - } else { - if (mSerialDebug) { - DPRINT(DBG_ERROR, F("plausibility check failed, expected ")); - DBGPRINT(String(rec->pyldLen)); - DBGPRINTLN(F(" bytes")); - } - iv->radioStatistics.rxFail++; - } - - iv->setQueuedCmdFinished(); - } - } - yield(); - } - } - - private: - void notify(uint8_t val, Inverter<> *iv) { - if(NULL != mCbPayload) - (mCbPayload)(val, iv); - } - - bool build(Inverter<> *iv, bool *complete, bool *fastNext ) { - DPRINTLN(DBG_VERBOSE, F("build")); - uint16_t crc = 0xffff, crcRcv = 0x0000; - if (mPayload[iv->id].maxPackId > MAX_PAYLOAD_ENTRIES) - mPayload[iv->id].maxPackId = MAX_PAYLOAD_ENTRIES; - - // check if all fragments are there - *complete = true; - *fastNext = false; - for (uint8_t i = 0; i < mPayload[iv->id].maxPackId; i++) { - if(mPayload[iv->id].len[i] == 0) { - *complete = false; - } - } - if(!*complete) - return false; - - for (uint8_t i = 0; i < mPayload[iv->id].maxPackId; i++) { - if (mPayload[iv->id].len[i] > 0) { - if (i == (mPayload[iv->id].maxPackId - 1)) { - crc = ah::crc16(mPayload[iv->id].data[i], mPayload[iv->id].len[i] - 2, crc); - crcRcv = (mPayload[iv->id].data[i][mPayload[iv->id].len[i] - 2] << 8) | (mPayload[iv->id].data[i][mPayload[iv->id].len[i] - 1]); - } else - crc = ah::crc16(mPayload[iv->id].data[i], mPayload[iv->id].len[i], crc); - } - yield(); - } - - //return (crc == crcRcv) ? true : false; - if (crc != crcRcv) - return false; - - //requests to cause the next request to be executed immediately - if (mPayload[iv->id].gotFragment && ((mPayload[iv->id].txCmd < RealTimeRunData_Debug) || (mPayload[iv->id].txCmd >= AlarmData))) { - *fastNext = true; - } - - return true; - } - - void reset(uint8_t id, bool setTxTmo = true) { - //DPRINT_IVID(DBG_INFO, id); - //DBGPRINTLN(F("resetPayload")); - memset(mPayload[id].len, 0, MAX_PAYLOAD_ENTRIES); - mPayload[id].txCmd = 0; - mPayload[id].gotFragment = false; - mPayload[id].retransmits = 0; - mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; - mPayload[id].lastFound = false; - mPayload[id].complete = false; - mPayload[id].requested = false; - mPayload[id].ts = *mTimestamp; - mPayload[id].rxTmo = setTxTmo; // design: don't start with complete retransmit - mPayload[id].sendMillis = millis(); - } - - IApp *mApp; - HMSYSTEM *mSys; - uint8_t mMaxRetrans; - uint32_t *mTimestamp; - invPayload_t mPayload[MAX_NUM_INVERTERS]; - uint8_t mIvCmd56Cnt[MAX_NUM_INVERTERS]; - bool mSerialDebug; - Inverter<> *mHighPrioIv; - - alarmListenerType mCbAlarm; - payloadListenerType mCbPayload; -}; - -#endif /*__HM_PAYLOAD_H__*/ diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index fc4f2069..203f39aa 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -9,7 +9,6 @@ #include #include "SPI.h" #include "radio.h" -#include "heuristic.h" #define SPI_SPEED 1000000 @@ -41,18 +40,6 @@ class HmRadio : public Radio { } mDtuSn = DTU_SN; - // 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 - mSerialDebug = false; mIrqRcvd = false; } @@ -78,8 +65,6 @@ class HmRadio : public Radio { mSpi->begin(); #endif - mHeu.setup(); - mNrf24.begin(mSpi, ce, cs); mNrf24.setRetries(3, 15); // 3*250us + 250us and 15 loops -> 15ms @@ -123,6 +108,9 @@ class HmRadio : public Radio { mNrf24.setChannel(mRfChLst[mRxChIdx]); mNrf24.startListening(); + if(NULL == mLastIv) // prevent reading on NULL object! + return; + uint32_t startMicros = micros() + 5110; uint32_t loopMillis = millis() + 400; while (millis() < loopMillis) { @@ -130,12 +118,9 @@ class HmRadio : public Radio { if (mIrqRcvd) { mIrqRcvd = false; - if (getReceived()) { // everything received - mHeu.setGotAll(); + if (getReceived()) { // everything received return; - } else - mHeu.setGotFragment(); - + } } yield(); } @@ -148,10 +133,7 @@ class HmRadio : public Radio { // not finished but time is over if(++mRxChIdx >= RF_CHANNELS) mRxChIdx = 0; - if(mBufCtrl.empty()) - mHeu.setGotNothing(); - mHeu.printStatus(); return; } @@ -290,7 +272,7 @@ class HmRadio : public Radio { updateCrcs(&len, appendCrc16); // set TX and RX channels - mTxChIdx = mHeu.getTxCh(); + mTxChIdx = mRfChLst[iv->txRfChId]; if(mSerialDebug) { DPRINT_IVID(DBG_INFO, iv->id); @@ -307,6 +289,8 @@ class HmRadio : public Radio { mNrf24.openWritingPipe(reinterpret_cast(&iv->radioId.u64)); mNrf24.startWrite(mTxBuf, len, false); // false = request ACK response mMillis = millis(); + + mLastIv = iv; } uint64_t getIvId(Inverter<> *iv) { @@ -318,14 +302,14 @@ class HmRadio : public Radio { } uint64_t DTU_RADIO_ID; - uint8_t mRfChLst[RF_CHANNELS]; - uint8_t mTxChIdx; - uint8_t mRxChIdx; + uint8_t mRfChLst[RF_CHANNELS] = {03, 23, 40, 61, 75}; // channel List:2403, 2423, 2440, 2461, 2475MHz + uint8_t mTxChIdx = 0; + uint8_t mRxChIdx = 0; uint32_t mMillis; SPIClass* mSpi; RF24 mNrf24; - Heuristic mHeu; + Inverter<> *mLastIv = NULL; }; #endif /*__HM_RADIO_H__*/ diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h deleted file mode 100644 index 94f7a9b3..00000000 --- a/src/hm/miPayload.h +++ /dev/null @@ -1,844 +0,0 @@ -//----------------------------------------------------------------------------- -// 2023 Ahoy, https://ahoydtu.de -// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed -//----------------------------------------------------------------------------- - -#ifndef __MI_PAYLOAD_H__ -#define __MI_PAYLOAD_H__ -#include "../utils/dbg.h" -#include "../utils/crc.h" -#include "../config/config.h" -#include - -#define MI_REQ_CH1 0x09 -#define MI_REQ_CH2 0x11 -#define MI_REQ_4CH 0x36 - -typedef struct { - uint32_t ts; - bool requested; - bool limitrequested; - uint8_t txCmd; - uint8_t len[MAX_PAYLOAD_ENTRIES]; - int8_t rssi[4]; - bool complete; - bool dataAB[3]; - bool stsAB[3]; - uint16_t sts[5]; - uint8_t txId; - uint8_t invId; - uint8_t retransmits; - bool gotFragment; - bool gotGPF; - uint8_t rtrRes; // for limiting resets - uint8_t multi_parts; // for quality - bool rxTmo; -} miPayload_t; - - -typedef std::function *)> miPayloadListenerType; - - -template -class MiPayload { - public: - MiPayload() {} - - void setup(IApp *app, HMSYSTEM *sys, uint32_t *timestamp) { - mApp = app; - mSys = sys; - mMaxRetrans = 5; - mTimestamp = timestamp; - for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { - reset(i, false, true); - mPayload[i].limitrequested = false; - mPayload[i].gotGPF = false; - } - mSerialDebug = false; - mHighPrioIv = NULL; - mCbPayload = NULL; - } - - void enableSerialDebug(bool enable) { - mSerialDebug = enable; - } - - void addPayloadListener(miPayloadListenerType cb) { - mCbPayload = cb; - } - - void addAlarmListener(alarmListenerType cb) { - mCbAlarm = cb; - } - - void loop() { - if (NULL != mHighPrioIv) { - ivSend(mHighPrioIv, true); // for e.g. 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 && mPayload[iv->id].rxTmo) { - if (mSerialDebug) - DPRINT_IVID(DBG_INFO, iv->id); - if (!mPayload[iv->id].gotFragment) { - iv->radioStatistics.rxFailNoAnser++; // got nothing - if (mSerialDebug) - DBGPRINTLN(F("enqueued cmd failed/timeout")); - } else { - iv->radioStatistics.rxFail++; // got "fragments" (part of the required messages) - // but no complete set of responses - if (mSerialDebug) { - DBGPRINT(F("no complete Payload received! (retransmits: ")); - DBGPRINT(String(mPayload[iv->id].retransmits)); - DBGPRINTLN(F(")")); - } - } - mPayload[iv->id].rxTmo = true; - mPayload[iv->id].complete = true; - iv->setQueuedCmdFinished(); // command failed - } - } - } - - reset(iv->id, !iv->isAvailable()); - mPayload[iv->id].requested = true; - - yield(); - if (mSerialDebug) { - DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINT(F("Requesting Inv SN ")); - DBGPRINTLN(String(iv->config->serial.u64, HEX)); - } - - if (iv->getDevControlRequest()) { - if (mSerialDebug) { - DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINT(F("Devcontrol request 0x")); - DHEX(iv->devControlCmd); - DBGPRINT(F(" power limit ")); - DBGPRINT(String(iv->powerLimit[0])); - DBGPRINT(F(" with PowerLimitControl ")); - DBGPRINTLN(String(iv->powerLimit[1])); - } - iv->powerLimitAck = false; - iv->radio->sendControlPacket(iv, iv->devControlCmd, iv->powerLimit, false, false, (iv->powerLimit[1] == RelativNonPersistent) ? 0 : iv->getMaxPower()); - mPayload[iv->id].txCmd = iv->devControlCmd; - mPayload[iv->id].limitrequested = true; - - iv->clearCmdQueue(); - } else { - uint8_t cmd = iv->getQueuedCmd(); - uint8_t cmd2 = cmd; - if ( cmd == SystemConfigPara ) { //0x05 for HM-types - if (!mPayload[iv->id].gotGPF) { - iv->setQueuedCmdFinished(); - cmd = iv->getQueuedCmd(); - } - } - - if (cmd == 0x01) { //0x1 for HM-types - cmd2 = 0x00; - cmd = 0x0f; // for MI, these seem to make part of polling the device software and hardware version number command - } else if (cmd == SystemConfigPara ) { // 0x05 for HM-types - cmd2 = 0x00; - cmd = 0x10; // legacy GPF request - } - if (mSerialDebug) { - DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINT(F("legacy cmd 0x")); - DBGHEXLN(cmd); - } - iv->radio->sendCmdPacket(iv, cmd, cmd2, false, false); - - 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] == (0x88)) { // 0x88 is MI status response to 0x09 - miStsDecode(iv, p); - } - - else if (p->packet[0] == (MI_REQ_CH2 + SINGLE_FRAME)) { // 0x92; MI status response to 0x11 - miStsDecode(iv, p, CH2); - - } else if ( p->packet[0] == MI_REQ_CH1 + ALL_FRAMES || - p->packet[0] == MI_REQ_CH2 + ALL_FRAMES || - ( p->packet[0] >= (MI_REQ_4CH + 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); - - } else if (p->packet[0] == ( 0x0f + ALL_FRAMES)) { - // MI response from get hardware information request - miHwDecode(iv, p); - mPayload[iv->id].txId = p->packet[0]; - - } else if (p->packet[0] == ( 0x10 + ALL_FRAMES)) { - // MI response from get Grid Profile information request - miGPFDecode(iv, p); - mPayload[iv->id].txId = p->packet[0]; - - } else if ( p->packet[0] == (TX_REQ_INFO + ALL_FRAMES) // response from get information command - || (p->packet[0] == 0xB6 && mPayload[iv->id].txCmd != MI_REQ_4CH)) { // strange short response from MI-1500 3rd gen; might be misleading! - // 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 if (p->packet[9] == 0x81) { // might need some additional check, as this is only meant for short answers! - DPRINT_IVID(DBG_WARN, iv->id); - DBGPRINTLN(F("seems to use 3rd gen. protocol - switching ivGen!")); - iv->ivGen = IV_HM; - iv->setQueuedCmdFinished(); - iv->clearCmdQueue(); - } - } 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 -#if DEBUG_LEVEL >= DBG_DEBUG - if (mSerialDebug) { - DPRINT_IVID(DBG_DEBUG, iv->id); - DBGPRINTLN(F("Response from devcontrol request received")); - } -#endif - mPayload[iv->id].txId = p->packet[0]; - iv->clearDevControlRequest(); - - if ((p->packet[9] == 0x5a) && (p->packet[10] == 0x5a)) { - mApp->setMqttPowerLimitAck(iv); - iv->powerLimitAck = true; - if (mSerialDebug) { - DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINT(F("has accepted power limit set point ")); - DBGPRINT(String(iv->powerLimit[0])); - DBGPRINT(F(" with PowerLimitControl ")); - DBGPRINTLN(String(iv->powerLimit[1])); - } - iv->clearCmdQueue(); - //does not work for MI - //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!!! - if (mSerialDebug) { - DPRINT_IVID(DBG_INFO,iv->id); - DBGPRINT(F("procPyld: cmd: 0x")); - DBGHEXLN(mPayload[iv->id].txCmd); - DPRINT_IVID(DBG_INFO,iv->id); - DBGPRINT(F("procPyld: txid: 0x")); - DBGHEXLN(mPayload[iv->id].txId); - } - - 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); - - payloadLen -= 2; - - if (mSerialDebug) { - DPRINT(DBG_INFO, F("Payload (")); - DBGPRINT(String(payloadLen)); - DBGPRINT("): "); - ah::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)) - iv->radioStatistics.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, iv); - - if(AlarmData == mPayload[iv->id].txCmd) { - uint8_t i = 0; - while(1) { - if(0 == iv->parseAlarmLog(i++, payload, payloadLen)) - break; - if (NULL != mCbAlarm) - (mCbAlarm)(iv); - yield(); - } - } - } else { - DPRINTLN(DBG_ERROR, F("plausibility check failed, expected ") + String(rec->pyldLen) + F(" bytes")); - iv->radioStatistics.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_MI != 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 < (MI_REQ_4CH + ALL_FRAMES)) && - (mPayload[iv->id].txId > (0x39 + ALL_FRAMES)) && - (mPayload[iv->id].txId != (MI_REQ_CH1 + ALL_FRAMES)) && - (mPayload[iv->id].txId != (MI_REQ_CH2 + ALL_FRAMES)) && - (mPayload[iv->id].txId != (0x88)) && - (mPayload[iv->id].txId != (0x92)) && - (mPayload[iv->id].txId != 0) && - mPayload[iv->id].txCmd != 0x0f && - !iv->getDevControlRequest()) { - // no processing needed if txId is not one of 0x95, 0x88, 0x89, 0x91, 0x92 or response to 0x36ff - mPayload[iv->id].complete = true; - mPayload[iv->id].rxTmo = true; - continue; // skip to next inverter - } - - if (!mPayload[iv->id].complete) { - bool gotAllMsgParts, pyldComplete, fastNext; - gotAllMsgParts = build(iv, &pyldComplete, &fastNext); - if (!gotAllMsgParts && !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. - DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINTLN(F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); - mPayload[iv->id].retransmits = mMaxRetrans; - mPayload[iv->id].rxTmo = true; - } else if(iv->devControlCmd == ActivePowerContr) { - DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINTLN(F("retransmit power limit")); - iv->radio->sendControlPacket(iv, iv->devControlCmd, iv->powerLimit, true, false, (iv->powerLimit[1] == RelativNonPersistent) ? 0 : iv->getMaxPower()); - } else { - uint8_t cmd = mPayload[iv->id].txCmd; - if (mPayload[iv->id].retransmits < mMaxRetrans) { - mPayload[iv->id].retransmits++; - if( !mPayload[iv->id].gotFragment && mPayload[iv->id].rxTmo ) { - DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINTLN(F("nothing received")); - mPayload[iv->id].retransmits = mMaxRetrans; - mPayload[iv->id].requested = false; //close failed request - } else if( !mPayload[iv->id].gotFragment && !mPayload[iv->id].rxTmo ) { - DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINTLN(F("retransmit on failed first request")); - mPayload[iv->id].rxTmo = true; - iv->radio->sendCmdPacket(iv, cmd, cmd, true, false); - } else if ( cmd == 0x0f ) { - //hard/firmware request - iv->radio->sendCmdPacket(iv, 0x0f, 0x00, true, false); - mPayload[id].multi_parts = 0; - } else { - bool change = false; - if ( cmd >= MI_REQ_4CH && cmd < 0x39 ) { // MI-1500 Data command - if (cmd > MI_REQ_4CH && mPayload[iv->id].retransmits==1) // first request for the upper channels - change = true; - } else if ( cmd == MI_REQ_CH1 ) {//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 = MI_REQ_CH2; - change = true; - if (mPayload[iv->id].rtrRes < 3) //only get back to first channel twice - mPayload[iv->id].retransmits = 0; //reset counter - } - } - } else if ( cmd == MI_REQ_CH2) { - 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 = MI_REQ_CH1; - change = true; - } - } - } - DPRINT_IVID(DBG_INFO, iv->id); - if (change) { - DBGPRINT(F("next request is")); - mPayload[iv->id].txCmd = cmd; - mPayload[iv->id].rtrRes++; - } else { - DBGPRINT(F("sth.")); - DBGPRINT(F(" missing: Request Retransmit")); - } - DBGPRINT(F(" 0x")); - DBGHEXLN(cmd); - mPayload[id].multi_parts = 0; - iv->radio->sendCmdPacket(iv, cmd, cmd, true, false); - yield(); - } - } else { - mPayload[iv->id].rxTmo = true; - } - } - } - } else if(!gotAllMsgParts && pyldComplete) { // crc error on complete Payload - if (mPayload[iv->id].retransmits < mMaxRetrans) { - mPayload[iv->id].retransmits++; - mPayload[iv->id].txCmd = iv->getQueuedCmd(); - mPayload[id].multi_parts = 0; - if (mSerialDebug) { - DPRINT_IVID(DBG_WARN, iv->id); - DBGPRINTLN(F("CRC Error: Request Complete Retransmit")); - DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINT(F("prepareDevInformCmd 0x")); - DBGHEXLN(mPayload[iv->id].txCmd); - } - iv->radio->sendCmdPacket(iv, mPayload[iv->id].txCmd, mPayload[iv->id].txCmd, false, false); - } else { - mPayload[iv->id].rxTmo = true; - } - } else { - if (!fastNext) { - mPayload[iv->id].rxTmo = true; - } else { - if (mHighPrioIv == NULL) - mHighPrioIv = iv; - } - } - } else { - mPayload[iv->id].rxTmo = true; - } - yield(); - } - } - - private: - void notify(uint8_t val, Inverter<> *iv) { - if(NULL != mCbPayload) - (mCbPayload)(val, iv); - } - - void miStsDecode(Inverter<> *iv, packet_t *p, uint8_t stschan = CH1) { - 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].multi_parts += 3; - 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; - } - - 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 statusMi = 3; // regular status for MI, change to 1 later? - if ( uState == 2 ) { - statusMi = 5050 + stschan; //first approach, needs review! - if (lState) - statusMi += lState*10; - } else if ( uState > 3 ) { - statusMi = uState*1000 + uEnum*10; - if (lState) - statusMi += lState*100; //needs review, esp. for 4ch-8310 state! - //if (lEnum) - statusMi += lEnum; - if (uEnum < 6) { - statusMi += stschan; - } - if (statusMi == 8000) - statusMi = 8310; //trick? - } - - uint16_t prntsts = statusMi == 3 ? 1 : statusMi; - bool stsok = true; - if ( statusMi != mPayload[iv->id].sts[stschan] ) { //sth.'s changed? - iv->alarmCnt = 1; // minimum... - //sth is or was wrong? - if ( (iv->type != INV_TYPE_1CH) && ( (statusMi != 3) - || ((mPayload[iv->id].sts[stschan]) && (statusMi == 3) && (mPayload[iv->id].sts[stschan] != 3))) - ) { - iv->lastAlarm[stschan] = alarm_t(prntsts, mPayload[iv->id].ts,0); - iv->alarmCnt = iv->type == INV_TYPE_2CH ? 3 : 5; - } - - iv->alarmLastId = prntsts; //iv->alarmMesIndex; - - mPayload[iv->id].sts[stschan] = statusMi; - stsok = false; - if (iv->alarmCnt > 1) { //more than one channel - for (uint8_t ch = 0; ch < (iv->alarmCnt); ++ch) { //start with 1 - if (mPayload[iv->id].sts[ch] == 3) { - stsok = true; - break; - } - } - } - if (mSerialDebug) { - DPRINT(DBG_WARN, F("New state on CH")); - DBGPRINT(String(stschan)); DBGPRINT(F(" (")); - DBGPRINT(String(prntsts)); DBGPRINT(F("): ")); - DBGPRINTLN(iv->getAlarmStr(prntsts)); - } - } - - if (!stsok) { - iv->setValue(iv->getPosByChFld(0, FLD_EVT, rec), rec, prntsts); - iv->lastAlarm[0] = alarm_t(prntsts, mPayload[iv->id].ts, 0); - } - - 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?!? - if (mSerialDebug) { - DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINT(F("alarm ID incremented to ")); - DBGPRINTLN(String(iv->alarmMesIndex)); - } - } - } - - 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; - mPayload[iv->id].multi_parts += 4; - - uint8_t datachan = ( p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES) || p->packet[0] == (MI_REQ_4CH + ALL_FRAMES) ) ? CH1 : - ( p->packet[0] == (MI_REQ_CH2 + ALL_FRAMES) || p->packet[0] == (0x37 + ALL_FRAMES) ) ? CH2 : - p->packet[0] == (0x38 + ALL_FRAMES) ? CH3 : - CH4; - // 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))); - mPayload[iv->id].rssi[(datachan-1)] = p->rssi; - - if ( datachan < 3 ) { - mPayload[iv->id].dataAB[datachan] = true; - } - if ( !mPayload[iv->id].dataAB[CH0] && mPayload[iv->id].dataAB[CH1] && mPayload[iv->id].dataAB[CH2] ) { - mPayload[iv->id].dataAB[CH0] = true; - } - - if (p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES) ) { - /*For MI1500: - if (MI1500) { - STAT = (uint8_t)(p->packet[25] ); - FCNT = (uint8_t)(p->packet[26]); - FCODE = (uint8_t)(p->packet[27]); - }*/ - miStsConsolidate(iv, datachan, rec, p->packet[23], p->packet[24]); - - if (p->packet[0] < (0x39 + ALL_FRAMES) ) { - mPayload[iv->id].txCmd++; - mPayload[iv->id].retransmits = 0; // reserve retransmissions for each response - mPayload[iv->id].complete = false; - } else { - miComplete(iv); - } - } - - } - - 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; - if (mSerialDebug) { - 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)); - - //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); - int8_t rssi = -127; - for (uint8_t i = 0; i < 4; i++) { - // get best RSSI - if(mPayload[iv->id].rssi[i] > rssi) - rssi = mPayload[iv->id].rssi[i]; - yield(); - } - iv->rssi = rssi; - - iv->doCalculations(); - // update status state-machine, - iv->isProducing(); - - iv->setQueuedCmdFinished(); - iv->radioStatistics.rxSuccess++; - yield(); - notify(RealTimeRunData_Debug, iv); - } - - bool build(Inverter<> *iv, bool *complete, bool *fastNext ) { - DPRINTLN(DBG_VERBOSE, F("build")); - // check if all messages are there - - *complete = mPayload[iv->id].complete; - *fastNext = false; - uint8_t txCmd = mPayload[iv->id].txCmd; - - if(!*complete) { - DPRINTLN(DBG_VERBOSE, F("incomlete, txCmd is 0x") + String(txCmd, HEX)); - //we got some delayed status msgs?!? - if ((txCmd == MI_REQ_CH1) || (txCmd == MI_REQ_CH2)) { - if (mPayload[iv->id].stsAB[CH0] && mPayload[iv->id].dataAB[CH0]) { - miComplete(iv); - return true; - } - return false; - } - if (txCmd >= MI_REQ_4CH && txCmd <= 0x39) { - return false; - } - if (txCmd == 0x0f) { //hw info request, at least hw part nr. and version have to be there... - bool gotRelevant = iv->getFwVersion() - && iv->getChannelFieldValue(CH0, FLD_PART_NUM, iv->getRecordStruct(InverterDevInform_Simple)); - if (gotRelevant) - *fastNext = true; - return gotRelevant; - } - } - - //check if we want the next request to be executed faster - if (mPayload[iv->id].gotFragment && txCmd == 0x0f) - *fastNext = true; - return true; - } - - void miHwDecode(Inverter<> *iv, packet_t *p ) { - 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_BOOTLOADER_VER, 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->isConnected = true; - if(mSerialDebug) { - DPRINT_IVID(DBG_INFO, iv->id); - DPRINT(DBG_INFO,F("HW_VER is ")); - DBGPRINTLN(String((p->packet[24] << 8) + p->packet[25])); - } - record_t<> *rec = iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure - rec->ts = mPayload[iv->id].ts; - iv->setValue(1, rec, (uint32_t) ((p->packet[24] << 8) + p->packet[25])/1); - mPayload[iv->id].multi_parts +=4; - } else if ( p->packet[9] == 0x01 || p->packet[9] == 0x10 ) {//second frame for MI, 3rd gen. answers in 0x10 - DPRINT_IVID(DBG_INFO, iv->id); - if ( p->packet[9] == 0x01 ) { - DBGPRINTLN(F("got 2nd frame (hw info)")); - /* according to xlsx (different start byte -1!) - byte[11] to byte[14] HW_PN - byte[15] byte[16] HW_FB_TLmValue - byte[17] byte[18] HW_FB_ReSPRT - byte[19] byte[20] HW_GridSamp_ResValule - byte[21] byte[22] HW_ECapValue - byte[23] to byte[26] Matching_APPFW_PN*/ - 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])); - record_t<> *rec = iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure - rec->ts = mPayload[iv->id].ts; - iv->setValue(0, rec, (uint32_t) ((((p->packet[10] << 8) | p->packet[11]) << 8 | p->packet[12]) << 8 | p->packet[13])/1); - - if(mSerialDebug) { - 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_ECapValue ")); - DBGPRINTLN(String((p->packet[20] << 8) + p->packet[21])); - DPRINT(DBG_INFO,F("Matching_APPFW_PN ")); - DBGPRINTLN(String((uint32_t) (((p->packet[22] << 8) | p->packet[23]) << 8 | p->packet[24]) << 8 | p->packet[25])); - } - //notify(InverterDevInform_Simple, iv); - mPayload[iv->id].multi_parts +=2; - notify(InverterDevInform_All, iv); - } else { - DBGPRINTLN(F("3rd gen. inverter!")); - } - - } else if ( p->packet[9] == 0x12 ) {//3rd frame - DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINTLN(F("got 3rd frame (hw info)")); - /* according to xlsx (different start byte -1!) - byte[11] byte[12] APPFW_MINVER - byte[13] byte[14] HWInfoAddr - byte[15] byte[16] PNInfoCRC_gusv - byte[15] byte[16] PNInfoCRC_gusv (this really is double mentionned in xlsx...) - */ - if(mSerialDebug) { - DPRINT(DBG_INFO,F("APPFW_MINVER ")); - DBGPRINTLN(String((p->packet[10] << 8) + p->packet[11])); - DPRINT(DBG_INFO,F("HWInfoAddr ")); - DBGPRINTLN(String((p->packet[12] << 8) + p->packet[13])); - DPRINT(DBG_INFO,F("PNInfoCRC_gusv ")); - DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15])); - } - mPayload[iv->id].multi_parts++; - } - if (mPayload[iv->id].multi_parts > 5) { - iv->setQueuedCmdFinished(); - mPayload[iv->id].complete = true; - mPayload[iv->id].rxTmo = true; - mPayload[iv->id].requested= false; - iv->radioStatistics.rxSuccess++; - } - if (mHighPrioIv == NULL) - mHighPrioIv = iv; - } - - void miGPFDecode(Inverter<> *iv, packet_t *p ) { - mPayload[iv->id].gotFragment = true; - mPayload[iv->id].gotGPF = true; - - record_t<> *rec = iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure - rec->ts = mPayload[iv->id].ts; - iv->setValue(2, rec, (uint32_t) (((p->packet[10] << 8) | p->packet[11]))); //FLD_GRID_PROFILE_CODE - iv->setValue(3, rec, (uint32_t) (((p->packet[12] << 8) | p->packet[13]))); //FLD_GRID_PROFILE_VERSION - iv->setQueuedCmdFinished(); - iv->radioStatistics.rxSuccess++; - -/* according to xlsx (different start byte -1!) - Polling Grid-connected Protection Parameter File Command - Receipt - byte[10] ST1 indicates the status of the grid-connected protection file. ST1=1 indicates the default grid-connected protection file, ST=2 indicates that the grid-connected protection file is configured and normal, ST=3 indicates that the grid-connected protection file cannot be recognized, ST=4 indicates that the grid-connected protection file is damaged - byte[11] byte[12] CountryStd variable indicates the national standard code of the grid-connected protection file - byte[13] byte[14] Version indicates the version of the grid-connected protection file - byte[15] byte[16] -*/ - if(mSerialDebug) { - DPRINT(DBG_INFO,F("ST1 ")); - DBGPRINTLN(String(p->packet[9])); - DPRINT(DBG_INFO,F("CountryStd ")); - DBGPRINTLN(String((p->packet[10] << 8) + p->packet[11])); - DPRINT(DBG_INFO,F("Version ")); - DBGPRINTLN(String((p->packet[12] << 8) + p->packet[13])); - } - if (mHighPrioIv == NULL) - mHighPrioIv = iv; - } - - void reset(uint8_t id, bool setTxTmo = true, bool clrSts = false) { - memset(mPayload[id].len, 0, MAX_PAYLOAD_ENTRIES); - mPayload[id].gotFragment = false; - mPayload[id].rxTmo = setTxTmo;// design: don't start with complete retransmit - mPayload[id].rtrRes = 0; - mPayload[id].multi_parts = 0; - 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].requested = false; - mPayload[id].ts = *mTimestamp; - if (clrSts) { // only clear channel states at startup - 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; - uint8_t mMaxRetrans; - uint32_t *mTimestamp; - miPayload_t mPayload[MAX_NUM_INVERTERS]; - bool mSerialDebug; - Inverter<> *mHighPrioIv; - - alarmListenerType mCbAlarm; - payloadListenerType mCbPayload; -}; - -#endif /*__MI_PAYLOAD_H__*/ diff --git a/src/web/RestApi.h b/src/web/RestApi.h index e53c91da..071030ba 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -680,12 +680,10 @@ class RestApi { iv->powerLimit[1] = AbsolutNonPersistent; accepted = iv->setDevControlRequest(ActivePowerContr); - } - else if(F("dev") == jsonIn[F("cmd")]) { + } else if(F("dev") == jsonIn[F("cmd")]) { DPRINTLN(DBG_INFO, F("dev cmd")); - //iv->enqueCommand(jsonIn[F("val")].as()); - } - else { + iv->setDevCommand(jsonIn[F("val")].as()); + } else { jsonOut[F("error")] = F("unknown cmd: '") + jsonIn["cmd"].as() + "'"; return false; } @@ -693,8 +691,7 @@ class RestApi { if(!accepted) { jsonOut[F("error")] = F("inverter does not accept dev control request at this moment"); return false; - } else - mApp->ivSendHighPrio(iv); + } return true; } From 179c51302b42e2985e6a36ebb1f8cf5c5a3aa750 Mon Sep 17 00:00:00 2001 From: lumapu Date: Wed, 1 Nov 2023 09:51:34 +0100 Subject: [PATCH 152/267] small Heuristic fix --- src/hm/Heuristic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index 7364f472..1675eda4 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -27,7 +27,7 @@ class Heuristic { id = i; } } - if(bestQuality > -6) + if(bestQuality == -6) iv->txRfChId = (iv->txRfChId + 1) % RF_MAX_CHANNEL_ID; // next channel else iv->txRfChId = id; // best quality channel From ac246bb7634a892e57a90cd32fa7a7475df40ce6 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 5 Nov 2023 13:58:16 +0100 Subject: [PATCH 153/267] fixed radio statistics --- src/hm/Communication.h | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index b2a82e89..baf912d2 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -56,6 +56,7 @@ class Communication : public CommQueue<> { mHeu.printStatus(q->iv); mHeu.getTxCh(q->iv); + mGotFragment = false; mState = States::START; break; @@ -87,16 +88,20 @@ class Communication : public CommQueue<> { DBGPRINT(String(millis() - mWaitTimeout + timeout)); DBGPRINTLN(F("ms")); - q->iv->radioStatistics.rxFailNoAnser++; // got nothing - mHeu.setGotNothing(q->iv); - if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { - q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, WORK_FREQ_KHZ); - mWaitTimeout = millis() + 1000; - } + if(!mGotFragment) { + q->iv->radioStatistics.rxFailNoAnser++; // got nothing + mHeu.setGotNothing(q->iv); + if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { + q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, WORK_FREQ_KHZ); + mWaitTimeout = millis() + 1000; + } + } else + q->iv->radioStatistics.rxFail++; mState = States::RESET; break; } + mGotFragment = true; States nextState = States::RESET; while(!q->iv->radio->mBufCtrl.empty()) { packet_t *p = &q->iv->radio->mBufCtrl.front(); @@ -132,6 +137,7 @@ class Communication : public CommQueue<> { parseMiFrame(p, q); } } else { + q->iv->radioStatistics.rxFail++; // got no complete payload DPRINTLN(DBG_WARN, F("Inverter serial does not match")); mWaitTimeout = millis() + timeout; } @@ -712,6 +718,7 @@ class Communication : public CommQueue<> { uint32_t *mTimestamp; uint32_t mWaitTimeout = 0; std::array mLocalBuf; + bool mGotFragment = false; uint8_t mMaxFrameId; uint8_t mPayload[MAX_BUFFER]; payloadListenerType mCbPayload = NULL; From 37d773eaa030c8860dfc9d4f6f5a75f052f9832b Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 5 Nov 2023 13:59:53 +0100 Subject: [PATCH 154/267] 0.8.1 * added tx channel heuristics (per inverter) * fix statistics counter --- src/CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 435379e9..a610cf59 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,6 +1,6 @@ # Development Changes -## 0.8.1 - 2023-10-31 +## 0.8.1 - 2023-11-05 * added tx channel heuristics (per inverter) * fix statistics counter From e582cb71d0164b71d632b5b198a20f9e24671acc Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 5 Nov 2023 14:13:39 +0100 Subject: [PATCH 155/267] 0.8.1 fix github actions --- .github/workflows/compile_development.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/compile_development.yml b/.github/workflows/compile_development.yml index 65a22730..af81492f 100644 --- a/.github/workflows/compile_development.yml +++ b/.github/workflows/compile_development.yml @@ -39,7 +39,7 @@ jobs: - name: Install PlatformIO run: | - python -m pip install --upgrade pip + python -m pip install setuptools --upgrade pip pip install --upgrade platformio - name: Run PlatformIO From e550111f9510d81004fae2edec888ca973953c92 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 5 Nov 2023 14:16:50 +0100 Subject: [PATCH 156/267] 0.8.1 fix github actions (include error) --- .github/workflows/compile_release.yml | 2 +- src/hm/Communication.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/compile_release.yml b/.github/workflows/compile_release.yml index cb4979b4..70eb5f29 100644 --- a/.github/workflows/compile_release.yml +++ b/.github/workflows/compile_release.yml @@ -43,7 +43,7 @@ jobs: - name: Install PlatformIO run: | - python -m pip install --upgrade pip + python -m pip install setuptools --upgrade pip pip install --upgrade platformio - name: Run PlatformIO diff --git a/src/hm/Communication.h b/src/hm/Communication.h index baf912d2..95f438d5 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -9,7 +9,7 @@ #include "CommQueue.h" #include #include "../utils/crc.h" -#include "heuristic.h" +#include "Heuristic.h" #define MI_TIMEOUT 250 #define DEFAULT_TIMEOUT 500 From b84391df893ea60395ab5c01d3112e8318048061 Mon Sep 17 00:00:00 2001 From: Wusaweki Date: Sun, 5 Nov 2023 16:19:13 +0100 Subject: [PATCH 157/267] fix null pointer access in display.h --- src/plugins/Display/Display.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index c4853bab..932c1a8f 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -91,12 +91,14 @@ class Display { Inverter<> *iv; record_t<> *rec; bool allOff = true; - for (uint8_t i = 0; i < mSys->getNumInverters(); i++) { + uint8_t nInv = mSys->getNumInverters(); + for (uint8_t i = 0; i < nInv; i++) { iv = mSys->getInverterByPos(i); - rec = iv->getRecordStruct(RealTimeRunData_Debug); if (iv == NULL) continue; + rec = iv->getRecordStruct(RealTimeRunData_Debug); + if (iv->isProducing()) nrprod++; else From 975f6923d304715d32fdc28ee18b6f0e9133e8d4 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 9 Nov 2023 00:08:42 +0100 Subject: [PATCH 158/267] 0.8.2 * beautified inverter settings in `setup` (preperation for future, settings become more inverter dependent) --- src/CHANGES.md | 3 + src/config/config.h | 2 +- src/defines.h | 2 +- src/hm/hmInverter.h | 3 - src/hm/hmSystem.h | 2 +- src/web/RestApi.h | 31 ++++- src/web/html/api.js | 19 ++- src/web/html/colorDark.css | 2 +- src/web/html/setup.html | 277 ++++++++++++++++++++++--------------- src/web/html/style.css | 6 +- src/web/html/system.html | 4 - src/web/web.h | 38 ----- 12 files changed, 223 insertions(+), 166 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index a610cf59..3c3c553a 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.8.2 - 2023-11-08 +* beautified inverter settings in `setup` (preperation for future, settings become more inverter dependent) + ## 0.8.1 - 2023-11-05 * added tx channel heuristics (per inverter) * fix statistics counter diff --git a/src/config/config.h b/src/config/config.h index da027fd6..f03ac702 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -158,7 +158,7 @@ #define MAX_RF_PAYLOAD_SIZE 32 // maximum total payload buffers (must be greater than the number of received frame fragments) -#define MAX_PAYLOAD_ENTRIES 10 +#define MAX_PAYLOAD_ENTRIES 20 // number of seconds since last successful response, before inverter is marked inactive #define INVERTER_INACT_THRES_SEC 5*60 diff --git a/src/defines.h b/src/defines.h index 1a865fa7..8e8b1f61 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 1 +#define VERSION_PATCH 2 //------------------------------------- typedef struct { diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 6cb2567e..023ae772 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -118,7 +118,6 @@ class Inverter { record_t recordHwInfo; // structure for simple (hardware) info values record_t recordConfig; // structure for system config values record_t recordAlarm; // structure for alarm values - bool initialized; // needed to check if the inverter was correctly added (ESP32 specific - union types are never null) bool isConnected; // shows if inverter was successfully identified (fw version and hardware info) InverterStatus status; // indicates the current inverter status std::array lastAlarm; // holds last 10 alarms @@ -142,7 +141,6 @@ class Inverter { actPowerLimit = 0xffff; // init feedback from inverter to -1 mDevControlRequest = false; devControlCmd = InitDataState; - initialized = false; alarmMesIndex = 0; isConnected = false; status = InverterStatus::OFF; @@ -193,7 +191,6 @@ class Inverter { initAssignment(&recordConfig, SystemConfigPara); initAssignment(&recordAlarm, AlarmData); toRadioId(); - initialized = true; } uint8_t getPosByChFld(uint8_t channel, uint8_t fieldId, record_t<> *rec) { diff --git a/src/hm/hmSystem.h b/src/hm/hmSystem.h index a8ca2371..de0d5911 100644 --- a/src/hm/hmSystem.h +++ b/src/hm/hmSystem.h @@ -114,7 +114,7 @@ class HmSystem { DPRINTLN(DBG_VERBOSE, F("hmSystem.h:getInverterByPos")); if(pos >= MAX_INVERTER) return NULL; - else if((mInverter[pos].initialized && mInverter[pos].config->serial.u64 != 0ULL) || false == check) + else if((mInverter[pos].config->serial.u64 != 0ULL) || (false == check)) return &mInverter[pos]; else return NULL; diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 071030ba..2267661e 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -124,7 +124,7 @@ class RestApi { void onApiPostBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) { DPRINTLN(DBG_VERBOSE, "onApiPostBody"); - DynamicJsonDocument json(200); + DynamicJsonDocument json(800); AsyncJsonResponse* response = new AsyncJsonResponse(false, 200); JsonObject root = response->getRoot(); @@ -708,8 +708,35 @@ class RestApi { mApp->setTimestamp(0); // 0: update ntp flag else if(F("serial_utc_offset") == jsonIn[F("cmd")]) mTimezoneOffset = jsonIn[F("val")]; - else if(F("discovery_cfg") == jsonIn[F("cmd")]) { + else if(F("discovery_cfg") == jsonIn[F("cmd")]) mApp->setMqttDiscoveryFlag(); // for homeassistant + else if(F("save_iv") == jsonIn[F("cmd")]) { + Inverter<> *iv = mSys->getInverterByPos(jsonIn[F("id")], false); + iv->config->enabled = jsonIn[F("en")]; + iv->config->serial.u64 = jsonIn[F("ser")]; + snprintf(iv->config->name, MAX_NAME_LENGTH, "%s", jsonIn[F("name")].as()); + + for(uint8_t i = 0; i < 6; i++) { + iv->config->chMaxPwr[i] = jsonIn[F("ch")][i][F("pwr")]; + iv->config->yieldCor[i] = jsonIn[F("ch")][i][F("yld")]; + snprintf(iv->config->chName[i], MAX_NAME_LENGTH, "%s", jsonIn[F("ch")][i][F("name")].as()); + } + + switch(iv->config->serial.b[4]) { + case 0x24: + case 0x22: + case 0x21: iv->type = INV_TYPE_1CH; iv->channels = 1; break; + + case 0x44: + case 0x42: + case 0x41: iv->type = INV_TYPE_2CH; iv->channels = 2; break; + + case 0x64: + case 0x62: + case 0x61: iv->type = INV_TYPE_4CH; iv->channels = 4; break; + default: break; + } + mApp->saveSettings(false); // without reboot } else { jsonOut[F("error")] = F("unknown cmd"); return false; diff --git a/src/web/html/api.js b/src/web/html/api.js index c9590d89..8c0ba54e 100644 --- a/src/web/html/api.js +++ b/src/web/html/api.js @@ -1,6 +1,4 @@ -/** - * SVG ICONS - */ +/* SVG ICONS - https://icons.getbootstrap.com */ iconWifi1 = [ "M11.046 10.454c.226-.226.185-.605-.1-.75A6.473 6.473 0 0 0 8 9c-1.06 0-2.062.254-2.946.704-.285.145-.326.524-.1.75l.015.015c.16.16.407.19.611.09A5.478 5.478 0 0 1 8 10c.868 0 1.69.201 2.42.56.203.1.45.07.611-.091l.015-.015zM9.06 12.44c.196-.196.198-.52-.04-.66A1.99 1.99 0 0 0 8 11.5a1.99 1.99 0 0 0-1.02.28c-.238.14-.236.464-.04.66l.706.706a.5.5 0 0 0 .707 0l.708-.707z" @@ -34,6 +32,15 @@ iconSuccessFull = [ "M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z" ]; +iconGear = [ + "M9.405 1.05c-.413-1.4-2.397-1.4-2.81 0l-.1.34a1.464 1.464 0 0 1-2.105.872l-.31-.17c-1.283-.698-2.686.705-1.987 1.987l.169.311c.446.82.023 1.841-.872 2.105l-.34.1c-1.4.413-1.4 2.397 0 2.81l.34.1a1.464 1.464 0 0 1 .872 2.105l-.17.31c-.698 1.283.705 2.686 1.987 1.987l.311-.169a1.464 1.464 0 0 1 2.105.872l.1.34c.413 1.4 2.397 1.4 2.81 0l.1-.34a1.464 1.464 0 0 1 2.105-.872l.31.17c1.283.698 2.686-.705 1.987-1.987l-.169-.311a1.464 1.464 0 0 1 .872-2.105l.34-.1c1.4-.413 1.4-2.397 0-2.81l-.34-.1a1.464 1.464 0 0 1-.872-2.105l.17-.31c.698-1.283-.705-2.686-1.987-1.987l-.311.169a1.464 1.464 0 0 1-2.105-.872l-.1-.34zM8 10.93a2.929 2.929 0 1 1 0-5.86 2.929 2.929 0 0 1 0 5.858z" +]; + +iconDel = [ + "M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z", + "M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z" +]; + /** * GENERIC FUNCTIONS */ @@ -119,7 +126,7 @@ function parseRssi(obj) { icon = iconWifi1; else if(obj["wifi_rssi"] <= -70) icon = iconWifi2; - document.getElementById("wifiicon").replaceChildren(svg(icon, 32, 32, "wifi", obj["wifi_rssi"])); + document.getElementById("wifiicon").replaceChildren(svg(icon, 32, 32, "icon-fg", obj["wifi_rssi"])); } function toIsoDateStr(d) { @@ -181,6 +188,10 @@ function tr(val1, val2) { ]); } +function badge(success, text, second="error") { + return ml("span", {class: "badge badge-" + ((success) ? "success" : second)}, text); +} + function des(val) { e = document.createElement('p'); e.classList.add("subdes"); diff --git a/src/web/html/colorDark.css b/src/web/html/colorDark.css index 3d9d167a..65100721 100644 --- a/src/web/html/colorDark.css +++ b/src/web/html/colorDark.css @@ -16,7 +16,7 @@ --secondary: #0072c8; --nav-active: #555; --footer-bg: #282828; - --modal-bg: #666; + --modal-bg: #282828; --invalid-bg: #400; diff --git a/src/web/html/setup.html b/src/web/html/setup.html index b9697141..2ec5d2b5 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -140,14 +140,7 @@
Inverter
-
-
-
-
-
-

Note

-

A 'max module power' value of '0' disables the channel in 'live' view

-
+

General

@@ -451,8 +444,6 @@ [1, "high active"], ]; - const re = /1[0,1,3][2,4,6,8][1,2,4].*/; - window.onload = function() { for(it of document.getElementsByClassName("s_collapsible")) { it.addEventListener("click", function() { @@ -471,10 +462,6 @@ }); } - document.getElementById("btnAdd").addEventListener("click", function() { - ivHtml(JSON.parse('{"enabled":true,"name":"","serial":"","channels":6,"ch_max_pwr":[0,0,0,0,0,0],"ch_name":["","","","","",""],"ch_yield_cor":[0,0,0,0,0,0]}')); - }); - function apiCbWifi(obj) { var e = document.getElementById("networks"); selDelAllOpt(e); @@ -573,98 +560,6 @@ return null; } - function ivHtml(obj) { - var id = getFreeId(); - if(null == id) { - setHide("btnAdd", true); - return; - } - - var iv = ml("div", {id: "inv" + id}, null); - document.getElementById("inverter").appendChild(iv); - iv.appendChild(des("Inverter " + id)); - id = "inv" + id; - - var addr = ml("input", {name: id + "Addr", class: "text", type: "number", max: 138999999999, value: obj["serial"]}, null); - - iv.append( - mlCb(id + "Enable", "Communication Enable", obj["enabled"]), - mlE("Serial Number (12 digits)*", addr) - ); - - ['keyup', 'change'].forEach(function(evt) { - addr.addEventListener(evt, (e) => { - var serial = addr.value.substring(0,4); - var max = 0; - for(var i=0;i<6;i++) { - setHide(id+"ModPwr"+i, true); - setHide(id+"ModName"+i, true); - setHide(id+"YieldCor"+i, true); - } - setHide("row"+id+"ModPwr", true); - setHide("row"+id+"ModName", true); - setHide("row"+id+"YieldCor", true); - - if(serial.charAt(0) == 1) { - if((serial.charAt(1) == 0) || (serial.charAt(1) == 1) || (serial.charAt(1) == 3)) { - if((serial.charAt(3) == 1) || (serial.charAt(3) == 2) || (serial.charAt(3) == 4)) { - switch(serial.charAt(2)) { - default: - case "2": max = 1; break; - case "4": max = 2; break; - case "6": max = 4; break; - case "8": max = 6; break; - } - } - } - } - - if(max != 0) { - for(var i=0;i { + var serial = ser.value.substring(0,4); + var max = 1; + for(var i = 0; i < 6; i++) { + setHide("ch"+i, true); + } + + if(serial.charAt(0) == 1) { + if((serial.charAt(1) == 0) || (serial.charAt(1) == 1) || (serial.charAt(1) == 3)) { + if((serial.charAt(3) == 1) || (serial.charAt(3) == 2) || (serial.charAt(3) == 4)) { + switch(serial.charAt(2)) { + default: + case "2": max = 1; break; + case "4": max = 2; break; + case "6": max = 4; break; + case "8": max = 6; break; + } + } + } + } + for(var i = 0; i < max; i++) { + setHide("ch"+i, false); + } + }) + }); + + modal("Edit inverter", html); + ser.dispatchEvent(new Event('change')); + + function ivSave() { + var o = new Object(); + o.cmd = "save_iv"; + o.id = obj.id; + o.ser = parseInt(document.getElementsByName("ser")[0].value, 16); + o.name = document.getElementsByName("name")[0].value; + o.en = document.getElementsByName("enable")[0].checked; + o.ch = []; + for(let i = 0; i < 6; i++) { + var q = new Object(); + q.pwr = document.getElementsByName("ch_p"+i)[0].value; + q.name = document.getElementsByName("ch_n"+i)[0].value; + q.yld = document.getElementsByName("yld_c"+i)[0].value; + o.ch.push(q); + } + getAjax("/api/setup", cb, "POST", JSON.stringify(o)); + } + + function cb(obj) { + var e = document.getElementById("res"); + if(!obj.success) + e.innerHTML = "error while saving"; + else { + modalClose(); + getAjax("/api/inverter/list", parseIv); + } + } + } + + function ivDel(obj) { + var html = ml("div", {class: "row"}, [ + ml("div", {class: "col-9"}, "do you realy want to delete inverter " + obj.name + "?"), + ml("div", {class: "col-3 a-r"}, ml("div", {class: "col-4 a-r"}, ml("input", {type: "button", value: "yes", class: "btn", onclick: function() { del(); }}, null))) + ]); + modal("Delete inverter " + obj.name, html); + + function del() { + var o = new Object(); + o.cmd = "save_iv"; + o.id = obj.id; + o.ser = 0; + o.name = ""; + o.en = false; + o.ch = []; + for(let i = 0; i < 6; i++) { + var q = new Object(); + q.pwr = 0; + q.name = ""; + q.yld = 0; + o.ch.push(q); + } + getAjax("/api/setup", cb, "POST", JSON.stringify(o)); + } + + function cb(obj) { + if(obj.success) { + modalClose(); + getAjax("/api/inverter/list", parseIv); + } + } + } + function parseMqtt(obj) { for(var i of [["Addr", "broker"], ["Port", "port"], ["ClientId", "clientId"], ["User", "user"], ["Pwd", "pwd"], ["Topic", "topic"], ["Interval", "interval"]]) document.getElementsByName("mqtt"+i[0])[0].value = obj[i[1]]; diff --git a/src/web/html/style.css b/src/web/html/style.css index 95cbff3b..8c40c780 100644 --- a/src/web/html/style.css +++ b/src/web/html/style.css @@ -94,8 +94,8 @@ svg.icon { fill: var(--success); } -.wifi { - fill: var(--fg2); +.icon-fg { + fill: var(--fg); } .title { @@ -708,7 +708,7 @@ div.hr { width: 100%; background-color: var(--modal-bg); background-clip: padding-box; - border: 1px solid rgba(0,0,0,.2); + border: 1px solid var(--fg); flex-direction: column; } diff --git a/src/web/html/system.html b/src/web/html/system.html index 27ad1801..7eddd7b0 100644 --- a/src/web/html/system.html +++ b/src/web/html/system.html @@ -40,10 +40,6 @@ ); } - function badge(success, text, second="error") { - return ml("span", {class: "badge badge-" + ((success) ? "success" : second)}, text); - } - function headline(text) { return ml("div", {class: "head p-2 mt-3"}, ml("div", {class: "row"}, ml("div", {class: "col a-c"}, text))) } diff --git a/src/web/web.h b/src/web/web.h index fabbd604..002c3cbc 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -487,44 +487,6 @@ class Web { request->arg("ipGateway").toCharArray(buf, 20); ah::ip2Arr(mConfig->sys.ip.gateway, buf); - // inverter - Inverter<> *iv; - for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { - iv = mSys->getInverterByPos(i, false); - // enable communication - iv->config->enabled = (request->arg("inv" + String(i) + "Enable") == "on"); - // address - request->arg("inv" + String(i) + "Addr").toCharArray(buf, 20); - if (strlen(buf) == 0) - memset(buf, 0, 20); - iv->config->serial.u64 = ah::Serial2u64(buf); - switch(iv->config->serial.b[4]) { - case 0x24: - case 0x22: - case 0x21: iv->type = INV_TYPE_1CH; iv->channels = 1; break; - - case 0x44: - case 0x42: - case 0x41: iv->type = INV_TYPE_2CH; iv->channels = 2; break; - - case 0x64: - case 0x62: - case 0x61: iv->type = INV_TYPE_4CH; iv->channels = 4; break; - default: break; - } - - // name - request->arg("inv" + String(i) + "Name").toCharArray(iv->config->name, MAX_NAME_LENGTH); - - // max channel power / name - for (uint8_t j = 0; j < 6; j++) { - iv->config->yieldCor[j] = request->arg("inv" + String(i) + "YieldCor" + String(j)).toDouble(); - iv->config->chMaxPwr[j] = request->arg("inv" + String(i) + "ModPwr" + String(j)).toInt() & 0xffff; - request->arg("inv" + String(i) + "ModName" + String(j)).toCharArray(iv->config->chName[j], MAX_NAME_LENGTH); - } - iv->initialized = true; - } - if (request->arg("invInterval") != "") mConfig->nrf.sendInterval = request->arg("invInterval").toInt(); mConfig->inst.rstYieldMidNight = (request->arg("invRstMid") == "on"); From 56a1f3beafba574de270ad2dc17eb48fbd86b13b Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 9 Nov 2023 22:58:48 +0100 Subject: [PATCH 159/267] 0.8.3 * fix yield day reset during day #848 * add total AC Max Power to WebUI * fix opendtufusion build (GxEPD patch) --- patches/GxEPD2_SW_SPI.patch | 11 +++++------ src/CHANGES.md | 5 +++++ src/defines.h | 2 +- src/hm/hmInverter.h | 17 +++++++++++++++-- src/platformio.ini | 4 ++-- src/web/html/visualization.html | 14 ++++++++------ 6 files changed, 36 insertions(+), 17 deletions(-) diff --git a/patches/GxEPD2_SW_SPI.patch b/patches/GxEPD2_SW_SPI.patch index 3eb6a32c..9697eec8 100644 --- a/patches/GxEPD2_SW_SPI.patch +++ b/patches/GxEPD2_SW_SPI.patch @@ -14,7 +14,7 @@ index 1588444..592869b 100644 { _initial_write = true; _initial_refresh = true; -@@ -67,27 +67,30 @@ void GxEPD2_EPD::init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset +@@ -71,27 +71,30 @@ void GxEPD2_EPD::init(uint32_t serial_diag_bitrate, bool initial, uint16_t reset { pinMode(_busy, INPUT); } @@ -58,7 +58,7 @@ index 1588444..592869b 100644 } void GxEPD2_EPD::setBusyCallback(void (*busyCallback)(const void*), const void* busy_callback_parameter) -@@ -96,12 +99,6 @@ void GxEPD2_EPD::setBusyCallback(void (*busyCallback)(const void*), const void* +@@ -100,12 +103,6 @@ void GxEPD2_EPD::setBusyCallback(void (*busyCallback)(const void*), const void* _busy_callback_parameter = busy_callback_parameter; } @@ -71,7 +71,7 @@ index 1588444..592869b 100644 void GxEPD2_EPD::_reset() { if (_rst >= 0) -@@ -168,115 +165,201 @@ void GxEPD2_EPD::_waitWhileBusy(const char* comment, uint16_t busy_time) +@@ -174,115 +169,201 @@ void GxEPD2_EPD::_waitWhileBusy(const char* comment, uint16_t busy_time) void GxEPD2_EPD::_writeCommand(uint8_t c) { @@ -334,7 +334,7 @@ index ef2318f..50aa961 100644 protected: void _reset(); void _waitWhileBusy(const char* comment = 0, uint16_t busy_time = 5000); -@@ -111,16 +115,21 @@ class GxEPD2_EPD +@@ -111,9 +115,14 @@ class GxEPD2_EPD void _startTransfer(); void _transfer(uint8_t value); void _endTransfer(); @@ -351,8 +351,7 @@ index ef2318f..50aa961 100644 bool _diag_enabled, _pulldown_rst_mode; - SPIClass* _pSPIx; SPISettings _spi_settings; - bool _initial_write, _initial_refresh; - bool _power_is_on, _using_partial_mode, _hibernating; +@@ -123,5 +124,5 @@ class GxEPD2_EPD uint16_t _reset_duration; - void (*_busy_callback)(const void*); + void (*_busy_callback)(const void*); diff --git a/src/CHANGES.md b/src/CHANGES.md index 3c3c553a..f24c77fc 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,10 @@ # Development Changes +## 0.8.3 - 2023-11-09 +* fix yield day reset during day #848 +* add total AC Max Power to WebUI +* fix opendtufusion build (GxEPD patch) + ## 0.8.2 - 2023-11-08 * beautified inverter settings in `setup` (preperation for future, settings become more inverter dependent) diff --git a/src/defines.h b/src/defines.h index 8e8b1f61..327b7f7e 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 2 +#define VERSION_PATCH 3 //------------------------------------- typedef struct { diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 023ae772..9bfe28b6 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -150,6 +150,9 @@ class Inverter { rssi = -127; memset(&radioStatistics, 0, sizeof(statistics_t)); memset(txRfQuality, -6, 5); + + memset(mOffYD, 0, sizeof(float) * 6); + memset(mLastYD, 0, sizeof(float) * 6); } void tickSend(std::function cb) { @@ -266,7 +269,12 @@ class Inverter { } else if (FLD_YT == rec->assign[pos].fieldId) { rec->record[pos] = ((REC_TYP)(val) / (REC_TYP)(div) * generalConfig->yieldEffiency) + ((REC_TYP)config->yieldCor[rec->assign[pos].ch-1]); } else if (FLD_YD == rec->assign[pos].fieldId) { - rec->record[pos] = (REC_TYP)(val) / (REC_TYP)(div) * generalConfig->yieldEffiency; + float actYD = (REC_TYP)(val) / (REC_TYP)(div) * generalConfig->yieldEffiency; + uint8_t idx = rec->assign[pos].ch - 1; + if (mLastYD[idx] > actYD) + mOffYD[idx] += mLastYD[idx]; + mLastYD[idx] = actYD; + rec->record[pos] = mOffYD[idx] + actYD; } else { if ((REC_TYP)(div) > 1) rec->record[pos] = (REC_TYP)(val) / (REC_TYP)(div); @@ -540,6 +548,9 @@ class Inverter { alarmNxtWrPos = 0; alarmCnt = 0; alarmLastId = 0; + + memset(mOffYD, 0, sizeof(float) * 6); + memset(mLastYD, 0, sizeof(float) * 6); } uint16_t parseAlarmLog(uint8_t id, uint8_t pyld[], uint8_t len) { @@ -662,7 +673,9 @@ class Inverter { radioId.b[0] = 0x01; } - bool mDevControlRequest; // true if change needed + private: + float mOffYD[6], mLastYD[6]; + bool mDevControlRequest; // true if change needed }; template diff --git a/src/platformio.ini b/src/platformio.ini index 942d2e15..d3c3c43c 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -30,7 +30,7 @@ lib_deps = https://github.com/bertmelis/espMqttClient#v1.4.5 bblanchon/ArduinoJson @ ^6.21.3 https://github.com/JChristensen/Timezone @ ^1.2.4 - olikraus/U8g2 @ ^2.34.17 + olikraus/U8g2 @ ^2.35.7 https://github.com/zinggjm/GxEPD2 @ ^1.5.2 build_flags = -std=c++17 @@ -98,7 +98,7 @@ lib_deps = https://github.com/bertmelis/espMqttClient#v1.4.4 bblanchon/ArduinoJson @ ^6.21.3 https://github.com/JChristensen/Timezone @ ^1.2.4 - olikraus/U8g2 @ ^2.34.17 + olikraus/U8g2 @ ^2.35.7 zinggjm/GxEPD2 @ ^1.5.2 build_flags = ${env.build_flags} -D ETHERNET diff --git a/src/web/html/visualization.html b/src/web/html/visualization.html index 24153389..aa05e414 100644 --- a/src/web/html/visualization.html +++ b/src/web/html/visualization.html @@ -19,7 +19,7 @@ var units, ivEn; var mIvHtml = []; var mNum = 0; - var total = Array(5).fill(0); + var total = Array(6).fill(0); var tPwrAck; function parseGeneric(obj) { @@ -61,7 +61,7 @@ } function totals() { - for(var i = 0; i < 5; i++) { + for(var i = 0; i < 6; i++) { total[i] = Math.round(total[i] * 100) / 100; } @@ -80,8 +80,9 @@ ]), ml("div", {class: "hr"}), ml("div", {class: "row"}, [ - numMid(total[3], "W", "DC Power"), - numMid(total[4], "var", "Reactive Power") + numMid(total[3], "W", "Max Power"), + numMid(total[4], "W", "DC Power"), + numMid(total[5], "var", "Reactive Power") ]) ]) ]) @@ -90,8 +91,9 @@ function ivHead(obj) { if(0 != obj.status) { // only add totals if inverter is online total[0] += obj.ch[0][2]; // P_AC - total[3] += obj.ch[0][8]; // P_DC - total[4] += obj.ch[0][10]; // Q_AC + total[3] += obj.ch[0][11]; // MAX P_AC + total[4] += obj.ch[0][8]; // P_DC + total[5] += obj.ch[0][10]; // Q_AC } total[1] += obj.ch[0][7]; // YieldDay total[2] += obj.ch[0][6]; // YieldTotal From 4e9a09f33fe1a38a36fd48ab7f6831c3a2e38314 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 9 Nov 2023 23:01:08 +0100 Subject: [PATCH 160/267] 0.8.3 * fix null ptr PR #1222 --- src/CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CHANGES.md b/src/CHANGES.md index f24c77fc..4547d6ed 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -4,6 +4,7 @@ * fix yield day reset during day #848 * add total AC Max Power to WebUI * fix opendtufusion build (GxEPD patch) +* fix null ptr PR #1222 ## 0.8.2 - 2023-11-08 * beautified inverter settings in `setup` (preperation for future, settings become more inverter dependent) From c98d35d7c4204bc0d8d1c18eb63633e47854addf Mon Sep 17 00:00:00 2001 From: lumapu Date: Fri, 10 Nov 2023 23:08:51 +0100 Subject: [PATCH 161/267] 0.8.4 * changed MqTT alarm topic, removed retained flag #1212 * reduce last_success MQTT messages (#1124) --- src/CHANGES.md | 4 ++++ src/defines.h | 2 +- src/publisher/pubMqtt.h | 26 +++++++++----------------- src/publisher/pubMqttIvData.h | 5 +---- 4 files changed, 15 insertions(+), 22 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 4547d6ed..cb9d8deb 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,9 @@ # Development Changes +## 0.8.4 - 2023-11-10 +* changed MqTT alarm topic, removed retained flag #1212 +* reduce last_success MQTT messages (#1124) + ## 0.8.3 - 2023-11-09 * fix yield day reset during day #848 * add total AC Max Power to WebUI diff --git a/src/defines.h b/src/defines.h index 327b7f7e..add9623d 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 3 +#define VERSION_PATCH 4 //------------------------------------- typedef struct { diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index a65a6b61..48dbe150 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -516,25 +516,17 @@ class PubMqtt { snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/alarm/cnt", iv->config->name); snprintf(mVal, 40, "%d", iv->alarmCnt); - publish(mSubTopic, mVal, true); + publish(mSubTopic, mVal, false); for(uint8_t j = 0; j < 10; j++) { if(0 != iv->lastAlarm[j].code) { - snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/alarm/%d/code", iv->config->name, j); - snprintf(mVal, 40, "%d", iv->lastAlarm[j].code); - publish(mSubTopic, mVal, true); - - snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/alarm/%d/str", iv->config->name, j); - snprintf(mVal, 40, "%s", iv->getAlarmStr(iv->lastAlarm[j].code).c_str()); - publish(mSubTopic, mVal, true); - - snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/alarm/%d/start", iv->config->name, j); - snprintf(mVal, 40, "%d", iv->lastAlarm[j].start + lastMidnight); - publish(mSubTopic, mVal, true); - - snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/alarm/%d/end", iv->config->name, j); - snprintf(mVal, 40, "%d", iv->lastAlarm[j].end + lastMidnight); - publish(mSubTopic, mVal, true); + snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/alarm/%d", iv->config->name, j); + snprintf(mVal, 100, "{\"code\":%d,\"str\":\"%s\",\"start\":%d,\"end\":%d}", + iv->lastAlarm[j].code, + iv->getAlarmStr(iv->lastAlarm[j].code).c_str(), + iv->lastAlarm[j].start + lastMidnight, + iv->lastAlarm[j].end + lastMidnight); + publish(mSubTopic, mVal, false); yield(); } } @@ -613,7 +605,7 @@ class PubMqtt { // global buffer for mqtt topic. Used when publishing mqtt messages. char mTopic[MQTT_TOPIC_LEN + 32 + MAX_NAME_LENGTH + 1]; char mSubTopic[32 + MAX_NAME_LENGTH + 1]; - char mVal[40]; + char mVal[100]; discovery_t mDiscovery; }; diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h index a1c03c86..053e359e 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -29,7 +29,6 @@ class PubMqttIvData { mZeroValues = false; memset(mIvLastRTRpub, 0, MAX_NUM_INVERTERS * sizeof(uint32_t)); - memset(mIvLastPublish, 0, MAX_NUM_INVERTERS * sizeof(uint32_t)); mRTRDataHasBeenSent = false; mTable[IDLE] = &PubMqttIvData::stateIdle; @@ -103,7 +102,7 @@ class PubMqttIvData { mPos = 0; if(found) { record_t<> *rec = mIv->getRecordStruct(mCmd); - if((mIv->getLastTs(rec) != mIvLastPublish[mIv->id]) && mIv->getLastTs(rec) != 0 ) { //workaround for startup. Suspect, mCmd might cause to much messages.... + if((RealTimeRunData_Debug == mCmd) && mIv->getLastTs(rec) != 0 ) { //workaround for startup. Suspect, mCmd might cause to much messages.... snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/last_success", mIv->config->name); snprintf(mVal, 40, "%d", mIv->getLastTs(rec)); mPublish(mSubTopic, mVal, true, QOS_0); @@ -134,7 +133,6 @@ class PubMqttIvData { pubData &= (lastTs != mIvLastRTRpub[mIv->id]); if (pubData) { - mIvLastPublish[mIv->id] = lastTs; if(mPos < rec->length) { bool retained = false; if (mCmd == RealTimeRunData_Debug) { @@ -241,7 +239,6 @@ class PubMqttIvData { Inverter<> *mIv, *mIvSend; uint8_t mPos; uint32_t mIvLastRTRpub[MAX_NUM_INVERTERS]; - uint32_t mIvLastPublish[MAX_NUM_INVERTERS]; bool mRTRDataHasBeenSent; char mSubTopic[32 + MAX_NAME_LENGTH + 1]; From efdac9634ff50febae4f395eeaf63311ca401875 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 11 Nov 2023 03:12:14 +0100 Subject: [PATCH 162/267] 0.8.4 * introduced tabs in WebGUI (inverter settings) * added inverter-wise power level and frequency --- src/CHANGES.md | 2 + src/app.cpp | 2 +- src/config/config.h | 3 - src/config/settings.h | 43 ++++++++++--- src/hm/Communication.h | 2 +- src/hm/hmInverter.h | 2 + src/hm/hmRadio.h | 7 +-- src/hms/cmt2300a.h | 4 ++ src/hms/hmsRadio.h | 16 ++++- src/web/RestApi.h | 12 +++- src/web/html/api.js | 42 ++++++++++--- src/web/html/setup.html | 129 ++++++++++++++++++++++++++------------- src/web/html/style.css | 51 +++++++++++++++- src/web/html/system.html | 2 - src/web/web.h | 2 - 15 files changed, 240 insertions(+), 79 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index cb9d8deb..3dc4a723 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -3,6 +3,8 @@ ## 0.8.4 - 2023-11-10 * changed MqTT alarm topic, removed retained flag #1212 * reduce last_success MQTT messages (#1124) +* introduced tabs in WebGUI (inverter settings) +* added inverter-wise power level and frequency ## 0.8.3 - 2023-11-09 * fix yield day reset during day #848 diff --git a/src/app.cpp b/src/app.cpp index afe17132..38f31e07 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -34,7 +34,7 @@ void app::setup() { DBGPRINTLN(F("false")); if(mConfig->nrf.enabled) { - mNrfRadio.setup(mConfig->nrf.amplifierPower, mConfig->nrf.pinIrq, mConfig->nrf.pinCe, mConfig->nrf.pinCs, mConfig->nrf.pinSclk, mConfig->nrf.pinMosi, mConfig->nrf.pinMiso); + mNrfRadio.setup(mConfig->nrf.pinIrq, mConfig->nrf.pinCe, mConfig->nrf.pinCs, mConfig->nrf.pinSclk, mConfig->nrf.pinMosi, mConfig->nrf.pinMiso); mNrfRadio.enableDebug(); } #if defined(ESP32) diff --git a/src/config/config.h b/src/config/config.h index f03ac702..e9d3adec 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -132,9 +132,6 @@ #define LED_HIGH_ACTIVE false #endif -// default NRF24 power, possible values (0 - 3) -#define DEF_AMPLIFIERPOWER 1 - // number of packets hold in buffer #define PACKET_BUFFER_SIZE 30 diff --git a/src/config/settings.h b/src/config/settings.h index 0771c148..d46e5687 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -30,6 +30,8 @@ * https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html#flash-layout * */ +#define CONFIG_VERSION 1 + #define PROT_MASK_INDEX 0x0001 #define PROT_MASK_LIVE 0x0002 @@ -88,7 +90,6 @@ typedef struct { uint8_t pinMiso; uint8_t pinMosi; uint8_t pinSclk; - uint8_t amplifierPower; } cfgNrf24_t; typedef struct { @@ -142,6 +143,8 @@ typedef struct { uint16_t chMaxPwr[6]; double yieldCor[6]; // YieldTotal correction value char chName[6][MAX_NAME_LENGTH]; + uint8_t frequency; + uint8_t powerLevel; } cfgIv_t; typedef struct { @@ -188,6 +191,7 @@ typedef struct { cfgInst_t inst; plugins_t plugin; bool valid; + uint16_t configVersion; } settings_t; class settings { @@ -284,6 +288,7 @@ class settings { if(root.containsKey(F("led"))) jsonLed(root[F("led")]); if(root.containsKey(F("plugin"))) jsonPlugin(root[F("plugin")]); if(root.containsKey(F("inst"))) jsonInst(root[F("inst")]); + getConfigVersion(root.as()); } else { Serial.println(F("failed to parse json, using default config")); @@ -299,6 +304,7 @@ class settings { DynamicJsonDocument json(MAX_ALLOWED_BUF_SIZE); JsonObject root = json.to(); + json[F("version")] = CONFIG_VERSION; jsonNetwork(root.createNestedObject(F("wifi")), true); jsonNrf(root.createNestedObject(F("nrf")), true); #if defined(ESP32) @@ -391,7 +397,6 @@ class settings { mCfg.nrf.pinMosi = DEF_NRF_MOSI_PIN; mCfg.nrf.pinSclk = DEF_NRF_SCLK_PIN; - mCfg.nrf.amplifierPower = DEF_AMPLIFIERPOWER & 0x03; mCfg.nrf.enabled = true; #if defined(ESP32) @@ -436,6 +441,11 @@ class settings { mCfg.inst.rstMaxValsMidNight = false; mCfg.inst.yieldEffiency = 0.955f; + for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { + mCfg.inst.iv[i].powerLevel = 0xff; // impossible high value + mCfg.inst.iv[i].frequency = 0x12; // 863MHz (minimum allowed frequency) + } + mCfg.led.led0 = DEF_LED0; mCfg.led.led1 = DEF_LED1; mCfg.led.led_high_active = LED_HIGH_ACTIVE; @@ -446,13 +456,30 @@ class settings { mCfg.plugin.display.contrast = 60; mCfg.plugin.display.pxShift = true; mCfg.plugin.display.rot = 0; - mCfg.plugin.display.disp_data = DEF_PIN_OFF; // SDA - mCfg.plugin.display.disp_clk = DEF_PIN_OFF; // SCL + mCfg.plugin.display.disp_data = DEF_PIN_OFF; // SDA + mCfg.plugin.display.disp_clk = DEF_PIN_OFF; // SCL mCfg.plugin.display.disp_cs = DEF_PIN_OFF; mCfg.plugin.display.disp_reset = DEF_PIN_OFF; mCfg.plugin.display.disp_busy = DEF_PIN_OFF; mCfg.plugin.display.disp_dc = DEF_PIN_OFF; - } + } + + void loadAddedDefaults() { + if(0 == mCfg.configVersion) { + for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { + mCfg.inst.iv[i].powerLevel = 0xff; // impossible high value + mCfg.inst.iv[i].frequency = 0x12; // 863MHz (minimum allowed frequency) + } + } + } + + void getConfigVersion(JsonObject obj) { + getVal(obj, F("version"), &mCfg.configVersion); + DPRINT(DBG_INFO, F("Config Version: ")); + DBGPRINTLN(String(mCfg.configVersion)); + if(CONFIG_VERSION != mCfg.configVersion) + loadAddedDefaults(); + } void jsonNetwork(JsonObject obj, bool set = false) { if(set) { @@ -506,7 +533,6 @@ class settings { obj[F("sclk")] = mCfg.nrf.pinSclk; obj[F("mosi")] = mCfg.nrf.pinMosi; obj[F("miso")] = mCfg.nrf.pinMiso; - obj[F("pwr")] = mCfg.nrf.amplifierPower; obj[F("en")] = (bool) mCfg.nrf.enabled; } else { getVal(obj, F("intvl"), &mCfg.nrf.sendInterval); @@ -516,7 +542,6 @@ class settings { getVal(obj, F("sclk"), &mCfg.nrf.pinSclk); getVal(obj, F("mosi"), &mCfg.nrf.pinMosi); getVal(obj, F("miso"), &mCfg.nrf.pinMiso); - getVal(obj, F("pwr"), &mCfg.nrf.amplifierPower); #if !defined(ESP32) mCfg.nrf.enabled = true; // ESP8266, read always as enabled #else @@ -707,6 +732,8 @@ class settings { obj[F("en")] = (bool)cfg->enabled; obj[F("name")] = cfg->name; obj[F("sn")] = cfg->serial.u64; + obj[F("freq")] = cfg->frequency; + obj[F("pa")] = cfg->powerLevel; for(uint8_t i = 0; i < 6; i++) { obj[F("yield")][i] = cfg->yieldCor[i]; obj[F("pwr")][i] = cfg->chMaxPwr[i]; @@ -716,6 +743,8 @@ class settings { getVal(obj, F("en"), &cfg->enabled); getChar(obj, F("name"), cfg->name, MAX_NAME_LENGTH); getVal(obj, F("sn"), &cfg->serial.u64); + getVal(obj, F("freq"), &cfg->frequency); + getVal(obj, F("pa"), &cfg->powerLevel); uint8_t size = 4; if(obj.containsKey(F("pwr"))) size = obj[F("pwr")].size(); diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 95f438d5..2675d1a2 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -92,7 +92,7 @@ class Communication : public CommQueue<> { q->iv->radioStatistics.rxFailNoAnser++; // got nothing mHeu.setGotNothing(q->iv); if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { - q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, WORK_FREQ_KHZ); + q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, (q->iv->config->frequency*FREQ_STEP_KHZ + HOY_BASE_FREQ_KHZ)); mWaitTimeout = millis() + 1000; } } else diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 9bfe28b6..52b7c5dd 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -129,6 +129,7 @@ class Inverter { statistics_t radioStatistics; // information about transmitted, failed, ... packets int8_t txRfQuality[5]; // heuristics tx quality (check 'Heuristics.h') uint8_t txRfChId; // RF TX channel id + uint8_t curCmtFreq; // current used CMT frequency, used to check if freq. was changed during runtime static uint32_t *timestamp; // system timestamp static cfgInst_t *generalConfig; // general inverter configuration from setup @@ -194,6 +195,7 @@ class Inverter { initAssignment(&recordConfig, SystemConfigPara); initAssignment(&recordAlarm, AlarmData); toRadioId(); + curCmtFreq = this->config->frequency; // update to frequency read from settings } uint8_t getPosByChFld(uint8_t channel, uint8_t fieldId, record_t<> *rec) { diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 203f39aa..a55c7d3c 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -45,7 +45,7 @@ class HmRadio : public Radio { } ~HmRadio() {} - void setup(uint8_t ampPwr = RF24_PA_LOW, uint8_t irq = IRQ_PIN, uint8_t ce = CE_PIN, uint8_t cs = CS_PIN, uint8_t sclk = SCLK_PIN, uint8_t mosi = MOSI_PIN, uint8_t miso = MISO_PIN) { + void setup(uint8_t irq = IRQ_PIN, uint8_t ce = CE_PIN, uint8_t cs = CS_PIN, uint8_t sclk = SCLK_PIN, uint8_t mosi = MOSI_PIN, uint8_t miso = MISO_PIN) { DPRINTLN(DBG_VERBOSE, F("hmRadio.h:setup")); pinMode(irq, INPUT_PULLUP); @@ -81,9 +81,7 @@ class HmRadio : public Radio { // 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); + mNrf24.setPALevel(1); // low is default if(mNrf24.isChipConnected()) { DPRINTLN(DBG_INFO, F("Radio Config:")); @@ -269,6 +267,7 @@ class HmRadio : public Radio { } void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) { + mNrf24.setPALevel(iv->config->powerLevel & 0x03); updateCrcs(&len, appendCrc16); // set TX and RX channels diff --git a/src/hms/cmt2300a.h b/src/hms/cmt2300a.h index ab54617d..75d2ce5c 100644 --- a/src/hms/cmt2300a.h +++ b/src/hms/cmt2300a.h @@ -422,6 +422,10 @@ class Cmt2300a { return HOY_BASE_FREQ_KHZ + (mCurCh * FREQ_STEP_KHZ); } + uint8_t getCurrentChannel(void) { + return mCurCh; + } + void setPaLevel(int8_t level) { if(level < -10) level = -10; diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index 097a3f03..811c60d2 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -66,6 +66,11 @@ class CmtRadio : public Radio { uint8_t fromCh = mCmt.freq2Chan(fromkHz); uint8_t toCh = mCmt.freq2Chan(tokHz); + return switchFrequencyCh(iv, fromCh, toCh); + } + + private: + bool switchFrequencyCh(Inverter<> *iv, uint8_t fromCh, uint8_t toCh) { if((0xff == fromCh) || (0xff == toCh)) return false; @@ -75,8 +80,17 @@ class CmtRadio : public Radio { return true; } - private: void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) { + // frequency was changed during runtime + if(iv->curCmtFreq != iv->config->frequency) { + if(switchFrequencyCh(iv, iv->curCmtFreq, iv->config->frequency)) + iv->curCmtFreq = iv->config->frequency; + } else { + // inverters have maybe different settings regarding frequency + if(mCmt.getCurrentChannel() != iv->config->frequency) + mCmt.switchChannel(iv->config->frequency); + } + updateCrcs(&len, appendCrc16); if(mSerialDebug) { diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 2267661e..6e977309 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -346,7 +346,14 @@ class RestApi { obj2[F("name")] = String(iv->config->name); obj2[F("serial")] = String(iv->config->serial.u64, HEX); obj2[F("channels")] = iv->channels; - obj2[F("version")] = String(iv->getFwVersion()); + obj2[F("freq")] = iv->config->frequency; + if(0xff == iv->config->powerLevel) { + if((IV_HMT == iv->ivGen) || (IV_HMS == iv->ivGen)) + obj2[F("pa")] = 30; // 20dBm + else + obj2[F("pa")] = 1; // low + } else + obj2[F("pa")] = iv->config->powerLevel; for(uint8_t j = 0; j < iv->channels; j ++) { obj2[F("ch_yield_cor")][j] = (double)iv->config->yieldCor[j]; @@ -529,7 +536,6 @@ class RestApi { void getRadioNrf(JsonObject obj) { obj[F("en")] = (bool) mConfig->nrf.enabled; obj[F("isconnected")] = mRadioNrf->isChipConnected(); - obj[F("power_level")] = mConfig->nrf.amplifierPower; obj[F("dataRate")] = mRadioNrf->getDataRate(); //obj[F("isPVariant")] = mRadioNrf->isPVariant(); } @@ -736,6 +742,8 @@ class RestApi { case 0x61: iv->type = INV_TYPE_4CH; iv->channels = 4; break; default: break; } + iv->config->frequency = jsonIn[F("freq")]; + iv->config->powerLevel = jsonIn[F("pa")]; mApp->saveSettings(false); // without reboot } else { jsonOut[F("error")] = F("unknown cmd"); diff --git a/src/web/html/api.js b/src/web/html/api.js index 8c0ba54e..11db6c45 100644 --- a/src/web/html/api.js +++ b/src/web/html/api.js @@ -192,6 +192,34 @@ function badge(success, text, second="error") { return ml("span", {class: "badge badge-" + ((success) ? "success" : second)}, text); } +function tabChange(id) { + var els = document.getElementsByClassName("nav-link"); + [].forEach.call(els, function(e) { + if(e.id != id) + e.classList.remove('active'); + else + e.classList.add('active'); + }); + + els = document.getElementsByClassName("tab-content"); + [].forEach.call(els, function(e) { + if(e.id == ("div"+id.substring(3))) + e.classList.remove('hide'); + else + e.classList.add('hide'); + }); +} + +function tabs(items) { + var li = []; + var cl = " active"; + for(it of items) { + li.push(ml("li", {class: "nav-item"},ml("a", {id: "tab"+it, class: "nav-link" + cl, href: "#", onclick: function(){tabChange(this.id)}}, it))) + cl = ""; + } + return ml("ul", {class: "nav nav-tabs mb-4"}, li); +} + function des(val) { e = document.createElement('p'); e.classList.add("subdes"); @@ -223,13 +251,11 @@ function inp(name, val, max=32, cl=["text"], id=null, type=null, pattern=null, t } function sel(name, options, selId) { - e = document.createElement('select'); - e.name = name; + var o = []; for(it of options) { - o = opt(it[0], it[1], (it[0] == selId)); - e.appendChild(o); + o.push(opt(it[0], it[1], (it[0] == selId))); } - return e; + return ml("select", {name: name}, o); } function selDelAllOpt(sel) { @@ -240,9 +266,7 @@ function selDelAllOpt(sel) { } function opt(val, html, sel=false) { - o = document.createElement('option'); - o.value = val; - o.innerHTML = html; + var o = ml("option", {value: val}, html); if(sel) o.selected = true; return o; @@ -301,7 +325,7 @@ function svg(data=null, w=24, h=24, cl=null, tooltip=null) { function modal(title, body) { if(null == document.getElementById("modal")) { document.getElementById("wrapper").append( - ml("div", {id: "modal-wrapper", class: "modal", onclick: modalClose}), + ml("div", {id: "modal-wrapper", onclick: modalClose}), ml("div", {id: "modal", class: "modal"}, ml("div", {class: "modal-content"}, [ ml("div", {class: "modal-header"}, [ diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 2ec5d2b5..1ca46ced 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -438,6 +438,23 @@ [47, "GPIO47"], [48, "GPIO48"], ]; + var nrfPa = [ + [0, "MIN (recommended)"], + [1, "LOW"], + [2, "HIGH"], + [3, "MAX (experimental)"] + ]; + var esp32cmtPa = []; + var esp32cmtFreq = []; + var freqFmt = new Intl.NumberFormat('en-US', { + minimumIntegerDigits: 3, + minimumFractionDigits: 2 + }); + for(var i = 0; i < 31; i++) { + esp32cmtPa.push([i, String(i-10) + " dBm"]); + if(i < 29) + esp32cmtFreq.push([i, freqFmt.format(860 + i*0.25) + " MHz"]); + } /*ENDIF_ESP32*/ var led_high_active = [ [0, "low active"], @@ -647,6 +664,7 @@ ml("th", {}, "Name (optional)"), ml("th", {}, "Yield Correction [kWh] (optional)") ])); + for(let i = 0; i < 6; i++) { lines.push(ml("tr", {id: "ch"+i}, [ ml("td", {}, String(i+1)), @@ -655,29 +673,54 @@ ml("td", {}, ml("input", {name: "yld_c"+i, class: "text", type: "number", max: 999999, value: obj.ch_yield_cor[i]}, null)) ])); } + var cbEn = ml("input", {name: "enable", type: "checkbox"}, null); if(obj.enabled) cbEn.checked = true; var ser = ml("input", {name: "ser", class: "text", type: "number", max: 138999999999, value: obj.serial}, null); var html = ml("div", {}, [ - ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-4"}, "Serial"), - ml("div", {class: "col-8"}, ser) + tabs(["General", "Inputs", "Radio"]), + ml("div", {id: "divGeneral", class: "tab-content"}, [ + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-4"}, "Enable"), + ml("div", {class: "col-8"}, cbEn) + ]), + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-4 mt-2"}, "Serial"), + ml("div", {class: "col-8"}, ser) + ]), + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-4 mt-2"}, "Name"), + ml("div", {class: "col-8"}, ml("input", {name: "name", class: "text", type: "text", value: obj.name}, null)) + ]) ]), - ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-4"}, "Name"), - ml("div", {class: "col-8"}, ml("input", {name: "name", class: "text", type: "text", value: obj.name}, null)) + ml("div", {id: "divInputs", class: "tab-content hide"}, [ + ml("div", {class: "row mb-3"}, + ml("table", {class: "table"}, + ml("tbody", {}, lines) + ) + ) ]), - ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-4"}, "Enable"), - ml("div", {class: "col-8"}, cbEn) + ml("div", {id: "divRadio", class: "tab-content hide"}, [ + ml("input", {type: "hidden", name: "isnrf"}, null), + ml("div", {id: "setcmt"}, [ + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-4 mt-2"}, "Frequency"), + ml("div", {class: "col-8"}, sel("freq", esp32cmtFreq, obj.freq)) + ]), + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-4 mt-2"}, "Power Level"), + ml("div", {class: "col-8"}, sel("cmtpa", esp32cmtPa, obj.pa)) + ]), + ]), + ml("div", {id: "setnrf"}, + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-4 mt-2"}, "Power Level"), + ml("div", {class: "col-8"}, sel("nrfpa", nrfPa, obj.pa)) + ]), + ), ]), - ml("div", {class: "row mb-3"}, - ml("table", {class: "table"}, - ml("tbody", {}, lines) - ) - ), - ml("div", {class: "row mb-3"}, [ + ml("div", {class: "row mt-5"}, [ ml("div", {class: "col-8", id: "res"}, ""), ml("div", {class: "col-4 a-r"}, ml("input", {type: "button", value: "save", class: "btn", onclick: function() { ivSave(); }}, null)) ]) @@ -685,28 +728,34 @@ ['keyup', 'change'].forEach(function(evt) { ser.addEventListener(evt, (e) => { - var serial = ser.value.substring(0,4); + var sn = parseInt(ser.value, 16); + sn = Math.floor(sn / Math.pow(2, 32)); + var max = 1; + switch(sn & 0x00f0) { + case 0x0010: max = 1; break; + case 0x0040: max = 2; break; + case 0x0060: max = 4; break; + case 0x0080: max = 6; break; + } for(var i = 0; i < 6; i++) { - setHide("ch"+i, true); + setHide("ch"+i, (i >= max)); } - if(serial.charAt(0) == 1) { - if((serial.charAt(1) == 0) || (serial.charAt(1) == 1) || (serial.charAt(1) == 3)) { - if((serial.charAt(3) == 1) || (serial.charAt(3) == 2) || (serial.charAt(3) == 4)) { - switch(serial.charAt(2)) { - default: - case "2": max = 1; break; - case "4": max = 2; break; - case "6": max = 4; break; - case "8": max = 6; break; - } + var nrf = true; + switch(sn & 0xff00) { + case 0x1000: nrf = true; break; + case 0x1100: + switch(sn & 0x000f) { + case 0x0004: nrf = false; break; + default: nrf = true; break; } - } - } - for(var i = 0; i < max; i++) { - setHide("ch"+i, false); + break; + case 0x1300: nrf = false; break; } + setHide("setcmt", nrf); + setHide("setnrf", !nrf); + document.getElementsByName("isnrf")[0].value = nrf; }) }); @@ -728,6 +777,11 @@ q.yld = document.getElementsByName("yld_c"+i)[0].value; o.ch.push(q); } + if("true" == document.getElementsByName("isnrf")[0].value) + o.pa = document.getElementsByName("nrfpa")[0].value; + else + o.pa = document.getElementsByName("cmtpa")[0].value; + o.freq = document.getElementsByName("freq")[0].value; getAjax("/api/setup", cb, "POST", JSON.stringify(o)); } @@ -845,19 +899,6 @@ ]) ); } - e.append( - ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-12 col-sm-3 my-2"}, "Power Level"), - ml("div", {class: "col-12 col-sm-9"}, - sel("rf24Power", [ - [0, "MIN (recommended)"], - [1, "LOW"], - [2, "HIGH"], - [3, "MAX (experimental)"] - ], obj["power_level"]) - ) - ]) - ); } /*IF_ESP32*/ diff --git a/src/web/html/style.css b/src/web/html/style.css index 8c40c780..064819f5 100644 --- a/src/web/html/style.css +++ b/src/web/html/style.css @@ -686,7 +686,7 @@ div.hr { margin: 1.75rem auto; } -.modal { +.modal, #modal-wrapper { position: fixed; top: 0; right: 0; @@ -695,6 +695,10 @@ div.hr { display: block; } +.modal { + height: calc(100% - 3.5rem); +} + #modal-wrapper { background-color: #000; opacity: 0.5; @@ -710,6 +714,8 @@ div.hr { background-clip: padding-box; border: 1px solid var(--fg); flex-direction: column; + max-height: 100%; + overflow: hidden; } .modal-header { @@ -717,7 +723,7 @@ div.hr { align-items: flex-start; justify-content: space-between; padding: 1rem; - border-bottom: 1px solid #e9ecef; + border-bottom: 1px solid var(--table-border); } .modal-header .close { @@ -726,7 +732,8 @@ div.hr { } .modal-body { - padding: 1rem 1rem 2rem 1rem; + padding: 1rem; + overflow-y: auto; } .close { @@ -779,3 +786,41 @@ h5 { vertical-align: baseline; border-radius: .25rem; } + +ul { + margin-top: 0; +} + +.nav { + display: flex; + flex-wrap: wrap; + padding-left: 0; + list-style: none; +} + +.nav-tabs { + border-bottom: 1px solid var(--fg); +} + +.nav-tabs .nav-link { + margin-bottom: -1px; + border: 1px solid transparent; + border-top-left-radius: .25rem; + border-top-right-radius: .25rem; +} + +.nav-link { + display: block; + padding: .5rem 1rem; + text-decoration: none; + color: var(--fg); +} + +.nav-tabs .nav-link.active { + border-color: var(--fg) var(--fg) var(--bg); +} + +.nav-link:hover, .nav-link:visited { + background-color: var(--input-bg); + color: var(--fg); +} diff --git a/src/web/html/system.html b/src/web/html/system.html index 7eddd7b0..a310890d 100644 --- a/src/web/html/system.html +++ b/src/web/html/system.html @@ -45,13 +45,11 @@ } function parseRadio(obj) { - const pa = ["MIN (recommended)", "LOW", "HIGH", "MAX"]; const dr = ["1 M", "2 M", "250 k"] if(obj.radioNrf.en) { lines = [ tr("NRF24L01", badge(obj.radioNrf.isconnected, ((obj.radioNrf.isconnected) ? "" : "not ") + "connected")), - tr("NRF24 Power Level", pa[obj.radioNrf.power_level]), tr("NRF24 Data Rate", dr[obj.radioNrf.dataRate] + "bps") ]; } else diff --git a/src/web/web.h b/src/web/web.h index 002c3cbc..c37db811 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -519,8 +519,6 @@ class Web { } } - // nrf24 amplifier power - mConfig->nrf.amplifierPower = request->arg("rf24Power").toInt() & 0x03; mConfig->nrf.enabled = (request->arg("nrfEnable") == "on"); // cmt From 8ac895f50a372fbe3ad861725bd5ad7e8d08b20d Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 12 Nov 2023 12:02:11 +0100 Subject: [PATCH 163/267] 0.8.5 * fixed endless loop while switching CMT frequency * removed obsolete "retries" field from settings #1224 * fixed crash while defining new invertes #1224 * fixed default frequency settings * added default input power to `400` while adding new inverters * fixed color of wifi RSSI icon #1224 --- src/CHANGES.md | 8 ++++++++ src/app.cpp | 10 +--------- src/app.h | 11 +++++++++++ src/appInterface.h | 1 + src/config/settings.h | 4 ++-- src/defines.h | 2 +- src/hm/Communication.h | 10 ++++++++++ src/hm/hmInverter.h | 1 + src/hm/hmSystem.h | 13 +++---------- src/hm/radio.h | 1 + src/hms/hmsRadio.h | 15 +++++---------- src/web/RestApi.h | 15 +-------------- src/web/html/api.js | 2 +- src/web/html/setup.html | 13 ++++++------- src/web/html/style.css | 7 ++++++- 15 files changed, 58 insertions(+), 55 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 3dc4a723..6c4f0a6d 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,13 @@ # Development Changes +## 0.8.5 - 2023-11-12 +* fixed endless loop while switching CMT frequency +* removed obsolete "retries" field from settings #1224 +* fixed crash while defining new invertes #1224 +* fixed default frequency settings +* added default input power to `400` while adding new inverters +* fixed color of wifi RSSI icon #1224 + ## 0.8.4 - 2023-11-10 * changed MqTT alarm topic, removed retained flag #1212 * reduce last_success MQTT messages (#1124) diff --git a/src/app.cpp b/src/app.cpp index 38f31e07..838c375f 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -63,15 +63,7 @@ void app::setup() { mCommunication.addPayloadListener(std::bind(&app::payloadEventListener, this, std::placeholders::_1, std::placeholders::_2)); mSys.setup(&mTimestamp, &mConfig->inst); for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { - mSys.addInverter(i, [this](Inverter<> *iv) { - // will be only called for valid inverters - if((IV_MI == iv->ivGen) || (IV_HM == iv->ivGen)) - iv->radio = &mNrfRadio; - #if defined(ESP32) - else if((IV_HMS == iv->ivGen) || (IV_HMT == iv->ivGen)) - iv->radio = &mCmtRadio; - #endif - }); + initInverter(i); } if(mConfig->nrf.enabled) { diff --git a/src/app.h b/src/app.h index c257d83d..0bb1c170 100644 --- a/src/app.h +++ b/src/app.h @@ -104,6 +104,17 @@ class app : public IApp, public ah::Scheduler { return true; } + void initInverter(uint8_t id) { + mSys.addInverter(id, [this](Inverter<> *iv) { + if((IV_MI == iv->ivGen) || (IV_HM == iv->ivGen)) + iv->radio = &mNrfRadio; + #if defined(ESP32) + else if((IV_HMS == iv->ivGen) || (IV_HMT == iv->ivGen)) + iv->radio = &mCmtRadio; + #endif + }); + } + bool readSettings(const char *path) { return mSettings.readSettings(path); } diff --git a/src/appInterface.h b/src/appInterface.h index 4bfc3b0c..802f21e6 100644 --- a/src/appInterface.h +++ b/src/appInterface.h @@ -25,6 +25,7 @@ class IApp { public: virtual ~IApp() {} virtual bool saveSettings(bool stopFs) = 0; + virtual void initInverter(uint8_t id) = 0; virtual bool readSettings(const char *path) = 0; virtual bool eraseSettings(bool eraseWifi) = 0; virtual bool getSavePending() = 0; diff --git a/src/config/settings.h b/src/config/settings.h index d46e5687..27aaf953 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -465,10 +465,10 @@ class settings { } void loadAddedDefaults() { - if(0 == mCfg.configVersion) { + if(0 < mCfg.configVersion) { for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { mCfg.inst.iv[i].powerLevel = 0xff; // impossible high value - mCfg.inst.iv[i].frequency = 0x12; // 863MHz (minimum allowed frequency) + mCfg.inst.iv[i].frequency = 0x0; // 860MHz (backward compatibility) } } } diff --git a/src/defines.h b/src/defines.h index add9623d..eeee3574 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 4 +#define VERSION_PATCH 5 //------------------------------------- typedef struct { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 2675d1a2..ea760200 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -57,11 +57,21 @@ class Communication : public CommQueue<> { mHeu.printStatus(q->iv); mHeu.getTxCh(q->iv); mGotFragment = false; + if(NULL == q->iv->radio) + cmdDone(true); // can't communicate while radio is not defined! mState = States::START; break; case States::START: setTs(mTimestamp); + if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { + // frequency was changed during runtime + if(q->iv->curCmtFreq != q->iv->config->frequency) { + if(q->iv->radio->switchFrequencyCh(q->iv, q->iv->curCmtFreq, q->iv->config->frequency)) + q->iv->curCmtFreq = q->iv->config->frequency; + } + } + if(q->isDevControl) { if(ActivePowerContr == q->cmd) q->iv->powerLimitAck = false; diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 52b7c5dd..f52bafe9 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -149,6 +149,7 @@ class Inverter { alarmCnt = 0; alarmLastId = 0; rssi = -127; + radio = NULL; memset(&radioStatistics, 0, sizeof(statistics_t)); memset(txRfQuality, -6, 5); diff --git a/src/hm/hmSystem.h b/src/hm/hmSystem.h index de0d5911..b86f8d08 100644 --- a/src/hm/hmSystem.h +++ b/src/hm/hmSystem.h @@ -17,17 +17,12 @@ class HmSystem { void setup(uint32_t *timestamp, cfgInst_t *config) { mInverter[0].timestamp = timestamp; mInverter[0].generalConfig = config; - mNumInv = 0; } void addInverter(uint8_t id, std::function *iv)> cb) { DPRINTLN(DBG_VERBOSE, F("hmSystem.h:addInverter")); - if(MAX_INVERTER <= mNumInv) { - DPRINT(DBG_WARN, F("max number of inverters reached!")); - return; - } - INVERTERTYPE *iv = &mInverter[mNumInv]; - iv->id = mNumInv; + INVERTERTYPE *iv = &mInverter[id]; + iv->id = id; iv->config = &mInverter[0].generalConfig->iv[id]; DPRINT(DBG_VERBOSE, "SERIAL: " + String(iv->config->serial.b[5], HEX)); DPRINTLN(DBG_VERBOSE, " " + String(iv->config->serial.b[4], HEX)); @@ -73,7 +68,6 @@ class HmSystem { iv->ivGen = IV_UNKNOWN; iv->init(); - mNumInv ++; if(IV_UNKNOWN == iv->ivGen) return; // serial is 0 @@ -99,7 +93,7 @@ class HmSystem { INVERTERTYPE *findInverter(uint8_t buf[]) { DPRINTLN(DBG_VERBOSE, F("hmSystem.h:findInverter")); INVERTERTYPE *p; - for(uint8_t i = 0; i < mNumInv; i++) { + for(uint8_t i = 0; i < MAX_INVERTER; i++) { p = &mInverter[i]; if((p->config->serial.b[3] == buf[0]) && (p->config->serial.b[2] == buf[1]) @@ -134,7 +128,6 @@ class HmSystem { private: INVERTERTYPE mInverter[MAX_INVERTER]; - uint8_t mNumInv; }; #endif /*__HM_SYSTEM_H__*/ diff --git a/src/hm/radio.h b/src/hm/radio.h index 79239022..07317e8c 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -23,6 +23,7 @@ class Radio { public: virtual void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit) = 0; virtual bool switchFrequency(Inverter<> *iv, uint32_t fromkHz, uint32_t tokHz) { return true; } + virtual bool switchFrequencyCh(Inverter<> *iv, uint8_t fromCh, uint8_t toCh) { return true; } virtual void loop(void) {}; bool get() { diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index 811c60d2..bcb08c3f 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -69,7 +69,6 @@ class CmtRadio : public Radio { return switchFrequencyCh(iv, fromCh, toCh); } - private: bool switchFrequencyCh(Inverter<> *iv, uint8_t fromCh, uint8_t toCh) { if((0xff == fromCh) || (0xff == toCh)) return false; @@ -80,16 +79,12 @@ class CmtRadio : public Radio { return true; } + private: + void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) { - // frequency was changed during runtime - if(iv->curCmtFreq != iv->config->frequency) { - if(switchFrequencyCh(iv, iv->curCmtFreq, iv->config->frequency)) - iv->curCmtFreq = iv->config->frequency; - } else { - // inverters have maybe different settings regarding frequency - if(mCmt.getCurrentChannel() != iv->config->frequency) - mCmt.switchChannel(iv->config->frequency); - } + // inverters have maybe different settings regarding frequency + if(mCmt.getCurrentChannel() != iv->config->frequency) + mCmt.switchChannel(iv->config->frequency); updateCrcs(&len, appendCrc16); diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 6e977309..53adb23f 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -728,20 +728,7 @@ class RestApi { snprintf(iv->config->chName[i], MAX_NAME_LENGTH, "%s", jsonIn[F("ch")][i][F("name")].as()); } - switch(iv->config->serial.b[4]) { - case 0x24: - case 0x22: - case 0x21: iv->type = INV_TYPE_1CH; iv->channels = 1; break; - - case 0x44: - case 0x42: - case 0x41: iv->type = INV_TYPE_2CH; iv->channels = 2; break; - - case 0x64: - case 0x62: - case 0x61: iv->type = INV_TYPE_4CH; iv->channels = 4; break; - default: break; - } + mApp->initInverter(jsonIn[F("id")]); iv->config->frequency = jsonIn[F("freq")]; iv->config->powerLevel = jsonIn[F("pa")]; mApp->saveSettings(false); // without reboot diff --git a/src/web/html/api.js b/src/web/html/api.js index 11db6c45..2eea8d94 100644 --- a/src/web/html/api.js +++ b/src/web/html/api.js @@ -126,7 +126,7 @@ function parseRssi(obj) { icon = iconWifi1; else if(obj["wifi_rssi"] <= -70) icon = iconWifi2; - document.getElementById("wifiicon").replaceChildren(svg(icon, 32, 32, "icon-fg", obj["wifi_rssi"])); + document.getElementById("wifiicon").replaceChildren(svg(icon, 32, 32, "icon-fg2", obj["wifi_rssi"])); } function toIsoDateStr(d) { diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 1ca46ced..a21aa073 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -149,10 +149,6 @@
Interval [s]
-
-
Max retries per Payload
-
-
Reset values and YieldDay at midnight
@@ -578,7 +574,7 @@ } function ivGlob(obj) { - for(var i of [["invInterval", "interval"], ["invRetry", "retries"], ["yldEff", "yldEff"]]) + for(var i of [["invInterval", "interval"], ["yldEff", "yldEff"]]) document.getElementsByName(i[0])[0].value = obj[i[1]]; for(var i of ["Mid", "ComStop", "NotAvail", "MaxMid"]) document.getElementsByName("invRst"+i)[0].checked = obj["rst" + i]; @@ -644,14 +640,17 @@ add.id = obj.inverter.length; add.name = ""; add.enabled = true; - add.ch_max_pwr = []; + add.ch_max_pwr = [400,400,400,400,400,400]; add.ch_name = []; add.ch_yield_cor = []; + add.freq = 12; + add.pa = 30; var e = document.getElementById("inverter"); e.innerHTML = ""; // remove all childs e.append(ml("table", {class: "table"}, ml("tbody", {}, lines))); - e.append(ml("div", {class: "row my-3"}, ml("div", {class: "col a-r"}, ml("input", {type: "button", value: "add Inverter", class: "btn", onclick: function() { ivModal(add); }}, null)))); + if(obj.max_num_inverters > obj.inverter.length) + e.append(ml("div", {class: "row my-3"}, ml("div", {class: "col a-r"}, ml("input", {type: "button", value: "add Inverter", class: "btn", onclick: function() { ivModal(add); }}, null)))); ivGlob(obj); } diff --git a/src/web/html/style.css b/src/web/html/style.css index 064819f5..b31ae7c9 100644 --- a/src/web/html/style.css +++ b/src/web/html/style.css @@ -98,6 +98,10 @@ svg.icon { fill: var(--fg); } +.icon-fg2 { + fill: var(--fg2); +} + .title { background-color: var(--primary); color: #fff !important; @@ -817,7 +821,8 @@ ul { } .nav-tabs .nav-link.active { - border-color: var(--fg) var(--fg) var(--bg); + border-color: var(--primary) var(--fg) var(--bg); + border-top-width: 4px; } .nav-link:hover, .nav-link:visited { From e8dbe02e4f3672b20d53177c9bf423de4b92b6c6 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 12 Nov 2023 12:05:58 +0100 Subject: [PATCH 164/267] merged --- src/hm/Communication.h | 16 +++++++++++++++- src/hm/Heuristic.h | 4 ++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index ea760200..fb1709c5 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -57,6 +57,7 @@ class Communication : public CommQueue<> { mHeu.printStatus(q->iv); mHeu.getTxCh(q->iv); mGotFragment = false; + mFirstTry = mFirstTry ? false : ( (IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen) ) && (q->iv->isAvailable()); //) || (millis() < 120000));} if(NULL == q->iv->radio) cmdDone(true); // can't communicate while radio is not defined! mState = States::START; @@ -98,7 +99,7 @@ class Communication : public CommQueue<> { DBGPRINT(String(millis() - mWaitTimeout + timeout)); DBGPRINTLN(F("ms")); - if(!mGotFragment) { + if(!mGotFragment && !mFirstTry) { q->iv->radioStatistics.rxFailNoAnser++; // got nothing mHeu.setGotNothing(q->iv); if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { @@ -112,6 +113,7 @@ class Communication : public CommQueue<> { } mGotFragment = true; + mFirstTry = false; // for correct reset States nextState = States::RESET; while(!q->iv->radio->mBufCtrl.empty()) { packet_t *p = &q->iv->radio->mBufCtrl.front(); @@ -270,6 +272,7 @@ class Communication : public CommQueue<> { record_t<> *rec = q->iv->getRecordStruct(RealTimeRunData_Debug); // choose the record structure rec->ts = q->ts; miStsConsolidate(q, ((p->packet[0] == 0x88) ? 1 : 2), rec, p->packet[10], p->packet[12], p->packet[9], p->packet[11]); + mHeu.setGotFragment(q->iv); } } @@ -512,6 +515,9 @@ class Communication : public CommQueue<> { cmdDone(true); mState = States::RESET; q->iv->radioStatistics.rxSuccess++; + mHeu.setGotAll(q->iv); + } else { + mHeu.setGotFragment(q->iv); } /*if (mPayload[iv->id].multi_parts > 5) { @@ -572,12 +578,14 @@ class Communication : public CommQueue<> { //mPayload[iv->id].retransmits = 0; // reserve retransmissions for each response //mPayload[iv->id].complete = false; miNextRequest((p->packet[0] - ALL_FRAMES + 1), q); + mHeu.setGotFragment(q->iv); } else { miComplete(q->iv); } } else if((p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES)) && (q->iv->type == INV_TYPE_2CH)) { //addImportant(q->iv, MI_REQ_CH2); miNextRequest(MI_REQ_CH2, q); + mHeu.setGotFragment(q->iv); } else { // first data msg for 1ch, 2nd for 2ch miComplete(q->iv); } @@ -709,7 +717,12 @@ class Communication : public CommQueue<> { // update status state-machine, if (ac_pow) iv->isProducing(); + mHeu.setGotAll(iv); cmdDone(true); + if(NULL != mCbPayload) + (mCbPayload)(RealTimeRunData_Debug, iv); + + mState = States::RESET; // everything ok, next request } private: @@ -729,6 +742,7 @@ class Communication : public CommQueue<> { uint32_t mWaitTimeout = 0; std::array mLocalBuf; bool mGotFragment = false; + bool mFirstTry = false; uint8_t mMaxFrameId; uint8_t mPayload[MAX_BUFFER]; payloadListenerType mCbPayload = NULL; diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index 1675eda4..b9f6ab4f 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -48,8 +48,8 @@ class Heuristic { } void printStatus(Inverter<> *iv) { - DPRINT(DBG_INFO, F("Status:")); - DBGPRINT(F(" |")); + DPRINT_IVID(DBG_INFO, iv->id); + DBGPRINT(F("CH qualities:")); for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) { DBGPRINT(F(" ")); DBGPRINT(String(iv->txRfQuality[i])); From a82777b2a1dff3f3a0fae36839040c31b3f10a3f Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 12 Nov 2023 13:32:00 +0100 Subject: [PATCH 165/267] 0.8.6 * merged PR #1225 * improved heuristics (prevent update of statitistic during testing) --- src/CHANGES.md | 4 ++++ src/hm/Communication.h | 36 +++++++++++++++++++---------- src/hm/Heuristic.h | 41 ++++++++++++++++++++++----------- src/web/html/api.js | 13 +++++++++++ src/web/html/visualization.html | 14 ++++++----- 5 files changed, 77 insertions(+), 31 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 6c4f0a6d..bbe0bbc3 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,9 @@ # Development Changes +## 0.8.6 - 2023-11-12 +* merged PR #1225 +* improved heuristics (prevent update of statitistic during testing) + ## 0.8.5 - 2023-11-12 * fixed endless loop while switching CMT frequency * removed obsolete "retries" field from settings #1224 diff --git a/src/hm/Communication.h b/src/hm/Communication.h index fb1709c5..a4eb43eb 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -44,6 +44,7 @@ class Communication : public CommQueue<> { return; // empty uint16_t timeout = q->iv->ivGen != IV_MI ? DEFAULT_TIMEOUT : MI_TIMEOUT; + bool testMode = false; switch(mState) { case States::RESET: @@ -56,6 +57,7 @@ class Communication : public CommQueue<> { mHeu.printStatus(q->iv); mHeu.getTxCh(q->iv); + testMode = mHeu.getTestModeEnabled(); mGotFragment = false; mFirstTry = mFirstTry ? false : ( (IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen) ) && (q->iv->isAvailable()); //) || (millis() < 120000));} if(NULL == q->iv->radio) @@ -79,7 +81,8 @@ class Communication : public CommQueue<> { q->iv->radio->sendControlPacket(q->iv, q->cmd, q->iv->powerLimit, false); } else q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); - q->iv->radioStatistics.txCnt++; + if(!testMode) + q->iv->radioStatistics.txCnt++; mWaitTimeout = millis() + timeout; setAttempt(); mState = States::WAIT; @@ -100,14 +103,17 @@ class Communication : public CommQueue<> { DBGPRINTLN(F("ms")); if(!mGotFragment && !mFirstTry) { - q->iv->radioStatistics.rxFailNoAnser++; // got nothing + if(!testMode) + q->iv->radioStatistics.rxFailNoAnser++; // got nothing mHeu.setGotNothing(q->iv); if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, (q->iv->config->frequency*FREQ_STEP_KHZ + HOY_BASE_FREQ_KHZ)); mWaitTimeout = millis() + 1000; } - } else - q->iv->radioStatistics.rxFail++; + } else { + if(!testMode) + q->iv->radioStatistics.rxFail++; + } mState = States::RESET; break; } @@ -137,7 +143,8 @@ class Communication : public CommQueue<> { ah::dumpBuf(p->packet, p->len); if(checkIvSerial(&p->packet[1], q->iv)) { - q->iv->radioStatistics.frmCnt++; + if(!testMode) + q->iv->radioStatistics.frmCnt++; if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command parseFrame(p); @@ -149,7 +156,8 @@ class Communication : public CommQueue<> { parseMiFrame(p, q); } } else { - q->iv->radioStatistics.rxFail++; // got no complete payload + if(!testMode) + q->iv->radioStatistics.rxFail++; // got no complete payload DPRINTLN(DBG_WARN, F("Inverter serial does not match")); mWaitTimeout = millis() + timeout; } @@ -158,8 +166,9 @@ class Communication : public CommQueue<> { yield(); } if(0 == q->attempts) { + if(!testMode) + q->iv->radioStatistics.rxFail++; // got no complete payload mHeu.setGotFragment(q->iv); - q->iv->radioStatistics.rxFail++; // got no complete payload cmdDone(true); mState = States::RESET; } else @@ -205,7 +214,7 @@ class Communication : public CommQueue<> { } mHeu.setGotAll(q->iv); - compilePayload(q); + compilePayload(q, testMode); if(NULL != mCbPayload) (mCbPayload)(q->cmd, q->iv); @@ -295,7 +304,7 @@ class Communication : public CommQueue<> { q->iv->actPowerLimit = 0xffff; // unknown, readback current value } - inline void compilePayload(const queue_s *q) { + inline void compilePayload(const queue_s *q, bool testMode) { uint16_t crc = 0xffff, crcRcv = 0x0000; for(uint8_t i = 0; i < mMaxFrameId; i++) { if(i == (mMaxFrameId - 1)) { @@ -311,7 +320,8 @@ class Communication : public CommQueue<> { DBGPRINT(F("CRC Error ")); if(q->attempts == 0) { DBGPRINTLN(F("-> Fail")); - q->iv->radioStatistics.rxFail++; // got fragments but not complete response + if(!testMode) + q->iv->radioStatistics.rxFail++; // got fragments but not complete response cmdDone(); } else DBGPRINTLN(F("-> complete retransmit")); @@ -356,11 +366,13 @@ class Communication : public CommQueue<> { DPRINT(DBG_ERROR, F("plausibility check failed, expected ")); DBGPRINT(String(rec->pyldLen)); DBGPRINTLN(F(" bytes")); - q->iv->radioStatistics.rxFail++; + if(!testMode) + q->iv->radioStatistics.rxFail++; return; } - q->iv->radioStatistics.rxSuccess++; + if(!testMode) + q->iv->radioStatistics.rxSuccess++; rec->ts = q->ts; for (uint8_t i = 0; i < rec->length; i++) { diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index b9f6ab4f..7bf9f4a9 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -19,6 +19,13 @@ class Heuristic { if((IV_HMS == iv->ivGen) || (IV_HMT == iv->ivGen)) return 0; // not used for these inverter types + mCycle++; // intended to overflow from time to time + if(mTestEn) { + iv->txRfChId = mCycle % RF_MAX_CHANNEL_ID; + DPRINTLN(DBG_INFO, F("heuristic test mode")); + return id2Ch(iv->txRfChId); + } + uint8_t id = 0; int8_t bestQuality = -6; for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) { @@ -37,14 +44,20 @@ class Heuristic { void setGotAll(Inverter<> *iv) { updateQuality(iv, 2); // GOOD + mTestEn = false; } void setGotFragment(Inverter<> *iv) { updateQuality(iv, 1); // OK + mTestEn = false; } void setGotNothing(Inverter<> *iv) { - updateQuality(iv, -2); // BAD + if(!mTestEn) { + updateQuality(iv, -2); // BAD + mTestEn = true; + iv->txRfChId = (iv->txRfChId + 1) % RF_MAX_CHANNEL_ID; + } } void printStatus(Inverter<> *iv) { @@ -54,7 +67,18 @@ class Heuristic { DBGPRINT(F(" ")); DBGPRINT(String(iv->txRfQuality[i])); } - DBGPRINTLN(""); + DBGPRINT(F(" | t: ")); + DBGPRINT(String(iv->radioStatistics.txCnt)); + DBGPRINT(F(", s: ")); + DBGPRINT(String(iv->radioStatistics.rxSuccess)); + DBGPRINT(F(", f: ")); + DBGPRINT(String(iv->radioStatistics.rxFail)); + DBGPRINT(F(", n: ")); + DBGPRINTLN(String(iv->radioStatistics.rxFailNoAnser)); + } + + bool getTestModeEnabled(void) { + return mTestEn; } private: @@ -66,17 +90,6 @@ class Heuristic { iv->txRfQuality[iv->txRfChId] = RF_MIN_QUALTIY; } - /*uint8_t ch2Id(uint8_t ch) { - switch(ch) { - case 3: return 0; - case 23: return 1; - case 40: return 2; - case 61: return 3; - case 75: return 4; - } - return 0; // standard - }*/ - inline uint8_t id2Ch(uint8_t id) { switch(id) { case 0: return 3; @@ -90,6 +103,8 @@ class Heuristic { private: uint8_t mChList[5] = {03, 23, 40, 61, 75}; + bool mTestEn = false; + uint8_t mCycle = 0; }; diff --git a/src/web/html/api.js b/src/web/html/api.js index 2eea8d94..e76aab2c 100644 --- a/src/web/html/api.js +++ b/src/web/html/api.js @@ -188,6 +188,19 @@ function tr(val1, val2) { ]); } +function tr2(cols) { + var t = []; + for(val of cols) { + if(typeof val == "number") + val = String(val); + if(t.length == 0) + t.push(ml("th", {}, val)); + else + t.push(ml("td", {}, val)); + } + return ml("tr", {}, t); +} + function badge(success, text, second="error") { return ml("span", {class: "badge badge-" + ((success) ? "success" : second)}, text); } diff --git a/src/web/html/visualization.html b/src/web/html/visualization.html index aa05e414..d4ac1557 100644 --- a/src/web/html/visualization.html +++ b/src/web/html/visualization.html @@ -296,15 +296,17 @@ modal("Info for inverter " + obj.name, ml("div", {}, html)); } + + function parseIvRadioStats(obj) { var html = ml("table", {class: "table"}, [ ml("tbody", {}, [ - tr("TX count", obj.tx_cnt), - tr("RX success", obj.rx_success), - tr("RX fail", obj.rx_fail), - tr("RX no answer", obj.rx_fail_answer), - tr("RX fragments", obj.frame_cnt), - tr("TX retransmits", obj.retransmits) + tr2(["TX count", obj.tx_cnt, ""]), + tr2(["RX success", obj.rx_success, String(Math.round(obj.rx_success / obj.tx_cnt * 10000) / 100) + "%"]), + tr2(["RX fail", obj.rx_fail, String(Math.round(obj.rx_fail / obj.tx_cnt * 10000) / 100) + "%"]), + tr2(["RX no answer", obj.rx_fail_answer, String(Math.round(obj.rx_fail_answer / obj.tx_cnt * 10000) / 100) + "%"]), + tr2(["RX fragments", obj.frame_cnt, ""]), + tr2(["TX retransmits", obj.retransmits, ""]) ]) ]); modal("Radio statistics for inverter " + obj.name, ml("div", {}, html)); From 1bc3a0f06f5a6e3fd5b0ad87c703110751b63afa Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 13 Nov 2023 23:54:55 +0100 Subject: [PATCH 166/267] 0.8.7 * fix ESP8266 inverter settings #1226 * send radio statistics via MqTT #1227 * made night communication inverter depended * added option to prevent adding values of inverter to total values (MqTT only) #1199 --- src/CHANGES.md | 6 +++ src/app.cpp | 92 +++++++++++++++++++---------------- src/app.h | 1 - src/config/settings.h | 26 ++++++---- src/defines.h | 2 +- src/hm/hmInverter.h | 2 + src/publisher/pubMqtt.h | 13 ++++- src/publisher/pubMqttDefs.h | 2 - src/publisher/pubMqttIvData.h | 68 ++++++++++++++++---------- src/web/RestApi.h | 80 ++++++++++++++++-------------- src/web/html/setup.html | 90 +++++++++++++++++++--------------- src/web/web.h | 2 - 12 files changed, 223 insertions(+), 161 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index bbe0bbc3..4fb9bf7e 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,11 @@ # Development Changes +## 0.8.7 - 2023-11-13 +* fix ESP8266 inverter settings #1226 +* send radio statistics via MqTT #1227 +* made night communication inverter depended +* added option to prevent adding values of inverter to total values (MqTT only) #1199 + ## 0.8.6 - 2023-11-12 * merged PR #1225 * improved heuristics (prevent update of statitistic during testing) diff --git a/src/app.cpp b/src/app.cpp index 838c375f..edd58306 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -4,9 +4,7 @@ //----------------------------------------------------------------------------- #include - #include "app.h" - #include "utils/sun.h" @@ -239,43 +237,50 @@ void app::tickCalcSunrise(void) { //----------------------------------------------------------------------------- void app::tickIVCommunication(void) { - mIVCommunicationOn = !mConfig->sun.disNightCom; // if sun.disNightCom is false, communication is always on - if (!mIVCommunicationOn) { // inverter communication only during the day - uint32_t nxtTrig; - if (mTimestamp < (mSunrise - mConfig->sun.offsetSec)) { // current time is before communication start, set next trigger to communication start - nxtTrig = mSunrise - mConfig->sun.offsetSec; - } else { - if (mTimestamp >= (mSunset + mConfig->sun.offsetSec)) { // current time is past communication stop, nothing to do. Next update will be done at midnight by tickCalcSunrise - nxtTrig = 0; - } else { // current time lies within communication start/stop time, set next trigger to communication stop - mIVCommunicationOn = true; - nxtTrig = mSunset + mConfig->sun.offsetSec; + bool restartTick = false; + bool zeroValues = false; + uint32_t nxtTrig = 0; + + Inverter<> *iv; + for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) { + iv = mSys.getInverterByPos(i); + if(NULL == iv) + continue; + + iv->commEnabled = !iv->config->disNightCom; // if sun.disNightCom is false, communication is always on + if (!iv->commEnabled) { // inverter communication only during the day + if (mTimestamp < (mSunrise - mConfig->sun.offsetSec)) { // current time is before communication start, set next trigger to communication start + nxtTrig = mSunrise - mConfig->sun.offsetSec; + } else { + if (mTimestamp >= (mSunset + mConfig->sun.offsetSec)) { // current time is past communication stop, nothing to do. Next update will be done at midnight by tickCalcSunrise + nxtTrig = 0; + } else { // current time lies within communication start/stop time, set next trigger to communication stop + iv->commEnabled = true; + nxtTrig = mSunset + mConfig->sun.offsetSec; + } } + if (nxtTrig != 0) + restartTick = true; } - if (nxtTrig != 0) - onceAt(std::bind(&app::tickIVCommunication, this), nxtTrig, "ivCom"); + + if ((!iv->commEnabled) && (mConfig->inst.rstValsCommStop)) + zeroValues = true; } - tickComm(); + + if(restartTick) // at least one inverter + onceAt(std::bind(&app::tickIVCommunication, this), nxtTrig, "ivCom"); + + if (zeroValues) // at least one inverter + once(std::bind(&app::tickZeroValues, this), mConfig->nrf.sendInterval, "tZero"); } //----------------------------------------------------------------------------- void app::tickSun(void) { // only used and enabled by MQTT (see setup()) - if (!mMqtt.tickerSun(mSunrise, mSunset, mConfig->sun.offsetSec, mConfig->sun.disNightCom)) + if (!mMqtt.tickerSun(mSunrise, mSunset, mConfig->sun.offsetSec)) once(std::bind(&app::tickSun, this), 1, "mqSun"); // MQTT not connected, retry } -//----------------------------------------------------------------------------- -void app::tickComm(void) { - if ((!mIVCommunicationOn) && (mConfig->inst.rstValsCommStop)) - once(std::bind(&app::tickZeroValues, this), mConfig->nrf.sendInterval, "tZero"); - - if (mMqttEnabled) { - if (!mMqtt.tickerComm(!mIVCommunicationOn)) - once(std::bind(&app::tickComm, this), 5, "mqCom"); // MQTT not connected, retry after 5s - } -} - //----------------------------------------------------------------------------- void app::tickZeroValues(void) { zeroIvValues(!CHECK_AVAIL, SKIP_YIELD_DAY); @@ -325,22 +330,24 @@ void app::tickMidnight(void) { //----------------------------------------------------------------------------- void app::tickSend(void) { - if(!mIVCommunicationOn) { - DPRINTLN(DBG_WARN, F("Time not set or it is night time, therefore no communication to the inverter!")); - return; - } - for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { Inverter<> *iv = mSys.getInverterByPos(i); - if(NULL != iv) { - if(iv->config->enabled) { - iv->tickSend([this, iv](uint8_t cmd, bool isDevControl) { - if(isDevControl) - mCommunication.addImportant(iv, cmd); - else - mCommunication.add(iv, cmd); - }); + if(NULL == iv) + continue; + + if(iv->config->enabled) { + if(!iv->commEnabled) { + DPRINT_IVID(DBG_INFO, iv->id); + DBGPRINTLN(F("no communication to the inverter (night time)")); + continue; } + + iv->tickSend([this, iv](uint8_t cmd, bool isDevControl) { + if(isDevControl) + mCommunication.addImportant(iv, cmd); + else + mCommunication.add(iv, cmd); + }); } } @@ -358,6 +365,8 @@ void app:: zeroIvValues(bool checkAvail, bool skipYieldDay) { continue; // skip to next inverter if (!iv->config->enabled) continue; // skip to next inverter + if (iv->commEnabled) + continue; // skip to next inverter if (checkAvail) { if (!iv->isAvailable()) @@ -415,7 +424,6 @@ void app::resetSystem(void) { mSendLastIvId = 0; mShowRebootRequest = false; - mIVCommunicationOn = true; mSavePending = false; mSaveReboot = false; diff --git a/src/app.h b/src/app.h index 0bb1c170..0098c417 100644 --- a/src/app.h +++ b/src/app.h @@ -307,7 +307,6 @@ class app : public IApp, public ah::Scheduler { Communication mCommunication; bool mShowRebootRequest; - bool mIVCommunicationOn; #if defined(ETHERNET) ahoyeth mEth; diff --git a/src/config/settings.h b/src/config/settings.h index 27aaf953..76a42e23 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -30,7 +30,7 @@ * https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html#flash-layout * */ -#define CONFIG_VERSION 1 +#define CONFIG_VERSION 2 #define PROT_MASK_INDEX 0x0001 @@ -110,7 +110,6 @@ typedef struct { typedef struct { float lat; float lon; - bool disNightCom; // disable night communication uint16_t offsetSec; } cfgSun_t; @@ -145,6 +144,8 @@ typedef struct { char chName[6][MAX_NAME_LENGTH]; uint8_t frequency; uint8_t powerLevel; + bool disNightCom; // disable night communication + bool add2Total; // add values to total values - useful if one inverter is on battery to turn off } cfgIv_t; typedef struct { @@ -420,7 +421,6 @@ class settings { mCfg.sun.lat = 0.0; mCfg.sun.lon = 0.0; - mCfg.sun.disNightCom = false; mCfg.sun.offsetSec = 0; mCfg.serial.interval = SERIAL_INTERVAL; @@ -442,8 +442,10 @@ class settings { mCfg.inst.yieldEffiency = 0.955f; for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { - mCfg.inst.iv[i].powerLevel = 0xff; // impossible high value - mCfg.inst.iv[i].frequency = 0x12; // 863MHz (minimum allowed frequency) + mCfg.inst.iv[i].powerLevel = 0xff; // impossible high value + mCfg.inst.iv[i].frequency = 0x12; // 863MHz (minimum allowed frequency) + mCfg.inst.iv[i].disNightCom = false; + mCfg.inst.iv[i].add2Total = true; } mCfg.led.led0 = DEF_LED0; @@ -465,11 +467,15 @@ class settings { } void loadAddedDefaults() { - if(0 < mCfg.configVersion) { - for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { + for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { + if(mCfg.configVersion < 1) { mCfg.inst.iv[i].powerLevel = 0xff; // impossible high value mCfg.inst.iv[i].frequency = 0x0; // 860MHz (backward compatibility) } + if(mCfg.configVersion < 2) { + mCfg.inst.iv[i].disNightCom = false; + mCfg.inst.iv[i].add2Total = true; + } } } @@ -601,12 +607,10 @@ class settings { if(set) { obj[F("lat")] = mCfg.sun.lat; obj[F("lon")] = mCfg.sun.lon; - obj[F("dis")] = mCfg.sun.disNightCom; obj[F("offs")] = mCfg.sun.offsetSec; } else { getVal(obj, F("lat"), &mCfg.sun.lat); getVal(obj, F("lon"), &mCfg.sun.lon); - getVal(obj, F("dis"), &mCfg.sun.disNightCom); getVal(obj, F("offs"), &mCfg.sun.offsetSec); } } @@ -734,6 +738,8 @@ class settings { obj[F("sn")] = cfg->serial.u64; obj[F("freq")] = cfg->frequency; obj[F("pa")] = cfg->powerLevel; + obj[F("dis")] = cfg->disNightCom; + obj[F("add")] = cfg->add2Total; for(uint8_t i = 0; i < 6; i++) { obj[F("yield")][i] = cfg->yieldCor[i]; obj[F("pwr")][i] = cfg->chMaxPwr[i]; @@ -745,6 +751,8 @@ class settings { getVal(obj, F("sn"), &cfg->serial.u64); getVal(obj, F("freq"), &cfg->frequency); getVal(obj, F("pa"), &cfg->powerLevel); + getVal(obj, F("dis"), &cfg->disNightCom); + getVal(obj, F("add"), &cfg->add2Total); uint8_t size = 4; if(obj.containsKey(F("pwr"))) size = obj[F("pwr")].size(); diff --git a/src/defines.h b/src/defines.h index eeee3574..fe9acf95 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 5 +#define VERSION_PATCH 7 //------------------------------------- typedef struct { diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index f52bafe9..f3d149c4 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -130,6 +130,7 @@ class Inverter { int8_t txRfQuality[5]; // heuristics tx quality (check 'Heuristics.h') uint8_t txRfChId; // RF TX channel id uint8_t curCmtFreq; // current used CMT frequency, used to check if freq. was changed during runtime + bool commEnabled; // 'pause night communication' sets this field to false static uint32_t *timestamp; // system timestamp static cfgInst_t *generalConfig; // general inverter configuration from setup @@ -150,6 +151,7 @@ class Inverter { alarmLastId = 0; rssi = -127; radio = NULL; + commEnabled = true; memset(&radioStatistics, 0, sizeof(statistics_t)); memset(txRfQuality, -6, 5); diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 48dbe150..2c23c719 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -134,7 +134,7 @@ class PubMqtt { #endif } - bool tickerSun(uint32_t sunrise, uint32_t sunset, uint32_t offs, bool disNightCom) { + bool tickerSun(uint32_t sunrise, uint32_t sunset, uint32_t offs) { if (!mClient.connected()) return false; @@ -142,7 +142,16 @@ class PubMqtt { publish(subtopics[MQTT_SUNSET], String(sunset).c_str(), true); publish(subtopics[MQTT_COMM_START], String(sunrise - offs).c_str(), true); publish(subtopics[MQTT_COMM_STOP], String(sunset + offs).c_str(), true); - publish(subtopics[MQTT_DIS_NIGHT_COMM], ((disNightCom) ? dict[STR_TRUE] : dict[STR_FALSE]), true); + + Inverter<> *iv; + for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { + iv = mSys->getInverterByPos(i); + if(NULL == iv) + continue; + + snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/dis_night_comm", iv->config->name); + publish(mSubTopic, ((iv->commEnabled) ? dict[STR_TRUE] : dict[STR_FALSE]), true); + } return true; } diff --git a/src/publisher/pubMqttDefs.h b/src/publisher/pubMqttDefs.h index ca8bf01e..c97daa78 100644 --- a/src/publisher/pubMqttDefs.h +++ b/src/publisher/pubMqttDefs.h @@ -48,7 +48,6 @@ enum { MQTT_SUNSET, MQTT_COMM_START, MQTT_COMM_STOP, - MQTT_DIS_NIGHT_COMM, MQTT_COMM_DISABLED, MQTT_COMM_DIS_TS, MQTT_VERSION, @@ -69,7 +68,6 @@ const char* const subtopics[] PROGMEM = { "sunset", "comm_start", "comm_stop", - "dis_night_comm", "comm_disabled", "comm_dis_ts", "version", diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h index 053e359e..0ac6d306 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -31,11 +31,11 @@ class PubMqttIvData { memset(mIvLastRTRpub, 0, MAX_NUM_INVERTERS * sizeof(uint32_t)); mRTRDataHasBeenSent = false; - mTable[IDLE] = &PubMqttIvData::stateIdle; - mTable[START] = &PubMqttIvData::stateStart; - mTable[FIND_NXT_IV] = &PubMqttIvData::stateFindNxtIv; - mTable[SEND_DATA] = &PubMqttIvData::stateSend; - mTable[SEND_TOTALS] = &PubMqttIvData::stateSendTotals; + mTable[IDLE] = &PubMqttIvData::stateIdle; + mTable[START] = &PubMqttIvData::stateStart; + mTable[FIND_NXT_IV] = &PubMqttIvData::stateFindNxtIv; + mTable[SEND_DATA] = &PubMqttIvData::stateSend; + mTable[SEND_TOTALS] = &PubMqttIvData::stateSendTotals; } void loop() { @@ -142,25 +142,27 @@ class PubMqttIvData { // calculate total values for RealTimeRunData_Debug if (CH0 == rec->assign[mPos].ch) { if(mIv->status > InverterStatus::STARTING) { - mTotalFound = true; - switch (rec->assign[mPos].fieldId) { - case FLD_PAC: - mTotal[0] += mIv->getValue(mPos, rec); - break; - case FLD_YT: - mTotal[1] += mIv->getValue(mPos, rec); - break; - case FLD_YD: { - float val = mIv->getValue(mPos, rec); - if(0 == val) // inverter restarted during day - mSendTotalYd = false; - else - mTotal[2] += val; - break; + if(mIv->config->add2Total) { + mTotalFound = true; + switch (rec->assign[mPos].fieldId) { + case FLD_PAC: + mTotal[0] += mIv->getValue(mPos, rec); + break; + case FLD_YT: + mTotal[1] += mIv->getValue(mPos, rec); + break; + case FLD_YD: { + float val = mIv->getValue(mPos, rec); + if(0 == val) // inverter restarted during day + mSendTotalYd = false; + else + mTotal[2] += val; + break; + } + case FLD_PDC: + mTotal[3] += mIv->getValue(mPos, rec); + break; } - case FLD_PDC: - mTotal[3] += mIv->getValue(mPos, rec); - break; } } else mAllTotalFound = false; @@ -178,12 +180,25 @@ class PubMqttIvData { mPublish(mSubTopic, mVal, retained, qos); } mPos++; - } else + } else { + sendRadioStat(rec->length); mState = FIND_NXT_IV; + } } else mState = FIND_NXT_IV; } + inline void sendRadioStat(uint8_t start) { + snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/radio_stat", mIv->config->name); + snprintf(mVal, 100, "{\"tx\":%d,\"success\":%d,\"fail\":%d,\"no_answer\":%d,\"retransmits\":%d}", + mIv->radioStatistics.txCnt, + mIv->radioStatistics.rxSuccess, + mIv->radioStatistics.rxFail, + mIv->radioStatistics.rxFailNoAnser, + mIv->radioStatistics.retransmits); + mPublish(mSubTopic, mVal, false, QOS_0); + } + void stateSendTotals() { uint8_t fieldId; mRTRDataHasBeenSent = true; @@ -221,7 +236,8 @@ class PubMqttIvData { } else { mSendList->pop(); mZeroValues = false; - mState = START; + mPos = 0; + mState = IDLE; } } @@ -242,7 +258,7 @@ class PubMqttIvData { bool mRTRDataHasBeenSent; char mSubTopic[32 + MAX_NAME_LENGTH + 1]; - char mVal[40]; + char mVal[100]; bool mZeroValues; // makes sure that yield day is sent even if no inverter is online std::queue *mSendList; diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 53adb23f..fa2aaf22 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -339,27 +339,30 @@ class RestApi { Inverter<> *iv; for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) { iv = mSys->getInverterByPos(i); - if(NULL != iv) { - JsonObject obj2 = invArr.createNestedObject(); - obj2[F("enabled")] = (bool)iv->config->enabled; - obj2[F("id")] = i; - obj2[F("name")] = String(iv->config->name); - obj2[F("serial")] = String(iv->config->serial.u64, HEX); - obj2[F("channels")] = iv->channels; - obj2[F("freq")] = iv->config->frequency; - if(0xff == iv->config->powerLevel) { - if((IV_HMT == iv->ivGen) || (IV_HMS == iv->ivGen)) - obj2[F("pa")] = 30; // 20dBm - else - obj2[F("pa")] = 1; // low - } else - obj2[F("pa")] = iv->config->powerLevel; - - for(uint8_t j = 0; j < iv->channels; j ++) { - obj2[F("ch_yield_cor")][j] = (double)iv->config->yieldCor[j]; - obj2[F("ch_name")][j] = iv->config->chName[j]; - obj2[F("ch_max_pwr")][j] = iv->config->chMaxPwr[j]; - } + if(NULL == iv) + continue; + + JsonObject obj2 = invArr.createNestedObject(); + obj2[F("enabled")] = (bool)iv->config->enabled; + obj2[F("id")] = i; + obj2[F("name")] = String(iv->config->name); + obj2[F("serial")] = String(iv->config->serial.u64, HEX); + obj2[F("channels")] = iv->channels; + obj2[F("freq")] = iv->config->frequency; + obj2[F("disnightcom")] = (bool)iv->config->disNightCom; + obj2[F("add2total")] = (bool)iv->config->add2Total; + if(0xff == iv->config->powerLevel) { + if((IV_HMT == iv->ivGen) || (IV_HMS == iv->ivGen)) + obj2[F("pa")] = 30; // 20dBm + else + obj2[F("pa")] = 1; // low + } else + obj2[F("pa")] = iv->config->powerLevel; + + for(uint8_t j = 0; j < iv->channels; j ++) { + obj2[F("ch_yield_cor")][j] = (double)iv->config->yieldCor[j]; + obj2[F("ch_name")][j] = iv->config->chName[j]; + obj2[F("ch_max_pwr")][j] = iv->config->chMaxPwr[j]; } } obj[F("interval")] = String(mConfig->nrf.sendInterval); @@ -501,7 +504,6 @@ class RestApi { void getSun(JsonObject obj) { obj[F("lat")] = mConfig->sun.lat ? String(mConfig->sun.lat, 5) : ""; obj[F("lon")] = mConfig->sun.lat ? String(mConfig->sun.lon, 5) : ""; - obj[F("disnightcom")] = mConfig->sun.disNightCom; obj[F("offs")] = mConfig->sun.offsetSec; } @@ -583,24 +585,28 @@ class RestApi { obj[F("ts_sunrise")] = mApp->getSunrise(); obj[F("ts_sunset")] = mApp->getSunset(); obj[F("ts_offset")] = mConfig->sun.offsetSec; - obj[F("disNightComm")] = mConfig->sun.disNightCom; JsonArray inv = obj.createNestedArray(F("inverter")); Inverter<> *iv; + bool disNightCom = false; 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 invObj = inv.createNestedObject(); - invObj[F("enabled")] = (bool)iv->config->enabled; - invObj[F("id")] = i; - invObj[F("name")] = String(iv->config->name); - invObj[F("cur_pwr")] = ah::round3(iv->getChannelFieldValue(CH0, FLD_PAC, rec)); - invObj[F("is_avail")] = iv->isAvailable(); - invObj[F("is_producing")] = iv->isProducing(); - invObj[F("ts_last_success")] = iv->getLastTs(rec); - } + if(NULL == iv) + continue; + + record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); + JsonObject invObj = inv.createNestedObject(); + invObj[F("enabled")] = (bool)iv->config->enabled; + invObj[F("id")] = i; + invObj[F("name")] = String(iv->config->name); + invObj[F("cur_pwr")] = ah::round3(iv->getChannelFieldValue(CH0, FLD_PAC, rec)); + invObj[F("is_avail")] = iv->isAvailable(); + invObj[F("is_producing")] = iv->isProducing(); + invObj[F("ts_last_success")] = iv->getLastTs(rec); + if(iv->config->disNightCom) + disNightCom = true; } + obj[F("disNightComm")] = disNightCom; JsonArray warn = obj.createNestedArray(F("warnings")); if(!mRadioNrf->isChipConnected() && mConfig->nrf.enabled) @@ -729,8 +735,10 @@ class RestApi { } mApp->initInverter(jsonIn[F("id")]); - iv->config->frequency = jsonIn[F("freq")]; - iv->config->powerLevel = jsonIn[F("pa")]; + iv->config->frequency = jsonIn[F("freq")]; + iv->config->powerLevel = jsonIn[F("pa")]; + iv->config->disNightCom = jsonIn[F("disnightcom")]; + iv->config->add2Total = jsonIn[F("add2total")]; mApp->saveSettings(false); // without reboot } else { jsonOut[F("error")] = F("unknown cmd"); diff --git a/src/web/html/setup.html b/src/web/html/setup.html index a21aa073..b9933cea 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -140,38 +140,33 @@
Inverter
- -
-

General

-
-
-
Interval [s]
-
+
Interval [s]
+
-
Reset values and YieldDay at midnight
-
+
Reset values and YieldDay at midnight
+
-
Reset values when inverter polling pauses at sunset
-
+
Reset values when inverter polling pauses at sunset
+
-
Reset values when inverter status is 'not available'
-
+
Reset values when inverter status is 'not available'
+
-
Reset 'max' values at midnight
-
+
Reset 'max' values at midnight
+
-
Start without time sync (useful in AP-Only-Mode)
-
+
Start without time sync (useful in AP-Only-Mode)
+
-
Yield Efficiency (should be between 0.95 and 0.96)
-
+
Yield Efficiency (should be between 0.95 and 0.96)
+
@@ -223,10 +218,6 @@
Offset (pre sunrise, post sunset)
-
-
Pause polling inverters during night
-
-
@@ -434,6 +425,7 @@ [47, "GPIO47"], [48, "GPIO48"], ]; + /*ENDIF_ESP32*/ var nrfPa = [ [0, "MIN (recommended)"], [1, "LOW"], @@ -442,6 +434,8 @@ ]; var esp32cmtPa = []; var esp32cmtFreq = []; + + /*IF_ESP32*/ var freqFmt = new Intl.NumberFormat('en-US', { minimumIntegerDigits: 3, minimumFractionDigits: 2 @@ -645,6 +639,7 @@ add.ch_yield_cor = []; add.freq = 12; add.pa = 30; + add.add2total = true; var e = document.getElementById("inverter"); e.innerHTML = ""; // remove all childs @@ -674,23 +669,27 @@ } var cbEn = ml("input", {name: "enable", type: "checkbox"}, null); - if(obj.enabled) - cbEn.checked = true; + var cbDisNightCom = ml("input", {name: "disnightcom", type: "checkbox"}, null); + var cbAddTotal = ml("input", {name: "add2total", type: "checkbox"}, null); + cbEn.checked = (obj.enabled); + cbDisNightCom.checked = (obj.disnightcom); + cbAddTotal.checked = (obj.add2total); + var ser = ml("input", {name: "ser", class: "text", type: "number", max: 138999999999, value: obj.serial}, null); var html = ml("div", {}, [ - tabs(["General", "Inputs", "Radio"]), + tabs(["General", "Inputs", "Radio", "Advanced"]), ml("div", {id: "divGeneral", class: "tab-content"}, [ ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-4"}, "Enable"), - ml("div", {class: "col-8"}, cbEn) + ml("div", {class: "col-2"}, "Enable"), + ml("div", {class: "col-10"}, cbEn) ]), ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-4 mt-2"}, "Serial"), - ml("div", {class: "col-8"}, ser) + ml("div", {class: "col-2 mt-2"}, "Serial"), + ml("div", {class: "col-10"}, ser) ]), ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-4 mt-2"}, "Name"), - ml("div", {class: "col-8"}, ml("input", {name: "name", class: "text", type: "text", value: obj.name}, null)) + ml("div", {class: "col-2 mt-2"}, "Name"), + ml("div", {class: "col-10"}, ml("input", {name: "name", class: "text", type: "text", value: obj.name}, null)) ]) ]), ml("div", {id: "divInputs", class: "tab-content hide"}, [ @@ -704,21 +703,31 @@ ml("input", {type: "hidden", name: "isnrf"}, null), ml("div", {id: "setcmt"}, [ ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-4 mt-2"}, "Frequency"), - ml("div", {class: "col-8"}, sel("freq", esp32cmtFreq, obj.freq)) + ml("div", {class: "col-3 mt-2"}, "Frequency"), + ml("div", {class: "col-9"}, sel("freq", esp32cmtFreq, obj.freq)) ]), ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-4 mt-2"}, "Power Level"), - ml("div", {class: "col-8"}, sel("cmtpa", esp32cmtPa, obj.pa)) + ml("div", {class: "col-3 mt-2"}, "Power Level"), + ml("div", {class: "col-9"}, sel("cmtpa", esp32cmtPa, obj.pa)) ]), ]), ml("div", {id: "setnrf"}, ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-4 mt-2"}, "Power Level"), - ml("div", {class: "col-8"}, sel("nrfpa", nrfPa, obj.pa)) + ml("div", {class: "col-3 mt-2"}, "Power Level"), + ml("div", {class: "col-9"}, sel("nrfpa", nrfPa, obj.pa)) ]), ), ]), + ml("div", {id: "divAdvanced", class: "tab-content hide"}, [ + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-10"}, "Pause communication during night (lat. and lon. need to be set)"), + ml("div", {class: "col-2"}, cbDisNightCom) + ]), + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-10"}, "Include inverter to sum of total (should be checked by default)"), + ml("div", {class: "col-2"}, cbAddTotal) + ]) + ]), ml("div", {class: "row mt-5"}, [ ml("div", {class: "col-8", id: "res"}, ""), ml("div", {class: "col-4 a-r"}, ml("input", {type: "button", value: "save", class: "btn", onclick: function() { ivSave(); }}, null)) @@ -758,7 +767,7 @@ }) }); - modal("Edit inverter", html); + modal("Edit inverter " + obj.name, html); ser.dispatchEvent(new Event('change')); function ivSave() { @@ -781,6 +790,8 @@ else o.pa = document.getElementsByName("cmtpa")[0].value; o.freq = document.getElementsByName("freq")[0].value; + o.disnightcom = document.getElementsByName("disnightcom")[0].checked; + o.add2total = document.getElementsByName("add2total")[0].checked; getAjax("/api/setup", cb, "POST", JSON.stringify(o)); } @@ -841,7 +852,6 @@ function parseSun(obj) { document.getElementsByName("sunLat")[0].value = obj["lat"]; document.getElementsByName("sunLon")[0].value = obj["lon"]; - document.getElementsByName("sunDisNightCom")[0].checked = obj["disnightcom"]; const sel = document.getElementsByName("sunOffs")[0]; for(var i = 0; i <= 60; i++) { sel.appendChild(opt(i, i + " minutes", (i == (obj["offs"] / 60)))); diff --git a/src/web/web.h b/src/web/web.h index c37db811..ae2fc091 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -535,12 +535,10 @@ class Web { if (request->arg("sunLat") == "" || (request->arg("sunLon") == "")) { mConfig->sun.lat = 0.0; mConfig->sun.lon = 0.0; - mConfig->sun.disNightCom = false; mConfig->sun.offsetSec = 0; } else { mConfig->sun.lat = request->arg("sunLat").toFloat(); mConfig->sun.lon = request->arg("sunLon").toFloat(); - mConfig->sun.disNightCom = (request->arg("sunDisNightCom") == "on"); mConfig->sun.offsetSec = request->arg("sunOffs").toInt() * 60; } From eb15ce5dba8b5b576a493b39e0519e4957040217 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 16 Nov 2023 11:33:53 +0100 Subject: [PATCH 167/267] 0.8.0707 --- src/defines.h | 2 +- src/hm/CommQueue.h | 4 ++ src/hm/Communication.h | 148 +++++++++++++++++++++++------------------ src/hm/Heuristic.h | 6 +- src/hm/hmInverter.h | 5 ++ src/hm/hmRadio.h | 7 +- src/hm/radio.h | 4 ++ src/utils/helper.cpp | 7 +- src/utils/helper.h | 2 +- 9 files changed, 113 insertions(+), 72 deletions(-) diff --git a/src/defines.h b/src/defines.h index fe9acf95..21c583b0 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 7 +#define VERSION_PATCH 0707 //------------------------------------- typedef struct { diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index 8d0bb0f8..9771393d 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -85,6 +85,10 @@ class CommQueue { mQueue[mRdPtr].attempts--; } + void incrAttempt(void) { + mQueue[mRdPtr].attempts++; + } + void inc(uint8_t *ptr) { if(++(*ptr) >= N) *ptr = 0; diff --git a/src/hm/Communication.h b/src/hm/Communication.h index a4eb43eb..f23fe416 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -11,9 +11,10 @@ #include "../utils/crc.h" #include "Heuristic.h" -#define MI_TIMEOUT 250 -#define DEFAULT_TIMEOUT 500 -#define SINGLEFR_TIMEOUT 60 +#define MI_TIMEOUT 250 // timeout for MI type requests +#define FRSTMSG_TIMEOUT 150 // how long to wait for first msg to be received +#define DEFAULT_TIMEOUT 500 // timeout for regular requests +#define SINGLEFR_TIMEOUT 60 // timeout for single frame requests #define MAX_BUFFER 250 typedef std::function *)> payloadListenerType; @@ -43,7 +44,8 @@ class Communication : public CommQueue<> { if(!valid) return; // empty - uint16_t timeout = q->iv->ivGen != IV_MI ? DEFAULT_TIMEOUT : MI_TIMEOUT; + uint16_t timeout = q->iv->ivGen != IV_MI ? (mGotFragment && q->iv->mGotLastMsg) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT : MI_TIMEOUT; + uint16_t timeout_min = q->iv->ivGen != IV_MI ? mGotFragment ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT : MI_TIMEOUT; bool testMode = false; switch(mState) { @@ -55,11 +57,13 @@ class Communication : public CommQueue<> { mLocalBuf[i].len = 0; } - mHeu.printStatus(q->iv); + if(q->iv->radio->isSerialDebug()) + mHeu.printStatus(q->iv); mHeu.getTxCh(q->iv); testMode = mHeu.getTestModeEnabled(); mGotFragment = false; - mFirstTry = mFirstTry ? false : ( (IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen) ) && (q->iv->isAvailable()); //) || (millis() < 120000));} + q->iv->mGotLastMsg = false; + mFirstTry = mFirstTry ? false : ( ( (IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen) ) && (q->iv->isAvailable()) || (millis() < 120000) ); if(NULL == q->iv->radio) cmdDone(true); // can't communicate while radio is not defined! mState = States::START; @@ -83,12 +87,33 @@ class Communication : public CommQueue<> { q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); if(!testMode) q->iv->radioStatistics.txCnt++; - mWaitTimeout = millis() + timeout; + mWaitTimeout = millis() + timeout; + mWaitTimeout_min = millis() + timeout_min; setAttempt(); mState = States::WAIT; break; case States::WAIT: + if(millis() > mWaitTimeout_min) { + if(!mGotFragment) { // nothing received yet? + if(q->iv->radio->get()) { // radio received sth.? + mGotFragment = true; + if(q->iv->mGotLastMsg) { + //mState = States::CHECK_FRAMES; + mWaitTimeout = mWaitTimeout_min; + } + } + } else if(mFirstTry) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINTLN(F("second try")); + mFirstTry = false; + if(!testMode) + q->iv->radioStatistics.retransmits++; // got nothing + mState = States::START; + break; + } + + } if(millis() < mWaitTimeout) return; mState = States::CHECK_FRAMES; @@ -102,7 +127,7 @@ class Communication : public CommQueue<> { DBGPRINT(String(millis() - mWaitTimeout + timeout)); DBGPRINTLN(F("ms")); - if(!mGotFragment && !mFirstTry) { + if(!mGotFragment) { // && !mFirstTry) { if(!testMode) q->iv->radioStatistics.rxFailNoAnser++; // got nothing mHeu.setGotNothing(q->iv); @@ -140,7 +165,7 @@ class Communication : public CommQueue<> { DBGPRINT(F(", ")); DBGPRINT(String(p->rssi)); DBGPRINT(F("dBm | ")); - ah::dumpBuf(p->packet, p->len); + ah::dumpBuf(p->packet, p->len, 1, 8, "#"+String(q->iv->id)); if(checkIvSerial(&p->packet[1], q->iv)) { if(!testMode) @@ -178,39 +203,37 @@ class Communication : public CommQueue<> { break; case States::CHECK_PACKAGE: + uint8_t framnr = 0; if(0 == mMaxFrameId) { - setAttempt(); - - DPRINT_IVID(DBG_WARN, q->iv->id); - DBGPRINT(F("frame missing: request retransmit (")); - DBGPRINT(String(q->attempts)); - DBGPRINTLN(F(" attempts left)")); - uint8_t i = 0; while(i < MAX_PAYLOAD_ENTRIES) { if(mLocalBuf[i].len == 0) + framnr = i+1; break; i++; } - - sendRetransmit(q, i); - return; } - for(uint8_t i = 0; i < mMaxFrameId; i++) { - if(mLocalBuf[i].len == 0) { - setAttempt(); + if(!framnr) { + for(uint8_t i = 0; i < mMaxFrameId; i++) { + if(mLocalBuf[i].len == 0) { + framnr = i+1; + break; + } + } + } - DPRINT_IVID(DBG_WARN, q->iv->id); - DBGPRINT(F("frame ")); - DBGPRINT(String(i + 1)); - DBGPRINT(F(" missing: request retransmit (")); - DBGPRINT(String(q->attempts)); - DBGPRINTLN(F(" attempts left)")); + if(framnr) { + setAttempt(); - sendRetransmit(q, i); - return; - } + DPRINT_IVID(DBG_WARN, q->iv->id); + DBGPRINT(F("frame ")); + DBGPRINT(String(framnr)); + DBGPRINT(F(" missing: request retransmit (")); + DBGPRINT(String(q->attempts)); + DBGPRINTLN(F(" attempts left)")); + sendRetransmit(q, framnr-1); + return; } mHeu.setGotAll(q->iv); @@ -257,8 +280,9 @@ class Communication : public CommQueue<> { return; // CRC8 is wrong, frame invalid } - if((*frameId & ALL_FRAMES) == ALL_FRAMES) + if((*frameId & ALL_FRAMES) == ALL_FRAMES) { mMaxFrameId = (*frameId & 0x7f); + } frame_t *f = &mLocalBuf[(*frameId & 0x7f) - 1]; memcpy(f->buf, &p->packet[10], p->len-11); @@ -413,9 +437,6 @@ class Communication : public CommQueue<> { inline void miHwDecode(packet_t *p, const queue_s *q) { record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_All); // choose the record structure rec->ts = q->ts; - //mPayload[iv->id].gotFragment = true; - uint8_t multi_parts = 0; - /* Polling the device software and hardware version number command start byte Command word routing address target address User data check end byte @@ -458,14 +479,13 @@ class Communication : public CommQueue<> { q->iv->isConnected = true; //if(mSerialDebug) { DPRINT_IVID(DBG_INFO, q->iv->id); - DPRINT(DBG_INFO,F("HW_VER is ")); + DBGPRINT(F("HW_VER is ")); DBGPRINTLN(String((p->packet[24] << 8) + p->packet[25])); //} record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure rec->ts = q->ts; q->iv->setValue(1, rec, (uint32_t) ((p->packet[24] << 8) + p->packet[25])/1); - //mPayload[iv->id].multi_parts +=4; - multi_parts +=4; + q->iv->miMultiParts +=4; } else if ( p->packet[9] == 0x01 || p->packet[9] == 0x10 ) {//second frame for MI, 3rd gen. answers in 0x10 DPRINT_IVID(DBG_INFO, q->iv->id); if ( p->packet[9] == 0x01 ) { @@ -486,19 +506,19 @@ class Communication : public CommQueue<> { //if(mSerialDebug) { DPRINT(DBG_INFO,F("HW_FB_TLmValue ")); DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15])); - DPRINT(DBG_INFO,F("HW_FB_ReSPRT ")); + DBGPRINT(F("HW_FB_ReSPRT ")); DBGPRINTLN(String((p->packet[16] << 8) + p->packet[17])); - DPRINT(DBG_INFO,F("HW_GridSamp_ResValule ")); + DBGPRINT(F("HW_GridSamp_ResValule ")); DBGPRINTLN(String((p->packet[18] << 8) + p->packet[19])); - DPRINT(DBG_INFO,F("HW_ECapValue ")); + DBGPRINT(F("HW_ECapValue ")); DBGPRINTLN(String((p->packet[20] << 8) + p->packet[21])); - DPRINT(DBG_INFO,F("Matching_APPFW_PN ")); + DBGPRINT(F("Matching_APPFW_PN ")); DBGPRINTLN(String((uint32_t) (((p->packet[22] << 8) | p->packet[23]) << 8 | p->packet[24]) << 8 | p->packet[25])); //} - //notify(InverterDevInform_Simple, iv); - //mPayload[iv->id].multi_parts +=2; - multi_parts +=2; - //notify(InverterDevInform_All, iv); + if(NULL != mCbPayload) + (mCbPayload)(InverterDevInform_All, q->iv); + q->iv->miMultiParts +=2; + } else { DBGPRINTLN(F("3rd gen. inverter!")); } @@ -515,21 +535,24 @@ class Communication : public CommQueue<> { //if(mSerialDebug) { DPRINT(DBG_INFO,F("APPFW_MINVER ")); DBGPRINTLN(String((p->packet[10] << 8) + p->packet[11])); - DPRINT(DBG_INFO,F("HWInfoAddr ")); + DBGPRINT(F("HWInfoAddr ")); DBGPRINTLN(String((p->packet[12] << 8) + p->packet[13])); - DPRINT(DBG_INFO,F("PNInfoCRC_gusv ")); + DBGPRINT(F("PNInfoCRC_gusv ")); DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15])); //} - //mPayload[iv->id].multi_parts++; - multi_parts++; + if(NULL != mCbPayload) + (mCbPayload)(InverterDevInform_Simple, q->iv); + q->iv->miMultiParts++; } - if(multi_parts > 5) { + if(q->iv->miMultiParts > 5) { cmdDone(true); mState = States::RESET; q->iv->radioStatistics.rxSuccess++; mHeu.setGotAll(q->iv); + q->iv->miMultiParts = 0; } else { mHeu.setGotFragment(q->iv); + mState = States::WAIT; } /*if (mPayload[iv->id].multi_parts > 5) { @@ -568,9 +591,8 @@ class Communication : public CommQueue<> { q->iv->setValue(q->iv->getPosByChFld(0, FLD_T, rec), rec, (float) ((int16_t)(p->packet[21] << 8) + p->packet[22])/10); q->iv->setValue(q->iv->getPosByChFld(0, FLD_IRR, rec), rec, (float) (calcIrradiation(q->iv, datachan))); - //mPayload[q->iv->id].rssi[(datachan-1)] = p->rssi; - if (datachan == 1) //mPayload[q->iv->id].rssi[(datachan-1)] = p->rssi; + if (datachan == 1) q->iv->rssi = p->rssi; else if(q->iv->rssi > p->rssi) q->iv->rssi = p->rssi; @@ -597,6 +619,7 @@ class Communication : public CommQueue<> { } else if((p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES)) && (q->iv->type == INV_TYPE_2CH)) { //addImportant(q->iv, MI_REQ_CH2); miNextRequest(MI_REQ_CH2, q); + //use also miMultiParts here for better statistics? mHeu.setGotFragment(q->iv); } else { // first data msg for 1ch, 2nd for 2ch miComplete(q->iv); @@ -604,25 +627,24 @@ class Communication : public CommQueue<> { } inline void miNextRequest(uint8_t cmd, const queue_s *q) { - //setAttempt(); + incrAttempt(); // if function is called, we got something, and we necessarily need more transmissions for MI types... DPRINT_IVID(DBG_WARN, q->iv->id); DBGPRINT(F("next request (")); DBGPRINT(String(q->attempts)); DBGPRINT(F(" attempts left): 0x")); DBGHEXLN(cmd); - if(q->attempts) { + //if(q->attempts) { q->iv->radio->sendCmdPacket(q->iv, cmd, 0x00, true); q->iv->radioStatistics.retransmits++; mWaitTimeout = millis() + MI_TIMEOUT; - //chgCmd(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) chgCmd(cmd); mState = States::WAIT; - } else { + /*} else { add(q, true); cmdDone(); mState = States::RESET; - } + }*/ } inline void miStsConsolidate(const queue_s *q, uint8_t stschan, record_t<> *rec, uint8_t uState, uint8_t uEnum, uint8_t lState = 0, uint8_t lEnum = 0) { @@ -699,13 +721,10 @@ class Communication : public CommQueue<> { inline 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; - //if (mSerialDebug) { + if (iv->radio->isSerialDebug()) { DPRINT_IVID(DBG_INFO, iv->id); DBGPRINTLN(F("got all data msgs")); - //} + } record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0)); @@ -751,7 +770,8 @@ class Communication : public CommQueue<> { private: States mState = States::RESET; uint32_t *mTimestamp; - uint32_t mWaitTimeout = 0; + uint32_t mWaitTimeout = 0; + uint32_t mWaitTimeout_min = 0; std::array mLocalBuf; bool mGotFragment = false; bool mFirstTry = false; diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index 7bf9f4a9..3ad249b9 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -62,7 +62,7 @@ class Heuristic { void printStatus(Inverter<> *iv) { DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINT(F("CH qualities:")); + DBGPRINT(F("Radio infos:")); for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) { DBGPRINT(F(" ")); DBGPRINT(String(iv->txRfQuality[i])); @@ -74,7 +74,9 @@ class Heuristic { DBGPRINT(F(", f: ")); DBGPRINT(String(iv->radioStatistics.rxFail)); DBGPRINT(F(", n: ")); - DBGPRINTLN(String(iv->radioStatistics.rxFailNoAnser)); + DBGPRINT(String(iv->radioStatistics.rxFailNoAnser)); + DBGPRINT(F(" | p: ")); // better debugging for helpers... + DBGPRINTLN(String(iv->config->powerLevel)); } bool getTestModeEnabled(void) { diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index f3d149c4..88a19a1b 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -125,6 +125,8 @@ class Inverter { uint16_t alarmCnt; // counts the total number of occurred alarms uint16_t alarmLastId; // lastId which was received int8_t rssi; // RSSI + uint8_t miMultiParts; // helper info for MI multiframe msgs + bool mGotLastMsg; // shows if inverter has already finished transmission cycle Radio *radio; // pointer to associated radio class statistics_t radioStatistics; // information about transmitted, failed, ... packets int8_t txRfQuality[5]; // heuristics tx quality (check 'Heuristics.h') @@ -150,8 +152,11 @@ class Inverter { alarmCnt = 0; alarmLastId = 0; rssi = -127; + miMultiParts = 0; + mGotLastMsg = false; radio = NULL; commEnabled = true; + memset(&radioStatistics, 0, sizeof(statistics_t)); memset(txRfQuality, -6, 5); diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index a55c7d3c..a51504df 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -257,12 +257,14 @@ class HmRadio : public Radio { isLastPackage = (p.packet[9] > ALL_FRAMES); // > ALL_FRAMES indicates last packet received else if (p.packet[0] == ( 0x0f + ALL_FRAMES) ) // response from MI get information command isLastPackage = (p.packet[9] > 0x10); // > 0x10 indicates last packet received - else if ((p.packet[0] != 0x88) && (p.packet[0] != 0x92)) // ignore fragment number zero and MI status messages //#0 was p.packet[0] != 0x00 && + else if ((p.packet[0] != 0x88) && (p.packet[0] != 0x92)) // ignore MI status messages //#0 was p.packet[0] != 0x00 && isLastPackage = true; // response from dev control command } } yield(); } + if(isLastPackage) + mLastIv->mGotLastMsg = true; return isLastPackage; } @@ -280,7 +282,7 @@ class HmRadio : public Radio { DBGPRINT(" CH"); DBGPRINT(String(mTxChIdx)); DBGPRINT(F(" | ")); - ah::dumpBuf(mTxBuf, len); + ah::dumpBuf(mTxBuf, len, 1, 4, "#"+String(iv->id)); } mNrf24.stopListening(); @@ -304,6 +306,7 @@ class HmRadio : public Radio { uint8_t mRfChLst[RF_CHANNELS] = {03, 23, 40, 61, 75}; // channel List:2403, 2423, 2440, 2461, 2475MHz uint8_t mTxChIdx = 0; uint8_t mRxChIdx = 0; + bool mGotLastMsg = false; uint32_t mMillis; SPIClass* mSpi; diff --git a/src/hm/radio.h b/src/hm/radio.h index 07317e8c..e4beb071 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -38,6 +38,10 @@ class Radio { mSerialDebug = true; } + bool isSerialDebug() { + return mSerialDebug; + } + void sendCmdPacket(Inverter<> *iv, uint8_t mid, uint8_t pid, bool isRetransmit, bool appendCrc16=true) { initPacket(getIvId(iv), mid, pid); sendPacket(iv, 10, isRetransmit, appendCrc16); diff --git a/src/utils/helper.cpp b/src/utils/helper.cpp index 4050c999..c7aefc1c 100644 --- a/src/utils/helper.cpp +++ b/src/utils/helper.cpp @@ -86,9 +86,12 @@ namespace ah { return ret; } - void dumpBuf(uint8_t buf[], uint8_t len) { + void dumpBuf(uint8_t buf[], uint8_t len, uint8_t firstRepl, uint8_t lastRepl, String repl) { for(uint8_t i = 0; i < len; i++) { - DHEX(buf[i]); + if(i < firstRepl || i > lastRepl) + DHEX(buf[i]); + else + DBGPRINT(repl); DBGPRINT(" "); } DBGPRINTLN(""); diff --git a/src/utils/helper.h b/src/utils/helper.h index 252ca9fe..296729db 100644 --- a/src/utils/helper.h +++ b/src/utils/helper.h @@ -45,7 +45,7 @@ namespace ah { String getDateTimeStrFile(time_t t); String getTimeStr(time_t t); uint64_t Serial2u64(const char *val); - void dumpBuf(uint8_t buf[], uint8_t len); + void dumpBuf(uint8_t buf[], uint8_t len, uint8_t firstRepl = 0, uint8_t lastRepl = 0, String repl = ""); } #endif /*__HELPER_H__*/ From 972b03376b255358226920a86637ff9447e3d2a2 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 16 Nov 2023 23:59:05 +0100 Subject: [PATCH 168/267] 0.8.8 * fix ESP8266 save inverter #1232 --- src/CHANGES.md | 3 +++ src/defines.h | 2 +- src/web/RestApi.h | 36 +++++++++++++++++++++++++++--------- src/web/html/setup.html | 2 +- 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 4fb9bf7e..380458fc 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.8.8 - 2023-11-16 +* fix ESP8266 save inverter #1232 + ## 0.8.7 - 2023-11-13 * fix ESP8266 inverter settings #1226 * send radio statistics via MqTT #1227 diff --git a/src/defines.h b/src/defines.h index fe9acf95..4d95b022 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 7 +#define VERSION_PATCH 8 //------------------------------------- typedef struct { diff --git a/src/web/RestApi.h b/src/web/RestApi.h index fa2aaf22..d44e0f1e 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -124,12 +124,26 @@ class RestApi { void onApiPostBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) { DPRINTLN(DBG_VERBOSE, "onApiPostBody"); - DynamicJsonDocument json(800); - AsyncJsonResponse* response = new AsyncJsonResponse(false, 200); - JsonObject root = response->getRoot(); - DeserializationError err = deserializeJson(json, (const char *)data, len); + if(0 == index) { + if(NULL != mTmpBuf) + delete[] mTmpBuf; + mTmpBuf = new uint8_t[total+1]; + mTmpSize = total; + } + if(mTmpSize >= (len + index)) + memcpy(&mTmpBuf[index], data, len); + + if((len + index) != total) + return; // not last frame - nothing to do + + DynamicJsonDocument json(1000); + + DeserializationError err = deserializeJson(json, (const char *)mTmpBuf, mTmpSize); JsonObject obj = json.as(); + + AsyncJsonResponse* response = new AsyncJsonResponse(false, 200); + JsonObject root = response->getRoot(); root[F("success")] = (err) ? false : true; if(!err) { String path = request->url().substring(5); @@ -141,18 +155,20 @@ class RestApi { root[F("success")] = false; root[F("error")] = "Path not found: " + path; } - } - else { + } else { switch (err.code()) { case DeserializationError::Ok: break; - case DeserializationError::InvalidInput: root[F("error")] = F("Invalid input"); break; - case DeserializationError::NoMemory: root[F("error")] = F("Not enough memory"); break; - default: root[F("error")] = F("Deserialization failed"); break; + case DeserializationError::IncompleteInput: root[F("error")] = F("Incomplete input"); break; + case DeserializationError::InvalidInput: root[F("error")] = F("Invalid input"); break; + case DeserializationError::NoMemory: root[F("error")] = F("Not enough memory"); break; + default: root[F("error")] = F("Deserialization failed"); break; } } response->setLength(); request->send(response); + delete[] mTmpBuf; + mTmpBuf = NULL; } void getNotFound(JsonObject obj, String url) { @@ -760,6 +776,8 @@ class RestApi { uint32_t mTimezoneOffset; uint32_t mHeapFree, mHeapFreeBlk; uint8_t mHeapFrag; + uint8_t *mTmpBuf = NULL; + uint32_t mTmpSize; }; #endif /*__WEB_API_H__*/ diff --git a/src/web/html/setup.html b/src/web/html/setup.html index b9933cea..c1c1c841 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -798,7 +798,7 @@ function cb(obj) { var e = document.getElementById("res"); if(!obj.success) - e.innerHTML = "error while saving"; + e.innerHTML = "error: " + obj.error; else { modalClose(); getAjax("/api/inverter/list", parseIv); From 08fcbb4e73e9d879f9ca633d87e9d190f12622e5 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Fri, 17 Nov 2023 10:49:03 +0100 Subject: [PATCH 169/267] Partly fix retransmit errors * move gotFragment flag --- src/hm/Communication.h | 26 +++++++++++--------------- src/hm/hmInverter.h | 2 ++ src/hm/hmRadio.h | 16 ++++++++++++++++ 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index f23fe416..ce2a7175 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -14,7 +14,7 @@ #define MI_TIMEOUT 250 // timeout for MI type requests #define FRSTMSG_TIMEOUT 150 // how long to wait for first msg to be received #define DEFAULT_TIMEOUT 500 // timeout for regular requests -#define SINGLEFR_TIMEOUT 60 // timeout for single frame requests +#define SINGLEFR_TIMEOUT 65 // timeout for single frame requests #define MAX_BUFFER 250 typedef std::function *)> payloadListenerType; @@ -44,8 +44,8 @@ class Communication : public CommQueue<> { if(!valid) return; // empty - uint16_t timeout = q->iv->ivGen != IV_MI ? (mGotFragment && q->iv->mGotLastMsg) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT : MI_TIMEOUT; - uint16_t timeout_min = q->iv->ivGen != IV_MI ? mGotFragment ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT : MI_TIMEOUT; + uint16_t timeout = q->iv->ivGen != IV_MI ? (q->iv->mGotFragment && q->iv->mGotLastMsg) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT : MI_TIMEOUT; + uint16_t timeout_min = q->iv->ivGen != IV_MI ? q->iv->mGotFragment ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT : MI_TIMEOUT; bool testMode = false; switch(mState) { @@ -61,7 +61,7 @@ class Communication : public CommQueue<> { mHeu.printStatus(q->iv); mHeu.getTxCh(q->iv); testMode = mHeu.getTestModeEnabled(); - mGotFragment = false; + q->iv->mGotFragment = false; q->iv->mGotLastMsg = false; mFirstTry = mFirstTry ? false : ( ( (IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen) ) && (q->iv->isAvailable()) || (millis() < 120000) ); if(NULL == q->iv->radio) @@ -95,13 +95,10 @@ class Communication : public CommQueue<> { case States::WAIT: if(millis() > mWaitTimeout_min) { - if(!mGotFragment) { // nothing received yet? - if(q->iv->radio->get()) { // radio received sth.? - mGotFragment = true; - if(q->iv->mGotLastMsg) { + if(!q->iv->mGotFragment) { // nothing received yet? + if(q->iv->mGotLastMsg) { //mState = States::CHECK_FRAMES; mWaitTimeout = mWaitTimeout_min; - } } } else if(mFirstTry) { DPRINT_IVID(DBG_INFO, q->iv->id); @@ -127,7 +124,7 @@ class Communication : public CommQueue<> { DBGPRINT(String(millis() - mWaitTimeout + timeout)); DBGPRINTLN(F("ms")); - if(!mGotFragment) { // && !mFirstTry) { + if(!q->iv->mGotFragment) { if(!testMode) q->iv->radioStatistics.rxFailNoAnser++; // got nothing mHeu.setGotNothing(q->iv); @@ -143,7 +140,6 @@ class Communication : public CommQueue<> { break; } - mGotFragment = true; mFirstTry = false; // for correct reset States nextState = States::RESET; while(!q->iv->radio->mBufCtrl.empty()) { @@ -207,9 +203,10 @@ class Communication : public CommQueue<> { if(0 == mMaxFrameId) { uint8_t i = 0; while(i < MAX_PAYLOAD_ENTRIES) { - if(mLocalBuf[i].len == 0) + if(mLocalBuf[i].len == 0) { framnr = i+1; break; + } i++; } } @@ -280,9 +277,8 @@ class Communication : public CommQueue<> { return; // CRC8 is wrong, frame invalid } - if((*frameId & ALL_FRAMES) == ALL_FRAMES) { + if((*frameId & ALL_FRAMES) == ALL_FRAMES) mMaxFrameId = (*frameId & 0x7f); - } frame_t *f = &mLocalBuf[(*frameId & 0x7f) - 1]; memcpy(f->buf, &p->packet[10], p->len-11); @@ -773,7 +769,7 @@ class Communication : public CommQueue<> { uint32_t mWaitTimeout = 0; uint32_t mWaitTimeout_min = 0; std::array mLocalBuf; - bool mGotFragment = false; + //bool mGotFragment = false; bool mFirstTry = false; uint8_t mMaxFrameId; uint8_t mPayload[MAX_BUFFER]; diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 88a19a1b..0b87fbb1 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -126,6 +126,8 @@ class Inverter { uint16_t alarmLastId; // lastId which was received int8_t rssi; // RSSI uint8_t miMultiParts; // helper info for MI multiframe msgs + uint8_t outstandingFrames; // helper info to count difference between expected and received frames + bool mGotFragment; // shows if inverter has sent at least one fragment bool mGotLastMsg; // shows if inverter has already finished transmission cycle Radio *radio; // pointer to associated radio class statistics_t radioStatistics; // information about transmitted, failed, ... packets diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index a51504df..d0a7b250 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -252,6 +252,12 @@ class HmRadio : public Radio { p.millis = millis() - mMillis; mNrf24.read(p.packet, p.len); if (p.packet[0] != 0x00) { + if(!checkIvSerial(&p.packet[1], mLastIv)) { + DPRINT(DBG_WARN, "RX other inverter: "); + ah::dumpBuf(p.packet, p.len); + return false; + } + mLastIv->mGotFragment = true; mBufCtrl.push(p); if (p.packet[0] == (TX_REQ_INFO + ALL_FRAMES)) // response from get information command isLastPackage = (p.packet[9] > ALL_FRAMES); // > ALL_FRAMES indicates last packet received @@ -302,6 +308,16 @@ class HmRadio : public Radio { return iv->ivGen; } + inline bool checkIvSerial(uint8_t buf[], Inverter<> *iv) { + uint8_t tmp[4]; + CP_U32_BigEndian(tmp, iv->radioId.u64 >> 8); + for(uint8_t i = 0; i < 4; i++) { + if(tmp[i] != buf[i]) + return false; + } + return true; + } + uint64_t DTU_RADIO_ID; uint8_t mRfChLst[RF_CHANNELS] = {03, 23, 40, 61, 75}; // channel List:2403, 2423, 2440, 2461, 2475MHz uint8_t mTxChIdx = 0; From b57e463b92327fa393aa8de984db7161ba00094c Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 19 Nov 2023 00:25:27 +0100 Subject: [PATCH 170/267] improved changes from PR #1234 --- src/defines.h | 2 +- src/hm/Communication.h | 10 +++++----- src/hm/hmRadio.h | 4 +--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/defines.h b/src/defines.h index 4d95b022..72f2887f 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 8 +#define VERSION_PATCH 9 //------------------------------------- typedef struct { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index ce2a7175..c599cadc 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -44,8 +44,8 @@ class Communication : public CommQueue<> { if(!valid) return; // empty - uint16_t timeout = q->iv->ivGen != IV_MI ? (q->iv->mGotFragment && q->iv->mGotLastMsg) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT : MI_TIMEOUT; - uint16_t timeout_min = q->iv->ivGen != IV_MI ? q->iv->mGotFragment ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT : MI_TIMEOUT; + uint16_t timeout = q->iv->ivGen != IV_MI ? ((q->iv->mGotFragment && q->iv->mGotLastMsg) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT) : MI_TIMEOUT; + uint16_t timeout_min = q->iv->ivGen != IV_MI ? ((q->iv->mGotFragment) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT) : MI_TIMEOUT; bool testMode = false; switch(mState) { @@ -63,7 +63,7 @@ class Communication : public CommQueue<> { testMode = mHeu.getTestModeEnabled(); q->iv->mGotFragment = false; q->iv->mGotLastMsg = false; - mFirstTry = mFirstTry ? false : ( ( (IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen) ) && (q->iv->isAvailable()) || (millis() < 120000) ); + mFirstTry = mFirstTry ? false : (((IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen) ) && (q->iv->isAvailable()) || (millis() < 120000)); if(NULL == q->iv->radio) cmdDone(true); // can't communicate while radio is not defined! mState = States::START; @@ -97,8 +97,8 @@ class Communication : public CommQueue<> { if(millis() > mWaitTimeout_min) { if(!q->iv->mGotFragment) { // nothing received yet? if(q->iv->mGotLastMsg) { - //mState = States::CHECK_FRAMES; - mWaitTimeout = mWaitTimeout_min; + //mState = States::CHECK_FRAMES; + mWaitTimeout = mWaitTimeout_min; } } else if(mFirstTry) { DPRINT_IVID(DBG_INFO, q->iv->id); diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index d0a7b250..88e62f8f 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -309,10 +309,8 @@ class HmRadio : public Radio { } inline bool checkIvSerial(uint8_t buf[], Inverter<> *iv) { - uint8_t tmp[4]; - CP_U32_BigEndian(tmp, iv->radioId.u64 >> 8); for(uint8_t i = 0; i < 4; i++) { - if(tmp[i] != buf[i]) + if(buf[3-i] != iv->radioId.b[i]) return false; } return true; From 49ef94cb7a1435821816807697addb0108e1d00e Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 19 Nov 2023 01:38:54 +0100 Subject: [PATCH 171/267] 0.8.9 * merged PR #1234 * added new alarm codes * removed serial interval, was not in use anymore --- src/CHANGES.md | 5 +++ src/app.cpp | 2 +- src/config/config.h | 3 -- src/config/settings.h | 4 -- src/hm/hmInverter.h | 82 ++++++++++++++++++++++++++++++++--------- src/platformio.ini | 18 ++++----- src/web/RestApi.h | 1 - src/web/html/setup.html | 5 --- src/web/web.h | 10 +---- 9 files changed, 82 insertions(+), 48 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 380458fc..9ea5ff5d 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,10 @@ # Development Changes +## 0.8.9 - 2023-11-19 +* merged PR #1234 +* added new alarm codes +* removed serial interval, was not in use anymore + ## 0.8.8 - 2023-11-16 * fix ESP8266 save inverter #1232 diff --git a/src/app.cpp b/src/app.cpp index edd58306..5226f5ac 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -142,7 +142,7 @@ void app::regularTickers(void) { if (mConfig->plugin.display.type != 0) everySec(std::bind(&DisplayType::tickerSecond, &mDisplay), "disp"); #endif - every(std::bind(&PubSerialType::tick, &mPubSerial), mConfig->serial.interval, "uart"); + every(std::bind(&PubSerialType::tick, &mPubSerial), 5, "uart"); #if !defined(ETHERNET) //everySec([this]() { mImprov.tickSerial(); }, "impro"); #endif diff --git a/src/config/config.h b/src/config/config.h index e9d3adec..5b17ca9d 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -142,9 +142,6 @@ #define MAX_NUM_INVERTERS 4 #endif -// default serial interval -#define SERIAL_INTERVAL 5 - // default send interval #define SEND_INTERVAL 15 diff --git a/src/config/settings.h b/src/config/settings.h index 76a42e23..50632d0a 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -114,7 +114,6 @@ typedef struct { } cfgSun_t; typedef struct { - uint16_t interval; bool showIv; bool debug; } cfgSerial_t; @@ -423,7 +422,6 @@ class settings { mCfg.sun.lon = 0.0; mCfg.sun.offsetSec = 0; - mCfg.serial.interval = SERIAL_INTERVAL; mCfg.serial.showIv = false; mCfg.serial.debug = false; @@ -617,11 +615,9 @@ class settings { void jsonSerial(JsonObject obj, bool set = false) { if(set) { - obj[F("intvl")] = mCfg.serial.interval; obj[F("show")] = mCfg.serial.showIv; obj[F("debug")] = mCfg.serial.debug; } else { - getVal(obj, F("intvl"), &mCfg.serial.interval); getVal(obj, F("show"), &mCfg.serial.showIv); getVal(obj, F("debug"), &mCfg.serial.debug); } diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 0b87fbb1..eddf0664 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -594,14 +594,40 @@ class Inverter { static String getAlarmStr(uint16_t alarmCode) { switch (alarmCode) { // breaks are intentionally missing! case 1: return String(F("Inverter start")); - case 2: return String(F("DTU command failed")); - case 73: return String(F("Temperature >80°C")); // https://github.com/tbnobody/OpenDTU/discussions/590#discussioncomment-6049750 + case 2: return String(F("Time calibration")); + case 3: return String(F("EEPROM reading and writing error during operation")); + case 4: return String(F("Offline")); + case 11: return String(F("Grid voltage surge")); + case 12: return String(F("Grid voltage sharp drop")); + case 13: return String(F("Grid frequency mutation")); + case 14: return String(F("Grid phase mutation")); + case 15: return String(F("Grid transient fluctuation")); + case 36: return String(F("INV overvoltage or overcurrent")); + case 46: return String(F("FB overvoltage")); + case 47: return String(F("FB overcurrent")); + case 48: return String(F("FB clamp overvoltage")); + case 49: return String(F("FB clamp overvoltage")); + case 61: return String(F("Calibration parameter error")); + case 62: return String(F("System configuration parameter error")); + case 63: return String(F("Abnormal power generation data")); + + case 71: return String(F("Grid overvoltage load reduction (VW) function enable")); + case 72: return String(F("Power grid over-frequency load reduction (FW) function enable")); + case 73: return String(F("Over-temperature load reduction (TW) function enable")); + + case 95: return String(F("PV-1: Module in suspected shadow")); + case 96: return String(F("PV-2: Module in suspected shadow")); + case 97: return String(F("PV-3: Module in suspected shadow")); + case 98: return String(F("PV-4: Module in suspected shadow")); + case 121: return String(F("Over temperature protection")); + case 122: return String(F("Microinverter is suspected of being stolen")); + case 123: return String(F("Locked by remote control")); case 124: return String(F("Shut down by remote control")); case 125: return String(F("Grid configuration parameter error")); - case 126: return String(F("Software error code 126")); + case 126: return String(F("EEPROM reading and writing error")); case 127: return String(F("Firmware error")); - case 128: return String(F("Software error code 128")); + case 128: return String(F("Hardware configuration error")); case 129: return String(F("Abnormal bias")); case 130: return String(F("Offline")); case 141: return String(F("Grid: Grid overvoltage")); @@ -613,7 +639,12 @@ class Inverter { case 147: return String(F("Grid: Power grid outage")); case 148: return String(F("Grid: Grid disconnection")); case 149: return String(F("Grid: Island detected")); + + case 150: return String(F("DCI exceeded")); + case 171: return String(F("Grid: Abnormal phase difference between phase to phase")); + case 181: return String(F("Abnormal insulation impedance")); + case 182: return String(F("Abnormal grounding")); case 205: return String(F("MPPT-A: Input overvoltage")); case 206: return String(F("MPPT-B: Input overvoltage")); case 207: return String(F("MPPT-A: Input undervoltage")); @@ -632,24 +663,33 @@ class Inverter { case 220: return String(F("PV-3: Input undervoltage")); case 221: return String(F("PV-4: Input overvoltage")); case 222: return String(F("PV-4: Input undervoltage")); - case 301: return String(F("Hardware error code 301")); - case 302: return String(F("Hardware error code 302")); - case 303: return String(F("Hardware error code 303")); - case 304: return String(F("Hardware error code 304")); - case 305: return String(F("Hardware error code 305")); - case 306: return String(F("Hardware error code 306")); - case 307: return String(F("Hardware error code 307")); - case 308: return String(F("Hardware error code 308")); + + case 301: return String(F("FB short circuit failure")); + case 302: return String(F("FB short circuit failure")); + case 303: return String(F("FB overcurrent protection failure")); + case 304: return String(F("FB overcurrent protection failure")); + case 305: return String(F("FB clamp circuit failure")); + case 306: return String(F("FB clamp circuit failure")); + case 307: return String(F("INV power device failure")); + case 308: return String(F("INV overcurrent or overvoltage protection failure")); case 309: return String(F("Hardware error code 309")); case 310: return String(F("Hardware error code 310")); case 311: return String(F("Hardware error code 311")); case 312: return String(F("Hardware error code 312")); case 313: return String(F("Hardware error code 313")); case 314: return String(F("Hardware error code 314")); - case 5041: return String(F("Error code-04 Port 1")); - case 5042: return String(F("Error code-04 Port 2")); - case 5043: return String(F("Error code-04 Port 3")); - case 5044: return String(F("Error code-04 Port 4")); + + case 5011: return String(F("PV-1: MOSFET overcurrent (II)")); + case 5012: return String(F("PV-2: MOSFET overcurrent (II)")); + case 5013: return String(F("PV-3: MOSFET overcurrent (II)")); + case 5014: return String(F("PV-4: MOSFET overcurrent (II)")); + case 5020: return String(F("H-bridge MOSFET overcurrent or H-bridge overvoltage")); + + case 5041: return String(F("PV-1: current overcurrent (II)")); + case 5042: return String(F("PV-2: current overcurrent (II)")); + case 5043: return String(F("PV-3: current overcurrent (II)")); + case 5044: return String(F("PV-4: current overcurrent (II)")); + case 5051: return String(F("PV Input 1 Overvoltage/Undervoltage")); case 5052: return String(F("PV Input 2 Overvoltage/Undervoltage")); case 5053: return String(F("PV Input 3 Overvoltage/Undervoltage")); @@ -659,10 +699,18 @@ class Inverter { case 5080: return String(F("Grid Overvoltage/Undervoltage")); case 5090: return String(F("Grid Overfrequency/Underfrequency")); case 5100: return String(F("Island detected")); + case 5110: return String(F("GFDI")); case 5120: return String(F("EEPROM reading and writing error")); + case 5141: + case 5142: + case 5143: + case 5144: + return String(F("FB clamp overvoltage")); case 5150: return String(F("10 min value grid overvoltage")); + case 5160: return String(F("Grid transient fluctuation")); case 5200: return String(F("Firmware error")); - case 8310: return String(F("Shut down")); + case 8310: return String(F("Shut down by remote control")); + case 8320: return String(F("Locked by remote control")); case 9000: return String(F("Microinverter is suspected of being stolen")); default: return String(F("Unknown")); } diff --git a/src/platformio.ini b/src/platformio.ini index d3c3c43c..e7c87979 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -25,9 +25,9 @@ extra_scripts = lib_deps = https://github.com/yubox-node-org/ESPAsyncWebServer - nrf24/RF24 @ 1.4.7 + nrf24/RF24 @ 1.4.8 paulstoffregen/Time @ ^1.6.1 - https://github.com/bertmelis/espMqttClient#v1.4.5 + https://github.com/bertmelis/espMqttClient#v1.5.0 bblanchon/ArduinoJson @ ^6.21.3 https://github.com/JChristensen/Timezone @ ^1.2.4 olikraus/U8g2 @ ^2.35.7 @@ -71,7 +71,7 @@ monitor_filters = esp8266_exception_decoder [env:esp32-wroom32] -platform = espressif32@6.3.2 +platform = espressif32@6.4.0 board = lolin_d32 build_flags = ${env.build_flags} -DUSE_HSPI_FOR_EPD @@ -79,7 +79,7 @@ monitor_filters = esp32_exception_decoder [env:esp32-wroom32-prometheus] -platform = espressif32@6.3.2 +platform = espressif32@6.4.0 board = lolin_d32 build_flags = ${env.build_flags} -DUSE_HSPI_FOR_EPD @@ -93,9 +93,9 @@ board = esp32dev lib_deps = khoih-prog/AsyncWebServer_ESP32_W5500 khoih-prog/AsyncUDP_ESP32_W5500 - nrf24/RF24 @ ^1.4.7 + nrf24/RF24 @ ^1.4.8 paulstoffregen/Time @ ^1.6.1 - https://github.com/bertmelis/espMqttClient#v1.4.4 + https://github.com/bertmelis/espMqttClient#v1.5.0 bblanchon/ArduinoJson @ ^6.21.3 https://github.com/JChristensen/Timezone @ ^1.2.4 olikraus/U8g2 @ ^2.35.7 @@ -110,7 +110,7 @@ monitor_filters = esp32_exception_decoder [env:esp32-s2-mini] -platform = espressif32@6.3.2 +platform = espressif32@6.4.0 board = lolin_s2_mini build_flags = ${env.build_flags} -DUSE_HSPI_FOR_EPD @@ -124,7 +124,7 @@ monitor_filters = esp32_exception_decoder [env:opendtufusion] -platform = espressif32@6.3.2 +platform = espressif32@6.4.0 board = esp32-s3-devkitc-1 upload_protocol = esp-builtin build_flags = ${env.build_flags} @@ -147,7 +147,7 @@ monitor_filters = esp32_exception_decoder, colorize [env:opendtufusion-dev] -platform = espressif32@6.3.2 +platform = espressif32@6.4.0 board = esp32-s3-devkitc-1 upload_protocol = esp-builtin build_flags = ${env.build_flags} diff --git a/src/web/RestApi.h b/src/web/RestApi.h index d44e0f1e..2378819c 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -559,7 +559,6 @@ class RestApi { } void getSerial(JsonObject obj) { - obj[F("interval")] = (uint16_t)mConfig->serial.interval; obj[F("show_live_data")] = mConfig->serial.showIv; obj[F("debug")] = mConfig->serial.debug; } diff --git a/src/web/html/setup.html b/src/web/html/setup.html index c1c1c841..aa0f5435 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -48,10 +48,6 @@
Serial Debug
-
-
Interval [s]
-
-
@@ -939,7 +935,6 @@ function parseSerial(obj) { for(var i of [["serEn", "show_live_data"], ["serDbg", "debug"]]) document.getElementsByName(i[0])[0].checked = obj[i[1]]; - document.getElementsByName("serIntvl")[0].value = obj["interval"]; } function parseDisplay(obj, type, system) { diff --git a/src/web/web.h b/src/web/web.h index ae2fc091..a795d5ed 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -558,14 +558,8 @@ class Web { mConfig->mqtt.interval = request->arg("mqttInterval").toInt(); // serial console - if (request->arg("serIntvl") != "") { - mConfig->serial.interval = request->arg("serIntvl").toInt() & 0xffff; - - mConfig->serial.debug = (request->arg("serDbg") == "on"); - mConfig->serial.showIv = (request->arg("serEn") == "on"); - // Needed to log TX buffers to serial console - // mSys->Radio.mSerialDebug = mConfig->serial.debug; - } + mConfig->serial.debug = (request->arg("serDbg") == "on"); + mConfig->serial.showIv = (request->arg("serEn") == "on"); // display mConfig->plugin.display.pwrSaveAtIvOffline = (request->arg("disp_pwr") == "on"); From b7f0e683ec6a28fe9248fe4017a7020ae8c36c33 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 19 Nov 2023 14:25:57 +0100 Subject: [PATCH 172/267] 0.8.10 * fix Mi and HM inverter communication #1235 * added privacy mode option #1211 * changed serial debug option to work without reboot --- src/CHANGES.md | 5 +++++ src/app.cpp | 8 +++----- src/config/settings.h | 4 ++++ src/defines.h | 2 +- src/hm/Communication.h | 16 ++++++++++----- src/hm/hmRadio.h | 44 ++++++++++++++++++++++++----------------- src/hm/radio.h | 13 +++--------- src/hms/hmsRadio.h | 16 ++++++++++----- src/utils/helper.cpp | 6 +++--- src/utils/helper.h | 2 +- src/web/RestApi.h | 1 + src/web/html/setup.html | 6 +++++- src/web/web.h | 2 +- 13 files changed, 75 insertions(+), 50 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 9ea5ff5d..6c905aaa 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,10 @@ # Development Changes +## 0.8.10 - 2023-11-19 +* fix Mi and HM inverter communication #1235 +* added privacy mode option #1211 +* changed serial debug option to work without reboot + ## 0.8.9 - 2023-11-19 * merged PR #1234 * added new alarm codes diff --git a/src/app.cpp b/src/app.cpp index 5226f5ac..daa13307 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -32,13 +32,11 @@ void app::setup() { DBGPRINTLN(F("false")); if(mConfig->nrf.enabled) { - mNrfRadio.setup(mConfig->nrf.pinIrq, mConfig->nrf.pinCe, mConfig->nrf.pinCs, mConfig->nrf.pinSclk, mConfig->nrf.pinMosi, mConfig->nrf.pinMiso); - mNrfRadio.enableDebug(); + mNrfRadio.setup(&mConfig->serial.debug, &mConfig->serial.privacyLog, mConfig->nrf.pinIrq, mConfig->nrf.pinCe, mConfig->nrf.pinCs, mConfig->nrf.pinSclk, mConfig->nrf.pinMosi, mConfig->nrf.pinMiso); } #if defined(ESP32) if(mConfig->cmt.enabled) { - mCmtRadio.setup(mConfig->cmt.pinSclk, mConfig->cmt.pinSdio, mConfig->cmt.pinCsb, mConfig->cmt.pinFcsb, false); - mCmtRadio.enableDebug(); + mCmtRadio.setup(&mConfig->serial.debug, &mConfig->serial.privacyLog, mConfig->cmt.pinSclk, mConfig->cmt.pinSdio, mConfig->cmt.pinCsb, mConfig->cmt.pinFcsb, false); } #endif #ifdef ETHERNET @@ -57,7 +55,7 @@ void app::setup() { #endif #endif /* defined(ETHERNET) */ - mCommunication.setup(&mTimestamp); + mCommunication.setup(&mTimestamp, &mConfig->serial.debug, &mConfig->serial.privacyLog); mCommunication.addPayloadListener(std::bind(&app::payloadEventListener, this, std::placeholders::_1, std::placeholders::_2)); mSys.setup(&mTimestamp, &mConfig->inst); for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { diff --git a/src/config/settings.h b/src/config/settings.h index 50632d0a..1fe7be00 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -116,6 +116,7 @@ typedef struct { typedef struct { bool showIv; bool debug; + bool privacyLog; } cfgSerial_t; typedef struct { @@ -424,6 +425,7 @@ class settings { mCfg.serial.showIv = false; mCfg.serial.debug = false; + mCfg.serial.privacyLog = true; mCfg.mqtt.port = DEF_MQTT_PORT; snprintf(mCfg.mqtt.broker, MQTT_ADDR_LEN, "%s", DEF_MQTT_BROKER); @@ -617,9 +619,11 @@ class settings { if(set) { obj[F("show")] = mCfg.serial.showIv; obj[F("debug")] = mCfg.serial.debug; + obj[F("prv")] = (bool) mCfg.serial.privacyLog; } else { getVal(obj, F("show"), &mCfg.serial.showIv); getVal(obj, F("debug"), &mCfg.serial.debug); + getVal(obj, F("prv"), &mCfg.serial.privacyLog); } } diff --git a/src/defines.h b/src/defines.h index 72f2887f..124aa817 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 9 +#define VERSION_PATCH 10 //------------------------------------- typedef struct { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index c599cadc..6d2d0e1a 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -22,8 +22,10 @@ typedef std::function *)> alarmListenerType; class Communication : public CommQueue<> { public: - void setup(uint32_t *timestamp) { + void setup(uint32_t *timestamp, bool *serialDebug, bool *privacyMode) { mTimestamp = timestamp; + mPrivacyMode = privacyMode; + mSerialDebug = serialDebug; } void addImportant(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) { @@ -57,13 +59,13 @@ class Communication : public CommQueue<> { mLocalBuf[i].len = 0; } - if(q->iv->radio->isSerialDebug()) + if(*mSerialDebug) mHeu.printStatus(q->iv); mHeu.getTxCh(q->iv); testMode = mHeu.getTestModeEnabled(); q->iv->mGotFragment = false; q->iv->mGotLastMsg = false; - mFirstTry = mFirstTry ? false : (((IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen) ) && (q->iv->isAvailable()) || (millis() < 120000)); + mFirstTry = mFirstTry ? false : (((IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen)) && ((q->iv->isAvailable()) || (millis() < 120000))); if(NULL == q->iv->radio) cmdDone(true); // can't communicate while radio is not defined! mState = States::START; @@ -161,7 +163,10 @@ class Communication : public CommQueue<> { DBGPRINT(F(", ")); DBGPRINT(String(p->rssi)); DBGPRINT(F("dBm | ")); - ah::dumpBuf(p->packet, p->len, 1, 8, "#"+String(q->iv->id)); + if(*mPrivacyMode) + ah::dumpBuf(p->packet, p->len, 1, 8); + else + ah::dumpBuf(p->packet, p->len); if(checkIvSerial(&p->packet[1], q->iv)) { if(!testMode) @@ -717,7 +722,7 @@ class Communication : public CommQueue<> { inline void miComplete(Inverter<> *iv) { - if (iv->radio->isSerialDebug()) { + if (*mSerialDebug) { DPRINT_IVID(DBG_INFO, iv->id); DBGPRINTLN(F("got all data msgs")); } @@ -766,6 +771,7 @@ class Communication : public CommQueue<> { private: States mState = States::RESET; uint32_t *mTimestamp; + bool *mPrivacyMode, *mSerialDebug; uint32_t mWaitTimeout = 0; uint32_t mWaitTimeout_min = 0; std::array mLocalBuf; diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 88e62f8f..a36935f8 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -29,7 +29,19 @@ template > 24) & 0xFF) | ((mDtuSn >> 8) & 0xFF00) | ((mDtuSn << 8) & 0xFF0000) | ((mDtuSn << 24) & 0xFF000000)) << 8) | 0x01; @@ -252,9 +254,12 @@ class HmRadio : public Radio { p.millis = millis() - mMillis; mNrf24.read(p.packet, p.len); if (p.packet[0] != 0x00) { - if(!checkIvSerial(&p.packet[1], mLastIv)) { - DPRINT(DBG_WARN, "RX other inverter: "); - ah::dumpBuf(p.packet, p.len); + if(!checkIvSerial(p.packet, mLastIv)) { + DPRINT(DBG_WARN, "RX other inverter "); + if(*mPrivacyMode) + ah::dumpBuf(p.packet, p.len, 1, 4); + else + ah::dumpBuf(p.packet, p.len); return false; } mLastIv->mGotFragment = true; @@ -281,14 +286,17 @@ class HmRadio : public Radio { // set TX and RX channels mTxChIdx = mRfChLst[iv->txRfChId]; - if(mSerialDebug) { + if(*mSerialDebug) { DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("TX ")); DBGPRINT(String(len)); DBGPRINT(" CH"); DBGPRINT(String(mTxChIdx)); DBGPRINT(F(" | ")); - ah::dumpBuf(mTxBuf, len, 1, 4, "#"+String(iv->id)); + if(*mPrivacyMode) + ah::dumpBuf(mTxBuf, len, 1, 4); + else + ah::dumpBuf(mTxBuf, len); } mNrf24.stopListening(); @@ -309,8 +317,8 @@ class HmRadio : public Radio { } inline bool checkIvSerial(uint8_t buf[], Inverter<> *iv) { - for(uint8_t i = 0; i < 4; i++) { - if(buf[3-i] != iv->radioId.b[i]) + for(uint8_t i = 1; i < 5; i++) { + if(buf[i] != iv->radioId.b[i]) return false; } return true; diff --git a/src/hm/radio.h b/src/hm/radio.h index e4beb071..ddba0b50 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -34,14 +34,6 @@ class Radio { mIrqRcvd = true; } - void enableDebug() { - mSerialDebug = true; - } - - bool isSerialDebug() { - return mSerialDebug; - } - void sendCmdPacket(Inverter<> *iv, uint8_t mid, uint8_t pid, bool isRetransmit, bool appendCrc16=true) { initPacket(getIvId(iv), mid, pid); sendPacket(iv, 10, isRetransmit, appendCrc16); @@ -55,7 +47,7 @@ class Radio { return; } - if(mSerialDebug) { + if(*mSerialDebug) { DPRINT(DBG_DEBUG, F("prepareDevInformCmd 0x")); DPRINTLN(DBG_DEBUG,String(cmd, HEX)); } @@ -115,7 +107,8 @@ class Radio { uint32_t mDtuSn; volatile bool mIrqRcvd; - bool mSerialDebug; + bool *mSerialDebug; + bool *mPrivacyMode; uint8_t mTxBuf[MAX_RF_PAYLOAD_SIZE]; }; diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index bcb08c3f..1f6044bb 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -19,14 +19,18 @@ class CmtRadio : public Radio { mCmtAvail = false; } - void setup(uint8_t pinSclk, uint8_t pinSdio, uint8_t pinCsb, uint8_t pinFcsb, bool genDtuSn = true) { + void setup(bool *serialDebug, bool *privacyMode, uint8_t pinSclk, uint8_t pinSdio, uint8_t pinCsb, uint8_t pinFcsb, bool genDtuSn = true) { mCmt.setup(pinSclk, pinSdio, pinCsb, pinFcsb); reset(genDtuSn); + mPrivacyMode = privacyMode; + mSerialDebug = serialDebug; } - void setup(bool genDtuSn = true) { + void setup(bool *serialDebug, bool *privacyMode, bool genDtuSn = true) { mCmt.setup(); reset(genDtuSn); + mPrivacyMode = privacyMode; + mSerialDebug = serialDebug; } void loop() { @@ -88,12 +92,15 @@ class CmtRadio : public Radio { updateCrcs(&len, appendCrc16); - if(mSerialDebug) { + if(*mSerialDebug) { DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("TX ")); DBGPRINT(String(mCmt.getFreqKhz()/1000.0f)); DBGPRINT(F("Mhz | ")); - ah::dumpBuf(mTxBuf, len); + if(*mPrivacyMode) + ah::dumpBuf(mTxBuf, len, 1, 4); + else + ah::dumpBuf(mTxBuf, len); } uint8_t status = mCmt.tx(mTxBuf, len); @@ -125,7 +132,6 @@ class CmtRadio : public Radio { mCmt.goRx(); } - mSerialDebug = false; mIrqRcvd = false; mRqstGetRx = false; } diff --git a/src/utils/helper.cpp b/src/utils/helper.cpp index c7aefc1c..67758f5d 100644 --- a/src/utils/helper.cpp +++ b/src/utils/helper.cpp @@ -86,12 +86,12 @@ namespace ah { return ret; } - void dumpBuf(uint8_t buf[], uint8_t len, uint8_t firstRepl, uint8_t lastRepl, String repl) { + void dumpBuf(uint8_t buf[], uint8_t len, uint8_t firstRepl, uint8_t lastRepl) { for(uint8_t i = 0; i < len; i++) { - if(i < firstRepl || i > lastRepl) + if((i < firstRepl) || (i > lastRepl) || (0 == firstRepl)) DHEX(buf[i]); else - DBGPRINT(repl); + DBGPRINT(F(" *")); DBGPRINT(" "); } DBGPRINTLN(""); diff --git a/src/utils/helper.h b/src/utils/helper.h index 296729db..d7c6f34c 100644 --- a/src/utils/helper.h +++ b/src/utils/helper.h @@ -45,7 +45,7 @@ namespace ah { String getDateTimeStrFile(time_t t); String getTimeStr(time_t t); uint64_t Serial2u64(const char *val); - void dumpBuf(uint8_t buf[], uint8_t len, uint8_t firstRepl = 0, uint8_t lastRepl = 0, String repl = ""); + void dumpBuf(uint8_t buf[], uint8_t len, uint8_t firstRepl = 0, uint8_t lastRepl = 0); } #endif /*__HELPER_H__*/ diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 2378819c..f6d40a3a 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -561,6 +561,7 @@ class RestApi { void getSerial(JsonObject obj) { obj[F("show_live_data")] = mConfig->serial.showIv; obj[F("debug")] = mConfig->serial.debug; + obj[F("priv")] = mConfig->serial.privacyLog; } void getStaticIp(JsonObject obj) { diff --git a/src/web/html/setup.html b/src/web/html/setup.html index aa0f5435..b4d5749d 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -48,6 +48,10 @@
Serial Debug
+
+
Privacy Mode
+
+
@@ -933,7 +937,7 @@ /*ENDIF_ESP32*/ function parseSerial(obj) { - for(var i of [["serEn", "show_live_data"], ["serDbg", "debug"]]) + for(var i of [["serEn", "show_live_data"], ["serDbg", "debug"], ["priv", "priv"]]) document.getElementsByName(i[0])[0].checked = obj[i[1]]; } diff --git a/src/web/web.h b/src/web/web.h index a795d5ed..8c9be435 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -559,6 +559,7 @@ class Web { // serial console mConfig->serial.debug = (request->arg("serDbg") == "on"); + mConfig->serial.privacyLog = (request->arg("priv") == "on"); mConfig->serial.showIv = (request->arg("serEn") == "on"); // display @@ -634,7 +635,6 @@ class Web { { Inverter<> *iv; record_t<> *rec; - statistics_t *stat; String promUnit, promType; String metrics; char type[60], topic[100], val[25]; From 6d6686b44e2258f65d6119059bafdcf80b6b6d51 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 19 Nov 2023 16:34:19 +0100 Subject: [PATCH 173/267] 0.8.1101 known issues: * crashes from time to time? * has MI commands in HM pipe? --- src/CHANGES.md | 3 ++ src/defines.h | 2 +- src/hm/Communication.h | 112 +++++++++++++++++++-------------------- src/web/html/update.html | 5 +- 4 files changed, 63 insertions(+), 59 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 6c905aaa..0505f7a5 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.8.11 - 2023-11-19 +* slightly improved communication, thx @rejoe2 + ## 0.8.10 - 2023-11-19 * fix Mi and HM inverter communication #1235 * added privacy mode option #1211 diff --git a/src/defines.h b/src/defines.h index 124aa817..f0215013 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 10 +#define VERSION_PATCH 1101 //------------------------------------- typedef struct { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 6d2d0e1a..af288c9a 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -46,9 +46,8 @@ class Communication : public CommQueue<> { if(!valid) return; // empty - uint16_t timeout = q->iv->ivGen != IV_MI ? ((q->iv->mGotFragment && q->iv->mGotLastMsg) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT) : MI_TIMEOUT; - uint16_t timeout_min = q->iv->ivGen != IV_MI ? ((q->iv->mGotFragment) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT) : MI_TIMEOUT; - bool testMode = false; + uint16_t timeout = (q->iv->ivGen = IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment && q->iv->mGotLastMsg) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT); + uint16_t timeout_min = (q->iv->ivGen = IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT); switch(mState) { case States::RESET: @@ -62,10 +61,8 @@ class Communication : public CommQueue<> { if(*mSerialDebug) mHeu.printStatus(q->iv); mHeu.getTxCh(q->iv); - testMode = mHeu.getTestModeEnabled(); q->iv->mGotFragment = false; q->iv->mGotLastMsg = false; - mFirstTry = mFirstTry ? false : (((IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen)) && ((q->iv->isAvailable()) || (millis() < 120000))); if(NULL == q->iv->radio) cmdDone(true); // can't communicate while radio is not defined! mState = States::START; @@ -87,7 +84,7 @@ class Communication : public CommQueue<> { q->iv->radio->sendControlPacket(q->iv, q->cmd, q->iv->powerLimit, false); } else q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); - if(!testMode) + if(!mHeu.getTestModeEnabled()) q->iv->radioStatistics.txCnt++; mWaitTimeout = millis() + timeout; mWaitTimeout_min = millis() + timeout_min; @@ -97,16 +94,17 @@ class Communication : public CommQueue<> { case States::WAIT: if(millis() > mWaitTimeout_min) { - if(!q->iv->mGotFragment) { // nothing received yet? + if(q->iv->mGotFragment) { // nothing received yet? if(q->iv->mGotLastMsg) { //mState = States::CHECK_FRAMES; mWaitTimeout = mWaitTimeout_min; } } else if(mFirstTry) { DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINTLN(F("second try")); + DBGPRINT(String(millis() - mWaitTimeout_min + timeout_min)); + DBGPRINTLN(F("ms - second try")); mFirstTry = false; - if(!testMode) + if(!mHeu.getTestModeEnabled()) q->iv->radioStatistics.retransmits++; // got nothing mState = States::START; break; @@ -119,7 +117,7 @@ class Communication : public CommQueue<> { break; case States::CHECK_FRAMES: { - if(!q->iv->radio->get()) { // radio buffer empty + if(!q->iv->radio->get() || ((q->iv->mGotFragment) && (0 == q->attempts))) { // radio buffer empty cmdDone(); DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("request timeout: ")); @@ -127,18 +125,12 @@ class Communication : public CommQueue<> { DBGPRINTLN(F("ms")); if(!q->iv->mGotFragment) { - if(!testMode) - q->iv->radioStatistics.rxFailNoAnser++; // got nothing - mHeu.setGotNothing(q->iv); if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, (q->iv->config->frequency*FREQ_STEP_KHZ + HOY_BASE_FREQ_KHZ)); mWaitTimeout = millis() + 1000; } - } else { - if(!testMode) - q->iv->radioStatistics.rxFail++; } - mState = States::RESET; + closeRequest(q->iv, false); break; } @@ -169,7 +161,7 @@ class Communication : public CommQueue<> { ah::dumpBuf(p->packet, p->len); if(checkIvSerial(&p->packet[1], q->iv)) { - if(!testMode) + if(!mHeu.getTestModeEnabled()) q->iv->radioStatistics.frmCnt++; if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command @@ -182,7 +174,7 @@ class Communication : public CommQueue<> { parseMiFrame(p, q); } } else { - if(!testMode) + if(!mHeu.getTestModeEnabled()) q->iv->radioStatistics.rxFail++; // got no complete payload DPRINTLN(DBG_WARN, F("Inverter serial does not match")); mWaitTimeout = millis() + timeout; @@ -191,13 +183,9 @@ class Communication : public CommQueue<> { q->iv->radio->mBufCtrl.pop(); yield(); } - if(0 == q->attempts) { - if(!testMode) - q->iv->radioStatistics.rxFail++; // got no complete payload - mHeu.setGotFragment(q->iv); - cmdDone(true); - mState = States::RESET; - } else + if((0 == q->attempts) && (!q->iv->mGotFragment)) + closeRequest(q->iv, false); + else mState = nextState; } @@ -238,14 +226,12 @@ class Communication : public CommQueue<> { return; } - mHeu.setGotAll(q->iv); - compilePayload(q, testMode); + compilePayload(q); if(NULL != mCbPayload) (mCbPayload)(q->cmd, q->iv); - cmdDone(true); // remove done request - mState = States::RESET; // everything ok, next request + closeRequest(q->iv); break; } }); @@ -329,7 +315,7 @@ class Communication : public CommQueue<> { q->iv->actPowerLimit = 0xffff; // unknown, readback current value } - inline void compilePayload(const queue_s *q, bool testMode) { + inline void compilePayload(const queue_s *q) { uint16_t crc = 0xffff, crcRcv = 0x0000; for(uint8_t i = 0; i < mMaxFrameId; i++) { if(i == (mMaxFrameId - 1)) { @@ -345,7 +331,7 @@ class Communication : public CommQueue<> { DBGPRINT(F("CRC Error ")); if(q->attempts == 0) { DBGPRINTLN(F("-> Fail")); - if(!testMode) + if(!mHeu.getTestModeEnabled()) q->iv->radioStatistics.rxFail++; // got fragments but not complete response cmdDone(); } else @@ -391,14 +377,11 @@ class Communication : public CommQueue<> { DPRINT(DBG_ERROR, F("plausibility check failed, expected ")); DBGPRINT(String(rec->pyldLen)); DBGPRINTLN(F(" bytes")); - if(!testMode) + if(!mHeu.getTestModeEnabled()) q->iv->radioStatistics.rxFail++; return; } - if(!testMode) - q->iv->radioStatistics.rxSuccess++; - rec->ts = q->ts; for (uint8_t i = 0; i < rec->length; i++) { q->iv->addValue(i, mPayload, rec); @@ -426,15 +409,36 @@ class Communication : public CommQueue<> { mWaitTimeout = millis() + SINGLEFR_TIMEOUT; // timeout mState = States::WAIT; } else { - mHeu.setGotFragment(q->iv); - q->iv->radioStatistics.rxFail++; // got no complete payload add(q, true); - cmdDone(true); - mState = States::RESET; + closeRequest(q->iv, false); } } private: + void closeRequest(Inverter<> *iv, bool succeeded = true) { + if(succeeded) { + mHeu.setGotAll(iv); + if(!mHeu.getTestModeEnabled()) + iv->radioStatistics.rxSuccess++; + cmdDone(true); + } else if(iv->mGotFragment) { + mHeu.setGotFragment(iv); + if(!mHeu.getTestModeEnabled()) + iv->radioStatistics.rxFail++; // got no complete payload + cmdDone(true); + } else { + mHeu.setGotNothing(iv); + if(!mHeu.getTestModeEnabled()) + iv->radioStatistics.rxFailNoAnser++; // got nothing + cmdDone(); + } + iv->mGotFragment = false; + iv->mGotLastMsg = false; + iv->miMultiParts = 0; + mFirstTry = false; // for correct reset + mState = States::RESET; + } + inline void miHwDecode(packet_t *p, const queue_s *q) { record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_All); // choose the record structure rec->ts = q->ts; @@ -545,16 +549,10 @@ class Communication : public CommQueue<> { (mCbPayload)(InverterDevInform_Simple, q->iv); q->iv->miMultiParts++; } - if(q->iv->miMultiParts > 5) { - cmdDone(true); - mState = States::RESET; - q->iv->radioStatistics.rxSuccess++; - mHeu.setGotAll(q->iv); - q->iv->miMultiParts = 0; - } else { - mHeu.setGotFragment(q->iv); + if(q->iv->miMultiParts > 5) + closeRequest(q->iv, true); + else mState = States::WAIT; - } /*if (mPayload[iv->id].multi_parts > 5) { iv->setQueuedCmdFinished(); @@ -571,7 +569,6 @@ class Communication : public CommQueue<> { inline void miDataDecode(packet_t *p, const queue_s *q) { record_t<> *rec = q->iv->getRecordStruct(RealTimeRunData_Debug); // choose the parser rec->ts = q->ts; - q->iv->radioStatistics.rxSuccess++; mState = States::RESET; uint8_t datachan = ( p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES) || p->packet[0] == (MI_REQ_4CH + ALL_FRAMES) ) ? CH1 : @@ -613,7 +610,7 @@ class Communication : public CommQueue<> { //mPayload[iv->id].retransmits = 0; // reserve retransmissions for each response //mPayload[iv->id].complete = false; miNextRequest((p->packet[0] - ALL_FRAMES + 1), q); - mHeu.setGotFragment(q->iv); + //mHeu.setGotFragment(q->iv); } else { miComplete(q->iv); } @@ -621,7 +618,7 @@ class Communication : public CommQueue<> { //addImportant(q->iv, MI_REQ_CH2); miNextRequest(MI_REQ_CH2, q); //use also miMultiParts here for better statistics? - mHeu.setGotFragment(q->iv); + //mHeu.setGotFragment(q->iv); } else { // first data msg for 1ch, 2nd for 2ch miComplete(q->iv); } @@ -721,7 +718,7 @@ class Communication : public CommQueue<> { } - inline void miComplete(Inverter<> *iv) { + void miComplete(Inverter<> *iv) { if (*mSerialDebug) { DPRINT_IVID(DBG_INFO, iv->id); DBGPRINTLN(F("got all data msgs")); @@ -749,12 +746,14 @@ class Communication : public CommQueue<> { // update status state-machine, if (ac_pow) iv->isProducing(); - mHeu.setGotAll(iv); - cmdDone(true); + closeRequest(iv, true); + + //mHeu.setGotAll(iv); + //cmdDone(true); if(NULL != mCbPayload) (mCbPayload)(RealTimeRunData_Debug, iv); - mState = States::RESET; // everything ok, next request + //mState = States::RESET; // everything ok, next request } private: @@ -775,7 +774,6 @@ class Communication : public CommQueue<> { uint32_t mWaitTimeout = 0; uint32_t mWaitTimeout_min = 0; std::array mLocalBuf; - //bool mGotFragment = false; bool mFirstTry = false; uint8_t mMaxFrameId; uint8_t mPayload[MAX_BUFFER]; diff --git a/src/web/html/update.html b/src/web/html/update.html index 214bc19f..fb748ffe 100644 --- a/src/web/html/update.html +++ b/src/web/html/update.html @@ -12,9 +12,12 @@ Select firmware file (*.bin)
- +
+ {#HTML_FOOTER} From 7c2beab9a70ddf99a93bc4d7393ec54797845aa0 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 19 Nov 2023 16:58:34 +0100 Subject: [PATCH 174/267] small fixes --- src/hm/Communication.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index af288c9a..e26cac39 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -46,8 +46,8 @@ class Communication : public CommQueue<> { if(!valid) return; // empty - uint16_t timeout = (q->iv->ivGen = IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment && q->iv->mGotLastMsg) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT); - uint16_t timeout_min = (q->iv->ivGen = IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT); + uint16_t timeout = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment && q->iv->mGotLastMsg) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT); + uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT); switch(mState) { case States::RESET: @@ -624,7 +624,7 @@ class Communication : public CommQueue<> { } } - inline void miNextRequest(uint8_t cmd, const queue_s *q) { + void miNextRequest(uint8_t cmd, const queue_s *q) { incrAttempt(); // if function is called, we got something, and we necessarily need more transmissions for MI types... DPRINT_IVID(DBG_WARN, q->iv->id); DBGPRINT(F("next request (")); @@ -645,7 +645,7 @@ class Communication : public CommQueue<> { }*/ } - inline void miStsConsolidate(const queue_s *q, uint8_t stschan, record_t<> *rec, uint8_t uState, uint8_t uEnum, uint8_t lState = 0, uint8_t lEnum = 0) { + void miStsConsolidate(const queue_s *q, 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 statusMi = 3; // regular status for MI, change to 1 later? if ( uState == 2 ) { From 34dff0b39524ce8564012ba527dffbd65536a7f8 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 19 Nov 2023 17:24:58 +0100 Subject: [PATCH 175/267] small changes added Radio DTU to /system --- src/hm/radio.h | 4 ++++ src/web/RestApi.h | 3 ++- src/web/html/system.html | 8 ++++++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/hm/radio.h b/src/hm/radio.h index ddba0b50..c67186d7 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -61,6 +61,10 @@ class Radio { sendPacket(iv, 24, isRetransmit); } + uint32_t getDTUSn(void) { + return mDtuSn; + } + public: std::queue mBufCtrl; diff --git a/src/web/RestApi.h b/src/web/RestApi.h index f6d40a3a..59a21ca5 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -548,6 +548,7 @@ class RestApi { void getRadioCmtInfo(JsonObject obj) { obj[F("en")] = (bool) mConfig->cmt.enabled; obj[F("isconnected")] = mRadioCmt->isConnected(); + obj[F("sn")] = String(mRadioCmt->getDTUSn(), HEX); } #endif @@ -555,7 +556,7 @@ class RestApi { obj[F("en")] = (bool) mConfig->nrf.enabled; obj[F("isconnected")] = mRadioNrf->isChipConnected(); obj[F("dataRate")] = mRadioNrf->getDataRate(); - //obj[F("isPVariant")] = mRadioNrf->isPVariant(); + obj[F("sn")] = String(mRadioCmt->getDTUSn(), HEX); } void getSerial(JsonObject obj) { diff --git a/src/web/html/system.html b/src/web/html/system.html index a310890d..b5596c7b 100644 --- a/src/web/html/system.html +++ b/src/web/html/system.html @@ -50,7 +50,8 @@ if(obj.radioNrf.en) { lines = [ tr("NRF24L01", badge(obj.radioNrf.isconnected, ((obj.radioNrf.isconnected) ? "" : "not ") + "connected")), - tr("NRF24 Data Rate", dr[obj.radioNrf.dataRate] + "bps") + tr("NRF24 Data Rate", dr[obj.radioNrf.dataRate] + "bps"), + tr("DTU Radio ID", obj.radioNrf.sn) ]; } else lines = [tr("NRF24L01", badge(false, "not enabled"))]; @@ -64,7 +65,10 @@ /*IF_ESP32*/ if(obj.radioCmt.en) { - cmt = [tr("CMT2300A", badge(obj.radioCmt.isconnected, ((obj.radioCmt.isconnected) ? "" : "not ") + "connected"))]; + cmt = [ + tr("CMT2300A", badge(obj.radioCmt.isconnected, ((obj.radioCmt.isconnected) ? "" : "not ") + "connected")), + tr("DTU Radio ID", obj.radioCmt.sn) + ]; } else cmt = [tr("CMT2300A", badge(false, "not enabled"))]; From bac4301b8adc0b452abc70e9c9ef4e96b71090a9 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 20 Nov 2023 20:30:59 +0100 Subject: [PATCH 176/267] 0.8.1011 * optimized communication * repaired statistics * fixed reboot --- src/hm/Communication.h | 180 +++++++++++++++++++++++++---------------- src/hm/Heuristic.h | 2 +- 2 files changed, 113 insertions(+), 69 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index e26cac39..91d10bed 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -46,7 +46,7 @@ class Communication : public CommQueue<> { if(!valid) return; // empty - uint16_t timeout = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment && q->iv->mGotLastMsg) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT); + uint16_t timeout = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment && q->iv->mGotLastMsg) || mIsResend) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT; uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT); switch(mState) { @@ -62,7 +62,7 @@ class Communication : public CommQueue<> { mHeu.printStatus(q->iv); mHeu.getTxCh(q->iv); q->iv->mGotFragment = false; - q->iv->mGotLastMsg = false; + q->iv->mGotLastMsg = false; if(NULL == q->iv->radio) cmdDone(true); // can't communicate while radio is not defined! mState = States::START; @@ -84,10 +84,13 @@ class Communication : public CommQueue<> { q->iv->radio->sendControlPacket(q->iv, q->cmd, q->iv->powerLimit, false); } else q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); + if(!mHeu.getTestModeEnabled()) q->iv->radioStatistics.txCnt++; mWaitTimeout = millis() + timeout; mWaitTimeout_min = millis() + timeout_min; + mIsResend = false; + mlastTO_min = timeout_min; setAttempt(); mState = States::WAIT; break; @@ -100,10 +103,13 @@ class Communication : public CommQueue<> { mWaitTimeout = mWaitTimeout_min; } } else if(mFirstTry) { - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(String(millis() - mWaitTimeout_min + timeout_min)); - DBGPRINTLN(F("ms - second try")); + if(*mSerialDebug) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(String(millis() - mWaitTimeout_min + mlastTO_min)); + DBGPRINTLN(F("ms - second try")); + } mFirstTry = false; + mlastTO_min = timeout_min; if(!mHeu.getTestModeEnabled()) q->iv->radioStatistics.retransmits++; // got nothing mState = States::START; @@ -117,12 +123,14 @@ class Communication : public CommQueue<> { break; case States::CHECK_FRAMES: { - if(!q->iv->radio->get() || ((q->iv->mGotFragment) && (0 == q->attempts))) { // radio buffer empty - cmdDone(); - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("request timeout: ")); - DBGPRINT(String(millis() - mWaitTimeout + timeout)); - DBGPRINTLN(F("ms")); + if((!q->iv->radio->get() && !mIsResend) || ((q->iv->mGotFragment) && (0 == q->attempts))) { // radio buffer empty + //cmdDone(); + if(*mSerialDebug) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("request timeout: ")); + DBGPRINT(String(millis() - mWaitTimeout + timeout)); + DBGPRINTLN(F("ms")); + } if(!q->iv->mGotFragment) { if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { @@ -130,11 +138,12 @@ class Communication : public CommQueue<> { mWaitTimeout = millis() + 1000; } } - closeRequest(q->iv, false); + closeRequest(q->iv, false, false); break; } mFirstTry = false; // for correct reset + States nextState = States::RESET; while(!q->iv->radio->mBufCtrl.empty()) { packet_t *p = &q->iv->radio->mBufCtrl.front(); @@ -185,8 +194,23 @@ class Communication : public CommQueue<> { } if((0 == q->attempts) && (!q->iv->mGotFragment)) closeRequest(q->iv, false); - else - mState = nextState; + else { + if(q->iv->ivGen != IV_MI) + mState = nextState; + else { + if( q->iv->miMultiParts > 5 && + ((q->cmd == 0x39) && (q->iv->type == INV_TYPE_4CH) || + (q->cmd == MI_REQ_CH2) && (q->iv->type == INV_TYPE_2CH) || + (q->cmd == MI_REQ_CH1) && (q->iv->type == INV_TYPE_1CH))) { + miComplete(q->iv); + //closeRequest(q->iv, q->iv->miMultiParts > 5); + } else if (q->iv->miMultiParts > 5) + closeRequest(q->iv, true); + else { + nextState = States::WAIT; + } + } + } } break; @@ -223,6 +247,8 @@ class Communication : public CommQueue<> { DBGPRINT(String(q->attempts)); DBGPRINTLN(F(" attempts left)")); sendRetransmit(q, framnr-1); + mIsResend = true; + mlastTO_min = timeout_min; return; } @@ -292,7 +318,7 @@ class Communication : public CommQueue<> { record_t<> *rec = q->iv->getRecordStruct(RealTimeRunData_Debug); // choose the record structure rec->ts = q->ts; miStsConsolidate(q, ((p->packet[0] == 0x88) ? 1 : 2), rec, p->packet[10], p->packet[12], p->packet[9], p->packet[11]); - mHeu.setGotFragment(q->iv); + //mHeu.setGotFragment(q->iv); only do this when we are through the cycle? } } @@ -331,9 +357,11 @@ class Communication : public CommQueue<> { DBGPRINT(F("CRC Error ")); if(q->attempts == 0) { DBGPRINTLN(F("-> Fail")); - if(!mHeu.getTestModeEnabled()) + /*if(!mHeu.getTestModeEnabled()) q->iv->radioStatistics.rxFail++; // got fragments but not complete response - cmdDone(); + cmdDone();*/ + closeRequest(q->iv, false, false); + } else DBGPRINTLN(F("-> complete retransmit")); mState = States::RESET; @@ -374,11 +402,15 @@ class Communication : public CommQueue<> { return; } if((rec->pyldLen != len) && (0 != rec->pyldLen)) { - DPRINT(DBG_ERROR, F("plausibility check failed, expected ")); - DBGPRINT(String(rec->pyldLen)); - DBGPRINTLN(F(" bytes")); - if(!mHeu.getTestModeEnabled()) - q->iv->radioStatistics.rxFail++; + if(*mSerialDebug) { + DPRINT(DBG_ERROR, F("plausibility check failed, expected ")); + DBGPRINT(String(rec->pyldLen)); + DBGPRINTLN(F(" bytes")); + } + /*if(!mHeu.getTestModeEnabled()) + q->iv->radioStatistics.rxFail++;*/ + closeRequest(q->iv, false, false); + return; } @@ -415,23 +447,22 @@ class Communication : public CommQueue<> { } private: - void closeRequest(Inverter<> *iv, bool succeeded = true) { + void closeRequest(Inverter<> *iv, bool succeeded = true, bool delCmd = true) { + // ordering of lines is relevant for statistics if(succeeded) { mHeu.setGotAll(iv); if(!mHeu.getTestModeEnabled()) iv->radioStatistics.rxSuccess++; - cmdDone(true); } else if(iv->mGotFragment) { mHeu.setGotFragment(iv); if(!mHeu.getTestModeEnabled()) iv->radioStatistics.rxFail++; // got no complete payload - cmdDone(true); } else { - mHeu.setGotNothing(iv); if(!mHeu.getTestModeEnabled()) iv->radioStatistics.rxFailNoAnser++; // got nothing - cmdDone(); + mHeu.setGotNothing(iv); } + cmdDone(delCmd); iv->mGotFragment = false; iv->mGotLastMsg = false; iv->miMultiParts = 0; @@ -482,11 +513,11 @@ class Communication : public CommQueue<> { q->iv->setValue(i, rec, (float) ((p->packet[(12+2*i)] << 8) + p->packet[(13+2*i)])/1); } q->iv->isConnected = true; - //if(mSerialDebug) { + if(*mSerialDebug) { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("HW_VER is ")); DBGPRINTLN(String((p->packet[24] << 8) + p->packet[25])); - //} + } record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure rec->ts = q->ts; q->iv->setValue(1, rec, (uint32_t) ((p->packet[24] << 8) + p->packet[25])/1); @@ -508,7 +539,7 @@ class Communication : public CommQueue<> { rec->ts = q->ts; q->iv->setValue(0, rec, (uint32_t) ((((p->packet[10] << 8) | p->packet[11]) << 8 | p->packet[12]) << 8 | p->packet[13])/1); - //if(mSerialDebug) { + if(*mSerialDebug) { DPRINT(DBG_INFO,F("HW_FB_TLmValue ")); DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15])); DBGPRINT(F("HW_FB_ReSPRT ")); @@ -519,7 +550,7 @@ class Communication : public CommQueue<> { DBGPRINTLN(String((p->packet[20] << 8) + p->packet[21])); DBGPRINT(F("Matching_APPFW_PN ")); DBGPRINTLN(String((uint32_t) (((p->packet[22] << 8) | p->packet[23]) << 8 | p->packet[24]) << 8 | p->packet[25])); - //} + } if(NULL != mCbPayload) (mCbPayload)(InverterDevInform_All, q->iv); q->iv->miMultiParts +=2; @@ -537,22 +568,23 @@ class Communication : public CommQueue<> { byte[15] byte[16] PNInfoCRC_gusv byte[15] byte[16] PNInfoCRC_gusv (this really is double mentionned in xlsx...) */ - //if(mSerialDebug) { + if(*mSerialDebug) { DPRINT(DBG_INFO,F("APPFW_MINVER ")); DBGPRINTLN(String((p->packet[10] << 8) + p->packet[11])); DBGPRINT(F("HWInfoAddr ")); DBGPRINTLN(String((p->packet[12] << 8) + p->packet[13])); DBGPRINT(F("PNInfoCRC_gusv ")); DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15])); - //} + } if(NULL != mCbPayload) (mCbPayload)(InverterDevInform_Simple, q->iv); q->iv->miMultiParts++; } - if(q->iv->miMultiParts > 5) - closeRequest(q->iv, true); - else - mState = States::WAIT; + //if(q->iv->miMultiParts > 5) + //closeRequest(q->iv, true); + //else + //if(q->iv->miMultiParts < 6) + // mState = States::WAIT; /*if (mPayload[iv->id].multi_parts > 5) { iv->setQueuedCmdFinished(); @@ -569,7 +601,9 @@ class Communication : public CommQueue<> { inline void miDataDecode(packet_t *p, const queue_s *q) { record_t<> *rec = q->iv->getRecordStruct(RealTimeRunData_Debug); // choose the parser rec->ts = q->ts; - mState = States::RESET; + //mState = States::RESET; + if(q->iv->miMultiParts < 6) + q->iv->miMultiParts += 6; uint8_t datachan = ( p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES) || p->packet[0] == (MI_REQ_4CH + ALL_FRAMES) ) ? CH1 : ( p->packet[0] == (MI_REQ_CH2 + ALL_FRAMES) || p->packet[0] == (0x37 + ALL_FRAMES) ) ? CH2 : @@ -605,14 +639,10 @@ class Communication : public CommQueue<> { miStsConsolidate(q, datachan, rec, p->packet[23], p->packet[24]); if (p->packet[0] < (0x39 + ALL_FRAMES) ) { - //addImportant(q->iv, (q->cmd + 1)); - //mPayload[iv->id].txCmd++; - //mPayload[iv->id].retransmits = 0; // reserve retransmissions for each response - //mPayload[iv->id].complete = false; miNextRequest((p->packet[0] - ALL_FRAMES + 1), q); - //mHeu.setGotFragment(q->iv); } else { - miComplete(q->iv); + q->iv->miMultiParts = 7; // indicate we are ready + //miComplete(q->iv); } } else if((p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES)) && (q->iv->type == INV_TYPE_2CH)) { //addImportant(q->iv, MI_REQ_CH2); @@ -620,29 +650,39 @@ class Communication : public CommQueue<> { //use also miMultiParts here for better statistics? //mHeu.setGotFragment(q->iv); } else { // first data msg for 1ch, 2nd for 2ch - miComplete(q->iv); + q->iv->miMultiParts += 6; // indicate we are ready + //miComplete(q->iv); } } void miNextRequest(uint8_t cmd, const queue_s *q) { incrAttempt(); // if function is called, we got something, and we necessarily need more transmissions for MI types... - DPRINT_IVID(DBG_WARN, q->iv->id); - DBGPRINT(F("next request (")); - DBGPRINT(String(q->attempts)); - DBGPRINT(F(" attempts left): 0x")); - DBGHEXLN(cmd); - - //if(q->attempts) { - q->iv->radio->sendCmdPacket(q->iv, cmd, 0x00, true); - q->iv->radioStatistics.retransmits++; - mWaitTimeout = millis() + MI_TIMEOUT; - chgCmd(cmd); - mState = States::WAIT; - /*} else { - add(q, true); - cmdDone(); - mState = States::RESET; - }*/ + if(*mSerialDebug) { + DPRINT_IVID(DBG_WARN, q->iv->id); + DBGPRINT(F("next request (")); + DBGPRINT(String(q->attempts)); + DBGPRINT(F(" attempts left): 0x")); + DBGHEXLN(cmd); + } + + if(q->iv->miMultiParts == 7) { + mHeu.setGotAll(q->iv); + if(!mHeu.getTestModeEnabled()) + q->iv->radioStatistics.rxSuccess++; + } else + mHeu.setGotFragment(q->iv); + /*if(!mHeu.getTestModeEnabled()) + iv->radioStatistics.rxFail++; // got no complete payload*/ + //q->iv->radioStatistics.retransmits++; + q->iv->radio->sendCmdPacket(q->iv, cmd, 0x00, true); + + mWaitTimeout = millis() + MI_TIMEOUT; + mWaitTimeout_min = mWaitTimeout; + q->iv->miMultiParts = 0; + q->iv->mGotFragment = 0; + mIsResend = true; + chgCmd(cmd); + //mState = States::WAIT; } void miStsConsolidate(const queue_s *q, uint8_t stschan, record_t<> *rec, uint8_t uState, uint8_t uEnum, uint8_t lState = 0, uint8_t lEnum = 0) { @@ -694,12 +734,14 @@ class Communication : public CommQueue<> { } } } - //if (mSerialDebug) { + if(*mSerialDebug) { DPRINT(DBG_WARN, F("New state on CH")); DBGPRINT(String(stschan)); DBGPRINT(F(" (")); DBGPRINT(String(prntsts)); DBGPRINT(F("): ")); DBGPRINTLN(q->iv->getAlarmStr(prntsts)); - //} + } + if(!q->iv->miMultiParts) + q->iv->miMultiParts = 1; // indicate we got status info (1+2 ch types) } if (!stsok) { @@ -709,11 +751,11 @@ class Communication : public CommQueue<> { if (q->iv->alarmMesIndex < rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)]) { q->iv->alarmMesIndex = rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)]; // seems there's no status per channel in 3rd gen. models?!? - //if (mSerialDebug) { + if (*mSerialDebug) { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("alarm ID incremented to ")); DBGPRINTLN(String(q->iv->alarmMesIndex)); - //} + } } } @@ -746,7 +788,7 @@ class Communication : public CommQueue<> { // update status state-machine, if (ac_pow) iv->isProducing(); - closeRequest(iv, true); + closeRequest(iv, iv->miMultiParts > 5); //mHeu.setGotAll(iv); //cmdDone(true); @@ -774,7 +816,9 @@ class Communication : public CommQueue<> { uint32_t mWaitTimeout = 0; uint32_t mWaitTimeout_min = 0; std::array mLocalBuf; - bool mFirstTry = false; + bool mFirstTry = false; // see, if we should do a second try + bool mIsResend = false; // we alrady had waited one complete cycle + uint16_t mlastTO_min = DEFAULT_TIMEOUT; // remember timeout_min for correct calculation uint8_t mMaxFrameId; uint8_t mPayload[MAX_BUFFER]; payloadListenerType mCbPayload = NULL; diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index 3ad249b9..49f259e3 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -56,7 +56,7 @@ class Heuristic { if(!mTestEn) { updateQuality(iv, -2); // BAD mTestEn = true; - iv->txRfChId = (iv->txRfChId + 1) % RF_MAX_CHANNEL_ID; + iv->txRfChId = mCycle % RF_MAX_CHANNEL_ID; } } From f417717fc386d5f4e5763aedc517ec2bf61b5a50 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 20 Nov 2023 22:58:57 +0100 Subject: [PATCH 177/267] * optimized heuristic * added option to reduce log size (strip frame payload to relevant field) thx @Oberfritze, @rejoe2 --- src/app.cpp | 6 +-- src/config/settings.h | 9 ++++- src/hm/Communication.h | 86 ++++++++++++++++++++++++----------------- src/hm/Heuristic.h | 43 +++++++++++++-------- src/hm/hmRadio.h | 14 ++++--- src/hm/radio.h | 3 +- src/hms/hmsRadio.h | 14 ++++--- src/web/RestApi.h | 1 + src/web/html/setup.html | 6 ++- src/web/web.h | 1 + 10 files changed, 114 insertions(+), 69 deletions(-) diff --git a/src/app.cpp b/src/app.cpp index daa13307..5359da30 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -32,11 +32,11 @@ void app::setup() { DBGPRINTLN(F("false")); if(mConfig->nrf.enabled) { - mNrfRadio.setup(&mConfig->serial.debug, &mConfig->serial.privacyLog, mConfig->nrf.pinIrq, mConfig->nrf.pinCe, mConfig->nrf.pinCs, mConfig->nrf.pinSclk, mConfig->nrf.pinMosi, mConfig->nrf.pinMiso); + mNrfRadio.setup(&mConfig->serial.debug, &mConfig->serial.privacyLog, &mConfig->serial.printWholeTrace, mConfig->nrf.pinIrq, mConfig->nrf.pinCe, mConfig->nrf.pinCs, mConfig->nrf.pinSclk, mConfig->nrf.pinMosi, mConfig->nrf.pinMiso); } #if defined(ESP32) if(mConfig->cmt.enabled) { - mCmtRadio.setup(&mConfig->serial.debug, &mConfig->serial.privacyLog, mConfig->cmt.pinSclk, mConfig->cmt.pinSdio, mConfig->cmt.pinCsb, mConfig->cmt.pinFcsb, false); + mCmtRadio.setup(&mConfig->serial.debug, &mConfig->serial.privacyLog, &mConfig->serial.printWholeTrace, mConfig->cmt.pinSclk, mConfig->cmt.pinSdio, mConfig->cmt.pinCsb, mConfig->cmt.pinFcsb, false); } #endif #ifdef ETHERNET @@ -55,7 +55,7 @@ void app::setup() { #endif #endif /* defined(ETHERNET) */ - mCommunication.setup(&mTimestamp, &mConfig->serial.debug, &mConfig->serial.privacyLog); + mCommunication.setup(&mTimestamp, &mConfig->serial.debug, &mConfig->serial.privacyLog, &mConfig->serial.printWholeTrace); mCommunication.addPayloadListener(std::bind(&app::payloadEventListener, this, std::placeholders::_1, std::placeholders::_2)); mSys.setup(&mTimestamp, &mConfig->inst); for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { diff --git a/src/config/settings.h b/src/config/settings.h index 1fe7be00..46f0a565 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -30,7 +30,7 @@ * https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html#flash-layout * */ -#define CONFIG_VERSION 2 +#define CONFIG_VERSION 3 #define PROT_MASK_INDEX 0x0001 @@ -117,6 +117,7 @@ typedef struct { bool showIv; bool debug; bool privacyLog; + bool printWholeTrace; } cfgSerial_t; typedef struct { @@ -426,6 +427,7 @@ class settings { mCfg.serial.showIv = false; mCfg.serial.debug = false; mCfg.serial.privacyLog = true; + mCfg.serial.printWholeTrace = true; mCfg.mqtt.port = DEF_MQTT_PORT; snprintf(mCfg.mqtt.broker, MQTT_ADDR_LEN, "%s", DEF_MQTT_BROKER); @@ -476,6 +478,9 @@ class settings { mCfg.inst.iv[i].disNightCom = false; mCfg.inst.iv[i].add2Total = true; } + if(mCfg.configVersion < 3) { + mCfg.serial.printWholeTrace = true; + } } } @@ -620,10 +625,12 @@ class settings { obj[F("show")] = mCfg.serial.showIv; obj[F("debug")] = mCfg.serial.debug; obj[F("prv")] = (bool) mCfg.serial.privacyLog; + obj[F("trc")] = (bool) mCfg.serial.printWholeTrace; } else { getVal(obj, F("show"), &mCfg.serial.showIv); getVal(obj, F("debug"), &mCfg.serial.debug); getVal(obj, F("prv"), &mCfg.serial.privacyLog); + getVal(obj, F("trc"), &mCfg.serial.printWholeTrace); } } diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 91d10bed..f05d7986 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -11,21 +11,23 @@ #include "../utils/crc.h" #include "Heuristic.h" -#define MI_TIMEOUT 250 // timeout for MI type requests -#define FRSTMSG_TIMEOUT 150 // how long to wait for first msg to be received -#define DEFAULT_TIMEOUT 500 // timeout for regular requests -#define SINGLEFR_TIMEOUT 65 // timeout for single frame requests -#define MAX_BUFFER 250 +#define MI_TIMEOUT 250 // timeout for MI type requests +#define FRSTMSG_TIMEOUT 150 // how long to wait for first msg to be received +#define DEFAULT_TIMEOUT 500 // timeout for regular requests +#define SINGLEFR_TIMEOUT 65 // timeout for single frame requests +#define WAIT_GAP_TIMEOUT 200 // timeout after no complete payload +#define MAX_BUFFER 250 typedef std::function *)> payloadListenerType; typedef std::function *)> alarmListenerType; class Communication : public CommQueue<> { public: - void setup(uint32_t *timestamp, bool *serialDebug, bool *privacyMode) { + void setup(uint32_t *timestamp, bool *serialDebug, bool *privacyMode, bool *printWholeTrace) { mTimestamp = timestamp; mPrivacyMode = privacyMode; mSerialDebug = serialDebug; + mPrintWholeTrace = printWholeTrace; } void addImportant(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) { @@ -47,7 +49,7 @@ class Communication : public CommQueue<> { return; // empty uint16_t timeout = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment && q->iv->mGotLastMsg) || mIsResend) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT; - uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT); + uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment || mIsResend)) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT; switch(mState) { case States::RESET: @@ -63,6 +65,7 @@ class Communication : public CommQueue<> { mHeu.getTxCh(q->iv); q->iv->mGotFragment = false; q->iv->mGotLastMsg = false; + mIsResend = false; if(NULL == q->iv->radio) cmdDone(true); // can't communicate while radio is not defined! mState = States::START; @@ -97,7 +100,9 @@ class Communication : public CommQueue<> { case States::WAIT: if(millis() > mWaitTimeout_min) { - if(q->iv->mGotFragment) { // nothing received yet? + if(mIsResend) { // we already have been through... + mWaitTimeout = mWaitTimeout_min; + } else if(q->iv->mGotFragment) { // nothing received yet? if(q->iv->mGotLastMsg) { //mState = States::CHECK_FRAMES; mWaitTimeout = mWaitTimeout_min; @@ -123,8 +128,7 @@ class Communication : public CommQueue<> { break; case States::CHECK_FRAMES: { - if((!q->iv->radio->get() && !mIsResend) || ((q->iv->mGotFragment) && (0 == q->attempts))) { // radio buffer empty - //cmdDone(); + if((!q->iv->radio->get() && !mIsResend) || (((q->iv->mGotFragment) || (mIsResend)) && (0 == q->attempts))) { // radio buffer empty or no more answers if(*mSerialDebug) { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("request timeout: ")); @@ -153,21 +157,26 @@ class Communication : public CommQueue<> { if(p->millis < 100) DBGPRINT(F(" ")); DBGPRINT(String(p->millis)); - DBGPRINT(F("ms ")); + DBGPRINT(F("ms | ")); DBGPRINT(String(p->len)); if((IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen)) { DBGPRINT(F(" CH")); if(3 == p->ch) DBGPRINT(F("0")); DBGPRINT(String(p->ch)); + } else { + DBGPRINT(String(p->rssi)); + DBGPRINT(F("dBm | ")); + } + if(*mPrintWholeTrace) { + if(*mPrivacyMode) + ah::dumpBuf(p->packet, p->len, 1, 8); + else + ah::dumpBuf(p->packet, p->len); + } else { + DBGPRINT(F("frm ")); + DBGHEXLN(p->packet[9]); } - DBGPRINT(F(", ")); - DBGPRINT(String(p->rssi)); - DBGPRINT(F("dBm | ")); - if(*mPrivacyMode) - ah::dumpBuf(p->packet, p->len, 1, 8); - else - ah::dumpBuf(p->packet, p->len); if(checkIvSerial(&p->packet[1], q->iv)) { if(!mHeu.getTestModeEnabled()) @@ -178,7 +187,7 @@ class Communication : public CommQueue<> { nextState = States::CHECK_PACKAGE; } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command parseDevCtrl(p, q); - cmdDone(true); // remove done request + closeRequest(q->iv, true); } else if(IV_MI == q->iv->ivGen) { parseMiFrame(p, q); } @@ -198,19 +207,20 @@ class Communication : public CommQueue<> { if(q->iv->ivGen != IV_MI) mState = nextState; else { - if( q->iv->miMultiParts > 5 && - ((q->cmd == 0x39) && (q->iv->type == INV_TYPE_4CH) || - (q->cmd == MI_REQ_CH2) && (q->iv->type == INV_TYPE_2CH) || - (q->cmd == MI_REQ_CH1) && (q->iv->type == INV_TYPE_1CH))) { + if(q->iv->miMultiParts < 6) { + nextState = States::WAIT; + } else { + if((q->cmd == 0x39) && (q->iv->type == INV_TYPE_4CH) || + (q->cmd == MI_REQ_CH2) && (q->iv->type == INV_TYPE_2CH) || + (q->cmd == MI_REQ_CH1) && (q->iv->type == INV_TYPE_1CH)) { miComplete(q->iv); //closeRequest(q->iv, q->iv->miMultiParts > 5); - } else if (q->iv->miMultiParts > 5) - closeRequest(q->iv, true); - else { - nextState = States::WAIT; } + closeRequest(q->iv, true); } + } + } } break; @@ -240,12 +250,14 @@ class Communication : public CommQueue<> { if(framnr) { setAttempt(); - DPRINT_IVID(DBG_WARN, q->iv->id); - DBGPRINT(F("frame ")); - DBGPRINT(String(framnr)); - DBGPRINT(F(" missing: request retransmit (")); - DBGPRINT(String(q->attempts)); - DBGPRINTLN(F(" attempts left)")); + if(*mSerialDebug) { + DPRINT_IVID(DBG_WARN, q->iv->id); + DBGPRINT(F("frame ")); + DBGPRINT(String(framnr)); + DBGPRINT(F(" missing: request retransmit (")); + DBGPRINT(String(q->attempts)); + DBGPRINTLN(F(" attempts left)")); + } sendRetransmit(q, framnr-1); mIsResend = true; mlastTO_min = timeout_min; @@ -448,7 +460,7 @@ class Communication : public CommQueue<> { private: void closeRequest(Inverter<> *iv, bool succeeded = true, bool delCmd = true) { - // ordering of lines is relevant for statistics + // ordering of lines is relevant for statistics if(succeeded) { mHeu.setGotAll(iv); if(!mHeu.getTestModeEnabled()) @@ -461,11 +473,13 @@ class Communication : public CommQueue<> { if(!mHeu.getTestModeEnabled()) iv->radioStatistics.rxFailNoAnser++; // got nothing mHeu.setGotNothing(iv); + mWaitTimeout = millis() + WAIT_GAP_TIMEOUT; } cmdDone(delCmd); iv->mGotFragment = false; iv->mGotLastMsg = false; iv->miMultiParts = 0; + mIsResend = false; mFirstTry = false; // for correct reset mState = States::RESET; } @@ -788,7 +802,7 @@ class Communication : public CommQueue<> { // update status state-machine, if (ac_pow) iv->isProducing(); - closeRequest(iv, iv->miMultiParts > 5); + //closeRequest(iv, iv->miMultiParts > 5); //mHeu.setGotAll(iv); //cmdDone(true); @@ -812,7 +826,7 @@ class Communication : public CommQueue<> { private: States mState = States::RESET; uint32_t *mTimestamp; - bool *mPrivacyMode, *mSerialDebug; + bool *mPrivacyMode, *mSerialDebug, *mPrintWholeTrace; uint32_t mWaitTimeout = 0; uint32_t mWaitTimeout_min = 0; std::array mLocalBuf; diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index 49f259e3..540d3326 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -12,6 +12,7 @@ #define RF_MAX_CHANNEL_ID 5 #define RF_MAX_QUALITY 4 #define RF_MIN_QUALTIY -6 +#define RF_NA -99 class Heuristic { public: @@ -19,25 +20,29 @@ class Heuristic { if((IV_HMS == iv->ivGen) || (IV_HMT == iv->ivGen)) return 0; // not used for these inverter types - mCycle++; // intended to overflow from time to time - if(mTestEn) { - iv->txRfChId = mCycle % RF_MAX_CHANNEL_ID; - DPRINTLN(DBG_INFO, F("heuristic test mode")); - return id2Ch(iv->txRfChId); - } - - uint8_t id = 0; + uint8_t bestId = 0; int8_t bestQuality = -6; for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) { if(iv->txRfQuality[i] > bestQuality) { bestQuality = iv->txRfQuality[i]; - id = i; + bestId = i; } } - if(bestQuality == -6) - iv->txRfChId = (iv->txRfChId + 1) % RF_MAX_CHANNEL_ID; // next channel - else - iv->txRfChId = id; // best quality channel + + if(mTestEn) { + DPRINTLN(DBG_INFO, F("heuristic test mode")); + mTestIdx = (mTestIdx + 1) % RF_MAX_CHANNEL_ID; + + if (mTestIdx == bestId) + mTestIdx = (mTestIdx + 1) % RF_MAX_CHANNEL_ID; + + // test channel get's quality of best channel (maybe temporarily, see in 'setGotNothing') + mStoredIdx = iv->txRfQuality[mTestIdx]; + iv->txRfQuality[mTestIdx] = bestQuality; + + iv->txRfChId = mTestIdx; + } else + iv->txRfChId = bestId; return id2Ch(iv->txRfChId); } @@ -53,10 +58,15 @@ class Heuristic { } void setGotNothing(Inverter<> *iv) { + if(RF_NA != mStoredIdx) { + // if communication fails on first try with temporarily good level, revert it back to its original level + iv->txRfQuality[iv->txRfChId] = mStoredIdx; + mStoredIdx = RF_NA; + } + if(!mTestEn) { updateQuality(iv, -2); // BAD mTestEn = true; - iv->txRfChId = mCycle % RF_MAX_CHANNEL_ID; } } @@ -100,13 +110,14 @@ class Heuristic { case 3: return 61; case 4: return 75; } - return 0; // standard + return 3; // standard } private: uint8_t mChList[5] = {03, 23, 40, 61, 75}; bool mTestEn = false; - uint8_t mCycle = 0; + uint8_t mTestIdx = 0; + int8_t mStoredIdx = RF_NA; }; diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index a36935f8..18ae549e 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -34,12 +34,13 @@ class HmRadio : public Radio { } ~HmRadio() {} - void setup(bool *serialDebug, bool *privacyMode, uint8_t irq = IRQ_PIN, uint8_t ce = CE_PIN, uint8_t cs = CS_PIN, uint8_t sclk = SCLK_PIN, uint8_t mosi = MOSI_PIN, uint8_t miso = MISO_PIN) { + void setup(bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint8_t irq = IRQ_PIN, uint8_t ce = CE_PIN, uint8_t cs = CS_PIN, uint8_t sclk = SCLK_PIN, uint8_t mosi = MOSI_PIN, uint8_t miso = MISO_PIN) { DPRINTLN(DBG_VERBOSE, F("hmRadio.h:setup")); pinMode(irq, INPUT_PULLUP); mSerialDebug = serialDebug; mPrivacyMode = privacyMode; + mPrintWholeTrace = printWholeTrace; if(*mSerialDebug) { DPRINT(DBG_VERBOSE, F("hmRadio.h : HmRadio():mNrf24(CE_PIN: ")); @@ -293,10 +294,13 @@ class HmRadio : public Radio { DBGPRINT(" CH"); DBGPRINT(String(mTxChIdx)); DBGPRINT(F(" | ")); - if(*mPrivacyMode) - ah::dumpBuf(mTxBuf, len, 1, 4); - else - ah::dumpBuf(mTxBuf, len); + if(*mPrintWholeTrace) { + if(*mPrivacyMode) + ah::dumpBuf(mTxBuf, len, 1, 4); + else + ah::dumpBuf(mTxBuf, len); + } else + DBGHEXLN(mTxBuf[9]); } mNrf24.stopListening(); diff --git a/src/hm/radio.h b/src/hm/radio.h index c67186d7..4fd1fe29 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -111,8 +111,7 @@ class Radio { uint32_t mDtuSn; volatile bool mIrqRcvd; - bool *mSerialDebug; - bool *mPrivacyMode; + bool *mSerialDebug, *mPrivacyMode, *mPrintWholeTrace; uint8_t mTxBuf[MAX_RF_PAYLOAD_SIZE]; }; diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index 1f6044bb..e476bdf1 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -19,11 +19,12 @@ class CmtRadio : public Radio { mCmtAvail = false; } - void setup(bool *serialDebug, bool *privacyMode, uint8_t pinSclk, uint8_t pinSdio, uint8_t pinCsb, uint8_t pinFcsb, bool genDtuSn = true) { + void setup(bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint8_t pinSclk, uint8_t pinSdio, uint8_t pinCsb, uint8_t pinFcsb, bool genDtuSn = true) { mCmt.setup(pinSclk, pinSdio, pinCsb, pinFcsb); reset(genDtuSn); mPrivacyMode = privacyMode; mSerialDebug = serialDebug; + mPrintWholeTrace = printWholeTrace; } void setup(bool *serialDebug, bool *privacyMode, bool genDtuSn = true) { @@ -97,10 +98,13 @@ class CmtRadio : public Radio { DBGPRINT(F("TX ")); DBGPRINT(String(mCmt.getFreqKhz()/1000.0f)); DBGPRINT(F("Mhz | ")); - if(*mPrivacyMode) - ah::dumpBuf(mTxBuf, len, 1, 4); - else - ah::dumpBuf(mTxBuf, len); + if(*mPrintWholeTrace) { + if(*mPrivacyMode) + ah::dumpBuf(mTxBuf, len, 1, 4); + else + ah::dumpBuf(mTxBuf, len); + } else + DBGHEXLN(mTxBuf[9]); } uint8_t status = mCmt.tx(mTxBuf, len); diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 59a21ca5..7a59ac2b 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -563,6 +563,7 @@ class RestApi { obj[F("show_live_data")] = mConfig->serial.showIv; obj[F("debug")] = mConfig->serial.debug; obj[F("priv")] = mConfig->serial.privacyLog; + obj[F("wholeTrace")] = mConfig->serial.printWholeTrace; } void getStaticIp(JsonObject obj) { diff --git a/src/web/html/setup.html b/src/web/html/setup.html index b4d5749d..ec68f65a 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -52,6 +52,10 @@
Privacy Mode
+
+
Print whole traces in Log
+
+
@@ -937,7 +941,7 @@ /*ENDIF_ESP32*/ function parseSerial(obj) { - for(var i of [["serEn", "show_live_data"], ["serDbg", "debug"], ["priv", "priv"]]) + for(var i of [["serEn", "show_live_data"], ["serDbg", "debug"], ["priv", "priv"], ["wholeTrace", "wholeTrace"]]) document.getElementsByName(i[0])[0].checked = obj[i[1]]; } diff --git a/src/web/web.h b/src/web/web.h index 8c9be435..c88d829a 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -560,6 +560,7 @@ class Web { // serial console mConfig->serial.debug = (request->arg("serDbg") == "on"); mConfig->serial.privacyLog = (request->arg("priv") == "on"); + mConfig->serial.printWholeTrace = (request->arg("wholeTrace") == "on"); mConfig->serial.showIv = (request->arg("serEn") == "on"); // display From 8fb7bf1fcff430c3ef53b38a3e0790ad4886cf35 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 20 Nov 2023 23:13:01 +0100 Subject: [PATCH 178/267] 0.8.11 * improved communication, thx @rejoe2 * improved heuristics, thx @rejoe2, @Oberfritze * added option to strip payload of frames to significant area --- src/CHANGES.md | 6 ++++-- src/defines.h | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 0505f7a5..fac3aceb 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,7 +1,9 @@ # Development Changes -## 0.8.11 - 2023-11-19 -* slightly improved communication, thx @rejoe2 +## 0.8.11 - 2023-11-20 +* improved communication, thx @rejoe2 +* improved heuristics, thx @rejoe2, @Oberfritze +* added option to strip payload of frames to significant area ## 0.8.10 - 2023-11-19 * fix Mi and HM inverter communication #1235 diff --git a/src/defines.h b/src/defines.h index f0215013..367b0629 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 1101 +#define VERSION_PATCH 11 //------------------------------------- typedef struct { From ba8d1f3fc34163548bc3fa7f0ce3e676f0a06574 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 20 Nov 2023 23:33:26 +0100 Subject: [PATCH 179/267] fix compile error and warnings --- src/hm/Communication.h | 6 +++--- src/web/RestApi.h | 2 +- src/web/html/serial.html | 7 +++++++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index f05d7986..da4496b1 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -210,9 +210,9 @@ class Communication : public CommQueue<> { if(q->iv->miMultiParts < 6) { nextState = States::WAIT; } else { - if((q->cmd == 0x39) && (q->iv->type == INV_TYPE_4CH) || - (q->cmd == MI_REQ_CH2) && (q->iv->type == INV_TYPE_2CH) || - (q->cmd == MI_REQ_CH1) && (q->iv->type == INV_TYPE_1CH)) { + if(((q->cmd == 0x39) && (q->iv->type == INV_TYPE_4CH)) + || ((q->cmd == MI_REQ_CH2) && (q->iv->type == INV_TYPE_2CH)) + || ((q->cmd == MI_REQ_CH1) && (q->iv->type == INV_TYPE_1CH))) { miComplete(q->iv); //closeRequest(q->iv, q->iv->miMultiParts > 5); } diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 7a59ac2b..4208be30 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -556,7 +556,7 @@ class RestApi { obj[F("en")] = (bool) mConfig->nrf.enabled; obj[F("isconnected")] = mRadioNrf->isChipConnected(); obj[F("dataRate")] = mRadioNrf->getDataRate(); - obj[F("sn")] = String(mRadioCmt->getDTUSn(), HEX); + obj[F("sn")] = String(mRadioNrf->getDTUSn(), HEX); } void getSerial(JsonObject obj) { diff --git a/src/web/html/serial.html b/src/web/html/serial.html index 3f9b4d94..ff25477a 100644 --- a/src/web/html/serial.html +++ b/src/web/html/serial.html @@ -17,6 +17,7 @@
+
@@ -63,6 +64,12 @@ mAutoScroll = !mAutoScroll; this.value = (mAutoScroll) ? "autoscroll" : "manual scroll"; }); + /*document.getElementById("copy").addEventListener("click", function() { + con.select(); + con.setSelectionRange(0, 9999999); + navigator.clipboard.writeText(con.value); + alert("Copied to clipboard"); + });*/ if (!!window.EventSource) { var source = new EventSource('/events'); From 531869737ebad847556853740164ddec8f32eab4 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 20 Nov 2023 23:50:25 +0100 Subject: [PATCH 180/267] 0.8.12 * added button `copy to clipboard` to `/serial` --- src/CHANGES.md | 3 +++ src/defines.h | 2 +- src/web/html/serial.html | 27 ++++++++++++++++++++------- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index fac3aceb..9b17e967 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.8.12 - 2023-11-20 +* added button `copy to clipboard` to `/serial` + ## 0.8.11 - 2023-11-20 * improved communication, thx @rejoe2 * improved heuristics, thx @rejoe2, @Oberfritze diff --git a/src/defines.h b/src/defines.h index 367b0629..a85053d8 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 11 +#define VERSION_PATCH 12 //------------------------------------- typedef struct { diff --git a/src/web/html/serial.html b/src/web/html/serial.html index ff25477a..675ee668 100644 --- a/src/web/html/serial.html +++ b/src/web/html/serial.html @@ -17,7 +17,7 @@
- +
@@ -64,12 +64,25 @@ mAutoScroll = !mAutoScroll; this.value = (mAutoScroll) ? "autoscroll" : "manual scroll"; }); - /*document.getElementById("copy").addEventListener("click", function() { - con.select(); - con.setSelectionRange(0, 9999999); - navigator.clipboard.writeText(con.value); - alert("Copied to clipboard"); - });*/ + document.getElementById("copy").addEventListener("click", function() { + if (window.clipboardData && window.clipboardData.setData) { + return window.clipboardData.setData("Text", text); + } else if (document.queryCommandSupported && document.queryCommandSupported("copy")) { + var ta = document.createElement("textarea"); + ta.textContent = con.value; + ta.style.position = "fixed"; // Prevent scrolling to bottom of page in Microsoft Edge. + document.body.appendChild(ta); + ta.select(); + try { + return document.execCommand("copy"); // Security exception may be thrown by some browsers. + } catch (ex) { + alert("Copy to clipboard failed" + ex); + } finally { + document.body.removeChild(ta); + alert("Copied to clipboard"); + } + } + }); if (!!window.EventSource) { var source = new EventSource('/events'); From baebbf4ff74a5f8c0c6e7f8745f1822f4463b4db Mon Sep 17 00:00:00 2001 From: Wusaweki Date: Sun, 5 Nov 2023 15:58:59 +0100 Subject: [PATCH 181/267] bind inverter rf-quality (from heuristic) to display radio RSSI bars --- src/plugins/Display/Display.h | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index 932c1a8f..557d73cb 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -87,6 +87,7 @@ class Display { uint8_t nrprod = 0; uint8_t nrsleep = 0; + int8_t minQAllInv = 4; Inverter<> *iv; record_t<> *rec; @@ -97,6 +98,15 @@ class Display { if (iv == NULL) continue; + int8_t maxQInv = -6; + for(uint8_t ch = 0; ch < RF_MAX_CHANNEL_ID; ch++) { + int8_t q = iv->txRfQuality[ch]; + if (q > maxQInv) + maxQInv = q; + } + if (maxQInv < minQAllInv) + minQAllInv = maxQInv; + rec = iv->getRecordStruct(RealTimeRunData_Debug); if (iv->isProducing()) @@ -123,7 +133,7 @@ class Display { mDisplayData.RadioSymbol = mHmRadio->isChipConnected(); mDisplayData.WifiSymbol = (WiFi.status() == WL_CONNECTED); mDisplayData.MQTTSymbol = mApp->getMqttIsConnected(); - mDisplayData.RadioRSSI = (0 < mDisplayData.nrProducing) ? 0 : SCHAR_MIN; // Workaround as NRF24 has no RSSI. Could be approximated by transmisson error heuristic in the future + mDisplayData.RadioRSSI = (0 < mDisplayData.nrProducing) ? ivQuality2RadioRSSI(minQAllInv) : SCHAR_MIN; // Workaround as NRF24 has no RSSI. Approximation by quality levels from heuristic function mDisplayData.WifiRSSI = (WiFi.status() == WL_CONNECTED) ? WiFi.RSSI() : SCHAR_MIN; mDisplayData.ipAddress = WiFi.localIP(); time_t utc= mApp->getTimestamp(); @@ -148,6 +158,26 @@ class Display { #endif } + // approximate RSSI in dB by invQuality levels from heuristic function (very unscientific but better than nothing :-) ) + int8_t ivQuality2RadioRSSI(int8_t invQuality) { + int8_t pseudoRSSIdB; + switch(invQuality) { + case 4: pseudoRSSIdB = -55; break; + case 3: + case 2: + case 1: pseudoRSSIdB = -65; break; + case 0: + case -1: + case -2: pseudoRSSIdB = -75; break; + case -3: + case -4: + case -5: pseudoRSSIdB = -85; break; + case -6: + default: pseudoRSSIdB = -95; break; + } + return (pseudoRSSIdB); + } + // private member variables IApp *mApp; DisplayData mDisplayData; From d3c0232e06ee0211c9d656c46913b357830e2431 Mon Sep 17 00:00:00 2001 From: Wusaweki Date: Sun, 12 Nov 2023 11:00:28 +0100 Subject: [PATCH 182/267] increase display update rate --- 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 557d73cb..e09b580f 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -66,7 +66,7 @@ class Display { if (mMono != NULL) mMono->loop(mCfg->contrast); - if (mNewPayload || (((++mLoopCnt) % 10) == 0)) { + if (mNewPayload || (((++mLoopCnt) % 5) == 0)) { mNewPayload = false; mLoopCnt = 0; DataScreen(); From 120522582e84779b525ae9aa8b2469afe82cf7a7 Mon Sep 17 00:00:00 2001 From: Wusaweki Date: Sun, 10 Sep 2023 16:35:32 +0200 Subject: [PATCH 183/267] adapt 128x64 to symbolic layout --- src/plugins/Display/Display_Mono.h | 8 +- src/plugins/Display/Display_Mono_128X64.h | 192 ++++++++++++++---- src/plugins/Display/Display_Mono_84X48.h | 21 +- .../u8g2_font_ncenB10_symbols10_ahoy.bdf | 10 +- .../fonts/u8g2_font_ncenB10_symbols10_ahoy.c_ | 6 +- .../u8g2_font_ncenB10_symbols10_ahoy.fon | Bin 1024 -> 1024 bytes 6 files changed, 180 insertions(+), 57 deletions(-) diff --git a/src/plugins/Display/Display_Mono.h b/src/plugins/Display/Display_Mono.h index 49fd18ec..b45b863a 100644 --- a/src/plugins/Display/Display_Mono.h +++ b/src/plugins/Display/Display_Mono.h @@ -109,7 +109,6 @@ const uint8_t u8g2_font_5x8_symbols_ahoy[1052] U8G2_FONT_SECTION("u8g2_font_5x8_ "\206\20\210<\254\342\20]\302(L\246C\30E\0\207\15wD\334X\25\267\341\20\15\21\0\210\16w" "<\214\203RQ\25I\212\324a\20\211\15f\304\213)\213\244,\222\222\245\0\0\0\0"; - const uint8_t u8g2_font_ncenB08_symbols8_ahoy[173] U8G2_FONT_SECTION("u8g2_font_ncenB08_symbols8_ahoy") = "\13\0\3\2\4\4\1\2\5\10\11\0\0\10\0\10\0\0\0\0\0\0\224A\14\207\305\70H\321\222H" "k\334\6B\20\230\305\32\262\60\211\244\266\60T\243\34\326\0C\20\210\305S\243\60\312\302(\214\302(" @@ -118,12 +117,11 @@ const uint8_t u8g2_font_ncenB08_symbols8_ahoy[173] U8G2_FONT_SECTION("u8g2_font_ "Q\4H\14w\307\215Uq\33\16\321\20\1I\21\227\305\311\222aP\245H\221\244H\212\324a\20J" "\5\0\275\0K\5\0\315\0\0\0\0"; -const uint8_t u8g2_font_ncenB10_symbols10_ahoy[207] U8G2_FONT_SECTION("u8g2_font_ncenB10_symbols10_ahoy") = - "\13\0\3\2\4\4\2\2\5\13\13\0\0\13\0\13\0\0\0\0\0\0\266A\15\267\212q\220\42\251\322" +const uint8_t u8g2_font_ncenB10_symbols10_ahoy[220] U8G2_FONT_SECTION("u8g2_font_ncenB10_symbols10_ahoy") = + "\13\0\3\2\4\4\2\2\5\13\13\0\0\13\0\13\0\0\0\0\0\0\303A\15\267\212q\220\42\251\322" "\266\306\275\1B\20\230\236\65da\22Ima\250F\71\254\1C\23\272\272\251\3Q\32\366Q\212\243" "\70\212\243\70\311\221\0D\20\271\252\361\242F:\242#: {\36\16\1E\22\267\212\361\222\14I\242" "\14\332\232\216[RJ\232\12F\25\250\233\221\14I\61I\206$\252%J\250Fa\224%J\71G\30" "\273\312W\316r`T\262DJ\303\64L#%K\304\35\310\342,\3H\27\272\272\217\344P\16\351\210" "\16\354\300<\244C\70,\303 \16!\0I\24\271\252\241\34\336\1-\223\64-\323\62-\323\62\35x" - "\10J\5\0\232\1K\5\0\232\1\0\0\0"; - + "\10J\22\210\232\61Hi\64Di\64DI\226$KeiK\5\0\232\1\0\0\0"; diff --git a/src/plugins/Display/Display_Mono_128X64.h b/src/plugins/Display/Display_Mono_128X64.h index 4ea85d50..bf500668 100644 --- a/src/plugins/Display/Display_Mono_128X64.h +++ b/src/plugins/Display/Display_Mono_128X64.h @@ -12,6 +12,7 @@ class DisplayMono128X64 : public DisplayMono { mEnPowerSave = true; mEnScreenSaver = true; mLuminance = 60; + mExtra = 0; mDispY = 0; mTimeout = DISP_DEFAULT_TIMEOUT; // interval at which to power save (milliseconds) } @@ -37,9 +38,10 @@ class DisplayMono128X64 : public DisplayMono { break; } calcLinePositions(); - printText("Ahoy!", 0, 35); - printText("ahoydtu.de", 2, 20); - printText(mDisplayData->version, 3, 46); + + printText("Ahoy!", l_Ahoy, 0xff); + printText("ahoydtu.de", l_Website, 0xff); + printText(mDisplayData->version, l_Version, 0xff); mDisplay->sendBuffer(); } @@ -56,42 +58,123 @@ class DisplayMono128X64 : public DisplayMono { } void disp(void) { + uint8_t pos, sun_pos, moon_pos; + + // Test + /* + mDisplayData->isSleeping = 1; + mDisplayData->isProducing = 0; + mDisplayData->totalPower = 10000; + mDisplayData->totalYieldDay = 4998; + mDisplayData->totalYieldTotal = 5321; + */ + mDisplay->clearBuffer(); + // set Contrast of the Display to raise the lifetime mDisplay->setContrast(mLuminance); - if ((mDisplayData->totalPower > 0) && (mDisplayData->nrProducing > 0)) { + // print total power + if (mDisplayData->nrProducing > 0) { mTimeout = DISP_DEFAULT_TIMEOUT; mDisplay->setPowerSave(false); if (mDisplayData->totalPower > 999) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%2.2f kW", (mDisplayData->totalPower / 1000)); + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kW", (mDisplayData->totalPower / 1000)); else - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%3.0f W", mDisplayData->totalPower); - - printText(mFmtText, 0); + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f W", mDisplayData->totalPower); + printText(mFmtText, l_TotalPower, 0xff); } else { - printText("offline", 0, 25); + printText("offline", l_TotalPower, 0xff); // check if it's time to enter power saving mode if (mTimeout == 0) mDisplay->setPowerSave(mEnPowerSave); } - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "today: %4.0f Wh", mDisplayData->totalYieldDay); - printText(mFmtText, 1); + // print Date and time + if (0 != mDisplayData->utcTs) + printText(ah::getDateTimeStrShort(gTimezone.toLocal(mDisplayData->utcTs)).c_str(), l_Time, 0xff); - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "total: %.1f kWh", mDisplayData->totalYieldTotal); - printText(mFmtText, 2); + // dynamic status bar, alternatively: + // print ip address + if (!(mExtra % 5) && (mDisplayData->ipAddress)) { + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%s", (mDisplayData->ipAddress).toString().c_str()); + printText(mFmtText, l_Status, 0xff); + } + // print status of inverters + else { + sun_pos = -1; + moon_pos = -1; + setLineFont(l_Status); + if (0 == mDisplayData->nrSleeping + mDisplayData->nrProducing) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "no inverter"); + else if (0 == mDisplayData->nrSleeping) { + snprintf(mFmtText, DISP_FMT_TEXT_LEN, " "); + sun_pos = 0; + } + else if (0 == mDisplayData->nrProducing) { + snprintf(mFmtText, DISP_FMT_TEXT_LEN, " "); + moon_pos = 0; + } + else { + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%2d", mDisplayData->nrProducing); + sun_pos = mDisplay->getStrWidth(mFmtText); + snprintf(mFmtText+2, DISP_FMT_TEXT_LEN, " %2d", mDisplayData->nrSleeping); + moon_pos = mDisplay->getStrWidth(mFmtText); + snprintf(mFmtText+7, DISP_FMT_TEXT_LEN, " "); + } + printText(mFmtText, l_Status, 0xff); + + pos = (mDispWidth - mDisplay->getStrWidth(mFmtText)) / 2; + mDisplay->setFont(u8g2_font_ncenB08_symbols8_ahoy); + if (sun_pos!=-1) + mDisplay->drawStr(pos+sun_pos, mLineYOffsets[l_Status], "G"); // sun + if (moon_pos!=-1) + mDisplay->drawStr(pos+moon_pos, mLineYOffsets[l_Status], "H"); // moon + } - IPAddress ip = WiFi.localIP(); - if (!(mExtra % 10) && (ip)) - printText(ip.toString().c_str(), 3); - else if (!(mExtra % 5)) { - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%d Inverter on", mDisplayData->nrProducing); - printText(mFmtText, 3); - } else if (0 != mDisplayData->utcTs) - printText(ah::getDateTimeStr(gTimezone.toLocal(mDisplayData->utcTs)).c_str(), 3); + // print yields + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%7.0f Wh", mDisplayData->totalYieldDay); + printText(mFmtText, l_YieldDay, 25); + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%7.1f kWh", mDisplayData->totalYieldTotal); + printText(mFmtText, l_YieldTotal, 25); + mDisplay->setFont(u8g2_font_ncenB10_symbols10_ahoy); + mDisplay->drawStr(11, mLineYOffsets[l_YieldDay], "I"); // day + mDisplay->drawStr(11, mLineYOffsets[l_YieldTotal], "D"); // total + + // draw dynamic RSSI bars + int rssi_bar_height = 9; + for (int i=0; i<4;i++) { + int radio_rssi_threshold = -60 - i*10; + int wifi_rssi_threshold = -60 - i*10; + if (mDisplayData->RadioRSSI > radio_rssi_threshold) + mDisplay->drawBox(0, 8+(rssi_bar_height+1)*i, 4-i,rssi_bar_height); + if (mDisplayData->WifiRSSI > wifi_rssi_threshold) + mDisplay->drawBox(mDispWidth-4+i, 8+(rssi_bar_height+1)*i, 4-i,rssi_bar_height); + } + + // draw dynamic antenna and WiFi symbols + mDisplay->setFont(u8g2_font_ncenB10_symbols10_ahoy); + char sym[]=" "; + sym[0] = mDisplayData->RadioSymbol?'A':'E'; // NRF + mDisplay->drawStr(0, mLineYOffsets[l_RSSI], sym); + + if (mDisplayData->MQTTSymbol) + sym[0] = 'J'; // MQTT + else + sym[0] = mDisplayData->WifiSymbol?'B':'F'; // Wifi + mDisplay->drawStr(mDispWidth - mDisplay->getStrWidth(sym), mLineYOffsets[l_RSSI], sym); + mDisplay->sendBuffer(); + + mExtra++; + + /* // just for test + mDisplay->drawPixel(0, 0); + mDisplay->drawPixel(mDispWidth-1, 0); + mDisplay->drawPixel(0, mDispHeight-1); + mDisplay->drawPixel(mDispWidth-1, mDispHeight-1); + */ mDisplay->sendBuffer(); @@ -100,32 +183,61 @@ class DisplayMono128X64 : public DisplayMono { } private: + enum _dispLine { + // start page + l_Website = 0, + l_Ahoy = 2, + l_Version = 4, + // run page + l_Time = 0, + l_Status = 1, + l_TotalPower = 2, + l_YieldDay = 3, + l_YieldTotal = 4, + // run page - rssi bar symbols + l_RSSI = 4, + // End + l_MAX_LINES = 5, + }; + void calcLinePositions() { uint8_t yOff = 0; - for (uint8_t i = 0; i < 4; i++) { - setFont(i); - yOff += (mDisplay->getMaxCharHeight()); + uint8_t i = 0; + uint8_t asc, dsc; + + do { + setLineFont(i); + asc = mDisplay->getAscent(); + yOff += asc; mLineYOffsets[i] = yOff; - } + dsc = mDisplay->getDescent(); + yOff -= dsc; + if (l_Time==i) // prevent time and status line to touch + yOff+=1; // -> one pixels space + i++; + } while(l_MAX_LINES>i); } - inline void setFont(uint8_t line) { - switch (line) { - case 0: - mDisplay->setFont(u8g2_font_ncenB14_tr); - break; - case 3: - mDisplay->setFont(u8g2_font_5x8_symbols_ahoy); - break; - default: - mDisplay->setFont(u8g2_font_ncenB10_tr); - break; - } + inline void setLineFont(uint8_t line) { + if ((line == l_TotalPower) || + (line == l_Ahoy)) + mDisplay->setFont(u8g2_font_ncenB14_tr); + else if ((line == l_YieldDay) || + (line == l_YieldTotal)) + // mDisplay->setFont(u8g2_font_5x8_symbols_ahoy); + mDisplay->setFont(u8g2_font_ncenB10_tr); + else + mDisplay->setFont(u8g2_font_ncenB08_tr); } - void printText(const char *text, uint8_t line, uint8_t dispX = 5) { - setFont(line); - dispX += (mEnScreenSaver) ? (mExtra % 7) : 0; + void printText(const char *text, uint8_t line, uint8_t col=0) { + uint8_t dispX; + + setLineFont(line); + if (0xff == col) + dispX = (mDispWidth - mDisplay->getStrWidth(text)) / 2; // center text + else + dispX = col; mDisplay->drawStr(dispX, mLineYOffsets[line], text); } }; diff --git a/src/plugins/Display/Display_Mono_84X48.h b/src/plugins/Display/Display_Mono_84X48.h index ed540523..47372a48 100644 --- a/src/plugins/Display/Display_Mono_84X48.h +++ b/src/plugins/Display/Display_Mono_84X48.h @@ -47,18 +47,22 @@ class DisplayMono84X48 : public DisplayMono { } void disp(void) { - // Test + mDisplay->clearBuffer(); + + // Layout-Test /* - mDisplayData->nrSleeping = 10; - mDisplayData->nrProducing = 10; + mDisplayData->nrSleeping = 0; + mDisplayData->nrProducing = 1; mDisplayData->totalPower = 12345.67; mDisplayData->totalYieldDay = 12345.67; mDisplayData->totalYieldTotal = 1234; mDisplayData->utcTs += 1000000; + mDisplay->drawPixel(0, 0); + mDisplay->drawPixel(mDispWidth-1, 0); + mDisplay->drawPixel(0, mDispHeight-1); + mDisplay->drawPixel(mDispWidth-1, mDispHeight-1); */ - mDisplay->clearBuffer(); - // print total power if (mDisplayData->nrProducing > 0) { mTimeout = DISP_DEFAULT_TIMEOUT; @@ -91,14 +95,15 @@ class DisplayMono84X48 : public DisplayMono { } // print status of inverters else { - if (0 == mDisplayData->nrSleeping) + if (0 == mDisplayData->nrSleeping + mDisplayData->nrProducing) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "no inverter"); + else if (0 == mDisplayData->nrSleeping) snprintf(mFmtText, DISP_FMT_TEXT_LEN, "\x86"); else if (0 == mDisplayData->nrProducing) snprintf(mFmtText, DISP_FMT_TEXT_LEN, "\x87"); else snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%d\x86 %d\x87", mDisplayData->nrProducing, mDisplayData->nrSleeping); - setLineFont(l_Status); - printText(mFmtText, l_Status, (mDispWidth - mDisplay->getStrWidth(mFmtText)) / 2); + printText(mFmtText, l_Status, 0xff); } // print yields diff --git a/tools/fonts/u8g2_font_ncenB10_symbols10_ahoy.bdf b/tools/fonts/u8g2_font_ncenB10_symbols10_ahoy.bdf index 8fb61063..e72a97b9 100644 --- a/tools/fonts/u8g2_font_ncenB10_symbols10_ahoy.bdf +++ b/tools/fonts/u8g2_font_ncenB10_symbols10_ahoy.bdf @@ -175,8 +175,16 @@ STARTCHAR 074 ENCODING 74 SWIDTH 648 0 DWIDTH 9 0 -BBX 0 0 0 0 +BBX 8 8 0 0 BITMAP +F9 +04 +F2 +09 +E5 +15 +D5 +D5 ENDCHAR STARTCHAR 075 ENCODING 75 diff --git a/tools/fonts/u8g2_font_ncenB10_symbols10_ahoy.c_ b/tools/fonts/u8g2_font_ncenB10_symbols10_ahoy.c_ index 45d3979e..04f29d3a 100644 --- a/tools/fonts/u8g2_font_ncenB10_symbols10_ahoy.c_ +++ b/tools/fonts/u8g2_font_ncenB10_symbols10_ahoy.c_ @@ -4,11 +4,11 @@ Glyphs: 11/11 BBX Build Mode: 0 */ -const uint8_t u8g2_font_ncenB10_symbols10_ahoy[207] U8G2_FONT_SECTION("u8g2_font_ncenB10_symbols10_ahoy") = - "\13\0\3\2\4\4\2\2\5\13\13\0\0\13\0\13\0\0\0\0\0\0\266A\15\267\212q\220\42\251\322" +const uint8_t u8g2_font_ncenB10_symbols10_ahoy[220] U8G2_FONT_SECTION("u8g2_font_ncenB10_symbols10_ahoy") = + "\13\0\3\2\4\4\2\2\5\13\13\0\0\13\0\13\0\0\0\0\0\0\303A\15\267\212q\220\42\251\322" "\266\306\275\1B\20\230\236\65da\22Ima\250F\71\254\1C\23\272\272\251\3Q\32\366Q\212\243" "\70\212\243\70\311\221\0D\20\271\252\361\242F:\242#: {\36\16\1E\22\267\212\361\222\14I\242" "\14\332\232\216[RJ\232\12F\25\250\233\221\14I\61I\206$\252%J\250Fa\224%J\71G\30" "\273\312W\316r`T\262DJ\303\64L#%K\304\35\310\342,\3H\27\272\272\217\344P\16\351\210" "\16\354\300<\244C\70,\303 \16!\0I\24\271\252\241\34\336\1-\223\64-\323\62-\323\62\35x" - "\10J\5\0\232\1K\5\0\232\1\0\0\0"; + "\10J\22\210\232\61Hi\64Di\64DI\226$KeiK\5\0\232\1\0\0\0"; diff --git a/tools/fonts/u8g2_font_ncenB10_symbols10_ahoy.fon b/tools/fonts/u8g2_font_ncenB10_symbols10_ahoy.fon index 8163a65b2e96c83e8d04e99d08caf503bdcdbde8..161e9b923ff928725369273433591d86c3fb573d 100644 GIT binary patch delta 20 ccmZqRXyDjzl$qlv%O}pKqF1j@4rDY2098Z?MF0Q* delta 14 VcmZqRXyDjzlzDO_qy9t#9sne+1abfX From 9647044e496b38637cd8c5bbfd3f0163d1dd0e17 Mon Sep 17 00:00:00 2001 From: Wusaweki Date: Sun, 24 Sep 2023 19:14:43 +0200 Subject: [PATCH 184/267] add motion sensor function for screensaver and remove redundant display code --- src/config/config.h | 6 ++ src/config/settings.h | 12 ++- src/plugins/Display/Display.h | 34 +++++- src/plugins/Display/Display_Mono.h | 46 ++++++-- src/plugins/Display/Display_Mono_128X32.h | 29 +---- src/plugins/Display/Display_Mono_128X64.h | 126 +++++++++------------- src/plugins/Display/Display_Mono_64X48.h | 29 +---- src/plugins/Display/Display_Mono_84X48.h | 27 +---- src/web/RestApi.h | 3 +- src/web/html/setup.html | 58 +++++++--- src/web/web.h | 3 +- 11 files changed, 191 insertions(+), 182 deletions(-) diff --git a/src/config/config.h b/src/config/config.h index 5b17ca9d..4fb78107 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -98,6 +98,9 @@ #ifndef DEF_CMT_IRQ #define DEF_CMT_IRQ 34 #endif + #ifndef DEF_MOTION_SENSOR_PIN + #define DEF_MOTION_SENSOR_PIN DEF_PIN_OFF + #endif #else #ifndef DEF_NRF_CS_PIN #define DEF_NRF_CS_PIN 15 @@ -119,6 +122,9 @@ #ifndef DEF_NRF_SCLK_PIN #define DEF_NRF_SCLK_PIN 14 #endif + #ifndef DEF_MOTION_SENSOR_PIN + #define DEF_MOTION_SENSOR_PIN A0 + #endif #endif #ifndef DEF_LED0 #define DEF_LED0 DEF_PIN_OFF diff --git a/src/config/settings.h b/src/config/settings.h index 46f0a565..058d2546 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -164,7 +164,7 @@ typedef struct { typedef struct { uint8_t type; bool pwrSaveAtIvOffline; - bool pxShift; + uint8_t screenSaver; uint8_t rot; //uint16_t wakeUp; //uint16_t sleepAt; @@ -175,6 +175,7 @@ typedef struct { uint8_t disp_reset; uint8_t disp_busy; uint8_t disp_dc; + uint8_t pirPin; } display_t; typedef struct { @@ -458,7 +459,7 @@ class settings { mCfg.plugin.display.pwrSaveAtIvOffline = false; mCfg.plugin.display.contrast = 60; - mCfg.plugin.display.pxShift = true; + mCfg.plugin.display.screenSaver = 1; // default: 1 .. pixelshift for OLED for downward compatibility mCfg.plugin.display.rot = 0; mCfg.plugin.display.disp_data = DEF_PIN_OFF; // SDA mCfg.plugin.display.disp_clk = DEF_PIN_OFF; // SCL @@ -466,6 +467,7 @@ class settings { mCfg.plugin.display.disp_reset = DEF_PIN_OFF; mCfg.plugin.display.disp_busy = DEF_PIN_OFF; mCfg.plugin.display.disp_dc = DEF_PIN_OFF; + mCfg.plugin.display.pirPin = DEF_MOTION_SENSOR_PIN; } void loadAddedDefaults() { @@ -672,7 +674,7 @@ class settings { JsonObject disp = obj.createNestedObject("disp"); disp[F("type")] = mCfg.plugin.display.type; disp[F("pwrSafe")] = (bool)mCfg.plugin.display.pwrSaveAtIvOffline; - disp[F("pxShift")] = (bool)mCfg.plugin.display.pxShift; + disp[F("screenSaver")] = mCfg.plugin.display.screenSaver; disp[F("rotation")] = mCfg.plugin.display.rot; //disp[F("wake")] = mCfg.plugin.display.wakeUp; //disp[F("sleep")] = mCfg.plugin.display.sleepAt; @@ -683,11 +685,12 @@ class settings { disp[F("reset")] = mCfg.plugin.display.disp_reset; disp[F("busy")] = mCfg.plugin.display.disp_busy; disp[F("dc")] = mCfg.plugin.display.disp_dc; + disp[F("pirPin")] = mCfg.plugin.display.pirPin; } else { JsonObject disp = obj["disp"]; getVal(disp, F("type"), &mCfg.plugin.display.type); getVal(disp, F("pwrSafe"), &mCfg.plugin.display.pwrSaveAtIvOffline); - getVal(disp, F("pxShift"), &mCfg.plugin.display.pxShift); + getVal(disp, F("screenSaver"), &mCfg.plugin.display.screenSaver); getVal(disp, F("rotation"), &mCfg.plugin.display.rot); //mCfg.plugin.display.wakeUp = disp[F("wake")]; //mCfg.plugin.display.sleepAt = disp[F("sleep")]; @@ -698,6 +701,7 @@ class settings { getVal(disp, F("reset"), &mCfg.plugin.display.disp_reset); getVal(disp, F("busy"), &mCfg.plugin.display.disp_busy); getVal(disp, F("dc"), &mCfg.plugin.display.disp_dc); + getVal(disp, F("pirPin"), &mCfg.plugin.display.pirPin); } } diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index e09b580f..c6d4dc03 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -53,9 +53,20 @@ class Display { default: mMono = NULL; break; } if(mMono) { - mMono->config(mCfg->pwrSaveAtIvOffline, mCfg->pxShift, mCfg->contrast); + mMono->config(mCfg->pwrSaveAtIvOffline, mCfg->screenSaver, mCfg->contrast); mMono->init(mCfg->type, mCfg->rot, mCfg->disp_cs, mCfg->disp_dc, 0xff, mCfg->disp_clk, mCfg->disp_data, &mDisplayData); } + + // setup PIR pin for motion sensor +#ifdef ESP32 + if ((mCfg->screenSaver == 2) && (mCfg->pirPin != DEF_PIN_OFF)) + pinMode(mCfg->pirPin, INPUT); +#endif +#ifdef ESP8266 + if ((mCfg->screenSaver == 2) && (mCfg->pirPin != DEF_PIN_OFF) && (mCfg->pirPin != A0)) + pinMode(mCfg->pirPin, INPUT); +#endif + } void payloadEventListener(uint8_t cmd) { @@ -64,19 +75,19 @@ class Display { void tickerSecond() { if (mMono != NULL) - mMono->loop(mCfg->contrast); + mMono->loop(mCfg->contrast, motionSensorActive()); if (mNewPayload || (((++mLoopCnt) % 5) == 0)) { + DataScreen(); mNewPayload = false; mLoopCnt = 0; - DataScreen(); } #if defined(ESP32) mEpaper.tickerSecond(); #endif } - private: + private: void DataScreen() { if (mCfg->type == 0) return; @@ -158,6 +169,21 @@ class Display { #endif } + bool motionSensorActive() { + if ((mCfg->screenSaver == 2) && (mCfg->pirPin != DEF_PIN_OFF)) { +#if defined(ESP8266) + if (mCfg->pirPin == A0) + return((analogRead(A0) >= 512)); + else + return(digitalRead(mCfg->pirPin)); +#elif defined(ESP32) + return(digitalRead(mCfg->pirPin)); +#endif + } + else + return(false); + } + // approximate RSSI in dB by invQuality levels from heuristic function (very unscientific but better than nothing :-) ) int8_t ivQuality2RadioRSSI(int8_t invQuality) { int8_t pseudoRSSIdB; diff --git a/src/plugins/Display/Display_Mono.h b/src/plugins/Display/Display_Mono.h index b45b863a..a38be58f 100644 --- a/src/plugins/Display/Display_Mono.h +++ b/src/plugins/Display/Display_Mono.h @@ -18,16 +18,49 @@ #endif #include "../../utils/helper.h" #include "Display_data.h" +#include "../../utils/dbg.h" class DisplayMono { public: DisplayMono() {}; virtual void init(uint8_t type, uint8_t rot, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, DisplayData *displayData) = 0; - virtual void config(bool enPowerSave, bool enScreenSaver, uint8_t lum) = 0; - virtual void loop(uint8_t lum) = 0; + virtual void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum) = 0; virtual void disp(void) = 0; + // Common loop function, manages display on/off functions for powersave and screensaver with motionsensor + // can be overridden by subclasses + virtual void loop(uint8_t lum, bool motion) { + + bool dispConditions = (!mEnPowerSave || (mDisplayData->nrProducing > 0)) && + ((mScreenSaver != 2) || motion); // screensaver 2 .. motionsensor + + if (mDisplayActive) { + if (!dispConditions) { + if ((millis() - mStarttime) > DISP_DEFAULT_TIMEOUT * 1000ul) { // switch display off after timeout + mDisplayActive = false; + mDisplay->setPowerSave(true); + DBGPRINTLN("**** Display off ****"); + } + } + else + mStarttime = millis(); // keep display on + } + else { + if (dispConditions) { + mDisplayActive = true; // switch display on + mStarttime = millis(); + mDisplay->setPowerSave(false); + DBGPRINTLN("**** Display on ****"); + } + } + + if(mLuminance != lum) { + mLuminance = lum; + mDisplay->setContrast(mLuminance); + } + } + protected: U8G2* mDisplay; DisplayData *mDisplayData; @@ -36,17 +69,17 @@ class DisplayMono { uint16_t mDispWidth; uint16_t mDispHeight; - bool mEnPowerSave, mEnScreenSaver; + bool mEnPowerSave; + uint8_t mScreenSaver = 1; // 0 .. off; 1 .. pixelShift; 2 .. motionsensor uint8_t mLuminance; uint8_t mLoopCnt; uint8_t mLineXOffsets[5] = {}; uint8_t mLineYOffsets[5] = {}; - uint16_t mDispY; - uint8_t mExtra; - uint16_t mTimeout; + uint32_t mStarttime = millis(); + bool mDisplayActive = true; // always start with display on char mFmtText[DISP_FMT_TEXT_LEN]; // Common initialization function to be called by subclasses @@ -55,6 +88,7 @@ class DisplayMono { mType = type; mDisplayData = displayData; mDisplay->begin(); + mDisplay->setPowerSave(false); // always start with display on mDisplay->setContrast(mLuminance); mDisplay->clearBuffer(); mDispWidth = mDisplay->getDisplayWidth(); diff --git a/src/plugins/Display/Display_Mono_128X32.h b/src/plugins/Display/Display_Mono_128X32.h index 7012604b..ffb96384 100644 --- a/src/plugins/Display/Display_Mono_128X32.h +++ b/src/plugins/Display/Display_Mono_128X32.h @@ -9,17 +9,12 @@ class DisplayMono128X32 : public DisplayMono { public: DisplayMono128X32() : DisplayMono() { - mEnPowerSave = true; - mEnScreenSaver = true; - mLuminance = 60; mExtra = 0; - mDispY = 0; - mTimeout = DISP_DEFAULT_TIMEOUT; // interval at which to power save (milliseconds) } - void config(bool enPowerSave, bool enScreenSaver, uint8_t lum) { + void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum) { mEnPowerSave = enPowerSave; - mEnScreenSaver = enScreenSaver; + mScreenSaver = screenSaver; mLuminance = lum; } @@ -33,18 +28,6 @@ class DisplayMono128X32 : public DisplayMono { mDisplay->sendBuffer(); } - void loop(uint8_t lum) { - if (mEnPowerSave) { - if (mTimeout != 0) - mTimeout--; - } - - if(mLuminance != lum) { - mLuminance = lum; - mDisplay->setContrast(mLuminance); - } - } - void disp(void) { mDisplay->clearBuffer(); @@ -53,8 +36,6 @@ class DisplayMono128X32 : public DisplayMono { mDisplay->setContrast(mLuminance); if ((mDisplayData->totalPower > 0) && (mDisplayData->nrProducing > 0)) { - mTimeout = DISP_DEFAULT_TIMEOUT; - mDisplay->setPowerSave(false); if (mDisplayData->totalPower > 999) snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%2.2f kW", (mDisplayData->totalPower / 1000)); else @@ -63,9 +44,6 @@ class DisplayMono128X32 : public DisplayMono { printText(mFmtText, 0); } else { printText("offline", 0); - // check if it's time to enter power saving mode - if (mTimeout == 0) - mDisplay->setPowerSave(mEnPowerSave); } snprintf(mFmtText, DISP_FMT_TEXT_LEN, "today: %4.0f Wh", mDisplayData->totalYieldDay); @@ -85,7 +63,6 @@ class DisplayMono128X32 : public DisplayMono { mDisplay->sendBuffer(); - mDispY = 0; mExtra++; } @@ -131,7 +108,7 @@ class DisplayMono128X32 : public DisplayMono { void printText(const char *text, uint8_t line) { setFont(line); - uint8_t dispX = mLineXOffsets[line] + ((mEnScreenSaver) ? (mExtra % 7) : 0); + uint8_t dispX = mLineXOffsets[line] + ((mScreenSaver==1) ? (mExtra % 7) : 0); if (isTwoRowLine(line)) { String stringText = String(text); diff --git a/src/plugins/Display/Display_Mono_128X64.h b/src/plugins/Display/Display_Mono_128X64.h index bf500668..dae49ac0 100644 --- a/src/plugins/Display/Display_Mono_128X64.h +++ b/src/plugins/Display/Display_Mono_128X64.h @@ -9,17 +9,12 @@ class DisplayMono128X64 : public DisplayMono { public: DisplayMono128X64() : DisplayMono() { - mEnPowerSave = true; - mEnScreenSaver = true; - mLuminance = 60; mExtra = 0; - mDispY = 0; - mTimeout = DISP_DEFAULT_TIMEOUT; // interval at which to power save (milliseconds) } - void config(bool enPowerSave, bool enScreenSaver, uint8_t lum) { + void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum) { mEnPowerSave = enPowerSave; - mEnScreenSaver = enScreenSaver; + mScreenSaver = screenSaver; mLuminance = lum; } @@ -45,41 +40,29 @@ class DisplayMono128X64 : public DisplayMono { mDisplay->sendBuffer(); } - void loop(uint8_t lum) { - if (mEnPowerSave) { - if (mTimeout != 0) - mTimeout--; - } - - if(mLuminance != lum) { - mLuminance = lum; - mDisplay->setContrast(mLuminance); - } - } - void disp(void) { uint8_t pos, sun_pos, moon_pos; - // Test + mDisplay->clearBuffer(); + + // Layout-Test /* - mDisplayData->isSleeping = 1; - mDisplayData->isProducing = 0; - mDisplayData->totalPower = 10000; - mDisplayData->totalYieldDay = 4998; - mDisplayData->totalYieldTotal = 5321; + mDisplayData->nrSleeping = 10; + mDisplayData->nrProducing = 10; + mDisplayData->totalPower = 99990; + mDisplayData->totalYieldDay = 8888; + mDisplayData->totalYieldTotal = 9999; + mDisplay->drawPixel(0, 0); + mDisplay->drawPixel(mDispWidth-1, 0); + mDisplay->drawPixel(0, mDispHeight-1); + mDisplay->drawPixel(mDispWidth-1, mDispHeight-1); */ - mDisplay->clearBuffer(); - - // set Contrast of the Display to raise the lifetime mDisplay->setContrast(mLuminance); // print total power if (mDisplayData->nrProducing > 0) { - mTimeout = DISP_DEFAULT_TIMEOUT; - mDisplay->setPowerSave(false); - if (mDisplayData->totalPower > 999) snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kW", (mDisplayData->totalPower / 1000)); else @@ -87,9 +70,6 @@ class DisplayMono128X64 : public DisplayMono { printText(mFmtText, l_TotalPower, 0xff); } else { printText("offline", l_TotalPower, 0xff); - // check if it's time to enter power saving mode - if (mTimeout == 0) - mDisplay->setPowerSave(mEnPowerSave); } // print Date and time @@ -119,9 +99,9 @@ class DisplayMono128X64 : public DisplayMono { } else { snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%2d", mDisplayData->nrProducing); - sun_pos = mDisplay->getStrWidth(mFmtText); + sun_pos = mDisplay->getStrWidth(mFmtText) + 1; snprintf(mFmtText+2, DISP_FMT_TEXT_LEN, " %2d", mDisplayData->nrSleeping); - moon_pos = mDisplay->getStrWidth(mFmtText); + moon_pos = mDisplay->getStrWidth(mFmtText) + 1; snprintf(mFmtText+7, DISP_FMT_TEXT_LEN, " "); } printText(mFmtText, l_Status, 0xff); @@ -129,56 +109,47 @@ class DisplayMono128X64 : public DisplayMono { pos = (mDispWidth - mDisplay->getStrWidth(mFmtText)) / 2; mDisplay->setFont(u8g2_font_ncenB08_symbols8_ahoy); if (sun_pos!=-1) - mDisplay->drawStr(pos+sun_pos, mLineYOffsets[l_Status], "G"); // sun + mDisplay->drawStr(pos + sun_pos + pixelshift(), mLineYOffsets[l_Status], "G"); // sun if (moon_pos!=-1) - mDisplay->drawStr(pos+moon_pos, mLineYOffsets[l_Status], "H"); // moon + mDisplay->drawStr(pos + moon_pos + pixelshift(), mLineYOffsets[l_Status], "H"); // moon } // print yields + mDisplay->setFont(u8g2_font_ncenB10_symbols10_ahoy); + mDisplay->drawStr(15 + pixelshift(), mLineYOffsets[l_YieldDay], "I"); // day + mDisplay->drawStr(15 + pixelshift(), mLineYOffsets[l_YieldTotal], "D"); // total snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%7.0f Wh", mDisplayData->totalYieldDay); printText(mFmtText, l_YieldDay, 25); snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%7.1f kWh", mDisplayData->totalYieldTotal); printText(mFmtText, l_YieldTotal, 25); - mDisplay->setFont(u8g2_font_ncenB10_symbols10_ahoy); - mDisplay->drawStr(11, mLineYOffsets[l_YieldDay], "I"); // day - mDisplay->drawStr(11, mLineYOffsets[l_YieldTotal], "D"); // total - - // draw dynamic RSSI bars - int rssi_bar_height = 9; - for (int i=0; i<4;i++) { - int radio_rssi_threshold = -60 - i*10; - int wifi_rssi_threshold = -60 - i*10; - if (mDisplayData->RadioRSSI > radio_rssi_threshold) - mDisplay->drawBox(0, 8+(rssi_bar_height+1)*i, 4-i,rssi_bar_height); - if (mDisplayData->WifiRSSI > wifi_rssi_threshold) - mDisplay->drawBox(mDispWidth-4+i, 8+(rssi_bar_height+1)*i, 4-i,rssi_bar_height); - } - // draw dynamic antenna and WiFi symbols - mDisplay->setFont(u8g2_font_ncenB10_symbols10_ahoy); - char sym[]=" "; - sym[0] = mDisplayData->RadioSymbol?'A':'E'; // NRF - mDisplay->drawStr(0, mLineYOffsets[l_RSSI], sym); - - if (mDisplayData->MQTTSymbol) - sym[0] = 'J'; // MQTT - else - sym[0] = mDisplayData->WifiSymbol?'B':'F'; // Wifi - mDisplay->drawStr(mDispWidth - mDisplay->getStrWidth(sym), mLineYOffsets[l_RSSI], sym); - mDisplay->sendBuffer(); - - mExtra++; - - /* // just for test - mDisplay->drawPixel(0, 0); - mDisplay->drawPixel(mDispWidth-1, 0); - mDisplay->drawPixel(0, mDispHeight-1); - mDisplay->drawPixel(mDispWidth-1, mDispHeight-1); - */ + if (mScreenSaver != 1 ) { // not practical for pixel shift screensaver + // draw dynamic RSSI bars + int rssi_bar_height = 9; + for (int i=0; i<4;i++) { + int radio_rssi_threshold = -60 - i*10; + int wifi_rssi_threshold = -60 - i*10; + if (mDisplayData->RadioRSSI > radio_rssi_threshold) + mDisplay->drawBox(0, 8+(rssi_bar_height+1)*i, 4-i,rssi_bar_height); + if (mDisplayData->WifiRSSI > wifi_rssi_threshold) + mDisplay->drawBox(mDispWidth-4+i, 8+(rssi_bar_height+1)*i, 4-i,rssi_bar_height); + } + // draw dynamic antenna and WiFi symbols + mDisplay->setFont(u8g2_font_ncenB10_symbols10_ahoy); + char sym[]=" "; + sym[0] = mDisplayData->RadioSymbol?'A':'E'; // NRF + mDisplay->drawStr(0, mLineYOffsets[l_RSSI], sym); + + if (mDisplayData->MQTTSymbol) + sym[0] = 'J'; // MQTT + else + sym[0] = mDisplayData->WifiSymbol?'B':'F'; // Wifi + mDisplay->drawStr(mDispWidth - mDisplay->getStrWidth(sym), mLineYOffsets[l_RSSI], sym); + mDisplay->sendBuffer(); + } mDisplay->sendBuffer(); - mDispY = 0; mExtra++; } @@ -218,6 +189,11 @@ class DisplayMono128X64 : public DisplayMono { } while(l_MAX_LINES>i); } + inline int8_t pixelshift(void) { + int8_t range = 11; // number of pixels to shift from left to right (centered) + return(mScreenSaver == 1 ? (mExtra % range - range/2) : 0); + } + inline void setLineFont(uint8_t line) { if ((line == l_TotalPower) || (line == l_Ahoy)) @@ -232,12 +208,12 @@ class DisplayMono128X64 : public DisplayMono { void printText(const char *text, uint8_t line, uint8_t col=0) { uint8_t dispX; - setLineFont(line); if (0xff == col) dispX = (mDispWidth - mDisplay->getStrWidth(text)) / 2; // center text else dispX = col; + dispX += pixelshift(); mDisplay->drawStr(dispX, mLineYOffsets[line], text); } }; diff --git a/src/plugins/Display/Display_Mono_64X48.h b/src/plugins/Display/Display_Mono_64X48.h index 43c7e365..9edaf5e4 100644 --- a/src/plugins/Display/Display_Mono_64X48.h +++ b/src/plugins/Display/Display_Mono_64X48.h @@ -9,17 +9,12 @@ class DisplayMono64X48 : public DisplayMono { public: DisplayMono64X48() : DisplayMono() { - mEnPowerSave = true; - mEnScreenSaver = false; - mLuminance = 20; mExtra = 0; - mDispY = 0; - mTimeout = DISP_DEFAULT_TIMEOUT; // interval at which to power save (milliseconds) } - void config(bool enPowerSave, bool enScreenSaver, uint8_t lum) { + void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum) { mEnPowerSave = enPowerSave; - mEnScreenSaver = enScreenSaver; + mScreenSaver = screenSaver; mLuminance = lum; } @@ -34,18 +29,6 @@ class DisplayMono64X48 : public DisplayMono { mDisplay->sendBuffer(); } - void loop(uint8_t lum) { - if (mEnPowerSave) { - if (mTimeout != 0) - mTimeout--; - } - - if(mLuminance != lum) { - mLuminance = lum; - mDisplay->setContrast(mLuminance); - } - } - void disp(void) { mDisplay->clearBuffer(); @@ -53,9 +36,6 @@ class DisplayMono64X48 : public DisplayMono { mDisplay->setContrast(mLuminance); if ((mDisplayData->totalPower > 0) && (mDisplayData->nrProducing > 0)) { - mTimeout = DISP_DEFAULT_TIMEOUT; - mDisplay->setPowerSave(false); - if (mDisplayData->totalPower > 999) snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%2.2f kW", (mDisplayData->totalPower / 1000)); else @@ -64,9 +44,6 @@ class DisplayMono64X48 : public DisplayMono { printText(mFmtText, 0); } else { printText("offline", 0); - // check if it's time to enter power saving mode - if (mTimeout == 0) - mDisplay->setPowerSave(mEnPowerSave); } snprintf(mFmtText, DISP_FMT_TEXT_LEN, "D: %4.0f Wh", mDisplayData->totalYieldDay); @@ -119,7 +96,7 @@ class DisplayMono64X48 : public DisplayMono { void printText(const char *text, uint8_t line) { uint8_t dispX = 0; //small display, use all we have - dispX += (mEnScreenSaver) ? (mExtra % 4) : 0; + dispX += (mScreenSaver==1) ? (mExtra % 4) : 0; setFont(line); mDisplay->drawStr(dispX, mLineYOffsets[line], text); } diff --git a/src/plugins/Display/Display_Mono_84X48.h b/src/plugins/Display/Display_Mono_84X48.h index 47372a48..ccc2d409 100644 --- a/src/plugins/Display/Display_Mono_84X48.h +++ b/src/plugins/Display/Display_Mono_84X48.h @@ -10,17 +10,12 @@ class DisplayMono84X48 : public DisplayMono { public: DisplayMono84X48() : DisplayMono() { - mEnPowerSave = true; - mEnScreenSaver = true; - mLuminance = 140; mExtra = 0; - mDispY = 0; - mTimeout = DISP_DEFAULT_TIMEOUT; // interval at which to power save (milliseconds) } - void config(bool enPowerSave, bool enScreenSaver, uint8_t lum) { + void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum) { mEnPowerSave = enPowerSave; - mEnScreenSaver = enScreenSaver; + mScreenSaver = screenSaver; mLuminance = lum; } @@ -34,18 +29,6 @@ class DisplayMono84X48 : public DisplayMono { mDisplay->sendBuffer(); } - void loop(uint8_t lum) { - if (mEnPowerSave) { - if (mTimeout != 0) - mTimeout--; - } - - if(mLuminance != lum) { - mLuminance = lum; - mDisplay->setContrast(mLuminance); - } - } - void disp(void) { mDisplay->clearBuffer(); @@ -65,9 +48,6 @@ class DisplayMono84X48 : public DisplayMono { // print total power if (mDisplayData->nrProducing > 0) { - mTimeout = DISP_DEFAULT_TIMEOUT; - mDisplay->setPowerSave(false); - if (mDisplayData->totalPower > 9999) snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2fkW", (mDisplayData->totalPower / 1000)); // forgo spacing between value and SI unit in favor of second position after decimal point else if (mDisplayData->totalPower > 999) @@ -78,9 +58,6 @@ class DisplayMono84X48 : public DisplayMono { printText(mFmtText, l_TotalPower, 0xff); } else { printText("offline", l_TotalPower, 0xff); - // check if it's time to enter power saving mode - if (mTimeout == 0) - mDisplay->setPowerSave(mEnPowerSave); } // print Date and time diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 4208be30..b53c8b79 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -578,7 +578,7 @@ class RestApi { void getDisplay(JsonObject obj) { obj[F("disp_typ")] = (uint8_t)mConfig->plugin.display.type; obj[F("disp_pwr")] = (bool)mConfig->plugin.display.pwrSaveAtIvOffline; - obj[F("disp_pxshift")] = (bool)mConfig->plugin.display.pxShift; + obj[F("disp_screensaver")] = (uint8_t)mConfig->plugin.display.screenSaver; obj[F("disp_rot")] = (uint8_t)mConfig->plugin.display.rot; 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; @@ -587,6 +587,7 @@ class RestApi { 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; + obj[F("pir_pin")] = mConfig->plugin.display.pirPin; } void getMqttInfo(JsonObject obj) { diff --git a/src/web/html/setup.html b/src/web/html/setup.html index ec68f65a..da9ab1a5 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -278,16 +278,14 @@
Turn off while inverters are offline
-
-
Enable Screensaver (pixel shifting, OLED only)
-
-
+
Luminance

Pinout

+
@@ -946,17 +944,17 @@ } function parseDisplay(obj, type, system) { - for(var i of ["disp_pwr", "disp_pxshift"]) + for(var i of ["disp_pwr"]) document.getElementsByName(i)[0].checked = obj[i]; - var e = document.getElementById("dispPins"); + var dpins_elem = document.getElementById("dispPins"); //KEEP this order !!! var pins = [['clock', 'disp_clk'], ['data', 'disp_data'], ['cs', 'disp_cs'], ['dc', 'disp_dc'], ['reset', 'disp_rst']]; /*IF_ESP32*/ pins.push(['busy', 'disp_bsy']); /*ENDIF_ESP32*/ for(p of pins) { - e.append( + dpins_elem.append( 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"}, @@ -965,23 +963,18 @@ ]) ); } - // keep display types grouped var opts = [[0, "None"], [2, "SH1106 1.3\" 128X64"], [5, "SSD1306 0.66\" 64X48 (Wemos OLED Shield)"], [4, "SSD1306 0.91\" 128X32"], [1, "SSD1306 0.96\" 128X64"], [6, "SSD1309 2.42\" 128X64"], [3, "Nokia5110"]]; /*IF_ESP32*/ opts.push([10, "ePaper"]); /*ENDIF_ESP32*/ - var dispType = sel("disp_typ", opts, obj["disp_typ"]); + var dtype_sel = 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"}, dispType) + ml("div", {class: "col-12 col-sm-9"}, dtype_sel) ]) ); - dispType.addEventListener('change', (e) => { - hideDispPins(pins, parseInt(e.target.value)) - }); - opts = [[0, "0°"], [2, "180°"]]; /*IF_ESP32*/ opts.push([1, "90°"]); @@ -994,7 +987,35 @@ ]) ); + var opts1 = [[0, "off"], [1, "pixel shift"], [2, "motion sensor"]]; + var screensaver_sel = sel("disp_screensaver", opts1, obj["disp_screensaver"]); + screensaver_sel.id = 'disp_screensaver'; + document.getElementById("screenSaver").append( + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-12 col-sm-3 my-2"}, "Screensaver (OLED only)"), + ml("div", {class: "col-12 col-sm-9"}, screensaver_sel) + ]) + ); + + var esp8266pirpins = [[255, "off / default"], + [17, "A0"]]; + document.getElementById("pirPin").append( + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-12 col-sm-3 my-2"}, "PIR sensor"), + ml("div", {class: "col-12 col-sm-9"}, sel("pir_pin", ("ESP8266" == type) ? esp8266pirpins : ("ESP32-S3" == system["chip_model"]) ? esp32s3pins : esp32pins, obj["pir_pin"])) + ]) + ); + document.getElementsByName("disp_cont")[0].value = obj["disp_cont"]; + + dtype_sel.addEventListener('change', function(e) { + hideDispPins(pins, parseInt(e.target.value)) + }); + + document.getElementById("disp_screensaver").addEventListener('change', function(e) { + hideDispPins(pins, parseInt(dtype_sel.value)) + }); + hideDispPins(pins, obj.disp_typ); } @@ -1021,6 +1042,15 @@ cl.add("hide"); } } + + var screenSaver = document.getElementById("disp_screensaver").value; + + if (2==screenSaver) { // show pir pin only for motion screensaver + setHide("pirPin", false); + } + else { // no pir pin for all others + setHide("pirPin", true); + } } function tick() { diff --git a/src/web/web.h b/src/web/web.h index c88d829a..cb5cf72a 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -565,7 +565,7 @@ class Web { // display mConfig->plugin.display.pwrSaveAtIvOffline = (request->arg("disp_pwr") == "on"); - mConfig->plugin.display.pxShift = (request->arg("disp_pxshift") == "on"); + mConfig->plugin.display.screenSaver = request->arg("disp_screensaver").toInt(); mConfig->plugin.display.rot = request->arg("disp_rot").toInt(); mConfig->plugin.display.type = request->arg("disp_typ").toInt(); mConfig->plugin.display.contrast = (mConfig->plugin.display.type == 0) ? 60 : request->arg("disp_cont").toInt(); @@ -575,6 +575,7 @@ class Web { 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(); + mConfig->plugin.display.pirPin = request->arg("pir_pin").toInt(); mApp->saveSettings((request->arg("reboot") == "on")); From 0a6437bf103e9f697ff0560bd8956fd823fbb90c Mon Sep 17 00:00:00 2001 From: Wusaweki Date: Sat, 25 Nov 2023 14:55:24 +0100 Subject: [PATCH 185/267] improve pixelshift screensaver (cherry picked from commit 9eaa369147430c7d8c94830f325192e8f2e81853) --- src/plugins/Display/Display_Mono.h | 6 ++ src/plugins/Display/Display_Mono_128X32.h | 9 +-- src/plugins/Display/Display_Mono_128X64.h | 71 ++++++++++++----------- src/plugins/Display/Display_Mono_64X48.h | 11 ++-- 4 files changed, 54 insertions(+), 43 deletions(-) diff --git a/src/plugins/Display/Display_Mono.h b/src/plugins/Display/Display_Mono.h index a38be58f..a360f796 100644 --- a/src/plugins/Display/Display_Mono.h +++ b/src/plugins/Display/Display_Mono.h @@ -78,6 +78,7 @@ class DisplayMono { uint8_t mLineYOffsets[5] = {}; uint8_t mExtra; + int8_t mPixelshift=0; uint32_t mStarttime = millis(); bool mDisplayActive = true; // always start with display on char mFmtText[DISP_FMT_TEXT_LEN]; @@ -94,6 +95,11 @@ class DisplayMono { mDispWidth = mDisplay->getDisplayWidth(); mDispHeight = mDisplay->getDisplayHeight(); } + + void calcPixelShift(int range) { + int8_t mod = (millis() / 10000) % ((range >> 1) << 2); + mPixelshift = mScreenSaver == 1 ? ((mod < range) ? mod - (range >> 1) : -(mod - range - (range >> 1) + 1)) : 0; + } }; /* adapted 5x8 Font for low-res displays with symbols diff --git a/src/plugins/Display/Display_Mono_128X32.h b/src/plugins/Display/Display_Mono_128X32.h index ffb96384..fa0cacdf 100644 --- a/src/plugins/Display/Display_Mono_128X32.h +++ b/src/plugins/Display/Display_Mono_128X32.h @@ -31,9 +31,8 @@ class DisplayMono128X32 : public DisplayMono { void disp(void) { mDisplay->clearBuffer(); - // set Contrast of the Display to raise the lifetime - if (3 != mType) - mDisplay->setContrast(mLuminance); + // calculate current pixelshift for pixelshift screensaver + calcPixelShift(pixelShiftRange); if ((mDisplayData->totalPower > 0) && (mDisplayData->nrProducing > 0)) { if (mDisplayData->totalPower > 999) @@ -67,6 +66,8 @@ class DisplayMono128X32 : public DisplayMono { } private: + const uint8_t pixelShiftRange = 7; // number of pixels to shift from left to right (centered -> must be odd!) + void calcLinePositions() { uint8_t yOff[] = {0, 0}; for (uint8_t i = 0; i < 4; i++) { @@ -108,7 +109,7 @@ class DisplayMono128X32 : public DisplayMono { void printText(const char *text, uint8_t line) { setFont(line); - uint8_t dispX = mLineXOffsets[line] + ((mScreenSaver==1) ? (mExtra % 7) : 0); + uint8_t dispX = mLineXOffsets[line] + pixelShiftRange / 2 + mPixelshift; if (isTwoRowLine(line)) { String stringText = String(text); diff --git a/src/plugins/Display/Display_Mono_128X64.h b/src/plugins/Display/Display_Mono_128X64.h index dae49ac0..78a18db6 100644 --- a/src/plugins/Display/Display_Mono_128X64.h +++ b/src/plugins/Display/Display_Mono_128X64.h @@ -58,8 +58,8 @@ class DisplayMono128X64 : public DisplayMono { mDisplay->drawPixel(mDispWidth-1, mDispHeight-1); */ - // set Contrast of the Display to raise the lifetime - mDisplay->setContrast(mLuminance); + // calculate current pixelshift for pixelshift screensaver + calcPixelShift(pixelShiftRange); // print total power if (mDisplayData->nrProducing > 0) { @@ -109,44 +109,48 @@ class DisplayMono128X64 : public DisplayMono { pos = (mDispWidth - mDisplay->getStrWidth(mFmtText)) / 2; mDisplay->setFont(u8g2_font_ncenB08_symbols8_ahoy); if (sun_pos!=-1) - mDisplay->drawStr(pos + sun_pos + pixelshift(), mLineYOffsets[l_Status], "G"); // sun + mDisplay->drawStr(pos + sun_pos + mPixelshift, mLineYOffsets[l_Status], "G"); // sun if (moon_pos!=-1) - mDisplay->drawStr(pos + moon_pos + pixelshift(), mLineYOffsets[l_Status], "H"); // moon + mDisplay->drawStr(pos + moon_pos + mPixelshift, mLineYOffsets[l_Status], "H"); // moon } // print yields mDisplay->setFont(u8g2_font_ncenB10_symbols10_ahoy); - mDisplay->drawStr(15 + pixelshift(), mLineYOffsets[l_YieldDay], "I"); // day - mDisplay->drawStr(15 + pixelshift(), mLineYOffsets[l_YieldTotal], "D"); // total + mDisplay->drawStr(17 + mPixelshift, mLineYOffsets[l_YieldDay], "I"); // day + mDisplay->drawStr(17 + mPixelshift, mLineYOffsets[l_YieldTotal], "D"); // total snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%7.0f Wh", mDisplayData->totalYieldDay); printText(mFmtText, l_YieldDay, 25); snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%7.1f kWh", mDisplayData->totalYieldTotal); printText(mFmtText, l_YieldTotal, 25); - if (mScreenSaver != 1 ) { // not practical for pixel shift screensaver - // draw dynamic RSSI bars - int rssi_bar_height = 9; - for (int i=0; i<4;i++) { - int radio_rssi_threshold = -60 - i*10; - int wifi_rssi_threshold = -60 - i*10; - if (mDisplayData->RadioRSSI > radio_rssi_threshold) - mDisplay->drawBox(0, 8+(rssi_bar_height+1)*i, 4-i,rssi_bar_height); - if (mDisplayData->WifiRSSI > wifi_rssi_threshold) - mDisplay->drawBox(mDispWidth-4+i, 8+(rssi_bar_height+1)*i, 4-i,rssi_bar_height); - } - // draw dynamic antenna and WiFi symbols - mDisplay->setFont(u8g2_font_ncenB10_symbols10_ahoy); - char sym[]=" "; - sym[0] = mDisplayData->RadioSymbol?'A':'E'; // NRF - mDisplay->drawStr(0, mLineYOffsets[l_RSSI], sym); - - if (mDisplayData->MQTTSymbol) - sym[0] = 'J'; // MQTT - else - sym[0] = mDisplayData->WifiSymbol?'B':'F'; // Wifi - mDisplay->drawStr(mDispWidth - mDisplay->getStrWidth(sym), mLineYOffsets[l_RSSI], sym); - mDisplay->sendBuffer(); + // draw dynamic RSSI bars + int xoffs; + if (mScreenSaver == 1) // shrink screenwidth for pixelshift screensaver + xoffs = pixelShiftRange/2; + else + xoffs = 0; + int rssi_bar_height = 9; + for (int i = 0; i < 4; i++) { + int radio_rssi_threshold = -60 - i * 10; + int wifi_rssi_threshold = -60 - i * 10; + if (mDisplayData->RadioRSSI > radio_rssi_threshold) + mDisplay->drawBox(xoffs + mPixelshift, 8 + (rssi_bar_height + 1) * i, 4 - i, rssi_bar_height); + if (mDisplayData->WifiRSSI > wifi_rssi_threshold) + mDisplay->drawBox(mDispWidth - 4 - xoffs + mPixelshift + i, 8 + (rssi_bar_height + 1) * i, 4 - i, rssi_bar_height); } + // draw dynamic antenna and WiFi symbols + mDisplay->setFont(u8g2_font_ncenB10_symbols10_ahoy); + char sym[]=" "; + sym[0] = mDisplayData->RadioSymbol?'A':'E'; // NRF + mDisplay->drawStr(xoffs + mPixelshift, mLineYOffsets[l_RSSI], sym); + + if (mDisplayData->MQTTSymbol) + sym[0] = 'J'; // MQTT + else + sym[0] = mDisplayData->WifiSymbol?'B':'F'; // Wifi + mDisplay->drawStr(mDispWidth - mDisplay->getStrWidth(sym) - xoffs + mPixelshift, mLineYOffsets[l_RSSI], sym); + mDisplay->sendBuffer(); + mDisplay->sendBuffer(); @@ -171,6 +175,8 @@ class DisplayMono128X64 : public DisplayMono { l_MAX_LINES = 5, }; + const uint8_t pixelShiftRange = 11; // number of pixels to shift from left to right (centered -> must be odd!) + void calcLinePositions() { uint8_t yOff = 0; uint8_t i = 0; @@ -189,11 +195,6 @@ class DisplayMono128X64 : public DisplayMono { } while(l_MAX_LINES>i); } - inline int8_t pixelshift(void) { - int8_t range = 11; // number of pixels to shift from left to right (centered) - return(mScreenSaver == 1 ? (mExtra % range - range/2) : 0); - } - inline void setLineFont(uint8_t line) { if ((line == l_TotalPower) || (line == l_Ahoy)) @@ -213,7 +214,7 @@ class DisplayMono128X64 : public DisplayMono { dispX = (mDispWidth - mDisplay->getStrWidth(text)) / 2; // center text else dispX = col; - dispX += pixelshift(); + dispX += mPixelshift; mDisplay->drawStr(dispX, mLineYOffsets[line], text); } }; diff --git a/src/plugins/Display/Display_Mono_64X48.h b/src/plugins/Display/Display_Mono_64X48.h index 9edaf5e4..68cac96f 100644 --- a/src/plugins/Display/Display_Mono_64X48.h +++ b/src/plugins/Display/Display_Mono_64X48.h @@ -22,6 +22,7 @@ class DisplayMono64X48 : public DisplayMono { u8g2_cb_t *rot = (u8g2_cb_t *)((rotation != 0x00) ? U8G2_R2 : U8G2_R0); // Wemos OLed Shield is not defined in u8 lib -> use nearest compatible monoInit(new U8G2_SSD1306_64X48_ER_F_HW_I2C(rot, reset, clock, data), type, displayData); + calcLinePositions(); printText("Ahoy!", 0); printText("ahoydtu.de", 1); @@ -32,8 +33,8 @@ class DisplayMono64X48 : public DisplayMono { void disp(void) { mDisplay->clearBuffer(); - // set Contrast of the Display to raise the lifetime - mDisplay->setContrast(mLuminance); + // calculate current pixelshift for pixelshift screensaver + calcPixelShift(pixelShiftRange); if ((mDisplayData->totalPower > 0) && (mDisplayData->nrProducing > 0)) { if (mDisplayData->totalPower > 999) @@ -67,6 +68,8 @@ class DisplayMono64X48 : public DisplayMono { } private: + const uint8_t pixelShiftRange = 4; // number of pixels to shift from left to right + void calcLinePositions() { uint8_t yOff = 0; for (uint8_t i = 0; i < 4; i++) { @@ -95,8 +98,8 @@ class DisplayMono64X48 : public DisplayMono { } void printText(const char *text, uint8_t line) { - uint8_t dispX = 0; //small display, use all we have - dispX += (mScreenSaver==1) ? (mExtra % 4) : 0; + uint8_t dispX = mLineXOffsets[line] + pixelShiftRange/2 + mPixelshift; + setFont(line); mDisplay->drawStr(dispX, mLineYOffsets[line], text); } From 6701c5204862147501846a9192d4df3dfba10209 Mon Sep 17 00:00:00 2001 From: lumapu Date: Tue, 28 Nov 2023 22:29:11 +0100 Subject: [PATCH 186/267] small corrections --- src/hm/Communication.h | 3 ++- src/web/html/update.html | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index da4496b1..f41c2206 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -164,6 +164,7 @@ class Communication : public CommQueue<> { if(3 == p->ch) DBGPRINT(F("0")); DBGPRINT(String(p->ch)); + DBGPRINT(F(" ")); } else { DBGPRINT(String(p->rssi)); DBGPRINT(F("dBm | ")); @@ -174,7 +175,7 @@ class Communication : public CommQueue<> { else ah::dumpBuf(p->packet, p->len); } else { - DBGPRINT(F("frm ")); + DBGPRINT(F("| ")); DBGHEXLN(p->packet[9]); } diff --git a/src/web/html/update.html b/src/web/html/update.html index fb748ffe..4e56b1ad 100644 --- a/src/web/html/update.html +++ b/src/web/html/update.html @@ -16,7 +16,7 @@
From ec30cc21eab5ff8db74620889513d79057b3600d Mon Sep 17 00:00:00 2001 From: lumapu Date: Tue, 28 Nov 2023 22:37:11 +0100 Subject: [PATCH 187/267] 0.8.13 * merge PR #1239 symbolic layout for OLED 128x64 + motion senser functionality * fix MqTT IP addr for ETH connections PR #1240 --- src/CHANGES.md | 4 ++++ src/defines.h | 2 +- src/publisher/pubMqtt.h | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 9b17e967..dc4b6855 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,9 @@ # Development Changes +## 0.8.13 - 2023-11-28 +* merge PR #1239 symbolic layout for OLED 128x64 + motion senser functionality +* fix MqTT IP addr for ETH connections PR #1240 + ## 0.8.12 - 2023-11-20 * added button `copy to clipboard` to `/serial` diff --git a/src/defines.h b/src/defines.h index a85053d8..d471a5ef 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 12 +#define VERSION_PATCH 13 //------------------------------------- typedef struct { diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 2c23c719..92f5de2f 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -245,7 +245,11 @@ class PubMqtt { publish(subtopics[MQTT_VERSION], mVersion, true); publish(subtopics[MQTT_DEVICE], mDevName, true); + #if defined(ETHERNET) + publish(subtopics[MQTT_IP_ADDR], ETH.localIP().toString().c_str(), true); + #else publish(subtopics[MQTT_IP_ADDR], WiFi.localIP().toString().c_str(), true); + #endif tickerMinute(); publish(mLwtTopic, mqttStr[MQTT_STR_LWT_CONN], true, false); From ca0698f06c2adae5ed0503bb5a8db800397fb68c Mon Sep 17 00:00:00 2001 From: lumapu Date: Tue, 28 Nov 2023 23:40:11 +0100 Subject: [PATCH 188/267] 0.8.13 * added ethernet build for fusion board, not tested so far --- .github/workflows/compile_development.yml | 2 +- .github/workflows/compile_release.yml | 2 +- scripts/getVersion.py | 18 ++++++++-- src/CHANGES.md | 1 + src/config/config.h | 20 +++++++++--- src/eth/ahoyeth.cpp | 2 +- src/platformio.ini | 40 +++++++++++++++++++++++ 7 files changed, 74 insertions(+), 11 deletions(-) diff --git a/.github/workflows/compile_development.yml b/.github/workflows/compile_development.yml index af81492f..31049c21 100644 --- a/.github/workflows/compile_development.yml +++ b/.github/workflows/compile_development.yml @@ -43,7 +43,7 @@ jobs: pip install --upgrade platformio - name: Run PlatformIO - run: pio run -d src --environment esp8266 --environment esp8266-prometheus --environment esp8285 --environment esp32-wroom32 --environment esp32-wroom32-prometheus --environment esp32-wroom32-ethernet --environment esp32-s2-mini --environment opendtufusion + run: pio run -d src --environment esp8266 --environment esp8266-prometheus --environment esp8285 --environment esp32-wroom32 --environment esp32-wroom32-prometheus --environment esp32-wroom32-ethernet --environment esp32-s2-mini --environment opendtufusion --environment opendtufusion-ethernet - name: Copy boot_app0.bin run: cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin src/.pio/build/opendtufusion/ota.bin diff --git a/.github/workflows/compile_release.yml b/.github/workflows/compile_release.yml index 70eb5f29..8f493100 100644 --- a/.github/workflows/compile_release.yml +++ b/.github/workflows/compile_release.yml @@ -47,7 +47,7 @@ jobs: pip install --upgrade platformio - name: Run PlatformIO - run: pio run -d src --environment esp8266 --environment esp8266-prometheus --environment esp8285 --environment esp32-wroom32 --environment esp32-wroom32-prometheus --environment esp32-wroom32-ethernet --environment esp32-s2-mini --environment opendtufusion + run: pio run -d src --environment esp8266 --environment esp8266-prometheus --environment esp8285 --environment esp32-wroom32 --environment esp32-wroom32-prometheus --environment esp32-wroom32-ethernet --environment esp32-s2-mini --environment opendtufusion --environment opendtufusion-ethernet - name: Copy boot_app0.bin run: cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin src/.pio/build/opendtufusion/ota.bin diff --git a/scripts/getVersion.py b/scripts/getVersion.py index be36895e..6234d432 100644 --- a/scripts/getVersion.py +++ b/scripts/getVersion.py @@ -93,9 +93,14 @@ def readVersion(path, infile): dst = path + "firmware/ESP32-S2/" + versionout os.rename(src, dst) - versionout = version[:-1] + "_" + sha + "_esp32s3.bin" - src = path + ".pio/build/opendtufusion/firmware.bin" - dst = path + "firmware/ESP32-S3/" + versionout + versionout = version[:-1] + "_" + sha + "_esp32s3_ethernet.bin" + src = path + ".pio/build/opendtufusion-ethernet/firmware.bin" + dst = path + "firmware/ESP32-S3-ETH/" + versionout + os.rename(src, dst) + + versionout = version[:-1] + "_" + sha + "_esp32_ethernet.bin" + src = path + ".pio/build/esp32-wroom32-ethernet/firmware.bin" + dst = path + "firmware/ESP32/" + versionout os.rename(src, dst) # other ESP32 bin files @@ -119,6 +124,13 @@ def readVersion(path, infile): os.rename(src + "partitions.bin", dst + "partitions.bin") genOtaBin(dst) + # other ESP32-S3-Eth bin files + src = path + ".pio/build/opendtufusion-ethernet/" + dst = path + "firmware/ESP32-S3-ETH/" + os.rename(src + "bootloader.bin", dst + "bootloader.bin") + os.rename(src + "partitions.bin", dst + "partitions.bin") + genOtaBin(dst) + os.rename("../scripts/gh-action-dev-build-flash.html", path + "install.html") print("name=" + versionnumber[:-1] ) diff --git a/src/CHANGES.md b/src/CHANGES.md index dc4b6855..f40f1991 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -3,6 +3,7 @@ ## 0.8.13 - 2023-11-28 * merge PR #1239 symbolic layout for OLED 128x64 + motion senser functionality * fix MqTT IP addr for ETH connections PR #1240 +* added ethernet build for fusion board, not tested so far ## 0.8.12 - 2023-11-20 * added button `copy to clipboard` to `/serial` diff --git a/src/config/config.h b/src/config/config.h index 4fb78107..c8fd86dc 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -41,11 +41,21 @@ #if defined(ETHERNET) #define ETH_SPI_HOST SPI2_HOST #define ETH_SPI_CLOCK_MHZ 25 - #define ETH_INT_GPIO 4 - #define ETH_MISO_GPIO 12 - #define ETH_MOSI_GPIO 13 - #define ETH_SCK_GPIO 14 - #define ETH_CS_PIN 15 + #ifndef DEF_ETH_IRQ_PIN + #define DEF_ETH_IRQ_PIN 4 + #endif + #ifndef DEF_ETH_MISO_PIN + #define DEF_ETH_MISO_PIN 12 + #endif + #ifndef DEF_ETH_MOSI_PIN + #define DEF_ETH_MOSI_PIN 13 + #endif + #ifndef DEF_ETH_SCK_PIN + #define DEF_ETH_SCK_PIN 14 + #endif + #ifndef DEF_ETH_CS_PIN + #define DEF_ETH_CS_PIN 15 + #endif #else /* defined(ETHERNET) */ // time in seconds how long the station info (ssid + pwd) will be tried #define WIFI_TRY_CONNECT_TIME 30 diff --git a/src/eth/ahoyeth.cpp b/src/eth/ahoyeth.cpp index cb63a950..21fa0821 100644 --- a/src/eth/ahoyeth.cpp +++ b/src/eth/ahoyeth.cpp @@ -41,7 +41,7 @@ void ahoyeth::setup(settings_t *config, uint32_t *utcTimestamp, OnNetworkCB onNe if(!ETH.config(ip, gateway, mask, dns1, dns2)) DPRINTLN(DBG_ERROR, F("failed to set static IP!")); } - ETH.begin(ETH_MISO_GPIO, ETH_MOSI_GPIO, ETH_SCK_GPIO, ETH_CS_PIN, ETH_INT_GPIO, ETH_SPI_CLOCK_MHZ, ETH_SPI_HOST); + ETH.begin(DEF_ETH_MISO_PIN, DEF_ETH_MOSI_PIN, DEF_ETH_SCK_PIN, DEF_ETH_CS_PIN, DEF_ETH_IRQ_PIN, ETH_SPI_CLOCK_MHZ, ETH_SPI_HOST); } diff --git a/src/platformio.ini b/src/platformio.ini index e7c87979..e1f4d574 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -146,6 +146,46 @@ build_flags = ${env.build_flags} monitor_filters = esp32_exception_decoder, colorize +[env:opendtufusion-ethernet] +platform = espressif32@6.4.0 +board = esp32-s3-devkitc-1 +lib_deps = + khoih-prog/AsyncWebServer_ESP32_W5500 + khoih-prog/AsyncUDP_ESP32_W5500 + nrf24/RF24 @ ^1.4.8 + paulstoffregen/Time @ ^1.6.1 + https://github.com/bertmelis/espMqttClient#v1.5.0 + bblanchon/ArduinoJson @ ^6.21.3 + https://github.com/JChristensen/Timezone @ ^1.2.4 + olikraus/U8g2 @ ^2.35.7 + zinggjm/GxEPD2 @ ^1.5.2 +upload_protocol = esp-builtin +build_flags = ${env.build_flags} + -DETHERNET + -DUSE_HSPI_FOR_EPD + -DDEF_ETH_CS_PIN=42 + -DDEF_ETH_SCK_PIN=39 + -DDEF_ETH_MISO_PIN=41 + -DDEF_ETH_MOSI_PIN=40 + -DDEF_ETH_IRQ_PIN=43 + -DDEF_NRF_CS_PIN=37 + -DDEF_NRF_CE_PIN=38 + -DDEF_NRF_IRQ_PIN=47 + -DDEF_NRF_MISO_PIN=48 + -DDEF_NRF_MOSI_PIN=35 + -DDEF_NRF_SCLK_PIN=36 + -DDEF_CMT_CSB=4 + -DDEF_CMT_FCSB=21 + -DDEF_CMT_IRQ=8 + -DDEF_CMT_SDIO=5 + -DDEF_CMT_SCLK=6 + -DDEF_LED0=18 + -DDEF_LED1=17 + -DLED_ACTIVE_HIGH + -DARDUINO_USB_MODE=1 +monitor_filters = + esp32_exception_decoder, colorize + [env:opendtufusion-dev] platform = espressif32@6.4.0 board = esp32-s3-devkitc-1 From d0e7609b9de398106ecdd1d2d957ed7f710d7268 Mon Sep 17 00:00:00 2001 From: lumapu Date: Wed, 29 Nov 2023 00:02:16 +0100 Subject: [PATCH 189/267] 0.8.13 * fix pinout --- scripts/getVersion.py | 1 + src/platformio.ini | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/getVersion.py b/scripts/getVersion.py index 6234d432..16f985bc 100644 --- a/scripts/getVersion.py +++ b/scripts/getVersion.py @@ -55,6 +55,7 @@ def readVersion(path, infile): os.mkdir(path + "firmware/ESP32/") os.mkdir(path + "firmware/ESP32-S2/") os.mkdir(path + "firmware/ESP32-S3/") + os.mkdir(path + "firmware/ESP32-S3-ETH/") sha = os.getenv("SHA",default="sha") versionout = version[:-1] + "_" + sha + "_esp8266.bin" diff --git a/src/platformio.ini b/src/platformio.ini index e1f4d574..643a77a0 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -167,7 +167,8 @@ build_flags = ${env.build_flags} -DDEF_ETH_SCK_PIN=39 -DDEF_ETH_MISO_PIN=41 -DDEF_ETH_MOSI_PIN=40 - -DDEF_ETH_IRQ_PIN=43 + -DDEF_ETH_IRQ_PIN=44 + -DDEF_ETH_RST_PIN=43 -DDEF_NRF_CS_PIN=37 -DDEF_NRF_CE_PIN=38 -DDEF_NRF_IRQ_PIN=47 From cfef2ce63a063c01866a22fd251b7666a630852f Mon Sep 17 00:00:00 2001 From: lumapu Date: Wed, 29 Nov 2023 07:40:17 +0100 Subject: [PATCH 190/267] 0.8.13 * fix github build --- scripts/getVersion.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/getVersion.py b/scripts/getVersion.py index 16f985bc..4ea74d71 100644 --- a/scripts/getVersion.py +++ b/scripts/getVersion.py @@ -94,16 +94,16 @@ def readVersion(path, infile): dst = path + "firmware/ESP32-S2/" + versionout os.rename(src, dst) + versionout = version[:-1] + "_" + sha + "_esp32s3.bin" + src = path + ".pio/build/opendtufusion/firmware.bin" + dst = path + "firmware/ESP32-S3/" + versionout + os.rename(src, dst) + versionout = version[:-1] + "_" + sha + "_esp32s3_ethernet.bin" src = path + ".pio/build/opendtufusion-ethernet/firmware.bin" dst = path + "firmware/ESP32-S3-ETH/" + versionout os.rename(src, dst) - versionout = version[:-1] + "_" + sha + "_esp32_ethernet.bin" - src = path + ".pio/build/esp32-wroom32-ethernet/firmware.bin" - dst = path + "firmware/ESP32/" + versionout - os.rename(src, dst) - # other ESP32 bin files src = path + ".pio/build/esp32-wroom32/" dst = path + "firmware/ESP32/" From b4976aa30fa3ed3c1f5fedd750feff6022fad1c9 Mon Sep 17 00:00:00 2001 From: Wusaweki Date: Fri, 1 Dec 2023 09:59:37 +0100 Subject: [PATCH 191/267] add 1.54" display to settings --- src/plugins/Display/Display.h | 14 +++++++------- src/web/html/setup.html | 8 +++++++- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index c6d4dc03..5efe5e87 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -34,13 +34,13 @@ class Display { mDisplayData.version = app->getVersion(); // version never changes, so only set once switch (mCfg->type) { - case 0: mMono = NULL; break; - case 1: // fall-through - case 2: mMono = new DisplayMono128X64(); break; - case 3: mMono = new DisplayMono84X48(); break; - case 4: mMono = new DisplayMono128X32(); break; - case 5: mMono = new DisplayMono64X48(); break; - case 6: mMono = new DisplayMono128X64(); break; + case 0: mMono = NULL; break; // None + case 1: mMono = new DisplayMono128X64(); break; // SSD1306_128X64 (0.96", 1.54") + case 2: mMono = new DisplayMono128X64(); break; // SH1106_128X64 (1.3") + case 3: mMono = new DisplayMono84X48(); break; // PCD8544_84X48 (1.6" - Nokia 5110) + case 4: mMono = new DisplayMono128X32(); break; // SSD1306_128X32 (0.91") + case 5: mMono = new DisplayMono64X48(); break; // SSD1306_64X48 (0.66" - Wemos OLED Shield) + case 6: mMono = new DisplayMono128X64(); break; // SSD1309_128X64 (2.42") #if defined(ESP32) case 10: mMono = NULL; // ePaper does not use this diff --git a/src/web/html/setup.html b/src/web/html/setup.html index da9ab1a5..9d447f15 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -964,7 +964,13 @@ ); } // keep display types grouped - var opts = [[0, "None"], [2, "SH1106 1.3\" 128X64"], [5, "SSD1306 0.66\" 64X48 (Wemos OLED Shield)"], [4, "SSD1306 0.91\" 128X32"], [1, "SSD1306 0.96\" 128X64"], [6, "SSD1309 2.42\" 128X64"], [3, "Nokia5110"]]; + var opts = [[0, "None"], + [2, "SH1106 128x64 (1.3\")"], + [5, "SSD1306 64x48 (0.66\" Wemos OLED Shield)"], + [4, "SSD1306 128x32 (0.91\")"], + [1, "SSD1306 128x64 (0.96\", 1.54\")"], + [6, "SSD1309 128X64 (2.42\")"], + [3, "PCD8544 84X48 (1.6\" Nokia 5110)"]]; /*IF_ESP32*/ opts.push([10, "ePaper"]); /*ENDIF_ESP32*/ From 81a05b37523af3ed2d3a426c5571703a6a291ad3 Mon Sep 17 00:00:00 2001 From: Wusaweki Date: Fri, 1 Dec 2023 12:17:38 +0100 Subject: [PATCH 192/267] support MWh for YieldTotal --- src/plugins/Display/Display_Mono_128X64.h | 33 ++++++++++------- src/plugins/Display/Display_Mono_84X48.h | 43 +++++++++++++---------- src/plugins/Display/Display_data.h | 4 +-- 3 files changed, 47 insertions(+), 33 deletions(-) diff --git a/src/plugins/Display/Display_Mono_128X64.h b/src/plugins/Display/Display_Mono_128X64.h index 78a18db6..7b7b7920 100644 --- a/src/plugins/Display/Display_Mono_128X64.h +++ b/src/plugins/Display/Display_Mono_128X64.h @@ -49,9 +49,9 @@ class DisplayMono128X64 : public DisplayMono { /* mDisplayData->nrSleeping = 10; mDisplayData->nrProducing = 10; - mDisplayData->totalPower = 99990; - mDisplayData->totalYieldDay = 8888; - mDisplayData->totalYieldTotal = 9999; + mDisplayData->totalPower = 54321.9; // W + mDisplayData->totalYieldDay = 4321.9; // Wh + mDisplayData->totalYieldTotal = 4321.9; // kWh mDisplay->drawPixel(0, 0); mDisplay->drawPixel(mDispWidth-1, 0); mDisplay->drawPixel(0, mDispHeight-1); @@ -64,9 +64,10 @@ class DisplayMono128X64 : public DisplayMono { // print total power if (mDisplayData->nrProducing > 0) { if (mDisplayData->totalPower > 999) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kW", (mDisplayData->totalPower / 1000)); + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f kW", (mDisplayData->totalPower / 1000.0)); else snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f W", mDisplayData->totalPower); + printText(mFmtText, l_TotalPower, 0xff); } else { printText("offline", l_TotalPower, 0xff); @@ -109,19 +110,27 @@ class DisplayMono128X64 : public DisplayMono { pos = (mDispWidth - mDisplay->getStrWidth(mFmtText)) / 2; mDisplay->setFont(u8g2_font_ncenB08_symbols8_ahoy); if (sun_pos!=-1) - mDisplay->drawStr(pos + sun_pos + mPixelshift, mLineYOffsets[l_Status], "G"); // sun + mDisplay->drawStr(pos + sun_pos + mPixelshift, mLineYOffsets[l_Status], "G"); // sun symbol if (moon_pos!=-1) - mDisplay->drawStr(pos + moon_pos + mPixelshift, mLineYOffsets[l_Status], "H"); // moon + mDisplay->drawStr(pos + moon_pos + mPixelshift, mLineYOffsets[l_Status], "H"); // moon symbol } // print yields mDisplay->setFont(u8g2_font_ncenB10_symbols10_ahoy); - mDisplay->drawStr(17 + mPixelshift, mLineYOffsets[l_YieldDay], "I"); // day - mDisplay->drawStr(17 + mPixelshift, mLineYOffsets[l_YieldTotal], "D"); // total - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%7.0f Wh", mDisplayData->totalYieldDay); - printText(mFmtText, l_YieldDay, 25); - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%7.1f kWh", mDisplayData->totalYieldTotal); - printText(mFmtText, l_YieldTotal, 25); + mDisplay->drawStr(16 + mPixelshift, mLineYOffsets[l_YieldDay], "I"); // day symbol + mDisplay->drawStr(16 + mPixelshift, mLineYOffsets[l_YieldTotal], "D"); // total symbol + + if (mDisplayData->totalYieldDay > 999.0) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f kWh", mDisplayData->totalYieldDay / 1000.0); + else + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f Wh", mDisplayData->totalYieldDay); + printText(mFmtText, l_YieldDay, 0xff); + + if (mDisplayData->totalYieldTotal > 999.0) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f MWh", mDisplayData->totalYieldTotal / 1000.0); + else + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f kWh", mDisplayData->totalYieldTotal); + printText(mFmtText, l_YieldTotal, 0xff); // draw dynamic RSSI bars int xoffs; diff --git a/src/plugins/Display/Display_Mono_84X48.h b/src/plugins/Display/Display_Mono_84X48.h index ccc2d409..df27a414 100644 --- a/src/plugins/Display/Display_Mono_84X48.h +++ b/src/plugins/Display/Display_Mono_84X48.h @@ -34,12 +34,11 @@ class DisplayMono84X48 : public DisplayMono { // Layout-Test /* - mDisplayData->nrSleeping = 0; - mDisplayData->nrProducing = 1; - mDisplayData->totalPower = 12345.67; - mDisplayData->totalYieldDay = 12345.67; - mDisplayData->totalYieldTotal = 1234; - mDisplayData->utcTs += 1000000; + mDisplayData->nrSleeping = 10; + mDisplayData->nrProducing = 10; + mDisplayData->totalPower = 111.91; // W + mDisplayData->totalYieldDay = 54321.9; // Wh + mDisplayData->totalYieldTotal = 654321.9; // kWh mDisplay->drawPixel(0, 0); mDisplay->drawPixel(mDispWidth-1, 0); mDisplay->drawPixel(0, mDispHeight-1); @@ -48,12 +47,10 @@ class DisplayMono84X48 : public DisplayMono { // print total power if (mDisplayData->nrProducing > 0) { - if (mDisplayData->totalPower > 9999) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2fkW", (mDisplayData->totalPower / 1000)); // forgo spacing between value and SI unit in favor of second position after decimal point - else if (mDisplayData->totalPower > 999) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kW", (mDisplayData->totalPower / 1000)); + if (mDisplayData->totalPower > 999) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f kW", (mDisplayData->totalPower / 1000)); else - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f W", mDisplayData->totalPower); + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f W", mDisplayData->totalPower); printText(mFmtText, l_TotalPower, 0xff); } else { @@ -75,21 +72,29 @@ class DisplayMono84X48 : public DisplayMono { if (0 == mDisplayData->nrSleeping + mDisplayData->nrProducing) snprintf(mFmtText, DISP_FMT_TEXT_LEN, "no inverter"); else if (0 == mDisplayData->nrSleeping) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "\x86"); + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "\x86"); // sun symbol else if (0 == mDisplayData->nrProducing) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "\x87"); + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "\x87"); // moon symbol else snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%d\x86 %d\x87", mDisplayData->nrProducing, mDisplayData->nrSleeping); printText(mFmtText, l_Status, 0xff); } // print yields - printText("\x88", l_YieldDay, 11); // day symbol - printText("\x83", l_YieldTotal, 11); // total symbol - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%7.0f Wh", mDisplayData->totalYieldDay); - printText(mFmtText, l_YieldDay, 18); - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%7.1f kWh", mDisplayData->totalYieldTotal); - printText(mFmtText, l_YieldTotal, 18); + printText("\x88", l_YieldDay, 10); // day symbol + printText("\x83", l_YieldTotal, 10); // total symbol + + if (mDisplayData->totalYieldDay > 999.0) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f kWh", mDisplayData->totalYieldDay / 1000.0); + else + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f Wh", mDisplayData->totalYieldDay); + printText(mFmtText, l_YieldDay, 0xff); + + if (mDisplayData->totalYieldTotal > 999.0) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f MWh", mDisplayData->totalYieldTotal / 1000.0); + else + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f kWh", mDisplayData->totalYieldTotal); + printText(mFmtText, l_YieldTotal, 0xff); // draw dynamic Nokia RSSI bars int rssi_bar_height = 7; diff --git a/src/plugins/Display/Display_data.h b/src/plugins/Display/Display_data.h index 32525bd4..a400377d 100644 --- a/src/plugins/Display/Display_data.h +++ b/src/plugins/Display/Display_data.h @@ -6,8 +6,8 @@ struct DisplayData { const char *version=nullptr; float totalPower=0.0f; // indicate current power (W) - float totalYieldDay=0.0f; // indicate day yield (W) - float totalYieldTotal=0.0f; // indicate total yield (W) + float totalYieldDay=0.0f; // indicate day yield (Wh) + float totalYieldTotal=0.0f; // indicate total yield (kWh) uint32_t utcTs=0; // indicate absolute timestamp (utc unix time). 0 = time is not synchonized uint8_t nrProducing=0; // indicate number of producing inverters uint8_t nrSleeping=0; // indicate number of sleeping inverters From 99add5c8b2d119cb33d8fedc2e2ae5c7c968fb4f Mon Sep 17 00:00:00 2001 From: Wusaweki Date: Fri, 1 Dec 2023 09:09:49 +0100 Subject: [PATCH 193/267] combine CMD module status to antenna-symbol ... and for this harmonize hmRadio and hmsRadio is_Chip_Connected() --- src/app.cpp | 6 +++++- src/app.h | 2 +- src/appInterface.h | 5 ++++- src/hm/radio.h | 2 ++ src/hms/hmsRadio.h | 2 +- src/plugins/Display/Display.h | 21 ++++++++++++++++----- src/web/RestApi.h | 2 +- 7 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/app.cpp b/src/app.cpp index 5359da30..dbda9036 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -86,7 +86,11 @@ void app::setup() { // Plugins #if defined(PLUGIN_DISPLAY) if (mConfig->plugin.display.type != 0) - mDisplay.setup(this, &mConfig->plugin.display, &mSys, &mNrfRadio, &mTimestamp); + #if defined(ESP32) + mDisplay.setup(this, &mConfig->plugin.display, &mSys, &mNrfRadio, &mCmtRadio, &mTimestamp); + #else + mDisplay.setup(this, &mConfig->plugin.display, &mSys, &mNrfRadio, NULL, &mTimestamp); + #endif #endif mPubSerial.setup(mConfig, &mSys, &mTimestamp); diff --git a/src/app.h b/src/app.h index 0098c417..154c9954 100644 --- a/src/app.h +++ b/src/app.h @@ -51,7 +51,7 @@ typedef PubSerial PubSerialType; #if defined(PLUGIN_DISPLAY) #include "plugins/Display/Display.h" #include "plugins/Display/Display_data.h" -typedef Display> DisplayType; +typedef Display DisplayType; #endif class app : public IApp, public ah::Scheduler { diff --git a/src/appInterface.h b/src/appInterface.h index 802f21e6..ec0f5437 100644 --- a/src/appInterface.h +++ b/src/appInterface.h @@ -53,8 +53,11 @@ class IApp { virtual bool getSettingsValid() = 0; virtual void setMqttDiscoveryFlag() = 0; virtual void setMqttPowerLimitAck(Inverter<> *iv) = 0; - virtual bool getMqttIsConnected() = 0; + + virtual bool getNrfEnabled() = 0; + virtual bool getCmtEnabled() = 0; + virtual uint32_t getMqttRxCnt() = 0; virtual uint32_t getMqttTxCnt() = 0; diff --git a/src/hm/radio.h b/src/hm/radio.h index 4fd1fe29..55901bd1 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -24,6 +24,8 @@ class Radio { virtual void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit) = 0; virtual bool switchFrequency(Inverter<> *iv, uint32_t fromkHz, uint32_t tokHz) { return true; } virtual bool switchFrequencyCh(Inverter<> *iv, uint8_t fromCh, uint8_t toCh) { return true; } + virtual bool isChipConnected(void) { return false; } + virtual void loop(void) {}; bool get() { diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index e476bdf1..10681ade 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -45,7 +45,7 @@ class CmtRadio : public Radio { } } - bool isConnected() { + bool isChipConnected(void) { return mCmtAvail; } diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index 5efe5e87..2002a94f 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -15,16 +15,17 @@ #include "Display_ePaper.h" #include "Display_data.h" -template +template class Display { public: Display() { mMono = NULL; } - void setup(IApp *app, display_t *cfg, HMSYSTEM *sys, HMRADIO *radio, uint32_t *utcTs) { + void setup(IApp *app, display_t *cfg, HMSYSTEM *sys, RADIO *hmradio, RADIO *hmsradio, uint32_t *utcTs) { mApp = app; - mHmRadio = radio; + mHmRadio = hmradio; + mHmsRadio = hmsradio; mCfg = cfg; mSys = sys; mUtcTs = utcTs; @@ -141,7 +142,16 @@ class Display { mDisplayData.totalPower = (allOff) ? 0.0 : totalPower; // if all inverters are off, total power can't be greater than 0 mDisplayData.totalYieldDay = totalYieldDay; mDisplayData.totalYieldTotal = totalYieldTotal; - mDisplayData.RadioSymbol = mHmRadio->isChipConnected(); + bool nrf_en = mApp->getNrfEnabled(); + bool nrf_ok = nrf_en && mHmRadio->isChipConnected(); + #if defined(ESP32) + bool cmt_en = mApp->getCmtEnabled(); + bool cmt_ok = cmt_en && mHmsRadio->isChipConnected(); + #else + bool cmt_en = false; + bool cmt_ok = false; + #endif + mDisplayData.RadioSymbol = (nrf_ok && !cmt_en) || (cmt_ok && !nrf_en) || (nrf_ok && cmt_ok); mDisplayData.WifiSymbol = (WiFi.status() == WL_CONNECTED); mDisplayData.MQTTSymbol = mApp->getMqttIsConnected(); mDisplayData.RadioRSSI = (0 < mDisplayData.nrProducing) ? ivQuality2RadioRSSI(minQAllInv) : SCHAR_MIN; // Workaround as NRF24 has no RSSI. Approximation by quality levels from heuristic function @@ -212,7 +222,8 @@ class Display { uint32_t *mUtcTs; display_t *mCfg; HMSYSTEM *mSys; - HMRADIO *mHmRadio; + RADIO *mHmRadio; + RADIO *mHmsRadio; uint16_t mRefreshCycle; #if defined(ESP32) diff --git a/src/web/RestApi.h b/src/web/RestApi.h index b53c8b79..c7b073b3 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -547,7 +547,7 @@ class RestApi { void getRadioCmtInfo(JsonObject obj) { obj[F("en")] = (bool) mConfig->cmt.enabled; - obj[F("isconnected")] = mRadioCmt->isConnected(); + obj[F("isconnected")] = mRadioCmt->isChipConnected(); obj[F("sn")] = String(mRadioCmt->getDTUSn(), HEX); } #endif From a4492305a765ba0826c93ef226e71150caf9e413 Mon Sep 17 00:00:00 2001 From: Wusaweki Date: Fri, 1 Dec 2023 15:25:32 +0100 Subject: [PATCH 194/267] change symbol for 'radio not found' (cherry picked from commit 1dbb0ceb2f82fd2e9fe4192763898add140f8c5a) (cherry picked from commit 3b137d029876bab67ac7f4c246c8a2fc4ce0abeb) --- src/plugins/Display/Display_Mono.h | 25 +++++++++--------- tools/fonts/u8g2_font_5x8_symbols_ahoy.bdf | 11 ++++---- tools/fonts/u8g2_font_5x8_symbols_ahoy.c_ | 10 +++---- tools/fonts/u8g2_font_5x8_symbols_ahoy.fon | Bin 2128 -> 2128 bytes .../u8g2_font_ncenB10_symbols10_ahoy.bdf | 22 +++++++-------- .../fonts/u8g2_font_ncenB10_symbols10_ahoy.c_ | 14 +++++----- .../u8g2_font_ncenB10_symbols10_ahoy.fon | Bin 1024 -> 1008 bytes 7 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/plugins/Display/Display_Mono.h b/src/plugins/Display/Display_Mono.h index a360f796..3fc691c2 100644 --- a/src/plugins/Display/Display_Mono.h +++ b/src/plugins/Display/Display_Mono.h @@ -114,8 +114,8 @@ Symbols: \x87 ... moon \x88 ... calendar/day \x89 ... MQTT */ -const uint8_t u8g2_font_5x8_symbols_ahoy[1052] U8G2_FONT_SECTION("u8g2_font_5x8_symbols_ahoy") = - "j\0\3\2\4\4\3\4\5\10\10\0\377\6\377\6\0\1\61\2b\4\3 \5\0\304\11!\7a\306" +const uint8_t u8g2_font_5x8_symbols_ahoy[1049] U8G2_FONT_SECTION("u8g2_font_5x8_symbols_ahoy") = + "j\0\3\2\4\4\3\4\5\10\10\0\377\6\377\6\0\1\61\2b\4\0 \5\0\304\11!\7a\306" "\212!\11\42\7\63\335\212\304\22#\16u\304\232R\222\14JePJI\2$\14u\304\252l\251m" "I\262E\0%\10S\315\212(\351\24&\13t\304\232(i\252\64%\1'\6\61\336\212\1(\7b" "\305\32\245))\11b\305\212(\251(\0*\13T\304\212(Q\206D\211\2+\12U\304\252\60\32\244" @@ -145,9 +145,10 @@ const uint8_t u8g2_font_5x8_symbols_ahoy[1052] U8G2_FONT_SECTION("u8g2_font_5x8_ "\0z\11D\304\212!*\15\1{\12t\304*%L\304(\24|\6a\306\212\3}\13t\304\12\61" "\12\225\60\221\0~\10$\344\232DI\0\5\0\304\12\200\13u\274\212K\242T\266\260\4\201\14f" "D\233!\11#-\312!\11\202\15hD<\65\12\243,\214\302$\16\203\15w<\214C\22F\71\220" - "\26\207A\204\16\205\274\212,)%Y\230%QR\13\205\17\206<\213\60\31\22\311\66D\245!\11\3" - "\206\20\210<\254\342\20]\302(L\246C\30E\0\207\15wD\334X\25\267\341\20\15\21\0\210\16w" - "<\214\203RQ\25I\212\324a\20\211\15f\304\213)\213\244,\222\222\245\0\0\0\0"; + "\26\207A\204\13u\274\212\244\232t\313\241\10\205\17\206<\213\60\31\22\311\66D\245!\11\3\206\20\210" + "<\254\342\20]\302(L\246C\30E\0\207\15wD\334X\25\267\341\20\15\21\0\210\16w<\214\203" + "RQ\25I\212\324a\20\211\15f\304\213)\213\244,\222\222\245\0\0\0\0"; + const uint8_t u8g2_font_ncenB08_symbols8_ahoy[173] U8G2_FONT_SECTION("u8g2_font_ncenB08_symbols8_ahoy") = "\13\0\3\2\4\4\1\2\5\10\11\0\0\10\0\10\0\0\0\0\0\0\224A\14\207\305\70H\321\222H" @@ -157,11 +158,11 @@ const uint8_t u8g2_font_ncenB08_symbols8_ahoy[173] U8G2_FONT_SECTION("u8g2_font_ "Q\4H\14w\307\215Uq\33\16\321\20\1I\21\227\305\311\222aP\245H\221\244H\212\324a\20J" "\5\0\275\0K\5\0\315\0\0\0\0"; -const uint8_t u8g2_font_ncenB10_symbols10_ahoy[220] U8G2_FONT_SECTION("u8g2_font_ncenB10_symbols10_ahoy") = - "\13\0\3\2\4\4\2\2\5\13\13\0\0\13\0\13\0\0\0\0\0\0\303A\15\267\212q\220\42\251\322" +const uint8_t u8g2_font_ncenB10_symbols10_ahoy[217] U8G2_FONT_SECTION("u8g2_font_ncenB10_symbols10_ahoy") = + "\13\0\3\2\4\4\2\2\5\13\13\0\0\13\0\13\0\0\0\0\0\0\300A\15\267\212q\220\42\251\322" "\266\306\275\1B\20\230\236\65da\22Ima\250F\71\254\1C\23\272\272\251\3Q\32\366Q\212\243" - "\70\212\243\70\311\221\0D\20\271\252\361\242F:\242#: {\36\16\1E\22\267\212\361\222\14I\242" - "\14\332\232\216[RJ\232\12F\25\250\233\221\14I\61I\206$\252%J\250Fa\224%J\71G\30" - "\273\312W\316r`T\262DJ\303\64L#%K\304\35\310\342,\3H\27\272\272\217\344P\16\351\210" - "\16\354\300<\244C\70,\303 \16!\0I\24\271\252\241\34\336\1-\223\64-\323\62-\323\62\35x" - "\10J\22\210\232\61Hi\64Di\64DI\226$KeiK\5\0\232\1\0\0\0"; + "\70\212\243\70\311\221\0D\20\271\252\361\242F:\242#: {\36\16\1E\17\267\212\221\264\3Q\35" + "\332\321\34\316\341\14F\25\250\233\221\14I\61I\206$\252%J\250Fa\224%J\71G\30\273\312W" + "\316r`T\262DJ\303\64L#%K\304\35\310\342,\3H\27\272\272\217\344P\16\351\210\16\354\300" + "<\244C\70,\303 \16!\0I\24\271\252\241\34\336\1-\223\64-\323\62-\323\62\35x\10J\22" + "\210\232\61Hi\64Di\64DI\226$KeiK\5\0\212\1\0\0\0"; diff --git a/tools/fonts/u8g2_font_5x8_symbols_ahoy.bdf b/tools/fonts/u8g2_font_5x8_symbols_ahoy.bdf index 82338aa1..b34ec09a 100644 --- a/tools/fonts/u8g2_font_5x8_symbols_ahoy.bdf +++ b/tools/fonts/u8g2_font_5x8_symbols_ahoy.bdf @@ -1243,16 +1243,15 @@ STARTCHAR 132 ENCODING 132 SWIDTH 360 0 DWIDTH 5 0 -BBX 5 8 0 -1 +BBX 5 7 0 -1 BITMAP -88 -50 +A8 +00 +A8 50 20 +00 20 -50 -50 -88 ENDCHAR STARTCHAR 133 ENCODING 133 diff --git a/tools/fonts/u8g2_font_5x8_symbols_ahoy.c_ b/tools/fonts/u8g2_font_5x8_symbols_ahoy.c_ index 0f378f39..18cef0b6 100644 --- a/tools/fonts/u8g2_font_5x8_symbols_ahoy.c_ +++ b/tools/fonts/u8g2_font_5x8_symbols_ahoy.c_ @@ -4,8 +4,8 @@ Glyphs: 106/106 BBX Build Mode: 0 */ -const uint8_t u8g2_font_5x8_symbols_ahoy[1052] U8G2_FONT_SECTION("u8g2_font_5x8_symbols_ahoy") = - "j\0\3\2\4\4\3\4\5\10\10\0\377\6\377\6\0\1\61\2b\4\3 \5\0\304\11!\7a\306" +const uint8_t u8g2_font_5x8_symbols_ahoy[1049] U8G2_FONT_SECTION("u8g2_font_5x8_symbols_ahoy") = + "j\0\3\2\4\4\3\4\5\10\10\0\377\6\377\6\0\1\61\2b\4\0 \5\0\304\11!\7a\306" "\212!\11\42\7\63\335\212\304\22#\16u\304\232R\222\14JePJI\2$\14u\304\252l\251m" "I\262E\0%\10S\315\212(\351\24&\13t\304\232(i\252\64%\1'\6\61\336\212\1(\7b" "\305\32\245))\11b\305\212(\251(\0*\13T\304\212(Q\206D\211\2+\12U\304\252\60\32\244" @@ -35,6 +35,6 @@ const uint8_t u8g2_font_5x8_symbols_ahoy[1052] U8G2_FONT_SECTION("u8g2_font_5x8_ "\0z\11D\304\212!*\15\1{\12t\304*%L\304(\24|\6a\306\212\3}\13t\304\12\61" "\12\225\60\221\0~\10$\344\232DI\0\5\0\304\12\200\13u\274\212K\242T\266\260\4\201\14f" "D\233!\11#-\312!\11\202\15hD<\65\12\243,\214\302$\16\203\15w<\214C\22F\71\220" - "\26\207A\204\16\205\274\212,)%Y\230%QR\13\205\17\206<\213\60\31\22\311\66D\245!\11\3" - "\206\20\210<\254\342\20]\302(L\246C\30E\0\207\15wD\334X\25\267\341\20\15\21\0\210\16w" - "<\214\203RQ\25I\212\324a\20\211\15f\304\213)\213\244,\222\222\245\0\0\0\0"; + "\26\207A\204\13u\274\212\244\232t\313\241\10\205\17\206<\213\60\31\22\311\66D\245!\11\3\206\20\210" + "<\254\342\20]\302(L\246C\30E\0\207\15wD\334X\25\267\341\20\15\21\0\210\16w<\214\203" + "RQ\25I\212\324a\20\211\15f\304\213)\213\244,\222\222\245\0\0\0\0"; diff --git a/tools/fonts/u8g2_font_5x8_symbols_ahoy.fon b/tools/fonts/u8g2_font_5x8_symbols_ahoy.fon index 891ea68901cb05fa6927d6da0e27b9df9b35b17b..0d8283238ba0f71dfa1390bd82955bcb14089687 100644 GIT binary patch delta 20 bcmca0a6w>$3$380i*K7hp9{kOp^l{%_kagPVQjzLgDF7c4UfYaX(IQ(Yu9Ql1S~8< PLMBbNW!^kFfl&Ye5L*_3 From cdba3a99d2a7c31d02b53e8849460b9cee25e6f7 Mon Sep 17 00:00:00 2001 From: Wusaweki Date: Sun, 3 Dec 2023 09:40:22 +0100 Subject: [PATCH 195/267] change logic for radio bar: only consider radio quality of inverters still communicating. All others are shown in nrsleep anyway --- src/plugins/Display/Display.h | 50 ++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index 2002a94f..c6c6f148 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -93,9 +93,9 @@ class Display { if (mCfg->type == 0) return; - float totalPower = 0; - float totalYieldDay = 0; - float totalYieldTotal = 0; + float totalPower = 0.0; + float totalYieldDay = 0.0; + float totalYieldTotal = 0.0; uint8_t nrprod = 0; uint8_t nrsleep = 0; @@ -110,36 +110,38 @@ class Display { if (iv == NULL) continue; - int8_t maxQInv = -6; - for(uint8_t ch = 0; ch < RF_MAX_CHANNEL_ID; ch++) { - int8_t q = iv->txRfQuality[ch]; - if (q > maxQInv) - maxQInv = q; - } - if (maxQInv < minQAllInv) - minQAllInv = maxQInv; - - rec = iv->getRecordStruct(RealTimeRunData_Debug); - - if (iv->isProducing()) + if (iv->isProducing()) // also updates inverter state engine nrprod++; else nrsleep++; - totalPower += iv->getChannelFieldValue(CH0, FLD_PAC, rec); - totalYieldDay += iv->getChannelFieldValue(CH0, FLD_YD, rec); - totalYieldTotal += iv->getChannelFieldValue(CH0, FLD_YT, rec); + rec = iv->getRecordStruct(RealTimeRunData_Debug); - if(allOff) { - if(iv->status != InverterStatus::OFF) - allOff = false; + if (iv->isAvailable()) { // consider only radio quality of inverters still communicating + int8_t maxQInv = -6; + for(uint8_t ch = 0; ch < RF_MAX_CHANNEL_ID; ch++) { + int8_t q = iv->txRfQuality[ch]; + if (q > maxQInv) + maxQInv = q; + } + if (maxQInv < minQAllInv) + minQAllInv = maxQInv; + + totalPower += iv->getChannelFieldValue(CH0, FLD_PAC, rec); // add only FLD_PAC from inverters still communicating + allOff = false; } + + totalYieldDay += iv->getChannelFieldValue(CH0, FLD_YD, rec); + totalYieldTotal += iv->getChannelFieldValue(CH0, FLD_YT, rec); } + if (allOff) + minQAllInv = -6; + // prepare display data mDisplayData.nrProducing = nrprod; mDisplayData.nrSleeping = nrsleep; - mDisplayData.totalPower = (allOff) ? 0.0 : totalPower; // if all inverters are off, total power can't be greater than 0 + mDisplayData.totalPower = totalPower; mDisplayData.totalYieldDay = totalYieldDay; mDisplayData.totalYieldTotal = totalYieldTotal; bool nrf_en = mApp->getNrfEnabled(); @@ -154,7 +156,7 @@ class Display { mDisplayData.RadioSymbol = (nrf_ok && !cmt_en) || (cmt_ok && !nrf_en) || (nrf_ok && cmt_ok); mDisplayData.WifiSymbol = (WiFi.status() == WL_CONNECTED); mDisplayData.MQTTSymbol = mApp->getMqttIsConnected(); - mDisplayData.RadioRSSI = (0 < mDisplayData.nrProducing) ? ivQuality2RadioRSSI(minQAllInv) : SCHAR_MIN; // Workaround as NRF24 has no RSSI. Approximation by quality levels from heuristic function + mDisplayData.RadioRSSI = ivQuality2RadioRSSI(minQAllInv); // Workaround as NRF24 has no RSSI. Approximation by quality levels from heuristic function mDisplayData.WifiRSSI = (WiFi.status() == WL_CONNECTED) ? WiFi.RSSI() : SCHAR_MIN; mDisplayData.ipAddress = WiFi.localIP(); time_t utc= mApp->getTimestamp(); @@ -168,7 +170,7 @@ class Display { } #if defined(ESP32) else if (mCfg->type == 10) { - mEpaper.loop(((allOff) ? 0.0 : totalPower), totalYieldDay, totalYieldTotal, nrprod); + mEpaper.loop((totalPower), totalYieldDay, totalYieldTotal, nrprod); mRefreshCycle++; } From 7c62df071fa07669cccc70efda1739d5904af588 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 4 Dec 2023 08:45:51 +0100 Subject: [PATCH 196/267] started implementation of ethernet for opendtufusion board --- scripts/applyPatches.py | 5 +- src/defines.h | 2 +- src/eth/ahoyeth.cpp | 10 +- src/eth/ahoyeth.h | 6 +- src/eth/ethSpi.h | 141 ++++++++++++++++++++++ src/hm/hmRadio.h | 102 +++++++++------- src/hm/nrfHal.h | 241 ++++++++++++++++++++++++++++++++++++++ src/hm/spiPatcher.h | 78 ++++++++++++ src/hm/spiPatcherHandle.h | 17 +++ src/platformio.ini | 6 +- 10 files changed, 557 insertions(+), 51 deletions(-) create mode 100644 src/eth/ethSpi.h create mode 100644 src/hm/nrfHal.h create mode 100644 src/hm/spiPatcher.h create mode 100644 src/hm/spiPatcherHandle.h diff --git a/scripts/applyPatches.py b/scripts/applyPatches.py index 657525e6..131572fd 100644 --- a/scripts/applyPatches.py +++ b/scripts/applyPatches.py @@ -26,7 +26,10 @@ def applyPatch(libName, patchFile): # list of patches to apply (relative to /src) -applyPatch("ESP Async WebServer", "../patches/AsyncWeb_Prometheus.patch") +if env['PIOENV'][:22] != "opendtufusion-ethernet": + applyPatch("ESP Async WebServer", "../patches/AsyncWeb_Prometheus.patch") if env['PIOENV'][:13] == "opendtufusion": applyPatch("GxEPD2", "../patches/GxEPD2_SW_SPI.patch") +if env['PIOENV'][:22] == "opendtufusion-ethernet": + applyPatch("RF24", "../patches/RF24_Hal.patch") diff --git a/src/defines.h b/src/defines.h index d471a5ef..80b94687 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 13 +#define VERSION_PATCH 14 //------------------------------------- typedef struct { diff --git a/src/eth/ahoyeth.cpp b/src/eth/ahoyeth.cpp index 21fa0821..85b9994c 100644 --- a/src/eth/ahoyeth.cpp +++ b/src/eth/ahoyeth.cpp @@ -11,7 +11,6 @@ #endif #include "ahoyeth.h" - //----------------------------------------------------------------------------- ahoyeth::ahoyeth() { @@ -41,8 +40,11 @@ void ahoyeth::setup(settings_t *config, uint32_t *utcTimestamp, OnNetworkCB onNe if(!ETH.config(ip, gateway, mask, dns1, dns2)) DPRINTLN(DBG_ERROR, F("failed to set static IP!")); } + #if defined(CONFIG_IDF_TARGET_ESP32S3) + mEthSpi.begin(DEF_ETH_MISO_PIN, DEF_ETH_MOSI_PIN, DEF_ETH_SCK_PIN, DEF_ETH_CS_PIN, DEF_ETH_IRQ_PIN, DEF_ETH_RST_PIN); + #else ETH.begin(DEF_ETH_MISO_PIN, DEF_ETH_MOSI_PIN, DEF_ETH_SCK_PIN, DEF_ETH_CS_PIN, DEF_ETH_IRQ_PIN, ETH_SPI_CLOCK_MHZ, ETH_SPI_HOST); - + #endif } @@ -155,7 +157,11 @@ void ahoyeth::onEthernetEvent(WiFiEvent_t event, arduino_event_info_t info) case ARDUINO_EVENT_ETH_GOT_IP: if (!ESP32_W5500_eth_connected) { + #if defined (CONFIG_IDF_TARGET_ESP32S3) + AWS_LOG3(F("ETH MAC: "), mEthSpi.macAddress(), F(", IPv4: "), ETH.localIP()); + #else AWS_LOG3(F("ETH MAC: "), ETH.macAddress(), F(", IPv4: "), ETH.localIP()); + #endif if (ETH.fullDuplex()) { diff --git a/src/eth/ahoyeth.h b/src/eth/ahoyeth.h index 9f5123fb..157a9c76 100644 --- a/src/eth/ahoyeth.h +++ b/src/eth/ahoyeth.h @@ -13,6 +13,7 @@ #include #include +#include "ethSpi.h" #include "../utils/dbg.h" #include "../config/config.h" #include "../config/settings.h" @@ -45,6 +46,9 @@ class ahoyeth { void onEthernetEvent(WiFiEvent_t event, arduino_event_info_t info); private: + #if defined(CONFIG_IDF_TARGET_ESP32S3) + EthSpi mEthSpi; + #endif settings_t *mConfig; uint32_t *mUtcTimestamp; @@ -57,4 +61,4 @@ class ahoyeth { }; #endif /*__AHOYETH_H__*/ -#endif /* defined(ETHERNET) */ \ No newline at end of file +#endif /* defined(ETHERNET) */ diff --git a/src/eth/ethSpi.h b/src/eth/ethSpi.h new file mode 100644 index 00000000..d0ef9487 --- /dev/null +++ b/src/eth/ethSpi.h @@ -0,0 +1,141 @@ +//----------------------------------------------------------------------------- +// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778 +// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +//----------------------------------------------------------------------------- + + +#if defined(CONFIG_IDF_TARGET_ESP32S3) +#if defined(ETHERNET) +#ifndef __ETH_SPI_H__ +#define __ETH_SPI_H__ + +#pragma once + +#include +#include +#include +#include + +// Functions from WiFiGeneric +void tcpipInit(); +void add_esp_interface_netif(esp_interface_t interface, esp_netif_t* esp_netif); + +class EthSpi { + public: + + EthSpi() : + eth_handle(nullptr), + eth_netif(nullptr) {} + + void begin(int8_t pin_miso, int8_t pin_mosi, int8_t pin_sclk, int8_t pin_cs, int8_t pin_int, int8_t pin_rst) { + gpio_reset_pin(static_cast(pin_rst)); + gpio_set_direction(static_cast(pin_rst), GPIO_MODE_OUTPUT); + gpio_set_level(static_cast(pin_rst), 0); + + gpio_reset_pin(static_cast(pin_sclk)); + gpio_reset_pin(static_cast(pin_mosi)); + gpio_reset_pin(static_cast(pin_miso)); + gpio_reset_pin(static_cast(pin_cs)); + gpio_set_pull_mode(static_cast(pin_miso), GPIO_PULLUP_ONLY); + + // Workaround, because calling gpio_install_isr_service directly causes issues with attachInterrupt later + attachInterrupt(digitalPinToInterrupt(pin_int), nullptr, CHANGE); + detachInterrupt(digitalPinToInterrupt(pin_int)); + gpio_reset_pin(static_cast(pin_int)); + gpio_set_pull_mode(static_cast(pin_int), GPIO_PULLUP_ONLY); + + spi_bus_config_t buscfg = { + .mosi_io_num = pin_mosi, + .miso_io_num = pin_miso, + .sclk_io_num = pin_sclk, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + .data4_io_num = -1, + .data5_io_num = -1, + .data6_io_num = -1, + .data7_io_num = -1, + .max_transfer_sz = 0, // uses default value internally + .flags = 0, + .intr_flags = 0 + }; + + ESP_ERROR_CHECK(spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO)); + + spi_device_interface_config_t devcfg = { + .command_bits = 16, // actually address phase + .address_bits = 8, // actually command phase + .dummy_bits = 0, + .mode = 0, + .duty_cycle_pos = 0, + .cs_ena_pretrans = 0, // only 0 supported + .cs_ena_posttrans = 0, // only 0 supported + .clock_speed_hz = 20000000, // stable with on OpenDTU Fusion Shield + .input_delay_ns = 0, + .spics_io_num = pin_cs, + .flags = 0, + .queue_size = 20, + .pre_cb = nullptr, + .post_cb = nullptr + }; + + spi_device_handle_t spi; + ESP_ERROR_CHECK(spi_bus_add_device(SPI3_HOST, &devcfg, &spi)); + + // Reset sequence + delayMicroseconds(500); + gpio_set_level(static_cast(pin_rst), 1); + delayMicroseconds(1000); + + // Arduino function to start networking stack if not already started + tcpipInit(); + + ESP_ERROR_CHECK(tcpip_adapter_set_default_eth_handlers()); // ? + + eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi); + w5500_config.int_gpio_num = pin_int; + + eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG(); + mac_config.rx_task_stack_size = 4096; + esp_eth_mac_t *mac = esp_eth_mac_new_w5500(&w5500_config, &mac_config); + + eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG(); + phy_config.reset_gpio_num = -1; + esp_eth_phy_t *phy = esp_eth_phy_new_w5500(&phy_config); + + esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(mac, phy); + ESP_ERROR_CHECK(esp_eth_driver_install(ð_config, ð_handle)); + + // Configure MAC address + uint8_t mac_addr[6]; + ESP_ERROR_CHECK(esp_efuse_mac_get_default(mac_addr)); + mac_addr[5] |= 0x03; // derive ethernet MAC address from base MAC address + ESP_ERROR_CHECK(esp_eth_ioctl(eth_handle, ETH_CMD_S_MAC_ADDR, mac_addr)); + + esp_netif_config_t netif_config = ESP_NETIF_DEFAULT_ETH(); + eth_netif = esp_netif_new(&netif_config); + + ESP_ERROR_CHECK(esp_netif_attach(eth_netif, esp_eth_new_netif_glue(eth_handle))); + + // Add to Arduino + add_esp_interface_netif(ESP_IF_ETH, eth_netif); + + ESP_ERROR_CHECK(esp_eth_start(eth_handle)); + } + + String macAddress() { + uint8_t mac_addr[6] = {0, 0, 0, 0, 0, 0}; + esp_eth_ioctl(eth_handle, ETH_CMD_G_MAC_ADDR, mac_addr); + char mac_addr_str[24]; + snprintf(mac_addr_str, sizeof(mac_addr_str), "%02X:%02X:%02X:%02X:%02X:%02X", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); + return String(mac_addr_str); + } + + + private: + esp_eth_handle_t eth_handle; + esp_netif_t *eth_netif; +}; + +#endif /*__ETH_SPI_H__*/ +#endif /*ETHERNET*/ +#endif /*CONFIG_IDF_TARGET_ESP32S3*/ diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 18ae549e..82eb85ff 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -9,6 +9,7 @@ #include #include "SPI.h" #include "radio.h" +#include "nrfHal.h" #define SPI_SPEED 1000000 @@ -28,7 +29,7 @@ const char* const rf24AmpPowerNames[] = {"MIN", "LOW", "HIGH", "MAX"}; template class HmRadio : public Radio { public: - HmRadio() : mNrf24(CE_PIN, CS_PIN, SPI_SPEED) { + HmRadio() { mDtuSn = DTU_SN; mIrqRcvd = false; } @@ -36,6 +37,14 @@ class HmRadio : public Radio { void setup(bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint8_t irq = IRQ_PIN, uint8_t ce = CE_PIN, uint8_t cs = CS_PIN, uint8_t sclk = SCLK_PIN, uint8_t mosi = MOSI_PIN, uint8_t miso = MISO_PIN) { DPRINTLN(DBG_VERBOSE, F("hmRadio.h:setup")); + #if defined(CONFIG_IDF_TARGET_ESP32S3) + DBGPRINTLN("1"); + delay(300); + mNrfHal->init(mosi, miso, sclk, cs, ce); + mNrf24 = new RF24(mNrfHal); + #else + mNrf24 = new RF24(CE_PIN, CS_PIN, SPI_SPEED); + #endif pinMode(irq, INPUT_PULLUP); mSerialDebug = serialDebug; @@ -56,39 +65,45 @@ class HmRadio : public Radio { DTU_RADIO_ID = ((uint64_t)(((mDtuSn >> 24) & 0xFF) | ((mDtuSn >> 8) & 0xFF00) | ((mDtuSn << 8) & 0xFF0000) | ((mDtuSn << 24) & 0xFF000000)) << 8) | 0x01; #ifdef ESP32 - #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 - mSpi = new SPIClass(HSPI); - #else - mSpi = new SPIClass(VSPI); + #if !defined(CONFIG_IDF_TARGET_ESP32S3) + #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 + mSpi = new SPIClass(HSPI); + #else + mSpi = new SPIClass(VSPI); + #endif + mSpi->begin(sclk, miso, mosi, cs); #endif - mSpi->begin(sclk, miso, mosi, cs); #else //the old ESP82xx cannot freely place their SPI pins mSpi = new SPIClass(); mSpi->begin(); #endif - mNrf24.begin(mSpi, 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.enableDynamicAck(); - mNrf24.enableDynamicPayloads(); - mNrf24.setCRCLength(RF24_CRC_16); - mNrf24.setAddressWidth(5); - mNrf24.openReadingPipe(1, reinterpret_cast(&DTU_RADIO_ID)); + #if defined(CONFIG_IDF_TARGET_ESP32S3) + mNrf24->begin(); + #else + mNrf24->begin(mSpi, ce, cs); + #endif + 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->enableDynamicAck(); + mNrf24->enableDynamicPayloads(); + mNrf24->setCRCLength(RF24_CRC_16); + mNrf24->setAddressWidth(5); + mNrf24->openReadingPipe(1, reinterpret_cast(&DTU_RADIO_ID)); // enable all receiving interrupts - mNrf24.maskIRQ(false, false, false); + mNrf24->maskIRQ(false, false, false); - mNrf24.setPALevel(1); // low is default + mNrf24->setPALevel(1); // low is default - if(mNrf24.isChipConnected()) { + if(mNrf24->isChipConnected()) { DPRINTLN(DBG_INFO, F("Radio Config:")); - mNrf24.printPrettyDetails(); + mNrf24->printPrettyDetails(); DPRINT(DBG_INFO, F("DTU_SN: 0x")); DBGPRINTLN(String(mDtuSn, HEX)); } else @@ -100,14 +115,14 @@ class HmRadio : public Radio { return; // 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 + mNrf24->whatHappened(tx_ok, tx_fail, rx_ready); // resets the IRQ pin to HIGH + mNrf24->flush_tx(); // empty TX FIFO // start listening - //mNrf24.setChannel(23); + //mNrf24->setChannel(23); //mRxChIdx = 0; - mNrf24.setChannel(mRfChLst[mRxChIdx]); - mNrf24.startListening(); + mNrf24->setChannel(mRfChLst[mRxChIdx]); + mNrf24->startListening(); if(NULL == mLastIv) // prevent reading on NULL object! return; @@ -128,7 +143,7 @@ class HmRadio : public Radio { // switch to next RX channel if(++mRxChIdx >= RF_CHANNELS) mRxChIdx = 0; - mNrf24.setChannel(mRfChLst[mRxChIdx]); + mNrf24->setChannel(mRfChLst[mRxChIdx]); startMicros = micros() + 5110; } // not finished but time is over @@ -140,7 +155,7 @@ class HmRadio : public Radio { bool isChipConnected(void) { //DPRINTLN(DBG_VERBOSE, F("hmRadio.h:isChipConnected")); - return mNrf24.isChipConnected(); + return mNrf24->isChipConnected(); } void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit) { @@ -229,31 +244,31 @@ class HmRadio : public Radio { } uint8_t getDataRate(void) { - if(!mNrf24.isChipConnected()) + if(!mNrf24->isChipConnected()) return 3; // unknown - return mNrf24.getDataRate(); + return mNrf24->getDataRate(); } bool isPVariant(void) { - return mNrf24.isPVariant(); + return mNrf24->isPVariant(); } private: inline bool getReceived(void) { bool tx_ok, tx_fail, rx_ready; - mNrf24.whatHappened(tx_ok, tx_fail, rx_ready); // resets the IRQ pin to HIGH + mNrf24->whatHappened(tx_ok, tx_fail, rx_ready); // resets the IRQ pin to HIGH bool isLastPackage = false; - while(mNrf24.available()) { + while(mNrf24->available()) { uint8_t len; - len = mNrf24.getDynamicPayloadSize(); // if payload size > 32, corrupt payload has been flushed + 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 > MAX_RF_PAYLOAD_SIZE) ? MAX_RF_PAYLOAD_SIZE : len; - p.rssi = mNrf24.testRPD() ? -64 : -75; + p.rssi = mNrf24->testRPD() ? -64 : -75; p.millis = millis() - mMillis; - mNrf24.read(p.packet, p.len); + mNrf24->read(p.packet, p.len); if (p.packet[0] != 0x00) { if(!checkIvSerial(p.packet, mLastIv)) { DPRINT(DBG_WARN, "RX other inverter "); @@ -281,7 +296,7 @@ class HmRadio : public Radio { } void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) { - mNrf24.setPALevel(iv->config->powerLevel & 0x03); + mNrf24->setPALevel(iv->config->powerLevel & 0x03); updateCrcs(&len, appendCrc16); // set TX and RX channels @@ -303,10 +318,10 @@ class HmRadio : public Radio { DBGHEXLN(mTxBuf[9]); } - mNrf24.stopListening(); - mNrf24.setChannel(mTxChIdx); - mNrf24.openWritingPipe(reinterpret_cast(&iv->radioId.u64)); - mNrf24.startWrite(mTxBuf, len, false); // false = request ACK response + mNrf24->stopListening(); + mNrf24->setChannel(mTxChIdx); + mNrf24->openWritingPipe(reinterpret_cast(&iv->radioId.u64)); + mNrf24->startWrite(mTxBuf, len, false); // false = request ACK response mMillis = millis(); mLastIv = iv; @@ -336,7 +351,8 @@ class HmRadio : public Radio { uint32_t mMillis; SPIClass* mSpi; - RF24 mNrf24; + RF24 *mNrf24; + nrfHal *mNrfHal; Inverter<> *mLastIv = NULL; }; diff --git a/src/hm/nrfHal.h b/src/hm/nrfHal.h new file mode 100644 index 00000000..be476a76 --- /dev/null +++ b/src/hm/nrfHal.h @@ -0,0 +1,241 @@ +//----------------------------------------------------------------------------- +// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778 +// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +//----------------------------------------------------------------------------- + +#ifndef __NRF_HAL_H__ +#define __NRF_HAL_H__ + +#pragma once + +#include "spiPatcher.h" + +#include +#include + +#define NRF_MAX_TRANSFER_SZ 64 +#define NRF_DEFAULT_SPI_SPEED 10000000 // 10 MHz + +class nrfHal: public RF24_hal, public SpiPatcherHandle { + public: + nrfHal() : mSpiPatcher(SPI2_HOST) {} + + void patch() override { + esp_rom_gpio_connect_out_signal(mPinMosi, spi_periph_signal[host_device].spid_out, false, false); + esp_rom_gpio_connect_in_signal(mPinMiso, spi_periph_signal[host_device].spiq_in, false); + esp_rom_gpio_connect_out_signal(mPinClk, spi_periph_signal[host_device].spiclk_out, false, false); + } + + void unpatch() override { + esp_rom_gpio_connect_out_signal(mPinMosi, SIG_GPIO_OUT_IDX, false, false); + esp_rom_gpio_connect_in_signal(mPinMiso, GPIO_MATRIX_CONST_ZERO_INPUT, false); + esp_rom_gpio_connect_out_signal(mPinClk, SIG_GPIO_OUT_IDX, false, false); + } + + void init(int8_t mosi, int8_t miso, int8_t sclk, int8_t cs, int8_t en, int32_t speed = 0) { + DHEX(mosi); + DBGPRINT(" "); + DHEX(miso); + DBGPRINT(" "); + DHEX(sclk); + DBGPRINT(" "); + DHEX(cs); + DBGPRINT(" "); + DHEX(en); + DBGPRINTLN(" "); + delay(300); + mPinMosi = static_cast<>(mosi); + DBGPRINTLN("21"); + delay(300); + mPinMiso = static_cast(miso); + DBGPRINTLN("22"); + delay(300); + mPinClk = static_cast(sclk); + DBGPRINTLN("23"); + delay(300); + mPinCs = static_cast(cs); + DBGPRINTLN("24"); + delay(300); + mPinEn = static_cast(en); + DBGPRINTLN("25"); + delay(300); + mSpiSpeed = speed; + + DBGPRINTLN("3"); + delay(300); + host_device = mSpiPatcher.init(); + DBGPRINTLN("4"); + delay(300); + + gpio_reset_pin(mPinMosi); + gpio_set_direction(mPinMosi, GPIO_MODE_OUTPUT); + gpio_set_level(mPinMosi, 1); + + gpio_reset_pin(mPinMiso); + gpio_set_direction(mPinMiso, GPIO_MODE_INPUT); + + gpio_reset_pin(mPinClk); + gpio_set_direction(mPinClk, GPIO_MODE_OUTPUT); + gpio_set_level(mPinClk, 0); + + gpio_reset_pin(mPinCs); + spi_device_interface_config_t devcfg = { + .command_bits = 0, + .address_bits = 0, + .dummy_bits = 0, + .mode = 0, + .duty_cycle_pos = 0, + .cs_ena_pretrans = 0, + .cs_ena_posttrans = 0, + .clock_speed_hz = mSpiSpeed, + .input_delay_ns = 0, + .spics_io_num = mPinCs, + .flags = 0, + .queue_size = 1, + .pre_cb = nullptr, + .post_cb = nullptr + }; + ESP_ERROR_CHECK(spi_bus_add_device(host_device, &devcfg, &spi)); + + gpio_reset_pin(mPinEn); + gpio_set_direction(mPinEn, GPIO_MODE_OUTPUT); + gpio_set_level(mPinEn, 0); + } + + + bool begin() override { + return true; + } + + void end() override {} + + void ce(bool level) override { + gpio_set_level(mPinEn, level); + } + + uint8_t write(uint8_t cmd, const uint8_t* buf, uint8_t len) override { + uint8_t data[NRF_MAX_TRANSFER_SZ]; + data[0] = cmd; + std::copy(&buf[0], &buf[len], &data[1]); + + request_spi(); + + size_t spiLen = (static_cast(len) + 1u) << 3; + spi_transaction_t t = { + .flags = 0, + .cmd = 0, + .addr = 0, + .length = spiLen, + .rxlength = spiLen, + .user = NULL, + .tx_buffer = data, + .rx_buffer = data + }; + ESP_ERROR_CHECK(spi_device_polling_transmit(spi, &t)); + + release_spi(); + + return data[0]; // status + } + + uint8_t write(uint8_t cmd, const uint8_t* buf, uint8_t data_len, uint8_t blank_len) override { + uint8_t data[NRF_MAX_TRANSFER_SZ]; + data[0] = cmd; + memset(data, 0, NRF_MAX_TRANSFER_SZ); + std::copy(&buf[0], &buf[data_len], &data[1]); + + request_spi(); + + size_t spiLen = (static_cast(data_len) + static_cast(blank_len) + 1u) << 3; + spi_transaction_t t = { + .flags = 0, + .cmd = 0, + .addr = 0, + .length = spiLen, + .rxlength = spiLen, + .user = NULL, + .tx_buffer = data, + .rx_buffer = data + }; + ESP_ERROR_CHECK(spi_device_polling_transmit(spi, &t)); + + release_spi(); + + return data[0]; // status + } + + uint8_t read(uint8_t cmd, uint8_t* buf, uint8_t len) override { + uint8_t data[NRF_MAX_TRANSFER_SZ]; + data[0] = cmd; + memset(&data[1], 0xff, len); + + request_spi(); + + size_t spiLen = (static_cast(len) + 1u) << 3; + spi_transaction_t t = { + .flags = 0, + .cmd = 0, + .addr = 0, + .length = spiLen, + .rxlength = spiLen, + .user = NULL, + .tx_buffer = data, + .rx_buffer = data + }; + ESP_ERROR_CHECK(spi_device_polling_transmit(spi, &t)); + + release_spi(); + + std::copy(&data[1], &data[len+1], buf); + return data[0]; // status + } + + uint8_t read(uint8_t cmd, uint8_t* buf, uint8_t data_len, uint8_t blank_len) override { + uint8_t data[NRF_MAX_TRANSFER_SZ]; + data[0] = cmd; + memset(&data[1], 0xff, (data_len + blank_len)); + + request_spi(); + + size_t spiLen = (static_cast(data_len) + static_cast(blank_len) + 1u) << 3; + spi_transaction_t t = { + .flags = 0, + .cmd = 0, + .addr = 0, + .length = spiLen, + .rxlength = spiLen, + .user = NULL, + .tx_buffer = data, + .rx_buffer = data + }; + ESP_ERROR_CHECK(spi_device_polling_transmit(spi, &t)); + + release_spi(); + + std::copy(&data[1], &data[data_len+1], buf); + return data[0]; // status + } + + private: + inline void request_spi() { + mSpiPatcher.request(this); + } + + inline void release_spi() { + mSpiPatcher.release(); + } + + private: + gpio_num_t mPinMosi = GPIO_NUM_NC; + gpio_num_t mPinMiso = GPIO_NUM_NC; + gpio_num_t mPinClk = GPIO_NUM_NC; + gpio_num_t mPinCs = GPIO_NUM_NC; + gpio_num_t mPinEn = GPIO_NUM_NC; + int32_t mSpiSpeed = NRF_DEFAULT_SPI_SPEED; + + spi_host_device_t host_device; + spi_device_handle_t spi; + SpiPatcher mSpiPatcher; +}; + +#endif /*__NRF_HAL_H__*/ diff --git a/src/hm/spiPatcher.h b/src/hm/spiPatcher.h new file mode 100644 index 00000000..4188fa22 --- /dev/null +++ b/src/hm/spiPatcher.h @@ -0,0 +1,78 @@ +//----------------------------------------------------------------------------- +// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778 +// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +//----------------------------------------------------------------------------- + +#ifndef __SPI_PATCHER_H__ +#define __SPI_PATCHER_H__ +#pragma once + +#include "spiPatcherHandle.h" + +#include +#include + +class SpiPatcher { + public: + explicit SpiPatcher(spi_host_device_t host_device) : + host_device(host_device), initialized(false), cur_handle(nullptr) { + // Use binary semaphore instead of mutex for performance reasons + mutex = xSemaphoreCreateBinaryStatic(&mutex_buffer); + xSemaphoreGive(mutex); + } + + ~SpiPatcher() { vSemaphoreDelete(mutex); } + + spi_host_device_t init() { + if (!initialized) { + initialized = true; + + spi_bus_config_t buscfg = { + .mosi_io_num = -1, + .miso_io_num = -1, + .sclk_io_num = -1, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + .data4_io_num = -1, + .data5_io_num = -1, + .data6_io_num = -1, + .data7_io_num = -1, + .max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE, + .flags = 0, + .intr_flags = 0 + }; + ESP_ERROR_CHECK(spi_bus_initialize(host_device, &buscfg, SPI_DMA_DISABLED)); + } + + return host_device; + } + + inline void request(SpiPatcherHandle* handle) { + xSemaphoreTake(mutex, portMAX_DELAY); + + if (cur_handle != handle) { + if (cur_handle) { + cur_handle->unpatch(); + } + cur_handle = handle; + if (cur_handle) { + cur_handle->patch(); + } + } + } + + inline void release() { + xSemaphoreGive(mutex); + } + + private: + const spi_host_device_t host_device; + bool initialized; + + SpiPatcherHandle* cur_handle; + + SemaphoreHandle_t mutex; + StaticSemaphore_t mutex_buffer; +}; + +#endif /*__SPI_PATCHER_H__*/ diff --git a/src/hm/spiPatcherHandle.h b/src/hm/spiPatcherHandle.h new file mode 100644 index 00000000..69aa14df --- /dev/null +++ b/src/hm/spiPatcherHandle.h @@ -0,0 +1,17 @@ +//----------------------------------------------------------------------------- +// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778 +// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +//----------------------------------------------------------------------------- + +#ifndef __SPI_PATCHER_HANDLE_H__ +#define __SPI_PATCHER_HANDLE_H__ +#pragma once + +class SpiPatcherHandle { + public: + virtual ~SpiPatcherHandle() {} + virtual void patch() = 0; + virtual void unpatch() = 0; +}; + +#endif /*__SPI_PATCHER_HANDLE_H__*/ diff --git a/src/platformio.ini b/src/platformio.ini index 643a77a0..da7b1dc5 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -91,8 +91,7 @@ monitor_filters = platform = espressif32 board = esp32dev lib_deps = - khoih-prog/AsyncWebServer_ESP32_W5500 - khoih-prog/AsyncUDP_ESP32_W5500 + https://github.com/yubox-node-org/ESPAsyncWebServer nrf24/RF24 @ ^1.4.8 paulstoffregen/Time @ ^1.6.1 https://github.com/bertmelis/espMqttClient#v1.5.0 @@ -152,7 +151,7 @@ board = esp32-s3-devkitc-1 lib_deps = khoih-prog/AsyncWebServer_ESP32_W5500 khoih-prog/AsyncUDP_ESP32_W5500 - nrf24/RF24 @ ^1.4.8 + https://github.com/nrf24/RF24 @ ^1.4.8 paulstoffregen/Time @ ^1.6.1 https://github.com/bertmelis/espMqttClient#v1.5.0 bblanchon/ArduinoJson @ ^6.21.3 @@ -184,6 +183,7 @@ build_flags = ${env.build_flags} -DDEF_LED1=17 -DLED_ACTIVE_HIGH -DARDUINO_USB_MODE=1 + -DARDUINO_USB_CDC_ON_BOOT=1 monitor_filters = esp32_exception_decoder, colorize From 2c8c49c75d8432bf34d29c1fe52db3d3295dbb8b Mon Sep 17 00:00:00 2001 From: you69man Date: Tue, 5 Dec 2023 18:51:04 +0100 Subject: [PATCH 197/267] fix decimal places for temperature value (issue #1251) --- src/web/html/visualization.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/web/html/visualization.html b/src/web/html/visualization.html index d4ac1557..bff8b4e3 100644 --- a/src/web/html/visualization.html +++ b/src/web/html/visualization.html @@ -108,7 +108,6 @@ if(0 != obj.max_pwr) pwrLimit += ", " + Math.round(obj.max_pwr * obj.power_limit_read / 100) + "W"; } - return ml("div", {class: "row mt-2"}, ml("div", {class: "col"}, [ ml("div", {class: "p-2 " + clh}, @@ -123,7 +122,7 @@ ml("div", {class: "col a-c"}, ml("span", { class: "pointer", onclick: function() { getAjax("/api/inverter/alarm/" + obj.id, parseIvAlarm); }}, ("Alarms: " + obj.alarm_cnt))), - ml("div", {class: "col a-r mx-2 mx-md-1"}, String(obj.ch[0][5]) + t.innerText) + ml("div", {class: "col a-r mx-2 mx-md-1"}, String(obj.ch[0][5].toFixed(1)) + t.innerText) ]) ), ml("div", {class: "p-2 " + clbg}, [ From 25c96676339ed4445b98ae26c736d85d2f6e5391 Mon Sep 17 00:00:00 2001 From: lumapu Date: Wed, 6 Dec 2023 23:15:18 +0100 Subject: [PATCH 198/267] converted CMT to use same SPI as NRF (for fusion board) --- src/app.h | 3 +- src/defines.h | 2 +- src/hm/nrfHal.h | 53 ++------ src/hm/spiPatcher.h | 78 ----------- src/hms/cmt2300a.h | 13 +- src/hms/cmtHal.h | 196 +++++++++++++++++++++++++++ src/hms/esp32_3wSpi.h | 183 ------------------------- src/hms/hmsRadio.h | 12 +- src/utils/spiPatcher.cpp | 9 ++ src/utils/spiPatcher.h | 84 ++++++++++++ src/{hm => utils}/spiPatcherHandle.h | 0 src/web/RestApi.h | 4 +- 12 files changed, 313 insertions(+), 324 deletions(-) delete mode 100644 src/hm/spiPatcher.h create mode 100644 src/hms/cmtHal.h delete mode 100644 src/hms/esp32_3wSpi.h create mode 100644 src/utils/spiPatcher.cpp create mode 100644 src/utils/spiPatcher.h rename src/{hm => utils}/spiPatcherHandle.h (100%) diff --git a/src/app.h b/src/app.h index 0098c417..5ccc7d14 100644 --- a/src/app.h +++ b/src/app.h @@ -40,7 +40,6 @@ typedef HmSystem HmSystemType; #ifdef ESP32 -typedef CmtRadio CmtRadioType; #endif typedef Web WebType; typedef RestApi RestApiType; @@ -322,7 +321,7 @@ class app : public IApp, public ah::Scheduler { //Improv mImprov; #endif #ifdef ESP32 - CmtRadioType mCmtRadio; + CmtRadio<> mCmtRadio; #endif char mVersion[12]; diff --git a/src/defines.h b/src/defines.h index 80b94687..ef559980 100644 --- a/src/defines.h +++ b/src/defines.h @@ -94,7 +94,7 @@ enum {MQTT_STATUS_OFFLINE = 0, MQTT_STATUS_PARTIAL, MQTT_STATUS_ONLINE}; #define MQTT_MAX_PACKET_SIZE 384 -#define PLUGIN_DISPLAY +//#define PLUGIN_DISPLAY typedef struct { uint32_t rxFail; diff --git a/src/hm/nrfHal.h b/src/hm/nrfHal.h index be476a76..49ccbee4 100644 --- a/src/hm/nrfHal.h +++ b/src/hm/nrfHal.h @@ -8,7 +8,7 @@ #pragma once -#include "spiPatcher.h" +#include "../utils/SpiPatcher.h" #include #include @@ -18,12 +18,14 @@ class nrfHal: public RF24_hal, public SpiPatcherHandle { public: - nrfHal() : mSpiPatcher(SPI2_HOST) {} + nrfHal() { + mSpiPatcher = SpiPatcher::getInstance(SPI2_HOST); + } void patch() override { - esp_rom_gpio_connect_out_signal(mPinMosi, spi_periph_signal[host_device].spid_out, false, false); - esp_rom_gpio_connect_in_signal(mPinMiso, spi_periph_signal[host_device].spiq_in, false); - esp_rom_gpio_connect_out_signal(mPinClk, spi_periph_signal[host_device].spiclk_out, false, false); + esp_rom_gpio_connect_out_signal(mPinMosi, spi_periph_signal[mHostDevice].spid_out, false, false); + esp_rom_gpio_connect_in_signal(mPinMiso, spi_periph_signal[mHostDevice].spiq_in, false); + esp_rom_gpio_connect_out_signal(mPinClk, spi_periph_signal[mHostDevice].spiclk_out, false, false); } void unpatch() override { @@ -32,40 +34,15 @@ class nrfHal: public RF24_hal, public SpiPatcherHandle { esp_rom_gpio_connect_out_signal(mPinClk, SIG_GPIO_OUT_IDX, false, false); } - void init(int8_t mosi, int8_t miso, int8_t sclk, int8_t cs, int8_t en, int32_t speed = 0) { - DHEX(mosi); - DBGPRINT(" "); - DHEX(miso); - DBGPRINT(" "); - DHEX(sclk); - DBGPRINT(" "); - DHEX(cs); - DBGPRINT(" "); - DHEX(en); - DBGPRINTLN(" "); - delay(300); - mPinMosi = static_cast<>(mosi); - DBGPRINTLN("21"); - delay(300); + void init(int8_t mosi, int8_t miso, int8_t sclk, int8_t cs, int8_t en, int32_t speed = NRF_DEFAULT_SPI_SPEED) { + mPinMosi = static_cast(mosi); mPinMiso = static_cast(miso); - DBGPRINTLN("22"); - delay(300); mPinClk = static_cast(sclk); - DBGPRINTLN("23"); - delay(300); mPinCs = static_cast(cs); - DBGPRINTLN("24"); - delay(300); mPinEn = static_cast(en); - DBGPRINTLN("25"); - delay(300); mSpiSpeed = speed; - DBGPRINTLN("3"); - delay(300); - host_device = mSpiPatcher.init(); - DBGPRINTLN("4"); - delay(300); + mHostDevice = mSpiPatcher->getDevice(); gpio_reset_pin(mPinMosi); gpio_set_direction(mPinMosi, GPIO_MODE_OUTPUT); @@ -95,7 +72,7 @@ class nrfHal: public RF24_hal, public SpiPatcherHandle { .pre_cb = nullptr, .post_cb = nullptr }; - ESP_ERROR_CHECK(spi_bus_add_device(host_device, &devcfg, &spi)); + ESP_ERROR_CHECK(spi_bus_add_device(mHostDevice, &devcfg, &spi)); gpio_reset_pin(mPinEn); gpio_set_direction(mPinEn, GPIO_MODE_OUTPUT); @@ -218,11 +195,11 @@ class nrfHal: public RF24_hal, public SpiPatcherHandle { private: inline void request_spi() { - mSpiPatcher.request(this); + mSpiPatcher->request(this); } inline void release_spi() { - mSpiPatcher.release(); + mSpiPatcher->release(); } private: @@ -233,9 +210,9 @@ class nrfHal: public RF24_hal, public SpiPatcherHandle { gpio_num_t mPinEn = GPIO_NUM_NC; int32_t mSpiSpeed = NRF_DEFAULT_SPI_SPEED; - spi_host_device_t host_device; + spi_host_device_t mHostDevice; spi_device_handle_t spi; - SpiPatcher mSpiPatcher; + SpiPatcher *mSpiPatcher; }; #endif /*__NRF_HAL_H__*/ diff --git a/src/hm/spiPatcher.h b/src/hm/spiPatcher.h deleted file mode 100644 index 4188fa22..00000000 --- a/src/hm/spiPatcher.h +++ /dev/null @@ -1,78 +0,0 @@ -//----------------------------------------------------------------------------- -// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778 -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ -//----------------------------------------------------------------------------- - -#ifndef __SPI_PATCHER_H__ -#define __SPI_PATCHER_H__ -#pragma once - -#include "spiPatcherHandle.h" - -#include -#include - -class SpiPatcher { - public: - explicit SpiPatcher(spi_host_device_t host_device) : - host_device(host_device), initialized(false), cur_handle(nullptr) { - // Use binary semaphore instead of mutex for performance reasons - mutex = xSemaphoreCreateBinaryStatic(&mutex_buffer); - xSemaphoreGive(mutex); - } - - ~SpiPatcher() { vSemaphoreDelete(mutex); } - - spi_host_device_t init() { - if (!initialized) { - initialized = true; - - spi_bus_config_t buscfg = { - .mosi_io_num = -1, - .miso_io_num = -1, - .sclk_io_num = -1, - .quadwp_io_num = -1, - .quadhd_io_num = -1, - .data4_io_num = -1, - .data5_io_num = -1, - .data6_io_num = -1, - .data7_io_num = -1, - .max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE, - .flags = 0, - .intr_flags = 0 - }; - ESP_ERROR_CHECK(spi_bus_initialize(host_device, &buscfg, SPI_DMA_DISABLED)); - } - - return host_device; - } - - inline void request(SpiPatcherHandle* handle) { - xSemaphoreTake(mutex, portMAX_DELAY); - - if (cur_handle != handle) { - if (cur_handle) { - cur_handle->unpatch(); - } - cur_handle = handle; - if (cur_handle) { - cur_handle->patch(); - } - } - } - - inline void release() { - xSemaphoreGive(mutex); - } - - private: - const spi_host_device_t host_device; - bool initialized; - - SpiPatcherHandle* cur_handle; - - SemaphoreHandle_t mutex; - StaticSemaphore_t mutex_buffer; -}; - -#endif /*__SPI_PATCHER_H__*/ diff --git a/src/hms/cmt2300a.h b/src/hms/cmt2300a.h index 75d2ce5c..24f71608 100644 --- a/src/hms/cmt2300a.h +++ b/src/hms/cmt2300a.h @@ -6,7 +6,7 @@ #ifndef __CMT2300A_H__ #define __CMT2300A_H__ -#include "esp32_3wSpi.h" +#include "cmtHal.h" // detailed register infos from AN142_CMT2300AW_Quick_Start_Guide-Rev0.8.pdf @@ -209,19 +209,12 @@ static uint8_t cmtConfig[0x60] PROGMEM { enum {CMT_SUCCESS = 0, CMT_ERR_SWITCH_STATE, CMT_ERR_TX_PENDING, CMT_FIFO_EMPTY, CMT_ERR_RX_IN_FIFO}; -template class Cmt2300a { - typedef SPI SpiType; public: Cmt2300a() {} void setup(uint8_t pinSclk, uint8_t pinSdio, uint8_t pinCsb, uint8_t pinFcsb) { - mSpi.setup(pinSclk, pinSdio, pinCsb, pinFcsb); - init(); - } - - void setup() { - mSpi.setup(); + mSpi.init(pinSdio, pinSclk, pinCsb, pinFcsb); init(); } @@ -483,7 +476,7 @@ class Cmt2300a { return mSpi.readReg(CMT2300A_CUS_MODE_STA) & CMT2300A_MASK_CHIP_MODE_STA; } - SpiType mSpi; + cmtHal mSpi; uint8_t mCnt; bool mTxPending; bool mInRxMode; diff --git a/src/hms/cmtHal.h b/src/hms/cmtHal.h new file mode 100644 index 00000000..65a3ebbf --- /dev/null +++ b/src/hms/cmtHal.h @@ -0,0 +1,196 @@ +//----------------------------------------------------------------------------- +// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778 +// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +//----------------------------------------------------------------------------- + +#ifndef __CMT_HAL_H__ +#define __CMT_HAL_H__ + +#pragma once + +#include "../utils/SpiPatcher.h" + +#include + +#define CMT_DEFAULT_SPI_SPEED 4000000 // 4 MHz + +class cmtHal : public SpiPatcherHandle { + public: + cmtHal() { + mSpiPatcher = SpiPatcher::getInstance(SPI2_HOST); + } + + void patch() override { + esp_rom_gpio_connect_out_signal(mPinSdio, spi_periph_signal[mHostDevice].spid_out, false, false); + esp_rom_gpio_connect_in_signal(mPinSdio, spi_periph_signal[mHostDevice].spid_in, false); + esp_rom_gpio_connect_out_signal(mPinClk, spi_periph_signal[mHostDevice].spiclk_out, false, false); + } + + void unpatch() override { + esp_rom_gpio_connect_out_signal(mPinSdio, SIG_GPIO_OUT_IDX, false, false); + esp_rom_gpio_connect_in_signal(mPinSdio, GPIO_MATRIX_CONST_ZERO_INPUT, false); + esp_rom_gpio_connect_out_signal(mPinClk, SIG_GPIO_OUT_IDX, false, false); + } + + void init(int8_t sdio, int8_t clk, int8_t cs, int8_t fcs, int32_t speed = CMT_DEFAULT_SPI_SPEED) { + mPinSdio = static_cast(sdio); + mPinClk = static_cast(clk); + mPinCs = static_cast(cs); + mPinFcs = static_cast(fcs); + mSpiSpeed = speed; + + mHostDevice = mSpiPatcher->getDevice(); + + gpio_reset_pin(mPinSdio); + gpio_set_direction(mPinSdio, GPIO_MODE_INPUT_OUTPUT); + gpio_set_level(mPinSdio, 1); + + gpio_reset_pin(mPinClk); + gpio_set_direction(mPinClk, GPIO_MODE_OUTPUT); + gpio_set_level(mPinClk, 0); + + gpio_reset_pin(mPinCs); + spi_device_interface_config_t devcfg_reg = { + .command_bits = 1, + .address_bits = 7, + .dummy_bits = 0, + .mode = 0, + .duty_cycle_pos = 0, + .cs_ena_pretrans = 1, + .cs_ena_posttrans = 1, + .clock_speed_hz = mSpiSpeed, + .input_delay_ns = 0, + .spics_io_num = mPinCs, + .flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE, + .queue_size = 1, + .pre_cb = nullptr, + .post_cb = nullptr + }; + ESP_ERROR_CHECK(spi_bus_add_device(mHostDevice, &devcfg_reg, &spi_reg)); + + gpio_reset_pin(mPinFcs); + spi_device_interface_config_t devcfg_fifo = { + .command_bits = 0, + .address_bits = 0, + .dummy_bits = 0, + .mode = 0, + .duty_cycle_pos = 0, + .cs_ena_pretrans = 2, + .cs_ena_posttrans = static_cast(2 * mSpiSpeed / 1000000), // >2 us + .clock_speed_hz = mSpiSpeed, + .input_delay_ns = 0, + .spics_io_num = mPinFcs, + .flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE, + .queue_size = 1, + .pre_cb = nullptr, + .post_cb = nullptr + }; + ESP_ERROR_CHECK(spi_bus_add_device(mHostDevice, &devcfg_fifo, &spi_fifo)); + } + + uint8_t readReg(uint8_t addr) { + uint8_t data; + + request_spi(); + + spi_transaction_t t = { + .flags = 0, + .cmd = 1, + .addr = addr, + .length = 0, + .rxlength = 8, + .user = NULL, + .tx_buffer = NULL, + .rx_buffer = &data + }; + ESP_ERROR_CHECK(spi_device_polling_transmit(spi_reg, &t)); + + release_spi(); + + return data; + } + + void writeReg(uint8_t addr, uint8_t data) { + request_spi(); + + spi_transaction_t t = { + .flags = 0, + .cmd = 0, + .addr = addr, + .length = 8, + .rxlength = 0, + .user = NULL, + .tx_buffer = &data, + .rx_buffer = NULL + }; + ESP_ERROR_CHECK(spi_device_polling_transmit(spi_reg, &t)); + + release_spi(); + } + + void readFifo(uint8_t buf[], uint8_t *len, uint8_t maxlen) { + request_spi(); + + spi_transaction_t t = { + .flags = 0, + .cmd = 0, + .addr = 0, + .length = 0, + .rxlength = 8, + .user = NULL, + .tx_buffer = NULL, + .rx_buffer = NULL + }; + for (uint8_t i = 0; i < maxlen; i++) { + if(0 == i) + t.rx_buffer = len; + else + t.rx_buffer = buf + i - 1; + ESP_ERROR_CHECK(spi_device_polling_transmit(spi_fifo, &t)); + } + + release_spi(); + } + void writeFifo(const uint8_t buf[], uint16_t len) { + request_spi(); + + spi_transaction_t t = { + .flags = 0, + .cmd = 0, + .addr = 0, + .length = 8, + .rxlength = 0, + .user = NULL, + .tx_buffer = NULL, + .rx_buffer = NULL + }; + for (uint16_t i = 0; i < len; i++) { + t.tx_buffer = buf + i; + ESP_ERROR_CHECK(spi_device_polling_transmit(spi_fifo, &t)); + } + + release_spi(); + } + + private: + inline void request_spi() { + mSpiPatcher->request(this); + } + + inline void release_spi() { + mSpiPatcher->release(); + } + + private: + gpio_num_t mPinSdio = GPIO_NUM_NC; + gpio_num_t mPinClk = GPIO_NUM_NC; + gpio_num_t mPinCs = GPIO_NUM_NC; + gpio_num_t mPinFcs = GPIO_NUM_NC; + int32_t mSpiSpeed = CMT_DEFAULT_SPI_SPEED; + + spi_host_device_t mHostDevice; + spi_device_handle_t spi_reg, spi_fifo; + SpiPatcher *mSpiPatcher; +}; + +#endif /*__CMT_HAL_H__*/ diff --git a/src/hms/esp32_3wSpi.h b/src/hms/esp32_3wSpi.h deleted file mode 100644 index e1c4114b..00000000 --- a/src/hms/esp32_3wSpi.h +++ /dev/null @@ -1,183 +0,0 @@ -//----------------------------------------------------------------------------- -// 2023 Ahoy, https://github.com/lumpapu/ahoy -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ -//----------------------------------------------------------------------------- - -#ifndef __ESP32_3WSPI_H__ -#define __ESP32_3WSPI_H__ - -#include "Arduino.h" -#if defined(ESP32) -#include "driver/spi_master.h" -#include "esp_rom_gpio.h" // for esp_rom_gpio_connect_out_signal - -#define SPI_CLK 1 * 1000 * 1000 // 1MHz - -#define SPI_PARAM_LOCK() \ - do { \ - } while (xSemaphoreTake(paramLock, portMAX_DELAY) != pdPASS) -#define SPI_PARAM_UNLOCK() xSemaphoreGive(paramLock) - -// for ESP32 this is the so-called HSPI -// for ESP32-S2/S3/C3 this nomenclature does not really exist anymore, -// it is simply the first externally usable hardware SPI master controller -#define SPI_CMT SPI2_HOST - -class esp32_3wSpi { - public: - esp32_3wSpi() { - mInitialized = false; - } - - void setup(uint8_t pinSclk = DEF_CMT_SCLK, uint8_t pinSdio = DEF_CMT_SDIO, uint8_t pinCsb = DEF_CMT_CSB, uint8_t pinFcsb = DEF_CMT_FCSB) { - paramLock = xSemaphoreCreateMutex(); - spi_bus_config_t buscfg = { - .mosi_io_num = pinSdio, - .miso_io_num = -1, // single wire MOSI/MISO - .sclk_io_num = pinSclk, - .quadwp_io_num = -1, - .quadhd_io_num = -1, - .max_transfer_sz = 32, - }; - spi_device_interface_config_t devcfg = { - .command_bits = 1, - .address_bits = 7, - .dummy_bits = 0, - .mode = 0, - .cs_ena_pretrans = 1, - .cs_ena_posttrans = 1, - .clock_speed_hz = SPI_CLK, - .spics_io_num = pinCsb, - .flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE, - .queue_size = 1, - .pre_cb = NULL, - .post_cb = NULL, - }; - - ESP_ERROR_CHECK(spi_bus_initialize(SPI_CMT, &buscfg, SPI_DMA_DISABLED)); - ESP_ERROR_CHECK(spi_bus_add_device(SPI_CMT, &devcfg, &spi_reg)); - - // FiFo - spi_device_interface_config_t devcfg2 = { - .command_bits = 0, - .address_bits = 0, - .dummy_bits = 0, - .mode = 0, - .cs_ena_pretrans = 2, - .cs_ena_posttrans = (uint8_t)(1 / (SPI_CLK * 10e6 * 2) + 2), // >2 us - .clock_speed_hz = SPI_CLK, - .spics_io_num = pinFcsb, - .flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE, - .queue_size = 1, - .pre_cb = NULL, - .post_cb = NULL, - }; - ESP_ERROR_CHECK(spi_bus_add_device(SPI_CMT, &devcfg2, &spi_fifo)); - - esp_rom_gpio_connect_out_signal(pinSdio, spi_periph_signal[SPI_CMT].spid_out, true, false); - delay(100); - - //pinMode(pinGpio3, INPUT); - mInitialized = true; - } - - void writeReg(uint8_t addr, uint8_t reg) { - if(!mInitialized) - return; - - uint8_t tx_data; - tx_data = ~reg; - spi_transaction_t t = { - .cmd = 1, - .addr = (uint64_t)(~addr), - .length = 8, - .tx_buffer = &tx_data, - .rx_buffer = NULL - }; - SPI_PARAM_LOCK(); - ESP_ERROR_CHECK(spi_device_polling_transmit(spi_reg, &t)); - SPI_PARAM_UNLOCK(); - delayMicroseconds(100); - } - - uint8_t readReg(uint8_t addr) { - if(!mInitialized) - return 0; - - uint8_t rx_data; - spi_transaction_t t = { - .cmd = 0, - .addr = (uint64_t)(~addr), - .length = 8, - .rxlength = 8, - .tx_buffer = NULL, - .rx_buffer = &rx_data - }; - - SPI_PARAM_LOCK(); - ESP_ERROR_CHECK(spi_device_polling_transmit(spi_reg, &t)); - SPI_PARAM_UNLOCK(); - delayMicroseconds(100); - return rx_data; - } - - void writeFifo(uint8_t buf[], uint8_t len) { - if(!mInitialized) - return; - uint8_t tx_data; - - spi_transaction_t t = { - .length = 8, - .tx_buffer = &tx_data, // reference to write data - .rx_buffer = NULL - }; - - SPI_PARAM_LOCK(); - for(uint8_t i = 0; i < len; i++) { - tx_data = ~buf[i]; // negate buffer contents - ESP_ERROR_CHECK(spi_device_polling_transmit(spi_fifo, &t)); - delayMicroseconds(4); // > 4 us - } - SPI_PARAM_UNLOCK(); - } - - void readFifo(uint8_t buf[], uint8_t *len, uint8_t maxlen) { - if(!mInitialized) - return; - uint8_t rx_data; - - spi_transaction_t t = { - .length = 8, - .rxlength = 8, - .tx_buffer = NULL, - .rx_buffer = &rx_data - }; - - SPI_PARAM_LOCK(); - for(uint8_t i = 0; i < maxlen; i++) { - ESP_ERROR_CHECK(spi_device_polling_transmit(spi_fifo, &t)); - delayMicroseconds(4); // > 4 us - if(0 == i) - *len = rx_data; - else - buf[i-1] = rx_data; - } - SPI_PARAM_UNLOCK(); - } - - private: - spi_device_handle_t spi_reg, spi_fifo; - bool mInitialized; - SemaphoreHandle_t paramLock = NULL; -}; -#else - template - class esp32_3wSpi { - public: - esp32_3wSpi() {} - void setup() {} - void loop() {} - }; -#endif - -#endif /*__ESP32_3WSPI_H__*/ diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index e476bdf1..0f708281 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -9,10 +9,9 @@ #include "cmt2300a.h" #include "../hm/radio.h" -template +template class CmtRadio : public Radio { - typedef SPI SpiType; - typedef Cmt2300a CmtType; + typedef Cmt2300a CmtType; public: CmtRadio() { mDtuSn = DTU_SN; @@ -27,13 +26,6 @@ class CmtRadio : public Radio { mPrintWholeTrace = printWholeTrace; } - void setup(bool *serialDebug, bool *privacyMode, bool genDtuSn = true) { - mCmt.setup(); - reset(genDtuSn); - mPrivacyMode = privacyMode; - mSerialDebug = serialDebug; - } - void loop() { mCmt.loop(); if((!mIrqRcvd) && (!mRqstGetRx)) diff --git a/src/utils/spiPatcher.cpp b/src/utils/spiPatcher.cpp new file mode 100644 index 00000000..c9e323b3 --- /dev/null +++ b/src/utils/spiPatcher.cpp @@ -0,0 +1,9 @@ +//----------------------------------------------------------------------------- +// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778 +// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +//----------------------------------------------------------------------------- + + +#include "spiPatcher.h" + +SpiPatcher *SpiPatcher::mInstance = nullptr; diff --git a/src/utils/spiPatcher.h b/src/utils/spiPatcher.h new file mode 100644 index 00000000..23788a90 --- /dev/null +++ b/src/utils/spiPatcher.h @@ -0,0 +1,84 @@ +//----------------------------------------------------------------------------- +// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778 +// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +//----------------------------------------------------------------------------- + +#ifndef __SPI_PATCHER_H__ +#define __SPI_PATCHER_H__ +#pragma once + +#include "spiPatcherHandle.h" + +#include +#include + +class SpiPatcher { + protected: + SpiPatcher(spi_host_device_t dev) : + mHostDevice(dev), mCurHandle(nullptr) { + // Use binary semaphore instead of mutex for performance reasons + mutex = xSemaphoreCreateBinaryStatic(&mutex_buffer); + xSemaphoreGive(mutex); + + spi_bus_config_t buscfg = { + .mosi_io_num = -1, + .miso_io_num = -1, + .sclk_io_num = -1, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + .data4_io_num = -1, + .data5_io_num = -1, + .data6_io_num = -1, + .data7_io_num = -1, + .max_transfer_sz = SOC_SPI_MAXIMUM_BUFFER_SIZE, + .flags = 0, + .intr_flags = 0 + }; + ESP_ERROR_CHECK(spi_bus_initialize(mHostDevice, &buscfg, SPI_DMA_DISABLED)); + } + + public: + SpiPatcher(SpiPatcher &other) = delete; + void operator=(const SpiPatcher &) = delete; + + static SpiPatcher* getInstance(spi_host_device_t dev) { + if(nullptr == mInstance) + mInstance = new SpiPatcher(dev); + return mInstance; + } + + ~SpiPatcher() { vSemaphoreDelete(mutex); } + + spi_host_device_t getDevice() { + return mHostDevice; + } + + inline void request(SpiPatcherHandle* handle) { + xSemaphoreTake(mutex, portMAX_DELAY); + + if (mCurHandle != handle) { + if (mCurHandle) { + mCurHandle->unpatch(); + } + mCurHandle = handle; + if (mCurHandle) { + mCurHandle->patch(); + } + } + } + + inline void release() { + xSemaphoreGive(mutex); + } + + protected: + static SpiPatcher *mInstance; + + private: + const spi_host_device_t mHostDevice; + SpiPatcherHandle* mCurHandle; + SemaphoreHandle_t mutex; + StaticSemaphore_t mutex_buffer; +}; + +#endif /*__SPI_PATCHER_H__*/ diff --git a/src/hm/spiPatcherHandle.h b/src/utils/spiPatcherHandle.h similarity index 100% rename from src/hm/spiPatcherHandle.h rename to src/utils/spiPatcherHandle.h diff --git a/src/web/RestApi.h b/src/web/RestApi.h index b53c8b79..882a26b9 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -47,7 +47,7 @@ class RestApi { mSys = sys; mRadioNrf = (HmRadio<>*)mApp->getRadioObj(true); #if defined(ESP32) - mRadioCmt = (CmtRadio*)mApp->getRadioObj(false); + mRadioCmt = (CmtRadio<>*)mApp->getRadioObj(false); #endif mConfig = config; mSrv->on("/api", HTTP_GET, std::bind(&RestApi::onApi, this, std::placeholders::_1)); @@ -771,7 +771,7 @@ class RestApi { HMSYSTEM *mSys; HmRadio<> *mRadioNrf; #if defined(ESP32) - CmtRadio *mRadioCmt; + CmtRadio<> *mRadioCmt; #endif AsyncWebServer *mSrv; settings_t *mConfig; From 90ac13dbcd519e2468f90f0a10bf44c7213e9141 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 7 Dec 2023 21:50:43 +0100 Subject: [PATCH 199/267] 0.8.14 * fixed decimal points for temperature (WebUI) PR #1254 * fixed inverter statemachine available state PR #1252 --- src/CHANGES.md | 4 ++++ src/defines.h | 2 +- src/hm/hmInverter.h | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index f40f1991..8ab41187 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,9 @@ # Development Changes +## 0.8.14 - 2023-12-07 +* fixed decimal points for temperature (WebUI) PR #1254 +* fixed inverter statemachine available state PR #1252 + ## 0.8.13 - 2023-11-28 * merge PR #1239 symbolic layout for OLED 128x64 + motion senser functionality * fix MqTT IP addr for ETH connections PR #1240 diff --git a/src/defines.h b/src/defines.h index d471a5ef..80b94687 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 13 +#define VERSION_PATCH 14 //------------------------------------- typedef struct { diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index eddf0664..76f08c77 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -391,6 +391,10 @@ class Inverter { bool isAvailable() { bool avail = false; + + if((recordMeas.ts == 0) && (recordInfo.ts == 0) && (recordConfig.ts == 0) && (recordAlarm.ts == 0)) + return false; + if((*timestamp - recordMeas.ts) < INVERTER_INACT_THRES_SEC) avail = true; if((*timestamp - recordInfo.ts) < INVERTER_INACT_THRES_SEC) From c771c2e5dfa0475ab9e247f146111253fb953995 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 7 Dec 2023 22:01:49 +0100 Subject: [PATCH 200/267] 0.8.14 * fixed NTP update and sunrise calculation #1240 #886 --- src/CHANGES.md | 1 + src/app.cpp | 3 ++- src/eth/ahoyeth.cpp | 6 ++---- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 8ab41187..72eea05e 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -3,6 +3,7 @@ ## 0.8.14 - 2023-12-07 * fixed decimal points for temperature (WebUI) PR #1254 * fixed inverter statemachine available state PR #1252 +* fixed NTPUpdate and sunrise calculation #1240 #886 ## 0.8.13 - 2023-11-28 * merge PR #1239 symbolic layout for OLED 128x64 + motion senser functionality diff --git a/src/app.cpp b/src/app.cpp index dbda9036..737116a8 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -201,7 +201,8 @@ void app::updateNtp(void) { void app::tickNtpUpdate(void) { uint32_t nxtTrig = 5; // default: check again in 5 sec #if defined(ETHERNET) - bool isOK = mEth.updateNtpTime(); + bool isOK = (mTimestamp != 0); + mEth.updateNtpTime(); #else bool isOK = mWifi.getNtpTime(); #endif diff --git a/src/eth/ahoyeth.cpp b/src/eth/ahoyeth.cpp index 21fa0821..4dbfd81c 100644 --- a/src/eth/ahoyeth.cpp +++ b/src/eth/ahoyeth.cpp @@ -57,8 +57,7 @@ bool ahoyeth::updateNtpTime(void) { return false; DPRINTLN(DBG_DEBUG, F("updateNtpTime: checking udp \"connection\"...")); Serial.flush(); - if (!mUdp.connected()) - { + if (!mUdp.connected()) { DPRINTLN(DBG_DEBUG, F("updateNtpTime: About to (re)connect...")); Serial.flush(); IPAddress timeServer; if (!WiFi.hostByName(mConfig->ntp.addr, timeServer)) @@ -68,8 +67,7 @@ bool ahoyeth::updateNtpTime(void) { return false; DPRINTLN(DBG_DEBUG, F("updateNtpTime: Connected...")); Serial.flush(); - mUdp.onPacket([this](AsyncUDPPacket packet) - { + mUdp.onPacket([this](AsyncUDPPacket packet) { DPRINTLN(DBG_DEBUG, F("updateNtpTime: about to handle ntp packet...")); Serial.flush(); this->handleNTPPacket(packet); }); From c3863f49282747762c425ed0668e6e884dd082c7 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 7 Dec 2023 23:28:34 +0100 Subject: [PATCH 201/267] 0.8.14 * display improvments #1248 #1247 * fixed overflow in `hmRadio.h` #1244 --- src/CHANGES.md | 8 +++++--- src/hm/hmRadio.h | 10 +++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 72eea05e..a925fdb6 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,9 +1,11 @@ # Development Changes ## 0.8.14 - 2023-12-07 -* fixed decimal points for temperature (WebUI) PR #1254 -* fixed inverter statemachine available state PR #1252 -* fixed NTPUpdate and sunrise calculation #1240 #886 +* fixed decimal points for temperature (WebUI) PR #1254 #1251 +* fixed inverter statemachine available state PR #1252 #1253 +* fixed NTP update and sunrise calculation #1240 #886 +* display improvments #1248 #1247 +* fixed overflow in `hmRadio.h` #1244 ## 0.8.13 - 2023-11-28 * merge PR #1239 symbolic layout for OLED 128x64 + motion senser functionality diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 18ae549e..4c6b013c 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -112,10 +112,10 @@ class HmRadio : public Radio { if(NULL == mLastIv) // prevent reading on NULL object! return; - uint32_t startMicros = micros() + 5110; - uint32_t loopMillis = millis() + 400; - while (millis() < loopMillis) { - while (micros() < startMicros) { // listen (4088us or?) 5110us to each channel + uint32_t startMicros = micros(); + uint32_t loopMillis = millis(); + while ((millis() - loopMillis) < 400) { + while ((micros() - startMicros) < 5110) { // listen (4088us or?) 5110us to each channel if (mIrqRcvd) { mIrqRcvd = false; @@ -129,7 +129,7 @@ class HmRadio : public Radio { if(++mRxChIdx >= RF_CHANNELS) mRxChIdx = 0; mNrf24.setChannel(mRfChLst[mRxChIdx]); - startMicros = micros() + 5110; + startMicros = micros(); } // not finished but time is over if(++mRxChIdx >= RF_CHANNELS) From 057c80162fe24a71a56a1dab06e963a98d8dd225 Mon Sep 17 00:00:00 2001 From: you69man Date: Wed, 6 Dec 2023 13:15:31 +0100 Subject: [PATCH 202/267] fix setGotNothing (didn't leave Testmode anymore) (cherry picked from commit f802036344f322770df2c261a21402fbd0eb86fd) --- src/hm/Heuristic.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index 540d3326..3579c596 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -68,6 +68,8 @@ class Heuristic { updateQuality(iv, -2); // BAD mTestEn = true; } + else + mTestEn = false; } void printStatus(Inverter<> *iv) { From 468d7a6db7d992c7bdd93397fda2a3f9bda658d7 Mon Sep 17 00:00:00 2001 From: lumapu Date: Fri, 8 Dec 2023 17:29:07 +0100 Subject: [PATCH 203/267] fix compile for ESP32 (not S3 versions) --- src/hm/hmRadio.h | 6 +- src/hms/cmt2300a.h | 8 ++ src/hms/esp32_3wSpi.h | 183 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 195 insertions(+), 2 deletions(-) create mode 100644 src/hms/esp32_3wSpi.h diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 54667571..78a7985e 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -9,7 +9,9 @@ #include #include "SPI.h" #include "radio.h" +#if defined(CONFIG_IDF_TARGET_ESP32S3) #include "nrfHal.h" +#endif #define SPI_SPEED 1000000 @@ -38,8 +40,6 @@ class HmRadio : public Radio { void setup(bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint8_t irq = IRQ_PIN, uint8_t ce = CE_PIN, uint8_t cs = CS_PIN, uint8_t sclk = SCLK_PIN, uint8_t mosi = MOSI_PIN, uint8_t miso = MISO_PIN) { DPRINTLN(DBG_VERBOSE, F("hmRadio.h:setup")); #if defined(CONFIG_IDF_TARGET_ESP32S3) - DBGPRINTLN("1"); - delay(300); mNrfHal->init(mosi, miso, sclk, cs, ce); mNrf24 = new RF24(mNrfHal); #else @@ -352,7 +352,9 @@ class HmRadio : public Radio { SPIClass* mSpi; RF24 *mNrf24; + #if defined(CONFIG_IDF_TARGET_ESP32S3) nrfHal *mNrfHal; + #endif Inverter<> *mLastIv = NULL; }; diff --git a/src/hms/cmt2300a.h b/src/hms/cmt2300a.h index 24f71608..54e7095e 100644 --- a/src/hms/cmt2300a.h +++ b/src/hms/cmt2300a.h @@ -6,7 +6,11 @@ #ifndef __CMT2300A_H__ #define __CMT2300A_H__ +#if defined(CONFIG_IDF_TARGET_ESP32S3) #include "cmtHal.h" +#else +#include "esp32_3wSpi.h" +#endif // detailed register infos from AN142_CMT2300AW_Quick_Start_Guide-Rev0.8.pdf @@ -476,7 +480,11 @@ class Cmt2300a { return mSpi.readReg(CMT2300A_CUS_MODE_STA) & CMT2300A_MASK_CHIP_MODE_STA; } + #if defined(CONFIG_IDF_TARGET_ESP32S3) cmtHal mSpi; + #else + esp32_3wSpi mSpi; + #endif uint8_t mCnt; bool mTxPending; bool mInRxMode; diff --git a/src/hms/esp32_3wSpi.h b/src/hms/esp32_3wSpi.h new file mode 100644 index 00000000..20c42632 --- /dev/null +++ b/src/hms/esp32_3wSpi.h @@ -0,0 +1,183 @@ +//----------------------------------------------------------------------------- +// 2023 Ahoy, https://github.com/lumpapu/ahoy +// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ +//----------------------------------------------------------------------------- + +#ifndef __ESP32_3WSPI_H__ +#define __ESP32_3WSPI_H__ + +#include "Arduino.h" +#if defined(ESP32) +#include "driver/spi_master.h" +#include "esp_rom_gpio.h" // for esp_rom_gpio_connect_out_signal + +#define SPI_CLK 1 * 1000 * 1000 // 1MHz + +#define SPI_PARAM_LOCK() \ + do { \ + } while (xSemaphoreTake(paramLock, portMAX_DELAY) != pdPASS) +#define SPI_PARAM_UNLOCK() xSemaphoreGive(paramLock) + +// for ESP32 this is the so-called HSPI +// for ESP32-S2/S3/C3 this nomenclature does not really exist anymore, +// it is simply the first externally usable hardware SPI master controller +#define SPI_CMT SPI2_HOST + +class esp32_3wSpi { + public: + esp32_3wSpi() { + mInitialized = false; + } + + void init(uint8_t pinSdio = DEF_CMT_SDIO, uint8_t pinSclk = DEF_CMT_SCLK, uint8_t pinCsb = DEF_CMT_CSB, uint8_t pinFcsb = DEF_CMT_FCSB) { + paramLock = xSemaphoreCreateMutex(); + spi_bus_config_t buscfg = { + .mosi_io_num = pinSdio, + .miso_io_num = -1, // single wire MOSI/MISO + .sclk_io_num = pinSclk, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + .max_transfer_sz = 32, + }; + spi_device_interface_config_t devcfg = { + .command_bits = 1, + .address_bits = 7, + .dummy_bits = 0, + .mode = 0, + .cs_ena_pretrans = 1, + .cs_ena_posttrans = 1, + .clock_speed_hz = SPI_CLK, + .spics_io_num = pinCsb, + .flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE, + .queue_size = 1, + .pre_cb = NULL, + .post_cb = NULL, + }; + + ESP_ERROR_CHECK(spi_bus_initialize(SPI_CMT, &buscfg, SPI_DMA_DISABLED)); + ESP_ERROR_CHECK(spi_bus_add_device(SPI_CMT, &devcfg, &spi_reg)); + + // FiFo + spi_device_interface_config_t devcfg2 = { + .command_bits = 0, + .address_bits = 0, + .dummy_bits = 0, + .mode = 0, + .cs_ena_pretrans = 2, + .cs_ena_posttrans = (uint8_t)(1 / (SPI_CLK * 10e6 * 2) + 2), // >2 us + .clock_speed_hz = SPI_CLK, + .spics_io_num = pinFcsb, + .flags = SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_3WIRE, + .queue_size = 1, + .pre_cb = NULL, + .post_cb = NULL, + }; + ESP_ERROR_CHECK(spi_bus_add_device(SPI_CMT, &devcfg2, &spi_fifo)); + + esp_rom_gpio_connect_out_signal(pinSdio, spi_periph_signal[SPI_CMT].spid_out, true, false); + delay(100); + + //pinMode(pinGpio3, INPUT); + mInitialized = true; + } + + void writeReg(uint8_t addr, uint8_t reg) { + if(!mInitialized) + return; + + uint8_t tx_data; + tx_data = ~reg; + spi_transaction_t t = { + .cmd = 1, + .addr = (uint64_t)(~addr), + .length = 8, + .tx_buffer = &tx_data, + .rx_buffer = NULL + }; + SPI_PARAM_LOCK(); + ESP_ERROR_CHECK(spi_device_polling_transmit(spi_reg, &t)); + SPI_PARAM_UNLOCK(); + delayMicroseconds(100); + } + + uint8_t readReg(uint8_t addr) { + if(!mInitialized) + return 0; + + uint8_t rx_data; + spi_transaction_t t = { + .cmd = 0, + .addr = (uint64_t)(~addr), + .length = 8, + .rxlength = 8, + .tx_buffer = NULL, + .rx_buffer = &rx_data + }; + + SPI_PARAM_LOCK(); + ESP_ERROR_CHECK(spi_device_polling_transmit(spi_reg, &t)); + SPI_PARAM_UNLOCK(); + delayMicroseconds(100); + return rx_data; + } + + void writeFifo(uint8_t buf[], uint8_t len) { + if(!mInitialized) + return; + uint8_t tx_data; + + spi_transaction_t t = { + .length = 8, + .tx_buffer = &tx_data, // reference to write data + .rx_buffer = NULL + }; + + SPI_PARAM_LOCK(); + for(uint8_t i = 0; i < len; i++) { + tx_data = ~buf[i]; // negate buffer contents + ESP_ERROR_CHECK(spi_device_polling_transmit(spi_fifo, &t)); + delayMicroseconds(4); // > 4 us + } + SPI_PARAM_UNLOCK(); + } + + void readFifo(uint8_t buf[], uint8_t *len, uint8_t maxlen) { + if(!mInitialized) + return; + uint8_t rx_data; + + spi_transaction_t t = { + .length = 8, + .rxlength = 8, + .tx_buffer = NULL, + .rx_buffer = &rx_data + }; + + SPI_PARAM_LOCK(); + for(uint8_t i = 0; i < maxlen; i++) { + ESP_ERROR_CHECK(spi_device_polling_transmit(spi_fifo, &t)); + delayMicroseconds(4); // > 4 us + if(0 == i) + *len = rx_data; + else + buf[i-1] = rx_data; + } + SPI_PARAM_UNLOCK(); + } + + private: + spi_device_handle_t spi_reg, spi_fifo; + bool mInitialized; + SemaphoreHandle_t paramLock = NULL; +}; +#else + template + class esp32_3wSpi { + public: + esp32_3wSpi() {} + void setup() {} + void loop() {} + }; +#endif + +#endif /*__ESP32_3WSPI_H__*/ From bf5fe900da5849f1d1f94e46c1ccf30bf9b1769b Mon Sep 17 00:00:00 2001 From: lumapu Date: Fri, 8 Dec 2023 17:35:29 +0100 Subject: [PATCH 204/267] fix compile for ESP8266 --- src/app.cpp | 1 - src/app.h | 2 ++ src/hm/hmRadio.h | 1 + src/utils/spiPatcher.cpp | 4 ++-- src/utils/spiPatcher.h | 4 ++++ 5 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/app.cpp b/src/app.cpp index 737116a8..1a4e248c 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -18,7 +18,6 @@ void app::setup() { while (!Serial) yield(); - resetSystem(); mSettings.setup(); diff --git a/src/app.h b/src/app.h index 32b50d34..cb0f8746 100644 --- a/src/app.h +++ b/src/app.h @@ -14,7 +14,9 @@ #include "appInterface.h" #include "hm/hmSystem.h" #include "hm/hmRadio.h" +#if defined(ESP32) #include "hms/hmsRadio.h" +#endif #include "publisher/pubMqtt.h" #include "publisher/pubSerial.h" #include "utils/crc.h" diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 78a7985e..ee5d7ec6 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -9,6 +9,7 @@ #include #include "SPI.h" #include "radio.h" +#include "../config/config.h" #if defined(CONFIG_IDF_TARGET_ESP32S3) #include "nrfHal.h" #endif diff --git a/src/utils/spiPatcher.cpp b/src/utils/spiPatcher.cpp index c9e323b3..0470b476 100644 --- a/src/utils/spiPatcher.cpp +++ b/src/utils/spiPatcher.cpp @@ -3,7 +3,7 @@ // Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ //----------------------------------------------------------------------------- - +#if defined(ESP32) #include "spiPatcher.h" - SpiPatcher *SpiPatcher::mInstance = nullptr; +#endif diff --git a/src/utils/spiPatcher.h b/src/utils/spiPatcher.h index 23788a90..14cb138c 100644 --- a/src/utils/spiPatcher.h +++ b/src/utils/spiPatcher.h @@ -7,6 +7,8 @@ #define __SPI_PATCHER_H__ #pragma once +#if defined(ESP32) + #include "spiPatcherHandle.h" #include @@ -81,4 +83,6 @@ class SpiPatcher { StaticSemaphore_t mutex_buffer; }; +#endif /*ESP32*/ + #endif /*__SPI_PATCHER_H__*/ From 583de41c6f3999015afc292ab69b8639da966b4b Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 9 Dec 2023 00:26:16 +0100 Subject: [PATCH 205/267] fix fusion eth crash --- src/hm/hmRadio.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index ee5d7ec6..c2975c48 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -41,8 +41,8 @@ class HmRadio : public Radio { void setup(bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint8_t irq = IRQ_PIN, uint8_t ce = CE_PIN, uint8_t cs = CS_PIN, uint8_t sclk = SCLK_PIN, uint8_t mosi = MOSI_PIN, uint8_t miso = MISO_PIN) { DPRINTLN(DBG_VERBOSE, F("hmRadio.h:setup")); #if defined(CONFIG_IDF_TARGET_ESP32S3) - mNrfHal->init(mosi, miso, sclk, cs, ce); - mNrf24 = new RF24(mNrfHal); + mNrfHal.init(mosi, miso, sclk, cs, ce); + mNrf24 = new RF24(&mNrfHal); #else mNrf24 = new RF24(CE_PIN, CS_PIN, SPI_SPEED); #endif @@ -354,7 +354,7 @@ class HmRadio : public Radio { SPIClass* mSpi; RF24 *mNrf24; #if defined(CONFIG_IDF_TARGET_ESP32S3) - nrfHal *mNrfHal; + nrfHal mNrfHal; #endif Inverter<> *mLastIv = NULL; }; From d5c45af63d6f17d4dd51a7297f070c5401b9703e Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 9 Dec 2023 00:42:36 +0100 Subject: [PATCH 206/267] disabled epaper display for fusion with ethernet --- src/defines.h | 2 +- src/plugins/Display/Display.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/defines.h b/src/defines.h index ef559980..80b94687 100644 --- a/src/defines.h +++ b/src/defines.h @@ -94,7 +94,7 @@ enum {MQTT_STATUS_OFFLINE = 0, MQTT_STATUS_PARTIAL, MQTT_STATUS_ONLINE}; #define MQTT_MAX_PACKET_SIZE 384 -//#define PLUGIN_DISPLAY +#define PLUGIN_DISPLAY typedef struct { uint32_t rxFail; diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index c6c6f148..8092ad2b 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -42,7 +42,7 @@ class Display { case 4: mMono = new DisplayMono128X32(); break; // SSD1306_128X32 (0.91") case 5: mMono = new DisplayMono64X48(); break; // SSD1306_64X48 (0.66" - Wemos OLED Shield) case 6: mMono = new DisplayMono128X64(); break; // SSD1309_128X64 (2.42") -#if defined(ESP32) +#if defined(ESP32) && !defined(ETHERNET) case 10: mMono = NULL; // ePaper does not use this mRefreshCycle = 0; @@ -83,7 +83,7 @@ class Display { mNewPayload = false; mLoopCnt = 0; } - #if defined(ESP32) + #if defined(ESP32) && !defined(ETHERNET) mEpaper.tickerSecond(); #endif } @@ -168,7 +168,7 @@ class Display { if (mMono ) { mMono->disp(); } -#if defined(ESP32) +#if defined(ESP32) && !defined(ETHERNET) else if (mCfg->type == 10) { mEpaper.loop((totalPower), totalYieldDay, totalYieldTotal, nrprod); mRefreshCycle++; @@ -228,7 +228,7 @@ class Display { RADIO *mHmsRadio; uint16_t mRefreshCycle; -#if defined(ESP32) +#if defined(ESP32) && !defined(ETHERNET) DisplayEPaper mEpaper; #endif DisplayMono *mMono; From 8be701724ccaebac1c7122ff4d1507d81fbb3f86 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 9 Dec 2023 00:49:44 +0100 Subject: [PATCH 207/267] fix startup without usb console --- src/platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platformio.ini b/src/platformio.ini index da7b1dc5..a2cdfcf1 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -183,7 +183,7 @@ build_flags = ${env.build_flags} -DDEF_LED1=17 -DLED_ACTIVE_HIGH -DARDUINO_USB_MODE=1 - -DARDUINO_USB_CDC_ON_BOOT=1 + #-DARDUINO_USB_CDC_ON_BOOT=1 monitor_filters = esp32_exception_decoder, colorize From bb1c3482b42a182170b5eab482d04f8aa4be6ace Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 9 Dec 2023 01:28:14 +0100 Subject: [PATCH 208/267] 0.8.15 * added support for opendtufusion fusion ethernet shield #886 * fixed range of HMS / HMT frequencies to 863 to 870 MHz #1238 * changed `yield effiency` per default to `1.0` #1243 --- src/CHANGES.md | 5 +++++ src/config/settings.h | 2 +- src/defines.h | 2 +- src/web/html/setup.html | 13 +++++++------ 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index a925fdb6..3b8892f2 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,10 @@ # Development Changes +## 0.8.15 - 2023-12-09 +* added support for opendtufusion fusion ethernet shield #886 +* fixed range of HMS / HMT frequencies to 863 to 870 MHz #1238 +* changed `yield effiency` per default to `1.0` #1243 + ## 0.8.14 - 2023-12-07 * fixed decimal points for temperature (WebUI) PR #1254 #1251 * fixed inverter statemachine available state PR #1252 #1253 diff --git a/src/config/settings.h b/src/config/settings.h index 058d2546..556c7e76 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -442,7 +442,7 @@ class settings { mCfg.inst.rstValsCommStop = false; mCfg.inst.startWithoutTime = false; mCfg.inst.rstMaxValsMidNight = false; - mCfg.inst.yieldEffiency = 0.955f; + mCfg.inst.yieldEffiency = 1.0f; for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { mCfg.inst.iv[i].powerLevel = 0xff; // impossible high value diff --git a/src/defines.h b/src/defines.h index 80b94687..ade86df4 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 14 +#define VERSION_PATCH 15 //------------------------------------- typedef struct { diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 9d447f15..87869fd6 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -169,7 +169,7 @@
-
Yield Efficiency (should be between 0.95 and 0.96)
+
Yield Efficiency (Standard 1.0)
@@ -444,8 +444,9 @@ }); for(var i = 0; i < 31; i++) { esp32cmtPa.push([i, String(i-10) + " dBm"]); - if(i < 29) - esp32cmtFreq.push([i, freqFmt.format(860 + i*0.25) + " MHz"]); + } + for(var i = 12; i < 41; i++) { + esp32cmtFreq.push([i, freqFmt.format(860 + i*0.25) + " MHz"]); } /*ENDIF_ESP32*/ var led_high_active = [ @@ -797,10 +798,10 @@ getAjax("/api/setup", cb, "POST", JSON.stringify(o)); } - function cb(obj) { + function cb(obj2) { var e = document.getElementById("res"); - if(!obj.success) - e.innerHTML = "error: " + obj.error; + if(!obj2.success) + e.innerHTML = "error: " + obj2.error; else { modalClose(); getAjax("/api/inverter/list", parseIv); From bd88242feacd2507aa54265393d9f05ab6486e84 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 9 Dec 2023 01:34:36 +0100 Subject: [PATCH 209/267] 0.8.15 * small heuristics improvements #1258 --- src/CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CHANGES.md b/src/CHANGES.md index 3b8892f2..c606e525 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -4,6 +4,7 @@ * added support for opendtufusion fusion ethernet shield #886 * fixed range of HMS / HMT frequencies to 863 to 870 MHz #1238 * changed `yield effiency` per default to `1.0` #1243 +* small heuristics improvements #1258 ## 0.8.14 - 2023-12-07 * fixed decimal points for temperature (WebUI) PR #1254 #1251 From 71e9fbdc0fd48a2096d89a838283d13c66530471 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 9 Dec 2023 02:30:57 +0100 Subject: [PATCH 210/267] 0.8.15 * added class to combine inverter heuristics fields #1258 --- src/CHANGES.md | 1 + src/eth/ahoyeth.cpp | 25 +++++-------- src/hm/Communication.h | 16 ++++----- src/hm/Heuristic.h | 66 +++++++++++++++-------------------- src/hm/HeuristicInv.h | 24 +++++++++++++ src/hm/hmInverter.h | 6 ++-- src/hm/hmRadio.h | 2 +- src/plugins/Display/Display.h | 2 +- 8 files changed, 75 insertions(+), 67 deletions(-) create mode 100644 src/hm/HeuristicInv.h diff --git a/src/CHANGES.md b/src/CHANGES.md index c606e525..d77355df 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -5,6 +5,7 @@ * fixed range of HMS / HMT frequencies to 863 to 870 MHz #1238 * changed `yield effiency` per default to `1.0` #1243 * small heuristics improvements #1258 +* added class to combine inverter heuristics fields #1258 ## 0.8.14 - 2023-12-07 * fixed decimal points for temperature (WebUI) PR #1254 #1251 diff --git a/src/eth/ahoyeth.cpp b/src/eth/ahoyeth.cpp index e0aeffc7..48824429 100644 --- a/src/eth/ahoyeth.cpp +++ b/src/eth/ahoyeth.cpp @@ -132,8 +132,7 @@ void ahoyeth::welcome(String ip, String mode) { void ahoyeth::onEthernetEvent(WiFiEvent_t event, arduino_event_info_t info) { AWS_LOG(F("[ETH]: Got event...")); - switch (event) - { + switch (event) { #if ( ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) ) && ( ARDUINO_ESP32_GIT_VER != 0x46d5afb1 ) ) // For breaking core v2.0.0 // Why so strange to define a breaking enum arduino_event_id_t in WiFiGeneric.h @@ -153,20 +152,16 @@ void ahoyeth::onEthernetEvent(WiFiEvent_t event, arduino_event_info_t info) break; case ARDUINO_EVENT_ETH_GOT_IP: - if (!ESP32_W5500_eth_connected) - { + if (!ESP32_W5500_eth_connected) { #if defined (CONFIG_IDF_TARGET_ESP32S3) AWS_LOG3(F("ETH MAC: "), mEthSpi.macAddress(), F(", IPv4: "), ETH.localIP()); #else AWS_LOG3(F("ETH MAC: "), ETH.macAddress(), F(", IPv4: "), ETH.localIP()); #endif - if (ETH.fullDuplex()) - { - AWS_LOG0(F("FULL_DUPLEX, ")); - } - else - { + if (ETH.fullDuplex()) { + AWS_LOG0(F("FULL_DUPLEX, ")); + } else { AWS_LOG0(F("HALF_DUPLEX, ")); } @@ -212,16 +207,12 @@ void ahoyeth::onEthernetEvent(WiFiEvent_t event, arduino_event_info_t info) break; case SYSTEM_EVENT_ETH_GOT_IP: - if (!ESP32_W5500_eth_connected) - { + if (!ESP32_W5500_eth_connected) { AWS_LOG3(F("ETH MAC: "), ETH.macAddress(), F(", IPv4: "), ETH.localIP()); - if (ETH.fullDuplex()) - { + if (ETH.fullDuplex()) { AWS_LOG0(F("FULL_DUPLEX, ")); - } - else - { + } else { AWS_LOG0(F("HALF_DUPLEX, ")); } diff --git a/src/hm/Communication.h b/src/hm/Communication.h index f41c2206..393330ba 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -88,7 +88,7 @@ class Communication : public CommQueue<> { } else q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); - if(!mHeu.getTestModeEnabled()) + if(!mHeu.getTestModeEnabled(q->iv)) q->iv->radioStatistics.txCnt++; mWaitTimeout = millis() + timeout; mWaitTimeout_min = millis() + timeout_min; @@ -115,7 +115,7 @@ class Communication : public CommQueue<> { } mFirstTry = false; mlastTO_min = timeout_min; - if(!mHeu.getTestModeEnabled()) + if(!mHeu.getTestModeEnabled(q->iv)) q->iv->radioStatistics.retransmits++; // got nothing mState = States::START; break; @@ -180,7 +180,7 @@ class Communication : public CommQueue<> { } if(checkIvSerial(&p->packet[1], q->iv)) { - if(!mHeu.getTestModeEnabled()) + if(!mHeu.getTestModeEnabled(q->iv)) q->iv->radioStatistics.frmCnt++; if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command @@ -193,7 +193,7 @@ class Communication : public CommQueue<> { parseMiFrame(p, q); } } else { - if(!mHeu.getTestModeEnabled()) + if(!mHeu.getTestModeEnabled(q->iv)) q->iv->radioStatistics.rxFail++; // got no complete payload DPRINTLN(DBG_WARN, F("Inverter serial does not match")); mWaitTimeout = millis() + timeout; @@ -464,14 +464,14 @@ class Communication : public CommQueue<> { // ordering of lines is relevant for statistics if(succeeded) { mHeu.setGotAll(iv); - if(!mHeu.getTestModeEnabled()) + if(!mHeu.getTestModeEnabled(iv)) iv->radioStatistics.rxSuccess++; } else if(iv->mGotFragment) { mHeu.setGotFragment(iv); - if(!mHeu.getTestModeEnabled()) + if(!mHeu.getTestModeEnabled(iv)) iv->radioStatistics.rxFail++; // got no complete payload } else { - if(!mHeu.getTestModeEnabled()) + if(!mHeu.getTestModeEnabled(iv)) iv->radioStatistics.rxFailNoAnser++; // got nothing mHeu.setGotNothing(iv); mWaitTimeout = millis() + WAIT_GAP_TIMEOUT; @@ -682,7 +682,7 @@ class Communication : public CommQueue<> { if(q->iv->miMultiParts == 7) { mHeu.setGotAll(q->iv); - if(!mHeu.getTestModeEnabled()) + if(!mHeu.getTestModeEnabled(q->iv)) q->iv->radioStatistics.rxSuccess++; } else mHeu.setGotFragment(q->iv); diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index 3579c596..c75cf545 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -8,11 +8,7 @@ #include "../utils/dbg.h" #include "hmInverter.h" - -#define RF_MAX_CHANNEL_ID 5 -#define RF_MAX_QUALITY 4 -#define RF_MIN_QUALTIY -6 -#define RF_NA -99 +#include "HeuristicInv.h" class Heuristic { public: @@ -23,53 +19,52 @@ class Heuristic { uint8_t bestId = 0; int8_t bestQuality = -6; for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) { - if(iv->txRfQuality[i] > bestQuality) { - bestQuality = iv->txRfQuality[i]; + if(iv->heuristics.txRfQuality[i] > bestQuality) { + bestQuality = iv->heuristics.txRfQuality[i]; bestId = i; } } - if(mTestEn) { + if(iv->heuristics.testEn) { DPRINTLN(DBG_INFO, F("heuristic test mode")); - mTestIdx = (mTestIdx + 1) % RF_MAX_CHANNEL_ID; + iv->heuristics.testIdx = (iv->heuristics.testIdx + 1) % RF_MAX_CHANNEL_ID; - if (mTestIdx == bestId) - mTestIdx = (mTestIdx + 1) % RF_MAX_CHANNEL_ID; + if (iv->heuristics.testIdx == bestId) + iv->heuristics.testIdx = (iv->heuristics.testIdx + 1) % RF_MAX_CHANNEL_ID; // test channel get's quality of best channel (maybe temporarily, see in 'setGotNothing') - mStoredIdx = iv->txRfQuality[mTestIdx]; - iv->txRfQuality[mTestIdx] = bestQuality; + iv->heuristics.storedIdx = iv->heuristics.txRfQuality[iv->heuristics.testIdx]; + iv->heuristics.txRfQuality[iv->heuristics.testIdx] = bestQuality; - iv->txRfChId = mTestIdx; + iv->heuristics.txRfChId = iv->heuristics.testIdx; } else - iv->txRfChId = bestId; + iv->heuristics.txRfChId = bestId; - return id2Ch(iv->txRfChId); + return id2Ch(iv->heuristics.txRfChId); } void setGotAll(Inverter<> *iv) { updateQuality(iv, 2); // GOOD - mTestEn = false; + iv->heuristics.testEn = false; } void setGotFragment(Inverter<> *iv) { updateQuality(iv, 1); // OK - mTestEn = false; + iv->heuristics.testEn = false; } void setGotNothing(Inverter<> *iv) { - if(RF_NA != mStoredIdx) { + if(RF_NA != iv->heuristics.storedIdx) { // if communication fails on first try with temporarily good level, revert it back to its original level - iv->txRfQuality[iv->txRfChId] = mStoredIdx; - mStoredIdx = RF_NA; + iv->heuristics.txRfQuality[iv->heuristics.txRfChId] = iv->heuristics.storedIdx; + iv->heuristics.storedIdx = RF_NA; } - if(!mTestEn) { + if(!iv->heuristics.testEn) { updateQuality(iv, -2); // BAD - mTestEn = true; - } - else - mTestEn = false; + iv->heuristics.testEn = true; + } else + iv->heuristics.testEn = false; } void printStatus(Inverter<> *iv) { @@ -77,7 +72,7 @@ class Heuristic { DBGPRINT(F("Radio infos:")); for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) { DBGPRINT(F(" ")); - DBGPRINT(String(iv->txRfQuality[i])); + DBGPRINT(String(iv->heuristics.txRfQuality[i])); } DBGPRINT(F(" | t: ")); DBGPRINT(String(iv->radioStatistics.txCnt)); @@ -91,17 +86,17 @@ class Heuristic { DBGPRINTLN(String(iv->config->powerLevel)); } - bool getTestModeEnabled(void) { - return mTestEn; + bool getTestModeEnabled(Inverter<> *iv) { + return iv->heuristics.testEn; } private: void updateQuality(Inverter<> *iv, uint8_t quality) { - iv->txRfQuality[iv->txRfChId] += quality; - if(iv->txRfQuality[iv->txRfChId] > RF_MAX_QUALITY) - iv->txRfQuality[iv->txRfChId] = RF_MAX_QUALITY; - else if(iv->txRfQuality[iv->txRfChId] < RF_MIN_QUALTIY) - iv->txRfQuality[iv->txRfChId] = RF_MIN_QUALTIY; + iv->heuristics.txRfQuality[iv->heuristics.txRfChId] += quality; + if(iv->heuristics.txRfQuality[iv->heuristics.txRfChId] > RF_MAX_QUALITY) + iv->heuristics.txRfQuality[iv->heuristics.txRfChId] = RF_MAX_QUALITY; + else if(iv->heuristics.txRfQuality[iv->heuristics.txRfChId] < RF_MIN_QUALTIY) + iv->heuristics.txRfQuality[iv->heuristics.txRfChId] = RF_MIN_QUALTIY; } inline uint8_t id2Ch(uint8_t id) { @@ -117,9 +112,6 @@ class Heuristic { private: uint8_t mChList[5] = {03, 23, 40, 61, 75}; - bool mTestEn = false; - uint8_t mTestIdx = 0; - int8_t mStoredIdx = RF_NA; }; diff --git a/src/hm/HeuristicInv.h b/src/hm/HeuristicInv.h new file mode 100644 index 00000000..1ca9c448 --- /dev/null +++ b/src/hm/HeuristicInv.h @@ -0,0 +1,24 @@ +//----------------------------------------------------------------------------- +// 2023 Ahoy, https://github.com/lumpapu/ahoy +// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed +//----------------------------------------------------------------------------- + +#ifndef __HEURISTIC_INV_H__ +#define __HEURISTIC_INV_H__ + +#define RF_MAX_CHANNEL_ID 5 +#define RF_MAX_QUALITY 4 +#define RF_MIN_QUALTIY -6 +#define RF_NA -99 + +class HeuristicInv { + public: + int8_t txRfQuality[5]; // heuristics tx quality (check 'Heuristics.h') + uint8_t txRfChId; // RF TX channel id + + bool testEn = false; + uint8_t testIdx = 0; + int8_t storedIdx = RF_NA; +}; + +#endif /*__HEURISTIC_INV_H__*/ diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 76f08c77..72bbb7fd 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -12,6 +12,7 @@ #endif #include "hmDefines.h" +#include "HeuristicInv.h" #include "../hms/hmsDefines.h" #include #include @@ -131,8 +132,7 @@ class Inverter { bool mGotLastMsg; // shows if inverter has already finished transmission cycle Radio *radio; // pointer to associated radio class statistics_t radioStatistics; // information about transmitted, failed, ... packets - int8_t txRfQuality[5]; // heuristics tx quality (check 'Heuristics.h') - uint8_t txRfChId; // RF TX channel id + HeuristicInv heuristics; uint8_t curCmtFreq; // current used CMT frequency, used to check if freq. was changed during runtime bool commEnabled; // 'pause night communication' sets this field to false @@ -160,7 +160,7 @@ class Inverter { commEnabled = true; memset(&radioStatistics, 0, sizeof(statistics_t)); - memset(txRfQuality, -6, 5); + memset(heuristics.txRfQuality, -6, 5); memset(mOffYD, 0, sizeof(float) * 6); memset(mLastYD, 0, sizeof(float) * 6); diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index c2975c48..99960e98 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -301,7 +301,7 @@ class HmRadio : public Radio { updateCrcs(&len, appendCrc16); // set TX and RX channels - mTxChIdx = mRfChLst[iv->txRfChId]; + mTxChIdx = mRfChLst[iv->heuristics.txRfChId]; if(*mSerialDebug) { DPRINT_IVID(DBG_INFO, iv->id); diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index 8092ad2b..0cfbd710 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -120,7 +120,7 @@ class Display { if (iv->isAvailable()) { // consider only radio quality of inverters still communicating int8_t maxQInv = -6; for(uint8_t ch = 0; ch < RF_MAX_CHANNEL_ID; ch++) { - int8_t q = iv->txRfQuality[ch]; + int8_t q = iv->heuristics.txRfQuality[ch]; if (q > maxQInv) maxQInv = q; } From cddd0a2d91c1a7d5b488e2336dc259683abb0324 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 9 Dec 2023 02:41:20 +0100 Subject: [PATCH 211/267] 0.8.15 added missing patch file --- patches/RF24_Hal.patch | 981 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 981 insertions(+) create mode 100644 patches/RF24_Hal.patch diff --git a/patches/RF24_Hal.patch b/patches/RF24_Hal.patch new file mode 100644 index 00000000..1a4f159e --- /dev/null +++ b/patches/RF24_Hal.patch @@ -0,0 +1,981 @@ +diff --git a/RF24.cpp b/RF24.cpp +index c0cc732..b6708d9 100644 +--- a/RF24.cpp ++++ b/RF24.cpp +@@ -12,228 +12,24 @@ + + /****************************************************************************/ + +-void RF24::csn(bool mode) +-{ +-#if defined(RF24_TINY) +- if (ce_pin != csn_pin) { +- digitalWrite(csn_pin, mode); +- } +- else { +- if (mode == HIGH) { +- PORTB |= (1 << PINB2); // SCK->CSN HIGH +- delayMicroseconds(RF24_CSN_SETTLE_HIGH_DELAY); // allow csn to settle. +- } +- else { +- PORTB &= ~(1 << PINB2); // SCK->CSN LOW +- delayMicroseconds(RF24_CSN_SETTLE_LOW_DELAY); // allow csn to settle +- } +- } +- // Return, CSN toggle complete +- return; +- +-#elif defined(ARDUINO) && !defined(RF24_SPI_TRANSACTIONS) +- // Minimum ideal SPI bus speed is 2x data rate +- // If we assume 2Mbs data rate and 16Mhz clock, a +- // divider of 4 is the minimum we want. +- // CLK:BUS 8Mhz:2Mhz, 16Mhz:4Mhz, or 20Mhz:5Mhz +- +- #if !defined(SOFTSPI) +- // applies to SPI_UART and inherent hardware SPI +- #if defined(RF24_SPI_PTR) +- _spi->setBitOrder(MSBFIRST); +- _spi->setDataMode(SPI_MODE0); +- +- #if !defined(F_CPU) || F_CPU < 20000000 +- _spi->setClockDivider(SPI_CLOCK_DIV2); +- #elif F_CPU < 40000000 +- _spi->setClockDivider(SPI_CLOCK_DIV4); +- #elif F_CPU < 80000000 +- _spi->setClockDivider(SPI_CLOCK_DIV8); +- #elif F_CPU < 160000000 +- _spi->setClockDivider(SPI_CLOCK_DIV16); +- #elif F_CPU < 320000000 +- _spi->setClockDivider(SPI_CLOCK_DIV32); +- #elif F_CPU < 640000000 +- _spi->setClockDivider(SPI_CLOCK_DIV64); +- #elif F_CPU < 1280000000 +- _spi->setClockDivider(SPI_CLOCK_DIV128); +- #else // F_CPU >= 1280000000 +- #error "Unsupported CPU frequency. Please set correct SPI divider." +- #endif // F_CPU to SPI_CLOCK_DIV translation +- +- #else // !defined(RF24_SPI_PTR) +- _SPI.setBitOrder(MSBFIRST); +- _SPI.setDataMode(SPI_MODE0); +- +- #if !defined(F_CPU) || F_CPU < 20000000 +- _SPI.setClockDivider(SPI_CLOCK_DIV2); +- #elif F_CPU < 40000000 +- _SPI.setClockDivider(SPI_CLOCK_DIV4); +- #elif F_CPU < 80000000 +- _SPI.setClockDivider(SPI_CLOCK_DIV8); +- #elif F_CPU < 160000000 +- _SPI.setClockDivider(SPI_CLOCK_DIV16); +- #elif F_CPU < 320000000 +- _SPI.setClockDivider(SPI_CLOCK_DIV32); +- #elif F_CPU < 640000000 +- _SPI.setClockDivider(SPI_CLOCK_DIV64); +- #elif F_CPU < 1280000000 +- _SPI.setClockDivider(SPI_CLOCK_DIV128); +- #else // F_CPU >= 1280000000 +- #error "Unsupported CPU frequency. Please set correct SPI divider." +- #endif // F_CPU to SPI_CLOCK_DIV translation +- #endif // !defined(RF24_SPI_PTR) +- #endif // !defined(SOFTSPI) +- +-#elif defined(RF24_RPi) +- if (!mode) +- _SPI.chipSelect(csn_pin); +-#endif // defined(RF24_RPi) +- +-#if !defined(RF24_LINUX) +- digitalWrite(csn_pin, mode); +- delayMicroseconds(csDelay); +-#else +- static_cast(mode); // ignore -Wunused-parameter +-#endif // !defined(RF24_LINUX) +-} +- +-/****************************************************************************/ +- + void RF24::ce(bool level) + { +-#ifndef RF24_LINUX +- //Allow for 3-pin use on ATTiny +- if (ce_pin != csn_pin) { +-#endif +- digitalWrite(ce_pin, level); +-#ifndef RF24_LINUX +- } +-#endif +-} +- +-/****************************************************************************/ +- +-inline void RF24::beginTransaction() +-{ +-#if defined(RF24_SPI_TRANSACTIONS) +- #if defined(RF24_SPI_PTR) +- #if defined(RF24_RP2) +- _spi->beginTransaction(spi_speed); +- #else // ! defined (RF24_RP2) +- _spi->beginTransaction(SPISettings(spi_speed, MSBFIRST, SPI_MODE0)); +- #endif // ! defined (RF24_RP2) +- #else // !defined(RF24_SPI_PTR) +- _SPI.beginTransaction(SPISettings(spi_speed, MSBFIRST, SPI_MODE0)); +- #endif // !defined(RF24_SPI_PTR) +-#endif // defined (RF24_SPI_TRANSACTIONS) +- csn(LOW); +-} +- +-/****************************************************************************/ +- +-inline void RF24::endTransaction() +-{ +- csn(HIGH); +-#if defined(RF24_SPI_TRANSACTIONS) +- #if defined(RF24_SPI_PTR) +- _spi->endTransaction(); +- #else // !defined(RF24_SPI_PTR) +- _SPI.endTransaction(); +- #endif // !defined(RF24_SPI_PTR) +-#endif // defined (RF24_SPI_TRANSACTIONS) ++ hal->ce(level); + } + + /****************************************************************************/ + + void RF24::read_register(uint8_t reg, uint8_t* buf, uint8_t len) + { +-#if defined(RF24_LINUX) || defined(RF24_RP2) +- beginTransaction(); //configures the spi settings for RPi, locks mutex and setting csn low +- uint8_t* prx = spi_rxbuff; +- uint8_t* ptx = spi_txbuff; +- uint8_t size = static_cast(len + 1); // Add register value to transmit buffer +- +- *ptx++ = (R_REGISTER | reg); +- +- while (len--) { +- *ptx++ = RF24_NOP; // Dummy operation, just for reading +- } +- +- #if defined(RF24_RP2) +- _spi->transfernb((const uint8_t*)spi_txbuff, spi_rxbuff, size); +- #else // !defined (RF24_RP2) +- _SPI.transfernb(reinterpret_cast(spi_txbuff), reinterpret_cast(spi_rxbuff), size); +- #endif // !defined (RF24_RP2) +- +- status = *prx++; // status is 1st byte of receive buffer +- +- // decrement before to skip status byte +- while (--size) { +- *buf++ = *prx++; +- } +- +- endTransaction(); // unlocks mutex and setting csn high +- +-#else // !defined(RF24_LINUX) && !defined(RF24_RP2) +- +- beginTransaction(); +- #if defined(RF24_SPI_PTR) +- status = _spi->transfer(R_REGISTER | reg); +- while (len--) { +- *buf++ = _spi->transfer(0xFF); +- } +- +- #else // !defined(RF24_SPI_PTR) +- status = _SPI.transfer(R_REGISTER | reg); +- while (len--) { +- *buf++ = _SPI.transfer(0xFF); +- } +- +- #endif // !defined(RF24_SPI_PTR) +- endTransaction(); +-#endif // !defined(RF24_LINUX) && !defined(RF24_RP2) ++ status = hal->read(R_REGISTER | reg, buf, len); + } + + /****************************************************************************/ + + uint8_t RF24::read_register(uint8_t reg) + { +- uint8_t result; +- +-#if defined(RF24_LINUX) || defined(RF24_RP2) +- beginTransaction(); +- +- uint8_t* prx = spi_rxbuff; +- uint8_t* ptx = spi_txbuff; +- *ptx++ = (R_REGISTER | reg); +- *ptx++ = RF24_NOP; // Dummy operation, just for reading +- +- #if defined(RF24_RP2) +- _spi->transfernb((const uint8_t*)spi_txbuff, spi_rxbuff, 2); +- #else // !defined(RF24_RP2) +- _SPI.transfernb(reinterpret_cast(spi_txbuff), reinterpret_cast(spi_rxbuff), 2); +- #endif // !defined(RF24_RP2) +- +- status = *prx; // status is 1st byte of receive buffer +- result = *++prx; // result is 2nd byte of receive buffer +- +- endTransaction(); +-#else // !defined(RF24_LINUX) && !defined(RF24_RP2) +- +- beginTransaction(); +- #if defined(RF24_SPI_PTR) +- status = _spi->transfer(R_REGISTER | reg); +- result = _spi->transfer(0xff); +- +- #else // !defined(RF24_SPI_PTR) +- status = _SPI.transfer(R_REGISTER | reg); +- result = _SPI.transfer(0xff); +- +- #endif // !defined(RF24_SPI_PTR) +- endTransaction(); +-#endif // !defined(RF24_LINUX) && !defined(RF24_RP2) +- ++ uint8_t result = 0xff; ++ status = hal->read(R_REGISTER | reg, &result, sizeof(result)); + return result; + } + +@@ -241,43 +37,7 @@ uint8_t RF24::read_register(uint8_t reg) + + void RF24::write_register(uint8_t reg, const uint8_t* buf, uint8_t len) + { +-#if defined(RF24_LINUX) || defined(RF24_RP2) +- beginTransaction(); +- uint8_t* prx = spi_rxbuff; +- uint8_t* ptx = spi_txbuff; +- uint8_t size = static_cast(len + 1); // Add register value to transmit buffer +- +- *ptx++ = (W_REGISTER | (REGISTER_MASK & reg)); +- while (len--) { +- *ptx++ = *buf++; +- } +- +- #if defined(RF24_RP2) +- _spi->transfernb((const uint8_t*)spi_txbuff, spi_rxbuff, size); +- #else // !defined(RF24_RP2) +- _SPI.transfernb(reinterpret_cast(spi_txbuff), reinterpret_cast(spi_rxbuff), size); +- #endif // !defined(RF24_RP2) +- +- status = *prx; // status is 1st byte of receive buffer +- endTransaction(); +-#else // !defined(RF24_LINUX) && !defined(RF24_RP2) +- +- beginTransaction(); +- #if defined(RF24_SPI_PTR) +- status = _spi->transfer(W_REGISTER | reg); +- while (len--) { +- _spi->transfer(*buf++); +- } +- +- #else // !defined(RF24_SPI_PTR) +- status = _SPI.transfer(W_REGISTER | reg); +- while (len--) { +- _SPI.transfer(*buf++); +- } +- +- #endif // !defined(RF24_SPI_PTR) +- endTransaction(); +-#endif // !defined(RF24_LINUX) && !defined(RF24_RP2) ++ status = hal->write(W_REGISTER | reg, buf, len); + } + + /****************************************************************************/ +@@ -288,47 +48,11 @@ void RF24::write_register(uint8_t reg, uint8_t value, bool is_cmd_only) + if (reg != RF24_NOP) { // don't print the get_status() operation + IF_SERIAL_DEBUG(printf_P(PSTR("write_register(%02x)\r\n"), reg)); + } +- beginTransaction(); +-#if defined(RF24_LINUX) +- status = _SPI.transfer(W_REGISTER | reg); +-#else // !defined(RF24_LINUX) || defined (RF24_RP2) +- #if defined(RF24_SPI_PTR) +- status = _spi->transfer(W_REGISTER | reg); +- #else // !defined (RF24_SPI_PTR) +- status = _SPI.transfer(W_REGISTER | reg); +- #endif // !defined (RF24_SPI_PTR) +-#endif // !defined(RF24_LINUX) || defined(RF24_RP2) +- endTransaction(); ++ status = hal->write(W_REGISTER | reg, nullptr, 0); + } + else { + IF_SERIAL_DEBUG(printf_P(PSTR("write_register(%02x,%02x)\r\n"), reg, value)); +-#if defined(RF24_LINUX) || defined(RF24_RP2) +- beginTransaction(); +- uint8_t* prx = spi_rxbuff; +- uint8_t* ptx = spi_txbuff; +- *ptx++ = (W_REGISTER | reg); +- *ptx = value; +- +- #if defined(RF24_RP2) +- _spi->transfernb((const uint8_t*)spi_txbuff, spi_rxbuff, 2); +- #else // !defined(RF24_RP2) +- _SPI.transfernb(reinterpret_cast(spi_txbuff), reinterpret_cast(spi_rxbuff), 2); +- #endif // !defined(RF24_RP2) +- +- status = *prx++; // status is 1st byte of receive buffer +- endTransaction(); +-#else // !defined(RF24_LINUX) && !defined(RF24_RP2) +- +- beginTransaction(); +- #if defined(RF24_SPI_PTR) +- status = _spi->transfer(W_REGISTER | reg); +- _spi->transfer(value); +- #else // !defined(RF24_SPI_PTR) +- status = _SPI.transfer(W_REGISTER | reg); +- _SPI.transfer(value); +- #endif // !defined(RF24_SPI_PTR) +- endTransaction(); +-#endif // !defined(RF24_LINUX) && !defined(RF24_RP2) ++ status = hal->write(W_REGISTER | reg, &value, sizeof(value)); + } + } + +@@ -347,60 +71,8 @@ void RF24::write_payload(const void* buf, uint8_t data_len, const uint8_t writeT + data_len = rf24_min(data_len, static_cast(32)); + } + +- //printf("[Writing %u bytes %u blanks]",data_len,blank_len); + IF_SERIAL_DEBUG(printf("[Writing %u bytes %u blanks]\n", data_len, blank_len);); +- +-#if defined(RF24_LINUX) || defined(RF24_RP2) +- beginTransaction(); +- uint8_t* prx = spi_rxbuff; +- uint8_t* ptx = spi_txbuff; +- uint8_t size; +- size = static_cast(data_len + blank_len + 1); // Add register value to transmit buffer +- +- *ptx++ = writeType; +- while (data_len--) { +- *ptx++ = *current++; +- } +- +- while (blank_len--) { +- *ptx++ = 0; +- } +- +- #if defined(RF24_RP2) +- _spi->transfernb((const uint8_t*)spi_txbuff, spi_rxbuff, size); +- #else // !defined(RF24_RP2) +- _SPI.transfernb(reinterpret_cast(spi_txbuff), reinterpret_cast(spi_rxbuff), size); +- #endif // !defined(RF24_RP2) +- +- status = *prx; // status is 1st byte of receive buffer +- endTransaction(); +- +-#else // !defined(RF24_LINUX) && !defined(RF24_RP2) +- +- beginTransaction(); +- #if defined(RF24_SPI_PTR) +- status = _spi->transfer(writeType); +- while (data_len--) { +- _spi->transfer(*current++); +- } +- +- while (blank_len--) { +- _spi->transfer(0); +- } +- +- #else // !defined(RF24_SPI_PTR) +- status = _SPI.transfer(writeType); +- while (data_len--) { +- _SPI.transfer(*current++); +- } +- +- while (blank_len--) { +- _SPI.transfer(0); +- } +- +- #endif // !defined(RF24_SPI_PTR) +- endTransaction(); +-#endif // !defined(RF24_LINUX) && !defined(RF24_RP2) ++ status = hal->write(writeType, current, data_len, blank_len); + } + + /****************************************************************************/ +@@ -421,65 +93,7 @@ void RF24::read_payload(void* buf, uint8_t data_len) + //printf("[Reading %u bytes %u blanks]",data_len,blank_len); + + IF_SERIAL_DEBUG(printf("[Reading %u bytes %u blanks]\n", data_len, blank_len);); +- +-#if defined(RF24_LINUX) || defined(RF24_RP2) +- beginTransaction(); +- uint8_t* prx = spi_rxbuff; +- uint8_t* ptx = spi_txbuff; +- uint8_t size; +- size = static_cast(data_len + blank_len + 1); // Add register value to transmit buffer +- +- *ptx++ = R_RX_PAYLOAD; +- while (--size) { +- *ptx++ = RF24_NOP; +- } +- +- size = static_cast(data_len + blank_len + 1); // Size has been lost during while, re affect +- +- #if defined(RF24_RP2) +- _spi->transfernb((const uint8_t*)spi_txbuff, spi_rxbuff, size); +- #else // !defined(RF24_RP2) +- _SPI.transfernb(reinterpret_cast(spi_txbuff), reinterpret_cast(spi_rxbuff), size); +- #endif // !defined(RF24_RP2) +- +- status = *prx++; // 1st byte is status +- +- if (data_len > 0) { +- // Decrement before to skip 1st status byte +- while (--data_len) { +- *current++ = *prx++; +- } +- +- *current = *prx; +- } +- endTransaction(); +-#else // !defined(RF24_LINUX) && !defined(RF24_RP2) +- +- beginTransaction(); +- #if defined(RF24_SPI_PTR) +- status = _spi->transfer(R_RX_PAYLOAD); +- while (data_len--) { +- *current++ = _spi->transfer(0xFF); +- } +- +- while (blank_len--) { +- _spi->transfer(0xFF); +- } +- +- #else // !defined(RF24_SPI_PTR) +- status = _SPI.transfer(R_RX_PAYLOAD); +- while (data_len--) { +- *current++ = _SPI.transfer(0xFF); +- } +- +- while (blank_len--) { +- _SPI.transfer(0xff); +- } +- +- #endif // !defined(RF24_SPI_PTR) +- endTransaction(); +- +-#endif // !defined(RF24_LINUX) && !defined(RF24_RP2) ++ status = hal->read(R_RX_PAYLOAD, current, data_len, blank_len); + } + + /****************************************************************************/ +@@ -577,16 +191,16 @@ uint8_t RF24::sprintf_address_register(char* out_buffer, uint8_t reg, uint8_t qt + + /****************************************************************************/ + +-RF24::RF24(rf24_gpio_pin_t _cepin, rf24_gpio_pin_t _cspin, uint32_t _spi_speed) +- : ce_pin(_cepin), csn_pin(_cspin), spi_speed(_spi_speed), payload_size(32), _is_p_variant(false), _is_p0_rx(false), addr_width(5), dynamic_payloads_enabled(true), csDelay(5) ++RF24::RF24(RF24_hal* _hal) ++ : hal(_hal), payload_size(32), _is_p_variant(false), _is_p0_rx(false), addr_width(5), dynamic_payloads_enabled(true), csDelay(5) + { + _init_obj(); + } + + /****************************************************************************/ + +-RF24::RF24(uint32_t _spi_speed) +- : ce_pin(RF24_PIN_INVALID), csn_pin(RF24_PIN_INVALID), spi_speed(_spi_speed), payload_size(32), _is_p_variant(false), _is_p0_rx(false), addr_width(5), dynamic_payloads_enabled(true), csDelay(5) ++RF24::RF24() ++ : hal(nullptr), payload_size(32), _is_p_variant(false), _is_p0_rx(false), addr_width(5), dynamic_payloads_enabled(true), csDelay(5) + { + _init_obj(); + } +@@ -595,16 +209,7 @@ RF24::RF24(uint32_t _spi_speed) + + void RF24::_init_obj() + { +- // Use a pointer on the Arduino platform +- +-#if defined(RF24_SPI_PTR) && !defined(RF24_RP2) +- _spi = &SPI; +-#endif // defined (RF24_SPI_PTR) +- + pipe0_reading_address[0] = 0; +- if (spi_speed <= 35000) { //Handle old BCM2835 speed constants, default to RF24_SPI_SPEED +- spi_speed = RF24_SPI_SPEED; +- } + } + + /****************************************************************************/ +@@ -677,19 +282,6 @@ static const PROGMEM char* const rf24_pa_dbm_e_str_P[] = { + rf24_pa_dbm_e_str_3, + }; + +- #if defined(RF24_LINUX) +-static const char rf24_csn_e_str_0[] = "CE0 (PI Hardware Driven)"; +-static const char rf24_csn_e_str_1[] = "CE1 (PI Hardware Driven)"; +-static const char rf24_csn_e_str_2[] = "CE2 (PI Hardware Driven)"; +-static const char rf24_csn_e_str_3[] = "Custom GPIO Software Driven"; +-static const char* const rf24_csn_e_str_P[] = { +- rf24_csn_e_str_0, +- rf24_csn_e_str_1, +- rf24_csn_e_str_2, +- rf24_csn_e_str_3, +-}; +- #endif // defined(RF24_LINUX) +- + static const PROGMEM char rf24_feature_e_str_on[] = "= Enabled"; + static const PROGMEM char rf24_feature_e_str_allowed[] = "= Allowed"; + static const PROGMEM char rf24_feature_e_str_open[] = " open "; +@@ -704,19 +296,6 @@ static const PROGMEM char* const rf24_feature_e_str_P[] = { + + void RF24::printDetails(void) + { +- +- #if defined(RF24_LINUX) +- printf("================ SPI Configuration ================\n"); +- uint8_t bus_ce = static_cast(csn_pin % 10); +- uint8_t bus_numb = static_cast((csn_pin - bus_ce) / 10); +- printf("CSN Pin\t\t= /dev/spidev%d.%d\n", bus_numb, bus_ce); +- printf("CE Pin\t\t= Custom GPIO%d\n", ce_pin); +- #endif +- printf_P(PSTR("SPI Speedz\t= %d Mhz\n"), static_cast(spi_speed / 1000000)); //Print the SPI speed on non-Linux devices +- #if defined(RF24_LINUX) +- printf("================ NRF Configuration ================\n"); +- #endif // defined(RF24_LINUX) +- + print_status(get_status()); + + print_address_register(PSTR("RX_ADDR_P0-1"), RX_ADDR_P0, 2); +@@ -748,19 +327,6 @@ void RF24::printDetails(void) + + void RF24::printPrettyDetails(void) + { +- +- #if defined(RF24_LINUX) +- printf("================ SPI Configuration ================\n"); +- uint8_t bus_ce = static_cast(csn_pin % 10); +- uint8_t bus_numb = static_cast((csn_pin - bus_ce) / 10); +- printf("CSN Pin\t\t\t= /dev/spidev%d.%d\n", bus_numb, bus_ce); +- printf("CE Pin\t\t\t= Custom GPIO%d\n", ce_pin); +- #endif +- printf_P(PSTR("SPI Frequency\t\t= %d Mhz\n"), static_cast(spi_speed / 1000000)); //Print the SPI speed on non-Linux devices +- #if defined(RF24_LINUX) +- printf("================ NRF Configuration ================\n"); +- #endif // defined(RF24_LINUX) +- + uint8_t channel = getChannel(); + uint16_t frequency = static_cast(channel + 2400); + printf_P(PSTR("Channel\t\t\t= %u (~ %u MHz)\r\n"), channel, frequency); +@@ -846,11 +412,6 @@ void RF24::printPrettyDetails(void) + uint16_t RF24::sprintfPrettyDetails(char* debugging_information) + { + const char* format_string = PSTR( +- "================ SPI Configuration ================\n" +- "CSN Pin\t\t\t= %d\n" +- "CE Pin\t\t\t= %d\n" +- "SPI Frequency\t\t= %d Mhz\n" +- "================ NRF Configuration ================\n" + "Channel\t\t\t= %u (~ %u MHz)\n" + "RF Data Rate\t\t" PRIPSTR "\n" + "RF Power Amplifier\t" PRIPSTR "\n" +@@ -870,8 +431,7 @@ uint16_t RF24::sprintfPrettyDetails(char* debugging_information) + const char* format_str3 = PSTR("\nPipe %d (" PRIPSTR ") bound\t= 0x"); + + uint16_t offset = sprintf_P( +- debugging_information, format_string, csn_pin, ce_pin, +- static_cast(spi_speed / 1000000), getChannel(), ++ debugging_information, format_string, getChannel(), + static_cast(getChannel() + 2400), + (char*)(pgm_read_ptr(&rf24_datarate_e_str_P[getDataRate()])), + (char*)(pgm_read_ptr(&rf24_pa_dbm_e_str_P[getPALevel()])), +@@ -940,87 +500,26 @@ void RF24::encodeRadioDetails(uint8_t* encoded_details) + *encoded_details++ = read_register(i); + } + } +- *encoded_details++ = ce_pin >> 4; +- *encoded_details++ = ce_pin & 0xFF; +- *encoded_details++ = csn_pin >> 4; +- *encoded_details++ = csn_pin & 0xFF; +- *encoded_details = static_cast((spi_speed / 1000000) | _BV(_is_p_variant * 4)); + } + #endif // !defined(MINIMAL) + + /****************************************************************************/ +-#if defined(RF24_SPI_PTR) || defined(DOXYGEN_FORCED) +-// does not apply to RF24_LINUX + +-bool RF24::begin(_SPI* spiBus) ++bool RF24::begin(void) + { +- _spi = spiBus; + return _init_pins() && _init_radio(); + } + + /****************************************************************************/ + +-bool RF24::begin(_SPI* spiBus, rf24_gpio_pin_t _cepin, rf24_gpio_pin_t _cspin) ++bool RF24::begin(RF24_hal* _hal) + { +- ce_pin = _cepin; +- csn_pin = _cspin; +- return begin(spiBus); +-} +- +-#endif // defined (RF24_SPI_PTR) || defined (DOXYGEN_FORCED) +- +-/****************************************************************************/ +- +-bool RF24::begin(rf24_gpio_pin_t _cepin, rf24_gpio_pin_t _cspin) +-{ +- ce_pin = _cepin; +- csn_pin = _cspin; ++ hal = _hal; + return begin(); + } + + /****************************************************************************/ + +-bool RF24::begin(void) +-{ +-#if defined(RF24_LINUX) +- #if defined(RF24_RPi) +- switch (csn_pin) { // Ensure valid hardware CS pin +- case 0: break; +- case 1: break; +- // Allow BCM2835 enums for RPi +- case 8: csn_pin = 0; break; +- case 7: csn_pin = 1; break; +- case 18: csn_pin = 10; break; // to make it work on SPI1 +- case 17: csn_pin = 11; break; +- case 16: csn_pin = 12; break; +- default: csn_pin = 0; break; +- } +- #endif // RF24_RPi +- +- _SPI.begin(csn_pin, spi_speed); +- +-#elif defined(XMEGA_D3) +- _spi->begin(csn_pin); +- +-#elif defined(RF24_RP2) +- _spi = new SPI(); +- _spi->begin(PICO_DEFAULT_SPI ? spi1 : spi0); +- +-#else // using an Arduino platform || defined (LITTLEWIRE) +- +- #if defined(RF24_SPI_PTR) +- _spi->begin(); +- #else // !defined(RF24_SPI_PTR) +- _SPI.begin(); +- #endif // !defined(RF24_SPI_PTR) +- +-#endif // !defined(XMEGA_D3) && !defined(RF24_LINUX) +- +- return _init_pins() && _init_radio(); +-} +- +-/****************************************************************************/ +- + bool RF24::_init_pins() + { + if (!isValid()) { +@@ -1028,46 +527,7 @@ bool RF24::_init_pins() + return false; + } + +-#if defined(RF24_LINUX) +- +- #if defined(MRAA) +- GPIO(); +- gpio.begin(ce_pin, csn_pin); +- #endif +- +- pinMode(ce_pin, OUTPUT); +- ce(LOW); +- delay(100); +- +-#elif defined(LITTLEWIRE) +- pinMode(csn_pin, OUTPUT); +- csn(HIGH); +- +-#elif defined(XMEGA_D3) +- if (ce_pin != csn_pin) { +- pinMode(ce_pin, OUTPUT); +- }; +- ce(LOW); +- csn(HIGH); +- delay(200); +- +-#else // using an Arduino platform +- +- // Initialize pins +- if (ce_pin != csn_pin) { +- pinMode(ce_pin, OUTPUT); +- pinMode(csn_pin, OUTPUT); +- } +- +- ce(LOW); +- csn(HIGH); +- +- #if defined(__ARDUINO_X86__) +- delay(100); +- #endif +-#endif // !defined(XMEGA_D3) && !defined(LITTLEWIRE) && !defined(RF24_LINUX) +- +- return true; // assuming pins are connected properly ++ return hal->begin(); + } + + /****************************************************************************/ +@@ -1151,7 +611,7 @@ bool RF24::isChipConnected() + + bool RF24::isValid() + { +- return ce_pin != RF24_PIN_INVALID && csn_pin != RF24_PIN_INVALID; ++ return hal != nullptr; + } + + /****************************************************************************/ +@@ -1676,15 +1136,8 @@ void RF24::closeReadingPipe(uint8_t pipe) + + void RF24::toggle_features(void) + { +- beginTransaction(); +-#if defined(RF24_SPI_PTR) +- status = _spi->transfer(ACTIVATE); +- _spi->transfer(0x73); +-#else +- status = _SPI.transfer(ACTIVATE); +- _SPI.transfer(0x73); +-#endif +- endTransaction(); ++ uint8_t value = 0x73; ++ status = hal->write(ACTIVATE, &value, sizeof(value)); + } + + /****************************************************************************/ +diff --git a/RF24.h b/RF24.h +index dbd32ae..f774bba 100644 +--- a/RF24.h ++++ b/RF24.h +@@ -16,12 +16,7 @@ + #define __RF24_H__ + + #include "RF24_config.h" +- +-#if defined(RF24_LINUX) || defined(LITTLEWIRE) +- #include "utility/includes.h" +-#elif defined SOFTSPI +- #include +-#endif ++#include "RF24_hal.h" + + /** + * @defgroup PALevel Power Amplifier level +@@ -115,29 +110,8 @@ typedef enum + class RF24 + { + private: +-#ifdef SOFTSPI +- SoftSPI spi; +-#elif defined(SPI_UART) +- SPIUARTClass uspi; +-#endif +- +-#if defined(RF24_LINUX) || defined(XMEGA_D3) /* XMEGA can use SPI class */ +- SPI spi; +-#endif // defined (RF24_LINUX) || defined (XMEGA_D3) +-#if defined(RF24_SPI_PTR) +- _SPI* _spi; +-#endif // defined (RF24_SPI_PTR) +-#if defined(MRAA) +- GPIO gpio; +-#endif ++ RF24_hal *hal; + +- rf24_gpio_pin_t ce_pin; /* "Chip Enable" pin, activates the RX or TX role */ +- rf24_gpio_pin_t csn_pin; /* SPI Chip select */ +- uint32_t spi_speed; /* SPI Bus Speed */ +-#if defined(RF24_LINUX) || defined(XMEGA_D3) || defined(RF24_RP2) +- uint8_t spi_rxbuff[32 + 1]; //SPI receive buffer (payload max 32 bytes) +- uint8_t spi_txbuff[32 + 1]; //SPI transmit buffer (payload max 32 bytes + 1 byte for the command) +-#endif + uint8_t status; /* The status byte returned from every SPI transaction */ + uint8_t payload_size; /* Fixed size of payloads */ + uint8_t pipe0_reading_address[5]; /* Last address set on pipe 0 for reading. */ +@@ -146,16 +120,6 @@ private: + bool _is_p0_rx; /* For keeping track of pipe 0's usage in user-triggered RX mode. */ + + protected: +- /** +- * SPI transactions +- * +- * Common code for SPI transactions including CSN toggle +- * +- */ +- inline void beginTransaction(); +- +- inline void endTransaction(); +- + /** Whether ack payloads are enabled. */ + bool ack_payloads_enabled; + /** The address width to use (3, 4 or 5 bytes). */ +@@ -198,30 +162,15 @@ public: + * + * See [Related Pages](pages.html) for device specific information + * +- * @param _cepin The pin attached to Chip Enable on the RF module +- * @param _cspin The pin attached to Chip Select (often labeled CSN) on the radio module. +- * - For the Arduino Due board, the [Arduino Due extended SPI feature](https://www.arduino.cc/en/Reference/DueExtendedSPI) +- * is not supported. This means that the Due's pins 4, 10, or 52 are not mandated options (can use any digital output pin) for +- * the radio's CSN pin. +- * @param _spi_speed The SPI speed in Hz ie: 1000000 == 1Mhz +- * - Users can specify default SPI speed by modifying @ref RF24_SPI_SPEED in @ref RF24_config.h +- * - For Arduino, the default SPI speed will only be properly configured this way on devices supporting SPI TRANSACTIONS +- * - Older/Unsupported Arduino devices will use a default clock divider & settings configuration +- * - For Linux: The old way of setting SPI speeds using BCM2835 driver enums has been removed as of v1.3.7 ++ * @param _hal A pointer to the device specific hardware abstraction layer + */ +- RF24(rf24_gpio_pin_t _cepin, rf24_gpio_pin_t _cspin, uint32_t _spi_speed = RF24_SPI_SPEED); ++ RF24(RF24_hal *_hal); + + /** + * A constructor for initializing the radio's hardware dynamically +- * @warning You MUST use begin(rf24_gpio_pin_t, rf24_gpio_pin_t) or begin(_SPI*, rf24_gpio_pin_t, rf24_gpio_pin_t) to pass both the +- * digital output pin numbers connected to the radio's CE and CSN pins. +- * @param _spi_speed The SPI speed in Hz ie: 1000000 == 1Mhz +- * - Users can specify default SPI speed by modifying @ref RF24_SPI_SPEED in @ref RF24_config.h +- * - For Arduino, the default SPI speed will only be properly configured this way on devices supporting SPI TRANSACTIONS +- * - Older/Unsupported Arduino devices will use a default clock divider & settings configuration +- * - For Linux: The old way of setting SPI speeds using BCM2835 driver enums has been removed as of v1.3.7 ++ * @warning You MUST use begin(RF24_hal*) + */ +- RF24(uint32_t _spi_speed = RF24_SPI_SPEED); ++ RF24(void); + + #if defined(RF24_LINUX) + virtual ~RF24() {}; +@@ -243,58 +192,16 @@ public: + */ + bool begin(void); + +-#if defined(RF24_SPI_PTR) || defined(DOXYGEN_FORCED) + /** + * Same as begin(), but allows specifying a non-default SPI bus to use. + * +- * @note This function assumes the `SPI::begin()` method was called before to +- * calling this function. +- * +- * @warning This function is for the Arduino platforms only +- * +- * @param spiBus A pointer or reference to an instantiated SPI bus object. +- * The `_SPI` datatype is a "wrapped" definition that will represent +- * various SPI implementations based on the specified platform. +- * @see Review the [Arduino support page](md_docs_arduino.html). +- * +- * @return same result as begin() +- */ +- bool begin(_SPI* spiBus); +- +- /** +- * Same as begin(), but allows dynamically specifying a SPI bus, CE pin, +- * and CSN pin to use. +- * +- * @note This function assumes the `SPI::begin()` method was called before to +- * calling this function. +- * + * @warning This function is for the Arduino platforms only + * +- * @param spiBus A pointer or reference to an instantiated SPI bus object. +- * The `_SPI` datatype is a "wrapped" definition that will represent +- * various SPI implementations based on the specified platform. +- * @param _cepin The pin attached to Chip Enable on the RF module +- * @param _cspin The pin attached to Chip Select (often labeled CSN) on the radio module. +- * - For the Arduino Due board, the [Arduino Due extended SPI feature](https://www.arduino.cc/en/Reference/DueExtendedSPI) +- * is not supported. This means that the Due's pins 4, 10, or 52 are not mandated options (can use any digital output pin) for the radio's CSN pin. ++ * @param _hal A pointer to the device specific hardware abstraction layer + * +- * @see Review the [Arduino support page](md_docs_arduino.html). +- * +- * @return same result as begin() +- */ +- bool begin(_SPI* spiBus, rf24_gpio_pin_t _cepin, rf24_gpio_pin_t _cspin); +-#endif // defined (RF24_SPI_PTR) || defined (DOXYGEN_FORCED) +- +- /** +- * Same as begin(), but allows dynamically specifying a CE pin +- * and CSN pin to use. +- * @param _cepin The pin attached to Chip Enable on the RF module +- * @param _cspin The pin attached to Chip Select (often labeled CSN) on the radio module. +- * - For the Arduino Due board, the [Arduino Due extended SPI feature](https://www.arduino.cc/en/Reference/DueExtendedSPI) +- * is not supported. This means that the Due's pins 4, 10, or 52 are not mandated options (can use any digital output pin) for the radio's CSN pin. + * @return same result as begin() + */ +- bool begin(rf24_gpio_pin_t _cepin, rf24_gpio_pin_t _cspin); ++ bool begin(RF24_hal* _hal); + + /** + * Checks if the chip is connected to the SPI bus +@@ -667,12 +574,12 @@ public: + * This function uses much less ram than other `*print*Details()` methods. + * + * @code +- * uint8_t encoded_details[43] = {0}; ++ * uint8_t encoded_details[38] = {0}; + * radio.encodeRadioDetails(encoded_details); + * @endcode + * + * @param encoded_status The uint8_t array that RF24 radio details are +- * encoded into. This array must be at least 43 bytes in length; any less would surely ++ * encoded into. This array must be at least 38 bytes in length; any less would surely + * cause undefined behavior. + * + * Registers names and/or data corresponding to the index of the `encoded_details` array: +@@ -704,9 +611,6 @@ public: + * | 35 | FIFO_STATUS | + * | 36 | DYNPD | + * | 37 | FEATURE | +- * | 38-39 | ce_pin | +- * | 40-41 | csn_pin | +- * | 42 | SPI speed (in MHz) or'd with (isPlusVariant << 4) | + */ + void encodeRadioDetails(uint8_t* encoded_status); + +@@ -1896,18 +1800,6 @@ private: + */ + bool _init_pins(); + +- /** +- * Set chip select pin +- * +- * Running SPI bus at PI_CLOCK_DIV2 so we don't waste time transferring data +- * and best of all, we make use of the radio's FIFO buffers. A lower speed +- * means we're less likely to effectively leverage our FIFOs and pay a higher +- * AVR runtime cost as toll. +- * +- * @param mode HIGH to take this unit off the SPI bus, LOW to put it on +- */ +- void csn(bool mode); +- + /** + * Set chip enable + * +diff --git a/RF24_hal.cpp b/RF24_hal.cpp +new file mode 100644 +index 0000000..3cc78e4 +--- /dev/null ++++ b/RF24_hal.cpp +@@ -0,0 +1 @@ ++#include "RF24_hal.h" +diff --git a/RF24_hal.h b/RF24_hal.h +new file mode 100644 +index 0000000..baceab3 +--- /dev/null ++++ b/RF24_hal.h +@@ -0,0 +1,15 @@ ++#pragma once ++ ++#include "RF24_config.h" ++ ++class RF24_hal ++{ ++public: ++ virtual void ce(bool level) = 0; ++ virtual uint8_t read(uint8_t cmd, uint8_t* buf, uint8_t len) = 0; ++ virtual uint8_t read(uint8_t cmd, uint8_t* buf, uint8_t data_len, uint8_t blank_len) = 0; ++ virtual uint8_t write(uint8_t cmd, const uint8_t* buf, uint8_t len) = 0; ++ virtual uint8_t write(uint8_t cmd, const uint8_t* buf, uint8_t len, uint8_t blank_len) = 0; ++ virtual bool begin() = 0; ++ virtual void end() = 0; ++}; From a91455eace338bf7954930f1f3db0ec6967bd479 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 9 Dec 2023 03:05:41 +0100 Subject: [PATCH 212/267] 0.8.15 fix github workflow (files are case sensitive) --- src/hm/nrfHal.h | 2 +- src/hms/cmtHal.h | 2 +- src/platformio.ini | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/hm/nrfHal.h b/src/hm/nrfHal.h index 49ccbee4..d4db9f92 100644 --- a/src/hm/nrfHal.h +++ b/src/hm/nrfHal.h @@ -8,7 +8,7 @@ #pragma once -#include "../utils/SpiPatcher.h" +#include "../utils/spiPatcher.h" #include #include diff --git a/src/hms/cmtHal.h b/src/hms/cmtHal.h index 65a3ebbf..d5e31ea0 100644 --- a/src/hms/cmtHal.h +++ b/src/hms/cmtHal.h @@ -8,7 +8,7 @@ #pragma once -#include "../utils/SpiPatcher.h" +#include "../utils/spiPatcher.h" #include diff --git a/src/platformio.ini b/src/platformio.ini index a2cdfcf1..e7fb137e 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -91,7 +91,8 @@ monitor_filters = platform = espressif32 board = esp32dev lib_deps = - https://github.com/yubox-node-org/ESPAsyncWebServer + khoih-prog/AsyncWebServer_ESP32_W5500 + khoih-prog/AsyncUDP_ESP32_W5500 nrf24/RF24 @ ^1.4.8 paulstoffregen/Time @ ^1.6.1 https://github.com/bertmelis/espMqttClient#v1.5.0 From 379654fa51a3c8012051d35f834a35ae4a702cb9 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 9 Dec 2023 03:25:03 +0100 Subject: [PATCH 213/267] 0.8.15 fix fusion build --- src/hm/hmRadio.h | 12 +++++++----- src/hms/cmt2300a.h | 4 ++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 99960e98..4a43914e 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -10,7 +10,7 @@ #include "SPI.h" #include "radio.h" #include "../config/config.h" -#if defined(CONFIG_IDF_TARGET_ESP32S3) +#if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(ETHERNET) #include "nrfHal.h" #endif @@ -40,7 +40,7 @@ class HmRadio : public Radio { void setup(bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint8_t irq = IRQ_PIN, uint8_t ce = CE_PIN, uint8_t cs = CS_PIN, uint8_t sclk = SCLK_PIN, uint8_t mosi = MOSI_PIN, uint8_t miso = MISO_PIN) { DPRINTLN(DBG_VERBOSE, F("hmRadio.h:setup")); - #if defined(CONFIG_IDF_TARGET_ESP32S3) + #if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(ETHERNET) mNrfHal.init(mosi, miso, sclk, cs, ce); mNrf24 = new RF24(&mNrfHal); #else @@ -66,8 +66,10 @@ class HmRadio : public Radio { DTU_RADIO_ID = ((uint64_t)(((mDtuSn >> 24) & 0xFF) | ((mDtuSn >> 8) & 0xFF00) | ((mDtuSn << 8) & 0xFF0000) | ((mDtuSn << 24) & 0xFF000000)) << 8) | 0x01; #ifdef ESP32 - #if !defined(CONFIG_IDF_TARGET_ESP32S3) - #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 + #if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(ETHERNET) + // + #else + #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 mSpi = new SPIClass(HSPI); #else mSpi = new SPIClass(VSPI); @@ -353,7 +355,7 @@ class HmRadio : public Radio { SPIClass* mSpi; RF24 *mNrf24; - #if defined(CONFIG_IDF_TARGET_ESP32S3) + #if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(ETHERNET) nrfHal mNrfHal; #endif Inverter<> *mLastIv = NULL; diff --git a/src/hms/cmt2300a.h b/src/hms/cmt2300a.h index 54e7095e..bbbeefc7 100644 --- a/src/hms/cmt2300a.h +++ b/src/hms/cmt2300a.h @@ -6,7 +6,7 @@ #ifndef __CMT2300A_H__ #define __CMT2300A_H__ -#if defined(CONFIG_IDF_TARGET_ESP32S3) +#if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(ETHERNET) #include "cmtHal.h" #else #include "esp32_3wSpi.h" @@ -480,7 +480,7 @@ class Cmt2300a { return mSpi.readReg(CMT2300A_CUS_MODE_STA) & CMT2300A_MASK_CHIP_MODE_STA; } - #if defined(CONFIG_IDF_TARGET_ESP32S3) + #if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(ETHERNET) cmtHal mSpi; #else esp32_3wSpi mSpi; From 4afd63184ddae2a558c634fcca8e4f9223c39e88 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 9 Dec 2023 15:01:23 +0100 Subject: [PATCH 214/267] 0.8.16 * fix crash if NRF is not enabled --- src/CHANGES.md | 3 +++ src/defines.h | 2 +- src/hm/hmRadio.h | 19 ++++++++++--------- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index d77355df..7186a436 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.8.16 - 2023-12-09 +* fix crash if NRF is not enabled + ## 0.8.15 - 2023-12-09 * added support for opendtufusion fusion ethernet shield #886 * fixed range of HMS / HMT frequencies to 863 to 870 MHz #1238 diff --git a/src/defines.h b/src/defines.h index ade86df4..9d35b9be 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 15 +#define VERSION_PATCH 16 //------------------------------------- typedef struct { diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 4a43914e..e227efe1 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -35,16 +35,17 @@ class HmRadio : public Radio { HmRadio() { mDtuSn = DTU_SN; mIrqRcvd = false; + mNrf24.reset(new RF24(CE_PIN, CS_PIN, SPI_SPEED)); } ~HmRadio() {} void setup(bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint8_t irq = IRQ_PIN, uint8_t ce = CE_PIN, uint8_t cs = CS_PIN, uint8_t sclk = SCLK_PIN, uint8_t mosi = MOSI_PIN, uint8_t miso = MISO_PIN) { DPRINTLN(DBG_VERBOSE, F("hmRadio.h:setup")); + #if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(ETHERNET) + // replace object mNrfHal.init(mosi, miso, sclk, cs, ce); - mNrf24 = new RF24(&mNrfHal); - #else - mNrf24 = new RF24(CE_PIN, CS_PIN, SPI_SPEED); + mNrf24.reset(new RF24(&mNrfHal)); #endif pinMode(irq, INPUT_PULLUP); @@ -70,22 +71,22 @@ class HmRadio : public Radio { // #else #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 - mSpi = new SPIClass(HSPI); + mSpi.reset(new SPIClass(HSPI)); #else - mSpi = new SPIClass(VSPI); + mSpi.reset(new SPIClass(VSPI)); #endif mSpi->begin(sclk, miso, mosi, cs); #endif #else //the old ESP82xx cannot freely place their SPI pins - mSpi = new SPIClass(); + mSpi.reset(new SPIClass()); mSpi->begin(); #endif #if defined(CONFIG_IDF_TARGET_ESP32S3) mNrf24->begin(); #else - mNrf24->begin(mSpi, ce, cs); + mNrf24->begin(mSpi.get(), ce, cs); #endif mNrf24->setRetries(3, 15); // 3*250us + 250us and 15 loops -> 15ms @@ -353,8 +354,8 @@ class HmRadio : public Radio { bool mGotLastMsg = false; uint32_t mMillis; - SPIClass* mSpi; - RF24 *mNrf24; + std::unique_ptr mSpi; + std::unique_ptr mNrf24; #if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(ETHERNET) nrfHal mNrfHal; #endif From 240be8cd98dc75c103d300be22d46ffbb1d26626 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 9 Dec 2023 17:09:05 +0100 Subject: [PATCH 215/267] 0.8.16 * updated heuristic #1080 #1259 * fix compile opendtufusion fusion ethernet --- src/CHANGES.md | 2 + src/hm/Communication.h | 34 ++++++--------- src/hm/Heuristic.h | 94 ++++++++++++++++++++++++------------------ src/hm/HeuristicInv.h | 15 ++++--- src/hm/hmRadio.h | 4 ++ 5 files changed, 83 insertions(+), 66 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 7186a436..6cba5040 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -2,6 +2,8 @@ ## 0.8.16 - 2023-12-09 * fix crash if NRF is not enabled +* updated heuristic #1080 #1259 +* fix compile opendtufusion fusion ethernet ## 0.8.15 - 2023-12-09 * added support for opendtufusion fusion ethernet shield #886 diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 393330ba..9d92992f 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -88,8 +88,7 @@ class Communication : public CommQueue<> { } else q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); - if(!mHeu.getTestModeEnabled(q->iv)) - q->iv->radioStatistics.txCnt++; + q->iv->radioStatistics.txCnt++; mWaitTimeout = millis() + timeout; mWaitTimeout_min = millis() + timeout_min; mIsResend = false; @@ -115,8 +114,7 @@ class Communication : public CommQueue<> { } mFirstTry = false; mlastTO_min = timeout_min; - if(!mHeu.getTestModeEnabled(q->iv)) - q->iv->radioStatistics.retransmits++; // got nothing + q->iv->radioStatistics.retransmits++; // got nothing mState = States::START; break; } @@ -166,6 +164,7 @@ class Communication : public CommQueue<> { DBGPRINT(String(p->ch)); DBGPRINT(F(" ")); } else { + DBGPRINT(F(" ")); DBGPRINT(String(p->rssi)); DBGPRINT(F("dBm | ")); } @@ -180,8 +179,7 @@ class Communication : public CommQueue<> { } if(checkIvSerial(&p->packet[1], q->iv)) { - if(!mHeu.getTestModeEnabled(q->iv)) - q->iv->radioStatistics.frmCnt++; + q->iv->radioStatistics.frmCnt++; if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command parseFrame(p); @@ -193,8 +191,7 @@ class Communication : public CommQueue<> { parseMiFrame(p, q); } } else { - if(!mHeu.getTestModeEnabled(q->iv)) - q->iv->radioStatistics.rxFail++; // got no complete payload + q->iv->radioStatistics.rxFail++; // got no complete payload DPRINTLN(DBG_WARN, F("Inverter serial does not match")); mWaitTimeout = millis() + timeout; } @@ -370,8 +367,7 @@ class Communication : public CommQueue<> { DBGPRINT(F("CRC Error ")); if(q->attempts == 0) { DBGPRINTLN(F("-> Fail")); - /*if(!mHeu.getTestModeEnabled()) - q->iv->radioStatistics.rxFail++; // got fragments but not complete response + /*q->iv->radioStatistics.rxFail++; // got fragments but not complete response cmdDone();*/ closeRequest(q->iv, false, false); @@ -420,8 +416,7 @@ class Communication : public CommQueue<> { DBGPRINT(String(rec->pyldLen)); DBGPRINTLN(F(" bytes")); } - /*if(!mHeu.getTestModeEnabled()) - q->iv->radioStatistics.rxFail++;*/ + /*q->iv->radioStatistics.rxFail++;*/ closeRequest(q->iv, false, false); return; @@ -464,15 +459,12 @@ class Communication : public CommQueue<> { // ordering of lines is relevant for statistics if(succeeded) { mHeu.setGotAll(iv); - if(!mHeu.getTestModeEnabled(iv)) - iv->radioStatistics.rxSuccess++; + iv->radioStatistics.rxSuccess++; } else if(iv->mGotFragment) { mHeu.setGotFragment(iv); - if(!mHeu.getTestModeEnabled(iv)) - iv->radioStatistics.rxFail++; // got no complete payload + iv->radioStatistics.rxFail++; // got no complete payload } else { - if(!mHeu.getTestModeEnabled(iv)) - iv->radioStatistics.rxFailNoAnser++; // got nothing + iv->radioStatistics.rxFailNoAnser++; // got nothing mHeu.setGotNothing(iv); mWaitTimeout = millis() + WAIT_GAP_TIMEOUT; } @@ -682,12 +674,10 @@ class Communication : public CommQueue<> { if(q->iv->miMultiParts == 7) { mHeu.setGotAll(q->iv); - if(!mHeu.getTestModeEnabled(q->iv)) - q->iv->radioStatistics.rxSuccess++; + q->iv->radioStatistics.rxSuccess++; } else mHeu.setGotFragment(q->iv); - /*if(!mHeu.getTestModeEnabled()) - iv->radioStatistics.rxFail++; // got no complete payload*/ + /*iv->radioStatistics.rxFail++; // got no complete payload*/ //q->iv->radioStatistics.retransmits++; q->iv->radio->sendCmdPacket(q->iv, cmd, 0x00, true); diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index c75cf545..c0101e62 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -10,61 +10,79 @@ #include "hmInverter.h" #include "HeuristicInv.h" +#define RF_TEST_PERIOD_MAX_SEND_CNT 50 +#define RF_TEST_PERIOD_MAX_FAIL_CNT 5 + +#define RF_TX_TEST_CHAN_1ST_USE 0xff + class Heuristic { public: uint8_t getTxCh(Inverter<> *iv) { if((IV_HMS == iv->ivGen) || (IV_HMT == iv->ivGen)) return 0; // not used for these inverter types - uint8_t bestId = 0; - int8_t bestQuality = -6; - for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) { - if(iv->heuristics.txRfQuality[i] > bestQuality) { - bestQuality = iv->heuristics.txRfQuality[i]; - bestId = i; - } + HeuristicInv *ih = &iv->heuristics; + + // start with the next index: round robbin in case of same 'best' quality + uint8_t curId = (ih->txRfChId + 1) % RF_MAX_CHANNEL_ID; + uint8_t lastBestId = ih->txRfChId; + ih->txRfChId = curId; + curId = (curId + 1) % RF_MAX_CHANNEL_ID; + for(uint8_t i = 1; i < RF_MAX_CHANNEL_ID; i++) { + if(ih->txRfQuality[curId] > ih->txRfQuality[ih->txRfChId]) + ih->txRfChId = curId; + curId = (curId + 1) % RF_MAX_CHANNEL_ID; } - if(iv->heuristics.testEn) { - DPRINTLN(DBG_INFO, F("heuristic test mode")); - iv->heuristics.testIdx = (iv->heuristics.testIdx + 1) % RF_MAX_CHANNEL_ID; + if(ih->testPeriodSendCnt < 0xff) + ih->testPeriodSendCnt++; - if (iv->heuristics.testIdx == bestId) - iv->heuristics.testIdx = (iv->heuristics.testIdx + 1) % RF_MAX_CHANNEL_ID; + if((ih->txRfChId == lastBestId) && (ih->testPeriodSendCnt >= RF_TEST_PERIOD_MAX_SEND_CNT)) { + if(ih->testPeriodFailCnt > RF_TEST_PERIOD_MAX_FAIL_CNT) { + // try round robbin another chan and see if it works even better + ih->testChId = (ih->testChId + 1) % RF_MAX_CHANNEL_ID; + if(ih->testChId = ih->txRfChId) + ih->testChId = (ih->testChId + 1) % RF_MAX_CHANNEL_ID; - // test channel get's quality of best channel (maybe temporarily, see in 'setGotNothing') - iv->heuristics.storedIdx = iv->heuristics.txRfQuality[iv->heuristics.testIdx]; - iv->heuristics.txRfQuality[iv->heuristics.testIdx] = bestQuality; + // give it a fair chance but remember old status in case of immediate fail + ih->txRfChId = ih->testChId; + ih->testChId = RF_TX_TEST_CHAN_1ST_USE; // mark the chan as a test and as 1st use during new test period + DPRINTLN(DBG_INFO, "Test CH " + String(id2Ch(ih->txRfChId))); + } - iv->heuristics.txRfChId = iv->heuristics.testIdx; - } else - iv->heuristics.txRfChId = bestId; + // start new test period + ih->testPeriodSendCnt = 0; + ih->testPeriodFailCnt = 0; + } else if(ih->txRfChId != lastBestId) { + // start new test period + ih->testPeriodSendCnt = 0; + ih->testPeriodFailCnt = 0; + } - return id2Ch(iv->heuristics.txRfChId); + return id2Ch(ih->txRfChId); } void setGotAll(Inverter<> *iv) { updateQuality(iv, 2); // GOOD - iv->heuristics.testEn = false; } void setGotFragment(Inverter<> *iv) { updateQuality(iv, 1); // OK - iv->heuristics.testEn = false; } void setGotNothing(Inverter<> *iv) { - if(RF_NA != iv->heuristics.storedIdx) { - // if communication fails on first try with temporarily good level, revert it back to its original level - iv->heuristics.txRfQuality[iv->heuristics.txRfChId] = iv->heuristics.storedIdx; - iv->heuristics.storedIdx = RF_NA; + HeuristicInv *ih = &iv->heuristics; + + if(RF_TX_TEST_CHAN_1ST_USE == ih->testChId) { + // immediate fail + ih->testChId = ih->txRfChId; // reset to best + return; } - if(!iv->heuristics.testEn) { - updateQuality(iv, -2); // BAD - iv->heuristics.testEn = true; - } else - iv->heuristics.testEn = false; + if(ih->testPeriodFailCnt < 0xff) + ih->testPeriodFailCnt++; + + updateQuality(iv, -2); // BAD } void printStatus(Inverter<> *iv) { @@ -86,17 +104,15 @@ class Heuristic { DBGPRINTLN(String(iv->config->powerLevel)); } - bool getTestModeEnabled(Inverter<> *iv) { - return iv->heuristics.testEn; - } - private: void updateQuality(Inverter<> *iv, uint8_t quality) { - iv->heuristics.txRfQuality[iv->heuristics.txRfChId] += quality; - if(iv->heuristics.txRfQuality[iv->heuristics.txRfChId] > RF_MAX_QUALITY) - iv->heuristics.txRfQuality[iv->heuristics.txRfChId] = RF_MAX_QUALITY; - else if(iv->heuristics.txRfQuality[iv->heuristics.txRfChId] < RF_MIN_QUALTIY) - iv->heuristics.txRfQuality[iv->heuristics.txRfChId] = RF_MIN_QUALTIY; + HeuristicInv *ih = &iv->heuristics; + + ih->txRfQuality[ih->txRfChId] += quality; + if(ih->txRfQuality[ih->txRfChId] > RF_MAX_QUALITY) + ih->txRfQuality[ih->txRfChId] = RF_MAX_QUALITY; + else if(ih->txRfQuality[ih->txRfChId] < RF_MIN_QUALTIY) + ih->txRfQuality[ih->txRfChId] = RF_MIN_QUALTIY; } inline uint8_t id2Ch(uint8_t id) { diff --git a/src/hm/HeuristicInv.h b/src/hm/HeuristicInv.h index 1ca9c448..d3c2cdf0 100644 --- a/src/hm/HeuristicInv.h +++ b/src/hm/HeuristicInv.h @@ -13,12 +13,17 @@ class HeuristicInv { public: - int8_t txRfQuality[5]; // heuristics tx quality (check 'Heuristics.h') - uint8_t txRfChId; // RF TX channel id + HeuristicInv() { + memset(txRfQuality, -6, RF_MAX_CHANNEL_ID); + } - bool testEn = false; - uint8_t testIdx = 0; - int8_t storedIdx = RF_NA; + public: + int8_t txRfQuality[RF_MAX_CHANNEL_ID]; // heuristics tx quality (check 'Heuristics.h') + uint8_t txRfChId = 0; // RF TX channel id + + uint8_t testPeriodSendCnt = 0; + uint8_t testPeriodFailCnt = 0; + uint8_t testChId = 0; }; #endif /*__HEURISTIC_INV_H__*/ diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index e227efe1..618f8e9a 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -35,7 +35,11 @@ class HmRadio : public Radio { HmRadio() { mDtuSn = DTU_SN; mIrqRcvd = false; + #if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(ETHERNET) + mNrf24.reset(new RF24()); + #else mNrf24.reset(new RF24(CE_PIN, CS_PIN, SPI_SPEED)); + #endif } ~HmRadio() {} From c71377011bb2a56c2589b00b2987bef6a98a0854 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 10 Dec 2023 11:14:36 +0100 Subject: [PATCH 216/267] 0.8.17 * possible fix of NRF with opendtufusion (without ETH) * small fix in heuristics (if conditions made assignment not comparisson) --- src/CHANGES.md | 4 ++++ src/defines.h | 2 +- src/hm/Heuristic.h | 2 +- src/hm/hmRadio.h | 12 +++--------- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 6cba5040..e7fbefcc 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,9 @@ # Development Changes +## 0.8.17 - 2023-12-10 +* possible fix of NRF with opendtufusion (without ETH) +* small fix in heuristics (if conditions made assignment not comparisson) + ## 0.8.16 - 2023-12-09 * fix crash if NRF is not enabled * updated heuristic #1080 #1259 diff --git a/src/defines.h b/src/defines.h index 9d35b9be..351810fa 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 16 +#define VERSION_PATCH 17 //------------------------------------- typedef struct { diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index c0101e62..6b28f216 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -41,7 +41,7 @@ class Heuristic { if(ih->testPeriodFailCnt > RF_TEST_PERIOD_MAX_FAIL_CNT) { // try round robbin another chan and see if it works even better ih->testChId = (ih->testChId + 1) % RF_MAX_CHANNEL_ID; - if(ih->testChId = ih->txRfChId) + if(ih->testChId == ih->txRfChId) ih->testChId = (ih->testChId + 1) % RF_MAX_CHANNEL_ID; // give it a fair chance but remember old status in case of immediate fail diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 618f8e9a..4c0bff73 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -46,11 +46,6 @@ class HmRadio : public Radio { void setup(bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint8_t irq = IRQ_PIN, uint8_t ce = CE_PIN, uint8_t cs = CS_PIN, uint8_t sclk = SCLK_PIN, uint8_t mosi = MOSI_PIN, uint8_t miso = MISO_PIN) { DPRINTLN(DBG_VERBOSE, F("hmRadio.h:setup")); - #if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(ETHERNET) - // replace object - mNrfHal.init(mosi, miso, sclk, cs, ce); - mNrf24.reset(new RF24(&mNrfHal)); - #endif pinMode(irq, INPUT_PULLUP); mSerialDebug = serialDebug; @@ -72,7 +67,8 @@ class HmRadio : public Radio { #ifdef ESP32 #if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(ETHERNET) - // + mNrfHal.init(mosi, miso, sclk, cs, ce); + mNrf24.reset(new RF24(&mNrfHal)); #else #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 mSpi.reset(new SPIClass(HSPI)); @@ -87,7 +83,7 @@ class HmRadio : public Radio { mSpi->begin(); #endif - #if defined(CONFIG_IDF_TARGET_ESP32S3) + #if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(ETHERNET) mNrf24->begin(); #else mNrf24->begin(mSpi.get(), ce, cs); @@ -127,8 +123,6 @@ class HmRadio : public Radio { mNrf24->flush_tx(); // empty TX FIFO // start listening - //mNrf24->setChannel(23); - //mRxChIdx = 0; mNrf24->setChannel(mRfChLst[mRxChIdx]); mNrf24->startListening(); From b2a0a24c2d337590717e668b432863df34aff68f Mon Sep 17 00:00:00 2001 From: Frank Date: Sun, 10 Dec 2023 16:54:15 +0100 Subject: [PATCH 217/267] Enhancement: mDNS Support in WiFi AP-Mode --- src/wifi/ahoywifi.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/wifi/ahoywifi.cpp b/src/wifi/ahoywifi.cpp index 8632de49..65410104 100644 --- a/src/wifi/ahoywifi.cpp +++ b/src/wifi/ahoywifi.cpp @@ -9,6 +9,7 @@ #define F(sl) (sl) #endif #include "ahoywifi.h" +#include // NTP CONFIG #define NTP_PACKET_SIZE 48 @@ -83,6 +84,7 @@ void ahoywifi::tickWifiLoop() { if (mGotDisconnect) { mStaConn = RESET; } + MDNS.update(); return; case IN_AP_MODE: if (WiFi.softAPgetStationNum() == 0) { @@ -180,6 +182,15 @@ void ahoywifi::tickWifiLoop() { mAppWifiCb(true); mGotDisconnect = false; mStaConn = IN_STA_MODE; + + if (!MDNS.begin(mConfig->sys.deviceName)) { + DPRINTLN(DBG_ERROR, F("Error setting up MDNS responder!")); + } else { + DBGPRINT(F("[WiFi] mDNS established: ")); + DBGPRINT(mConfig->sys.deviceName); + DBGPRINTLN(F(".local")); + } + break; case RESET: mGotDisconnect = false; @@ -245,7 +256,6 @@ void ahoywifi::setupStation(void) { WiFi.hostname(mConfig->sys.deviceName); WiFi.mode(WIFI_AP_STA); - DBGPRINT(F("connect to network '")); DBGPRINT(mConfig->sys.stationSsid); DBGPRINTLN(F("' ...")); From df2e8407510871a13459c84a7e5eb3f0aa4fc939 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 10 Dec 2023 22:40:46 +0100 Subject: [PATCH 218/267] 0.8.18 * copied even more from the original heuristic code #1259 --- src/CHANGES.md | 3 ++ src/defines.h | 2 +- src/hm/Communication.h | 82 ++++++++++++++++++++++------------------- src/hm/Heuristic.h | 84 +++++++++++++++++++++++++++++------------- src/hm/HeuristicInv.h | 11 ++++-- src/hm/hmInverter.h | 1 + 6 files changed, 116 insertions(+), 67 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index e7fbefcc..a36e0769 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.8.18 - 2023-12-10 +* copied even more from the original heuristic code #1259 + ## 0.8.17 - 2023-12-10 * possible fix of NRF with opendtufusion (without ETH) * small fix in heuristics (if conditions made assignment not comparisson) diff --git a/src/defines.h b/src/defines.h index 351810fa..ffd3c6ae 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 17 +#define VERSION_PATCH 18 //------------------------------------- typedef struct { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 9d92992f..bf95d44c 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -65,6 +65,7 @@ class Communication : public CommQueue<> { mHeu.getTxCh(q->iv); q->iv->mGotFragment = false; q->iv->mGotLastMsg = false; + q->iv->curFrmCnt = 0; mIsResend = false; if(NULL == q->iv->radio) cmdDone(true); // can't communicate while radio is not defined! @@ -140,7 +141,7 @@ class Communication : public CommQueue<> { mWaitTimeout = millis() + 1000; } } - closeRequest(q->iv, false, false); + closeRequest(q, false, false); break; } @@ -182,17 +183,18 @@ class Communication : public CommQueue<> { q->iv->radioStatistics.frmCnt++; if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command - parseFrame(p); + if(parseFrame(p)) + q->iv->curFrmCnt++; nextState = States::CHECK_PACKAGE; } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command parseDevCtrl(p, q); - closeRequest(q->iv, true); + closeRequest(q, true, true); } else if(IV_MI == q->iv->ivGen) { - parseMiFrame(p, q); + if(parseMiFrame(p, q)) + q->iv->curFrmCnt++; } } else { q->iv->radioStatistics.rxFail++; // got no complete payload - DPRINTLN(DBG_WARN, F("Inverter serial does not match")); mWaitTimeout = millis() + timeout; } @@ -200,7 +202,7 @@ class Communication : public CommQueue<> { yield(); } if((0 == q->attempts) && (!q->iv->mGotFragment)) - closeRequest(q->iv, false); + closeRequest(q, false, true); else { if(q->iv->ivGen != IV_MI) mState = nextState; @@ -212,9 +214,8 @@ class Communication : public CommQueue<> { || ((q->cmd == MI_REQ_CH2) && (q->iv->type == INV_TYPE_2CH)) || ((q->cmd == MI_REQ_CH1) && (q->iv->type == INV_TYPE_1CH))) { miComplete(q->iv); - //closeRequest(q->iv, q->iv->miMultiParts > 5); } - closeRequest(q->iv, true); + closeRequest(q, true, true); } } @@ -267,7 +268,7 @@ class Communication : public CommQueue<> { if(NULL != mCbPayload) (mCbPayload)(q->cmd, q->iv); - closeRequest(q->iv); + closeRequest(q, true, true); break; } }); @@ -278,8 +279,13 @@ class Communication : public CommQueue<> { uint8_t tmp[4]; CP_U32_BigEndian(tmp, iv->radioId.u64 >> 8); for(uint8_t i = 0; i < 4; i++) { - if(tmp[i] != buf[i]) + if(tmp[i] != buf[i]) { + DPRINT(DBG_WARN, F("Inverter serial does not match, got: 0x")); + DHEX(buf[0]);DHEX(buf[1]);DHEX(buf[2]);DHEX(buf[3]); + DBGPRINT(F(", expected: 0x")); + DHEX(tmp[0]);DHEX(tmp[1]);DHEX(tmp[2]);DHEX(tmp[3]); return false; + } } return true; } @@ -288,20 +294,20 @@ class Communication : public CommQueue<> { return (ah::crc8(buf, len - 1) == buf[len-1]); } - inline void parseFrame(packet_t *p) { + inline bool parseFrame(packet_t *p) { uint8_t *frameId = &p->packet[9]; if(0x00 == *frameId) { DPRINTLN(DBG_WARN, F("invalid frameId 0x00")); - return; // skip current packet + return false; // skip current packet } if((*frameId & 0x7f) > MAX_PAYLOAD_ENTRIES) { DPRINTLN(DBG_WARN, F("local buffer to small for payload fragments")); - return; // local storage is to small for id + return false; // local storage is to small for id } if(!checkFrameCrc(p->packet, p->len)) { DPRINTLN(DBG_WARN, F("frame CRC is wrong")); - return; // CRC8 is wrong, frame invalid + return false; // CRC8 is wrong, frame invalid } if((*frameId & ALL_FRAMES) == ALL_FRAMES) @@ -311,9 +317,11 @@ class Communication : public CommQueue<> { memcpy(f->buf, &p->packet[10], p->len-11); f->len = p->len - 11; f->rssi = p->rssi; + + return true; } - inline void parseMiFrame(packet_t *p, const queue_s *q) { + inline bool parseMiFrame(packet_t *p, const queue_s *q) { if ((p->packet[0] == MI_REQ_CH1 + ALL_FRAMES) || (p->packet[0] == MI_REQ_CH2 + ALL_FRAMES) || ((p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES)) @@ -330,6 +338,8 @@ class Communication : public CommQueue<> { miStsConsolidate(q, ((p->packet[0] == 0x88) ? 1 : 2), rec, p->packet[10], p->packet[12], p->packet[9], p->packet[11]); //mHeu.setGotFragment(q->iv); only do this when we are through the cycle? } + + return true; } inline void parseDevCtrl(packet_t *p, const queue_s *q) { @@ -369,7 +379,7 @@ class Communication : public CommQueue<> { DBGPRINTLN(F("-> Fail")); /*q->iv->radioStatistics.rxFail++; // got fragments but not complete response cmdDone();*/ - closeRequest(q->iv, false, false); + closeRequest(q, false, false); } else DBGPRINTLN(F("-> complete retransmit")); @@ -417,7 +427,7 @@ class Communication : public CommQueue<> { DBGPRINTLN(F(" bytes")); } /*q->iv->radioStatistics.rxFail++;*/ - closeRequest(q->iv, false, false); + closeRequest(q, false, false); return; } @@ -450,31 +460,29 @@ class Communication : public CommQueue<> { mState = States::WAIT; } else { add(q, true); - closeRequest(q->iv, false); + closeRequest(q, false, true); } } private: - void closeRequest(Inverter<> *iv, bool succeeded = true, bool delCmd = true) { - // ordering of lines is relevant for statistics - if(succeeded) { - mHeu.setGotAll(iv); - iv->radioStatistics.rxSuccess++; - } else if(iv->mGotFragment) { - mHeu.setGotFragment(iv); - iv->radioStatistics.rxFail++; // got no complete payload - } else { - iv->radioStatistics.rxFailNoAnser++; // got nothing - mHeu.setGotNothing(iv); + void closeRequest(const queue_s *q, bool crcPass, bool delCmd) { + mHeu.evalTxChQuality(q->iv, crcPass, (4 - q->attempts), q->iv->curFrmCnt); + if(crcPass) + q->iv->radioStatistics.rxSuccess++; + else if(q->iv->mGotFragment) + q->iv->radioStatistics.rxFail++; // got no complete payload + else { + q->iv->radioStatistics.rxFailNoAnser++; // got nothing mWaitTimeout = millis() + WAIT_GAP_TIMEOUT; } + cmdDone(delCmd); - iv->mGotFragment = false; - iv->mGotLastMsg = false; - iv->miMultiParts = 0; - mIsResend = false; - mFirstTry = false; // for correct reset - mState = States::RESET; + q->iv->mGotFragment = false; + q->iv->mGotLastMsg = false; + q->iv->miMultiParts = 0; + mIsResend = false; + mFirstTry = false; // for correct reset + mState = States::RESET; } inline void miHwDecode(packet_t *p, const queue_s *q) { @@ -673,10 +681,10 @@ class Communication : public CommQueue<> { } if(q->iv->miMultiParts == 7) { - mHeu.setGotAll(q->iv); + //mHeu.setGotAll(q->iv); q->iv->radioStatistics.rxSuccess++; } else - mHeu.setGotFragment(q->iv); + //mHeu.setGotFragment(q->iv); /*iv->radioStatistics.rxFail++; // got no complete payload*/ //q->iv->radioStatistics.retransmits++; q->iv->radio->sendCmdPacket(q->iv, cmd, 0x00, true); diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index 6b28f216..a30436f7 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -15,6 +15,11 @@ #define RF_TX_TEST_CHAN_1ST_USE 0xff +#define RF_TX_CHAN_QUALITY_GOOD 2 +#define RF_TX_CHAN_QUALITY_OK 1 +#define RF_TX_CHAN_QUALITY_LOW -1 +#define RF_TX_CHAN_QUALITY_BAD -2 + class Heuristic { public: uint8_t getTxCh(Inverter<> *iv) { @@ -25,7 +30,7 @@ class Heuristic { // start with the next index: round robbin in case of same 'best' quality uint8_t curId = (ih->txRfChId + 1) % RF_MAX_CHANNEL_ID; - uint8_t lastBestId = ih->txRfChId; + ih->lastBestTxChId = ih->txRfChId; ih->txRfChId = curId; curId = (curId + 1) % RF_MAX_CHANNEL_ID; for(uint8_t i = 1; i < RF_MAX_CHANNEL_ID; i++) { @@ -37,14 +42,16 @@ class Heuristic { if(ih->testPeriodSendCnt < 0xff) ih->testPeriodSendCnt++; - if((ih->txRfChId == lastBestId) && (ih->testPeriodSendCnt >= RF_TEST_PERIOD_MAX_SEND_CNT)) { + if((ih->txRfChId == ih->lastBestTxChId) && (ih->testPeriodSendCnt >= RF_TEST_PERIOD_MAX_SEND_CNT)) { if(ih->testPeriodFailCnt > RF_TEST_PERIOD_MAX_FAIL_CNT) { - // try round robbin another chan and see if it works even better + // try round robbin another chan and see if it works even better ih->testChId = (ih->testChId + 1) % RF_MAX_CHANNEL_ID; if(ih->testChId == ih->txRfChId) ih->testChId = (ih->testChId + 1) % RF_MAX_CHANNEL_ID; // give it a fair chance but remember old status in case of immediate fail + ih->saveOldTestQuality = ih->txRfQuality[ih->testChId]; + ih->txRfQuality[ih->testChId] = ih->txRfQuality[ih->txRfChId]; ih->txRfChId = ih->testChId; ih->testChId = RF_TX_TEST_CHAN_1ST_USE; // mark the chan as a test and as 1st use during new test period DPRINTLN(DBG_INFO, "Test CH " + String(id2Ch(ih->txRfChId))); @@ -53,7 +60,7 @@ class Heuristic { // start new test period ih->testPeriodSendCnt = 0; ih->testPeriodFailCnt = 0; - } else if(ih->txRfChId != lastBestId) { + } else if(ih->txRfChId != ih->lastBestTxChId) { // start new test period ih->testPeriodSendCnt = 0; ih->testPeriodFailCnt = 0; @@ -62,27 +69,52 @@ class Heuristic { return id2Ch(ih->txRfChId); } - void setGotAll(Inverter<> *iv) { - updateQuality(iv, 2); // GOOD - } - - void setGotFragment(Inverter<> *iv) { - updateQuality(iv, 1); // OK - } - - void setGotNothing(Inverter<> *iv) { + void evalTxChQuality(Inverter<> *iv, bool crcPass, uint8_t retransmits, uint8_t rxFragments) { HeuristicInv *ih = &iv->heuristics; - if(RF_TX_TEST_CHAN_1ST_USE == ih->testChId) { - // immediate fail - ih->testChId = ih->txRfChId; // reset to best - return; - } - - if(ih->testPeriodFailCnt < 0xff) - ih->testPeriodFailCnt++; - - updateQuality(iv, -2); // BAD + if(ih->lastRxFragments == rxFragments) { + // nothing received: send probably lost + if(!retransmits || isNewTxCh(ih)) { + if(RF_TX_TEST_CHAN_1ST_USE == ih->testChId) { + // switch back to original quality + ih->txRfQuality[ih->txRfChId] = ih->saveOldTestQuality; + + updateQuality(ih, RF_TX_CHAN_QUALITY_BAD); + if(ih->testPeriodFailCnt < 0xff) + ih->testPeriodFailCnt++; + } + } + } else if(!ih->lastRxFragments && crcPass) { + if(!retransmits || isNewTxCh(ih)) { + // every fragment received successfull immediately + updateQuality(ih, RF_TX_CHAN_QUALITY_GOOD); + } else { + // every fragment received successfully + updateQuality(ih, RF_TX_CHAN_QUALITY_OK); + } + } else if(crcPass) { + if(isNewTxCh(ih)) { + // last Fragment successfully received on new send channel + updateQuality(ih, RF_TX_CHAN_QUALITY_OK); + } + } else if(!retransmits || isNewTxCh(ih)) { + // no complete receive for this send channel + if((rxFragments - ih->lastRxFragments) > 2) { + // graceful evaluation for big inverters that have to send 4 answer packets + updateQuality(ih, RF_TX_CHAN_QUALITY_OK); + } else if((rxFragments - ih->lastRxFragments) < 2) { + if(RF_TX_TEST_CHAN_1ST_USE == ih->txRfChId) { + // switch back to original quality + ih->txRfQuality[ih->txRfChId] = ih->saveOldTestQuality; + } + updateQuality(ih, RF_TX_CHAN_QUALITY_LOW); + if(ih->testPeriodFailCnt < 0xff) + ih->testPeriodFailCnt++; + } // else: _QUALITY_NEUTRAL, keep any test channel + } // else: dont overestimate burst distortion + + ih->testChId = ih->txRfChId; // reset to best + ih->lastRxFragments = rxFragments; } void printStatus(Inverter<> *iv) { @@ -105,9 +137,11 @@ class Heuristic { } private: - void updateQuality(Inverter<> *iv, uint8_t quality) { - HeuristicInv *ih = &iv->heuristics; + bool isNewTxCh(HeuristicInv *ih) { + return ih->txRfChId != ih->lastBestTxChId; + } + void updateQuality(HeuristicInv *ih, uint8_t quality) { ih->txRfQuality[ih->txRfChId] += quality; if(ih->txRfQuality[ih->txRfChId] > RF_MAX_QUALITY) ih->txRfQuality[ih->txRfChId] = RF_MAX_QUALITY; diff --git a/src/hm/HeuristicInv.h b/src/hm/HeuristicInv.h index d3c2cdf0..e7ad6edd 100644 --- a/src/hm/HeuristicInv.h +++ b/src/hm/HeuristicInv.h @@ -19,11 +19,14 @@ class HeuristicInv { public: int8_t txRfQuality[RF_MAX_CHANNEL_ID]; // heuristics tx quality (check 'Heuristics.h') - uint8_t txRfChId = 0; // RF TX channel id + uint8_t txRfChId = 0; // RF TX channel id + uint8_t lastBestTxChId = 0; - uint8_t testPeriodSendCnt = 0; - uint8_t testPeriodFailCnt = 0; - uint8_t testChId = 0; + uint8_t testPeriodSendCnt = 0; + uint8_t testPeriodFailCnt = 0; + uint8_t testChId = 0; + int8_t saveOldTestQuality = -6; + uint8_t lastRxFragments = 0; }; #endif /*__HEURISTIC_INV_H__*/ diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 72bbb7fd..3e3e1c08 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -129,6 +129,7 @@ class Inverter { uint8_t miMultiParts; // helper info for MI multiframe msgs uint8_t outstandingFrames; // helper info to count difference between expected and received frames bool mGotFragment; // shows if inverter has sent at least one fragment + uint8_t curFrmCnt; // count received frames in current loop bool mGotLastMsg; // shows if inverter has already finished transmission cycle Radio *radio; // pointer to associated radio class statistics_t radioStatistics; // information about transmitted, failed, ... packets From 2f51bd10706a20d8678172577c299aef70737e82 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 10 Dec 2023 22:49:55 +0100 Subject: [PATCH 219/267] added ESP32 mDNS support --- src/wifi/ahoywifi.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/wifi/ahoywifi.cpp b/src/wifi/ahoywifi.cpp index 65410104..d58e3847 100644 --- a/src/wifi/ahoywifi.cpp +++ b/src/wifi/ahoywifi.cpp @@ -9,7 +9,12 @@ #define F(sl) (sl) #endif #include "ahoywifi.h" + +#if defined(ESP32) +#include +#else #include +#endif // NTP CONFIG #define NTP_PACKET_SIZE 48 From e4ab7e9e5b53cb3ecb78f4cce354075ee6317fc1 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 10 Dec 2023 23:16:09 +0100 Subject: [PATCH 220/267] 0.8.18 fix mDNS --- src/CHANGES.md | 1 + src/eth/ahoyeth.cpp | 15 +++++++++++++++ src/wifi/ahoywifi.cpp | 2 ++ 3 files changed, 18 insertions(+) diff --git a/src/CHANGES.md b/src/CHANGES.md index a36e0769..472e3c8f 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -2,6 +2,7 @@ ## 0.8.18 - 2023-12-10 * copied even more from the original heuristic code #1259 +* added mDNS support #1262 ## 0.8.17 - 2023-12-10 * possible fix of NRF with opendtufusion (without ETH) diff --git a/src/eth/ahoyeth.cpp b/src/eth/ahoyeth.cpp index 48824429..be114cf1 100644 --- a/src/eth/ahoyeth.cpp +++ b/src/eth/ahoyeth.cpp @@ -10,6 +10,7 @@ #define F(sl) (sl) #endif #include "ahoyeth.h" +#include //----------------------------------------------------------------------------- ahoyeth::ahoyeth() @@ -170,6 +171,13 @@ void ahoyeth::onEthernetEvent(WiFiEvent_t event, arduino_event_info_t info) ESP32_W5500_eth_connected = true; mOnNetworkCB(true); } + if (!MDNS.begin(mConfig->sys.deviceName)) { + DPRINTLN(DBG_ERROR, F("Error setting up MDNS responder!")); + } else { + DBGPRINT(F("[WiFi] mDNS established: ")); + DBGPRINT(mConfig->sys.deviceName); + DBGPRINTLN(F(".local")); + } break; case ARDUINO_EVENT_ETH_DISCONNECTED: @@ -221,6 +229,13 @@ void ahoyeth::onEthernetEvent(WiFiEvent_t event, arduino_event_info_t info) ESP32_W5500_eth_connected = true; mOnNetworkCB(true); } + if (!MDNS.begin(mConfig->sys.deviceName)) { + DPRINTLN(DBG_ERROR, F("Error setting up MDNS responder!")); + } else { + DBGPRINT(F("[WiFi] mDNS established: ")); + DBGPRINT(mConfig->sys.deviceName); + DBGPRINTLN(F(".local")); + } break; case SYSTEM_EVENT_ETH_DISCONNECTED: diff --git a/src/wifi/ahoywifi.cpp b/src/wifi/ahoywifi.cpp index d58e3847..02f8d252 100644 --- a/src/wifi/ahoywifi.cpp +++ b/src/wifi/ahoywifi.cpp @@ -89,7 +89,9 @@ void ahoywifi::tickWifiLoop() { if (mGotDisconnect) { mStaConn = RESET; } + #if !defined(ESP32) MDNS.update(); + #endif return; case IN_AP_MODE: if (WiFi.softAPgetStationNum() == 0) { From e6b5edb784b0b6444b30434fbbb2e0bbb5445bf6 Mon Sep 17 00:00:00 2001 From: geronet1 Date: Mon, 11 Dec 2023 21:59:13 +0100 Subject: [PATCH 221/267] ETH config bugfix --- src/config/settings.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/config/settings.h b/src/config/settings.h index 556c7e76..4c5b20cb 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -377,18 +377,16 @@ class settings { mCfg.sys.darkMode = false; mCfg.sys.schedReboot = false; // restore temp settings - #if defined(ETHERNET) - memcpy(&mCfg.sys, &tmp, sizeof(cfgSys_t)); - #else /* defined(ETHERNET) */ if(keepWifi) memcpy(&mCfg.sys, &tmp, sizeof(cfgSys_t)); + #if !defined(ETHERNET) else { snprintf(mCfg.sys.stationSsid, SSID_LEN, FB_WIFI_SSID); snprintf(mCfg.sys.stationPwd, PWD_LEN, FB_WIFI_PWD); snprintf(mCfg.sys.apPwd, PWD_LEN, WIFI_AP_PWD); mCfg.sys.isHidden = false; } - #endif /* defined(ETHERNET) */ + #endif /* !defined(ETHERNET) */ snprintf(mCfg.sys.deviceName, DEVNAME_LEN, DEF_DEVICE_NAME); From 1c12f4c141fb47daf00714fc7af33629c2dd5ec6 Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 11 Dec 2023 22:38:48 +0100 Subject: [PATCH 222/267] 0.8.19 * added ms to serial log * added (debug) option to configure gap between inverter requests --- src/CHANGES.md | 4 ++++ src/app.cpp | 2 +- src/app.h | 9 --------- src/appInterface.h | 1 - src/config/settings.h | 19 +++++++++++++------ src/defines.h | 2 +- src/hm/Communication.h | 10 ++++++---- src/hm/Heuristic.h | 5 ++++- src/utils/helper.cpp | 9 +++++++++ src/utils/helper.h | 1 + src/web/RestApi.h | 1 + src/web/html/setup.html | 6 +++++- src/web/web.h | 8 +++++--- 13 files changed, 50 insertions(+), 27 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 472e3c8f..418acb84 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,9 @@ # Development Changes +## 0.8.19 - 2023-12-11 +* added ms to serial log +* added (debug) option to configure gap between inverter requests + ## 0.8.18 - 2023-12-10 * copied even more from the original heuristic code #1259 * added mDNS support #1262 diff --git a/src/app.cpp b/src/app.cpp index 1a4e248c..0d59ab10 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -54,7 +54,7 @@ void app::setup() { #endif #endif /* defined(ETHERNET) */ - mCommunication.setup(&mTimestamp, &mConfig->serial.debug, &mConfig->serial.privacyLog, &mConfig->serial.printWholeTrace); + mCommunication.setup(&mTimestamp, &mConfig->serial.debug, &mConfig->serial.privacyLog, &mConfig->serial.printWholeTrace, &mConfig->inst.gapMs); mCommunication.addPayloadListener(std::bind(&app::payloadEventListener, this, std::placeholders::_1, std::placeholders::_2)); mSys.setup(&mTimestamp, &mConfig->inst); for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { diff --git a/src/app.h b/src/app.h index cb0f8746..f2b4e548 100644 --- a/src/app.h +++ b/src/app.h @@ -211,15 +211,6 @@ class app : public IApp, public ah::Scheduler { return mConfig->cmt.pinIrq; } - String getTimeStr(uint32_t offset = 0) { - char str[10]; - if(0 == mTimestamp) - sprintf(str, "n/a"); - else - sprintf(str, "%02d:%02d:%02d ", hour(mTimestamp + offset), minute(mTimestamp + offset), second(mTimestamp + offset)); - return String(str); - } - uint32_t getTimezoneOffset() { return mApi.getTimezoneOffset(); } diff --git a/src/appInterface.h b/src/appInterface.h index ec0f5437..7814d0e1 100644 --- a/src/appInterface.h +++ b/src/appInterface.h @@ -44,7 +44,6 @@ class IApp { virtual uint32_t getSunrise() = 0; virtual uint32_t getSunset() = 0; virtual void setTimestamp(uint32_t newTime) = 0; - virtual String getTimeStr(uint32_t offset) = 0; virtual uint32_t getTimezoneOffset() = 0; virtual void getSchedulerInfo(uint8_t *max) = 0; virtual void getSchedulerNames() = 0; diff --git a/src/config/settings.h b/src/config/settings.h index 556c7e76..6a8f1dc3 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -30,7 +30,7 @@ * https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html#flash-layout * */ -#define CONFIG_VERSION 3 +#define CONFIG_VERSION 4 #define PROT_MASK_INDEX 0x0001 @@ -159,6 +159,7 @@ typedef struct { bool rstMaxValsMidNight; bool startWithoutTime; float yieldEffiency; + uint16_t gapMs; } cfgInst_t; typedef struct { @@ -443,6 +444,7 @@ class settings { mCfg.inst.startWithoutTime = false; mCfg.inst.rstMaxValsMidNight = false; mCfg.inst.yieldEffiency = 1.0f; + mCfg.inst.gapMs = 2000; for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { mCfg.inst.iv[i].powerLevel = 0xff; // impossible high value @@ -483,6 +485,9 @@ class settings { if(mCfg.configVersion < 3) { mCfg.serial.printWholeTrace = true; } + if(mCfg.configVersion < 4) { + mCfg.inst.gapMs = 2000; + } } } @@ -708,12 +713,13 @@ class settings { void jsonInst(JsonObject obj, bool set = false) { if(set) { obj[F("en")] = (bool)mCfg.inst.enabled; - obj[F("rstMidNight")] = (bool)mCfg.inst.rstYieldMidNight; - obj[F("rstNotAvail")] = (bool)mCfg.inst.rstValsNotAvail; - obj[F("rstComStop")] = (bool)mCfg.inst.rstValsCommStop; - obj[F("strtWthtTime")] = (bool)mCfg.inst.startWithoutTime; + obj[F("rstMidNight")] = (bool)mCfg.inst.rstYieldMidNight; + obj[F("rstNotAvail")] = (bool)mCfg.inst.rstValsNotAvail; + obj[F("rstComStop")] = (bool)mCfg.inst.rstValsCommStop; + obj[F("strtWthtTime")] = (bool)mCfg.inst.startWithoutTime; obj[F("rstMaxMidNight")] = (bool)mCfg.inst.rstMaxValsMidNight; - obj[F("yldEff")] = mCfg.inst.yieldEffiency; + obj[F("yldEff")] = mCfg.inst.yieldEffiency; + obj[F("gap")] = mCfg.inst.gapMs; } else { getVal(obj, F("en"), &mCfg.inst.enabled); @@ -723,6 +729,7 @@ class settings { getVal(obj, F("strtWthtTime"), &mCfg.inst.startWithoutTime); getVal(obj, F("rstMaxMidNight"), &mCfg.inst.rstMaxValsMidNight); getVal(obj, F("yldEff"), &mCfg.inst.yieldEffiency); + getVal(obj, F("gap"), &mCfg.inst.gapMs); if(mCfg.inst.yieldEffiency < 0.5) mCfg.inst.yieldEffiency = 1.0f; diff --git a/src/defines.h b/src/defines.h index ffd3c6ae..24bcc8a5 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 18 +#define VERSION_PATCH 19 //------------------------------------- typedef struct { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index bf95d44c..e8c17d1e 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -15,7 +15,6 @@ #define FRSTMSG_TIMEOUT 150 // how long to wait for first msg to be received #define DEFAULT_TIMEOUT 500 // timeout for regular requests #define SINGLEFR_TIMEOUT 65 // timeout for single frame requests -#define WAIT_GAP_TIMEOUT 200 // timeout after no complete payload #define MAX_BUFFER 250 typedef std::function *)> payloadListenerType; @@ -23,11 +22,12 @@ typedef std::function *)> alarmListenerType; class Communication : public CommQueue<> { public: - void setup(uint32_t *timestamp, bool *serialDebug, bool *privacyMode, bool *printWholeTrace) { + void setup(uint32_t *timestamp, bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint16_t *inverterGap) { mTimestamp = timestamp; mPrivacyMode = privacyMode; mSerialDebug = serialDebug; mPrintWholeTrace = printWholeTrace; + mInverterGap = inverterGap; } void addImportant(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) { @@ -134,7 +134,6 @@ class Communication : public CommQueue<> { DBGPRINT(String(millis() - mWaitTimeout + timeout)); DBGPRINTLN(F("ms")); } - if(!q->iv->mGotFragment) { if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, (q->iv->config->frequency*FREQ_STEP_KHZ + HOY_BASE_FREQ_KHZ)); @@ -284,6 +283,7 @@ class Communication : public CommQueue<> { DHEX(buf[0]);DHEX(buf[1]);DHEX(buf[2]);DHEX(buf[3]); DBGPRINT(F(", expected: 0x")); DHEX(tmp[0]);DHEX(tmp[1]);DHEX(tmp[2]);DHEX(tmp[3]); + DBGPRINTLN(""); return false; } } @@ -473,8 +473,8 @@ class Communication : public CommQueue<> { q->iv->radioStatistics.rxFail++; // got no complete payload else { q->iv->radioStatistics.rxFailNoAnser++; // got nothing - mWaitTimeout = millis() + WAIT_GAP_TIMEOUT; } + mWaitTimeout = millis() + *mInverterGap; cmdDone(delCmd); q->iv->mGotFragment = false; @@ -483,6 +483,7 @@ class Communication : public CommQueue<> { mIsResend = false; mFirstTry = false; // for correct reset mState = States::RESET; + DBGPRINTLN("-----"); } inline void miHwDecode(packet_t *p, const queue_s *q) { @@ -826,6 +827,7 @@ class Communication : public CommQueue<> { States mState = States::RESET; uint32_t *mTimestamp; bool *mPrivacyMode, *mSerialDebug, *mPrintWholeTrace; + uint16_t *mInverterGap; uint32_t mWaitTimeout = 0; uint32_t mWaitTimeout_min = 0; std::array mLocalBuf; diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index a30436f7..17efe080 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -133,7 +133,10 @@ class Heuristic { DBGPRINT(F(", n: ")); DBGPRINT(String(iv->radioStatistics.rxFailNoAnser)); DBGPRINT(F(" | p: ")); // better debugging for helpers... - DBGPRINTLN(String(iv->config->powerLevel)); + if((IV_HMS == iv->ivGen) || (IV_HMT == iv->ivGen)) + DBGPRINTLN(String(iv->config->powerLevel-10)); + else + DBGPRINTLN(String(iv->config->powerLevel)); } private: diff --git a/src/utils/helper.cpp b/src/utils/helper.cpp index 67758f5d..e606ad8b 100644 --- a/src/utils/helper.cpp +++ b/src/utils/helper.cpp @@ -70,6 +70,15 @@ namespace ah { return String(str); } + String getTimeStrMs(time_t t) { + char str[13]; + if(0 == t) + sprintf(str, "n/a"); + else + sprintf(str, "%02d:%02d:%02d.%03d", hour(t), minute(t), second(t), millis() % 1000); + return String(str); + } + uint64_t Serial2u64(const char *val) { char tmp[3]; uint64_t ret = 0ULL; diff --git a/src/utils/helper.h b/src/utils/helper.h index d7c6f34c..60721414 100644 --- a/src/utils/helper.h +++ b/src/utils/helper.h @@ -44,6 +44,7 @@ namespace ah { String getDateTimeStrShort(time_t t); String getDateTimeStrFile(time_t t); String getTimeStr(time_t t); + String getTimeStrMs(time_t t); uint64_t Serial2u64(const char *val); void dumpBuf(uint8_t buf[], uint8_t len, uint8_t firstRepl = 0, uint8_t lastRepl = 0); } diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 61478cc9..d431c474 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -389,6 +389,7 @@ class RestApi { obj[F("strtWthtTm")] = (bool)mConfig->inst.startWithoutTime; obj[F("rstMaxMid")] = (bool)mConfig->inst.rstMaxValsMidNight; obj[F("yldEff")] = mConfig->inst.yieldEffiency; + obj[F("gap")] = mConfig->inst.gapMs; } void getInverter(JsonObject obj, uint8_t id) { diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 87869fd6..fecebd81 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -148,6 +148,10 @@
Interval [s]
+
+
Inverter Gap [ms]
+
+
Reset values and YieldDay at midnight
@@ -571,7 +575,7 @@ } function ivGlob(obj) { - for(var i of [["invInterval", "interval"], ["yldEff", "yldEff"]]) + for(var i of [["invInterval", "interval"], ["yldEff", "yldEff"], ["invGap", "gap"]]) document.getElementsByName(i[0])[0].value = obj[i[1]]; for(var i of ["Mid", "ComStop", "NotAvail", "MaxMid"]) document.getElementsByName("invRst"+i)[0].checked = obj["rst" + i]; diff --git a/src/web/web.h b/src/web/web.h index cb5cf72a..75d06e19 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -208,10 +208,11 @@ class Web { msg.replace("\r\n", ""); if (mSerialAddTime) { - if ((9 + mSerialBufFill) < WEB_SERIAL_BUF_SIZE) { + if ((13 + mSerialBufFill) < WEB_SERIAL_BUF_SIZE) { if (mApp->getTimestamp() > 0) { - strncpy(&mSerialBuf[mSerialBufFill], mApp->getTimeStr(mApp->getTimezoneOffset()).c_str(), 9); - mSerialBufFill += 9; + strncpy(&mSerialBuf[mSerialBufFill], ah::getTimeStrMs(mApp->getTimestamp() + mApp->getTimezoneOffset()).c_str(), 12); + mSerialBuf[mSerialBufFill+12] = ' '; + mSerialBufFill += 13; } } else { mSerialBufFill = 0; @@ -495,6 +496,7 @@ class Web { mConfig->inst.startWithoutTime = (request->arg("strtWthtTm") == "on"); mConfig->inst.rstMaxValsMidNight = (request->arg("invRstMaxMid") == "on"); mConfig->inst.yieldEffiency = (request->arg("yldEff")).toFloat(); + mConfig->inst.gapMs = (request->arg("invGap")).toInt(); // pinout From 41e000f01ae39aa28347fb046dd1c9b671da861b Mon Sep 17 00:00:00 2001 From: you69man Date: Mon, 11 Dec 2023 23:48:03 +0100 Subject: [PATCH 223/267] Only call loop() functions of radio modules that are enabled and set up --- src/app.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/app.cpp b/src/app.cpp index 0d59ab10..cb2e6947 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -105,9 +105,11 @@ void app::setup() { void app::loop(void) { ah::Scheduler::loop(); - mNrfRadio.loop(); + if(mConfig->nrf.enabled) + mNrfRadio.loop(); #if defined(ESP32) - mCmtRadio.loop(); + if(mConfig->cmt.enabled) + mCmtRadio.loop(); #endif mCommunication.loop(); From 689a295d0ba189148df9909edd67b101c143d5dc Mon Sep 17 00:00:00 2001 From: lumapu Date: Tue, 12 Dec 2023 20:49:43 +0100 Subject: [PATCH 224/267] 0.8.20 * improved HM communication #1259 #1249 * fix `loadDefaults` for ethernet builds #1263 * don't loop through radios which aren't in use #1264 --- src/CHANGES.md | 5 +++++ src/config/settings.h | 7 ++----- src/defines.h | 2 +- src/hm/Communication.h | 17 ++++++++++++----- 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 418acb84..74401b87 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,10 @@ # Development Changes +## 0.8.20 - 2023-12-12 +* improved HM communication #1259 #1249 +* fix `loadDefaults` for ethernet builds #1263 +* don't loop through radios which aren't in use #1264 + ## 0.8.19 - 2023-12-11 * added ms to serial log * added (debug) option to configure gap between inverter requests diff --git a/src/config/settings.h b/src/config/settings.h index a2851bd0..92ad1195 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -67,16 +67,13 @@ typedef struct { bool darkMode; bool schedReboot; -#if defined(ETHERNET) - // ethernet - -#else /* defined(ETHERNET) */ +#if !defined(ETHERNET) // wifi char stationSsid[SSID_LEN]; char stationPwd[PWD_LEN]; char apPwd[PWD_LEN]; bool isHidden; -#endif /* defined(ETHERNET) */ +#endif /* !defined(ETHERNET) */ cfgIp_t ip; } cfgSys_t; diff --git a/src/defines.h b/src/defines.h index 24bcc8a5..79555749 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 19 +#define VERSION_PATCH 20 //------------------------------------- typedef struct { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index e8c17d1e..23934c0c 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -51,6 +51,11 @@ class Communication : public CommQueue<> { uint16_t timeout = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment && q->iv->mGotLastMsg) || mIsResend) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT; uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment || mIsResend)) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT; + /*if(mDebugState != mState) { + DPRINT(DBG_INFO, F("State: ")); + DBGHEXLN((uint8_t)(mState)); + mDebugState = mState; + }*/ switch(mState) { case States::RESET: if(millis() < mWaitTimeout) @@ -99,7 +104,7 @@ class Communication : public CommQueue<> { break; case States::WAIT: - if(millis() > mWaitTimeout_min) { + /*if(millis() > mWaitTimeout_min) { if(mIsResend) { // we already have been through... mWaitTimeout = mWaitTimeout_min; } else if(q->iv->mGotFragment) { // nothing received yet? @@ -120,7 +125,7 @@ class Communication : public CommQueue<> { break; } - } + }*/ if(millis() < mWaitTimeout) return; mState = States::CHECK_FRAMES; @@ -200,7 +205,7 @@ class Communication : public CommQueue<> { q->iv->radio->mBufCtrl.pop(); yield(); } - if((0 == q->attempts) && (!q->iv->mGotFragment)) + if(0 == q->attempts) closeRequest(q, false, true); else { if(q->iv->ivGen != IV_MI) @@ -459,7 +464,7 @@ class Communication : public CommQueue<> { mWaitTimeout = millis() + SINGLEFR_TIMEOUT; // timeout mState = States::WAIT; } else { - add(q, true); + //add(q, true); closeRequest(q, false, true); } } @@ -476,7 +481,7 @@ class Communication : public CommQueue<> { } mWaitTimeout = millis() + *mInverterGap; - cmdDone(delCmd); + cmdDone(q->delOnPop); q->iv->mGotFragment = false; q->iv->mGotLastMsg = false; q->iv->miMultiParts = 0; @@ -839,6 +844,8 @@ class Communication : public CommQueue<> { payloadListenerType mCbPayload = NULL; alarmListenerType mCbAlarm = NULL; Heuristic mHeu; + + //States mDebugState = States::START; }; #endif /*__COMMUNICATION_H__*/ From 8c0ff5a3bd9fc7f520ec6cbeaee5c69706627d7a Mon Sep 17 00:00:00 2001 From: lumapu Date: Tue, 12 Dec 2023 23:29:06 +0100 Subject: [PATCH 225/267] 0.8.21 * fix ethernet save inverter parameters #886 * fix ethernet OTA update #886 * improved radio statistics, fixed heuristic output for HMS and HMT inverters --- src/CHANGES.md | 5 +++++ src/defines.h | 2 +- src/hm/Communication.h | 23 +++++++++++++---------- src/hm/Heuristic.h | 11 +++++++---- src/hm/hmRadio.h | 10 ---------- src/platformio.ini | 2 +- src/web/RestApi.h | 10 +++++++++- src/web/web.h | 9 ++++++++- 8 files changed, 44 insertions(+), 28 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 74401b87..ff2eefc4 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,10 @@ # Development Changes +## 0.8.21 - 2023-12-12 +* fix ethernet save inverter parameters #886 +* fix ethernet OTA update #886 +* improved radio statistics, fixed heuristic output for HMS and HMT inverters + ## 0.8.20 - 2023-12-12 * improved HM communication #1259 #1249 * fix `loadDefaults` for ethernet builds #1263 diff --git a/src/defines.h b/src/defines.h index 79555749..7e715484 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 20 +#define VERSION_PATCH 21 //------------------------------------- typedef struct { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 23934c0c..5e004417 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -145,7 +145,7 @@ class Communication : public CommQueue<> { mWaitTimeout = millis() + 1000; } } - closeRequest(q, false, false); + closeRequest(q, false); break; } @@ -192,7 +192,7 @@ class Communication : public CommQueue<> { nextState = States::CHECK_PACKAGE; } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command parseDevCtrl(p, q); - closeRequest(q, true, true); + closeRequest(q, true); } else if(IV_MI == q->iv->ivGen) { if(parseMiFrame(p, q)) q->iv->curFrmCnt++; @@ -206,10 +206,13 @@ class Communication : public CommQueue<> { yield(); } if(0 == q->attempts) - closeRequest(q, false, true); + closeRequest(q, false); else { - if(q->iv->ivGen != IV_MI) + if(q->iv->ivGen != IV_MI) { mState = nextState; + if(States::RESET == mState) + closeRequest(q, false); + } else { if(q->iv->miMultiParts < 6) { nextState = States::WAIT; @@ -219,7 +222,7 @@ class Communication : public CommQueue<> { || ((q->cmd == MI_REQ_CH1) && (q->iv->type == INV_TYPE_1CH))) { miComplete(q->iv); } - closeRequest(q, true, true); + closeRequest(q, true); } } @@ -272,7 +275,7 @@ class Communication : public CommQueue<> { if(NULL != mCbPayload) (mCbPayload)(q->cmd, q->iv); - closeRequest(q, true, true); + closeRequest(q, true); break; } }); @@ -384,7 +387,7 @@ class Communication : public CommQueue<> { DBGPRINTLN(F("-> Fail")); /*q->iv->radioStatistics.rxFail++; // got fragments but not complete response cmdDone();*/ - closeRequest(q, false, false); + closeRequest(q, false); } else DBGPRINTLN(F("-> complete retransmit")); @@ -432,7 +435,7 @@ class Communication : public CommQueue<> { DBGPRINTLN(F(" bytes")); } /*q->iv->radioStatistics.rxFail++;*/ - closeRequest(q, false, false); + closeRequest(q, false); return; } @@ -465,12 +468,12 @@ class Communication : public CommQueue<> { mState = States::WAIT; } else { //add(q, true); - closeRequest(q, false, true); + closeRequest(q, false); } } private: - void closeRequest(const queue_s *q, bool crcPass, bool delCmd) { + void closeRequest(const queue_s *q, bool crcPass) { mHeu.evalTxChQuality(q->iv, crcPass, (4 - q->attempts), q->iv->curFrmCnt); if(crcPass) q->iv->radioStatistics.rxSuccess++; diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index 17efe080..4b3705dd 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -120,11 +120,14 @@ class Heuristic { void printStatus(Inverter<> *iv) { DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("Radio infos:")); - for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) { - DBGPRINT(F(" ")); - DBGPRINT(String(iv->heuristics.txRfQuality[i])); + if((IV_HMS != iv->ivGen) && (IV_HMT != iv->ivGen)) { + for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) { + DBGPRINT(F(" ")); + DBGPRINT(String(iv->heuristics.txRfQuality[i])); + } + DBGPRINT(F(" |")); } - DBGPRINT(F(" | t: ")); + DBGPRINT(F(" t: ")); DBGPRINT(String(iv->radioStatistics.txCnt)); DBGPRINT(F(", s: ")); DBGPRINT(String(iv->radioStatistics.rxSuccess)); diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 4c0bff73..14146830 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -52,16 +52,6 @@ class HmRadio : public Radio { mPrivacyMode = privacyMode; mPrintWholeTrace = printWholeTrace; - if(*mSerialDebug) { - DPRINT(DBG_VERBOSE, F("hmRadio.h : HmRadio():mNrf24(CE_PIN: ")); - DBGPRINT(String(CE_PIN)); - DBGPRINT(F(", CS_PIN: ")); - DBGPRINT(String(CS_PIN)); - DBGPRINT(F(", SPI_SPEED: ")); - DBGPRINT(String(SPI_SPEED)); - DBGPRINTLN(F(")")); - } - generateDtuSn(); DTU_RADIO_ID = ((uint64_t)(((mDtuSn >> 24) & 0xFF) | ((mDtuSn >> 8) & 0xFF00) | ((mDtuSn << 8) & 0xFF0000) | ((mDtuSn << 24) & 0xFF000000)) << 8) | 0x01; diff --git a/src/platformio.ini b/src/platformio.ini index e7fb137e..116eff2c 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -184,7 +184,7 @@ build_flags = ${env.build_flags} -DDEF_LED1=17 -DLED_ACTIVE_HIGH -DARDUINO_USB_MODE=1 - #-DARDUINO_USB_CDC_ON_BOOT=1 + -DARDUINO_USB_CDC_ON_BOOT=1 monitor_filters = esp32_exception_decoder, colorize diff --git a/src/web/RestApi.h b/src/web/RestApi.h index d431c474..1524fed4 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -50,9 +50,9 @@ class RestApi { mRadioCmt = (CmtRadio<>*)mApp->getRadioObj(false); #endif mConfig = config; - mSrv->on("/api", HTTP_GET, std::bind(&RestApi::onApi, this, std::placeholders::_1)); mSrv->on("/api", HTTP_POST, std::bind(&RestApi::onApiPost, this, std::placeholders::_1)).onBody( std::bind(&RestApi::onApiPostBody, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5)); + mSrv->on("/api", HTTP_GET, std::bind(&RestApi::onApi, this, std::placeholders::_1)); mSrv->on("/get_setup", HTTP_GET, std::bind(&RestApi::onDwnldSetup, this, std::placeholders::_1)); } @@ -72,6 +72,8 @@ class RestApi { private: void onApi(AsyncWebServerRequest *request) { + DPRINTLN(DBG_VERBOSE, String("onApi: ") + String((uint16_t)request->method())); // 1 == Get, 3 == POST + mHeapFree = ESP.getFreeHeap(); #ifndef ESP32 mHeapFreeBlk = ESP.getMaxFreeBlockSize(); @@ -120,6 +122,12 @@ class RestApi { void onApiPost(AsyncWebServerRequest *request) { DPRINTLN(DBG_VERBOSE, "onApiPost"); + #if defined(ETHERNET) + // workaround for AsyncWebServer_ESP32_W5500, because it can't distinguish + // between HTTP_GET and HTTP_POST if both are registered + if(request->method() == HTTP_GET) + onApi(request); + #endif } void onApiPostBody(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total) { diff --git a/src/web/web.h b/src/web/web.h index 75d06e19..7ac0f4ad 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -82,9 +82,9 @@ class Web { mWeb.on("/metrics", HTTP_ANY, std::bind(&Web::showMetrics, this, std::placeholders::_1)); #endif - mWeb.on("/update", HTTP_GET, std::bind(&Web::onUpdate, this, std::placeholders::_1)); mWeb.on("/update", HTTP_POST, std::bind(&Web::showUpdate, this, std::placeholders::_1), std::bind(&Web::showUpdate2, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6)); + mWeb.on("/update", HTTP_GET, std::bind(&Web::onUpdate, this, std::placeholders::_1)); mWeb.on("/upload", HTTP_POST, std::bind(&Web::onUpload, this, std::placeholders::_1), std::bind(&Web::onUpload2, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6)); mWeb.on("/serial", HTTP_GET, std::bind(&Web::onSerial, this, std::placeholders::_1)); @@ -273,6 +273,13 @@ class Web { } void showUpdate(AsyncWebServerRequest *request) { + #if defined(ETHERNET) + // workaround for AsyncWebServer_ESP32_W5500, because it can't distinguish + // between HTTP_GET and HTTP_POST if both are registered + if(request->method() == HTTP_GET) + onUpdate(request); + #endif + bool reboot = (!Update.hasError()); String html = F("UpdateUpdate: "); From 3938216db2d94ad530a645b24ba0119ae0d0860c Mon Sep 17 00:00:00 2001 From: lumapu Date: Tue, 12 Dec 2023 23:33:16 +0100 Subject: [PATCH 226/267] 0.8.21 fix fusion cdc boot --- src/platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platformio.ini b/src/platformio.ini index 116eff2c..e7fb137e 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -184,7 +184,7 @@ build_flags = ${env.build_flags} -DDEF_LED1=17 -DLED_ACTIVE_HIGH -DARDUINO_USB_MODE=1 - -DARDUINO_USB_CDC_ON_BOOT=1 + #-DARDUINO_USB_CDC_ON_BOOT=1 monitor_filters = esp32_exception_decoder, colorize From 30f580891ffd6f9b59053aad7d91df8d4b79d12e Mon Sep 17 00:00:00 2001 From: lumapu Date: Wed, 13 Dec 2023 22:51:59 +0100 Subject: [PATCH 227/267] 0.8.22 * fix communication state-machine regarding zero export #1267 --- src/CHANGES.md | 3 ++ src/defines.h | 2 +- src/hm/Communication.h | 111 +++++++++++++++++++++-------------------- src/hm/radio.h | 4 -- 4 files changed, 62 insertions(+), 58 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index ff2eefc4..839470fb 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.8.22 - 2023-12-13 +* fix communication state-machine regarding zero export #1267 + ## 0.8.21 - 2023-12-12 * fix ethernet save inverter parameters #886 * fix ethernet OTA update #886 diff --git a/src/defines.h b/src/defines.h index 7e715484..8d5dbfd3 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 21 +#define VERSION_PATCH 22 //------------------------------------- typedef struct { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 5e004417..c72aa45d 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -48,8 +48,8 @@ class Communication : public CommQueue<> { if(!valid) return; // empty - uint16_t timeout = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment && q->iv->mGotLastMsg) || mIsResend) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT; - uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment || mIsResend)) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT; + uint16_t timeout = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment && q->iv->mGotLastMsg) || mIsRetransmit) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT; + uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment || mIsRetransmit)) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT; /*if(mDebugState != mState) { DPRINT(DBG_INFO, F("State: ")); @@ -71,7 +71,7 @@ class Communication : public CommQueue<> { q->iv->mGotFragment = false; q->iv->mGotLastMsg = false; q->iv->curFrmCnt = 0; - mIsResend = false; + mIsRetransmit = false; if(NULL == q->iv->radio) cmdDone(true); // can't communicate while radio is not defined! mState = States::START; @@ -97,15 +97,15 @@ class Communication : public CommQueue<> { q->iv->radioStatistics.txCnt++; mWaitTimeout = millis() + timeout; mWaitTimeout_min = millis() + timeout_min; - mIsResend = false; - mlastTO_min = timeout_min; + mIsRetransmit = false; + mlastTO_min = timeout_min; setAttempt(); mState = States::WAIT; break; case States::WAIT: /*if(millis() > mWaitTimeout_min) { - if(mIsResend) { // we already have been through... + if(mIsRetransmit) { // we already have been through... mWaitTimeout = mWaitTimeout_min; } else if(q->iv->mGotFragment) { // nothing received yet? if(q->iv->mGotLastMsg) { @@ -132,7 +132,7 @@ class Communication : public CommQueue<> { break; case States::CHECK_FRAMES: { - if((!q->iv->radio->get() && !mIsResend) || (((q->iv->mGotFragment) || (mIsResend)) && (0 == q->attempts))) { // radio buffer empty or no more answers + if((q->iv->radio->mBufCtrl.empty() && !mIsRetransmit) || (0 == q->attempts)) { // radio buffer empty or no more answers if(*mSerialDebug) { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("request timeout: ")); @@ -148,42 +148,15 @@ class Communication : public CommQueue<> { closeRequest(q, false); break; } - + mIsRetransmit = false; mFirstTry = false; // for correct reset States nextState = States::RESET; while(!q->iv->radio->mBufCtrl.empty()) { packet_t *p = &q->iv->radio->mBufCtrl.front(); + printRxInfo(q, p); - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("RX ")); - if(p->millis < 100) - DBGPRINT(F(" ")); - DBGPRINT(String(p->millis)); - DBGPRINT(F("ms | ")); - DBGPRINT(String(p->len)); - if((IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen)) { - DBGPRINT(F(" CH")); - if(3 == p->ch) - DBGPRINT(F("0")); - DBGPRINT(String(p->ch)); - DBGPRINT(F(" ")); - } else { - DBGPRINT(F(" ")); - DBGPRINT(String(p->rssi)); - DBGPRINT(F("dBm | ")); - } - if(*mPrintWholeTrace) { - if(*mPrivacyMode) - ah::dumpBuf(p->packet, p->len, 1, 8); - else - ah::dumpBuf(p->packet, p->len); - } else { - DBGPRINT(F("| ")); - DBGHEXLN(p->packet[9]); - } - - if(checkIvSerial(&p->packet[1], q->iv)) { + if(validateIvSerial(&p->packet[1], q->iv)) { q->iv->radioStatistics.frmCnt++; if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command @@ -191,29 +164,29 @@ class Communication : public CommQueue<> { q->iv->curFrmCnt++; nextState = States::CHECK_PACKAGE; } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command - parseDevCtrl(p, q); - closeRequest(q, true); + if(parseDevCtrl(p, q)) + closeRequest(q, true); + else + closeRequest(q, false); + return; // don't wait for empty buffer } else if(IV_MI == q->iv->ivGen) { if(parseMiFrame(p, q)) q->iv->curFrmCnt++; } - } else { - q->iv->radioStatistics.rxFail++; // got no complete payload - mWaitTimeout = millis() + timeout; - } + } //else // serial does not match q->iv->radio->mBufCtrl.pop(); yield(); } + if(0 == q->attempts) closeRequest(q, false); else { if(q->iv->ivGen != IV_MI) { mState = nextState; - if(States::RESET == mState) + if(States::RESET == nextState) // no valid package received closeRequest(q, false); - } - else { + } else { if(q->iv->miMultiParts < 6) { nextState = States::WAIT; } else { @@ -265,7 +238,7 @@ class Communication : public CommQueue<> { DBGPRINTLN(F(" attempts left)")); } sendRetransmit(q, framnr-1); - mIsResend = true; + mIsRetransmit = true; mlastTO_min = timeout_min; return; } @@ -282,7 +255,37 @@ class Communication : public CommQueue<> { } private: - inline bool checkIvSerial(uint8_t buf[], Inverter<> *iv) { + inline void printRxInfo(const queue_s *q, packet_t *p) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("RX ")); + if(p->millis < 100) + DBGPRINT(F(" ")); + DBGPRINT(String(p->millis)); + DBGPRINT(F("ms | ")); + DBGPRINT(String(p->len)); + if((IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen)) { + DBGPRINT(F(" CH")); + if(3 == p->ch) + DBGPRINT(F("0")); + DBGPRINT(String(p->ch)); + DBGPRINT(F(" ")); + } else { + DBGPRINT(F(" ")); + DBGPRINT(String(p->rssi)); + DBGPRINT(F("dBm | ")); + } + if(*mPrintWholeTrace) { + if(*mPrivacyMode) + ah::dumpBuf(p->packet, p->len, 1, 8); + else + ah::dumpBuf(p->packet, p->len); + } else { + DBGPRINT(F("| ")); + DBGHEXLN(p->packet[9]); + } + } + + inline bool validateIvSerial(uint8_t buf[], Inverter<> *iv) { uint8_t tmp[4]; CP_U32_BigEndian(tmp, iv->radioId.u64 >> 8); for(uint8_t i = 0; i < 4; i++) { @@ -350,9 +353,9 @@ class Communication : public CommQueue<> { return true; } - inline void parseDevCtrl(packet_t *p, const queue_s *q) { + inline bool parseDevCtrl(packet_t *p, const queue_s *q) { if((p->packet[12] != ActivePowerContr) || (p->packet[13] != 0x00)) - return; + return false; bool accepted = true; if((p->packet[10] == 0x00) && (p->packet[11] == 0x00)) q->iv->powerLimitAck = true; @@ -367,6 +370,8 @@ class Communication : public CommQueue<> { DBGPRINT(F(" with PowerLimitControl ")); DBGPRINTLN(String(q->iv->powerLimit[1])); q->iv->actPowerLimit = 0xffff; // unknown, readback current value + + return accepted; } inline void compilePayload(const queue_s *q) { @@ -488,7 +493,7 @@ class Communication : public CommQueue<> { q->iv->mGotFragment = false; q->iv->mGotLastMsg = false; q->iv->miMultiParts = 0; - mIsResend = false; + mIsRetransmit = false; mFirstTry = false; // for correct reset mState = States::RESET; DBGPRINTLN("-----"); @@ -702,7 +707,7 @@ class Communication : public CommQueue<> { mWaitTimeout_min = mWaitTimeout; q->iv->miMultiParts = 0; q->iv->mGotFragment = 0; - mIsResend = true; + mIsRetransmit = true; chgCmd(cmd); //mState = States::WAIT; } @@ -840,7 +845,7 @@ class Communication : public CommQueue<> { uint32_t mWaitTimeout_min = 0; std::array mLocalBuf; bool mFirstTry = false; // see, if we should do a second try - bool mIsResend = false; // we alrady had waited one complete cycle + bool mIsRetransmit = false; // we alrady had waited one complete cycle uint16_t mlastTO_min = DEFAULT_TIMEOUT; // remember timeout_min for correct calculation uint8_t mMaxFrameId; uint8_t mPayload[MAX_BUFFER]; diff --git a/src/hm/radio.h b/src/hm/radio.h index 55901bd1..2fe4f640 100644 --- a/src/hm/radio.h +++ b/src/hm/radio.h @@ -28,10 +28,6 @@ class Radio { virtual void loop(void) {}; - bool get() { - return !mBufCtrl.empty(); - } - void handleIntr(void) { mIrqRcvd = true; } From 222bf0e54a4315706bb0d39c38af05b2943c2821 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 14 Dec 2023 23:34:10 +0100 Subject: [PATCH 228/267] 0.8.23 * heuristics fix #1269 #1270 * moved `sendInterval` in settings, **important:** *will be reseted to 15s after update to this version* * try to prevent access to radio classes if they are not activated * fixed millis in serial log * changed 'print whole trace' = `false` as default * added communication loop duration in [ms] to serial console * don't print Hex-Payload if 'print whole trace' == `false` --- src/CHANGES.md | 9 +++++++++ src/app.cpp | 14 ++++++++++++-- src/app.h | 6 +++++- src/appInterface.h | 1 + src/config/settings.h | 16 ++++++++++------ src/defines.h | 2 +- src/hm/CommQueue.h | 9 +++++++++ src/hm/Communication.h | 40 +++++++++++++++++++++++++++------------- src/hm/Heuristic.h | 29 +++++++++++++++++++++-------- src/utils/helper.cpp | 6 ++++-- src/utils/helper.h | 2 +- src/utils/scheduler.h | 11 ++++++----- src/web/RestApi.h | 22 ++++++++++++---------- src/web/web.h | 6 ++---- 14 files changed, 120 insertions(+), 53 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 839470fb..85e477e3 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,14 @@ # Development Changes +## 0.8.23 - 2023-12-14 +* heuristics fix #1269 #1270 +* moved `sendInterval` in settings, **important:** *will be reseted to 15s after update to this version* +* try to prevent access to radio classes if they are not activated +* fixed millis in serial log +* changed 'print whole trace' = `false` as default +* added communication loop duration in [ms] to serial console +* don't print Hex-Payload if 'print whole trace' == `false` + ## 0.8.22 - 2023-12-13 * fix communication state-machine regarding zero export #1267 diff --git a/src/app.cpp b/src/app.cpp index cb2e6947..d670c696 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -123,7 +123,7 @@ void app::onNetwork(bool gotIp) { mNetworkConnected = gotIp; ah::Scheduler::resetTicker(); regularTickers(); //reinstall regular tickers - every(std::bind(&app::tickSend, this), mConfig->nrf.sendInterval, "tSend"); + every(std::bind(&app::tickSend, this), mConfig->inst.sendInterval, "tSend"); mMqttReconnect = true; mSunrise = 0; // needs to be set to 0, to reinstall sunrise and ivComm tickers! once(std::bind(&app::tickNtpUpdate, this), 2, "ntp2"); @@ -275,7 +275,7 @@ void app::tickIVCommunication(void) { onceAt(std::bind(&app::tickIVCommunication, this), nxtTrig, "ivCom"); if (zeroValues) // at least one inverter - once(std::bind(&app::tickZeroValues, this), mConfig->nrf.sendInterval, "tZero"); + once(std::bind(&app::tickZeroValues, this), mConfig->inst.sendInterval, "tZero"); } //----------------------------------------------------------------------------- @@ -334,6 +334,16 @@ void app::tickMidnight(void) { //----------------------------------------------------------------------------- void app::tickSend(void) { + uint8_t fill = mCommunication.getFillState(); + uint8_t max = mCommunication.getMaxFill(); + if((max-MAX_NUM_INVERTERS) <= fill) { + DPRINT(DBG_WARN, F("send queue almost full, consider to increase interval, ")); + DBGPRINT(String(fill)); + DBGPRINT(F(" of ")); + DBGPRINT(String(max)); + DBGPRINTLN(F("entries used")); + } + for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { Inverter<> *iv = mSys.getInverterByPos(i); if(NULL == iv) diff --git a/src/app.h b/src/app.h index f2b4e548..a71ee03c 100644 --- a/src/app.h +++ b/src/app.h @@ -91,7 +91,11 @@ class app : public IApp, public ah::Scheduler { } uint32_t getTimestamp() { - return Scheduler::getTimestamp(); + return Scheduler::mTimestamp; + } + + uint64_t getTimestampMs() { + return ((uint64_t)Scheduler::mTimestamp * 1000) + (uint64_t)Scheduler::mTsMillis; } bool saveSettings(bool reboot) { diff --git a/src/appInterface.h b/src/appInterface.h index 7814d0e1..34dc5ddc 100644 --- a/src/appInterface.h +++ b/src/appInterface.h @@ -41,6 +41,7 @@ class IApp { virtual uint32_t getUptime() = 0; virtual uint32_t getTimestamp() = 0; + virtual uint64_t getTimestampMs() = 0; virtual uint32_t getSunrise() = 0; virtual uint32_t getSunset() = 0; virtual void setTimestamp(uint32_t newTime) = 0; diff --git a/src/config/settings.h b/src/config/settings.h index 92ad1195..31b5cab4 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -30,7 +30,7 @@ * https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html#flash-layout * */ -#define CONFIG_VERSION 4 +#define CONFIG_VERSION 5 #define PROT_MASK_INDEX 0x0001 @@ -80,7 +80,6 @@ typedef struct { typedef struct { bool enabled; - uint16_t sendInterval; uint8_t pinCs; uint8_t pinCe; uint8_t pinIrq; @@ -150,6 +149,7 @@ typedef struct { bool enabled; cfgIv_t iv[MAX_NUM_INVERTERS]; + uint16_t sendInterval; bool rstYieldMidNight; bool rstValsNotAvail; bool rstValsCommStop; @@ -388,7 +388,6 @@ class settings { snprintf(mCfg.sys.deviceName, DEVNAME_LEN, DEF_DEVICE_NAME); - mCfg.nrf.sendInterval = SEND_INTERVAL; mCfg.nrf.pinCs = DEF_NRF_CS_PIN; mCfg.nrf.pinCe = DEF_NRF_CE_PIN; mCfg.nrf.pinIrq = DEF_NRF_IRQ_PIN; @@ -433,6 +432,7 @@ class settings { snprintf(mCfg.mqtt.topic, MQTT_TOPIC_LEN, "%s", DEF_MQTT_TOPIC); mCfg.mqtt.interval = 0; // off + mCfg.inst.sendInterval = SEND_INTERVAL; mCfg.inst.rstYieldMidNight = false; mCfg.inst.rstValsNotAvail = false; mCfg.inst.rstValsCommStop = false; @@ -478,11 +478,15 @@ class settings { mCfg.inst.iv[i].add2Total = true; } if(mCfg.configVersion < 3) { - mCfg.serial.printWholeTrace = true; + mCfg.serial.printWholeTrace = false; } if(mCfg.configVersion < 4) { mCfg.inst.gapMs = 2000; } + if(mCfg.configVersion < 5) { + mCfg.inst.sendInterval = SEND_INTERVAL; + mCfg.serial.printWholeTrace = false; + } } } @@ -539,7 +543,6 @@ class settings { void jsonNrf(JsonObject obj, bool set = false) { if(set) { - obj[F("intvl")] = mCfg.nrf.sendInterval; obj[F("cs")] = mCfg.nrf.pinCs; obj[F("ce")] = mCfg.nrf.pinCe; obj[F("irq")] = mCfg.nrf.pinIrq; @@ -548,7 +551,6 @@ class settings { obj[F("miso")] = mCfg.nrf.pinMiso; obj[F("en")] = (bool) mCfg.nrf.enabled; } else { - getVal(obj, F("intvl"), &mCfg.nrf.sendInterval); getVal(obj, F("cs"), &mCfg.nrf.pinCs); getVal(obj, F("ce"), &mCfg.nrf.pinCe); getVal(obj, F("irq"), &mCfg.nrf.pinIrq); @@ -707,6 +709,7 @@ class settings { void jsonInst(JsonObject obj, bool set = false) { if(set) { + obj[F("intvl")] = mCfg.inst.sendInterval; obj[F("en")] = (bool)mCfg.inst.enabled; obj[F("rstMidNight")] = (bool)mCfg.inst.rstYieldMidNight; obj[F("rstNotAvail")] = (bool)mCfg.inst.rstValsNotAvail; @@ -717,6 +720,7 @@ class settings { obj[F("gap")] = mCfg.inst.gapMs; } else { + getVal(obj, F("intvl"), &mCfg.inst.sendInterval); getVal(obj, F("en"), &mCfg.inst.enabled); getVal(obj, F("rstMidNight"), &mCfg.inst.rstYieldMidNight); getVal(obj, F("rstNotAvail"), &mCfg.inst.rstValsNotAvail); diff --git a/src/defines.h b/src/defines.h index 8d5dbfd3..c4559891 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 22 +#define VERSION_PATCH 23 //------------------------------------- typedef struct { diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index 9771393d..5d6f9bd0 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -9,6 +9,7 @@ #include #include #include "hmInverter.h" +#include "../utils/dbg.h" template class CommQueue { @@ -29,6 +30,14 @@ class CommQueue { mQueue[mWrPtr] = queue_s(iv, cmd, delOnPop, false); } + uint8_t getFillState(void) { + return abs(mRdPtr - mWrPtr); + } + + uint8_t getMaxFill(void) { + return N; + } + protected: struct queue_s { Inverter<> *iv; diff --git a/src/hm/Communication.h b/src/hm/Communication.h index c72aa45d..51db6418 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -45,8 +45,19 @@ class Communication : public CommQueue<> { void loop() { get([this](bool valid, const queue_s *q) { - if(!valid) + if(!valid) { + if(mPrintSequenceDuration) { + mPrintSequenceDuration = false; + DPRINT(DBG_INFO, F("com loop duration: ")); + DBGPRINT(String(millis() - mLastEmptyQueueMillis)); + DBGPRINTLN(F("ms")); + DBGPRINTLN(F("-----")); + } return; // empty + } + if(!mPrintSequenceDuration) // entry was added to the queue + mLastEmptyQueueMillis = millis(); + mPrintSequenceDuration = true; uint16_t timeout = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment && q->iv->mGotLastMsg) || mIsRetransmit) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT; uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment || mIsRetransmit)) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT; @@ -151,7 +162,6 @@ class Communication : public CommQueue<> { mIsRetransmit = false; mFirstTry = false; // for correct reset - States nextState = States::RESET; while(!q->iv->radio->mBufCtrl.empty()) { packet_t *p = &q->iv->radio->mBufCtrl.front(); printRxInfo(q, p); @@ -162,7 +172,6 @@ class Communication : public CommQueue<> { if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command if(parseFrame(p)) q->iv->curFrmCnt++; - nextState = States::CHECK_PACKAGE; } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command if(parseDevCtrl(p, q)) closeRequest(q, true); @@ -179,16 +188,16 @@ class Communication : public CommQueue<> { yield(); } - if(0 == q->attempts) + if(0 == q->attempts) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("no attempts left")); closeRequest(q, false); - else { + } else { if(q->iv->ivGen != IV_MI) { - mState = nextState; - if(States::RESET == nextState) // no valid package received - closeRequest(q, false); + mState = States::CHECK_PACKAGE; } else { if(q->iv->miMultiParts < 6) { - nextState = States::WAIT; + mState = States::WAIT; } else { if(((q->cmd == 0x39) && (q->iv->type == INV_TYPE_4CH)) || ((q->cmd == MI_REQ_CH2) && (q->iv->type == INV_TYPE_2CH)) @@ -237,7 +246,7 @@ class Communication : public CommQueue<> { DBGPRINT(String(q->attempts)); DBGPRINTLN(F(" attempts left)")); } - sendRetransmit(q, framnr-1); + sendRetransmit(q, (framnr-1)); mIsRetransmit = true; mlastTO_min = timeout_min; return; @@ -425,8 +434,11 @@ class Communication : public CommQueue<> { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("Payload (")); DBGPRINT(String(len)); - DBGPRINT(F("): ")); - ah::dumpBuf(mPayload, len); + if(*mPrintWholeTrace) { + DBGPRINT(F("): ")); + ah::dumpBuf(mPayload, len); + } else + DBGPRINTLN(F(")")); record_t<> *rec = q->iv->getRecordStruct(q->cmd); if(NULL == rec) { @@ -496,7 +508,7 @@ class Communication : public CommQueue<> { mIsRetransmit = false; mFirstTry = false; // for correct reset mState = States::RESET; - DBGPRINTLN("-----"); + DBGPRINTLN(F("-----")); } inline void miHwDecode(packet_t *p, const queue_s *q) { @@ -852,6 +864,8 @@ class Communication : public CommQueue<> { payloadListenerType mCbPayload = NULL; alarmListenerType mCbAlarm = NULL; Heuristic mHeu; + uint32_t mLastEmptyQueueMillis = 0; + bool mPrintSequenceDuration = false; //States mDebugState = States::START; }; diff --git a/src/hm/Heuristic.h b/src/hm/Heuristic.h index 4b3705dd..64c78cc8 100644 --- a/src/hm/Heuristic.h +++ b/src/hm/Heuristic.h @@ -54,7 +54,7 @@ class Heuristic { ih->txRfQuality[ih->testChId] = ih->txRfQuality[ih->txRfChId]; ih->txRfChId = ih->testChId; ih->testChId = RF_TX_TEST_CHAN_1ST_USE; // mark the chan as a test and as 1st use during new test period - DPRINTLN(DBG_INFO, "Test CH " + String(id2Ch(ih->txRfChId))); + DPRINTLN(DBG_INFO, F("Test CH ") + String(id2Ch(ih->txRfChId))); } // start new test period @@ -72,17 +72,29 @@ class Heuristic { void evalTxChQuality(Inverter<> *iv, bool crcPass, uint8_t retransmits, uint8_t rxFragments) { HeuristicInv *ih = &iv->heuristics; + #if (DBG_DEBUG == DEBUG_LEVEL) + DPRINT(DBG_DEBUG, "eval "); + DBGPRINT(String(crcPass)); + DBGPRINT(", "); + DBGPRINT(String(retransmits)); + DBGPRINT(", "); + DBGPRINT(String(rxFragments)); + DBGPRINT(", "); + DBGPRINTLN(String(ih->lastRxFragments)); + #endif + if(ih->lastRxFragments == rxFragments) { - // nothing received: send probably lost - if(!retransmits || isNewTxCh(ih)) { + if(crcPass) + updateQuality(ih, RF_TX_CHAN_QUALITY_GOOD); + else if(!retransmits || isNewTxCh(ih)) { // nothing received: send probably lost if(RF_TX_TEST_CHAN_1ST_USE == ih->testChId) { // switch back to original quality + DPRINTLN(DBG_INFO, F("Test failed (-2)")); ih->txRfQuality[ih->txRfChId] = ih->saveOldTestQuality; - - updateQuality(ih, RF_TX_CHAN_QUALITY_BAD); - if(ih->testPeriodFailCnt < 0xff) - ih->testPeriodFailCnt++; } + updateQuality(ih, RF_TX_CHAN_QUALITY_BAD); + if(ih->testPeriodFailCnt < 0xff) + ih->testPeriodFailCnt++; } } else if(!ih->lastRxFragments && crcPass) { if(!retransmits || isNewTxCh(ih)) { @@ -103,8 +115,9 @@ class Heuristic { // graceful evaluation for big inverters that have to send 4 answer packets updateQuality(ih, RF_TX_CHAN_QUALITY_OK); } else if((rxFragments - ih->lastRxFragments) < 2) { - if(RF_TX_TEST_CHAN_1ST_USE == ih->txRfChId) { + if(RF_TX_TEST_CHAN_1ST_USE == ih->testChId) { // switch back to original quality + DPRINTLN(DBG_INFO, F("Test failed (-1)")); ih->txRfQuality[ih->txRfChId] = ih->saveOldTestQuality; } updateQuality(ih, RF_TX_CHAN_QUALITY_LOW); diff --git a/src/utils/helper.cpp b/src/utils/helper.cpp index e606ad8b..9aea1054 100644 --- a/src/utils/helper.cpp +++ b/src/utils/helper.cpp @@ -70,12 +70,14 @@ namespace ah { return String(str); } - String getTimeStrMs(time_t t) { + String getTimeStrMs(uint64_t t) { char str[13]; if(0 == t) sprintf(str, "n/a"); - else + else { + t = (t + (millis() % 1000)) / 1000; sprintf(str, "%02d:%02d:%02d.%03d", hour(t), minute(t), second(t), millis() % 1000); + } return String(str); } diff --git a/src/utils/helper.h b/src/utils/helper.h index 60721414..1dbba3d9 100644 --- a/src/utils/helper.h +++ b/src/utils/helper.h @@ -44,7 +44,7 @@ namespace ah { String getDateTimeStrShort(time_t t); String getDateTimeStrFile(time_t t); String getTimeStr(time_t t); - String getTimeStrMs(time_t t); + String getTimeStrMs(uint64_t t); uint64_t Serial2u64(const char *val); void dumpBuf(uint8_t buf[], uint8_t len, uint8_t firstRepl = 0, uint8_t lastRepl = 0); } diff --git a/src/utils/scheduler.h b/src/utils/scheduler.h index 954ae18a..23af29f8 100644 --- a/src/utils/scheduler.h +++ b/src/utils/scheduler.h @@ -34,6 +34,7 @@ namespace ah { void setup(bool directStart) { mUptime = 0; mTimestamp = (directStart) ? 1 : 0; + mTsMillis = 0; mMax = 0; mPrevMillis = millis(); resetTicker(); @@ -59,8 +60,10 @@ namespace ah { } mUptime += mDiffSeconds; - if(0 != mTimestamp) + if(0 != mTimestamp) { mTimestamp += mDiffSeconds; + mTsMillis = mMillis % 1000; + } checkTicker(); } @@ -77,6 +80,7 @@ namespace ah { virtual void setTimestamp(uint32_t ts) { mTimestamp = ts; + mTsMillis = millis() % 1000; } bool resetEveryById(uint8_t id) { @@ -90,10 +94,6 @@ namespace ah { return mUptime; } - uint32_t getTimestamp(void) { - return mTimestamp; - } - inline void resetTicker(void) { for (uint8_t i = 0; i < MAX_NUM_TICKER; i++) mTickerInUse[i] = false; @@ -118,6 +118,7 @@ namespace ah { protected: uint32_t mTimestamp; uint32_t mUptime; + uint16_t mTsMillis; private: inline uint8_t addTicker(scdCb c, uint32_t timeout, uint32_t reload, bool isTimestamp, const char *name) { diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 1524fed4..a60d55b8 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -389,7 +389,7 @@ class RestApi { obj2[F("ch_max_pwr")][j] = iv->config->chMaxPwr[j]; } } - obj[F("interval")] = String(mConfig->nrf.sendInterval); + obj[F("interval")] = String(mConfig->inst.sendInterval); obj[F("max_num_inverters")] = MAX_NUM_INVERTERS; obj[F("rstMid")] = (bool)mConfig->inst.rstYieldMidNight; obj[F("rstNotAvail")] = (bool)mConfig->inst.rstValsNotAvail; @@ -556,16 +556,20 @@ class RestApi { void getRadioCmtInfo(JsonObject obj) { obj[F("en")] = (bool) mConfig->cmt.enabled; - obj[F("isconnected")] = mRadioCmt->isChipConnected(); - obj[F("sn")] = String(mRadioCmt->getDTUSn(), HEX); + if(mConfig->cmt.enabled) { + obj[F("isconnected")] = mRadioCmt->isChipConnected(); + obj[F("sn")] = String(mRadioCmt->getDTUSn(), HEX); + } } #endif void getRadioNrf(JsonObject obj) { - obj[F("en")] = (bool) mConfig->nrf.enabled; - obj[F("isconnected")] = mRadioNrf->isChipConnected(); - obj[F("dataRate")] = mRadioNrf->getDataRate(); - obj[F("sn")] = String(mRadioNrf->getDTUSn(), HEX); + obj[F("en")] = (bool) mConfig->nrf.enabled; + if(mConfig->nrf.enabled) { + obj[F("isconnected")] = mRadioNrf->isChipConnected(); + obj[F("dataRate")] = mRadioNrf->getDataRate(); + obj[F("sn")] = String(mRadioNrf->getDTUSn(), HEX); + } } void getSerial(JsonObject obj) { @@ -639,8 +643,6 @@ class RestApi { JsonArray warn = obj.createNestedArray(F("warnings")); if(!mRadioNrf->isChipConnected() && mConfig->nrf.enabled) warn.add(F("your NRF24 module can't be reached, check the wiring, pinout and enable")); - else if(!mRadioNrf->isPVariant() && mConfig->nrf.enabled) - warn.add(F("your NRF24 module isn't a plus version(+), maybe incompatible")); if(!mApp->getSettingsValid()) warn.add(F("your settings are invalid")); if(mApp->getRebootRequestState()) @@ -674,7 +676,7 @@ class RestApi { void getLive(AsyncWebServerRequest *request, JsonObject obj) { getGeneric(request, obj.createNestedObject(F("generic"))); - obj[F("refresh")] = mConfig->nrf.sendInterval; + obj[F("refresh")] = mConfig->inst.sendInterval; for (uint8_t fld = 0; fld < sizeof(acList); fld++) { obj[F("ch0_fld_units")][fld] = String(units[fieldUnits[acList[fld]]]); diff --git a/src/web/web.h b/src/web/web.h index 7ac0f4ad..9dc7ca8f 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -210,7 +210,7 @@ class Web { if (mSerialAddTime) { if ((13 + mSerialBufFill) < WEB_SERIAL_BUF_SIZE) { if (mApp->getTimestamp() > 0) { - strncpy(&mSerialBuf[mSerialBufFill], ah::getTimeStrMs(mApp->getTimestamp() + mApp->getTimezoneOffset()).c_str(), 12); + strncpy(&mSerialBuf[mSerialBufFill], ah::getTimeStrMs(mApp->getTimestampMs() + mApp->getTimezoneOffset() * 1000).c_str(), 12); mSerialBuf[mSerialBufFill+12] = ' '; mSerialBufFill += 13; } @@ -496,7 +496,7 @@ class Web { ah::ip2Arr(mConfig->sys.ip.gateway, buf); if (request->arg("invInterval") != "") - mConfig->nrf.sendInterval = request->arg("invInterval").toInt(); + mConfig->inst.sendInterval = request->arg("invInterval").toInt(); mConfig->inst.rstYieldMidNight = (request->arg("invRstMid") == "on"); mConfig->inst.rstValsCommStop = (request->arg("invRstComStop") == "on"); mConfig->inst.rstValsNotAvail = (request->arg("invRstNotAvail") == "on"); @@ -529,8 +529,6 @@ class Web { } mConfig->nrf.enabled = (request->arg("nrfEnable") == "on"); - - // cmt mConfig->cmt.enabled = (request->arg("cmtEnable") == "on"); // ntp From 69cdacaac7cb33fb4f341effae6d9ec814e2503c Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 15 Dec 2023 11:33:12 +0100 Subject: [PATCH 229/267] Enhancement: log to syslog server instead of web-serial --- src/utils/syslog.cpp | 99 ++++++++++++++++++++++++++++++++++++++++++++ src/utils/syslog.h | 54 ++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 src/utils/syslog.cpp create mode 100644 src/utils/syslog.h diff --git a/src/utils/syslog.cpp b/src/utils/syslog.cpp new file mode 100644 index 00000000..5e73f287 --- /dev/null +++ b/src/utils/syslog.cpp @@ -0,0 +1,99 @@ +#include +#include "syslog.h" + +#ifdef ENABLE_SYSLOG + +#define SYSLOG_MAX_PACKET_SIZE 256 + + +//----------------------------------------------------------------------------- +void DbgSyslog::setup(settings_t *config) { + mConfig = config; + + // Syslog callback overrides web-serial callback + registerDebugCb(std::bind(&DbgSyslog::syslogCb, this, std::placeholders::_1)); // dbg.h +} + +//----------------------------------------------------------------------------- +void DbgSyslog::syslogCb (String msg) +{ + if (!mSyslogIP.isSet()) { + // use WiFi.hostByName to DNS lookup for IPAddress of syslog server + if (WiFi.status() == WL_CONNECTED) { + WiFi.hostByName(SYSLOG_HOST,mSyslogIP); + } + } + if (!mSyslogIP.isSet()) { + return; + } + uint16_t msgLength = msg.length(); + uint16_t msgPos = 0; + + do { + uint16_t charsToCopy = std::min(msgLength-msgPos,SYSLOG_BUF_SIZE - mSyslogBufFill); + + while (charsToCopy > 0) { + mSyslogBuffer[mSyslogBufFill] = msg[msgPos]; + msgPos++; + mSyslogBufFill++; + charsToCopy--; + } + mSyslogBuffer[mSyslogBufFill] = '\0'; + + bool isBufferFull = (mSyslogBufFill == SYSLOG_BUF_SIZE); + bool isEolFound = false; + if (mSyslogBufFill >= 2) { + isEolFound = (mSyslogBuffer[mSyslogBufFill-2] == '\r' && mSyslogBuffer[mSyslogBufFill-1] == '\n'); + } + // Get severity from input message + if (msgLength >= 2) { + if (':' == msg[1]) { + switch(msg[0]) { + case 'E': mSyslogSeverity = PRI_ERROR; break; + case 'W': mSyslogSeverity = PRI_WARNING; break; + case 'I': mSyslogSeverity = PRI_INFO; break; + case 'D': mSyslogSeverity = PRI_DEBUG; break; + default: mSyslogSeverity = PRI_NOTICE; break; + } + } + } + + if (isBufferFull || isEolFound) { + // Send mSyslogBuffer in chunks because mSyslogBuffer is larger than syslog packet size + int packetStart = 0; + int packetSize = 122; // syslog payload depends also on hostname and app + char saveChar; + if (isEolFound) { + mSyslogBuffer[mSyslogBufFill-2]=0; // skip \r\n + } + while(packetStart < mSyslogBufFill) { + saveChar = mSyslogBuffer[packetStart+packetSize]; + mSyslogBuffer[packetStart+packetSize] = 0; + log(mConfig->sys.deviceName,SYSLOG_FACILITY, mSyslogSeverity, &mSyslogBuffer[packetStart]); + mSyslogBuffer[packetStart+packetSize] = saveChar; + packetStart += packetSize; + } + mSyslogBufFill = 0; + } + + } while (msgPos < msgLength); // Message not completely processed + +} + +//----------------------------------------------------------------------------- +void DbgSyslog::log(const char *hostname, uint8_t facility, uint8_t severity, char* msg) { + // The PRI value is an integer number which calculates by the following metric: + uint8_t priority = (8 * facility) + severity; + + // This is a unit8 instead of a char because that's what udp.write() wants + uint8_t buffer[SYSLOG_MAX_PACKET_SIZE]; + int len = snprintf((char*)buffer, SYSLOG_MAX_PACKET_SIZE, "<%d>%s %s: %s", priority, hostname, SYSLOG_APP, msg); + //printf("syslog::log %s\n",mSyslogIP.toString().c_str()); + //printf("syslog::log %d %s\n",len,buffer); + // Send the raw UDP packet + mSyslogUdp.beginPacket(mSyslogIP, SYSLOG_PORT); + mSyslogUdp.write(buffer, len); + mSyslogUdp.endPacket(); +} + +#endif \ No newline at end of file diff --git a/src/utils/syslog.h b/src/utils/syslog.h new file mode 100644 index 00000000..aac9db14 --- /dev/null +++ b/src/utils/syslog.h @@ -0,0 +1,54 @@ + +#ifndef __SYSLOG_H__ +#define __SYSLOG_H__ + +#ifdef ESP8266 + #include +#elif defined(ESP32) + #include +#endif +#include +#include "../config/config.h" +#include "../config/settings.h" + +#ifdef ENABLE_SYSLOG + +#define SYSLOG_BUF_SIZE 255 + +#define PRI_EMERGENCY 0 +#define PRI_ALERT 1 +#define PRI_CRITICAL 2 +#define PRI_ERROR 3 +#define PRI_WARNING 4 +#define PRI_NOTICE 5 +#define PRI_INFO 6 +#define PRI_DEBUG 7 + +#define FAC_USER 1 +#define FAC_LOCAL0 16 +#define FAC_LOCAL1 17 +#define FAC_LOCAL2 18 +#define FAC_LOCAL3 19 +#define FAC_LOCAL4 20 +#define FAC_LOCAL5 21 +#define FAC_LOCAL6 22 +#define FAC_LOCAL7 23 + +class DbgSyslog { + public: + void setup (settings_t *config); + void syslogCb(String msg); + void log(const char *hostname, uint8_t facility, uint8_t severity, char* msg); + + private: + WiFiUDP mSyslogUdp; + IPAddress mSyslogIP; + settings_t *mConfig; + char mSyslogBuffer[SYSLOG_BUF_SIZE+1]; + uint16_t mSyslogBufFill = 0; + int mSyslogSeverity = PRI_NOTICE; +}; + +#endif + +#endif \ No newline at end of file From 21848bd5ae5f163e3add306db0163fbadf41567f Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 15 Dec 2023 11:33:48 +0100 Subject: [PATCH 230/267] Enhancement: log to syslog server instead of web-serial --- src/app.cpp | 3 +++ src/app.h | 4 ++++ src/config/config_override_example.h | 9 +++++++++ 3 files changed, 16 insertions(+) diff --git a/src/app.cpp b/src/app.cpp index d670c696..82e25724 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -82,6 +82,9 @@ void app::setup() { mApi.setup(this, &mSys, mWeb.getWebSrvPtr(), mConfig); + #ifdef ENABLE_SYSLOG + mDbgSyslog.setup(mConfig); // be sure to init after mWeb.setup (webSerial uses also debug callback) + #endif // Plugins #if defined(PLUGIN_DISPLAY) if (mConfig->plugin.display.type != 0) diff --git a/src/app.h b/src/app.h index a71ee03c..a24cccb3 100644 --- a/src/app.h +++ b/src/app.h @@ -22,6 +22,7 @@ #include "utils/crc.h" #include "utils/dbg.h" #include "utils/scheduler.h" +#include "utils/syslog.h" #include "web/RestApi.h" #include "web/web.h" #include "hm/Communication.h" @@ -311,6 +312,9 @@ class app : public IApp, public ah::Scheduler { #endif /* defined(ETHERNET) */ WebType mWeb; RestApiType mApi; + #ifdef ENABLE_SYSLOG + DbgSyslog mDbgSyslog; + #endif //PayloadType mPayload; //MiPayloadType mMiPayload; PubSerialType mPubSerial; diff --git a/src/config/config_override_example.h b/src/config/config_override_example.h index c653bf10..b90bbdbd 100644 --- a/src/config/config_override_example.h +++ b/src/config/config_override_example.h @@ -35,4 +35,13 @@ // #define ENABLE_PROMETHEUS_EP +// to enable the syslog logging (will disable web-serial) +//#define ENABLE_SYSLOG +#ifdef ENABLE_SYSLOG +#define SYSLOG_HOST "" +#define SYSLOG_APP "ahoy" +#define SYSLOG_FACILITY FAC_USER +#define SYSLOG_PORT 514 +#endif + #endif /*__CONFIG_OVERRIDE_H__*/ From f191c036bb633668576d69960ff55a4fee631b7c Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 16 Dec 2023 03:06:28 +0100 Subject: [PATCH 231/267] 0.8.24 * fix NRF communication for opendtufusion ethernet variant --- scripts/applyPatches.py | 1 - src/CHANGES.md | 3 +++ src/defines.h | 2 +- src/hm/CommQueue.h | 1 + src/hm/hmRadio.h | 20 +++++++++----------- src/hm/nrfHal.h | 2 +- src/hms/cmt2300a.h | 4 ++-- src/platformio.ini | 13 ++++++++++++- 8 files changed, 29 insertions(+), 17 deletions(-) diff --git a/scripts/applyPatches.py b/scripts/applyPatches.py index 131572fd..3ba30a5f 100644 --- a/scripts/applyPatches.py +++ b/scripts/applyPatches.py @@ -31,5 +31,4 @@ if env['PIOENV'][:22] != "opendtufusion-ethernet": if env['PIOENV'][:13] == "opendtufusion": applyPatch("GxEPD2", "../patches/GxEPD2_SW_SPI.patch") -if env['PIOENV'][:22] == "opendtufusion-ethernet": applyPatch("RF24", "../patches/RF24_Hal.patch") diff --git a/src/CHANGES.md b/src/CHANGES.md index 85e477e3..6364a7e7 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.8.24 - 2023-12-16 +* fix NRF communication for opendtufusion ethernet variant + ## 0.8.23 - 2023-12-14 * heuristics fix #1269 #1270 * moved `sendInterval` in settings, **important:** *will be reseted to 15s after update to this version* diff --git a/src/defines.h b/src/defines.h index c4559891..71bfc1fa 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 23 +#define VERSION_PATCH 24 //------------------------------------- typedef struct { diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index 5d6f9bd0..d1beedfc 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -31,6 +31,7 @@ class CommQueue { } uint8_t getFillState(void) { + DPRINTLN(DBG_INFO, "wr: " + String(mWrPtr) + ", rd: " + String(mRdPtr)); return abs(mRdPtr - mWrPtr); } diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 14146830..d0387aa4 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -10,7 +10,7 @@ #include "SPI.h" #include "radio.h" #include "../config/config.h" -#if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(ETHERNET) +#if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(SPI_HAL) #include "nrfHal.h" #endif @@ -35,8 +35,8 @@ class HmRadio : public Radio { HmRadio() { mDtuSn = DTU_SN; mIrqRcvd = false; - #if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(ETHERNET) - mNrf24.reset(new RF24()); + #if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(SPI_HAL) + //mNrf24.reset(new RF24()); #else mNrf24.reset(new RF24(CE_PIN, CS_PIN, SPI_SPEED)); #endif @@ -56,8 +56,8 @@ class HmRadio : public Radio { DTU_RADIO_ID = ((uint64_t)(((mDtuSn >> 24) & 0xFF) | ((mDtuSn >> 8) & 0xFF00) | ((mDtuSn << 8) & 0xFF0000) | ((mDtuSn << 24) & 0xFF000000)) << 8) | 0x01; #ifdef ESP32 - #if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(ETHERNET) - mNrfHal.init(mosi, miso, sclk, cs, ce); + #if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(SPI_HAL) + mNrfHal.init(mosi, miso, sclk, cs, ce, SPI_SPEED); mNrf24.reset(new RF24(&mNrfHal)); #else #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 @@ -73,7 +73,7 @@ class HmRadio : public Radio { mSpi->begin(); #endif - #if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(ETHERNET) + #if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(SPI_HAL) mNrf24->begin(); #else mNrf24->begin(mSpi.get(), ce, cs); @@ -133,14 +133,12 @@ class HmRadio : public Radio { yield(); } // switch to next RX channel - if(++mRxChIdx >= RF_CHANNELS) - mRxChIdx = 0; + mRxChIdx = (mRxChIdx + 1) % RF_CHANNELS; mNrf24->setChannel(mRfChLst[mRxChIdx]); startMicros = micros(); } // not finished but time is over - if(++mRxChIdx >= RF_CHANNELS) - mRxChIdx = 0; + mRxChIdx = (mRxChIdx + 1) % RF_CHANNELS; return; } @@ -344,7 +342,7 @@ class HmRadio : public Radio { std::unique_ptr mSpi; std::unique_ptr mNrf24; - #if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(ETHERNET) + #if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(SPI_HAL) nrfHal mNrfHal; #endif Inverter<> *mLastIv = NULL; diff --git a/src/hm/nrfHal.h b/src/hm/nrfHal.h index d4db9f92..c9fbcdc7 100644 --- a/src/hm/nrfHal.h +++ b/src/hm/nrfHal.h @@ -118,7 +118,7 @@ class nrfHal: public RF24_hal, public SpiPatcherHandle { uint8_t write(uint8_t cmd, const uint8_t* buf, uint8_t data_len, uint8_t blank_len) override { uint8_t data[NRF_MAX_TRANSFER_SZ]; data[0] = cmd; - memset(data, 0, NRF_MAX_TRANSFER_SZ); + memset(&data[1], 0, (NRF_MAX_TRANSFER_SZ-1)); std::copy(&buf[0], &buf[data_len], &data[1]); request_spi(); diff --git a/src/hms/cmt2300a.h b/src/hms/cmt2300a.h index bbbeefc7..1ff112e2 100644 --- a/src/hms/cmt2300a.h +++ b/src/hms/cmt2300a.h @@ -6,7 +6,7 @@ #ifndef __CMT2300A_H__ #define __CMT2300A_H__ -#if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(ETHERNET) +#if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(SPI_HAL) #include "cmtHal.h" #else #include "esp32_3wSpi.h" @@ -480,7 +480,7 @@ class Cmt2300a { return mSpi.readReg(CMT2300A_CUS_MODE_STA) & CMT2300A_MASK_CHIP_MODE_STA; } - #if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(ETHERNET) + #if defined(CONFIG_IDF_TARGET_ESP32S3) && defined(SPI_HAL) cmtHal mSpi; #else esp32_3wSpi mSpi; diff --git a/src/platformio.ini b/src/platformio.ini index e7fb137e..43fd7ddd 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -162,6 +162,7 @@ lib_deps = upload_protocol = esp-builtin build_flags = ${env.build_flags} -DETHERNET + -DSPI_HAL -DUSE_HSPI_FOR_EPD -DDEF_ETH_CS_PIN=42 -DDEF_ETH_SCK_PIN=39 @@ -184,13 +185,22 @@ build_flags = ${env.build_flags} -DDEF_LED1=17 -DLED_ACTIVE_HIGH -DARDUINO_USB_MODE=1 - #-DARDUINO_USB_CDC_ON_BOOT=1 + -DARDUINO_USB_CDC_ON_BOOT=1 monitor_filters = esp32_exception_decoder, colorize [env:opendtufusion-dev] platform = espressif32@6.4.0 board = esp32-s3-devkitc-1 +lib_deps = + https://github.com/yubox-node-org/ESPAsyncWebServer + https://github.com/nrf24/RF24 @ ^1.4.8 + paulstoffregen/Time @ ^1.6.1 + https://github.com/bertmelis/espMqttClient#v1.5.0 + bblanchon/ArduinoJson @ ^6.21.3 + https://github.com/JChristensen/Timezone @ ^1.2.4 + olikraus/U8g2 @ ^2.35.7 + https://github.com/zinggjm/GxEPD2 @ ^1.5.2 upload_protocol = esp-builtin build_flags = ${env.build_flags} -DDEF_NRF_CS_PIN=37 @@ -209,5 +219,6 @@ build_flags = ${env.build_flags} -DLED_ACTIVE_HIGH -DARDUINO_USB_MODE=1 -DARDUINO_USB_CDC_ON_BOOT=1 + -DSPI_HAL monitor_filters = esp32_exception_decoder, colorize From 78b603e37331b0ba6c8632fb9ce5d0f4ed6fd398 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 16 Dec 2023 03:13:01 +0100 Subject: [PATCH 232/267] 0.8.24 * remove debug flag for fusion eth --- src/platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platformio.ini b/src/platformio.ini index 43fd7ddd..54b63a22 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -185,7 +185,7 @@ build_flags = ${env.build_flags} -DDEF_LED1=17 -DLED_ACTIVE_HIGH -DARDUINO_USB_MODE=1 - -DARDUINO_USB_CDC_ON_BOOT=1 + #-DARDUINO_USB_CDC_ON_BOOT=1 monitor_filters = esp32_exception_decoder, colorize From d62b53019ae0629f58bbad531cba4a26a0fb7394 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 17 Dec 2023 01:01:20 +0100 Subject: [PATCH 233/267] 0.8.25 * RX channel ID starts with fixed value #1277 * fix static IP for Ethernet --- src/CHANGES.md | 4 ++++ src/app.cpp | 5 ----- src/eth/ahoyeth.cpp | 16 +++++++--------- src/hm/hmRadio.h | 2 +- src/platformio.ini | 2 +- 5 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 6364a7e7..a4805fd8 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,9 @@ # Development Changes +## 0.8.25 - 2023-12-17 +* RX channel ID starts with fixed value #1277 +* fix static IP for Ethernet + ## 0.8.24 - 2023-12-16 * fix NRF communication for opendtufusion ethernet variant diff --git a/src/app.cpp b/src/app.cpp index d670c696..05ca5563 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -40,11 +40,7 @@ void app::setup() { #endif #ifdef ETHERNET delay(1000); - DPRINT(DBG_INFO, F("mEth setup...")); - DSERIAL.flush(); mEth.setup(mConfig, &mTimestamp, [this](bool gotIp) { this->onNetwork(gotIp); }, [this](bool gotTime) { this->onNtpUpdate(gotTime); }); - DBGPRINTLN(F("done...")); - DSERIAL.flush(); #endif // ETHERNET #if !defined(ETHERNET) @@ -149,7 +145,6 @@ void app::regularTickers(void) { #if !defined(ETHERNET) //everySec([this]() { mImprov.tickSerial(); }, "impro"); #endif - // every([this]() { mPayload.simulation();}, 15, "simul"); } #if defined(ETHERNET) diff --git a/src/eth/ahoyeth.cpp b/src/eth/ahoyeth.cpp index be114cf1..2226fce6 100644 --- a/src/eth/ahoyeth.cpp +++ b/src/eth/ahoyeth.cpp @@ -26,12 +26,16 @@ void ahoyeth::setup(settings_t *config, uint32_t *utcTimestamp, OnNetworkCB onNe mOnNetworkCB = onNetworkCB; mOnTimeCB = onTimeCB; - DPRINTLN(DBG_INFO, F("[ETH]: Register for events...")); Serial.flush(); WiFi.onEvent([this](WiFiEvent_t event, arduino_event_info_t info) -> void { this->onEthernetEvent(event, info); }); - DPRINTLN(DBG_INFO, F("[ETH]: begin...")); Serial.flush(); + #if defined(CONFIG_IDF_TARGET_ESP32S3) + mEthSpi.begin(DEF_ETH_MISO_PIN, DEF_ETH_MOSI_PIN, DEF_ETH_SCK_PIN, DEF_ETH_CS_PIN, DEF_ETH_IRQ_PIN, DEF_ETH_RST_PIN); + #else + ETH.begin(DEF_ETH_MISO_PIN, DEF_ETH_MOSI_PIN, DEF_ETH_SCK_PIN, DEF_ETH_CS_PIN, DEF_ETH_IRQ_PIN, ETH_SPI_CLOCK_MHZ, ETH_SPI_HOST); + #endif + if(mConfig->sys.ip.ip[0] != 0) { IPAddress ip(mConfig->sys.ip.ip); IPAddress mask(mConfig->sys.ip.mask); @@ -41,11 +45,6 @@ void ahoyeth::setup(settings_t *config, uint32_t *utcTimestamp, OnNetworkCB onNe if(!ETH.config(ip, gateway, mask, dns1, dns2)) DPRINTLN(DBG_ERROR, F("failed to set static IP!")); } - #if defined(CONFIG_IDF_TARGET_ESP32S3) - mEthSpi.begin(DEF_ETH_MISO_PIN, DEF_ETH_MOSI_PIN, DEF_ETH_SCK_PIN, DEF_ETH_CS_PIN, DEF_ETH_IRQ_PIN, DEF_ETH_RST_PIN); - #else - ETH.begin(DEF_ETH_MISO_PIN, DEF_ETH_MOSI_PIN, DEF_ETH_SCK_PIN, DEF_ETH_CS_PIN, DEF_ETH_IRQ_PIN, ETH_SPI_CLOCK_MHZ, ETH_SPI_HOST); - #endif } @@ -130,8 +129,7 @@ void ahoyeth::welcome(String ip, String mode) { DBGPRINTLN(F("--------------------------------\n")); } -void ahoyeth::onEthernetEvent(WiFiEvent_t event, arduino_event_info_t info) -{ +void ahoyeth::onEthernetEvent(WiFiEvent_t event, arduino_event_info_t info) { AWS_LOG(F("[ETH]: Got event...")); switch (event) { #if ( ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 2) ) && ( ARDUINO_ESP32_GIT_VER != 0x46d5afb1 ) ) diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index d0387aa4..4fe3ea58 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -138,7 +138,7 @@ class HmRadio : public Radio { startMicros = micros(); } // not finished but time is over - mRxChIdx = (mRxChIdx + 1) % RF_CHANNELS; + mRxChIdx = 1; return; } diff --git a/src/platformio.ini b/src/platformio.ini index 54b63a22..43fd7ddd 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -185,7 +185,7 @@ build_flags = ${env.build_flags} -DDEF_LED1=17 -DLED_ACTIVE_HIGH -DARDUINO_USB_MODE=1 - #-DARDUINO_USB_CDC_ON_BOOT=1 + -DARDUINO_USB_CDC_ON_BOOT=1 monitor_filters = esp32_exception_decoder, colorize From d7f7cfb7ceb200156464be5352036f930e8dbc25 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 17 Dec 2023 01:01:53 +0100 Subject: [PATCH 234/267] 0.8.25 updated version number --- src/defines.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/defines.h b/src/defines.h index 71bfc1fa..b8bb8c64 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 24 +#define VERSION_PATCH 25 //------------------------------------- typedef struct { From 681c58e6a2214d3d6b093782db69a1d56c365d14 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 17 Dec 2023 01:30:39 +0100 Subject: [PATCH 235/267] 0.8.25 fix platformio.ini --- src/platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platformio.ini b/src/platformio.ini index 43fd7ddd..54b63a22 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -185,7 +185,7 @@ build_flags = ${env.build_flags} -DDEF_LED1=17 -DLED_ACTIVE_HIGH -DARDUINO_USB_MODE=1 - -DARDUINO_USB_CDC_ON_BOOT=1 + #-DARDUINO_USB_CDC_ON_BOOT=1 monitor_filters = esp32_exception_decoder, colorize From 16d0eb204842941a65e38e015a5f5c668a4037f4 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 17 Dec 2023 15:04:09 +0100 Subject: [PATCH 236/267] 0.8.26 * read grid profile as HEX (`live` -> click inverter name -> `show grid profile`) --- src/CHANGES.md | 3 +++ src/app.cpp | 2 +- src/config/settings.h | 12 ++++++++++-- src/defines.h | 2 +- src/hm/Communication.h | 8 +++++++- src/hm/hmInverter.h | 23 ++++++++++++++++++++++- src/web/RestApi.h | 14 ++++++++++++++ src/web/html/setup.html | 5 +++++ src/web/html/visualization.html | 10 +++++++++- src/web/web.h | 1 + 10 files changed, 73 insertions(+), 7 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index a4805fd8..d57c90d6 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.8.26 - 2023-12-17 +* read grid profile as HEX (`live` -> click inverter name -> `show grid profile`) + ## 0.8.25 - 2023-12-17 * RX channel ID starts with fixed value #1277 * fix static IP for Ethernet diff --git a/src/app.cpp b/src/app.cpp index 05ca5563..5a183cf4 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -336,7 +336,7 @@ void app::tickSend(void) { DBGPRINT(String(fill)); DBGPRINT(F(" of ")); DBGPRINT(String(max)); - DBGPRINTLN(F("entries used")); + DBGPRINTLN(F(" entries used")); } for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { diff --git a/src/config/settings.h b/src/config/settings.h index 31b5cab4..8acb0942 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -30,7 +30,7 @@ * https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html#flash-layout * */ -#define CONFIG_VERSION 5 +#define CONFIG_VERSION 6 #define PROT_MASK_INDEX 0x0001 @@ -157,6 +157,7 @@ typedef struct { bool startWithoutTime; float yieldEffiency; uint16_t gapMs; + bool readGrid; } cfgInst_t; typedef struct { @@ -440,6 +441,7 @@ class settings { mCfg.inst.rstMaxValsMidNight = false; mCfg.inst.yieldEffiency = 1.0f; mCfg.inst.gapMs = 2000; + mCfg.inst.readGrid = true; for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { mCfg.inst.iv[i].powerLevel = 0xff; // impossible high value @@ -481,12 +483,16 @@ class settings { mCfg.serial.printWholeTrace = false; } if(mCfg.configVersion < 4) { - mCfg.inst.gapMs = 2000; + mCfg.inst.gapMs = 500; } if(mCfg.configVersion < 5) { mCfg.inst.sendInterval = SEND_INTERVAL; mCfg.serial.printWholeTrace = false; } + if(mCfg.configVersion < 6) { + mCfg.inst.gapMs = 500; + mCfg.inst.readGrid = true; + } } } @@ -718,6 +724,7 @@ class settings { obj[F("rstMaxMidNight")] = (bool)mCfg.inst.rstMaxValsMidNight; obj[F("yldEff")] = mCfg.inst.yieldEffiency; obj[F("gap")] = mCfg.inst.gapMs; + obj[F("rdGrid")] = (bool)mCfg.inst.readGrid; } else { getVal(obj, F("intvl"), &mCfg.inst.sendInterval); @@ -729,6 +736,7 @@ class settings { getVal(obj, F("rstMaxMidNight"), &mCfg.inst.rstMaxValsMidNight); getVal(obj, F("yldEff"), &mCfg.inst.yieldEffiency); getVal(obj, F("gap"), &mCfg.inst.gapMs); + getVal(obj, F("rdGrid"), &mCfg.inst.readGrid); if(mCfg.inst.yieldEffiency < 0.5) mCfg.inst.yieldEffiency = 1.0f; diff --git a/src/defines.h b/src/defines.h index b8bb8c64..4d94bc95 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 25 +#define VERSION_PATCH 26 //------------------------------------- typedef struct { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 51db6418..3e95b665 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -254,7 +254,7 @@ class Communication : public CommQueue<> { compilePayload(q); - if(NULL != mCbPayload) + if((NULL != mCbPayload) && (GridOnProFilePara != q->cmd)) (mCbPayload)(q->cmd, q->iv); closeRequest(q, true); @@ -440,9 +440,15 @@ class Communication : public CommQueue<> { } else DBGPRINTLN(F(")")); + if(GridOnProFilePara == q->cmd) { + q->iv->addGridProfile(mPayload, len); + return; + } + record_t<> *rec = q->iv->getRecordStruct(q->cmd); if(NULL == rec) { DPRINTLN(DBG_ERROR, F("record is NULL!")); + closeRequest(q, false); return; } if((rec->pyldLen != len) && (0 != rec->pyldLen)) { diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 3e3e1c08..66496340 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -11,6 +11,8 @@ #define F(sl) (sl) #endif +#define MAX_GRID_LENGTH 150 + #include "hmDefines.h" #include "HeuristicInv.h" #include "../hms/hmsDefines.h" @@ -133,7 +135,7 @@ class Inverter { bool mGotLastMsg; // shows if inverter has already finished transmission cycle Radio *radio; // pointer to associated radio class statistics_t radioStatistics; // information about transmitted, failed, ... packets - HeuristicInv heuristics; + HeuristicInv heuristics; // heuristic information / logic uint8_t curCmtFreq; // current used CMT frequency, used to check if freq. was changed during runtime bool commEnabled; // 'pause night communication' sets this field to false @@ -183,6 +185,8 @@ class Inverter { else if(InitDataState != devControlCmd) { cb(devControlCmd, false); // custom command which was received by API devControlCmd = InitDataState; + } else if((0 == mGridLen) && generalConfig->readGrid) { // read grid profile + cb(GridOnProFilePara, false); } else cb(RealTimeRunData_Debug, false); // get live data } else { @@ -721,6 +725,21 @@ class Inverter { } } + void addGridProfile(uint8_t buf[], uint8_t length) { + mGridLen = (length > MAX_GRID_LENGTH) ? MAX_GRID_LENGTH : length; + std::copy(buf, &buf[mGridLen], mGridProfile); + } + + String getGridProfile(void) { + char buf[MAX_GRID_LENGTH * 3]; + memset(buf, 0, MAX_GRID_LENGTH); + for(uint8_t i = 0; i < mGridLen; i++) { + snprintf(&buf[i*3], 4, "%02X ", mGridProfile[i]); + } + buf[mGridLen*3] = 0; + return String(buf); + } + private: inline void addAlarm(uint16_t code, uint32_t start, uint32_t end) { lastAlarm[alarmNxtWrPos] = alarm_t(code, start, end); @@ -741,6 +760,8 @@ class Inverter { private: float mOffYD[6], mLastYD[6]; bool mDevControlRequest; // true if change needed + uint8_t mGridLen = 0; + uint8_t mGridProfile[MAX_GRID_LENGTH]; }; template diff --git a/src/web/RestApi.h b/src/web/RestApi.h index a60d55b8..e98b00fe 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -109,6 +109,8 @@ class RestApi { getIvStatistis(root, request->url().substring(24).toInt()); else if(path.substring(0, 16) == "inverter/pwrack/") getIvPowerLimitAck(root, request->url().substring(21).toInt()); + else if(path.substring(0, 14) == "inverter/grid/") + getGridProfile(root, request->url().substring(19).toInt()); else getNotFound(root, F("http://") + request->host() + F("/api/")); } @@ -395,6 +397,7 @@ class RestApi { obj[F("rstNotAvail")] = (bool)mConfig->inst.rstValsNotAvail; obj[F("rstComStop")] = (bool)mConfig->inst.rstValsCommStop; obj[F("strtWthtTm")] = (bool)mConfig->inst.startWithoutTime; + obj[F("rdGrid")] = (bool)mConfig->inst.readGrid; obj[F("rstMaxMid")] = (bool)mConfig->inst.rstMaxValsMidNight; obj[F("yldEff")] = mConfig->inst.yieldEffiency; obj[F("gap")] = mConfig->inst.gapMs; @@ -452,6 +455,16 @@ class RestApi { } } + void getGridProfile(JsonObject obj, uint8_t id) { + Inverter<> *iv = mSys->getInverterByPos(id); + if(NULL == iv) { + return; + } + + obj[F("name")] = String(iv->config->name); + obj[F("grid")] = iv->getGridProfile(); + } + void getIvAlarms(JsonObject obj, uint8_t id) { Inverter<> *iv = mSys->getInverterByPos(id); if(NULL == iv) { @@ -484,6 +497,7 @@ class RestApi { record_t<> *rec = iv->getRecordStruct(InverterDevInform_Simple); + obj[F("id")] = id; obj[F("name")] = String(iv->config->name); obj[F("serial")] = String(iv->config->serial.u64, HEX); obj[F("generation")] = iv->ivGen; diff --git a/src/web/html/setup.html b/src/web/html/setup.html index fecebd81..a1e42a5c 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -172,6 +172,10 @@
Start without time sync (useful in AP-Only-Mode)
+
+
Read Grid Profile
+
+
Yield Efficiency (Standard 1.0)
@@ -580,6 +584,7 @@ for(var i of ["Mid", "ComStop", "NotAvail", "MaxMid"]) document.getElementsByName("invRst"+i)[0].checked = obj["rst" + i]; document.getElementsByName("strtWthtTm")[0].checked = obj["strtWthtTm"]; + document.getElementsByName("rdGrid")[0].checked = obj["rdGrid"]; } function parseSys(obj) { diff --git a/src/web/html/visualization.html b/src/web/html/visualization.html index bff8b4e3..faf76432 100644 --- a/src/web/html/visualization.html +++ b/src/web/html/visualization.html @@ -289,12 +289,20 @@ tr("Firmware Version / Build", String(obj.fw_ver) + " (build: " + String(obj.fw_date) + " " + String(obj.fw_time) + ")"), tr("Hardware Version / Build", (obj.hw_ver/100).toFixed(2) + " (build: " + String(obj.prod_cw) + "/" + String(obj.prod_year) + ")"), tr("Hardware Number", obj.part_num.toString(16)), - tr("Bootloader Version", (obj.boot_ver/100).toFixed(2)) + tr("Bootloader Version", (obj.boot_ver/100).toFixed(2)), + tr("Grid Profile", ml("input", {type: "button", value: "show", class: "btn", onclick: function() { + modalClose(); + getAjax("/api/inverter/grid/" + obj.id, showGridProfile); + }}, null)) ]) ]); modal("Info for inverter " + obj.name, ml("div", {}, html)); } + function showGridProfile(obj) { + var html = ml("pre", {}, obj.grid); + modal("Grid Profile for inverter " + obj.name, ml("div", {}, html)); + } function parseIvRadioStats(obj) { diff --git a/src/web/web.h b/src/web/web.h index 9dc7ca8f..b104e9fd 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -501,6 +501,7 @@ class Web { mConfig->inst.rstValsCommStop = (request->arg("invRstComStop") == "on"); mConfig->inst.rstValsNotAvail = (request->arg("invRstNotAvail") == "on"); mConfig->inst.startWithoutTime = (request->arg("strtWthtTm") == "on"); + mConfig->inst.readGrid = (request->arg("rdGrid") == "on"); mConfig->inst.rstMaxValsMidNight = (request->arg("invRstMaxMid") == "on"); mConfig->inst.yieldEffiency = (request->arg("yldEff")).toFloat(); mConfig->inst.gapMs = (request->arg("invGap")).toInt(); From d31f39286ee570b2f373a03934115455dad7b63b Mon Sep 17 00:00:00 2001 From: lumapu Date: Mon, 18 Dec 2023 13:55:49 +0100 Subject: [PATCH 237/267] 0.8.27 * fix set power limit #1276 --- src/CHANGES.md | 3 +++ src/defines.h | 2 +- src/hm/CommQueue.h | 23 +++++++++++------------ src/hm/Communication.h | 22 ++++++++++++---------- src/hm/hmRadio.h | 2 +- 5 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index d57c90d6..95265968 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.8.27 - 2023-12-18 +* fix set power limit #1276 + ## 0.8.26 - 2023-12-17 * read grid profile as HEX (`live` -> click inverter name -> `show grid profile`) diff --git a/src/defines.h b/src/defines.h index 4d94bc95..b6e5b8aa 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 26 +#define VERSION_PATCH 27 //------------------------------------- typedef struct { diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index d1beedfc..37ffda62 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -16,22 +16,22 @@ class CommQueue { public: CommQueue() {} - void addImportant(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) { + void addImportant(Inverter<> *iv, uint8_t cmd) { dec(&mRdPtr); - mQueue[mRdPtr] = queue_s(iv, cmd, delOnPop, true); + mQueue[mRdPtr] = queue_s(iv, cmd, true); } - void add(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) { - mQueue[mWrPtr] = queue_s(iv, cmd, delOnPop, false); + void add(Inverter<> *iv, uint8_t cmd) { + mQueue[mWrPtr] = queue_s(iv, cmd, false); inc(&mWrPtr); } - void chgCmd(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) { - mQueue[mWrPtr] = queue_s(iv, cmd, delOnPop, false); + void chgCmd(Inverter<> *iv, uint8_t cmd) { + mQueue[mWrPtr] = queue_s(iv, cmd, false); } uint8_t getFillState(void) { - DPRINTLN(DBG_INFO, "wr: " + String(mWrPtr) + ", rd: " + String(mRdPtr)); + //DPRINTLN(DBG_INFO, "wr: " + String(mWrPtr) + ", rd: " + String(mRdPtr)); return abs(mRdPtr - mWrPtr); } @@ -45,11 +45,10 @@ class CommQueue { uint8_t cmd; uint8_t attempts; uint32_t ts; - bool delOnPop; bool isDevControl; queue_s() {} - queue_s(Inverter<> *i, uint8_t c, bool d, bool dev) : - iv(i), cmd(c), attempts(5), ts(0), delOnPop(d), isDevControl(dev) {} + queue_s(Inverter<> *i, uint8_t c, bool dev) : + iv(i), cmd(c), attempts(5), ts(0), isDevControl(dev) {} }; protected: @@ -78,8 +77,8 @@ class CommQueue { cb(true, &mQueue[mRdPtr]); } - void cmdDone(bool force = false) { - if(!mQueue[mRdPtr].delOnPop && !force) { + void cmdDone(bool keep = false) { + if(keep) { mQueue[mRdPtr].attempts = 5; add(mQueue[mRdPtr]); // add to the end again } diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 3e95b665..23254922 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -30,9 +30,9 @@ class Communication : public CommQueue<> { mInverterGap = inverterGap; } - void addImportant(Inverter<> *iv, uint8_t cmd, bool delOnPop = true) { + void addImportant(Inverter<> *iv, uint8_t cmd) { mState = States::RESET; // cancel current operation - CommQueue::addImportant(iv, cmd, delOnPop); + CommQueue::addImportant(iv, cmd); } void addPayloadListener(payloadListenerType cb) { @@ -84,7 +84,7 @@ class Communication : public CommQueue<> { q->iv->curFrmCnt = 0; mIsRetransmit = false; if(NULL == q->iv->radio) - cmdDone(true); // can't communicate while radio is not defined! + cmdDone(false); // can't communicate while radio is not defined! mState = States::START; break; @@ -177,6 +177,7 @@ class Communication : public CommQueue<> { closeRequest(q, true); else closeRequest(q, false); + q->iv->radio->mBufCtrl.pop(); return; // don't wait for empty buffer } else if(IV_MI == q->iv->ivGen) { if(parseMiFrame(p, q)) @@ -399,8 +400,6 @@ class Communication : public CommQueue<> { DBGPRINT(F("CRC Error ")); if(q->attempts == 0) { DBGPRINTLN(F("-> Fail")); - /*q->iv->radioStatistics.rxFail++; // got fragments but not complete response - cmdDone();*/ closeRequest(q, false); } else @@ -502,16 +501,19 @@ class Communication : public CommQueue<> { q->iv->radioStatistics.rxSuccess++; else if(q->iv->mGotFragment) q->iv->radioStatistics.rxFail++; // got no complete payload - else { + else q->iv->radioStatistics.rxFailNoAnser++; // got nothing - } mWaitTimeout = millis() + *mInverterGap; - cmdDone(q->delOnPop); + bool keep = false; + if(q->isDevControl) + keep = !crcPass; + + cmdDone(keep); q->iv->mGotFragment = false; q->iv->mGotLastMsg = false; q->iv->miMultiParts = 0; - mIsRetransmit = false; + mIsRetransmit = false; mFirstTry = false; // for correct reset mState = States::RESET; DBGPRINTLN(F("-----")); @@ -836,7 +838,7 @@ class Communication : public CommQueue<> { //closeRequest(iv, iv->miMultiParts > 5); //mHeu.setGotAll(iv); - //cmdDone(true); + //cmdDone(false); if(NULL != mCbPayload) (mCbPayload)(RealTimeRunData_Debug, iv); diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 4fe3ea58..d0387aa4 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -138,7 +138,7 @@ class HmRadio : public Radio { startMicros = micros(); } // not finished but time is over - mRxChIdx = 1; + mRxChIdx = (mRxChIdx + 1) % RF_CHANNELS; return; } From b3ceadadd4a533a95f4a016afe3157d686be8092 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 23 Dec 2023 14:53:47 +0100 Subject: [PATCH 238/267] 0.8.28 * fix bug heuristic * add version information to clipboard once 'copy' was clicked --- src/CHANGES.md | 4 ++++ src/defines.h | 2 +- src/hm/hmRadio.h | 6 +++--- src/web/html/serial.html | 2 ++ 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 95265968..83917be9 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,9 @@ # Development Changes +## 0.8.28 - 2023-12-23 +* fix bug heuristic +* add version information to clipboard once 'copy' was clicked + ## 0.8.27 - 2023-12-18 * fix set power limit #1276 diff --git a/src/defines.h b/src/defines.h index b6e5b8aa..b7ab4e55 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 27 +#define VERSION_PATCH 28 //------------------------------------- typedef struct { diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index d0387aa4..dd83544f 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -290,14 +290,14 @@ class HmRadio : public Radio { updateCrcs(&len, appendCrc16); // set TX and RX channels - mTxChIdx = mRfChLst[iv->heuristics.txRfChId]; + mTxChIdx = iv->heuristics.txRfChId; if(*mSerialDebug) { DPRINT_IVID(DBG_INFO, iv->id); DBGPRINT(F("TX ")); DBGPRINT(String(len)); DBGPRINT(" CH"); - DBGPRINT(String(mTxChIdx)); + DBGPRINT(String(mRfChLst[mTxChIdx])); DBGPRINT(F(" | ")); if(*mPrintWholeTrace) { if(*mPrivacyMode) @@ -309,7 +309,7 @@ class HmRadio : public Radio { } mNrf24->stopListening(); - mNrf24->setChannel(mTxChIdx); + mNrf24->setChannel(mRfChLst[mTxChIdx]); mNrf24->openWritingPipe(reinterpret_cast(&iv->radioId.u64)); mNrf24->startWrite(mTxBuf, len, false); // false = request ACK response mMillis = millis(); diff --git a/src/web/html/serial.html b/src/web/html/serial.html index 675ee668..966ffecd 100644 --- a/src/web/html/serial.html +++ b/src/web/html/serial.html @@ -27,6 +27,7 @@ var mAutoScroll = true; var con = document.getElementById("serial"); var exeOnce = true; + var version, build; function parseGeneric(obj) { var up = obj["ts_uptime"]; @@ -65,6 +66,7 @@ this.value = (mAutoScroll) ? "autoscroll" : "manual scroll"; }); document.getElementById("copy").addEventListener("click", function() { + con.value = version + " - " + build + "\n---------------\n" + con.value; if (window.clipboardData && window.clipboardData.setData) { return window.clipboardData.setData("Text", text); } else if (document.queryCommandSupported && document.queryCommandSupported("copy")) { From 5a52677cbda98775c04ea3abd3a17d4503131609 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 23 Dec 2023 15:57:40 +0100 Subject: [PATCH 239/267] 0.8.28 * add get loss rate @rejoe2 * improve communication @rejoe2 --- src/CHANGES.md | 2 ++ src/hm/CommQueue.h | 4 +-- src/hm/Communication.h | 65 ++++++++++++++++++++++++++++++----- src/hm/hmDefines.h | 2 ++ src/hm/hmInverter.h | 42 ++++++++++++++++++++++ src/hm/hmRadio.h | 17 ++++++--- src/hms/hmsRadio.h | 8 ++++- src/publisher/pubMqttIvData.h | 5 +++ src/web/html/serial.html | 2 ++ 9 files changed, 131 insertions(+), 16 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 83917be9..95fcae66 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -3,6 +3,8 @@ ## 0.8.28 - 2023-12-23 * fix bug heuristic * add version information to clipboard once 'copy' was clicked +* add get loss rate @rejoe2 +* improve communication @rejoe2 ## 0.8.27 - 2023-12-18 * fix set power limit #1276 diff --git a/src/hm/CommQueue.h b/src/hm/CommQueue.h index 37ffda62..bb815a7e 100644 --- a/src/hm/CommQueue.h +++ b/src/hm/CommQueue.h @@ -94,8 +94,8 @@ class CommQueue { mQueue[mRdPtr].attempts--; } - void incrAttempt(void) { - mQueue[mRdPtr].attempts++; + void incrAttempt(uint8_t attempts = 1) { + mQueue[mRdPtr].attempts += attempts; } void inc(uint8_t *ptr) { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 23254922..818b396d 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -14,7 +14,7 @@ #define MI_TIMEOUT 250 // timeout for MI type requests #define FRSTMSG_TIMEOUT 150 // how long to wait for first msg to be received #define DEFAULT_TIMEOUT 500 // timeout for regular requests -#define SINGLEFR_TIMEOUT 65 // timeout for single frame requests +#define SINGLEFR_TIMEOUT 100 // timeout for single frame requests #define MAX_BUFFER 250 typedef std::function *)> payloadListenerType; @@ -59,7 +59,7 @@ class Communication : public CommQueue<> { mLastEmptyQueueMillis = millis(); mPrintSequenceDuration = true; - uint16_t timeout = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment && q->iv->mGotLastMsg) || mIsRetransmit) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT; + uint16_t timeout = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : (((q->iv->mGotFragment && q->iv->mGotLastMsg) || mIsRetransmit) ? SINGLEFR_TIMEOUT : ((q->cmd != AlarmData) ? DEFAULT_TIMEOUT : (1.5 * DEFAULT_TIMEOUT))); uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment || mIsRetransmit)) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT; /*if(mDebugState != mState) { @@ -85,6 +85,8 @@ class Communication : public CommQueue<> { mIsRetransmit = false; if(NULL == q->iv->radio) cmdDone(false); // can't communicate while radio is not defined! + q->iv->mCmd = q->cmd; + q->iv->mIsSingleframeReq = false; mState = States::START; break; @@ -159,8 +161,9 @@ class Communication : public CommQueue<> { closeRequest(q, false); break; } - mIsRetransmit = false; mFirstTry = false; // for correct reset + if((IV_MI != q->iv->ivGen) || (0 == q->attempts)) + mIsRetransmit = false; while(!q->iv->radio->mBufCtrl.empty()) { packet_t *p = &q->iv->radio->mBufCtrl.front(); @@ -168,6 +171,7 @@ class Communication : public CommQueue<> { if(validateIvSerial(&p->packet[1], q->iv)) { q->iv->radioStatistics.frmCnt++; + q->iv->mDtuRxCnt++; if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command if(parseFrame(p)) @@ -197,15 +201,25 @@ class Communication : public CommQueue<> { if(q->iv->ivGen != IV_MI) { mState = States::CHECK_PACKAGE; } else { + bool fastNext = true; if(q->iv->miMultiParts < 6) { mState = States::WAIT; + if((millis() > mWaitTimeout && mIsRetransmit) || !mIsRetransmit) { + miRepeatRequest(q); + return; + } } else { + mHeu.evalTxChQuality(q->iv, true, (4 - q->attempts), q->iv->curFrmCnt); if(((q->cmd == 0x39) && (q->iv->type == INV_TYPE_4CH)) || ((q->cmd == MI_REQ_CH2) && (q->iv->type == INV_TYPE_2CH)) || ((q->cmd == MI_REQ_CH1) && (q->iv->type == INV_TYPE_1CH))) { miComplete(q->iv); + fastNext = false; } - closeRequest(q, true); + if(fastNext) + miNextRequest(q->iv->type == INV_TYPE_4CH ? MI_REQ_4CH : MI_REQ_CH1, q); + else + closeRequest(q, true); } } @@ -247,6 +261,8 @@ class Communication : public CommQueue<> { DBGPRINT(String(q->attempts)); DBGPRINTLN(F(" attempts left)")); } + if (!mIsRetransmit) + q->iv->mIsSingleframeReq = true; sendRetransmit(q, (framnr-1)); mIsRetransmit = true; mlastTO_min = timeout_min; @@ -290,7 +306,9 @@ class Communication : public CommQueue<> { else ah::dumpBuf(p->packet, p->len); } else { - DBGPRINT(F("| ")); + DBGPRINT(F("| 0x")); + DHEX(p->packet[0]); + DBGPRINT(F(" ")); DBGHEXLN(p->packet[9]); } } @@ -331,8 +349,11 @@ class Communication : public CommQueue<> { return false; // CRC8 is wrong, frame invalid } - if((*frameId & ALL_FRAMES) == ALL_FRAMES) + if((*frameId & ALL_FRAMES) == ALL_FRAMES) { mMaxFrameId = (*frameId & 0x7f); + if(mMaxFrameId > 8) // large payloads, e.g. AlarmData + incrAttempt(mMaxFrameId - 6); + } frame_t *f = &mLocalBuf[(*frameId & 0x7f) - 1]; memcpy(f->buf, &p->packet[10], p->len-11); @@ -373,7 +394,7 @@ class Communication : public CommQueue<> { accepted = false; DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F(" has ")); + DBGPRINT(F("has ")); if(!accepted) DBGPRINT(F("not ")); DBGPRINT(F("accepted power limit set point ")); DBGPRINT(String(q->iv->powerLimit[0])); @@ -446,8 +467,14 @@ class Communication : public CommQueue<> { record_t<> *rec = q->iv->getRecordStruct(q->cmd); if(NULL == rec) { - DPRINTLN(DBG_ERROR, F("record is NULL!")); - closeRequest(q, false); + if(GetLossRate == q->cmd) { + q->iv->parseGetLossRate(mPayload, len); + //closeRequest(q, true); //@lumapu: Activating would crash most esp's! + return; + } else { + DPRINTLN(DBG_ERROR, F("record is NULL!")); + closeRequest(q, false); + } return; } if((rec->pyldLen != len) && (0 != rec->pyldLen)) { @@ -688,6 +715,7 @@ class Communication : public CommQueue<> { miStsConsolidate(q, datachan, rec, p->packet[23], p->packet[24]); if (p->packet[0] < (0x39 + ALL_FRAMES) ) { + mHeu.evalTxChQuality(q->iv, true, (4 - q->attempts), 1); miNextRequest((p->packet[0] - ALL_FRAMES + 1), q); } else { q->iv->miMultiParts = 7; // indicate we are ready @@ -696,6 +724,7 @@ class Communication : public CommQueue<> { } else if((p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES)) && (q->iv->type == INV_TYPE_2CH)) { //addImportant(q->iv, MI_REQ_CH2); miNextRequest(MI_REQ_CH2, q); + mHeu.evalTxChQuality(q->iv, true, (4 - q->attempts), q->iv->curFrmCnt); //use also miMultiParts here for better statistics? //mHeu.setGotFragment(q->iv); } else { // first data msg for 1ch, 2nd for 2ch @@ -732,6 +761,24 @@ class Communication : public CommQueue<> { //mState = States::WAIT; } + void miRepeatRequest(const queue_s *q) { + setAttempt(); // if function is called, we got something, and we necessarily need more transmissions for MI types... + if(*mSerialDebug) { + DPRINT_IVID(DBG_WARN, q->iv->id); + DBGPRINT(F("resend request (")); + DBGPRINT(String(q->attempts)); + DBGPRINT(F(" attempts left): 0x")); + DBGHEXLN(q->cmd); + } + + q->iv->radio->sendCmdPacket(q->iv, q->cmd, 0x00, true); + + mWaitTimeout = millis() + MI_TIMEOUT; + mWaitTimeout_min = mWaitTimeout; + //mState = States::WAIT; + mIsRetransmit = false; + } + void miStsConsolidate(const queue_s *q, 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 statusMi = 3; // regular status for MI, change to 1 later? diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index c00f4940..55259289 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -139,6 +139,8 @@ const byteAssign_t AlarmDataAssignment[] = { #define HMALARMDATA_PAYLOAD_LEN 0 // 0: means check is off #define ALARM_LOG_ENTRY_SIZE 12 +#define HMGETLOSSRATE_PAYLOAD_LEN 4 +#define AHOY_GET_LOSS_INTERVAL 10 //------------------------------------- // HM300, HM350, HM400 diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 66496340..2ae60e10 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -133,12 +133,20 @@ class Inverter { bool mGotFragment; // shows if inverter has sent at least one fragment uint8_t curFrmCnt; // count received frames in current loop bool mGotLastMsg; // shows if inverter has already finished transmission cycle + uint8_t mCmd; // holds the command to send + bool mIsSingleframeReq; // indicates this is a missing single frame request Radio *radio; // pointer to associated radio class statistics_t radioStatistics; // information about transmitted, failed, ... packets HeuristicInv heuristics; // heuristic information / logic uint8_t curCmtFreq; // current used CMT frequency, used to check if freq. was changed during runtime bool commEnabled; // 'pause night communication' sets this field to false + uint16_t mIvRxCnt; // last iv rx frames (from GetLossRate) + uint16_t mIvTxCnt; // last iv tx frames (from GetLossRate) + uint16_t mDtuRxCnt; // cur dtu rx frames (since last GetLossRate) + uint16_t mDtuTxCnt; // cur dtu tx frames (since last getLoassRate) + uint8_t mGetLossInterval; // request iv every AHOY_GET_LOSS_INTERVAL RealTimeRunData_Debu + static uint32_t *timestamp; // system timestamp static cfgInst_t *generalConfig; // general inverter configuration from setup @@ -159,8 +167,14 @@ class Inverter { rssi = -127; miMultiParts = 0; mGotLastMsg = false; + mCmd = InitDataState; + mIsSingleframeReq = false; radio = NULL; commEnabled = true; + mIvRxCnt = 0; + mIvTxCnt = 0; + mDtuRxCnt = 0; + mDtuTxCnt = 0; memset(&radioStatistics, 0, sizeof(statistics_t)); memset(heuristics.txRfQuality, -6, 5); @@ -174,6 +188,7 @@ class Inverter { cb(devControlCmd, true); mDevControlRequest = false; } else if (IV_MI != ivGen) { + mGetLossInterval++; if((alarmLastId != alarmMesIndex) && (alarmMesIndex != 0)) cb(AlarmData, false); // get last alarms else if(0 == getFwVersion()) @@ -185,8 +200,12 @@ class Inverter { else if(InitDataState != devControlCmd) { cb(devControlCmd, false); // custom command which was received by API devControlCmd = InitDataState; + mGetLossInterval = 1; } else if((0 == mGridLen) && generalConfig->readGrid) { // read grid profile cb(GridOnProFilePara, false); + } else if (mGetLossInterval > AHOY_GET_LOSS_INTERVAL) { // get loss rate + mGetLossInterval = 1; + cb(GetLossRate, false); } else cb(RealTimeRunData_Debug, false); // get live data } else { @@ -574,6 +593,29 @@ class Inverter { memset(mLastYD, 0, sizeof(float) * 6); } + bool parseGetLossRate(uint8_t pyld[], uint8_t len) { + if (len == HMGETLOSSRATE_PAYLOAD_LEN) { + uint16_t rxCnt = (pyld[0] << 8) + pyld[1]; + uint16_t txCnt = (pyld[2] << 8) + pyld[3]; + + if (mIvRxCnt || mIvTxCnt) { // there was successful GetLossRate in the past + DPRINT_IVID(DBG_INFO, id); + DBGPRINTLN("Inv loss: " + + String (mDtuTxCnt - (rxCnt - mIvRxCnt)) + " of " + + String (mDtuTxCnt) + ", DTU loss: " + + String (txCnt - mIvTxCnt - mDtuRxCnt) + " of " + + String (txCnt - mIvTxCnt)); + } + + mIvRxCnt = rxCnt; + mIvTxCnt = txCnt; + mDtuRxCnt = 0; // start new interval + mDtuTxCnt = 0; // start new interval + return true; + } + return false; + } + uint16_t parseAlarmLog(uint8_t id, uint8_t pyld[], uint8_t len) { uint8_t startOff = 2 + id * ALARM_LOG_ENTRY_SIZE; if((startOff + ALARM_LOG_ENTRY_SIZE) > len) diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index dd83544f..6db39d7f 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -119,9 +119,11 @@ class HmRadio : public Radio { if(NULL == mLastIv) // prevent reading on NULL object! return; - uint32_t startMicros = micros(); - uint32_t loopMillis = millis(); - while ((millis() - loopMillis) < 400) { + uint32_t startMicros = micros(); + uint32_t loopMillis = millis(); + uint32_t outerLoopTimeout = (mLastIv->mIsSingleframeReq) ? 100 : ((mLastIv->mCmd != AlarmData) ? 400 : 600); + + while ((millis() - loopMillis) < outerLoopTimeout) { while ((micros() - startMicros) < 5110) { // listen (4088us or?) 5110us to each channel if (mIrqRcvd) { mIrqRcvd = false; @@ -304,8 +306,14 @@ class HmRadio : public Radio { ah::dumpBuf(mTxBuf, len, 1, 4); else ah::dumpBuf(mTxBuf, len); - } else + } else { + DBGPRINT(F("0x")); + DHEX(mTxBuf[0]); + DBGPRINT(F(" 0x")); + DHEX(mTxBuf[10]); + DBGPRINT(F(" ")); DBGHEXLN(mTxBuf[9]); + } } mNrf24->stopListening(); @@ -315,6 +323,7 @@ class HmRadio : public Radio { mMillis = millis(); mLastIv = iv; + iv->mDtuTxCnt++; } uint64_t getIvId(Inverter<> *iv) { diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index 40200085..80a2ecd9 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -95,8 +95,13 @@ class CmtRadio : public Radio { ah::dumpBuf(mTxBuf, len, 1, 4); else ah::dumpBuf(mTxBuf, len); - } else + } else { + DBGPRINT(F("0x")); + DHEX(mTxBuf[0]); + DBGPRINT(F(" 0x")); + DHEX(mTxBuf[10]); DBGHEXLN(mTxBuf[9]); + } } uint8_t status = mCmt.tx(mTxBuf, len); @@ -107,6 +112,7 @@ class CmtRadio : public Radio { if(CMT_ERR_RX_IN_FIFO == status) mIrqRcvd = true; } + iv->mDtuTxCnt++; } uint64_t getIvId(Inverter<> *iv) { diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h index 0ac6d306..3600e22c 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -127,6 +127,11 @@ class PubMqttIvData { void stateSend() { record_t<> *rec = mIv->getRecordStruct(mCmd); + if(rec == NULL) { + if (mCmd != GetLossRate) + DPRINT(DBG_WARN, "unknown record to publish!"); + return; + } uint32_t lastTs = mIv->getLastTs(rec); bool pubData = (lastTs > 0); if (mCmd == RealTimeRunData_Debug) diff --git a/src/web/html/serial.html b/src/web/html/serial.html index 966ffecd..ef7aa4c3 100644 --- a/src/web/html/serial.html +++ b/src/web/html/serial.html @@ -48,6 +48,8 @@ exeOnce = false; setTimeOffset(); } + version = obj.version; + build = obj.build; } function setTimeOffset() { From 8b379f768e281030545e9796da0f80d1dde7af42 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 23 Dec 2023 16:47:07 +0100 Subject: [PATCH 240/267] 0.8.29 * fix MqTT generic topic `comm_disabled` #1265 #1286 * potential fix of #1285 (reset yield day) * fix fraction of yield correction #1280 --- src/CHANGES.md | 5 +++++ src/app.cpp | 2 +- src/defines.h | 2 +- src/hm/hmInverter.h | 5 +++++ src/publisher/pubMqtt.h | 14 +++++++++----- src/publisher/pubMqttIvData.h | 2 +- src/web/RestApi.h | 2 +- src/web/html/setup.html | 2 +- 8 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 95fcae66..e9563510 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,10 @@ # Development Changes +## 0.8.29 - 2023-12-23 +* fix MqTT generic topic `comm_disabled` #1265 #1286 +* potential fix of #1285 (reset yield day) +* fix fraction of yield correction #1280 + ## 0.8.28 - 2023-12-23 * fix bug heuristic * add version information to clipboard once 'copy' was clicked diff --git a/src/app.cpp b/src/app.cpp index 5a183cf4..88065e20 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -305,7 +305,7 @@ void app::tickMidnight(void) { continue; // skip to next inverter // reset alarms - if(InverterStatus::OFF == iv->status) + if(InverterStatus::OFF == iv->getStatus()) iv->resetAlarms(); // clear max values diff --git a/src/defines.h b/src/defines.h index b7ab4e55..2b304f9f 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 28 +#define VERSION_PATCH 29 //------------------------------------- typedef struct { diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 2ae60e10..776b9c6f 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -458,6 +458,11 @@ class Inverter { return producing; } + InverterStatus getStatus(){ + isProducing(); // recalculate status + return status; + } + uint16_t getFwVersion() { record_t<> *rec = getRecordStruct(InverterDevInform_All); return getChannelFieldValue(CH0, FLD_FW_VERSION, rec); diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 92f5de2f..e062439c 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -153,6 +153,10 @@ class PubMqtt { publish(mSubTopic, ((iv->commEnabled) ? dict[STR_TRUE] : dict[STR_FALSE]), true); } + + snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "comm_disabled"); + publish(mSubTopic, (((*mUtcTimestamp > (sunset + offs)) || (*mUtcTimestamp < (sunrise - offs))) ? dict[STR_TRUE] : dict[STR_FALSE]), true); + return true; } @@ -483,22 +487,22 @@ class PubMqtt { continue; // skip to next inverter // inverter status - iv->isProducing(); // recalculate status - if (InverterStatus::OFF < iv->status) + InverterStatus status = iv->getStatus(); + if (InverterStatus::OFF < status) anyAvail = true; else // inverter is enabled but not available allAvail = false; - if(mLastIvState[id] != iv->status) { + if(mLastIvState[id] != status) { // if status changed from producing to not producing send last data immediately if (InverterStatus::WAS_PRODUCING == mLastIvState[id]) sendData(iv, RealTimeRunData_Debug); - mLastIvState[id] = iv->status; + mLastIvState[id] = status; changed = true; snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/available", iv->config->name); - snprintf(mVal, 40, "%d", (uint8_t)iv->status); + snprintf(mVal, 40, "%d", (uint8_t)status); publish(mSubTopic, mVal, true); } } diff --git a/src/publisher/pubMqttIvData.h b/src/publisher/pubMqttIvData.h index 3600e22c..9a364ec9 100644 --- a/src/publisher/pubMqttIvData.h +++ b/src/publisher/pubMqttIvData.h @@ -146,7 +146,7 @@ class PubMqttIvData { // calculate total values for RealTimeRunData_Debug if (CH0 == rec->assign[mPos].ch) { - if(mIv->status > InverterStatus::STARTING) { + if(mIv->getStatus() > InverterStatus::STARTING) { if(mIv->config->add2Total) { mTotalFound = true; switch (rec->assign[mPos].fieldId) { diff --git a/src/web/RestApi.h b/src/web/RestApi.h index e98b00fe..990f3e92 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -421,7 +421,7 @@ class RestApi { obj[F("max_pwr")] = iv->getMaxPower(); obj[F("ts_last_success")] = rec->ts; obj[F("generation")] = iv->ivGen; - obj[F("status")] = (uint8_t)iv->status; + obj[F("status")] = (uint8_t)iv->getStatus(); obj[F("alarm_cnt")] = iv->alarmCnt; obj[F("rssi")] = iv->rssi; diff --git a/src/web/html/setup.html b/src/web/html/setup.html index a1e42a5c..8187fe3b 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -676,7 +676,7 @@ ml("td", {}, String(i+1)), ml("td", {}, ml("input", {name: "ch_p"+i, class: "text", type: "number", max: 999, value: obj.ch_max_pwr[i]}, null)), ml("td", {}, ml("input", {name: "ch_n"+i, class: "text", type: "text", maxlength: 15, value: (undefined === obj.ch_name[i]) ? "" : obj.ch_name[i]}, null)), - ml("td", {}, ml("input", {name: "yld_c"+i, class: "text", type: "number", max: 999999, value: obj.ch_yield_cor[i]}, null)) + ml("td", {}, ml("input", {name: "yld_c"+i, class: "text", type: "number", max: 999999, value: obj.ch_yield_cor[i], step: "0.001"}, null)) ])); } From e5176b7430ab131cca5dd0800820d103dc99d049 Mon Sep 17 00:00:00 2001 From: kscholty Date: Sat, 23 Dec 2023 17:33:00 +0100 Subject: [PATCH 241/267] Added ESP32-C3 chip --- src/platformio.ini | 15 ++++++++++++ src/web/html/setup.html | 53 +++++++++++++++++++++++++++++++++++++---- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/src/platformio.ini b/src/platformio.ini index 54b63a22..2b4b25cf 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -123,6 +123,21 @@ build_flags = ${env.build_flags} monitor_filters = esp32_exception_decoder +[env:esp32-c3-mini] +platform = espressif32@6.4.0 +board = lolin_c3_mini +build_flags = ${env.build_flags} + -DUSE_HSPI_FOR_EPD + -DDEF_NRF_CS_PIN=5 + -DDEF_NRF_CE_PIN=0 + -DDEF_NRF_IRQ_PIN=1 + -DDEF_NRF_MISO_PIN=3 + -DDEF_NRF_MOSI_PIN=4 + -DDEF_NRF_SCLK_PIN=2 +monitor_filters = + esp32_exception_decoder + + [env:opendtufusion] platform = espressif32@6.4.0 board = esp32-s3-devkitc-1 diff --git a/src/web/html/setup.html b/src/web/html/setup.html index a1e42a5c..638ef8e0 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -435,6 +435,31 @@ [47, "GPIO47"], [48, "GPIO48"], ]; + var esp32c3pins = [ + [255, "off / default"], + [0, "GPIO0"], + [1, "GPIO1"], + [2, "GPIO2"], + [3, "GPIO3"], + [4, "GPIO4"], + [5, "GPIO5"], + [6, "GPIO6"], + [7, "GPIO7"], + [8, "GPIO8"], + [9, "GPIO9"], + [10, "GPIO10"], + [11, "GPIO11"], + [12, "GPIO12 (PSRAM/FLASH)"], + [13, "GPIO13 (PSRAM/FLASH)"], + [14, "GPIO14 (PSRAM/FLASH)"], + [15, "GPIO15 (PSRAM/FLASH)"], + [16, "GPIO16 (PSRAM/FLASH)"], + [17, "GPIO17 (PSRAM/FLASH)"], + [18, "GPIO18 (DONT USE - USB-)"], + [19, "GPIO19 (DONT USE - USB+)"], + [20, "GPIO20 (RX)"], + [21, "GPIO21 (TX)"], + ]; /*ENDIF_ESP32*/ var nrfPa = [ [0, "MIN (recommended)"], @@ -872,13 +897,17 @@ function parsePinout(obj, type, system) { var e = document.getElementById("pinout"); + var pinList = esp32pins; + if("ESP8266" == type) pinList = esp8266pins; + else if ("ESP32-S3" == system["chip_model"]) pinList = esp32s3pins; + else if("ESP32-C3" == system["chip_model"]) pinList = esp32c3pins; pins = [['led0', 'pinLed0', 'At least one inverter is producing'], ['led1', 'pinLed1', 'MqTT connected']]; for(p of pins) { e.append( ml("div", {class: "row mb-3"}, [ ml("div", {class: "col-12 col-sm-3 my-2"}, p[2]), ml("div", {class: "col-12 col-sm-9"}, - sel(p[1], ("ESP8266" == type) ? esp8266pins : ("ESP32-S3" == system["chip_model"]) ? esp32s3pins : esp32pins, obj[p[0]]) + sel(p[1], pinList, obj[p[0]]) ) ]) ); @@ -898,6 +927,11 @@ var en = inp("nrfEnable", null, null, ["cb"], "nrfEnable", "checkbox"); en.checked = obj["en"]; + var pinList = esp32pins; + if("ESP8266" == type) pinList = esp8266pins; + else if ("ESP32-S3" == system["chip_model"]) pinList = esp32s3pins; + else if("ESP32-C3" == system["chip_model"]) pinList = esp32c3pins; + e.replaceChildren ( ml("div", {class: "row mb-3"}, [ ml("div", {class: "col-8 col-sm-3 my-2"}, "NRF24 Enable"), @@ -915,7 +949,7 @@ ml("div", {class: "row mb-3"}, [ 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 : ("ESP32-S3" == system["chip_model"]) ? esp32s3pins : esp32pins, objPin[p[0]]) + sel(p[1], pinList, objPin[p[0]]) ) ]) ); @@ -926,6 +960,10 @@ function parseCmtRadio(obj, type, system) { var e = document.getElementById("cmt"); var en = inp("cmtEnable", null, null, ["cb"], "cmtEnable", "checkbox"); + var pinList = esp32pins; + if ("ESP32-S3" == system["chip_model"]) pinList = esp32s3pins; + else if("ESP32-C3" == system["chip_model"]) pinList = esp32c3pins; + en.checked = obj["en"]; e.replaceChildren ( @@ -940,7 +978,7 @@ ml("div", {class: "row mb-3"}, [ ml("div", {class: "col-12 col-sm-3 my-2"}, p[0].toUpperCase()), ml("div", {class: "col-12 col-sm-9"}, - sel(p[1], (("ESP32-S3" == system["chip_model"]) ? esp32s3pins : esp32pins), obj[p[0]]) + sel(p[1], pinList, obj[p[0]]) ) ]) ); @@ -954,6 +992,11 @@ } function parseDisplay(obj, type, system) { + var pinList = esp32pins; + if("ESP8266" == type) pinList = esp8266pirpins; + else if ("ESP32-S3" == system["chip_model"]) pinList = esp32s3pins; + else if("ESP32-C3" == system["chip_model"]) pinList = esp32c3pins; + for(var i of ["disp_pwr"]) document.getElementsByName(i)[0].checked = obj[i]; @@ -968,7 +1011,7 @@ 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 : ("ESP32-S3" == system["chip_model"]) ? esp32s3pins : esp32pins, obj[p[1]]) + sel(p[1], pinList, obj[p[1]]) ) ]) ); @@ -1018,7 +1061,7 @@ document.getElementById("pirPin").append( ml("div", {class: "row mb-3"}, [ ml("div", {class: "col-12 col-sm-3 my-2"}, "PIR sensor"), - ml("div", {class: "col-12 col-sm-9"}, sel("pir_pin", ("ESP8266" == type) ? esp8266pirpins : ("ESP32-S3" == system["chip_model"]) ? esp32s3pins : esp32pins, obj["pir_pin"])) + ml("div", {class: "col-12 col-sm-9"}, sel("pir_pin", pinList, obj["pir_pin"])) ]) ); From 28fd60f89630fb7d3367a6174a4e52f864dc2c7b Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Sun, 24 Dec 2023 15:26:47 +0100 Subject: [PATCH 242/267] Fix https://github.com/lumapu/ahoy/issues/1288 #1288 --- src/hm/Communication.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 818b396d..07da4311 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -271,7 +271,7 @@ class Communication : public CommQueue<> { compilePayload(q); - if((NULL != mCbPayload) && (GridOnProFilePara != q->cmd)) + if((NULL != mCbPayload) && (GridOnProFilePara != q->cmd) && (GetLossRate != q->cmd)) (mCbPayload)(q->cmd, q->iv); closeRequest(q, true); From 4f75ce7dd1ab528018644d285bf6571c1d543e3c Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 28 Dec 2023 02:21:37 +0100 Subject: [PATCH 243/267] 0.8.29 * fix crash if `getLossRate` was read from inverter #1288 #1290 * reduce reload time for opendtufusion ethernet variant to 5 seconds * added basic grid parser --- scripts/convertHtml.py | 2 +- src/CHANGES.md | 5 +- src/hm/Communication.h | 29 +- src/hm/hmRadio.h | 7 +- src/hms/hmsRadio.h | 5 +- src/web/RestApi.h | 11 +- src/web/html/api.js | 8 + src/web/html/grid_info.json | 764 ++++++++++++++++++++++++++++++++ src/web/html/save.html | 4 +- src/web/html/visualization.html | 75 +++- src/web/web.h | 12 + 11 files changed, 876 insertions(+), 46 deletions(-) create mode 100644 src/web/html/grid_info.json diff --git a/scripts/convertHtml.py b/scripts/convertHtml.py index 70d5f6e2..6eaa92a3 100644 --- a/scripts/convertHtml.py +++ b/scripts/convertHtml.py @@ -159,7 +159,7 @@ if os.path.exists(wd): # grab all files with following extensions os.chdir('./web/html') -types = ('*.html', '*.css', '*.js', '*.ico') # the tuple of file types +types = ('*.html', '*.css', '*.js', '*.ico', '*.json') # the tuple of file types files_grabbed = [] for files in types: files_grabbed.extend(glob.glob(files)) diff --git a/src/CHANGES.md b/src/CHANGES.md index e9563510..99b7dc64 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,9 +1,12 @@ # Development Changes -## 0.8.29 - 2023-12-23 +## 0.8.29 - 2023-12-27 * fix MqTT generic topic `comm_disabled` #1265 #1286 * potential fix of #1285 (reset yield day) * fix fraction of yield correction #1280 +* fix crash if `getLossRate` was read from inverter #1288 #1290 +* reduce reload time for opendtufusion ethernet variant to 5 seconds +* added basic grid parser ## 0.8.28 - 2023-12-23 * fix bug heuristic diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 818b396d..23d20004 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -117,28 +117,6 @@ class Communication : public CommQueue<> { break; case States::WAIT: - /*if(millis() > mWaitTimeout_min) { - if(mIsRetransmit) { // we already have been through... - mWaitTimeout = mWaitTimeout_min; - } else if(q->iv->mGotFragment) { // nothing received yet? - if(q->iv->mGotLastMsg) { - //mState = States::CHECK_FRAMES; - mWaitTimeout = mWaitTimeout_min; - } - } else if(mFirstTry) { - if(*mSerialDebug) { - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(String(millis() - mWaitTimeout_min + mlastTO_min)); - DBGPRINTLN(F("ms - second try")); - } - mFirstTry = false; - mlastTO_min = timeout_min; - q->iv->radioStatistics.retransmits++; // got nothing - mState = States::START; - break; - } - - }*/ if(millis() < mWaitTimeout) return; mState = States::CHECK_FRAMES; @@ -187,7 +165,7 @@ class Communication : public CommQueue<> { if(parseMiFrame(p, q)) q->iv->curFrmCnt++; } - } //else // serial does not match + } //else -> serial does not match q->iv->radio->mBufCtrl.pop(); yield(); @@ -221,7 +199,6 @@ class Communication : public CommQueue<> { else closeRequest(q, true); } - } } @@ -271,7 +248,7 @@ class Communication : public CommQueue<> { compilePayload(q); - if((NULL != mCbPayload) && (GridOnProFilePara != q->cmd)) + if((NULL != mCbPayload) && (GridOnProFilePara != q->cmd) && (GetLossRate != q->cmd)) (mCbPayload)(q->cmd, q->iv); closeRequest(q, true); @@ -306,7 +283,7 @@ class Communication : public CommQueue<> { else ah::dumpBuf(p->packet, p->len); } else { - DBGPRINT(F("| 0x")); + DBGPRINT(F("| ")); DHEX(p->packet[0]); DBGPRINT(F(" ")); DBGHEXLN(p->packet[9]); diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 6db39d7f..1c4e26e9 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -98,7 +98,7 @@ class HmRadio : public Radio { if(mNrf24->isChipConnected()) { DPRINTLN(DBG_INFO, F("Radio Config:")); mNrf24->printPrettyDetails(); - DPRINT(DBG_INFO, F("DTU_SN: 0x")); + DPRINT(DBG_INFO, F("DTU_SN: ")); DBGPRINTLN(String(mDtuSn, HEX)); } else DPRINTLN(DBG_WARN, F("WARNING! your NRF24 module can't be reached, check the wiring")); @@ -152,7 +152,7 @@ class HmRadio : public Radio { void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit) { DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINT(F("sendControlPacket cmd: 0x")); + DBGPRINT(F("sendControlPacket cmd: ")); DBGHEXLN(cmd); initPacket(iv->radioId.u64, TX_REQ_DEVCONTROL, SINGLE_FRAME); uint8_t cnt = 10; @@ -307,9 +307,8 @@ class HmRadio : public Radio { else ah::dumpBuf(mTxBuf, len); } else { - DBGPRINT(F("0x")); DHEX(mTxBuf[0]); - DBGPRINT(F(" 0x")); + DBGPRINT(F(" ")); DHEX(mTxBuf[10]); DBGPRINT(F(" ")); DBGHEXLN(mTxBuf[9]); diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index 80a2ecd9..2b147107 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -42,7 +42,7 @@ class CmtRadio : public Radio { } void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit) { - DPRINT(DBG_INFO, F("sendControlPacket cmd: 0x")); + DPRINT(DBG_INFO, F("sendControlPacket cmd: ")); DBGHEXLN(cmd); initPacket(iv->radioId.u64, TX_REQ_DEVCONTROL, SINGLE_FRAME); uint8_t cnt = 10; @@ -96,9 +96,8 @@ class CmtRadio : public Radio { else ah::dumpBuf(mTxBuf, len); } else { - DBGPRINT(F("0x")); DHEX(mTxBuf[0]); - DBGPRINT(F(" 0x")); + DBGPRINT(F(" ")); DHEX(mTxBuf[10]); DBGHEXLN(mTxBuf[9]); } diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 990f3e92..f2c193cd 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -323,9 +323,14 @@ class RestApi { void getHtmlSave(AsyncWebServerRequest *request, JsonObject obj) { getGeneric(request, obj.createNestedObject(F("generic"))); - obj["pending"] = (bool)mApp->getSavePending(); - obj["success"] = (bool)mApp->getLastSaveSucceed(); - obj["reboot"] = (bool)mApp->getShouldReboot(); + obj[F("pending")] = (bool)mApp->getSavePending(); + obj[F("success")] = (bool)mApp->getLastSaveSucceed(); + obj[F("reboot")] = (bool)mApp->getShouldReboot(); + #if defined(ETHERNET) && defined(CONFIG_IDF_TARGET_ESP32S3) + obj[F("reload")] = 5; + #else + obj[F("reload")] = 20; + #endif } void getReboot(AsyncWebServerRequest *request, JsonObject obj) { diff --git a/src/web/html/api.js b/src/web/html/api.js index e76aab2c..b059cc69 100644 --- a/src/web/html/api.js +++ b/src/web/html/api.js @@ -175,6 +175,14 @@ function getAjax(url, ptr, method="GET", json=null) { } } +const getJSON = async url => { + const re = await fetch(url); + if(!re.ok) + throw new Error(re.statusText); + const data = re.json(); + return data; +} + /** * CREATE DOM FUNCTIONS */ diff --git a/src/web/html/grid_info.json b/src/web/html/grid_info.json new file mode 100644 index 00000000..adb68393 --- /dev/null +++ b/src/web/html/grid_info.json @@ -0,0 +1,764 @@ +{ + "type": [ + {"0x0300": "DE_VDE4105_2018"}, + {"0x0a00": "DE NF_EN_50549-1:2019"}, + {"0x0c00": "AT_TOR_Erzeuger_default"}, + {"0x0d04": "France NF_EN_50549-1:2019"}, + {"0x1200": "2.0.4 (EU_EN50438)"}, + {"0x3700": "2.0.0 (CH_NA EEA-NE7–CH2020)"} + ], + "grp_codes": [ + {"0x00": "Voltage H/LVRT"}, + {"0x10": "Frequency H/LFRT"}, + {"0x20": "Islanding Detection"}, + {"0x30": "Reconnection"}, + {"0x40": "Ramp Rates"}, + {"0x50": "Frequency Watt"}, + {"0x60": "Volt Watt"}, + {"0x70": "Active Power Control"}, + {"0x80": "Volt Var"}, + {"0x90": "Specified Power Factor"}, + {"0xa0": "Reactive Power Control"}, + {"0xb0": "Watt Power Factor"} + ], + "group": [ + { + "0x0003": [ + { + "name": "Nominal Voltage", + "div": 10, + "def": 230, + "unit": "V" + }, + { + "name": "Low Voltage 1", + "div": 10, + "min": 180, + "max": 207, + "def": 184, + "unit": "V" + }, + { + "name": "LV1 Maximum Trip Time", + "div": 10, + "def": 1.5, + "unit": "s" + }, + { + "name": "High Voltage 1", + "div": 10, + "min": 250, + "max": 270, + "def": 253, + "unit": "V" + }, + { + "name": "HV1 Maximum Trip Time", + "div": 10, + "min": 0.1, + "max": 100, + "def": 0.1, + "unit": "s" + }, + { + "name": "Low Voltage 2", + "div": 10, + "min": 80, + "max": 161, + "def": 104, + "unit": "V" + }, + { + "name": "LV2 Maximum Trip Time", + "div": 100, + "min": 0.1, + "max": 5, + "def": 0.3, + "unit": "s" + }, + { + "name": "High Voltage 2", + "div": 10, + "min": 230, + "max": 299, + "def": 276, + "unit": "V" + }, + { + "name": "HV2 Maximum Trip Time", + "div": 100, + "min": 0, + "max": 5, + "def": 0.05, + "unit": "s" + } + ] + }, + { + "0x000a": [ + { + "name": "Nominal Voltage", + "div": 10, + "def": 230, + "unit": "V" + }, + { + "name": "Low Voltage 1", + "div": 10, + "min": 160, + "max": 195.5, + "def": 184, + "unit": "V" + }, + { + "name": "LV1 Maximum Trip Time", + "div": 10, + "def": 3, + "unit": "s" + }, + { + "name": "High Voltage 1", + "div": 10, + "min": 270, + "max": 287.5, + "def": 287.5, + "unit": "V" + }, + { + "name": "HV1 Maximum Trip Time", + "div": 10, + "def": 0.1, + "unit": "s" + }, + { + "name": "Low Voltage 2", + "div": 10, + "max": 150, + "min": 100, + "def": 103.5, + "unit": "V" + }, + { + "name": "LV2 Maximum Trip Time", + "div": 100, + "def": 0.3, + "unit": "s" + }, + { + "name": "10 mins Average High Voltage", + "div": 10, + "min": 250, + "max": 270, + "def": 253, + "unit": "V" + } + ] + }, + { + "0x000c": [ + { + "name": "Nominal Voltage", + "div": 10, + "unit": "V" + }, + { + "name": "Low Voltage 1", + "div": 10, + "min": 180, + "max": 207, + "def": 184, + "unit": "V" + }, + { + "name": "LV1 Maximum Trip Time", + "div": 10, + "min": 0.1, + "max": 5, + "def": 1.5, + "unit": "s" + }, + { + "name": "High Voltage 1", + "div": 10, + "min": 250, + "max": 270, + "def": 253, + "unit": "V" + }, + { + "name": "HV1 Maximum Trip Time", + "div": 10, + "min": 0.1, + "max": 100, + "def": 3, + "unit": "s" + }, + { + "name": "Low Voltage 2", + "div": 10, + "min": 80, + "max": 161, + "def": 161, + "unit": "V" + }, + { + "name": "LV2 Maximum Trip Time", + "div": 100, + "min": 0.1, + "max": 5, + "def": 0.2, + "unit": "s" + }, + { + "name": "High Voltage 2", + "div": 10, + "min": 230, + "max": 299, + "def": 264.5, + "unit": "V" + }, + { + "name": "HV2 Maximum Trip Time", + "div": 100, + "min": 0.1, + "max": 5, + "def": 0.2, + "unit": "s" + }, + { + "name": "High Voltage 3", + "div": 10, + "def": 276, + "unit": "V" + }, + { + "name": "HV3 Maximum Trip Time", + "div": 100, + "min": 0.1, + "max": 10, + "def": 0.1, + "unit": "s" + }, + { + "name": "10 mins Average High Voltage", + "div": 10, + "def": 253, + "unit": "V" + } + ] + }, + { + "0x1000": [ + { + "name": "Nominal Frequency", + "div": 100, + "def": 50, + "unit": "Hz" + }, + { + "name": "Low Frequency 1", + "div": 100, + "min": 47.5, + "max": 49.9, + "def": 47.5, + "unit": "Hz" + }, + { + "name": "LF1 Maximum Trip Time", + "div": 10, + "def": 0.1, + "unit": "s" + }, + { + "name": "High Frequency 1", + "div": 100, + "min": 50.1, + "max": 51.5, + "def": 51.5, + "unit": "Hz" + }, + { + "name": "HF1 Maximum Trip Time", + "div": 10, + "def": 0.1, + "unit": "s" + } + ] + }, + { + "0x1003": [ + { + "name": "Nominal Frequency", + "div": 100, + "def": 50, + "unit": "Hz" + }, + { + "name": "Low Frequency 1", + "div": 100, + "min": 45, + "max": 49.9, + "def": 48, + "unit": "Hz" + }, + { + "name": "LF1 Maximum Trip Time", + "div": 100, + "min": 0.1, + "max": 20, + "def": 2, + "unit": "s" + }, + { + "name": "High Frequency 1", + "div": 100, + "min": 50, + "max": 53, + "def": 51, + "unit": "Hz" + }, + { + "name": "HF1 Maximum Trip time", + "div": 10, + "min": 0.1, + "max": 20, + "def": 2, + "unit": "s" + }, + { + "name": "Low Frequency 2", + "div": 100, + "min": 45, + "max": 50, + "def": 47.5, + "unit": "Hz" + }, + { + "name": "LF2 Maximum Trip Time", + "div": 10, + "min": 0.1, + "max": 5, + "def": 0.5, + "unit": "s" + }, + { + "name": "High Frequency 2", + "div": 100, + "min": 50, + "max": 52, + "def": 52, + "unit": "Hz" + }, + { + "name": "HF2 Maximum Trip time", + "div": 10, + "min": 0.1, + "max": 5, + "def": 0.5, + "unit": "s" + } + ] + }, + { + "0x2000": [ + { + "name": "Island Detection Activated", + "div": 1, + "min": 0, + "max": 1, + "def": 1 + } + ] + }, + { + "0x3003": [ + { + "name": "Reconnect Time", + "div": 10, + "min": 10, + "max": 300, + "def": 60, + "unit": "s" + }, + { + "name": "Reconnect High Voltage", + "div": 10, + "min": 240, + "max": 276, + "def": 253, + "unit": "V" + }, + { + "name": "Reconnect Low Voltage", + "div": 10, + "min": 195.5, + "max": 210, + "def": 195.5, + "unit": "V" + }, + { + "name": "Reconnect High Frequency", + "div": 100, + "max": 50.9, + "min": 50.1, + "def": 50.2, + "unit": "Hz" + }, + { + "name": "Reconnect Low Frequency", + "div": 100, + "min": 47.5, + "max": 49.9, + "def": 49.5, + "unit": "Hz" + } + ] + }, + { + "0x4000": [ + { + "name": "Normal Ramp up Rate", + "div": 100, + "min": 0.1, + "max": 100, + "def": 20, + "unit": "Rated%/s" + }, + { + "name": "Soft Start Ramp up Rate ", + "div": 100, + "min": 0.1, + "max": 10, + "def": 0.16, + "unit": "Rated%/s" + } + ] + }, + { + "0x5001": [ + { + "name": "FW Function Activated", + "div": 1, + "min": 0, + "max": 1, + "def": 1 + }, + { + "name": "Start of Frequency Watt Droop", + "div": 100, + "min": 50.2, + "max": 53, + "def": 50.2, + "unit": "Hz" + }, + { + "name": "FW Droop Slope", + "div": 10, + "min": 16.7, + "max": 100, + "def": 40, + "unit": "Pn%/Hz" + }, + { + "name": "Recovery Ramp Rate", + "div": 100, + "min": 0.1, + "max": 100, + "def": 0.16, + "unit": "Pn%/s" + + }, + { + "name": "FW Setting Time", + "div": 10, + "min": 0, + "max": 2, + "def": 0, + "unit": "s" + } + ] + }, + { + "0x5008": [ + { + "name": "FW Function Activated", + "div": 1, + "min": 0, + "max": 1, + "def": 1 + }, + { + "name": "Start of Frequency Watt Droop", + "div": 100, + "min": 50.2, + "max": 52, + "def": 50.2, + "unit": "Hz" + }, + { + "name": "FW Droop Slope", + "div": 10, + "min": 16.7, + "max": 100, + "def": 40, + "unit": "Pn%/Hz" + }, + { + "name": "Recovery Ramp Rate", + "div": 100, + "min": 0.1, + "max": 50, + "def": 0.16, + "unit": "Pn%/s" + }, + { + "name": "Recovery High Frequency", + "div": 10, + "min": 50.1, + "max": 52, + "def": 50.2, + "unit": "Hz" + }, + { + "name": "Recovery Low Frequency", + "div": 100, + "min": 49, + "max": 49.9, + "def": 49.8, + "unit": "Hz" + } + ] + }, + { + "0x6000": [ + { + "name": "VW Function Activated", + "div": 1, + "min": 0, + "max": 1, + "def": 1 + }, + { + "name": "Start of Voltage Watt Droop", + "div": 10, + "def": 253, + "unit": "V" + }, + { + "name": "End of Voltage Watt Droop", + "div": 10, + "min": 258, + "max": 270, + "def": 265, + "unit": "V" + }, + { + "name": "VW Droop Slope", + "div": 100, + "min": 5, + "max": 18, + "def": 5.33, + "unit": "Pn%/V" + } + ] + }, + { + "0x7002": [ + { + "name": "APC Function Activated", + "div": 1, + "min": 0, + "max": 1, + "def": 1 + }, + { + "name": "Power Ramp Rate", + "div": 100, + "min": 0.33, + "max": 100, + "def": 100, + "unit": "Pn%/s" + } + ] + }, + { + "0x8000": [ + { + "name": "VV Function Activated", + "div": 1, + "min": 0, + "max": 1, + "def": 0 + }, + { + "name": "Voltage Set Point V1", + "div": 10, + "min": 184, + "max": 230, + "def": 213.9, + "unit": "V" + }, + { + "name": "Reactive Set Point Q1", + "div": 10, + "min": 0, + "max": 100, + "def": 30, + "unit": "%Pn" + }, + { + "name": "Voltage Set Point V2", + "div": 10, + "min": 210, + "max": 240, + "def": 223.1, + "unit": "V" + }, + { + "name": "Voltage Set Point V3", + "div": 10, + "min": 220, + "max": 240, + "def": 236.9, + "unit": "V" + }, + { + "name": "Voltage Set Point V4", + "div": 10, + "min": 230, + "max": 253, + "def": 246.1, + "unit": "V" + }, + { + "name": "Reactive Set Point Q4", + "div": 10, + "min": 0, + "max": 100, + "def": 30, + "unit": "%Pn" + } + ] + }, + { + "0x8001": [ + { + "name": "VV Function Activated", + "div": 1, + "min": 0, + "max": 1, + "def": 0 + }, + { + "name": "Voltage Set Point V1", + "div": 10, + "def": 213.9, + "unit": "V" + }, + { + "name": "Reactive Set Point Q1", + "div": 10, + "min": 0, + "max": 100, + "def": 30, + "unit": "%Pn" + }, + { + "name": "Voltage Set Point V2", + "div": 10, + "def": 223.1, + "unit": "V" + }, + { + "name": "Voltage Set Point V3", + "div": 10, + "def": 236.9, + "unit": "V" + }, + { + "name": "Voltage Set Point V4", + "div": 10, + "def": 246.1, + "unit": "V" + }, + { + "name": "Reactive Set Point Q4", + "div": 10, + "min": 0, + "max": 100, + "def": 30, + "unit": "%Pn" + }, + { + "name": "VV Setting Time", + "div": 10, + "min": 0, + "max": 60, + "def": 10, + "unit": "s" + } + ] + }, + { + "0x9000": [ + { + "name": "Specified Power Factor Activated", + "div": 1, + "min": 0, + "max": 1, + "def": 0 + }, + { + "name": "Power Factor", + "div": 100, + "min": 0.9, + "max": 1, + "def": 0.95 + } + ] + }, + { + "0xa002": [ + { + "name": "RPC Function Activated", + "div": 1, + "min": 0, + "max": 1, + "def": 0 + }, + { + "name": "Reactive Power", + "div": 100, + "min": 0, + "max": 50, + "def": 0, + "unit": "%Sn" + } + ] + }, + { + "0xb000": [ + { + "name": "WPF Function Activated", + "div": 1, + "min": 0, + "max": 1, + "def": 0 + }, + { + "name": "Start of Power of WPF", + "div": 10, + "def": 50, + "unit": "%Pn" + }, + { + "name": "Power Factor ar Rated Power", + "div": 100, + "min": 0.8, + "max": 1, + "def": 0.95 + } + ] + } + ] +} diff --git a/src/web/html/save.html b/src/web/html/save.html index ce50c6ca..9b5b4864 100644 --- a/src/web/html/save.html +++ b/src/web/html/save.html @@ -34,8 +34,8 @@ html = "Settings successfully saved. Automatic page reload in 3 seconds."; meta.content = 3; } else { - html = "Settings successfully saved. Rebooting. Automatic redirect in 20 seconds."; - meta.content = 20 + "; URL=/"; + html = "Settings successfully saved. Rebooting. Automatic redirect in " + obj.reload + " seconds."; + meta.content = obj.reload + "; URL=/"; } document.getElementsByTagName('head')[0].appendChild(meta); } else { diff --git a/src/web/html/visualization.html b/src/web/html/visualization.html index faf76432..b561d5cc 100644 --- a/src/web/html/visualization.html +++ b/src/web/html/visualization.html @@ -295,13 +295,76 @@ getAjax("/api/inverter/grid/" + obj.id, showGridProfile); }}, null)) ]) - ]); - modal("Info for inverter " + obj.name, ml("div", {}, html)); + ]) + modal("Info for inverter " + obj.name, ml("div", {}, html)) + } + + function getGridValue(g) { + var val = (parseInt(g.grid.substring(g.offs*3, g.offs*3+2), 16) * 256) + + parseInt(g.grid.substring(g.offs*3+3, g.offs*3+5), 16) + g.offs += 2 + return val + } + + function getGridIdentifier(g) { + return "0x" + getGridValue(g).toString(16).padStart(4, '0') + } + + function getGridType(t, id) { + for(e of t) { + if(undefined !== e[id]) + return e[id] + } + return null + } + + function parseGridGroup(g) { + var id = getGridIdentifier(g) + var type = getGridType(g.info.grp_codes, id.substring(0, 4)) + var content = [] + content.push(ml("div", {class: "row"}, + ml("div", {class: "col head p-2 mt-3"}, + ml("div", {class: "col a-c"}, type + " (Code " + id + ")") + ) + )) + content.push(ml("div", {class: "row my-2"}, [ + ml("div", {class: "col-4"}, ml("b", {}, "Name")), + ml("div", {class: "col-3"}, ml("b", {}, "Value")), + ml("div", {class: "col-3"}, ml("b", {}, "Range")), + ml("div", {class: "col-2"}, ml("b", {}, "Default")) + ])) + for(e of g.info.group) { + if(Array.isArray(e[id])) { + for(e of e[id]) { + var v = String(getGridValue(g) / e.div); + var vt = (v !== String(e.def)) ? "b" : "span"; + content.push(ml("div", {class: "row mt-2"}, [ + ml("div", {class: "col-4"}, e.name), + ml("div", {class: "col-3"}, ml(vt, {}, v + ((undefined !== e.unit) ? " [" + e.unit + "]" : ""))), + ml("div", {class: "col-3"}, (undefined !== e.min) ? (e.min + " - " + e.max) : "n/a"), + ml("div", {class: "col-2"}, String(e.def)) + ])) + } + } + } + + return ml("div", {class: "col"}, [...content]) } function showGridProfile(obj) { - var html = ml("pre", {}, obj.grid); - modal("Grid Profile for inverter " + obj.name, ml("div", {}, html)); + getJSON("/grid_info.json").then(data => { + var glob = {offs:0, grid:obj.grid, info: data} + var content = []; + content.push(ml("div", {class: "row"}, + ml("div", {class: "col my-3"}, ml("h5", {}, getGridType(glob.info.type, getGridIdentifier(glob)) + " (Version " + getGridValue(glob).toString(16) + ")")) + )) + + while((glob.offs*3) < glob.grid.length) { + content.push(parseGridGroup(glob)) + } + + modal("Grid Profile for inverter " + obj.name, ml("div", {}, ml("div", {class: "col mb-2"}, [...content]))) + }) } @@ -315,8 +378,8 @@ tr2(["RX fragments", obj.frame_cnt, ""]), tr2(["TX retransmits", obj.retransmits, ""]) ]) - ]); - modal("Radio statistics for inverter " + obj.name, ml("div", {}, html)); + ]) + modal("Radio statistics for inverter " + obj.name, ml("div", {}, html)) } function limitModal(obj) { diff --git a/src/web/web.h b/src/web/web.h index b104e9fd..451dc656 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -25,6 +25,7 @@ #include "html/h/colorBright_css.h" #include "html/h/colorDark_css.h" #include "html/h/favicon_ico.h" +#include "html/h/grid_info_json.h" #include "html/h/index_html.h" #include "html/h/login_html.h" #include "html/h/serial_html.h" @@ -65,6 +66,7 @@ class Web { mWeb.on("/colors.css", HTTP_GET, std::bind(&Web::onColor, this, std::placeholders::_1)); mWeb.on("/style.css", HTTP_GET, std::bind(&Web::onCss, this, std::placeholders::_1)); mWeb.on("/api.js", HTTP_GET, std::bind(&Web::onApiJs, this, std::placeholders::_1)); + mWeb.on("/grid_info.json", HTTP_GET, std::bind(&Web::onGridInfoJson, this, std::placeholders::_1)); mWeb.on("/favicon.ico", HTTP_GET, std::bind(&Web::onFavicon, this, std::placeholders::_1)); mWeb.onNotFound ( std::bind(&Web::showNotFound, this, std::placeholders::_1)); mWeb.on("/reboot", HTTP_ANY, std::bind(&Web::onReboot, this, std::placeholders::_1)); @@ -389,6 +391,16 @@ class Web { request->send(response); } + void onGridInfoJson(AsyncWebServerRequest *request) { + DPRINTLN(DBG_VERBOSE, F("onGridInfoJson")); + + AsyncWebServerResponse *response = request->beginResponse_P(200, F("application/json; charset=utf-8"), grid_info_json, grid_info_json_len); + response->addHeader(F("Content-Encoding"), "gzip"); + if(request->hasParam("v")) + response->addHeader(F("Cache-Control"), F("max-age=604800")); + request->send(response); + } + void onFavicon(AsyncWebServerRequest *request) { static const char favicon_type[] PROGMEM = "image/x-icon"; AsyncWebServerResponse *response = request->beginResponse_P(200, favicon_type, favicon_ico, favicon_ico_len); From cbb93cfd5a849c1d41ba8a0e993947256d28a290 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 28 Dec 2023 02:30:13 +0100 Subject: [PATCH 244/267] 0.8.29 * added ESP32-C3 mini environment #1289 --- .github/workflows/compile_development.yml | 2 +- .github/workflows/compile_release.yml | 2 +- scripts/getVersion.py | 13 +++++++++++++ src/CHANGES.md | 1 + 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/.github/workflows/compile_development.yml b/.github/workflows/compile_development.yml index 31049c21..6eba4879 100644 --- a/.github/workflows/compile_development.yml +++ b/.github/workflows/compile_development.yml @@ -43,7 +43,7 @@ jobs: pip install --upgrade platformio - name: Run PlatformIO - run: pio run -d src --environment esp8266 --environment esp8266-prometheus --environment esp8285 --environment esp32-wroom32 --environment esp32-wroom32-prometheus --environment esp32-wroom32-ethernet --environment esp32-s2-mini --environment opendtufusion --environment opendtufusion-ethernet + run: pio run -d src --environment esp8266 --environment esp8266-prometheus --environment esp8285 --environment esp32-wroom32 --environment esp32-wroom32-prometheus --environment esp32-wroom32-ethernet --environment esp32-s2-mini --environment esp32-c3-mini --environment opendtufusion --environment opendtufusion-ethernet - name: Copy boot_app0.bin run: cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin src/.pio/build/opendtufusion/ota.bin diff --git a/.github/workflows/compile_release.yml b/.github/workflows/compile_release.yml index 8f493100..61c920b3 100644 --- a/.github/workflows/compile_release.yml +++ b/.github/workflows/compile_release.yml @@ -47,7 +47,7 @@ jobs: pip install --upgrade platformio - name: Run PlatformIO - run: pio run -d src --environment esp8266 --environment esp8266-prometheus --environment esp8285 --environment esp32-wroom32 --environment esp32-wroom32-prometheus --environment esp32-wroom32-ethernet --environment esp32-s2-mini --environment opendtufusion --environment opendtufusion-ethernet + run: pio run -d src --environment esp8266 --environment esp8266-prometheus --environment esp8285 --environment esp32-wroom32 --environment esp32-wroom32-prometheus --environment esp32-wroom32-ethernet --environment esp32-s2-mini --environment esp32-c3-mini --environment opendtufusion --environment opendtufusion-ethernet - name: Copy boot_app0.bin run: cp ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin src/.pio/build/opendtufusion/ota.bin diff --git a/scripts/getVersion.py b/scripts/getVersion.py index 4ea74d71..cdb39ae8 100644 --- a/scripts/getVersion.py +++ b/scripts/getVersion.py @@ -55,6 +55,7 @@ def readVersion(path, infile): os.mkdir(path + "firmware/ESP32/") os.mkdir(path + "firmware/ESP32-S2/") os.mkdir(path + "firmware/ESP32-S3/") + os.mkdir(path + "firmware/ESP32-C3/") os.mkdir(path + "firmware/ESP32-S3-ETH/") sha = os.getenv("SHA",default="sha") @@ -94,6 +95,11 @@ def readVersion(path, infile): dst = path + "firmware/ESP32-S2/" + versionout os.rename(src, dst) + versionout = version[:-1] + "_" + sha + "_esp32c3-mini.bin" + src = path + ".pio/build/esp32-c3-mini/firmware.bin" + dst = path + "firmware/ESP32-C3/" + versionout + os.rename(src, dst) + versionout = version[:-1] + "_" + sha + "_esp32s3.bin" src = path + ".pio/build/opendtufusion/firmware.bin" dst = path + "firmware/ESP32-S3/" + versionout @@ -118,6 +124,13 @@ def readVersion(path, infile): os.rename(src + "partitions.bin", dst + "partitions.bin") genOtaBin(dst) + # other ESP32-C3 bin files + src = path + ".pio/build/esp32-c3-mini/" + dst = path + "firmware/ESP32-C3/" + os.rename(src + "bootloader.bin", dst + "bootloader.bin") + os.rename(src + "partitions.bin", dst + "partitions.bin") + genOtaBin(dst) + # other ESP32-S3 bin files src = path + ".pio/build/opendtufusion/" dst = path + "firmware/ESP32-S3/" diff --git a/src/CHANGES.md b/src/CHANGES.md index 99b7dc64..fc8566cc 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -7,6 +7,7 @@ * fix crash if `getLossRate` was read from inverter #1288 #1290 * reduce reload time for opendtufusion ethernet variant to 5 seconds * added basic grid parser +* added ESP32-C3 mini environment #1289 ## 0.8.28 - 2023-12-23 * fix bug heuristic From 4e277e20c8b0b1663f365dd1d1c14fd6432311c5 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 28 Dec 2023 10:29:55 +0100 Subject: [PATCH 245/267] 0.8.29 * fix compile for ESP32-C3 --- patches/AsyncWeb_Prometheus.patch | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/patches/AsyncWeb_Prometheus.patch b/patches/AsyncWeb_Prometheus.patch index 7fb9209a..21fe22cd 100644 --- a/patches/AsyncWeb_Prometheus.patch +++ b/patches/AsyncWeb_Prometheus.patch @@ -1,3 +1,16 @@ +diff --git a/src/AsyncWebSocket.cpp b/src/AsyncWebSocket.cpp +index 12be5f8..cffeed7 100644 +--- a/src/AsyncWebSocket.cpp ++++ b/src/AsyncWebSocket.cpp +@@ -737,7 +737,7 @@ void AsyncWebSocketClient::binary(const __FlashStringHelper *data, size_t len) + IPAddress AsyncWebSocketClient::remoteIP() const + { + if (!_client) +- return IPAddress(0U); ++ return IPAddress(); + + return _client->remoteIP(); + } diff --git a/src/WebResponses.cpp b/src/WebResponses.cpp index 22a549f..e0b36b3 100644 --- a/src/WebResponses.cpp From e8185b9e809914a9e671addaa32c7efe98ec3ac4 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 28 Dec 2023 12:03:00 +0100 Subject: [PATCH 246/267] discord .2901 - add longer timeout + more retransmits to GridProfile req. - close GridProfile + GetLossRate req. explicitly (also for heuristiscs) --- src/hm/Communication.h | 35 +++++++++++++++++++++++++++++++++-- src/hm/hmRadio.h | 4 ++-- 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 23d20004..a0e593c2 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -59,7 +59,7 @@ class Communication : public CommQueue<> { mLastEmptyQueueMillis = millis(); mPrintSequenceDuration = true; - uint16_t timeout = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : (((q->iv->mGotFragment && q->iv->mGotLastMsg) || mIsRetransmit) ? SINGLEFR_TIMEOUT : ((q->cmd != AlarmData) ? DEFAULT_TIMEOUT : (1.5 * DEFAULT_TIMEOUT))); + uint16_t timeout = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : (((q->iv->mGotFragment && q->iv->mGotLastMsg) || mIsRetransmit) ? SINGLEFR_TIMEOUT : ((q->cmd != AlarmData) && q->cmd != GridOnProFilePara ? DEFAULT_TIMEOUT : (1.5 * DEFAULT_TIMEOUT))); uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment || mIsRetransmit)) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT; /*if(mDebugState != mState) { @@ -113,10 +113,35 @@ class Communication : public CommQueue<> { mIsRetransmit = false; mlastTO_min = timeout_min; setAttempt(); + if(q->cmd == AlarmData || q->cmd == GridOnProFilePara) + incrAttempt(q->cmd == AlarmData? 5 : 3); + mState = States::WAIT; break; case States::WAIT: + /*if(millis() > mWaitTimeout_min) { + if(mIsRetransmit) { // we already have been through... + mWaitTimeout = mWaitTimeout_min; + } else if(q->iv->mGotFragment) { // nothing received yet? + if(q->iv->mGotLastMsg) { + //mState = States::CHECK_FRAMES; + mWaitTimeout = mWaitTimeout_min; + } + } else if(mFirstTry) { + if(*mSerialDebug) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(String(millis() - mWaitTimeout_min + mlastTO_min)); + DBGPRINTLN(F("ms - second try")); + } + mFirstTry = false; + mlastTO_min = timeout_min; + q->iv->radioStatistics.retransmits++; // got nothing + mState = States::START; + break; + } + + }*/ if(millis() < mWaitTimeout) return; mState = States::CHECK_FRAMES; @@ -283,7 +308,7 @@ class Communication : public CommQueue<> { else ah::dumpBuf(p->packet, p->len); } else { - DBGPRINT(F("| ")); + DBGPRINT(F("| 0x")); DHEX(p->packet[0]); DBGPRINT(F(" ")); DBGHEXLN(p->packet[9]); @@ -439,6 +464,9 @@ class Communication : public CommQueue<> { if(GridOnProFilePara == q->cmd) { q->iv->addGridProfile(mPayload, len); + q->iv->radioStatistics.rxSuccess++; + mHeu.evalTxChQuality(q->iv, true, (7 - q->attempts), q->iv->curFrmCnt); + cmdDone(false); return; } @@ -447,6 +475,9 @@ class Communication : public CommQueue<> { if(GetLossRate == q->cmd) { q->iv->parseGetLossRate(mPayload, len); //closeRequest(q, true); //@lumapu: Activating would crash most esp's! + mHeu.evalTxChQuality(q->iv, true, (9 - q->attempts), q->iv->curFrmCnt); + q->iv->radioStatistics.rxSuccess++; + cmdDone(false); return; } else { DPRINTLN(DBG_ERROR, F("record is NULL!")); diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 1c4e26e9..2e02e92a 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -121,9 +121,10 @@ class HmRadio : public Radio { uint32_t startMicros = micros(); uint32_t loopMillis = millis(); - uint32_t outerLoopTimeout = (mLastIv->mIsSingleframeReq) ? 100 : ((mLastIv->mCmd != AlarmData) ? 400 : 600); + uint32_t outerLoopTimeout = (mLastIv->mIsSingleframeReq) ? 100 : ((mLastIv->mCmd != AlarmData) && (mLastIv->mCmd != GridOnProFilePara)) ? 400 : 600; while ((millis() - loopMillis) < outerLoopTimeout) { + uint32_t startMicros = micros(); while ((micros() - startMicros) < 5110) { // listen (4088us or?) 5110us to each channel if (mIrqRcvd) { mIrqRcvd = false; @@ -137,7 +138,6 @@ class HmRadio : public Radio { // switch to next RX channel mRxChIdx = (mRxChIdx + 1) % RF_CHANNELS; mNrf24->setChannel(mRfChLst[mRxChIdx]); - startMicros = micros(); } // not finished but time is over mRxChIdx = (mRxChIdx + 1) % RF_CHANNELS; From 6ec9561d7a1e99348bfe51fd8d3ae902dd3010b6 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 28 Dec 2023 12:16:02 +0100 Subject: [PATCH 247/267] discord .2902 - disable cmdDone() calls for GridProfile+GetLossRate - Typo --- src/hm/Communication.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index a0e593c2..bc6f9f38 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -308,7 +308,7 @@ class Communication : public CommQueue<> { else ah::dumpBuf(p->packet, p->len); } else { - DBGPRINT(F("| 0x")); + DBGPRINT(F("| ")); DHEX(p->packet[0]); DBGPRINT(F(" ")); DBGHEXLN(p->packet[9]); @@ -466,7 +466,7 @@ class Communication : public CommQueue<> { q->iv->addGridProfile(mPayload, len); q->iv->radioStatistics.rxSuccess++; mHeu.evalTxChQuality(q->iv, true, (7 - q->attempts), q->iv->curFrmCnt); - cmdDone(false); + //cmdDone(false); return; } @@ -477,7 +477,7 @@ class Communication : public CommQueue<> { //closeRequest(q, true); //@lumapu: Activating would crash most esp's! mHeu.evalTxChQuality(q->iv, true, (9 - q->attempts), q->iv->curFrmCnt); q->iv->radioStatistics.rxSuccess++; - cmdDone(false); + //cmdDone(false); return; } else { DPRINTLN(DBG_ERROR, F("record is NULL!")); From f9257934300ab52f45aae6916e389700e143e07e Mon Sep 17 00:00:00 2001 From: you69man Date: Thu, 28 Dec 2023 12:38:22 +0100 Subject: [PATCH 248/267] fix esp8266 pin settings --- src/web/html/setup.html | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 74425185..7ca17005 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -897,10 +897,12 @@ function parsePinout(obj, type, system) { var e = document.getElementById("pinout"); + var pinList = esp8266pins; + /*IF_ESP32*/ var pinList = esp32pins; - if("ESP8266" == type) pinList = esp8266pins; - else if ("ESP32-S3" == system["chip_model"]) pinList = esp32s3pins; + if ("ESP32-S3" == system["chip_model"]) pinList = esp32s3pins; else if("ESP32-C3" == system["chip_model"]) pinList = esp32c3pins; + /*ENDIF_ESP32*/ pins = [['led0', 'pinLed0', 'At least one inverter is producing'], ['led1', 'pinLed1', 'MqTT connected']]; for(p of pins) { e.append( @@ -927,10 +929,12 @@ var en = inp("nrfEnable", null, null, ["cb"], "nrfEnable", "checkbox"); en.checked = obj["en"]; + var pinList = esp8266pins; + /*IF_ESP32*/ var pinList = esp32pins; - if("ESP8266" == type) pinList = esp8266pins; - else if ("ESP32-S3" == system["chip_model"]) pinList = esp32s3pins; + if ("ESP32-S3" == system["chip_model"]) pinList = esp32s3pins; else if("ESP32-C3" == system["chip_model"]) pinList = esp32c3pins; + /*ENDIF_ESP32*/ e.replaceChildren ( ml("div", {class: "row mb-3"}, [ @@ -992,10 +996,12 @@ } function parseDisplay(obj, type, system) { + var pinList = esp8266pins; + /*IF_ESP32*/ var pinList = esp32pins; - if("ESP8266" == type) pinList = esp8266pirpins; - else if ("ESP32-S3" == system["chip_model"]) pinList = esp32s3pins; + if ("ESP32-S3" == system["chip_model"]) pinList = esp32s3pins; else if("ESP32-C3" == system["chip_model"]) pinList = esp32c3pins; + /*ENDIF_ESP32*/ for(var i of ["disp_pwr"]) document.getElementsByName(i)[0].checked = obj[i]; @@ -1061,7 +1067,7 @@ document.getElementById("pirPin").append( ml("div", {class: "row mb-3"}, [ ml("div", {class: "col-12 col-sm-3 my-2"}, "PIR sensor"), - ml("div", {class: "col-12 col-sm-9"}, sel("pir_pin", pinList, obj["pir_pin"])) + ml("div", {class: "col-12 col-sm-9"}, sel("pir_pin", ("ESP8266" == type) ? esp8266pirpins : pinList, obj["pir_pin"])) ]) ); From cf7fa9c3a338918c2bba100272dfc6820a205039 Mon Sep 17 00:00:00 2001 From: you69man Date: Thu, 28 Dec 2023 19:10:03 +0100 Subject: [PATCH 249/267] fix yields for displays 128x64 and 84x48 --- src/plugins/Display/Display_Mono_128X64.h | 20 ++++++++++---------- src/plugins/Display/Display_Mono_84X48.h | 18 +++++++++--------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/plugins/Display/Display_Mono_128X64.h b/src/plugins/Display/Display_Mono_128X64.h index 7b7b7920..afb581dd 100644 --- a/src/plugins/Display/Display_Mono_128X64.h +++ b/src/plugins/Display/Display_Mono_128X64.h @@ -49,9 +49,9 @@ class DisplayMono128X64 : public DisplayMono { /* mDisplayData->nrSleeping = 10; mDisplayData->nrProducing = 10; - mDisplayData->totalPower = 54321.9; // W - mDisplayData->totalYieldDay = 4321.9; // Wh - mDisplayData->totalYieldTotal = 4321.9; // kWh + mDisplayData->totalPower = 15432.9; // W + mDisplayData->totalYieldDay = 14321.9; // Wh + mDisplayData->totalYieldTotal = 15432.9; // kWh mDisplay->drawPixel(0, 0); mDisplay->drawPixel(mDispWidth-1, 0); mDisplay->drawPixel(0, mDispHeight-1); @@ -63,8 +63,8 @@ class DisplayMono128X64 : public DisplayMono { // print total power if (mDisplayData->nrProducing > 0) { - if (mDisplayData->totalPower > 999) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f kW", (mDisplayData->totalPower / 1000.0)); + if (mDisplayData->totalPower > 9999.0) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kW", (mDisplayData->totalPower / 1000.0)); else snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f W", mDisplayData->totalPower); @@ -120,16 +120,16 @@ class DisplayMono128X64 : public DisplayMono { mDisplay->drawStr(16 + mPixelshift, mLineYOffsets[l_YieldDay], "I"); // day symbol mDisplay->drawStr(16 + mPixelshift, mLineYOffsets[l_YieldTotal], "D"); // total symbol - if (mDisplayData->totalYieldDay > 999.0) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f kWh", mDisplayData->totalYieldDay / 1000.0); + if (mDisplayData->totalYieldDay > 9999.0) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kWh", mDisplayData->totalYieldDay / 1000.0); else snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f Wh", mDisplayData->totalYieldDay); printText(mFmtText, l_YieldDay, 0xff); - if (mDisplayData->totalYieldTotal > 999.0) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f MWh", mDisplayData->totalYieldTotal / 1000.0); + if (mDisplayData->totalYieldTotal > 9999.0) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f MWh", mDisplayData->totalYieldTotal / 1000.0); else - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f kWh", mDisplayData->totalYieldTotal); + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f kWh", mDisplayData->totalYieldTotal); printText(mFmtText, l_YieldTotal, 0xff); // draw dynamic RSSI bars diff --git a/src/plugins/Display/Display_Mono_84X48.h b/src/plugins/Display/Display_Mono_84X48.h index df27a414..7e5c157f 100644 --- a/src/plugins/Display/Display_Mono_84X48.h +++ b/src/plugins/Display/Display_Mono_84X48.h @@ -36,8 +36,8 @@ class DisplayMono84X48 : public DisplayMono { /* mDisplayData->nrSleeping = 10; mDisplayData->nrProducing = 10; - mDisplayData->totalPower = 111.91; // W - mDisplayData->totalYieldDay = 54321.9; // Wh + mDisplayData->totalPower = 19897.6; // W + mDisplayData->totalYieldDay = 15521.9; // Wh mDisplayData->totalYieldTotal = 654321.9; // kWh mDisplay->drawPixel(0, 0); mDisplay->drawPixel(mDispWidth-1, 0); @@ -47,8 +47,8 @@ class DisplayMono84X48 : public DisplayMono { // print total power if (mDisplayData->nrProducing > 0) { - if (mDisplayData->totalPower > 999) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f kW", (mDisplayData->totalPower / 1000)); + if (mDisplayData->totalPower > 9999.0) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kW", (mDisplayData->totalPower / 1000.0)); else snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f W", mDisplayData->totalPower); @@ -84,16 +84,16 @@ class DisplayMono84X48 : public DisplayMono { printText("\x88", l_YieldDay, 10); // day symbol printText("\x83", l_YieldTotal, 10); // total symbol - if (mDisplayData->totalYieldDay > 999.0) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f kWh", mDisplayData->totalYieldDay / 1000.0); + if (mDisplayData->totalYieldDay > 9999.0) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kWh", mDisplayData->totalYieldDay / 1000.0); else snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f Wh", mDisplayData->totalYieldDay); printText(mFmtText, l_YieldDay, 0xff); - if (mDisplayData->totalYieldTotal > 999.0) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f MWh", mDisplayData->totalYieldTotal / 1000.0); + if (mDisplayData->totalYieldTotal > 9999.0) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f MWh", mDisplayData->totalYieldTotal / 1000.0); else - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f kWh", mDisplayData->totalYieldTotal); + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f kWh", mDisplayData->totalYieldTotal); printText(mFmtText, l_YieldTotal, 0xff); // draw dynamic Nokia RSSI bars From f047e31d4b984fdc1de0856ded7ae7e56ac3aa2f Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 28 Dec 2023 20:53:39 +0100 Subject: [PATCH 250/267] fix double success counts --- Communication.h | 930 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 930 insertions(+) create mode 100644 Communication.h diff --git a/Communication.h b/Communication.h new file mode 100644 index 00000000..9cf8fcb7 --- /dev/null +++ b/Communication.h @@ -0,0 +1,930 @@ +//----------------------------------------------------------------------------- +// 2023 Ahoy, https://github.com/lumpapu/ahoy +// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed +//----------------------------------------------------------------------------- + +#ifndef __COMMUNICATION_H__ +#define __COMMUNICATION_H__ + +#include "CommQueue.h" +#include +#include "../utils/crc.h" +#include "Heuristic.h" + +#define MI_TIMEOUT 250 // timeout for MI type requests +#define FRSTMSG_TIMEOUT 150 // how long to wait for first msg to be received +#define DEFAULT_TIMEOUT 500 // timeout for regular requests +#define SINGLEFR_TIMEOUT 100 // timeout for single frame requests +#define MAX_BUFFER 250 + +typedef std::function *)> payloadListenerType; +typedef std::function *)> alarmListenerType; + +class Communication : public CommQueue<> { + public: + void setup(uint32_t *timestamp, bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint16_t *inverterGap) { + mTimestamp = timestamp; + mPrivacyMode = privacyMode; + mSerialDebug = serialDebug; + mPrintWholeTrace = printWholeTrace; + mInverterGap = inverterGap; + } + + void addImportant(Inverter<> *iv, uint8_t cmd) { + mState = States::RESET; // cancel current operation + CommQueue::addImportant(iv, cmd); + } + + void addPayloadListener(payloadListenerType cb) { + mCbPayload = cb; + } + + void addAlarmListener(alarmListenerType cb) { + mCbAlarm = cb; + } + + void loop() { + get([this](bool valid, const queue_s *q) { + if(!valid) { + if(mPrintSequenceDuration) { + mPrintSequenceDuration = false; + DPRINT(DBG_INFO, F("com loop duration: ")); + DBGPRINT(String(millis() - mLastEmptyQueueMillis)); + DBGPRINTLN(F("ms")); + DBGPRINTLN(F("-----")); + } + return; // empty + } + if(!mPrintSequenceDuration) // entry was added to the queue + mLastEmptyQueueMillis = millis(); + mPrintSequenceDuration = true; + + uint16_t timeout = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : (((q->iv->mGotFragment && q->iv->mGotLastMsg) || mIsRetransmit) ? SINGLEFR_TIMEOUT : ((q->cmd != AlarmData) && q->cmd != GridOnProFilePara ? DEFAULT_TIMEOUT : (1.5 * DEFAULT_TIMEOUT))); + uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment || mIsRetransmit)) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT; + + /*if(mDebugState != mState) { + DPRINT(DBG_INFO, F("State: ")); + DBGHEXLN((uint8_t)(mState)); + mDebugState = mState; + }*/ + switch(mState) { + case States::RESET: + if(millis() < mWaitTimeout) + return; + mMaxFrameId = 0; + for(uint8_t i = 0; i < MAX_PAYLOAD_ENTRIES; i++) { + mLocalBuf[i].len = 0; + } + + if(*mSerialDebug) + mHeu.printStatus(q->iv); + mHeu.getTxCh(q->iv); + q->iv->mGotFragment = false; + q->iv->mGotLastMsg = false; + q->iv->curFrmCnt = 0; + mIsRetransmit = false; + if(NULL == q->iv->radio) + cmdDone(false); // can't communicate while radio is not defined! + q->iv->mCmd = q->cmd; + q->iv->mIsSingleframeReq = false; + mState = States::START; + break; + + case States::START: + setTs(mTimestamp); + if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { + // frequency was changed during runtime + if(q->iv->curCmtFreq != q->iv->config->frequency) { + if(q->iv->radio->switchFrequencyCh(q->iv, q->iv->curCmtFreq, q->iv->config->frequency)) + q->iv->curCmtFreq = q->iv->config->frequency; + } + } + + if(q->isDevControl) { + if(ActivePowerContr == q->cmd) + q->iv->powerLimitAck = false; + q->iv->radio->sendControlPacket(q->iv, q->cmd, q->iv->powerLimit, false); + } else + q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); + + q->iv->radioStatistics.txCnt++; + mWaitTimeout = millis() + timeout; + mWaitTimeout_min = millis() + timeout_min; + mIsRetransmit = false; + mlastTO_min = timeout_min; + setAttempt(); + if(q->cmd == AlarmData || q->cmd == GridOnProFilePara) + incrAttempt(q->cmd == AlarmData? 5 : 3); + + mState = States::WAIT; + break; + + case States::WAIT: + /*if(millis() > mWaitTimeout_min) { + if(mIsRetransmit) { // we already have been through... + mWaitTimeout = mWaitTimeout_min; + } else if(q->iv->mGotFragment) { // nothing received yet? + if(q->iv->mGotLastMsg) { + //mState = States::CHECK_FRAMES; + mWaitTimeout = mWaitTimeout_min; + } + } else if(mFirstTry) { + if(*mSerialDebug) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(String(millis() - mWaitTimeout_min + mlastTO_min)); + DBGPRINTLN(F("ms - second try")); + } + mFirstTry = false; + mlastTO_min = timeout_min; + q->iv->radioStatistics.retransmits++; // got nothing + mState = States::START; + break; + } + + }*/ + if(millis() < mWaitTimeout) + return; + mState = States::CHECK_FRAMES; + break; + + case States::CHECK_FRAMES: { + if((q->iv->radio->mBufCtrl.empty() && !mIsRetransmit) || (0 == q->attempts)) { // radio buffer empty or no more answers + if(*mSerialDebug) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("request timeout: ")); + DBGPRINT(String(millis() - mWaitTimeout + timeout)); + DBGPRINTLN(F("ms")); + } + if(!q->iv->mGotFragment) { + if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { + q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, (q->iv->config->frequency*FREQ_STEP_KHZ + HOY_BASE_FREQ_KHZ)); + mWaitTimeout = millis() + 1000; + } + } + closeRequest(q, false); + break; + } + mFirstTry = false; // for correct reset + if((IV_MI != q->iv->ivGen) || (0 == q->attempts)) + mIsRetransmit = false; + + while(!q->iv->radio->mBufCtrl.empty()) { + packet_t *p = &q->iv->radio->mBufCtrl.front(); + printRxInfo(q, p); + + if(validateIvSerial(&p->packet[1], q->iv)) { + q->iv->radioStatistics.frmCnt++; + q->iv->mDtuRxCnt++; + + if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command + if(parseFrame(p)) + q->iv->curFrmCnt++; + } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command + if(parseDevCtrl(p, q)) + closeRequest(q, true); + else + closeRequest(q, false); + q->iv->radio->mBufCtrl.pop(); + return; // don't wait for empty buffer + } else if(IV_MI == q->iv->ivGen) { + if(parseMiFrame(p, q)) + q->iv->curFrmCnt++; + } + } //else -> serial does not match + + q->iv->radio->mBufCtrl.pop(); + yield(); + } + + if(0 == q->attempts) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("no attempts left")); + closeRequest(q, false); + } else { + if(q->iv->ivGen != IV_MI) { + mState = States::CHECK_PACKAGE; + } else { + bool fastNext = true; + if(q->iv->miMultiParts < 6) { + mState = States::WAIT; + if((millis() > mWaitTimeout && mIsRetransmit) || !mIsRetransmit) { + miRepeatRequest(q); + return; + } + } else { + mHeu.evalTxChQuality(q->iv, true, (4 - q->attempts), q->iv->curFrmCnt); + if(((q->cmd == 0x39) && (q->iv->type == INV_TYPE_4CH)) + || ((q->cmd == MI_REQ_CH2) && (q->iv->type == INV_TYPE_2CH)) + || ((q->cmd == MI_REQ_CH1) && (q->iv->type == INV_TYPE_1CH))) { + miComplete(q->iv); + fastNext = false; + } + if(fastNext) + miNextRequest(q->iv->type == INV_TYPE_4CH ? MI_REQ_4CH : MI_REQ_CH1, q); + else + closeRequest(q, true); + } + } + } + + } + break; + + case States::CHECK_PACKAGE: + uint8_t framnr = 0; + if(0 == mMaxFrameId) { + uint8_t i = 0; + while(i < MAX_PAYLOAD_ENTRIES) { + if(mLocalBuf[i].len == 0) { + framnr = i+1; + break; + } + i++; + } + } + + if(!framnr) { + for(uint8_t i = 0; i < mMaxFrameId; i++) { + if(mLocalBuf[i].len == 0) { + framnr = i+1; + break; + } + } + } + + if(framnr) { + setAttempt(); + + if(*mSerialDebug) { + DPRINT_IVID(DBG_WARN, q->iv->id); + DBGPRINT(F("frame ")); + DBGPRINT(String(framnr)); + DBGPRINT(F(" missing: request retransmit (")); + DBGPRINT(String(q->attempts)); + DBGPRINTLN(F(" attempts left)")); + } + if (!mIsRetransmit) + q->iv->mIsSingleframeReq = true; + sendRetransmit(q, (framnr-1)); + mIsRetransmit = true; + mlastTO_min = timeout_min; + return; + } + + compilePayload(q); + + if((NULL != mCbPayload) && (GridOnProFilePara != q->cmd) && (GetLossRate != q->cmd)) + (mCbPayload)(q->cmd, q->iv); + + closeRequest(q, true); + break; + } + }); + } + + private: + inline void printRxInfo(const queue_s *q, packet_t *p) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("RX ")); + if(p->millis < 100) + DBGPRINT(F(" ")); + DBGPRINT(String(p->millis)); + DBGPRINT(F("ms | ")); + DBGPRINT(String(p->len)); + if((IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen)) { + DBGPRINT(F(" CH")); + if(3 == p->ch) + DBGPRINT(F("0")); + DBGPRINT(String(p->ch)); + DBGPRINT(F(" ")); + } else { + DBGPRINT(F(" ")); + DBGPRINT(String(p->rssi)); + DBGPRINT(F("dBm | ")); + } + if(*mPrintWholeTrace) { + if(*mPrivacyMode) + ah::dumpBuf(p->packet, p->len, 1, 8); + else + ah::dumpBuf(p->packet, p->len); + } else { + DBGPRINT(F("| ")); + DHEX(p->packet[0]); + DBGPRINT(F(" ")); + DBGHEXLN(p->packet[9]); + } + } + + inline bool validateIvSerial(uint8_t buf[], Inverter<> *iv) { + uint8_t tmp[4]; + CP_U32_BigEndian(tmp, iv->radioId.u64 >> 8); + for(uint8_t i = 0; i < 4; i++) { + if(tmp[i] != buf[i]) { + DPRINT(DBG_WARN, F("Inverter serial does not match, got: 0x")); + DHEX(buf[0]);DHEX(buf[1]);DHEX(buf[2]);DHEX(buf[3]); + DBGPRINT(F(", expected: 0x")); + DHEX(tmp[0]);DHEX(tmp[1]);DHEX(tmp[2]);DHEX(tmp[3]); + DBGPRINTLN(""); + return false; + } + } + return true; + } + + inline bool checkFrameCrc(uint8_t buf[], uint8_t len) { + return (ah::crc8(buf, len - 1) == buf[len-1]); + } + + inline bool parseFrame(packet_t *p) { + uint8_t *frameId = &p->packet[9]; + if(0x00 == *frameId) { + DPRINTLN(DBG_WARN, F("invalid frameId 0x00")); + return false; // skip current packet + } + if((*frameId & 0x7f) > MAX_PAYLOAD_ENTRIES) { + DPRINTLN(DBG_WARN, F("local buffer to small for payload fragments")); + return false; // local storage is to small for id + } + + if(!checkFrameCrc(p->packet, p->len)) { + DPRINTLN(DBG_WARN, F("frame CRC is wrong")); + return false; // CRC8 is wrong, frame invalid + } + + if((*frameId & ALL_FRAMES) == ALL_FRAMES) { + mMaxFrameId = (*frameId & 0x7f); + if(mMaxFrameId > 8) // large payloads, e.g. AlarmData + incrAttempt(mMaxFrameId - 6); + } + + frame_t *f = &mLocalBuf[(*frameId & 0x7f) - 1]; + memcpy(f->buf, &p->packet[10], p->len-11); + f->len = p->len - 11; + f->rssi = p->rssi; + + return true; + } + + inline bool parseMiFrame(packet_t *p, const queue_s *q) { + if ((p->packet[0] == MI_REQ_CH1 + ALL_FRAMES) + || (p->packet[0] == MI_REQ_CH2 + ALL_FRAMES) + || ((p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES)) + && (p->packet[0] < (0x39 + SINGLE_FRAME)) + )) { //&& (p->packet[0] != (0x0f + ALL_FRAMES)))) { + // small MI or MI 1500 data responses to 0x09, 0x11, 0x36, 0x37, 0x38 and 0x39 + //mPayload[iv->id].txId = p->packet[0]; + miDataDecode(p, q); + } else if (p->packet[0] == (0x0f + ALL_FRAMES)) + miHwDecode(p, q); + else if ((p->packet[0] == 0x88) || (p->packet[0] == 0x92)) { + record_t<> *rec = q->iv->getRecordStruct(RealTimeRunData_Debug); // choose the record structure + rec->ts = q->ts; + miStsConsolidate(q, ((p->packet[0] == 0x88) ? 1 : 2), rec, p->packet[10], p->packet[12], p->packet[9], p->packet[11]); + //mHeu.setGotFragment(q->iv); only do this when we are through the cycle? + } + + return true; + } + + inline bool parseDevCtrl(packet_t *p, const queue_s *q) { + if((p->packet[12] != ActivePowerContr) || (p->packet[13] != 0x00)) + return false; + bool accepted = true; + if((p->packet[10] == 0x00) && (p->packet[11] == 0x00)) + q->iv->powerLimitAck = true; + else + accepted = false; + + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("has ")); + if(!accepted) DBGPRINT(F("not ")); + DBGPRINT(F("accepted power limit set point ")); + DBGPRINT(String(q->iv->powerLimit[0])); + DBGPRINT(F(" with PowerLimitControl ")); + DBGPRINTLN(String(q->iv->powerLimit[1])); + q->iv->actPowerLimit = 0xffff; // unknown, readback current value + + return accepted; + } + + inline void compilePayload(const queue_s *q) { + uint16_t crc = 0xffff, crcRcv = 0x0000; + for(uint8_t i = 0; i < mMaxFrameId; i++) { + if(i == (mMaxFrameId - 1)) { + crc = ah::crc16(mLocalBuf[i].buf, mLocalBuf[i].len - 2, crc); + crcRcv = (mLocalBuf[i].buf[mLocalBuf[i].len-2] << 8); + crcRcv |= mLocalBuf[i].buf[mLocalBuf[i].len-1]; + } else + crc = ah::crc16(mLocalBuf[i].buf, mLocalBuf[i].len, crc); + } + + if(crc != crcRcv) { + DPRINT_IVID(DBG_WARN, q->iv->id); + DBGPRINT(F("CRC Error ")); + if(q->attempts == 0) { + DBGPRINTLN(F("-> Fail")); + closeRequest(q, false); + + } else + DBGPRINTLN(F("-> complete retransmit")); + mState = States::RESET; + return; + } + + /*DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("procPyld: cmd: 0x")); + DBGHEXLN(q->cmd);*/ + + memset(mPayload, 0, MAX_BUFFER); + int8_t rssi = -127; + uint8_t len = 0; + + for(uint8_t i = 0; i < mMaxFrameId; i++) { + if(mLocalBuf[i].len + len > MAX_BUFFER) { + DPRINTLN(DBG_ERROR, F("payload buffer to small!")); + return; + } + memcpy(&mPayload[len], mLocalBuf[i].buf, mLocalBuf[i].len); + len += mLocalBuf[i].len; + // get worst RSSI (high value is better) + if(mLocalBuf[i].rssi > rssi) + rssi = mLocalBuf[i].rssi; + } + + len -= 2; + + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("Payload (")); + DBGPRINT(String(len)); + if(*mPrintWholeTrace) { + DBGPRINT(F("): ")); + ah::dumpBuf(mPayload, len); + } else + DBGPRINTLN(F(")")); + + if(GridOnProFilePara == q->cmd) { + q->iv->addGridProfile(mPayload, len); + return; + } + + record_t<> *rec = q->iv->getRecordStruct(q->cmd); + if(NULL == rec) { + if(GetLossRate == q->cmd) { + q->iv->parseGetLossRate(mPayload, len); + //closeRequest(q, true); //@lumapu: Activating would crash most esp's! + return; + } else { + DPRINTLN(DBG_ERROR, F("record is NULL!")); + closeRequest(q, false); + } + return; + } + if((rec->pyldLen != len) && (0 != rec->pyldLen)) { + if(*mSerialDebug) { + DPRINT(DBG_ERROR, F("plausibility check failed, expected ")); + DBGPRINT(String(rec->pyldLen)); + DBGPRINTLN(F(" bytes")); + } + /*q->iv->radioStatistics.rxFail++;*/ + closeRequest(q, false); + + return; + } + + rec->ts = q->ts; + for (uint8_t i = 0; i < rec->length; i++) { + q->iv->addValue(i, mPayload, rec); + } + + q->iv->rssi = rssi; + q->iv->doCalculations(); + + if(AlarmData == q->cmd) { + uint8_t i = 0; + while(1) { + if(0 == q->iv->parseAlarmLog(i++, mPayload, len)) + break; + if (NULL != mCbAlarm) + (mCbAlarm)(q->iv); + yield(); + } + } + } + + void sendRetransmit(const queue_s *q, uint8_t i) { + if(q->attempts) { + q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true); + q->iv->radioStatistics.retransmits++; + mWaitTimeout = millis() + SINGLEFR_TIMEOUT; // timeout + mState = States::WAIT; + } else { + //add(q, true); + closeRequest(q, false); + } + } + + private: + void closeRequest(const queue_s *q, bool crcPass) { + mHeu.evalTxChQuality(q->iv, crcPass, (4 - q->attempts), q->iv->curFrmCnt); + if(crcPass) + q->iv->radioStatistics.rxSuccess++; + else if(q->iv->mGotFragment) + q->iv->radioStatistics.rxFail++; // got no complete payload + else + q->iv->radioStatistics.rxFailNoAnser++; // got nothing + mWaitTimeout = millis() + *mInverterGap; + + bool keep = false; + if(q->isDevControl) + keep = !crcPass; + + cmdDone(keep); + q->iv->mGotFragment = false; + q->iv->mGotLastMsg = false; + q->iv->miMultiParts = 0; + mIsRetransmit = false; + mFirstTry = false; // for correct reset + mState = States::RESET; + DBGPRINTLN(F("-----")); + } + + inline void miHwDecode(packet_t *p, const queue_s *q) { + record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_All); // choose the record structure + rec->ts = q->ts; + /* + 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_BOOTLOADER_VER, UNIT_NONE, CH0, 8, 2, 1 } + }; + */ + + if ( p->packet[9] == 0x00 ) {//first frame + //FLD_FW_VERSION + for (uint8_t i = 0; i < 5; i++) { + q->iv->setValue(i, rec, (float) ((p->packet[(12+2*i)] << 8) + p->packet[(13+2*i)])/1); + } + q->iv->isConnected = true; + if(*mSerialDebug) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("HW_VER is ")); + DBGPRINTLN(String((p->packet[24] << 8) + p->packet[25])); + } + record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure + rec->ts = q->ts; + q->iv->setValue(1, rec, (uint32_t) ((p->packet[24] << 8) + p->packet[25])/1); + q->iv->miMultiParts +=4; + } else if ( p->packet[9] == 0x01 || p->packet[9] == 0x10 ) {//second frame for MI, 3rd gen. answers in 0x10 + DPRINT_IVID(DBG_INFO, q->iv->id); + if ( p->packet[9] == 0x01 ) { + DBGPRINTLN(F("got 2nd frame (hw info)")); + /* according to xlsx (different start byte -1!) + byte[11] to byte[14] HW_PN + byte[15] byte[16] HW_FB_TLmValue + byte[17] byte[18] HW_FB_ReSPRT + byte[19] byte[20] HW_GridSamp_ResValule + byte[21] byte[22] HW_ECapValue + byte[23] to byte[26] Matching_APPFW_PN*/ + 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])); + record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure + rec->ts = q->ts; + q->iv->setValue(0, rec, (uint32_t) ((((p->packet[10] << 8) | p->packet[11]) << 8 | p->packet[12]) << 8 | p->packet[13])/1); + + if(*mSerialDebug) { + DPRINT(DBG_INFO,F("HW_FB_TLmValue ")); + DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15])); + DBGPRINT(F("HW_FB_ReSPRT ")); + DBGPRINTLN(String((p->packet[16] << 8) + p->packet[17])); + DBGPRINT(F("HW_GridSamp_ResValule ")); + DBGPRINTLN(String((p->packet[18] << 8) + p->packet[19])); + DBGPRINT(F("HW_ECapValue ")); + DBGPRINTLN(String((p->packet[20] << 8) + p->packet[21])); + DBGPRINT(F("Matching_APPFW_PN ")); + DBGPRINTLN(String((uint32_t) (((p->packet[22] << 8) | p->packet[23]) << 8 | p->packet[24]) << 8 | p->packet[25])); + } + if(NULL != mCbPayload) + (mCbPayload)(InverterDevInform_All, q->iv); + q->iv->miMultiParts +=2; + + } else { + DBGPRINTLN(F("3rd gen. inverter!")); + } + + } else if ( p->packet[9] == 0x12 ) {//3rd frame + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINTLN(F("got 3rd frame (hw info)")); + /* according to xlsx (different start byte -1!) + byte[11] byte[12] APPFW_MINVER + byte[13] byte[14] HWInfoAddr + byte[15] byte[16] PNInfoCRC_gusv + byte[15] byte[16] PNInfoCRC_gusv (this really is double mentionned in xlsx...) + */ + if(*mSerialDebug) { + DPRINT(DBG_INFO,F("APPFW_MINVER ")); + DBGPRINTLN(String((p->packet[10] << 8) + p->packet[11])); + DBGPRINT(F("HWInfoAddr ")); + DBGPRINTLN(String((p->packet[12] << 8) + p->packet[13])); + DBGPRINT(F("PNInfoCRC_gusv ")); + DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15])); + } + if(NULL != mCbPayload) + (mCbPayload)(InverterDevInform_Simple, q->iv); + q->iv->miMultiParts++; + } + //if(q->iv->miMultiParts > 5) + //closeRequest(q->iv, true); + //else + //if(q->iv->miMultiParts < 6) + // mState = States::WAIT; + + /*if (mPayload[iv->id].multi_parts > 5) { + iv->setQueuedCmdFinished(); + mPayload[iv->id].complete = true; + mPayload[iv->id].rxTmo = true; + mPayload[iv->id].requested= false; + iv->radioStatistics.rxSuccess++; + } + if (mHighPrioIv == NULL) + mHighPrioIv = iv; + */ + } + + inline void miDataDecode(packet_t *p, const queue_s *q) { + record_t<> *rec = q->iv->getRecordStruct(RealTimeRunData_Debug); // choose the parser + rec->ts = q->ts; + //mState = States::RESET; + if(q->iv->miMultiParts < 6) + q->iv->miMultiParts += 6; + + uint8_t datachan = ( p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES) || p->packet[0] == (MI_REQ_4CH + ALL_FRAMES) ) ? CH1 : + ( p->packet[0] == (MI_REQ_CH2 + ALL_FRAMES) || p->packet[0] == (0x37 + ALL_FRAMES) ) ? CH2 : + p->packet[0] == (0x38 + ALL_FRAMES) ? CH3 : + CH4; + // count in RF_communication_protocol.xlsx is with offset = -1 + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_UDC, rec), rec, (float)((p->packet[9] << 8) + p->packet[10])/10); + + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_IDC, rec), rec, (float)((p->packet[11] << 8) + p->packet[12])/10); + + q->iv->setValue(q->iv->getPosByChFld(0, FLD_UAC, rec), rec, (float)((p->packet[13] << 8) + p->packet[14])/10); + + q->iv->setValue(q->iv->getPosByChFld(0, FLD_F, rec), rec, (float) ((p->packet[15] << 8) + p->packet[16])/100); + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_PDC, rec), rec, (float)((p->packet[17] << 8) + p->packet[18])/10); + + q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_YD, rec), rec, (float)((p->packet[19] << 8) + p->packet[20])/1); + + q->iv->setValue(q->iv->getPosByChFld(0, FLD_T, rec), rec, (float) ((int16_t)(p->packet[21] << 8) + p->packet[22])/10); + q->iv->setValue(q->iv->getPosByChFld(0, FLD_IRR, rec), rec, (float) (calcIrradiation(q->iv, datachan))); + + if (datachan == 1) + q->iv->rssi = p->rssi; + else if(q->iv->rssi > p->rssi) + q->iv->rssi = p->rssi; + + if (p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES) ) { + /*For MI1500: + if (MI1500) { + STAT = (uint8_t)(p->packet[25] ); + FCNT = (uint8_t)(p->packet[26]); + FCODE = (uint8_t)(p->packet[27]); + }*/ + miStsConsolidate(q, datachan, rec, p->packet[23], p->packet[24]); + + if (p->packet[0] < (0x39 + ALL_FRAMES) ) { + mHeu.evalTxChQuality(q->iv, true, (4 - q->attempts), 1); + miNextRequest((p->packet[0] - ALL_FRAMES + 1), q); + } else { + q->iv->miMultiParts = 7; // indicate we are ready + //miComplete(q->iv); + } + } else if((p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES)) && (q->iv->type == INV_TYPE_2CH)) { + //addImportant(q->iv, MI_REQ_CH2); + miNextRequest(MI_REQ_CH2, q); + mHeu.evalTxChQuality(q->iv, true, (4 - q->attempts), q->iv->curFrmCnt); + //use also miMultiParts here for better statistics? + //mHeu.setGotFragment(q->iv); + } else { // first data msg for 1ch, 2nd for 2ch + q->iv->miMultiParts += 6; // indicate we are ready + //miComplete(q->iv); + } + } + + void miNextRequest(uint8_t cmd, const queue_s *q) { + incrAttempt(); // if function is called, we got something, and we necessarily need more transmissions for MI types... + if(*mSerialDebug) { + DPRINT_IVID(DBG_WARN, q->iv->id); + DBGPRINT(F("next request (")); + DBGPRINT(String(q->attempts)); + DBGPRINT(F(" attempts left): 0x")); + DBGHEXLN(cmd); + } + + if(q->iv->miMultiParts == 7) { + //mHeu.setGotAll(q->iv); + q->iv->radioStatistics.rxSuccess++; + } else + //mHeu.setGotFragment(q->iv); + /*iv->radioStatistics.rxFail++; // got no complete payload*/ + //q->iv->radioStatistics.retransmits++; + q->iv->radio->sendCmdPacket(q->iv, cmd, 0x00, true); + + mWaitTimeout = millis() + MI_TIMEOUT; + mWaitTimeout_min = mWaitTimeout; + q->iv->miMultiParts = 0; + q->iv->mGotFragment = 0; + mIsRetransmit = true; + chgCmd(cmd); + //mState = States::WAIT; + } + + void miRepeatRequest(const queue_s *q) { + setAttempt(); // if function is called, we got something, and we necessarily need more transmissions for MI types... + if(*mSerialDebug) { + DPRINT_IVID(DBG_WARN, q->iv->id); + DBGPRINT(F("resend request (")); + DBGPRINT(String(q->attempts)); + DBGPRINT(F(" attempts left): 0x")); + DBGHEXLN(q->cmd); + } + + q->iv->radio->sendCmdPacket(q->iv, q->cmd, 0x00, true); + + mWaitTimeout = millis() + MI_TIMEOUT; + mWaitTimeout_min = mWaitTimeout; + //mState = States::WAIT; + mIsRetransmit = false; + } + + void miStsConsolidate(const queue_s *q, 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 statusMi = 3; // regular status for MI, change to 1 later? + if ( uState == 2 ) { + statusMi = 5050 + stschan; //first approach, needs review! + if (lState) + statusMi += lState*10; + } else if ( uState > 3 ) { + statusMi = uState*1000 + uEnum*10; + if (lState) + statusMi += lState*100; //needs review, esp. for 4ch-8310 state! + //if (lEnum) + statusMi += lEnum; + if (uEnum < 6) { + statusMi += stschan; + } + if (statusMi == 8000) + statusMi = 8310; //trick? + } + + uint16_t prntsts = statusMi == 3 ? 1 : statusMi; + bool stsok = true; + if ( prntsts != rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)] ) { //sth.'s changed? + q->iv->alarmCnt = 1; // minimum... + stsok = false; + //sth is or was wrong? + if ( (q->iv->type != INV_TYPE_1CH) && ( (statusMi != 3) + || ((q->iv->lastAlarm[stschan].code) && (statusMi == 3) && (q->iv->lastAlarm[stschan].code != 1))) + ) { + q->iv->lastAlarm[stschan+q->iv->type==INV_TYPE_2CH ? 2: 4] = alarm_t(q->iv->lastAlarm[stschan].code, q->iv->lastAlarm[stschan].start,q->ts); + q->iv->lastAlarm[stschan] = alarm_t(prntsts, q->ts,0); + q->iv->alarmCnt = q->iv->type == INV_TYPE_2CH ? 3 : 5; + } else if ( (q->iv->type == INV_TYPE_1CH) && ( (statusMi != 3) + || ((q->iv->lastAlarm[stschan].code) && (statusMi == 3) && (q->iv->lastAlarm[stschan].code != 1))) + ) { + q->iv->lastAlarm[stschan] = alarm_t(q->iv->lastAlarm[0].code, q->iv->lastAlarm[0].start,q->ts); + } else if (q->iv->type == INV_TYPE_1CH) + stsok = true; + + q->iv->alarmLastId = prntsts; //iv->alarmMesIndex; + + if (q->iv->alarmCnt > 1) { //more than one channel + for (uint8_t ch = 0; ch < (q->iv->alarmCnt); ++ch) { //start with 1 + if (q->iv->lastAlarm[ch].code == 1) { + stsok = true; + break; + } + } + } + if(*mSerialDebug) { + DPRINT(DBG_WARN, F("New state on CH")); + DBGPRINT(String(stschan)); DBGPRINT(F(" (")); + DBGPRINT(String(prntsts)); DBGPRINT(F("): ")); + DBGPRINTLN(q->iv->getAlarmStr(prntsts)); + } + if(!q->iv->miMultiParts) + q->iv->miMultiParts = 1; // indicate we got status info (1+2 ch types) + } + + if (!stsok) { + q->iv->setValue(q->iv->getPosByChFld(0, FLD_EVT, rec), rec, prntsts); + q->iv->lastAlarm[0] = alarm_t(prntsts, q->ts, 0); + } + + if (q->iv->alarmMesIndex < rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)]) { + q->iv->alarmMesIndex = rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)]; // seems there's no status per channel in 3rd gen. models?!? + if (*mSerialDebug) { + DPRINT_IVID(DBG_INFO, q->iv->id); + DBGPRINT(F("alarm ID incremented to ")); + DBGPRINTLN(String(q->iv->alarmMesIndex)); + } + } + } + + + void miComplete(Inverter<> *iv) { + if (*mSerialDebug) { + DPRINT_IVID(DBG_INFO, iv->id); + DBGPRINTLN(F("got all data 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; + if (iv->type == INV_TYPE_1CH) { + if ((!iv->lastAlarm[0].code) || (iv->lastAlarm[0].code == 1)) + ac_pow += iv->getValue(iv->getPosByChFld(1, FLD_PDC, rec), rec); + } else { + for(uint8_t i = 1; i <= iv->channels; i++) { + if ((!iv->lastAlarm[i].code) || (iv->lastAlarm[i].code == 1)) { + 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(); + // update status state-machine, + if (ac_pow) + iv->isProducing(); + //closeRequest(iv, iv->miMultiParts > 5); + + //mHeu.setGotAll(iv); + //cmdDone(false); + if(NULL != mCbPayload) + (mCbPayload)(RealTimeRunData_Debug, iv); + + //mState = States::RESET; // everything ok, next request + } + + private: + enum class States : uint8_t { + RESET, START, WAIT, CHECK_FRAMES, CHECK_PACKAGE + }; + + typedef struct { + uint8_t buf[MAX_RF_PAYLOAD_SIZE]; + uint8_t len; + int8_t rssi; + } frame_t; + + private: + States mState = States::RESET; + uint32_t *mTimestamp; + bool *mPrivacyMode, *mSerialDebug, *mPrintWholeTrace; + uint16_t *mInverterGap; + uint32_t mWaitTimeout = 0; + uint32_t mWaitTimeout_min = 0; + std::array mLocalBuf; + bool mFirstTry = false; // see, if we should do a second try + bool mIsRetransmit = false; // we alrady had waited one complete cycle + uint16_t mlastTO_min = DEFAULT_TIMEOUT; // remember timeout_min for correct calculation + uint8_t mMaxFrameId; + uint8_t mPayload[MAX_BUFFER]; + payloadListenerType mCbPayload = NULL; + alarmListenerType mCbAlarm = NULL; + Heuristic mHeu; + uint32_t mLastEmptyQueueMillis = 0; + bool mPrintSequenceDuration = false; + + //States mDebugState = States::START; +}; + +#endif /*__COMMUNICATION_H__*/ From 2ab73d9627930b3d8366558cab27741e9f7c6ad6 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 28 Dec 2023 20:56:08 +0100 Subject: [PATCH 251/267] fix double counts From 8a489ca14c4efc97c41a3457a6c739cbdba2f426 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 28 Dec 2023 20:59:22 +0100 Subject: [PATCH 252/267] Delete Communication.h wrong place... --- Communication.h | 930 ------------------------------------------------ 1 file changed, 930 deletions(-) delete mode 100644 Communication.h diff --git a/Communication.h b/Communication.h deleted file mode 100644 index 9cf8fcb7..00000000 --- a/Communication.h +++ /dev/null @@ -1,930 +0,0 @@ -//----------------------------------------------------------------------------- -// 2023 Ahoy, https://github.com/lumpapu/ahoy -// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed -//----------------------------------------------------------------------------- - -#ifndef __COMMUNICATION_H__ -#define __COMMUNICATION_H__ - -#include "CommQueue.h" -#include -#include "../utils/crc.h" -#include "Heuristic.h" - -#define MI_TIMEOUT 250 // timeout for MI type requests -#define FRSTMSG_TIMEOUT 150 // how long to wait for first msg to be received -#define DEFAULT_TIMEOUT 500 // timeout for regular requests -#define SINGLEFR_TIMEOUT 100 // timeout for single frame requests -#define MAX_BUFFER 250 - -typedef std::function *)> payloadListenerType; -typedef std::function *)> alarmListenerType; - -class Communication : public CommQueue<> { - public: - void setup(uint32_t *timestamp, bool *serialDebug, bool *privacyMode, bool *printWholeTrace, uint16_t *inverterGap) { - mTimestamp = timestamp; - mPrivacyMode = privacyMode; - mSerialDebug = serialDebug; - mPrintWholeTrace = printWholeTrace; - mInverterGap = inverterGap; - } - - void addImportant(Inverter<> *iv, uint8_t cmd) { - mState = States::RESET; // cancel current operation - CommQueue::addImportant(iv, cmd); - } - - void addPayloadListener(payloadListenerType cb) { - mCbPayload = cb; - } - - void addAlarmListener(alarmListenerType cb) { - mCbAlarm = cb; - } - - void loop() { - get([this](bool valid, const queue_s *q) { - if(!valid) { - if(mPrintSequenceDuration) { - mPrintSequenceDuration = false; - DPRINT(DBG_INFO, F("com loop duration: ")); - DBGPRINT(String(millis() - mLastEmptyQueueMillis)); - DBGPRINTLN(F("ms")); - DBGPRINTLN(F("-----")); - } - return; // empty - } - if(!mPrintSequenceDuration) // entry was added to the queue - mLastEmptyQueueMillis = millis(); - mPrintSequenceDuration = true; - - uint16_t timeout = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : (((q->iv->mGotFragment && q->iv->mGotLastMsg) || mIsRetransmit) ? SINGLEFR_TIMEOUT : ((q->cmd != AlarmData) && q->cmd != GridOnProFilePara ? DEFAULT_TIMEOUT : (1.5 * DEFAULT_TIMEOUT))); - uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment || mIsRetransmit)) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT; - - /*if(mDebugState != mState) { - DPRINT(DBG_INFO, F("State: ")); - DBGHEXLN((uint8_t)(mState)); - mDebugState = mState; - }*/ - switch(mState) { - case States::RESET: - if(millis() < mWaitTimeout) - return; - mMaxFrameId = 0; - for(uint8_t i = 0; i < MAX_PAYLOAD_ENTRIES; i++) { - mLocalBuf[i].len = 0; - } - - if(*mSerialDebug) - mHeu.printStatus(q->iv); - mHeu.getTxCh(q->iv); - q->iv->mGotFragment = false; - q->iv->mGotLastMsg = false; - q->iv->curFrmCnt = 0; - mIsRetransmit = false; - if(NULL == q->iv->radio) - cmdDone(false); // can't communicate while radio is not defined! - q->iv->mCmd = q->cmd; - q->iv->mIsSingleframeReq = false; - mState = States::START; - break; - - case States::START: - setTs(mTimestamp); - if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { - // frequency was changed during runtime - if(q->iv->curCmtFreq != q->iv->config->frequency) { - if(q->iv->radio->switchFrequencyCh(q->iv, q->iv->curCmtFreq, q->iv->config->frequency)) - q->iv->curCmtFreq = q->iv->config->frequency; - } - } - - if(q->isDevControl) { - if(ActivePowerContr == q->cmd) - q->iv->powerLimitAck = false; - q->iv->radio->sendControlPacket(q->iv, q->cmd, q->iv->powerLimit, false); - } else - q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); - - q->iv->radioStatistics.txCnt++; - mWaitTimeout = millis() + timeout; - mWaitTimeout_min = millis() + timeout_min; - mIsRetransmit = false; - mlastTO_min = timeout_min; - setAttempt(); - if(q->cmd == AlarmData || q->cmd == GridOnProFilePara) - incrAttempt(q->cmd == AlarmData? 5 : 3); - - mState = States::WAIT; - break; - - case States::WAIT: - /*if(millis() > mWaitTimeout_min) { - if(mIsRetransmit) { // we already have been through... - mWaitTimeout = mWaitTimeout_min; - } else if(q->iv->mGotFragment) { // nothing received yet? - if(q->iv->mGotLastMsg) { - //mState = States::CHECK_FRAMES; - mWaitTimeout = mWaitTimeout_min; - } - } else if(mFirstTry) { - if(*mSerialDebug) { - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(String(millis() - mWaitTimeout_min + mlastTO_min)); - DBGPRINTLN(F("ms - second try")); - } - mFirstTry = false; - mlastTO_min = timeout_min; - q->iv->radioStatistics.retransmits++; // got nothing - mState = States::START; - break; - } - - }*/ - if(millis() < mWaitTimeout) - return; - mState = States::CHECK_FRAMES; - break; - - case States::CHECK_FRAMES: { - if((q->iv->radio->mBufCtrl.empty() && !mIsRetransmit) || (0 == q->attempts)) { // radio buffer empty or no more answers - if(*mSerialDebug) { - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("request timeout: ")); - DBGPRINT(String(millis() - mWaitTimeout + timeout)); - DBGPRINTLN(F("ms")); - } - if(!q->iv->mGotFragment) { - if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { - q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, (q->iv->config->frequency*FREQ_STEP_KHZ + HOY_BASE_FREQ_KHZ)); - mWaitTimeout = millis() + 1000; - } - } - closeRequest(q, false); - break; - } - mFirstTry = false; // for correct reset - if((IV_MI != q->iv->ivGen) || (0 == q->attempts)) - mIsRetransmit = false; - - while(!q->iv->radio->mBufCtrl.empty()) { - packet_t *p = &q->iv->radio->mBufCtrl.front(); - printRxInfo(q, p); - - if(validateIvSerial(&p->packet[1], q->iv)) { - q->iv->radioStatistics.frmCnt++; - q->iv->mDtuRxCnt++; - - if (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES)) { // response from get information command - if(parseFrame(p)) - q->iv->curFrmCnt++; - } else if (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES)) { // response from dev control command - if(parseDevCtrl(p, q)) - closeRequest(q, true); - else - closeRequest(q, false); - q->iv->radio->mBufCtrl.pop(); - return; // don't wait for empty buffer - } else if(IV_MI == q->iv->ivGen) { - if(parseMiFrame(p, q)) - q->iv->curFrmCnt++; - } - } //else -> serial does not match - - q->iv->radio->mBufCtrl.pop(); - yield(); - } - - if(0 == q->attempts) { - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("no attempts left")); - closeRequest(q, false); - } else { - if(q->iv->ivGen != IV_MI) { - mState = States::CHECK_PACKAGE; - } else { - bool fastNext = true; - if(q->iv->miMultiParts < 6) { - mState = States::WAIT; - if((millis() > mWaitTimeout && mIsRetransmit) || !mIsRetransmit) { - miRepeatRequest(q); - return; - } - } else { - mHeu.evalTxChQuality(q->iv, true, (4 - q->attempts), q->iv->curFrmCnt); - if(((q->cmd == 0x39) && (q->iv->type == INV_TYPE_4CH)) - || ((q->cmd == MI_REQ_CH2) && (q->iv->type == INV_TYPE_2CH)) - || ((q->cmd == MI_REQ_CH1) && (q->iv->type == INV_TYPE_1CH))) { - miComplete(q->iv); - fastNext = false; - } - if(fastNext) - miNextRequest(q->iv->type == INV_TYPE_4CH ? MI_REQ_4CH : MI_REQ_CH1, q); - else - closeRequest(q, true); - } - } - } - - } - break; - - case States::CHECK_PACKAGE: - uint8_t framnr = 0; - if(0 == mMaxFrameId) { - uint8_t i = 0; - while(i < MAX_PAYLOAD_ENTRIES) { - if(mLocalBuf[i].len == 0) { - framnr = i+1; - break; - } - i++; - } - } - - if(!framnr) { - for(uint8_t i = 0; i < mMaxFrameId; i++) { - if(mLocalBuf[i].len == 0) { - framnr = i+1; - break; - } - } - } - - if(framnr) { - setAttempt(); - - if(*mSerialDebug) { - DPRINT_IVID(DBG_WARN, q->iv->id); - DBGPRINT(F("frame ")); - DBGPRINT(String(framnr)); - DBGPRINT(F(" missing: request retransmit (")); - DBGPRINT(String(q->attempts)); - DBGPRINTLN(F(" attempts left)")); - } - if (!mIsRetransmit) - q->iv->mIsSingleframeReq = true; - sendRetransmit(q, (framnr-1)); - mIsRetransmit = true; - mlastTO_min = timeout_min; - return; - } - - compilePayload(q); - - if((NULL != mCbPayload) && (GridOnProFilePara != q->cmd) && (GetLossRate != q->cmd)) - (mCbPayload)(q->cmd, q->iv); - - closeRequest(q, true); - break; - } - }); - } - - private: - inline void printRxInfo(const queue_s *q, packet_t *p) { - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("RX ")); - if(p->millis < 100) - DBGPRINT(F(" ")); - DBGPRINT(String(p->millis)); - DBGPRINT(F("ms | ")); - DBGPRINT(String(p->len)); - if((IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen)) { - DBGPRINT(F(" CH")); - if(3 == p->ch) - DBGPRINT(F("0")); - DBGPRINT(String(p->ch)); - DBGPRINT(F(" ")); - } else { - DBGPRINT(F(" ")); - DBGPRINT(String(p->rssi)); - DBGPRINT(F("dBm | ")); - } - if(*mPrintWholeTrace) { - if(*mPrivacyMode) - ah::dumpBuf(p->packet, p->len, 1, 8); - else - ah::dumpBuf(p->packet, p->len); - } else { - DBGPRINT(F("| ")); - DHEX(p->packet[0]); - DBGPRINT(F(" ")); - DBGHEXLN(p->packet[9]); - } - } - - inline bool validateIvSerial(uint8_t buf[], Inverter<> *iv) { - uint8_t tmp[4]; - CP_U32_BigEndian(tmp, iv->radioId.u64 >> 8); - for(uint8_t i = 0; i < 4; i++) { - if(tmp[i] != buf[i]) { - DPRINT(DBG_WARN, F("Inverter serial does not match, got: 0x")); - DHEX(buf[0]);DHEX(buf[1]);DHEX(buf[2]);DHEX(buf[3]); - DBGPRINT(F(", expected: 0x")); - DHEX(tmp[0]);DHEX(tmp[1]);DHEX(tmp[2]);DHEX(tmp[3]); - DBGPRINTLN(""); - return false; - } - } - return true; - } - - inline bool checkFrameCrc(uint8_t buf[], uint8_t len) { - return (ah::crc8(buf, len - 1) == buf[len-1]); - } - - inline bool parseFrame(packet_t *p) { - uint8_t *frameId = &p->packet[9]; - if(0x00 == *frameId) { - DPRINTLN(DBG_WARN, F("invalid frameId 0x00")); - return false; // skip current packet - } - if((*frameId & 0x7f) > MAX_PAYLOAD_ENTRIES) { - DPRINTLN(DBG_WARN, F("local buffer to small for payload fragments")); - return false; // local storage is to small for id - } - - if(!checkFrameCrc(p->packet, p->len)) { - DPRINTLN(DBG_WARN, F("frame CRC is wrong")); - return false; // CRC8 is wrong, frame invalid - } - - if((*frameId & ALL_FRAMES) == ALL_FRAMES) { - mMaxFrameId = (*frameId & 0x7f); - if(mMaxFrameId > 8) // large payloads, e.g. AlarmData - incrAttempt(mMaxFrameId - 6); - } - - frame_t *f = &mLocalBuf[(*frameId & 0x7f) - 1]; - memcpy(f->buf, &p->packet[10], p->len-11); - f->len = p->len - 11; - f->rssi = p->rssi; - - return true; - } - - inline bool parseMiFrame(packet_t *p, const queue_s *q) { - if ((p->packet[0] == MI_REQ_CH1 + ALL_FRAMES) - || (p->packet[0] == MI_REQ_CH2 + ALL_FRAMES) - || ((p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES)) - && (p->packet[0] < (0x39 + SINGLE_FRAME)) - )) { //&& (p->packet[0] != (0x0f + ALL_FRAMES)))) { - // small MI or MI 1500 data responses to 0x09, 0x11, 0x36, 0x37, 0x38 and 0x39 - //mPayload[iv->id].txId = p->packet[0]; - miDataDecode(p, q); - } else if (p->packet[0] == (0x0f + ALL_FRAMES)) - miHwDecode(p, q); - else if ((p->packet[0] == 0x88) || (p->packet[0] == 0x92)) { - record_t<> *rec = q->iv->getRecordStruct(RealTimeRunData_Debug); // choose the record structure - rec->ts = q->ts; - miStsConsolidate(q, ((p->packet[0] == 0x88) ? 1 : 2), rec, p->packet[10], p->packet[12], p->packet[9], p->packet[11]); - //mHeu.setGotFragment(q->iv); only do this when we are through the cycle? - } - - return true; - } - - inline bool parseDevCtrl(packet_t *p, const queue_s *q) { - if((p->packet[12] != ActivePowerContr) || (p->packet[13] != 0x00)) - return false; - bool accepted = true; - if((p->packet[10] == 0x00) && (p->packet[11] == 0x00)) - q->iv->powerLimitAck = true; - else - accepted = false; - - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("has ")); - if(!accepted) DBGPRINT(F("not ")); - DBGPRINT(F("accepted power limit set point ")); - DBGPRINT(String(q->iv->powerLimit[0])); - DBGPRINT(F(" with PowerLimitControl ")); - DBGPRINTLN(String(q->iv->powerLimit[1])); - q->iv->actPowerLimit = 0xffff; // unknown, readback current value - - return accepted; - } - - inline void compilePayload(const queue_s *q) { - uint16_t crc = 0xffff, crcRcv = 0x0000; - for(uint8_t i = 0; i < mMaxFrameId; i++) { - if(i == (mMaxFrameId - 1)) { - crc = ah::crc16(mLocalBuf[i].buf, mLocalBuf[i].len - 2, crc); - crcRcv = (mLocalBuf[i].buf[mLocalBuf[i].len-2] << 8); - crcRcv |= mLocalBuf[i].buf[mLocalBuf[i].len-1]; - } else - crc = ah::crc16(mLocalBuf[i].buf, mLocalBuf[i].len, crc); - } - - if(crc != crcRcv) { - DPRINT_IVID(DBG_WARN, q->iv->id); - DBGPRINT(F("CRC Error ")); - if(q->attempts == 0) { - DBGPRINTLN(F("-> Fail")); - closeRequest(q, false); - - } else - DBGPRINTLN(F("-> complete retransmit")); - mState = States::RESET; - return; - } - - /*DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("procPyld: cmd: 0x")); - DBGHEXLN(q->cmd);*/ - - memset(mPayload, 0, MAX_BUFFER); - int8_t rssi = -127; - uint8_t len = 0; - - for(uint8_t i = 0; i < mMaxFrameId; i++) { - if(mLocalBuf[i].len + len > MAX_BUFFER) { - DPRINTLN(DBG_ERROR, F("payload buffer to small!")); - return; - } - memcpy(&mPayload[len], mLocalBuf[i].buf, mLocalBuf[i].len); - len += mLocalBuf[i].len; - // get worst RSSI (high value is better) - if(mLocalBuf[i].rssi > rssi) - rssi = mLocalBuf[i].rssi; - } - - len -= 2; - - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("Payload (")); - DBGPRINT(String(len)); - if(*mPrintWholeTrace) { - DBGPRINT(F("): ")); - ah::dumpBuf(mPayload, len); - } else - DBGPRINTLN(F(")")); - - if(GridOnProFilePara == q->cmd) { - q->iv->addGridProfile(mPayload, len); - return; - } - - record_t<> *rec = q->iv->getRecordStruct(q->cmd); - if(NULL == rec) { - if(GetLossRate == q->cmd) { - q->iv->parseGetLossRate(mPayload, len); - //closeRequest(q, true); //@lumapu: Activating would crash most esp's! - return; - } else { - DPRINTLN(DBG_ERROR, F("record is NULL!")); - closeRequest(q, false); - } - return; - } - if((rec->pyldLen != len) && (0 != rec->pyldLen)) { - if(*mSerialDebug) { - DPRINT(DBG_ERROR, F("plausibility check failed, expected ")); - DBGPRINT(String(rec->pyldLen)); - DBGPRINTLN(F(" bytes")); - } - /*q->iv->radioStatistics.rxFail++;*/ - closeRequest(q, false); - - return; - } - - rec->ts = q->ts; - for (uint8_t i = 0; i < rec->length; i++) { - q->iv->addValue(i, mPayload, rec); - } - - q->iv->rssi = rssi; - q->iv->doCalculations(); - - if(AlarmData == q->cmd) { - uint8_t i = 0; - while(1) { - if(0 == q->iv->parseAlarmLog(i++, mPayload, len)) - break; - if (NULL != mCbAlarm) - (mCbAlarm)(q->iv); - yield(); - } - } - } - - void sendRetransmit(const queue_s *q, uint8_t i) { - if(q->attempts) { - q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true); - q->iv->radioStatistics.retransmits++; - mWaitTimeout = millis() + SINGLEFR_TIMEOUT; // timeout - mState = States::WAIT; - } else { - //add(q, true); - closeRequest(q, false); - } - } - - private: - void closeRequest(const queue_s *q, bool crcPass) { - mHeu.evalTxChQuality(q->iv, crcPass, (4 - q->attempts), q->iv->curFrmCnt); - if(crcPass) - q->iv->radioStatistics.rxSuccess++; - else if(q->iv->mGotFragment) - q->iv->radioStatistics.rxFail++; // got no complete payload - else - q->iv->radioStatistics.rxFailNoAnser++; // got nothing - mWaitTimeout = millis() + *mInverterGap; - - bool keep = false; - if(q->isDevControl) - keep = !crcPass; - - cmdDone(keep); - q->iv->mGotFragment = false; - q->iv->mGotLastMsg = false; - q->iv->miMultiParts = 0; - mIsRetransmit = false; - mFirstTry = false; // for correct reset - mState = States::RESET; - DBGPRINTLN(F("-----")); - } - - inline void miHwDecode(packet_t *p, const queue_s *q) { - record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_All); // choose the record structure - rec->ts = q->ts; - /* - 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_BOOTLOADER_VER, UNIT_NONE, CH0, 8, 2, 1 } - }; - */ - - if ( p->packet[9] == 0x00 ) {//first frame - //FLD_FW_VERSION - for (uint8_t i = 0; i < 5; i++) { - q->iv->setValue(i, rec, (float) ((p->packet[(12+2*i)] << 8) + p->packet[(13+2*i)])/1); - } - q->iv->isConnected = true; - if(*mSerialDebug) { - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("HW_VER is ")); - DBGPRINTLN(String((p->packet[24] << 8) + p->packet[25])); - } - record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure - rec->ts = q->ts; - q->iv->setValue(1, rec, (uint32_t) ((p->packet[24] << 8) + p->packet[25])/1); - q->iv->miMultiParts +=4; - } else if ( p->packet[9] == 0x01 || p->packet[9] == 0x10 ) {//second frame for MI, 3rd gen. answers in 0x10 - DPRINT_IVID(DBG_INFO, q->iv->id); - if ( p->packet[9] == 0x01 ) { - DBGPRINTLN(F("got 2nd frame (hw info)")); - /* according to xlsx (different start byte -1!) - byte[11] to byte[14] HW_PN - byte[15] byte[16] HW_FB_TLmValue - byte[17] byte[18] HW_FB_ReSPRT - byte[19] byte[20] HW_GridSamp_ResValule - byte[21] byte[22] HW_ECapValue - byte[23] to byte[26] Matching_APPFW_PN*/ - 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])); - record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure - rec->ts = q->ts; - q->iv->setValue(0, rec, (uint32_t) ((((p->packet[10] << 8) | p->packet[11]) << 8 | p->packet[12]) << 8 | p->packet[13])/1); - - if(*mSerialDebug) { - DPRINT(DBG_INFO,F("HW_FB_TLmValue ")); - DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15])); - DBGPRINT(F("HW_FB_ReSPRT ")); - DBGPRINTLN(String((p->packet[16] << 8) + p->packet[17])); - DBGPRINT(F("HW_GridSamp_ResValule ")); - DBGPRINTLN(String((p->packet[18] << 8) + p->packet[19])); - DBGPRINT(F("HW_ECapValue ")); - DBGPRINTLN(String((p->packet[20] << 8) + p->packet[21])); - DBGPRINT(F("Matching_APPFW_PN ")); - DBGPRINTLN(String((uint32_t) (((p->packet[22] << 8) | p->packet[23]) << 8 | p->packet[24]) << 8 | p->packet[25])); - } - if(NULL != mCbPayload) - (mCbPayload)(InverterDevInform_All, q->iv); - q->iv->miMultiParts +=2; - - } else { - DBGPRINTLN(F("3rd gen. inverter!")); - } - - } else if ( p->packet[9] == 0x12 ) {//3rd frame - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINTLN(F("got 3rd frame (hw info)")); - /* according to xlsx (different start byte -1!) - byte[11] byte[12] APPFW_MINVER - byte[13] byte[14] HWInfoAddr - byte[15] byte[16] PNInfoCRC_gusv - byte[15] byte[16] PNInfoCRC_gusv (this really is double mentionned in xlsx...) - */ - if(*mSerialDebug) { - DPRINT(DBG_INFO,F("APPFW_MINVER ")); - DBGPRINTLN(String((p->packet[10] << 8) + p->packet[11])); - DBGPRINT(F("HWInfoAddr ")); - DBGPRINTLN(String((p->packet[12] << 8) + p->packet[13])); - DBGPRINT(F("PNInfoCRC_gusv ")); - DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15])); - } - if(NULL != mCbPayload) - (mCbPayload)(InverterDevInform_Simple, q->iv); - q->iv->miMultiParts++; - } - //if(q->iv->miMultiParts > 5) - //closeRequest(q->iv, true); - //else - //if(q->iv->miMultiParts < 6) - // mState = States::WAIT; - - /*if (mPayload[iv->id].multi_parts > 5) { - iv->setQueuedCmdFinished(); - mPayload[iv->id].complete = true; - mPayload[iv->id].rxTmo = true; - mPayload[iv->id].requested= false; - iv->radioStatistics.rxSuccess++; - } - if (mHighPrioIv == NULL) - mHighPrioIv = iv; - */ - } - - inline void miDataDecode(packet_t *p, const queue_s *q) { - record_t<> *rec = q->iv->getRecordStruct(RealTimeRunData_Debug); // choose the parser - rec->ts = q->ts; - //mState = States::RESET; - if(q->iv->miMultiParts < 6) - q->iv->miMultiParts += 6; - - uint8_t datachan = ( p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES) || p->packet[0] == (MI_REQ_4CH + ALL_FRAMES) ) ? CH1 : - ( p->packet[0] == (MI_REQ_CH2 + ALL_FRAMES) || p->packet[0] == (0x37 + ALL_FRAMES) ) ? CH2 : - p->packet[0] == (0x38 + ALL_FRAMES) ? CH3 : - CH4; - // count in RF_communication_protocol.xlsx is with offset = -1 - q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_UDC, rec), rec, (float)((p->packet[9] << 8) + p->packet[10])/10); - - q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_IDC, rec), rec, (float)((p->packet[11] << 8) + p->packet[12])/10); - - q->iv->setValue(q->iv->getPosByChFld(0, FLD_UAC, rec), rec, (float)((p->packet[13] << 8) + p->packet[14])/10); - - q->iv->setValue(q->iv->getPosByChFld(0, FLD_F, rec), rec, (float) ((p->packet[15] << 8) + p->packet[16])/100); - q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_PDC, rec), rec, (float)((p->packet[17] << 8) + p->packet[18])/10); - - q->iv->setValue(q->iv->getPosByChFld(datachan, FLD_YD, rec), rec, (float)((p->packet[19] << 8) + p->packet[20])/1); - - q->iv->setValue(q->iv->getPosByChFld(0, FLD_T, rec), rec, (float) ((int16_t)(p->packet[21] << 8) + p->packet[22])/10); - q->iv->setValue(q->iv->getPosByChFld(0, FLD_IRR, rec), rec, (float) (calcIrradiation(q->iv, datachan))); - - if (datachan == 1) - q->iv->rssi = p->rssi; - else if(q->iv->rssi > p->rssi) - q->iv->rssi = p->rssi; - - if (p->packet[0] >= (MI_REQ_4CH + ALL_FRAMES) ) { - /*For MI1500: - if (MI1500) { - STAT = (uint8_t)(p->packet[25] ); - FCNT = (uint8_t)(p->packet[26]); - FCODE = (uint8_t)(p->packet[27]); - }*/ - miStsConsolidate(q, datachan, rec, p->packet[23], p->packet[24]); - - if (p->packet[0] < (0x39 + ALL_FRAMES) ) { - mHeu.evalTxChQuality(q->iv, true, (4 - q->attempts), 1); - miNextRequest((p->packet[0] - ALL_FRAMES + 1), q); - } else { - q->iv->miMultiParts = 7; // indicate we are ready - //miComplete(q->iv); - } - } else if((p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES)) && (q->iv->type == INV_TYPE_2CH)) { - //addImportant(q->iv, MI_REQ_CH2); - miNextRequest(MI_REQ_CH2, q); - mHeu.evalTxChQuality(q->iv, true, (4 - q->attempts), q->iv->curFrmCnt); - //use also miMultiParts here for better statistics? - //mHeu.setGotFragment(q->iv); - } else { // first data msg for 1ch, 2nd for 2ch - q->iv->miMultiParts += 6; // indicate we are ready - //miComplete(q->iv); - } - } - - void miNextRequest(uint8_t cmd, const queue_s *q) { - incrAttempt(); // if function is called, we got something, and we necessarily need more transmissions for MI types... - if(*mSerialDebug) { - DPRINT_IVID(DBG_WARN, q->iv->id); - DBGPRINT(F("next request (")); - DBGPRINT(String(q->attempts)); - DBGPRINT(F(" attempts left): 0x")); - DBGHEXLN(cmd); - } - - if(q->iv->miMultiParts == 7) { - //mHeu.setGotAll(q->iv); - q->iv->radioStatistics.rxSuccess++; - } else - //mHeu.setGotFragment(q->iv); - /*iv->radioStatistics.rxFail++; // got no complete payload*/ - //q->iv->radioStatistics.retransmits++; - q->iv->radio->sendCmdPacket(q->iv, cmd, 0x00, true); - - mWaitTimeout = millis() + MI_TIMEOUT; - mWaitTimeout_min = mWaitTimeout; - q->iv->miMultiParts = 0; - q->iv->mGotFragment = 0; - mIsRetransmit = true; - chgCmd(cmd); - //mState = States::WAIT; - } - - void miRepeatRequest(const queue_s *q) { - setAttempt(); // if function is called, we got something, and we necessarily need more transmissions for MI types... - if(*mSerialDebug) { - DPRINT_IVID(DBG_WARN, q->iv->id); - DBGPRINT(F("resend request (")); - DBGPRINT(String(q->attempts)); - DBGPRINT(F(" attempts left): 0x")); - DBGHEXLN(q->cmd); - } - - q->iv->radio->sendCmdPacket(q->iv, q->cmd, 0x00, true); - - mWaitTimeout = millis() + MI_TIMEOUT; - mWaitTimeout_min = mWaitTimeout; - //mState = States::WAIT; - mIsRetransmit = false; - } - - void miStsConsolidate(const queue_s *q, 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 statusMi = 3; // regular status for MI, change to 1 later? - if ( uState == 2 ) { - statusMi = 5050 + stschan; //first approach, needs review! - if (lState) - statusMi += lState*10; - } else if ( uState > 3 ) { - statusMi = uState*1000 + uEnum*10; - if (lState) - statusMi += lState*100; //needs review, esp. for 4ch-8310 state! - //if (lEnum) - statusMi += lEnum; - if (uEnum < 6) { - statusMi += stschan; - } - if (statusMi == 8000) - statusMi = 8310; //trick? - } - - uint16_t prntsts = statusMi == 3 ? 1 : statusMi; - bool stsok = true; - if ( prntsts != rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)] ) { //sth.'s changed? - q->iv->alarmCnt = 1; // minimum... - stsok = false; - //sth is or was wrong? - if ( (q->iv->type != INV_TYPE_1CH) && ( (statusMi != 3) - || ((q->iv->lastAlarm[stschan].code) && (statusMi == 3) && (q->iv->lastAlarm[stschan].code != 1))) - ) { - q->iv->lastAlarm[stschan+q->iv->type==INV_TYPE_2CH ? 2: 4] = alarm_t(q->iv->lastAlarm[stschan].code, q->iv->lastAlarm[stschan].start,q->ts); - q->iv->lastAlarm[stschan] = alarm_t(prntsts, q->ts,0); - q->iv->alarmCnt = q->iv->type == INV_TYPE_2CH ? 3 : 5; - } else if ( (q->iv->type == INV_TYPE_1CH) && ( (statusMi != 3) - || ((q->iv->lastAlarm[stschan].code) && (statusMi == 3) && (q->iv->lastAlarm[stschan].code != 1))) - ) { - q->iv->lastAlarm[stschan] = alarm_t(q->iv->lastAlarm[0].code, q->iv->lastAlarm[0].start,q->ts); - } else if (q->iv->type == INV_TYPE_1CH) - stsok = true; - - q->iv->alarmLastId = prntsts; //iv->alarmMesIndex; - - if (q->iv->alarmCnt > 1) { //more than one channel - for (uint8_t ch = 0; ch < (q->iv->alarmCnt); ++ch) { //start with 1 - if (q->iv->lastAlarm[ch].code == 1) { - stsok = true; - break; - } - } - } - if(*mSerialDebug) { - DPRINT(DBG_WARN, F("New state on CH")); - DBGPRINT(String(stschan)); DBGPRINT(F(" (")); - DBGPRINT(String(prntsts)); DBGPRINT(F("): ")); - DBGPRINTLN(q->iv->getAlarmStr(prntsts)); - } - if(!q->iv->miMultiParts) - q->iv->miMultiParts = 1; // indicate we got status info (1+2 ch types) - } - - if (!stsok) { - q->iv->setValue(q->iv->getPosByChFld(0, FLD_EVT, rec), rec, prntsts); - q->iv->lastAlarm[0] = alarm_t(prntsts, q->ts, 0); - } - - if (q->iv->alarmMesIndex < rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)]) { - q->iv->alarmMesIndex = rec->record[q->iv->getPosByChFld(0, FLD_EVT, rec)]; // seems there's no status per channel in 3rd gen. models?!? - if (*mSerialDebug) { - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(F("alarm ID incremented to ")); - DBGPRINTLN(String(q->iv->alarmMesIndex)); - } - } - } - - - void miComplete(Inverter<> *iv) { - if (*mSerialDebug) { - DPRINT_IVID(DBG_INFO, iv->id); - DBGPRINTLN(F("got all data 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; - if (iv->type == INV_TYPE_1CH) { - if ((!iv->lastAlarm[0].code) || (iv->lastAlarm[0].code == 1)) - ac_pow += iv->getValue(iv->getPosByChFld(1, FLD_PDC, rec), rec); - } else { - for(uint8_t i = 1; i <= iv->channels; i++) { - if ((!iv->lastAlarm[i].code) || (iv->lastAlarm[i].code == 1)) { - 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(); - // update status state-machine, - if (ac_pow) - iv->isProducing(); - //closeRequest(iv, iv->miMultiParts > 5); - - //mHeu.setGotAll(iv); - //cmdDone(false); - if(NULL != mCbPayload) - (mCbPayload)(RealTimeRunData_Debug, iv); - - //mState = States::RESET; // everything ok, next request - } - - private: - enum class States : uint8_t { - RESET, START, WAIT, CHECK_FRAMES, CHECK_PACKAGE - }; - - typedef struct { - uint8_t buf[MAX_RF_PAYLOAD_SIZE]; - uint8_t len; - int8_t rssi; - } frame_t; - - private: - States mState = States::RESET; - uint32_t *mTimestamp; - bool *mPrivacyMode, *mSerialDebug, *mPrintWholeTrace; - uint16_t *mInverterGap; - uint32_t mWaitTimeout = 0; - uint32_t mWaitTimeout_min = 0; - std::array mLocalBuf; - bool mFirstTry = false; // see, if we should do a second try - bool mIsRetransmit = false; // we alrady had waited one complete cycle - uint16_t mlastTO_min = DEFAULT_TIMEOUT; // remember timeout_min for correct calculation - uint8_t mMaxFrameId; - uint8_t mPayload[MAX_BUFFER]; - payloadListenerType mCbPayload = NULL; - alarmListenerType mCbAlarm = NULL; - Heuristic mHeu; - uint32_t mLastEmptyQueueMillis = 0; - bool mPrintSequenceDuration = false; - - //States mDebugState = States::START; -}; - -#endif /*__COMMUNICATION_H__*/ From 0d3bfe371082818c56c1c3f9d0a83a6661b799d6 Mon Sep 17 00:00:00 2001 From: rejoe2 Date: Thu, 28 Dec 2023 20:59:52 +0100 Subject: [PATCH 253/267] fix some double counts --- src/hm/Communication.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/hm/Communication.h b/src/hm/Communication.h index bc6f9f38..eff60869 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -464,9 +464,6 @@ class Communication : public CommQueue<> { if(GridOnProFilePara == q->cmd) { q->iv->addGridProfile(mPayload, len); - q->iv->radioStatistics.rxSuccess++; - mHeu.evalTxChQuality(q->iv, true, (7 - q->attempts), q->iv->curFrmCnt); - //cmdDone(false); return; } @@ -474,10 +471,6 @@ class Communication : public CommQueue<> { if(NULL == rec) { if(GetLossRate == q->cmd) { q->iv->parseGetLossRate(mPayload, len); - //closeRequest(q, true); //@lumapu: Activating would crash most esp's! - mHeu.evalTxChQuality(q->iv, true, (9 - q->attempts), q->iv->curFrmCnt); - q->iv->radioStatistics.rxSuccess++; - //cmdDone(false); return; } else { DPRINTLN(DBG_ERROR, F("record is NULL!")); From 61ebe3e989a4c1152c804b881924adbdc38fe157 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 28 Dec 2023 21:36:35 +0100 Subject: [PATCH 254/267] 0.8.30 * added info if grid profile was not found --- src/CHANGES.md | 3 +++ src/defines.h | 2 +- src/web/html/grid_info.json | 1 + src/web/html/visualization.html | 19 +++++++++++++------ 4 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index fc8566cc..17d0528c 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.8.30 - 2023-12-28 +* added info if grid profile was not found + ## 0.8.29 - 2023-12-27 * fix MqTT generic topic `comm_disabled` #1265 #1286 * potential fix of #1285 (reset yield day) diff --git a/src/defines.h b/src/defines.h index 2b304f9f..d3936d62 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 29 +#define VERSION_PATCH 30 //------------------------------------- typedef struct { diff --git a/src/web/html/grid_info.json b/src/web/html/grid_info.json index adb68393..5dcdda65 100644 --- a/src/web/html/grid_info.json +++ b/src/web/html/grid_info.json @@ -159,6 +159,7 @@ { "name": "Nominal Voltage", "div": 10, + "def": 230, "unit": "V" }, { diff --git a/src/web/html/visualization.html b/src/web/html/visualization.html index b561d5cc..2c771f5a 100644 --- a/src/web/html/visualization.html +++ b/src/web/html/visualization.html @@ -355,12 +355,19 @@ getJSON("/grid_info.json").then(data => { var glob = {offs:0, grid:obj.grid, info: data} var content = []; - content.push(ml("div", {class: "row"}, - ml("div", {class: "col my-3"}, ml("h5", {}, getGridType(glob.info.type, getGridIdentifier(glob)) + " (Version " + getGridValue(glob).toString(16) + ")")) - )) - - while((glob.offs*3) < glob.grid.length) { - content.push(parseGridGroup(glob)) + var g = getGridType(glob.info.type, getGridIdentifier(glob)) + if(null === g) { + content.push(ml("div", {class: "row"}, ml("div", {class: "col"}, ml("h5", {}, "Unknown Profile")))) + content.push(ml("div", {class: "row"}, ml("div", {class: "col"}, ml("p", {}, "Please open a new issue at https://github.com/lumapu/ahoy and copy the raw data into it.")))) + content.push(ml("div", {class: "row"}, ml("div", {class: "col my-2"}, ml("pre", {}, obj.grid)))) + } else { + content.push(ml("div", {class: "row"}, + ml("div", {class: "col my-3"}, ml("h5", {}, g + " (Version " + getGridValue(glob).toString(16) + ")")) + )) + + while((glob.offs*3) < glob.grid.length) { + content.push(parseGridGroup(glob)) + } } modal("Grid Profile for inverter " + obj.name, ml("div", {}, ml("div", {class: "col mb-2"}, [...content]))) From 9c074b9814831a67a2f9221993aa8447334d4109 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 28 Dec 2023 21:45:37 +0100 Subject: [PATCH 255/267] 0.8.30 * merge PR #1293 * merge PR #1295 fix ESP8266 pin settings --- src/CHANGES.md | 2 ++ src/hm/Communication.h | 26 ++------------------------ src/hm/hmRadio.h | 2 +- src/web/html/setup.html | 6 +++--- 4 files changed, 8 insertions(+), 28 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 17d0528c..a0fa874a 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -2,6 +2,8 @@ ## 0.8.30 - 2023-12-28 * added info if grid profile was not found +* merge PR #1293 +* merge PR #1295 fix ESP8266 pin settings ## 0.8.29 - 2023-12-27 * fix MqTT generic topic `comm_disabled` #1265 #1286 diff --git a/src/hm/Communication.h b/src/hm/Communication.h index eff60869..6ed10e9f 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -59,7 +59,7 @@ class Communication : public CommQueue<> { mLastEmptyQueueMillis = millis(); mPrintSequenceDuration = true; - uint16_t timeout = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : (((q->iv->mGotFragment && q->iv->mGotLastMsg) || mIsRetransmit) ? SINGLEFR_TIMEOUT : ((q->cmd != AlarmData) && q->cmd != GridOnProFilePara ? DEFAULT_TIMEOUT : (1.5 * DEFAULT_TIMEOUT))); + uint16_t timeout = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : (((q->iv->mGotFragment && q->iv->mGotLastMsg) || mIsRetransmit) ? SINGLEFR_TIMEOUT : ((q->cmd != AlarmData) && (q->cmd != GridOnProFilePara) ? DEFAULT_TIMEOUT : (1.5 * DEFAULT_TIMEOUT))); uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment || mIsRetransmit)) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT; /*if(mDebugState != mState) { @@ -113,35 +113,13 @@ class Communication : public CommQueue<> { mIsRetransmit = false; mlastTO_min = timeout_min; setAttempt(); - if(q->cmd == AlarmData || q->cmd == GridOnProFilePara) + if((q->cmd == AlarmData) || (q->cmd == GridOnProFilePara)) incrAttempt(q->cmd == AlarmData? 5 : 3); mState = States::WAIT; break; case States::WAIT: - /*if(millis() > mWaitTimeout_min) { - if(mIsRetransmit) { // we already have been through... - mWaitTimeout = mWaitTimeout_min; - } else if(q->iv->mGotFragment) { // nothing received yet? - if(q->iv->mGotLastMsg) { - //mState = States::CHECK_FRAMES; - mWaitTimeout = mWaitTimeout_min; - } - } else if(mFirstTry) { - if(*mSerialDebug) { - DPRINT_IVID(DBG_INFO, q->iv->id); - DBGPRINT(String(millis() - mWaitTimeout_min + mlastTO_min)); - DBGPRINTLN(F("ms - second try")); - } - mFirstTry = false; - mlastTO_min = timeout_min; - q->iv->radioStatistics.retransmits++; // got nothing - mState = States::START; - break; - } - - }*/ if(millis() < mWaitTimeout) return; mState = States::CHECK_FRAMES; diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 2e02e92a..d7ae594b 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -124,7 +124,7 @@ class HmRadio : public Radio { uint32_t outerLoopTimeout = (mLastIv->mIsSingleframeReq) ? 100 : ((mLastIv->mCmd != AlarmData) && (mLastIv->mCmd != GridOnProFilePara)) ? 400 : 600; while ((millis() - loopMillis) < outerLoopTimeout) { - uint32_t startMicros = micros(); + startMicros = micros(); while ((micros() - startMicros) < 5110) { // listen (4088us or?) 5110us to each channel if (mIrqRcvd) { mIrqRcvd = false; diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 7ca17005..8e415c2c 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -900,7 +900,7 @@ var pinList = esp8266pins; /*IF_ESP32*/ var pinList = esp32pins; - if ("ESP32-S3" == system["chip_model"]) pinList = esp32s3pins; + if ("ESP32-S3" == system.chip_model) pinList = esp32s3pins; else if("ESP32-C3" == system["chip_model"]) pinList = esp32c3pins; /*ENDIF_ESP32*/ pins = [['led0', 'pinLed0', 'At least one inverter is producing'], ['led1', 'pinLed1', 'MqTT connected']]; @@ -932,7 +932,7 @@ var pinList = esp8266pins; /*IF_ESP32*/ var pinList = esp32pins; - if ("ESP32-S3" == system["chip_model"]) pinList = esp32s3pins; + if ("ESP32-S3" == system.chip_model) pinList = esp32s3pins; else if("ESP32-C3" == system["chip_model"]) pinList = esp32c3pins; /*ENDIF_ESP32*/ @@ -999,7 +999,7 @@ var pinList = esp8266pins; /*IF_ESP32*/ var pinList = esp32pins; - if ("ESP32-S3" == system["chip_model"]) pinList = esp32s3pins; + if ("ESP32-S3" == system.chip_model) pinList = esp32s3pins; else if("ESP32-C3" == system["chip_model"]) pinList = esp32c3pins; /*ENDIF_ESP32*/ From c28d051ba480eae120ccdac1448e4c514e423b54 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 28 Dec 2023 21:49:50 +0100 Subject: [PATCH 256/267] 0.8.30 * added info if grid profile was not found * merge PR #1293 * merge PR #1295 fix ESP8266 pin settings * merge PR #1297 fix layout for OLED displays --- src/CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/CHANGES.md b/src/CHANGES.md index a0fa874a..f09b00a5 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -4,6 +4,7 @@ * added info if grid profile was not found * merge PR #1293 * merge PR #1295 fix ESP8266 pin settings +* merge PR #1297 fix layout for OLED displays ## 0.8.29 - 2023-12-27 * fix MqTT generic topic `comm_disabled` #1265 #1286 From f7e35e440454e7c3450e0f1a63aca55fdc15bcde Mon Sep 17 00:00:00 2001 From: you69man Date: Sun, 24 Dec 2023 05:56:28 +0100 Subject: [PATCH 257/267] implement TimeMonitor Class --- src/hm/Communication.h | 52 ++++++++++------- src/utils/timemonitor.h | 126 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+), 20 deletions(-) create mode 100644 src/utils/timemonitor.h diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 6ed10e9f..8f9404a1 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -10,6 +10,7 @@ #include #include "../utils/crc.h" #include "Heuristic.h" +#include "../utils/timemonitor.h" #define MI_TIMEOUT 250 // timeout for MI type requests #define FRSTMSG_TIMEOUT 150 // how long to wait for first msg to be received @@ -60,7 +61,7 @@ class Communication : public CommQueue<> { mPrintSequenceDuration = true; uint16_t timeout = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : (((q->iv->mGotFragment && q->iv->mGotLastMsg) || mIsRetransmit) ? SINGLEFR_TIMEOUT : ((q->cmd != AlarmData) && (q->cmd != GridOnProFilePara) ? DEFAULT_TIMEOUT : (1.5 * DEFAULT_TIMEOUT))); - uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment || mIsRetransmit)) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT; + // uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment || mIsRetransmit)) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT; // not used /*if(mDebugState != mState) { DPRINT(DBG_INFO, F("State: ")); @@ -69,8 +70,10 @@ class Communication : public CommQueue<> { }*/ switch(mState) { case States::RESET: - if(millis() < mWaitTimeout) + //if(millis() < mWaitTimeout) // replaced by TimeMonitor + if (!mWaitTime.isTimeout()) return; + mMaxFrameId = 0; for(uint8_t i = 0; i < MAX_PAYLOAD_ENTRIES; i++) { mLocalBuf[i].len = 0; @@ -108,10 +111,11 @@ class Communication : public CommQueue<> { q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); q->iv->radioStatistics.txCnt++; - mWaitTimeout = millis() + timeout; - mWaitTimeout_min = millis() + timeout_min; + // mWaitTimeout = millis() + timeout; // replaced by Timemonitor + mWaitTime.startTimeMonitor(timeout); + // mWaitTimeout_min = millis() + timeout_min; // not used mIsRetransmit = false; - mlastTO_min = timeout_min; + // mlastTO_min = timeout_min; // not used setAttempt(); if((q->cmd == AlarmData) || (q->cmd == GridOnProFilePara)) incrAttempt(q->cmd == AlarmData? 5 : 3); @@ -120,7 +124,8 @@ class Communication : public CommQueue<> { break; case States::WAIT: - if(millis() < mWaitTimeout) + // if(millis() < mWaitTimeout) // replaced by Timemonitor + if (!mWaitTime.isTimeout()) return; mState = States::CHECK_FRAMES; break; @@ -130,13 +135,15 @@ class Communication : public CommQueue<> { if(*mSerialDebug) { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("request timeout: ")); - DBGPRINT(String(millis() - mWaitTimeout + timeout)); + // DBGPRINT(String(millis() - mWaitTimeout + timeout)); // replaced by Timemonitor + DBGPRINT(String(mWaitTime.getRunTime())); DBGPRINTLN(F("ms")); } if(!q->iv->mGotFragment) { if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, (q->iv->config->frequency*FREQ_STEP_KHZ + HOY_BASE_FREQ_KHZ)); - mWaitTimeout = millis() + 1000; + //mWaitTimeout = millis() + 1000; // replaced by Timemonitor + mWaitTime.startTimeMonitor(1000UL); } } closeRequest(q, false); @@ -185,7 +192,8 @@ class Communication : public CommQueue<> { bool fastNext = true; if(q->iv->miMultiParts < 6) { mState = States::WAIT; - if((millis() > mWaitTimeout && mIsRetransmit) || !mIsRetransmit) { + // if((millis() > mWaitTimeout && mIsRetransmit) || !mIsRetransmit) { // replaced by TimeMonitor + if((mWaitTime.isTimeout() && mIsRetransmit) || !mIsRetransmit) { miRepeatRequest(q); return; } @@ -245,7 +253,7 @@ class Communication : public CommQueue<> { q->iv->mIsSingleframeReq = true; sendRetransmit(q, (framnr-1)); mIsRetransmit = true; - mlastTO_min = timeout_min; + // mlastTO_min = timeout_min; // not used return; } @@ -492,7 +500,8 @@ class Communication : public CommQueue<> { if(q->attempts) { q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true); q->iv->radioStatistics.retransmits++; - mWaitTimeout = millis() + SINGLEFR_TIMEOUT; // timeout + // mWaitTimeout = millis() + SINGLEFR_TIMEOUT; // timeout replaced by Timemonitor + mWaitTime.startTimeMonitor(SINGLEFR_TIMEOUT); // timeout mState = States::WAIT; } else { //add(q, true); @@ -509,7 +518,8 @@ class Communication : public CommQueue<> { q->iv->radioStatistics.rxFail++; // got no complete payload else q->iv->radioStatistics.rxFailNoAnser++; // got nothing - mWaitTimeout = millis() + *mInverterGap; + // mWaitTimeout = millis() + *mInverterGap; // replaced by Timemonitor + mWaitTime.startTimeMonitor(*mInverterGap); bool keep = false; if(q->isDevControl) @@ -731,8 +741,9 @@ class Communication : public CommQueue<> { //q->iv->radioStatistics.retransmits++; q->iv->radio->sendCmdPacket(q->iv, cmd, 0x00, true); - mWaitTimeout = millis() + MI_TIMEOUT; - mWaitTimeout_min = mWaitTimeout; + // mWaitTimeout = millis() + MI_TIMEOUT; // replaced by TimeMonitor + // mWaitTimeout_min = mWaitTimeout; // not used + mWaitTime.startTimeMonitor(MI_TIMEOUT); q->iv->miMultiParts = 0; q->iv->mGotFragment = 0; mIsRetransmit = true; @@ -752,8 +763,9 @@ class Communication : public CommQueue<> { q->iv->radio->sendCmdPacket(q->iv, q->cmd, 0x00, true); - mWaitTimeout = millis() + MI_TIMEOUT; - mWaitTimeout_min = mWaitTimeout; + // mWaitTimeout = millis() + MI_TIMEOUT; // replaced by TimeMonitor + // mWaitTimeout_min = mWaitTimeout; // not used + mWaitTime.startTimeMonitor(MI_TIMEOUT); //mState = States::WAIT; mIsRetransmit = false; } @@ -887,12 +899,12 @@ class Communication : public CommQueue<> { uint32_t *mTimestamp; bool *mPrivacyMode, *mSerialDebug, *mPrintWholeTrace; uint16_t *mInverterGap; - uint32_t mWaitTimeout = 0; - uint32_t mWaitTimeout_min = 0; + TimeMonitor mWaitTime = TimeMonitor(0, true); // start as expired (due to code in RESET state) + // uint32_t mWaitTimeout_min = 0; // not used std::array mLocalBuf; bool mFirstTry = false; // see, if we should do a second try - bool mIsRetransmit = false; // we alrady had waited one complete cycle - uint16_t mlastTO_min = DEFAULT_TIMEOUT; // remember timeout_min for correct calculation + bool mIsRetransmit = false; // we already had waited one complete cycle + // uint16_t mlastTO_min = DEFAULT_TIMEOUT; // remember timeout_min for correct calculation not used uint8_t mMaxFrameId; uint8_t mPayload[MAX_BUFFER]; payloadListenerType mCbPayload = NULL; diff --git a/src/utils/timemonitor.h b/src/utils/timemonitor.h new file mode 100644 index 00000000..ce44a94d --- /dev/null +++ b/src/utils/timemonitor.h @@ -0,0 +1,126 @@ +//----------------------------------------------------------- +// You69Man, 2023 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// version 2 as published by the Free Software Foundation. +//----------------------------------------------------------- + +/** + * @file timemonitor.h + * + * Class declaration for TimeMonitor + */ + +#ifndef __TIMEMONITOR_H__ +#define __TIMEMONITOR_H__ + +#include + +class TimeMonitor { + public: + /** + * A constructor for initializing a TimeMonitor + * @note TimeMonitor witch default constructor is stopped + */ + TimeMonitor(void) {}; + + /** + * A constructor for initializing a TimeMonitor + * @param timeout timeout in ms + * @param start (optional) if true, start TimeMonitor immediately + * @note TimeMonitor witch default constructor is stopped + */ + TimeMonitor(uint32_t timeout, bool start = false) { + if (start) + startTimeMonitor(timeout); + else + configureTimeMonitor(timeout); + }; + + /** + * Start the TimeMonitor with new timeout configuration + * @param timeout timout in ms + */ + void startTimeMonitor(uint32_t timeout) { + mStartTime = millis(); + mTimeout = timeout; + mStarted = true; + } + + /** + * Restart the TimeMonitor with already set timeout configuration + * @note returns nothing + */ + void reStartTimeMonitor(void) { + mStartTime = millis(); + mStarted = true; + } + + /** + * Configure the TimeMonitor to new timeout configuration + * @param timeout timeout in ms + * @note This doesn't restart an already running TimeMonitor. + * If timer is already running and new timeout is longer that current timeout runtime of the running timer is expanded + * If timer is already running and new timeout is shorter that current timeout this can immediately lead to a timeout + */ + void configureTimeMonitor(uint32_t timeout) { + mTimeout = timeout; + } + + /** + * Stop the TimeMonitor + */ + void stopTimeMonitor(void) { + mStarted = false; + } + + /** + * Get timeout status of the TimeMonitor + * @return bool + * true: TimeMonitor already timed out + * false: TimeMonitor still in time or TimeMonitor was stopped + */ + bool isTimeout(void) { + if ((mStarted) && (millis() - mStartTime >= mTimeout)) + return true; + else + return false; + } + + /** + * Get timeout configuration of the TimeMonitor + * @return uint32_t timeout value in ms + */ + uint32_t getTimeout(void) const { + return mTimeout; + } + + /** + * Get residual time of the TimeMonitor until timeout + * @return uint32_t residual time until timeout in ms + * @note in case of a stopped TimeMonitor residual time is always 0xFFFFFFFFUL + * in case of a timed out TimeMonitor residual time is always 0UL (zero) + */ + uint32_t getResidualTime(void) const { + uint32_t delayed = millis() - mStartTime; + return(mStarted ? (delayed < mTimeout ? mTimeout - delayed : 0UL) : 0xFFFFFFFFUL); + } + + /** + * Get overall run time of the TimeMonitor + * @return uint32_t residual time until timeout in ms + * @note in case of a stopped TimeMonitor residual time is always 0xFFFFFFFFUL + * in case of a timed out TimeMonitor residual time is always 0UL (zero) + */ + uint32_t getRunTime(void) const { + return(mStarted ? millis() - mStartTime : 0UL); + } + + private: + uint32_t mStartTime = 0UL; // start time of the TimeMonitor + uint32_t mTimeout = 0UL; // timeout configuration of the TimeMonitor + bool mStarted = false; // start/stop state of the TimeMonitor +}; + +#endif \ No newline at end of file From bd0c5e3613e118975633b5503c00effb594fdde8 Mon Sep 17 00:00:00 2001 From: you69man Date: Sun, 24 Dec 2023 05:56:58 +0100 Subject: [PATCH 258/267] adapt Display_Mono.h to TimeMonitor --- src/plugins/Display/Display_Mono.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/plugins/Display/Display_Mono.h b/src/plugins/Display/Display_Mono.h index 3fc691c2..5b0d7457 100644 --- a/src/plugins/Display/Display_Mono.h +++ b/src/plugins/Display/Display_Mono.h @@ -19,6 +19,7 @@ #include "../../utils/helper.h" #include "Display_data.h" #include "../../utils/dbg.h" +#include "../../utils/timemonitor.h" class DisplayMono { public: @@ -37,19 +38,19 @@ class DisplayMono { if (mDisplayActive) { if (!dispConditions) { - if ((millis() - mStarttime) > DISP_DEFAULT_TIMEOUT * 1000ul) { // switch display off after timeout + if (mDisplayTime.isTimeout()) { // switch display off after timeout mDisplayActive = false; mDisplay->setPowerSave(true); DBGPRINTLN("**** Display off ****"); } } else - mStarttime = millis(); // keep display on + mDisplayTime.reStartTimeMonitor(); // keep display on } else { if (dispConditions) { - mDisplayActive = true; // switch display on - mStarttime = millis(); + mDisplayActive = true; + mDisplayTime.reStartTimeMonitor(); // switch display on mDisplay->setPowerSave(false); DBGPRINTLN("**** Display on ****"); } @@ -79,7 +80,7 @@ class DisplayMono { uint8_t mExtra; int8_t mPixelshift=0; - uint32_t mStarttime = millis(); + TimeMonitor mDisplayTime = TimeMonitor(1000ul * 15, true); bool mDisplayActive = true; // always start with display on char mFmtText[DISP_FMT_TEXT_LEN]; From 7c08d934a93748b0d7291777990120b3ee8fd563 Mon Sep 17 00:00:00 2001 From: lumapu Date: Fri, 29 Dec 2023 00:18:55 +0100 Subject: [PATCH 259/267] 0.8.31 * added class to handle timeouts PR #1298 --- src/CHANGES.md | 3 +++ src/defines.h | 2 +- src/hm/Communication.h | 26 ++++---------------------- src/plugins/Display/Display_Mono.h | 2 +- src/utils/timemonitor.h | 10 +++++----- 5 files changed, 14 insertions(+), 29 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index f09b00a5..7839d420 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.8.31 - 2023-12-29 +* added class to handle timeouts PR #1298 + ## 0.8.30 - 2023-12-28 * added info if grid profile was not found * merge PR #1293 diff --git a/src/defines.h b/src/defines.h index d3936d62..b3c5089a 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 30 +#define VERSION_PATCH 31 //------------------------------------- typedef struct { diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 8f9404a1..1ed45831 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -9,8 +9,8 @@ #include "CommQueue.h" #include #include "../utils/crc.h" -#include "Heuristic.h" #include "../utils/timemonitor.h" +#include "Heuristic.h" #define MI_TIMEOUT 250 // timeout for MI type requests #define FRSTMSG_TIMEOUT 150 // how long to wait for first msg to be received @@ -61,7 +61,6 @@ class Communication : public CommQueue<> { mPrintSequenceDuration = true; uint16_t timeout = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : (((q->iv->mGotFragment && q->iv->mGotLastMsg) || mIsRetransmit) ? SINGLEFR_TIMEOUT : ((q->cmd != AlarmData) && (q->cmd != GridOnProFilePara) ? DEFAULT_TIMEOUT : (1.5 * DEFAULT_TIMEOUT))); - // uint16_t timeout_min = (q->iv->ivGen == IV_MI) ? MI_TIMEOUT : ((q->iv->mGotFragment || mIsRetransmit)) ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT; // not used /*if(mDebugState != mState) { DPRINT(DBG_INFO, F("State: ")); @@ -70,7 +69,6 @@ class Communication : public CommQueue<> { }*/ switch(mState) { case States::RESET: - //if(millis() < mWaitTimeout) // replaced by TimeMonitor if (!mWaitTime.isTimeout()) return; @@ -111,11 +109,8 @@ class Communication : public CommQueue<> { q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false); q->iv->radioStatistics.txCnt++; - // mWaitTimeout = millis() + timeout; // replaced by Timemonitor mWaitTime.startTimeMonitor(timeout); - // mWaitTimeout_min = millis() + timeout_min; // not used mIsRetransmit = false; - // mlastTO_min = timeout_min; // not used setAttempt(); if((q->cmd == AlarmData) || (q->cmd == GridOnProFilePara)) incrAttempt(q->cmd == AlarmData? 5 : 3); @@ -124,7 +119,6 @@ class Communication : public CommQueue<> { break; case States::WAIT: - // if(millis() < mWaitTimeout) // replaced by Timemonitor if (!mWaitTime.isTimeout()) return; mState = States::CHECK_FRAMES; @@ -135,15 +129,13 @@ class Communication : public CommQueue<> { if(*mSerialDebug) { DPRINT_IVID(DBG_INFO, q->iv->id); DBGPRINT(F("request timeout: ")); - // DBGPRINT(String(millis() - mWaitTimeout + timeout)); // replaced by Timemonitor DBGPRINT(String(mWaitTime.getRunTime())); DBGPRINTLN(F("ms")); } if(!q->iv->mGotFragment) { if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, (q->iv->config->frequency*FREQ_STEP_KHZ + HOY_BASE_FREQ_KHZ)); - //mWaitTimeout = millis() + 1000; // replaced by Timemonitor - mWaitTime.startTimeMonitor(1000UL); + mWaitTime.startTimeMonitor(1000); } } closeRequest(q, false); @@ -192,7 +184,6 @@ class Communication : public CommQueue<> { bool fastNext = true; if(q->iv->miMultiParts < 6) { mState = States::WAIT; - // if((millis() > mWaitTimeout && mIsRetransmit) || !mIsRetransmit) { // replaced by TimeMonitor if((mWaitTime.isTimeout() && mIsRetransmit) || !mIsRetransmit) { miRepeatRequest(q); return; @@ -253,7 +244,6 @@ class Communication : public CommQueue<> { q->iv->mIsSingleframeReq = true; sendRetransmit(q, (framnr-1)); mIsRetransmit = true; - // mlastTO_min = timeout_min; // not used return; } @@ -500,7 +490,6 @@ class Communication : public CommQueue<> { if(q->attempts) { q->iv->radio->sendCmdPacket(q->iv, TX_REQ_INFO, (SINGLE_FRAME + i), true); q->iv->radioStatistics.retransmits++; - // mWaitTimeout = millis() + SINGLEFR_TIMEOUT; // timeout replaced by Timemonitor mWaitTime.startTimeMonitor(SINGLEFR_TIMEOUT); // timeout mState = States::WAIT; } else { @@ -518,7 +507,6 @@ class Communication : public CommQueue<> { q->iv->radioStatistics.rxFail++; // got no complete payload else q->iv->radioStatistics.rxFailNoAnser++; // got nothing - // mWaitTimeout = millis() + *mInverterGap; // replaced by Timemonitor mWaitTime.startTimeMonitor(*mInverterGap); bool keep = false; @@ -741,8 +729,6 @@ class Communication : public CommQueue<> { //q->iv->radioStatistics.retransmits++; q->iv->radio->sendCmdPacket(q->iv, cmd, 0x00, true); - // mWaitTimeout = millis() + MI_TIMEOUT; // replaced by TimeMonitor - // mWaitTimeout_min = mWaitTimeout; // not used mWaitTime.startTimeMonitor(MI_TIMEOUT); q->iv->miMultiParts = 0; q->iv->mGotFragment = 0; @@ -763,8 +749,6 @@ class Communication : public CommQueue<> { q->iv->radio->sendCmdPacket(q->iv, q->cmd, 0x00, true); - // mWaitTimeout = millis() + MI_TIMEOUT; // replaced by TimeMonitor - // mWaitTimeout_min = mWaitTimeout; // not used mWaitTime.startTimeMonitor(MI_TIMEOUT); //mState = States::WAIT; mIsRetransmit = false; @@ -900,11 +884,9 @@ class Communication : public CommQueue<> { bool *mPrivacyMode, *mSerialDebug, *mPrintWholeTrace; uint16_t *mInverterGap; TimeMonitor mWaitTime = TimeMonitor(0, true); // start as expired (due to code in RESET state) - // uint32_t mWaitTimeout_min = 0; // not used std::array mLocalBuf; - bool mFirstTry = false; // see, if we should do a second try - bool mIsRetransmit = false; // we already had waited one complete cycle - // uint16_t mlastTO_min = DEFAULT_TIMEOUT; // remember timeout_min for correct calculation not used + bool mFirstTry = false; // see, if we should do a second try + bool mIsRetransmit = false; // we already had waited one complete cycle uint8_t mMaxFrameId; uint8_t mPayload[MAX_BUFFER]; payloadListenerType mCbPayload = NULL; diff --git a/src/plugins/Display/Display_Mono.h b/src/plugins/Display/Display_Mono.h index 5b0d7457..3e998b6d 100644 --- a/src/plugins/Display/Display_Mono.h +++ b/src/plugins/Display/Display_Mono.h @@ -80,7 +80,7 @@ class DisplayMono { uint8_t mExtra; int8_t mPixelshift=0; - TimeMonitor mDisplayTime = TimeMonitor(1000ul * 15, true); + TimeMonitor mDisplayTime = TimeMonitor(1000 * 15, true); bool mDisplayActive = true; // always start with display on char mFmtText[DISP_FMT_TEXT_LEN]; diff --git a/src/utils/timemonitor.h b/src/utils/timemonitor.h index ce44a94d..798077d5 100644 --- a/src/utils/timemonitor.h +++ b/src/utils/timemonitor.h @@ -23,7 +23,7 @@ class TimeMonitor { * A constructor for initializing a TimeMonitor * @note TimeMonitor witch default constructor is stopped */ - TimeMonitor(void) {}; + TimeMonitor(void) {} /** * A constructor for initializing a TimeMonitor @@ -36,7 +36,7 @@ class TimeMonitor { startTimeMonitor(timeout); else configureTimeMonitor(timeout); - }; + } /** * Start the TimeMonitor with new timeout configuration @@ -118,9 +118,9 @@ class TimeMonitor { } private: - uint32_t mStartTime = 0UL; // start time of the TimeMonitor - uint32_t mTimeout = 0UL; // timeout configuration of the TimeMonitor - bool mStarted = false; // start/stop state of the TimeMonitor + uint32_t mStartTime = 0UL; // start time of the TimeMonitor + uint32_t mTimeout = 0UL; // timeout configuration of the TimeMonitor + bool mStarted = false; // start/stop state of the TimeMonitor }; #endif \ No newline at end of file From cf19423d919b5445d090e342329d9e6ebc943c03 Mon Sep 17 00:00:00 2001 From: lumapu Date: Fri, 29 Dec 2023 15:09:14 +0100 Subject: [PATCH 260/267] 0.8.32 * fix `start` / `stop` / `restart` commands #1287 * added message, if profile was not read until now #1300 --- src/CHANGES.md | 4 ++++ src/hm/Communication.h | 23 ++++++++++++++++++++--- src/hms/hmsRadio.h | 1 + src/web/RestApi.h | 4 ++++ src/web/html/system.html | 10 +++++----- src/web/html/visualization.html | 10 +++++++--- 6 files changed, 41 insertions(+), 11 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 7839d420..cfa967f4 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,9 @@ # Development Changes +## 0.8.32 - 2023-12-29 +* fix `start` / `stop` / `restart` commands #1287 +* added message, if profile was not read until now #1300 + ## 0.8.31 - 2023-12-29 * added class to handle timeouts PR #1298 diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 1ed45831..9f96533d 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -276,9 +276,10 @@ class Communication : public CommQueue<> { } else { DBGPRINT(F(" ")); DBGPRINT(String(p->rssi)); - DBGPRINT(F("dBm | ")); + DBGPRINT(F("dBm ")); } if(*mPrintWholeTrace) { + DBGPRINT(F("| ")); if(*mPrivacyMode) ah::dumpBuf(p->packet, p->len, 1, 8); else @@ -363,8 +364,24 @@ class Communication : public CommQueue<> { } inline bool parseDevCtrl(packet_t *p, const queue_s *q) { - if((p->packet[12] != ActivePowerContr) || (p->packet[13] != 0x00)) - return false; + switch(p->packet[12]) { + case ActivePowerContr: + if(p->packet[13] != 0x00) + return false; + break; + + case TurnOn: [[fallthrough]]; + case TurnOff: [[fallthrough]]; + case Restart: + return true; + break; + + default: + DPRINT(DBG_WARN, F("unknown dev ctrl: ")); + DBGHEXLN(p->packet[12]); + break; + } + bool accepted = true; if((p->packet[10] == 0x00) && (p->packet[11] == 0x00)) q->iv->powerLimitAck = true; diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index 2b147107..d2779012 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -99,6 +99,7 @@ class CmtRadio : public Radio { DHEX(mTxBuf[0]); DBGPRINT(F(" ")); DHEX(mTxBuf[10]); + DBGPRINT(F(" ")); DBGHEXLN(mTxBuf[9]); } } diff --git a/src/web/RestApi.h b/src/web/RestApi.h index f2c193cd..f3d70d26 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -316,7 +316,11 @@ class RestApi { void getHtmlReboot(AsyncWebServerRequest *request, JsonObject obj) { getGeneric(request, obj.createNestedObject(F("generic"))); + #if defined(ETHERNET) && defined(CONFIG_IDF_TARGET_ESP32S3) + obj[F("refresh")] = 5; + #else obj[F("refresh")] = 20; + #endif obj[F("refresh_url")] = "/"; obj[F("html")] = F("rebooting ..."); } diff --git a/src/web/html/system.html b/src/web/html/system.html index b5596c7b..ef487ad5 100644 --- a/src/web/html/system.html +++ b/src/web/html/system.html @@ -119,21 +119,21 @@ function parse(obj) { if(null != obj) { - parseGeneric(obj["generic"]); + parseGeneric(obj.generic); - if(null != obj["refresh"]) { + if(null != obj.refresh) { var meta = document.createElement('meta'); meta.httpEquiv = "refresh" - meta.content = obj["refresh"] + "; URL=" + obj["refresh_url"]; + meta.content = obj.refresh + "; URL=" + obj.refresh_url; document.getElementsByTagName('head')[0].appendChild(meta); } else { parseRadio(obj.system); parseMqtt(obj.system.mqtt); - parseSysInfo(obj["system"]); + parseSysInfo(obj.system); getAjax('/api/index', parseIndex); } - document.getElementById("html").innerHTML = obj["html"]; + document.getElementById("html").innerHTML = obj.html; } } diff --git a/src/web/html/visualization.html b/src/web/html/visualization.html index 2c771f5a..d255d1c5 100644 --- a/src/web/html/visualization.html +++ b/src/web/html/visualization.html @@ -357,9 +357,13 @@ var content = []; var g = getGridType(glob.info.type, getGridIdentifier(glob)) if(null === g) { - content.push(ml("div", {class: "row"}, ml("div", {class: "col"}, ml("h5", {}, "Unknown Profile")))) - content.push(ml("div", {class: "row"}, ml("div", {class: "col"}, ml("p", {}, "Please open a new issue at https://github.com/lumapu/ahoy and copy the raw data into it.")))) - content.push(ml("div", {class: "row"}, ml("div", {class: "col my-2"}, ml("pre", {}, obj.grid)))) + if(0 == obj.grid.length) { + content.push(ml("div", {class: "row"}, ml("div", {class: "col"}, ml("p", {}, "Profile was not read until now, maybe turned off?")))) + } else { + content.push(ml("div", {class: "row"}, ml("div", {class: "col"}, ml("h5", {}, "Unknown Profile")))) + content.push(ml("div", {class: "row"}, ml("div", {class: "col"}, ml("p", {}, "Please open a new issue at https://github.com/lumapu/ahoy and copy the raw data into it.")))) + content.push(ml("div", {class: "row"}, ml("div", {class: "col my-2"}, ml("pre", {}, obj.grid)))) + } } else { content.push(ml("div", {class: "row"}, ml("div", {class: "col my-3"}, ml("h5", {}, g + " (Version " + getGridValue(glob).toString(16) + ")")) From a8b10eec6c3be29a4eb3cd74948d610ac24a8470 Mon Sep 17 00:00:00 2001 From: lumapu Date: Fri, 29 Dec 2023 15:12:47 +0100 Subject: [PATCH 261/267] 0.8.32 * added developer option to use 'syslog-server' instead of 'web-serail' #1299 --- src/CHANGES.md | 1 + src/utils/syslog.h | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index cfa967f4..8dde956c 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -3,6 +3,7 @@ ## 0.8.32 - 2023-12-29 * fix `start` / `stop` / `restart` commands #1287 * added message, if profile was not read until now #1300 +* added developer option to use 'syslog-server' instead of 'web-serail' #1299 ## 0.8.31 - 2023-12-29 * added class to handle timeouts PR #1298 diff --git a/src/utils/syslog.h b/src/utils/syslog.h index aac9db14..37bdc524 100644 --- a/src/utils/syslog.h +++ b/src/utils/syslog.h @@ -49,6 +49,6 @@ class DbgSyslog { int mSyslogSeverity = PRI_NOTICE; }; -#endif +#endif /*ENABLE_SYSLOG*/ -#endif \ No newline at end of file +#endif /*__SYSLOG_H__*/ \ No newline at end of file From b043f4c2ac098491b6d3f5e65ffa3c91d7b882d5 Mon Sep 17 00:00:00 2001 From: lumapu Date: Fri, 29 Dec 2023 15:48:25 +0100 Subject: [PATCH 262/267] 0.8.33 * improved communication thx @rejoe2 --- src/CHANGES.md | 3 +++ src/hm/hmRadio.h | 27 ++++++++++++++++++++++----- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 8dde956c..8c1a56f0 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,8 @@ # Development Changes +## 0.8.33 - 2023-12-29 +* improved communication thx @rejoe2 + ## 0.8.32 - 2023-12-29 * fix `start` / `stop` / `restart` commands #1287 * added message, if profile was not read until now #1300 diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index d7ae594b..0754f83c 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -113,34 +113,51 @@ class HmRadio : public Radio { mNrf24->flush_tx(); // empty TX FIFO // start listening + uint8_t chOffset = 2; + mRxChIdx = (mTxChIdx + chOffset) % RF_CHANNELS; mNrf24->setChannel(mRfChLst[mRxChIdx]); mNrf24->startListening(); if(NULL == mLastIv) // prevent reading on NULL object! return; - uint32_t startMicros = micros(); + uint32_t innerLoopTimeout = 55000; uint32_t loopMillis = millis(); uint32_t outerLoopTimeout = (mLastIv->mIsSingleframeReq) ? 100 : ((mLastIv->mCmd != AlarmData) && (mLastIv->mCmd != GridOnProFilePara)) ? 400 : 600; + bool isRxInit = true; + while ((millis() - loopMillis) < outerLoopTimeout) { - startMicros = micros(); - while ((micros() - startMicros) < 5110) { // listen (4088us or?) 5110us to each channel + uint32_t startMicros = micros(); + while ((micros() - startMicros) < innerLoopTimeout) { // listen (4088us or?) 5110us to each channel if (mIrqRcvd) { mIrqRcvd = false; if (getReceived()) { // everything received return; } + + innerLoopTimeout = 4088*5; + if (isRxInit) { + isRxInit = false; + if (micros() - startMicros < 42000) { + innerLoopTimeout = 4088*12; + mRxChIdx = (mRxChIdx + 4) % RF_CHANNELS; + mNrf24->setChannel(mRfChLst[mRxChIdx]); + } + } + + startMicros = micros(); } yield(); } // switch to next RX channel - mRxChIdx = (mRxChIdx + 1) % RF_CHANNELS; + mRxChIdx = (mRxChIdx + 4) % RF_CHANNELS; mNrf24->setChannel(mRfChLst[mRxChIdx]); + innerLoopTimeout = 4088; + isRxInit = false; } // not finished but time is over - mRxChIdx = (mRxChIdx + 1) % RF_CHANNELS; return; } From b8c651e0a8a0c2f30dc526e4656c401986375153 Mon Sep 17 00:00:00 2001 From: lumapu Date: Fri, 29 Dec 2023 15:48:46 +0100 Subject: [PATCH 263/267] 0.8.33 --- src/defines.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/defines.h b/src/defines.h index b3c5089a..6eadb705 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 31 +#define VERSION_PATCH 33 //------------------------------------- typedef struct { From 3178325b42a59fe7555c3fd945917802bd46bf72 Mon Sep 17 00:00:00 2001 From: lumapu Date: Fri, 29 Dec 2023 17:01:07 +0100 Subject: [PATCH 264/267] 0.8.34 release --- src/CHANGES.md | 1019 ++---------------------------------------------- src/defines.h | 2 +- 2 files changed, 32 insertions(+), 989 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 8c1a56f0..6aa9683d 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,992 +1,35 @@ -# Development Changes +Changelog v0.8.34 -## 0.8.33 - 2023-12-29 -* improved communication thx @rejoe2 - -## 0.8.32 - 2023-12-29 -* fix `start` / `stop` / `restart` commands #1287 -* added message, if profile was not read until now #1300 -* added developer option to use 'syslog-server' instead of 'web-serail' #1299 - -## 0.8.31 - 2023-12-29 -* added class to handle timeouts PR #1298 - -## 0.8.30 - 2023-12-28 -* added info if grid profile was not found -* merge PR #1293 -* merge PR #1295 fix ESP8266 pin settings -* merge PR #1297 fix layout for OLED displays - -## 0.8.29 - 2023-12-27 -* fix MqTT generic topic `comm_disabled` #1265 #1286 -* potential fix of #1285 (reset yield day) -* fix fraction of yield correction #1280 -* fix crash if `getLossRate` was read from inverter #1288 #1290 -* reduce reload time for opendtufusion ethernet variant to 5 seconds -* added basic grid parser -* added ESP32-C3 mini environment #1289 - -## 0.8.28 - 2023-12-23 -* fix bug heuristic -* add version information to clipboard once 'copy' was clicked -* add get loss rate @rejoe2 -* improve communication @rejoe2 - -## 0.8.27 - 2023-12-18 -* fix set power limit #1276 - -## 0.8.26 - 2023-12-17 -* read grid profile as HEX (`live` -> click inverter name -> `show grid profile`) - -## 0.8.25 - 2023-12-17 -* RX channel ID starts with fixed value #1277 -* fix static IP for Ethernet - -## 0.8.24 - 2023-12-16 -* fix NRF communication for opendtufusion ethernet variant - -## 0.8.23 - 2023-12-14 -* heuristics fix #1269 #1270 -* moved `sendInterval` in settings, **important:** *will be reseted to 15s after update to this version* -* try to prevent access to radio classes if they are not activated -* fixed millis in serial log -* changed 'print whole trace' = `false` as default -* added communication loop duration in [ms] to serial console -* don't print Hex-Payload if 'print whole trace' == `false` - -## 0.8.22 - 2023-12-13 -* fix communication state-machine regarding zero export #1267 - -## 0.8.21 - 2023-12-12 -* fix ethernet save inverter parameters #886 -* fix ethernet OTA update #886 -* improved radio statistics, fixed heuristic output for HMS and HMT inverters - -## 0.8.20 - 2023-12-12 -* improved HM communication #1259 #1249 -* fix `loadDefaults` for ethernet builds #1263 -* don't loop through radios which aren't in use #1264 - -## 0.8.19 - 2023-12-11 -* added ms to serial log -* added (debug) option to configure gap between inverter requests - -## 0.8.18 - 2023-12-10 -* copied even more from the original heuristic code #1259 -* added mDNS support #1262 - -## 0.8.17 - 2023-12-10 -* possible fix of NRF with opendtufusion (without ETH) -* small fix in heuristics (if conditions made assignment not comparisson) - -## 0.8.16 - 2023-12-09 -* fix crash if NRF is not enabled -* updated heuristic #1080 #1259 -* fix compile opendtufusion fusion ethernet - -## 0.8.15 - 2023-12-09 -* added support for opendtufusion fusion ethernet shield #886 -* fixed range of HMS / HMT frequencies to 863 to 870 MHz #1238 -* changed `yield effiency` per default to `1.0` #1243 -* small heuristics improvements #1258 -* added class to combine inverter heuristics fields #1258 - -## 0.8.14 - 2023-12-07 -* fixed decimal points for temperature (WebUI) PR #1254 #1251 -* fixed inverter statemachine available state PR #1252 #1253 -* fixed NTP update and sunrise calculation #1240 #886 -* display improvments #1248 #1247 -* fixed overflow in `hmRadio.h` #1244 - -## 0.8.13 - 2023-11-28 -* merge PR #1239 symbolic layout for OLED 128x64 + motion senser functionality -* fix MqTT IP addr for ETH connections PR #1240 -* added ethernet build for fusion board, not tested so far - -## 0.8.12 - 2023-11-20 -* added button `copy to clipboard` to `/serial` - -## 0.8.11 - 2023-11-20 -* improved communication, thx @rejoe2 -* improved heuristics, thx @rejoe2, @Oberfritze -* added option to strip payload of frames to significant area - -## 0.8.10 - 2023-11-19 -* fix Mi and HM inverter communication #1235 -* added privacy mode option #1211 -* changed serial debug option to work without reboot - -## 0.8.9 - 2023-11-19 -* merged PR #1234 -* added new alarm codes -* removed serial interval, was not in use anymore - -## 0.8.8 - 2023-11-16 -* fix ESP8266 save inverter #1232 - -## 0.8.7 - 2023-11-13 -* fix ESP8266 inverter settings #1226 -* send radio statistics via MqTT #1227 -* made night communication inverter depended -* added option to prevent adding values of inverter to total values (MqTT only) #1199 - -## 0.8.6 - 2023-11-12 -* merged PR #1225 -* improved heuristics (prevent update of statitistic during testing) - -## 0.8.5 - 2023-11-12 -* fixed endless loop while switching CMT frequency -* removed obsolete "retries" field from settings #1224 -* fixed crash while defining new invertes #1224 -* fixed default frequency settings -* added default input power to `400` while adding new inverters -* fixed color of wifi RSSI icon #1224 - -## 0.8.4 - 2023-11-10 -* changed MqTT alarm topic, removed retained flag #1212 -* reduce last_success MQTT messages (#1124) -* introduced tabs in WebGUI (inverter settings) -* added inverter-wise power level and frequency - -## 0.8.3 - 2023-11-09 -* fix yield day reset during day #848 -* add total AC Max Power to WebUI -* fix opendtufusion build (GxEPD patch) -* fix null ptr PR #1222 - -## 0.8.2 - 2023-11-08 -* beautified inverter settings in `setup` (preperation for future, settings become more inverter dependent) - -## 0.8.1 - 2023-11-05 -* added tx channel heuristics (per inverter) -* fix statistics counter - -## 0.8.0 - 2023-10-?? -* switched to new communication scheme - -## 0.7.66 - 2023-10-04 -* prepared PA-Level for CMT -* removed settings for number of retransmits, its fixed to `5` now -* added parentheses to have a excactly defined behaviour - -## 0.7.65 - 2023-10-02 -* MI control command review #1197 - -## 0.7.64 - 2023-10-02 -* moved active power control to modal in `live` view (per inverter) by click on current APC state - -## 0.7.63 - 2023-10-01 -* fix NRF24 communication #1200 - -## 0.7.62 - 2023-10-01 -* fix communication to inverters #1198 -* add timeout before payload is tried to process (necessary for HMS/HMT) - -## 0.7.61 - 2023-10-01 -* merged `hmPayload` and `hmsPayload` into single class -* merged generic radio functions into new parent class `radio.h` +* improve communication, all inverters are polled during interval +* add hardware info, click on inverter name (in `/live`) +* added RSSI info for HMS and HMT inverters (MqTT + REST API) +* add signal strength for NRF24 +* change ePaper text to symbols +* 2.42" display (SSD1309) integration +* moved active power control to modal in `/live` view (per inverter) by click on current APC state * moved radio statistics into the inverter - each inverter has now seperate statistics which can be accessed by click on the footer in `/live` -* fix compiler warnings #1191 -* fix ePaper logo during night time #1151 - -## 0.7.60 - 2023-09-27 -* fixed typos in changelog #1172 -* fixed MqTT manual clientId storage #1174 -* fixed inverter name length in setup #1181 -* added inverter name to the header of alarm list #1181 -* improved code to avoid warning during compilation #1182 -* fix scheduler #1188, #1179 - -## 0.7.59 - 2023-09-20 -* re-add another HM-400 hardware serial number accidentally removed with `0.7.45` (#1169) -* merge PR #1170 -* reduce last_success MQTT messages (#1124) -* add re-request if inverter is known to be online and first try fails -* add alarm reporting to MI (might need review!) -* rebuild MI limiting code closer to DTUSimMI example -* round APC in `W` to an integer #1171 - -## 0.7.58 -* fix ESP8266 save settings issue #1166 - -## 0.7.57 - 2023-09-18 -* fix Alarms are always in queue (since 0.7.56) -* fix display active power control to long for small devices #1165 - -## 0.7.56 - 2023-09-17 -* only request alarms which were not received before #1113 -* added flag if alarm was requested but not received and re-request it #1105 -* merge PR #1163 - -## 0.7.55 - 2023-09-17 -* fix prometheus builds -* fix ESP32 default pinout #1159 -* added `opendtufusion-dev` because of annoying `-DARDUINO_USB_CDC_ON_BOOT=1` flag -* fix display of current power on `index` -* fix OTA, was damaged by version `0.7.51`, need to use webinstaller (from `0.7.51` to `0.7.54`) - -## 0.7.54 - 2023-09-16 -* added active power control in `W` to live view #201, #673 -* updated docu, active power control related #706 -* added current AC-Power to `index` page and removed version #763 -* improved statistic data, moved to entire struct -* removed `/api/statistics` endpoint from REST-API - -## 0.7.53 - 2023-09-16 -* fix ePaper / display night behaviour #1151 -* fix ESP8266 compile error - -## 0.7.52 - 2023-09-16 -* fix CMT configurable pins #1150, #1159 -* update MqTT lib to version `1.4.5` - -## 0.7.51 - 2023-09-16 -* fix CMT configurable pins #1150 -* fix default CMT pins for opendtufusion -* beautified `system` -* changed main loops, fix resets #1125, #1135 - -## 0.7.50 - 2023-09-12 -* moved MqTT info to `system` -* added CMT info for ESP32 devices -* improved CMT settings, now `SCLK` and `SDIO` are configurable #1046, #1150 -* changed `Power-Limit` in live-view to `Active Power Control` -* increase length of update file selector #1132 - -## 0.7.49 - 2023-09-11 -* merge PR: symbolic icons for mono displays, PR #1136 -* merge MI code restructuring PR #1145 -* merge Prometheus PR #1148 -* add option to strip webUI for ESP8266 (reduce code size, add ESP32 special features; `IF_ESP32` directives) -* started to get CMT info into `system` - not finished - -## 0.7.48 - 2023-09-10 -* fix SSD1309 2.42" display pinout -* improved setup page: save and delete of inverters - -## 0.7.47 - 2023-09-07 -* fix boot loop #1140 -* fix regex in `setup` page -* fix MI serial number display `max-module-power` in `setup` #1142 -* renamed `opendtufusionv1` to `opendtufusion` - -## 0.7.46 - 2023-09-04 -* removed `delay` from ePaper -* started improvements of `/system` -* fix LEDs to check all configured inverters -* send loop skip disabled inverters fix -* print generated DTU SN to console -* HW Versions for MI series PR #1133 -* 2.42" display (SSD1309) integration PR #1139 -* update user manual PR #1121 -* add / rename alarm codes PR #1118 -* revert default pin ESP32 for NRF23-CE #1132 -* luminance of display can be changed during runtime #1106 - -## 0.7.45 - 2023-08-29 -* change ePaper text to symbols PR #1131 -* added some invertes to dev info list #1111 - -## 0.7.44 - 2023-08-28 -* fix `last_success` transmitted to often #1124 - -## 0.7.43 - 2023-08-28 -* improved RSSI for NRF24, now it's read per package (and inverter) #1129 -* arranged `heap` related info together in `/system` -* fix display navi during save -* clean up binary output, separated to folders - -## 0.7.42 - 2023-08-27 -* fix ePaper for opendtufusion_v2.x boards (Software SPI) -* add signal strength for NRF24 - PR #1119 -* refactor wifi class to support ESP32 S2 PR #1127 -* update platform for ESP32 to 6.3.2 -* fix opendtufusion LED (were mixed) -* fix `last_success` transmitted to often #1124 -* added ESP32-S3-mini to github actions -* added old Changelog Entries, to have full log of changes - -## 0.7.41 - 2023-08-26 -* merge PR #1117 code spelling fixes #1112 -* alarms were not read after the first day - -## 0.7.40 - 2023-08-21 +* serveral improvements for MI inverters +* add total AC Max Power to WebUI +* added inverter-wise power-level, frequency and night-communication +* added privacy mode option (`/serial`) +* added button `copy to clipboard` to `/serial` +* added ms to `/serial` +* fixed range of HMS / HMT frequencies to 863 to 870 MHz +* read grid profile (`live` -> click inverter name -> `show grid profile`) +* moved MqTT info to `/system` +* beautified `/system` +* added current AC-Power to `/index` page and removed version * added default pins for opendtu-fusion-v1 board -* fixed hw version display in `live` -* removed development builds, renamed environments in `platform.ini` - -## 0.7.39 - 2023-08-21 -* fix background color of invalid inputs -* add hardware info (click in `live` on inverter name) - -## 0.7.38 - 2023-08-21 -* reset alarms at midnight (if inverter is not available) #1105, #1096 -* add option to reset 'max' values on midnight #1102 -* added default pins for CMT2300A (matching OpenDTU) - -## 0.7.37 - 2023-08-18 -* fix alarm time on WebGui #1099 -* added RSSI info for HMS and HMT inverters (MqTT + REST API) - -# RELEASE 0.7.36 - 2023-08-18 - -## 0.7.35 - 2023-08-17 -* fixed timestamp for alarms send over MqTT -* auto-patch of `AsyncWebServer` #834, #1036 -* Update documentation in Git regarding `ESP8266` default NRF24 pin assignments - -## 0.7.34 - 2023-08-16 -* fixed timezone offset of alarms -* added `AC` and `DC` to `/live` #1098 -* changed `ESP8266` default NRF24 pin assignments (`D3` = `CE` and `D4` = `IRQ`) -* fixed background of modal window for bright color -* fix MI crashes -* fix some lost debug messages -* merged PR #1095, MI fixes for 0.7.x versions -* fix scheduled reboot #1097 -* added vector graphic logo `/doc/logo.svg` -* merge PR #1093, improved Nokia5110 display layout - -## 0.7.33 - 2023-08-15 -* add alarms overview to WebGui #608 -* fix webGui total values #1084 - -## 0.7.32 - 2023-08-14 -* fix colors of live view #1091 - -## 0.7.31 - 2023-08-13 -* fixed docu #1085 -* changed active power limit MqTT messages to QOS2 #1072 -* improved alarm messages, added alarm-id to log #1089 -* trigger power limit read on next day (if inverter was offline meanwhile) -* disabled improv implementation to check if it is related to 'Schwuppdizitaet' -* changed live view to gray once inverter isn't available -* added inverter status to API -* changed sum of totals on WebGui depending on inverter status #1084 -* merge maximum power (AC and DC) from PR #1080 - -## 0.7.30 - 2023-08-10 -* attempt to improve speed / response times (Schwuppdizitaet) #1075 - -## 0.7.29 - 2023-08-09 -* MqTT alarm data was never sent, fixed -* REST API: added alarm data -* REST API: made get record obsolete -* REST API: added power limit acknowledge `/api/inverter/id/[0-x]` #1072 - -## 0.7.28 - 2023-08-08 -* fix MI inverter support #1078 - -## 0.7.27 - 2023-08-08 -* added compile option for ethernet #886 -* fix ePaper configuration, missing `Busy`-Pin #1075 - -# RELEASE 0.7.26 - 2023-08-06 - -* fix MqTT `last_success` - -# RELEASE 0.7.25 - 2023-08-06 - -## 0.7.24 - 2023-08-05 -* merge PR #1069 make MqTT client ID configurable -* fix #1016, general MqTT status depending on inverter state machine -* changed icon for fully available inverter to a filled check mark #1070 -* fixed `last_success` update with MqTT #1068 -* removed `improv` esp-web-installer script, because it is not fully functional at this time - -## 0.7.23 - 2023-08-04 -* merge PR #1056, visualization html -* update MqTT library to 1.4.4 -* update RF24 library to 1.4.7 -* update ArduinoJson library to 6.21.3 -* set minimum invervall for `/live` to 5 seconds - -## 0.7.22 - 2023-08-04 -* attempt to fix homeassistant auto discovery #1066 - -## 0.7.21 - 2023-07-30 -* fix MqTT YieldDay Total goes to 0 several times #1016 - -## 0.7.20 - 2023-07-28 -* merge PR #1048 version and hash in API, fixes #1045 -* fix: no yield day update if yield day reads `0` after inverter reboot (mostly on evening) #848 -* try to fix Wifi override #1047 -* added information after NTP sync to WebUI #1040 - -## 0.7.19 - 2023-07-27 -* next attempt to fix yield day for multiple inverters #1016 -* reduced threshold for inverter state machine from 60min to 15min to go from state `WAS_ON` to `OFF` - -## 0.7.18 - 2023-07-26 -* next attempt to fix yield day for multiple inverters #1016 - -## 0.7.17 - 2023-07-25 -* next attempt to fix yield day for multiple inverters #1016 -* added two more states for the inverter status (also docu) - -## 0.7.16 - 2023-07-24 -* next attempt to fix yield day for multiple inverters #1016 -* fix export settings date #1040 -* fix time on WebUI (timezone was not observed) #913 #1016 - -## 0.7.15 - 2023-07-23 -* add NTP sync interval #1019 -* adjusted range of contrast / luminance setting #1041 -* use only ISO time format in Web-UI #913 - -## 0.7.14 - 2023-07-23 -* fix Contrast for Nokia Display #1041 -* attempt to fix #1016 by improving inverter status -* added option to adjust efficiency for yield (day/total) #1028 - -## 0.7.13 - 2023-07-19 -* merged display PR #1027 -* add date, time and version to export json #1024 - -## 0.7.12 - 2023-07-09 -* added inverter status - state-machine #1016 - -## 0.7.11 - 2023-07-09 -* fix MqTT endless loop #1013 - -## 0.7.10 - 2023-07-08 -* fix MqTT endless loop #1013 - -## 0.7.9 - 2023-07-08 -* added 'improve' functions to set wifi password directly with ESP web tools #1014 -* fixed MqTT publish while applying power limit #1013 -* slightly improved HMT live view (Voltage & Current) - -## 0.7.8 - 2023-07-05 -* fix `YieldDay`, `YieldTotal` and `P_AC` in `TotalValues` #929 -* fix some serial debug prints -* merge PR #1005 which fixes issue #889 -* merge homeassistant PR #963 -* merge PR #890 which gives option for scheduled reboot at midnight (default off) - -## 0.7.7 - 2023-07-03 -* attempt to fix MqTT `YieldDay` in `TotalValues` #927 -* attempt to fix MqTT `YieldDay` and `YieldTotal` even if inverters are not completely available #929 -* fix wrong message 'NRF not connected' if it is disabled #1007 - -## 0.7.6 - 2023-06-17 -* fix display of hidden SSID checkbox -* changed yield correction data type to `double`, now decimal places are supported -* corrected name of 0.91" display in settings -* attempt to fix MqTT zero values only if setting is there #980, #957 -* made AP password configurable #951 -* added option to start without time-sync, eg. for AP-only-mode #951 - -## 0.7.5 - 2023-06-16 -* fix yield day reset on midnight #957 -* improved tickers in `app.cpp` - -## 0.7.4 - 2023-06-15 -* fix MqTT `P_AC` send if inverters are available #987 -* fix assignments for HMS 1CH and 2CH devices -* fixed uptime overflow #990 - -## 0.7.3 - 2023-06-09 -* fix hidden SSID scan #983 -* improved NRF24 missing message on home screen #981 -* fix MqTT publishing only updated values #982 - -## 0.7.2 - 2023-06-08 -* fix HMS-800 and HMS-1000 assignments #981 -* make nrf enabled all the time for ESP8266 -* fix menu item `active` highlight for 'API' and 'Doku' -* fix MqTT totals issue #927, #980 -* reduce maximum number of inverters to 4 for ESP8266, increase to 16 for ESP32 - -## 0.7.1 - 2023-06-05 -* enabled power limit control for HMS / HMT devices -* changed NRF24 lib version back to 1.4.5 because of compile problems for EPS8266 - -## 0.7.0 - 2023-06-04 -* HMS / HMT support for ESP32 devices - -## 0.6.15 - 2023-05-25 -* improved Prometheus Endpoint PR #958 -* fix turn off ePaper only if setting was set #956 -* improved reset values and update MqTT #957 - -## 0.6.14 - 2023-05-21 -* merge PR #902 Mono-Display - -## 0.6.13 - 2023-05-16 -* merge PR #934 (fix JSON API) and #944 (update manual) - -## 0.6.12 - 2023-04-28 -* improved MqTT -* fix menu active item - -## 0.6.11 - 2023-04-27 -* added MqTT class for publishing all values in Arduino `loop` - -## 0.6.10 - HMS -* Version available in `HMS` branch - -# RELEASE 0.6.9 - 2023-04-19 - -## 0.6.8 - 2023-04-19 -* fix #892 `zeroYieldDay` loop was not applied to all channels - -## 0.6.7 - 2023-04-13 -* merge PR #883, improved store of settings and javascript, thx @tastendruecker123 -* support `.` and `,` as floating point separator in setup #881 - -## 0.6.6 - 2023-04-12 -* increased distance for `import` button in mobile view #879 -* changed `led_high_active` to `bool` #879 - -## 0.6.5 - 2023-04-11 -* fix #845 MqTT subscription for `ctrl/power/[IV-ID]` was missing -* merge PR #876, check JSON settings during read for existence -* **NOTE:** incompatible change: renamed `led_high_active` to `act_high`, maybe setting must be changed after update -* merge PR #861 do not send channel metric if channel is disabled - -## 0.6.4 - 2023-04-06 -* merge PR #846, improved NRF24 communication and MI, thx @beegee3 & @rejoe2 -* merge PR #859, fix burger menu height, thx @ThomasPohl - -## 0.6.3 - 2023-04-04 -* fix login, password length was not checked #852 -* merge PR #854 optimize browser caching, thx @tastendruecker123 #828 -* fix WiFi reconnect not working #851 -* updated issue templates #822 - -## 0.6.2 - 2023-04-04 -* fix login from multiple clients #819 -* fix login screen on small displays - -## 0.6.1 - 2023-04-01 -* merge LED fix - LED1 shows MqTT state, LED configurable active high/low #839 -* only publish new inverter data #826 -* potential fix of WiFi hostname during boot up #752 - -# RELEASE 0.6.0 - 2023-03-27 - -## 0.5.110 -* MQTT fix reconnection by new lib version #780 -* add `about` page -* improved documentation regarding SPI pins #814 -* improved documentation (getting started) #815 #816 -* improved MI 4-ch inverter #820 - -## 0.5.109 -* reduced heap fragmentation by optimizing MqTT #768 -* ePaper: centered text thx @knickohr - -## 0.5.108 -* merge: PR SPI pins configurable (ESP32) #807, #806 (requires manual set of MISO=19, MOSI=23, SCLK=18 in GUI for existing installs) -* merge: PR MI serial outputs #809 -* fix: no MQTT `total` sensor for autodiscover if only one inverter was found #805 -* fix: MQTT `total` renamed to `device_name` + `_TOTOL` for better visibility #805 - -## 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 -* fixed MQTT autodiscover #794, #632 - -## 0.5.105 -* merged MI, thx @rejoe2 #788 -* fixed reboot message #793 - -## 0.5.104 -* further improved save settings -* 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 -* changed display inverter online message -* merged heap improvements #772 - -## 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 -* 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 -* 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` -* 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 -* repaired inverter wise limit control -* fix upload settings #686 - -## 0.5.97 -* Attention: re-ordered display types, check your settings! #746 -* improved saving settings of display #747, #746 -* disabled contrast for Nokia display #746 -* added Prometheus as compile option #719, #615 -* update MQTT lib to v1.4.1 -* limit decimal places to 2 in `live` -* added `-DPIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48` to esp8266 debug build #657 -* a `max-module-power` of `0` disables channel in live view `setup` -* merge MI improvements, get firmware information #753 - -## 0.5.96 -* added Nokia display again for ESP8266 #764 -* changed `var` / `VAr` to SI unit `var` #732 -* fix MQTT retained flags for totals (P_AC, P_DC) #726, #721 - -## 0.5.95 -* merged #742 MI Improvements -* merged #736 remove obsolete JSON Endpoint - -## 0.5.94 -* added ePaper (for ESP32 only!), thx @dAjaY85 #735 -* improved `/live` margins #732 -* renamed `var` to `VAr` #732 - -## 0.5.93 -* improved web API for `live` -* added dark mode option -* converted all forms to reponsive design -* repaired menu with password protection #720, #716, #709 -* merged MI series fixes #729 - -## 0.5.92 -* fix mobile menu -* fix inverters in select `serial.html` #709 - -## 0.5.91 -* improved html and navi, navi is visible even when API dies #660 -* reduced maximum allowed JSON size for API to 6000Bytes #660 -* small fix: output command at `prepareDevInformCmd` #692 -* improved inverter handling #671 - -## 0.5.90 -* merged PR #684, #698, #705 -* webserial minor overflow fix #660 -* web `index.html` improve version information #701 -* fix MQTT sets power limit to zero (0) #692 -* changed `reset at midnight` with timezone #697 - -## 0.5.89 -* reduced heap fragmentation (removed `strtok` completely) #644, #645, #682 -* added part of mac address to MQTT client ID to separate multiple ESPs in same network -* added dictionary for MQTT to reduce heap-fragmentation -* removed `last Alarm` from Live view, because it showed always the same alarm - will change in future - -## 0.5.88 -* MQTT Yield Day zero, next try to fix #671, thx @beegee3 -* added Solenso inverter to supported devices -* improved reconnection of MQTT #650 - -## 0.5.87 -* fix yield total correction as module (inverter input) value #570 -* reneabled instant start communication (once NTP is synced) #674 - -## 0.5.86 -* prevent send devcontrol request during disabled night communication -* changed yield total correction as module (inverter input) value #570 -* MQTT Yield Day zero, next try to fix #671 - -## 0.5.85 -* fix power-limit was not checked for max retransmits #667 -* fix blue LED lights up all the time #672 -* fix installing schedulers if NTP server isn't available -* improved zero values on triggers #671 -* hardcoded MQTT subtopics, because wildcard `#` leads to errors -* rephrased some messages on webif, thx to @Argafal #638 -* fixed 'polling stop message' on `index.html` #639 - -## 0.5.84 -* fix blue LED lights up all the time #672 -* added an instant start communication (once NTP is synced) -* add MI 3rd generation inverters (10x2 serial numbers) -* first decodings of messages from MI 2nd generation inverters - -## 0.5.83 -* fix MQTT publishing, `callback` was set but reset by following `setup()` - -## 0.5.82 -* fixed communication error #652 -* reset values is no bound to MQTT any more, setting moved to `inverter` #649 -* fixed wording on `index.hmtl` #661 - -## 0.5.81 -* started implementation of MI inverters (setup.html, own processing `MiPayload.h`) - -## 0.5.80 -* fixed communication #656 - -## 0.5.79 -* fixed mixed reset flags #648 -* fixed `mCbAlarm` if MQTT is not used #653 -* fixed MQTT `autodiscover` #630 thanks to @antibill51 -* next changes from @beegee many thanks for your contribution! -* replaced `CircularBuffer` by `std::queue` -* reworked `hmRadio.h` completely (interrupts, packaging) -* fix exception while `reboot` -* cleanup MQTT coding - -## 0.5.78 -* further improvements regarding wifi #611, fix connection if only one AP with same SSID is there -* fix endless loop in `zerovalues` #564 -* fix auto discover again #565 -* added total values to autodiscover #630 -* improved zero at midnight #625 - -## 0.5.77 -* fix wrong filename for automatically created manifest (online installer) #620 -* added rotate display feature #619 -* improved Prometheus endpoint #615, thx to @fsck-block -* improved wifi to connect always to strongest RSSI, thx to @beegee3 #611 - -## 0.5.76 -* reduce MQTT retry interval from maximum speed to one second -* fixed homeassistant autodiscovery #565 -* implemented `getNTPTime` improvements #609 partially #611 -* added alarm messages to MQTT #177, #600, #608 - -## 0.5.75 -* fix wakeup issue, once wifi was lost during night the communication didn't start in the morning -* re-enabled FlashStringHelper because of lacking RAM -* complete rewrite of monochrome display class, thx to @dAjaY85 -> displays are now configurable in setup -* fix power limit not possible #607 - -## 0.5.74 -* improved payload handling (retransmit all fragments on CRC error) -* improved `isAvailable`, checks all record structs, inverter becomes available more early because version is check first -* fix tickers were not set if NTP is not available -* disabled annoying `FlashStringHelper` it gives randomly Exceptions during development, feels more stable since then -* moved erase button to the bottom in settings, not nice but more functional -* split `tx_count` to `tx_cnt` and `retransmits` in `system.html` -* fix mqtt retransmit IP address #602 -* added debug infos for `scheduler` (web -> `/debug` as trigger prints list of tickers to serial console) - -## 0.5.73 -* improved payload handling (request / retransmit) #464 -* included alarm ID parse to serial console (in development) - -## 0.5.72 -* repaired system, scheduler was not called any more #596 - -## 0.5.71 -* improved wifi handling and tickers, many thanks to @beegee3 #571 -* fixed YieldTotal correction calculation #589 -* fixed serial output of power limit acknowledge #569 -* reviewed `sendDiscoveryConfig` #565 -* merged PR `Monodisplay`, many thanks to @dAjaY85 #566, Note: (settings are introduced but not able to be modified, will be included in next version) - -## 0.5.70 -* corrected MQTT `comm_disabled` #529 -* fix Prometheus and JSON endpoints (`config_override.h`) #561 -* publish MQTT with fixed interval even if inverter is not available #542 -* added JSON settings upload. NOTE: settings JSON download changed, so only settings should be uploaded starting from version `0.5.70` #551 -* MQTT topic and inverter name have more allowed characters: `[A-Za-z0-9./#$%&=+_-]+`, thx: @Mo Demman -* improved potential issue with `checkTicker`, thx @cbscpe -* MQTT option for reset values on midnight / not avail / communication stop #539 -* small fix in `tickIVCommunication` #534 -* add `YieldTotal` correction, eg. to have the option to zero at year start #512 - -## 0.5.69 -* merged SH1106 1.3" Display, thx @dAjaY85 -* added SH1106 to automatic build -* added IP address to MQTT (version, device and IP are retained and only transmitted once after boot) #556 -* added `set_power_limit` acknowledge MQTT publish #553 -* changed: version, device name are only published via MQTT once after boot -* added `Login` to menu if admin password is set #554 -* added `development` to second changelog link in `index.html` #543 -* added interval for MQTT (as option). With this settings MQTT live data is published in a fixed timing (only if inverter is available) #542, #523 -* added MQTT `comm_disabled` #529 -* changed name of binaries, moved GIT-Sha to the front #538 - -## 0.5.68 -* repaired receive payload -* Powerlimit is transferred immediately to inverter - -## 0.5.67 -* changed calculation of start / stop communication to 1 min after last comm. stop #515 -* moved payload send to `payload.h`, function `ivSend` #515 -* payload: if last frame is missing, request all frames again - -# RELEASE 0.5.66 - 2022-12-30 - -## 0.5.65 -* wifi, code optimization #509 - -## 0.5.64 -* channel name can use any character, not limited any more -* added `/` to MQTT topic and Inverter name -* trigger for `calcSunrise` is now using local time #515 -* fix reconnect timeout for WiFi #509 -* start AP only after boot, not on WiFi connection loss -* improved /system `free_heap` value (measured before JSON-tree is built) - -## 0.5.63 -* fix Update button protection (prevent double click #527) -* optimized scheduler #515 (thx @beegee3) -* potential fix of #526 duplicates in API `/api/record/live` -* added update information to `index.html` - -## 0.5.62 -* fix MQTT `status` update -* removed MQTT `available_text` (can be deducted from `available`) -* enhanced MQTT documentation in `User_Manual.md` -* removed `tickSunset` and `tickSunrise` from MQTT. It's not needed any more because of minute wise check of status (`processIvStatus`) -* changed MQTT topic `status` to nummeric value, check documentation in `User_Manual.md` -* fix regular expression of `setup.html` for inverter name and channel name - -## 0.5.61 -* fix #521 no reconnect at beginning of day -* added immediate (each minute) report of inverter status MQTT #522 -* added protection mask to select which pages should be protected -* update of monochrome display, show values also if nothing changed - -## 0.5.60 -* added regex to inverter name and MQTT topic (setup.html) -* beautified serial.html -* added ticker for wifi loop #515 - -## 0.5.59 -* fix night communication enable -* improved different WiFi connection scenarios (STA WiFi not found, reconnect #509, redirect for AP to configuration) -* increased MQTT user, pwd and topic length to 64 characters + `\0`. (The string end `\0` reduces the available size by one) #516 - -## 0.5.58 -* improved stability -* improved WiFi initial connection - especially if station WiFi is not available -* removed new operators from web.h (reduce dynamic allocation) -* improved sun calculation #515, #505 -* fixed WiFi auto reconnect #509 -* added disable night communication flag to MQTT #505 -* changed MQTT publish of `available` and `available_text` to sunset #468 - -## 0.5.57 -* improved stability -* added icons to index.html, added WiFi-strength symbol on each page -* moved packet stats and sun to system.html -* refactored communication offset (adjustable in minutes now) - -## 0.5.56 -* factory reset formats entire little fs -* renamed sunrise / sunset on index.html to start / stop communication -* show system information only if called directly from menu -* beautified system.html - -## 0.5.55 -* fixed static IP save - -## 0.5.54 -* changed sunrise / sunset calculation, angle is now `-3.5` instead of original `-0.83` -* improved scheduler (removed -1 from `reload`) #483 -* improved reboot flag in `app.h` -* fixed #493 no MQTT payload once display is defined - -## 0.5.53 -* Mono-Display: show values in offline mode #498 -* improved WiFi class #483 -* added communication enable / disable (to test multiple DTUs with the same inverter) -* fix factory reset #495 - -## 0.5.52 -* improved ahoyWifi class -* added interface class for app -* refactored web and webApi -> RestApi -* fix calcSunrise was not called every day -* added MQTT RX counter to index.html -* all values are displayed on /live even if they are 0 -* added MQTT /status to show status over all inverters - -## 0.5.51 -* improved scheduler, @beegee3 #483 -* refactored get NTP time, @beegee3 #483 -* generate `bin.gz` only for 1M device ESP8285 -* fix calcSunrise was not called every day -* increased number of allowed characters for MQTT user, broker and password, @DanielR92 -* added NRF24 info to Systeminfo, @DanielR92 -* added timezone for monochrome displays, @gh-fx2 -* added support for second inverter for monochrome displays, @gh-fx2 - -## 0.5.50 -* fixed scheduler, uptime and timestamp counted too fast -* added / renamed automatically build outputs -* fixed MQTT ESP uptime on reconnect (not zero any more) -* changed uptime on index.html to count each second, synced with ESP each 10 seconds - -## 0.5.49 -* fixed AP mode on brand new ESP modules -* fixed `last_success` MQTT message -* fixed MQTT inverter available status at sunset -* reordered enqueue commands after boot up to prevent same payload length for successive commands -* added automatic build for Nokia5110 and SSD1306 displays (ESP8266) - -## 0.5.48 -* added MQTT message send at sunset -* added monochrome display support -* added `once` and `onceAt` to scheduler to make code cleaner -* improved sunrise / sunset calculation - -## 0.5.47 -* refactored ahoyWifi class: AP is opened on every boot, once station connection is successful the AP will be closed -* improved NTP sync after boot, faster sync -* fix NRF24 details only on valid SPI connection - -## 0.5.46 -* fix sunrise / sunset calculation -* improved setup.html: `reboot on save` is checked as default - -## 0.5.45 -* changed MQTT last will topic from `status` to `mqtt` -* fix sunrise / sunset calculation -* fix time of serial web console - -## 0.5.44 -* marked some MQTT messages as retained -* moved global functions to global location (no duplicates) -* changed index.html interval to static 10 seconds -* fix static IP -* fix NTP with static IP -* print MQTT info only if MQTT was configured - -## 0.5.43 -* updated REST API and MQTT (both of them use the same functionality) -* added ESP-heap information as MQTT message -* changed output name of automatic development build to fixed name (to have a static link from https://ahoydtu.de) -* updated user manual to latest MQTT and API changes - -## 0.5.42 -* fix web logout (auto logout) -* switched MQTT library - -# RELEASE 0.5.41 - 2022-11-22 - -# RELEASE 0.5.28 - 2022-10-30 - -# RELEASE 0.5.17 - 2022-09-06 - -# RELEASE 0.5.16 - 2022-09-04 +* added default pins for ESP32 with CMT2300A (matching OpenDTU) +* added ethernet build for fusion board +* added ESP32-S2 to github actions +* added ESP32-S3-mini to github actions +* added ESP32-C3-mini to github actions +* add option to reset 'max' values on midnight +* luminance of display can be changed during runtime +* added developer option to use 'syslog-server' instead of 'web-serail' +* added / renamed alarm codes +* changed MqTT alarm topic, removed retained flag +* added default input power to `400` while adding new inverters +full version log: [Development Log](https://github.com/lumapu/ahoy/blob/development03/src/CHANGES.md) \ No newline at end of file diff --git a/src/defines.h b/src/defines.h index 6eadb705..ff7e9772 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 33 +#define VERSION_PATCH 34 //------------------------------------- typedef struct { From b5cdd775a77f2c1a350087714bbf230ac9124b9d Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 30 Dec 2023 00:20:36 +0100 Subject: [PATCH 265/267] 0.8.35 * added dim option for LEDS * changed reload time for opendtufusion after update to 5s --- .github/workflows/compile_release.yml | 2 +- src/CHANGES.md | 1025 ++++++++++++++++++++++++- src/app.cpp | 22 +- src/config/settings.h | 29 +- src/defines.h | 2 +- src/web/RestApi.h | 3 +- src/web/html/setup.html | 6 +- src/web/web.h | 31 +- 8 files changed, 1051 insertions(+), 69 deletions(-) diff --git a/.github/workflows/compile_release.yml b/.github/workflows/compile_release.yml index 61c920b3..e65494ab 100644 --- a/.github/workflows/compile_release.yml +++ b/.github/workflows/compile_release.yml @@ -77,7 +77,7 @@ jobs: VERSION: ${{ steps.rename-binary-files.outputs.name }} - name: Create Artifact - run: zip --junk-paths ${{ steps.rename-binary-files.outputs.name }}.zip src/firmware/* rc/firmware/s3/* User_Manual.md + run: zip --junk-paths ${{ steps.rename-binary-files.outputs.name }}.zip src/firmware/* User_Manual.md - name: Upload Release id: upload-release diff --git a/src/CHANGES.md b/src/CHANGES.md index 6aa9683d..52f185f3 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,35 +1,998 @@ -Changelog v0.8.34 +# Development Changes -* improve communication, all inverters are polled during interval -* add hardware info, click on inverter name (in `/live`) -* added RSSI info for HMS and HMT inverters (MqTT + REST API) -* add signal strength for NRF24 -* change ePaper text to symbols -* 2.42" display (SSD1309) integration -* moved active power control to modal in `/live` view (per inverter) by click on current APC state -* moved radio statistics into the inverter - each inverter has now seperate statistics which can be accessed by click on the footer in `/live` -* serveral improvements for MI inverters -* add total AC Max Power to WebUI -* added inverter-wise power-level, frequency and night-communication -* added privacy mode option (`/serial`) +## 0.8.35 - 2023-12-30 +* added dim option for LEDS +* changed reload time for opendtufusion after update to 5s + +# RELEASE 0.8.34 - 2023-12-29 + +## 0.8.33 - 2023-12-29 +* improved communication thx @rejoe2 + +## 0.8.32 - 2023-12-29 +* fix `start` / `stop` / `restart` commands #1287 +* added message, if profile was not read until now #1300 +* added developer option to use 'syslog-server' instead of 'web-serail' #1299 + +## 0.8.31 - 2023-12-29 +* added class to handle timeouts PR #1298 + +## 0.8.30 - 2023-12-28 +* added info if grid profile was not found +* merge PR #1293 +* merge PR #1295 fix ESP8266 pin settings +* merge PR #1297 fix layout for OLED displays + +## 0.8.29 - 2023-12-27 +* fix MqTT generic topic `comm_disabled` #1265 #1286 +* potential fix of #1285 (reset yield day) +* fix fraction of yield correction #1280 +* fix crash if `getLossRate` was read from inverter #1288 #1290 +* reduce reload time for opendtufusion ethernet variant to 5 seconds +* added basic grid parser +* added ESP32-C3 mini environment #1289 + +## 0.8.28 - 2023-12-23 +* fix bug heuristic +* add version information to clipboard once 'copy' was clicked +* add get loss rate @rejoe2 +* improve communication @rejoe2 + +## 0.8.27 - 2023-12-18 +* fix set power limit #1276 + +## 0.8.26 - 2023-12-17 +* read grid profile as HEX (`live` -> click inverter name -> `show grid profile`) + +## 0.8.25 - 2023-12-17 +* RX channel ID starts with fixed value #1277 +* fix static IP for Ethernet + +## 0.8.24 - 2023-12-16 +* fix NRF communication for opendtufusion ethernet variant + +## 0.8.23 - 2023-12-14 +* heuristics fix #1269 #1270 +* moved `sendInterval` in settings, **important:** *will be reseted to 15s after update to this version* +* try to prevent access to radio classes if they are not activated +* fixed millis in serial log +* changed 'print whole trace' = `false` as default +* added communication loop duration in [ms] to serial console +* don't print Hex-Payload if 'print whole trace' == `false` + +## 0.8.22 - 2023-12-13 +* fix communication state-machine regarding zero export #1267 + +## 0.8.21 - 2023-12-12 +* fix ethernet save inverter parameters #886 +* fix ethernet OTA update #886 +* improved radio statistics, fixed heuristic output for HMS and HMT inverters + +## 0.8.20 - 2023-12-12 +* improved HM communication #1259 #1249 +* fix `loadDefaults` for ethernet builds #1263 +* don't loop through radios which aren't in use #1264 + +## 0.8.19 - 2023-12-11 +* added ms to serial log +* added (debug) option to configure gap between inverter requests + +## 0.8.18 - 2023-12-10 +* copied even more from the original heuristic code #1259 +* added mDNS support #1262 + +## 0.8.17 - 2023-12-10 +* possible fix of NRF with opendtufusion (without ETH) +* small fix in heuristics (if conditions made assignment not comparisson) + +## 0.8.16 - 2023-12-09 +* fix crash if NRF is not enabled +* updated heuristic #1080 #1259 +* fix compile opendtufusion fusion ethernet + +## 0.8.15 - 2023-12-09 +* added support for opendtufusion fusion ethernet shield #886 +* fixed range of HMS / HMT frequencies to 863 to 870 MHz #1238 +* changed `yield effiency` per default to `1.0` #1243 +* small heuristics improvements #1258 +* added class to combine inverter heuristics fields #1258 + +## 0.8.14 - 2023-12-07 +* fixed decimal points for temperature (WebUI) PR #1254 #1251 +* fixed inverter statemachine available state PR #1252 #1253 +* fixed NTP update and sunrise calculation #1240 #886 +* display improvments #1248 #1247 +* fixed overflow in `hmRadio.h` #1244 + +## 0.8.13 - 2023-11-28 +* merge PR #1239 symbolic layout for OLED 128x64 + motion senser functionality +* fix MqTT IP addr for ETH connections PR #1240 +* added ethernet build for fusion board, not tested so far + +## 0.8.12 - 2023-11-20 * added button `copy to clipboard` to `/serial` -* added ms to `/serial` -* fixed range of HMS / HMT frequencies to 863 to 870 MHz -* read grid profile (`live` -> click inverter name -> `show grid profile`) -* moved MqTT info to `/system` -* beautified `/system` -* added current AC-Power to `/index` page and removed version -* added default pins for opendtu-fusion-v1 board -* added default pins for ESP32 with CMT2300A (matching OpenDTU) -* added ethernet build for fusion board -* added ESP32-S2 to github actions -* added ESP32-S3-mini to github actions -* added ESP32-C3-mini to github actions -* add option to reset 'max' values on midnight -* luminance of display can be changed during runtime -* added developer option to use 'syslog-server' instead of 'web-serail' -* added / renamed alarm codes -* changed MqTT alarm topic, removed retained flag + +## 0.8.11 - 2023-11-20 +* improved communication, thx @rejoe2 +* improved heuristics, thx @rejoe2, @Oberfritze +* added option to strip payload of frames to significant area + +## 0.8.10 - 2023-11-19 +* fix Mi and HM inverter communication #1235 +* added privacy mode option #1211 +* changed serial debug option to work without reboot + +## 0.8.9 - 2023-11-19 +* merged PR #1234 +* added new alarm codes +* removed serial interval, was not in use anymore + +## 0.8.8 - 2023-11-16 +* fix ESP8266 save inverter #1232 + +## 0.8.7 - 2023-11-13 +* fix ESP8266 inverter settings #1226 +* send radio statistics via MqTT #1227 +* made night communication inverter depended +* added option to prevent adding values of inverter to total values (MqTT only) #1199 + +## 0.8.6 - 2023-11-12 +* merged PR #1225 +* improved heuristics (prevent update of statitistic during testing) + +## 0.8.5 - 2023-11-12 +* fixed endless loop while switching CMT frequency +* removed obsolete "retries" field from settings #1224 +* fixed crash while defining new invertes #1224 +* fixed default frequency settings * added default input power to `400` while adding new inverters +* fixed color of wifi RSSI icon #1224 + +## 0.8.4 - 2023-11-10 +* changed MqTT alarm topic, removed retained flag #1212 +* reduce last_success MQTT messages (#1124) +* introduced tabs in WebGUI (inverter settings) +* added inverter-wise power level and frequency + +## 0.8.3 - 2023-11-09 +* fix yield day reset during day #848 +* add total AC Max Power to WebUI +* fix opendtufusion build (GxEPD patch) +* fix null ptr PR #1222 + +## 0.8.2 - 2023-11-08 +* beautified inverter settings in `setup` (preperation for future, settings become more inverter dependent) + +## 0.8.1 - 2023-11-05 +* added tx channel heuristics (per inverter) +* fix statistics counter + +## 0.8.0 - 2023-10-?? +* switched to new communication scheme + +## 0.7.66 - 2023-10-04 +* prepared PA-Level for CMT +* removed settings for number of retransmits, its fixed to `5` now +* added parentheses to have a excactly defined behaviour + +## 0.7.65 - 2023-10-02 +* MI control command review #1197 + +## 0.7.64 - 2023-10-02 +* moved active power control to modal in `live` view (per inverter) by click on current APC state + +## 0.7.63 - 2023-10-01 +* fix NRF24 communication #1200 + +## 0.7.62 - 2023-10-01 +* fix communication to inverters #1198 +* add timeout before payload is tried to process (necessary for HMS/HMT) + +## 0.7.61 - 2023-10-01 +* merged `hmPayload` and `hmsPayload` into single class +* merged generic radio functions into new parent class `radio.h` +* moved radio statistics into the inverter - each inverter has now seperate statistics which can be accessed by click on the footer in `/live` +* fix compiler warnings #1191 +* fix ePaper logo during night time #1151 + +## 0.7.60 - 2023-09-27 +* fixed typos in changelog #1172 +* fixed MqTT manual clientId storage #1174 +* fixed inverter name length in setup #1181 +* added inverter name to the header of alarm list #1181 +* improved code to avoid warning during compilation #1182 +* fix scheduler #1188, #1179 + +## 0.7.59 - 2023-09-20 +* re-add another HM-400 hardware serial number accidentally removed with `0.7.45` (#1169) +* merge PR #1170 +* reduce last_success MQTT messages (#1124) +* add re-request if inverter is known to be online and first try fails +* add alarm reporting to MI (might need review!) +* rebuild MI limiting code closer to DTUSimMI example +* round APC in `W` to an integer #1171 + +## 0.7.58 +* fix ESP8266 save settings issue #1166 + +## 0.7.57 - 2023-09-18 +* fix Alarms are always in queue (since 0.7.56) +* fix display active power control to long for small devices #1165 + +## 0.7.56 - 2023-09-17 +* only request alarms which were not received before #1113 +* added flag if alarm was requested but not received and re-request it #1105 +* merge PR #1163 + +## 0.7.55 - 2023-09-17 +* fix prometheus builds +* fix ESP32 default pinout #1159 +* added `opendtufusion-dev` because of annoying `-DARDUINO_USB_CDC_ON_BOOT=1` flag +* fix display of current power on `index` +* fix OTA, was damaged by version `0.7.51`, need to use webinstaller (from `0.7.51` to `0.7.54`) + +## 0.7.54 - 2023-09-16 +* added active power control in `W` to live view #201, #673 +* updated docu, active power control related #706 +* added current AC-Power to `index` page and removed version #763 +* improved statistic data, moved to entire struct +* removed `/api/statistics` endpoint from REST-API + +## 0.7.53 - 2023-09-16 +* fix ePaper / display night behaviour #1151 +* fix ESP8266 compile error + +## 0.7.52 - 2023-09-16 +* fix CMT configurable pins #1150, #1159 +* update MqTT lib to version `1.4.5` + +## 0.7.51 - 2023-09-16 +* fix CMT configurable pins #1150 +* fix default CMT pins for opendtufusion +* beautified `system` +* changed main loops, fix resets #1125, #1135 + +## 0.7.50 - 2023-09-12 +* moved MqTT info to `system` +* added CMT info for ESP32 devices +* improved CMT settings, now `SCLK` and `SDIO` are configurable #1046, #1150 +* changed `Power-Limit` in live-view to `Active Power Control` +* increase length of update file selector #1132 + +## 0.7.49 - 2023-09-11 +* merge PR: symbolic icons for mono displays, PR #1136 +* merge MI code restructuring PR #1145 +* merge Prometheus PR #1148 +* add option to strip webUI for ESP8266 (reduce code size, add ESP32 special features; `IF_ESP32` directives) +* started to get CMT info into `system` - not finished + +## 0.7.48 - 2023-09-10 +* fix SSD1309 2.42" display pinout +* improved setup page: save and delete of inverters + +## 0.7.47 - 2023-09-07 +* fix boot loop #1140 +* fix regex in `setup` page +* fix MI serial number display `max-module-power` in `setup` #1142 +* renamed `opendtufusionv1` to `opendtufusion` + +## 0.7.46 - 2023-09-04 +* removed `delay` from ePaper +* started improvements of `/system` +* fix LEDs to check all configured inverters +* send loop skip disabled inverters fix +* print generated DTU SN to console +* HW Versions for MI series PR #1133 +* 2.42" display (SSD1309) integration PR #1139 +* update user manual PR #1121 +* add / rename alarm codes PR #1118 +* revert default pin ESP32 for NRF23-CE #1132 +* luminance of display can be changed during runtime #1106 + +## 0.7.45 - 2023-08-29 +* change ePaper text to symbols PR #1131 +* added some invertes to dev info list #1111 + +## 0.7.44 - 2023-08-28 +* fix `last_success` transmitted to often #1124 + +## 0.7.43 - 2023-08-28 +* improved RSSI for NRF24, now it's read per package (and inverter) #1129 +* arranged `heap` related info together in `/system` +* fix display navi during save +* clean up binary output, separated to folders + +## 0.7.42 - 2023-08-27 +* fix ePaper for opendtufusion_v2.x boards (Software SPI) +* add signal strength for NRF24 - PR #1119 +* refactor wifi class to support ESP32 S2 PR #1127 +* update platform for ESP32 to 6.3.2 +* fix opendtufusion LED (were mixed) +* fix `last_success` transmitted to often #1124 +* added ESP32-S3-mini to github actions +* added old Changelog Entries, to have full log of changes + +## 0.7.41 - 2023-08-26 +* merge PR #1117 code spelling fixes #1112 +* alarms were not read after the first day + +## 0.7.40 - 2023-08-21 +* added default pins for opendtu-fusion-v1 board +* fixed hw version display in `live` +* removed development builds, renamed environments in `platform.ini` + +## 0.7.39 - 2023-08-21 +* fix background color of invalid inputs +* add hardware info (click in `live` on inverter name) + +## 0.7.38 - 2023-08-21 +* reset alarms at midnight (if inverter is not available) #1105, #1096 +* add option to reset 'max' values on midnight #1102 +* added default pins for CMT2300A (matching OpenDTU) + +## 0.7.37 - 2023-08-18 +* fix alarm time on WebGui #1099 +* added RSSI info for HMS and HMT inverters (MqTT + REST API) + +# RELEASE 0.7.36 - 2023-08-18 + +## 0.7.35 - 2023-08-17 +* fixed timestamp for alarms send over MqTT +* auto-patch of `AsyncWebServer` #834, #1036 +* Update documentation in Git regarding `ESP8266` default NRF24 pin assignments + +## 0.7.34 - 2023-08-16 +* fixed timezone offset of alarms +* added `AC` and `DC` to `/live` #1098 +* changed `ESP8266` default NRF24 pin assignments (`D3` = `CE` and `D4` = `IRQ`) +* fixed background of modal window for bright color +* fix MI crashes +* fix some lost debug messages +* merged PR #1095, MI fixes for 0.7.x versions +* fix scheduled reboot #1097 +* added vector graphic logo `/doc/logo.svg` +* merge PR #1093, improved Nokia5110 display layout + +## 0.7.33 - 2023-08-15 +* add alarms overview to WebGui #608 +* fix webGui total values #1084 + +## 0.7.32 - 2023-08-14 +* fix colors of live view #1091 + +## 0.7.31 - 2023-08-13 +* fixed docu #1085 +* changed active power limit MqTT messages to QOS2 #1072 +* improved alarm messages, added alarm-id to log #1089 +* trigger power limit read on next day (if inverter was offline meanwhile) +* disabled improv implementation to check if it is related to 'Schwuppdizitaet' +* changed live view to gray once inverter isn't available +* added inverter status to API +* changed sum of totals on WebGui depending on inverter status #1084 +* merge maximum power (AC and DC) from PR #1080 + +## 0.7.30 - 2023-08-10 +* attempt to improve speed / response times (Schwuppdizitaet) #1075 + +## 0.7.29 - 2023-08-09 +* MqTT alarm data was never sent, fixed +* REST API: added alarm data +* REST API: made get record obsolete +* REST API: added power limit acknowledge `/api/inverter/id/[0-x]` #1072 + +## 0.7.28 - 2023-08-08 +* fix MI inverter support #1078 + +## 0.7.27 - 2023-08-08 +* added compile option for ethernet #886 +* fix ePaper configuration, missing `Busy`-Pin #1075 + +# RELEASE 0.7.26 - 2023-08-06 + +* fix MqTT `last_success` + +# RELEASE 0.7.25 - 2023-08-06 + +## 0.7.24 - 2023-08-05 +* merge PR #1069 make MqTT client ID configurable +* fix #1016, general MqTT status depending on inverter state machine +* changed icon for fully available inverter to a filled check mark #1070 +* fixed `last_success` update with MqTT #1068 +* removed `improv` esp-web-installer script, because it is not fully functional at this time + +## 0.7.23 - 2023-08-04 +* merge PR #1056, visualization html +* update MqTT library to 1.4.4 +* update RF24 library to 1.4.7 +* update ArduinoJson library to 6.21.3 +* set minimum invervall for `/live` to 5 seconds + +## 0.7.22 - 2023-08-04 +* attempt to fix homeassistant auto discovery #1066 + +## 0.7.21 - 2023-07-30 +* fix MqTT YieldDay Total goes to 0 several times #1016 + +## 0.7.20 - 2023-07-28 +* merge PR #1048 version and hash in API, fixes #1045 +* fix: no yield day update if yield day reads `0` after inverter reboot (mostly on evening) #848 +* try to fix Wifi override #1047 +* added information after NTP sync to WebUI #1040 + +## 0.7.19 - 2023-07-27 +* next attempt to fix yield day for multiple inverters #1016 +* reduced threshold for inverter state machine from 60min to 15min to go from state `WAS_ON` to `OFF` + +## 0.7.18 - 2023-07-26 +* next attempt to fix yield day for multiple inverters #1016 + +## 0.7.17 - 2023-07-25 +* next attempt to fix yield day for multiple inverters #1016 +* added two more states for the inverter status (also docu) + +## 0.7.16 - 2023-07-24 +* next attempt to fix yield day for multiple inverters #1016 +* fix export settings date #1040 +* fix time on WebUI (timezone was not observed) #913 #1016 + +## 0.7.15 - 2023-07-23 +* add NTP sync interval #1019 +* adjusted range of contrast / luminance setting #1041 +* use only ISO time format in Web-UI #913 + +## 0.7.14 - 2023-07-23 +* fix Contrast for Nokia Display #1041 +* attempt to fix #1016 by improving inverter status +* added option to adjust efficiency for yield (day/total) #1028 + +## 0.7.13 - 2023-07-19 +* merged display PR #1027 +* add date, time and version to export json #1024 + +## 0.7.12 - 2023-07-09 +* added inverter status - state-machine #1016 + +## 0.7.11 - 2023-07-09 +* fix MqTT endless loop #1013 + +## 0.7.10 - 2023-07-08 +* fix MqTT endless loop #1013 + +## 0.7.9 - 2023-07-08 +* added 'improve' functions to set wifi password directly with ESP web tools #1014 +* fixed MqTT publish while applying power limit #1013 +* slightly improved HMT live view (Voltage & Current) + +## 0.7.8 - 2023-07-05 +* fix `YieldDay`, `YieldTotal` and `P_AC` in `TotalValues` #929 +* fix some serial debug prints +* merge PR #1005 which fixes issue #889 +* merge homeassistant PR #963 +* merge PR #890 which gives option for scheduled reboot at midnight (default off) + +## 0.7.7 - 2023-07-03 +* attempt to fix MqTT `YieldDay` in `TotalValues` #927 +* attempt to fix MqTT `YieldDay` and `YieldTotal` even if inverters are not completely available #929 +* fix wrong message 'NRF not connected' if it is disabled #1007 + +## 0.7.6 - 2023-06-17 +* fix display of hidden SSID checkbox +* changed yield correction data type to `double`, now decimal places are supported +* corrected name of 0.91" display in settings +* attempt to fix MqTT zero values only if setting is there #980, #957 +* made AP password configurable #951 +* added option to start without time-sync, eg. for AP-only-mode #951 + +## 0.7.5 - 2023-06-16 +* fix yield day reset on midnight #957 +* improved tickers in `app.cpp` + +## 0.7.4 - 2023-06-15 +* fix MqTT `P_AC` send if inverters are available #987 +* fix assignments for HMS 1CH and 2CH devices +* fixed uptime overflow #990 + +## 0.7.3 - 2023-06-09 +* fix hidden SSID scan #983 +* improved NRF24 missing message on home screen #981 +* fix MqTT publishing only updated values #982 + +## 0.7.2 - 2023-06-08 +* fix HMS-800 and HMS-1000 assignments #981 +* make nrf enabled all the time for ESP8266 +* fix menu item `active` highlight for 'API' and 'Doku' +* fix MqTT totals issue #927, #980 +* reduce maximum number of inverters to 4 for ESP8266, increase to 16 for ESP32 + +## 0.7.1 - 2023-06-05 +* enabled power limit control for HMS / HMT devices +* changed NRF24 lib version back to 1.4.5 because of compile problems for EPS8266 + +## 0.7.0 - 2023-06-04 +* HMS / HMT support for ESP32 devices + +## 0.6.15 - 2023-05-25 +* improved Prometheus Endpoint PR #958 +* fix turn off ePaper only if setting was set #956 +* improved reset values and update MqTT #957 + +## 0.6.14 - 2023-05-21 +* merge PR #902 Mono-Display + +## 0.6.13 - 2023-05-16 +* merge PR #934 (fix JSON API) and #944 (update manual) + +## 0.6.12 - 2023-04-28 +* improved MqTT +* fix menu active item + +## 0.6.11 - 2023-04-27 +* added MqTT class for publishing all values in Arduino `loop` + +## 0.6.10 - HMS +* Version available in `HMS` branch + +# RELEASE 0.6.9 - 2023-04-19 + +## 0.6.8 - 2023-04-19 +* fix #892 `zeroYieldDay` loop was not applied to all channels + +## 0.6.7 - 2023-04-13 +* merge PR #883, improved store of settings and javascript, thx @tastendruecker123 +* support `.` and `,` as floating point separator in setup #881 + +## 0.6.6 - 2023-04-12 +* increased distance for `import` button in mobile view #879 +* changed `led_high_active` to `bool` #879 + +## 0.6.5 - 2023-04-11 +* fix #845 MqTT subscription for `ctrl/power/[IV-ID]` was missing +* merge PR #876, check JSON settings during read for existence +* **NOTE:** incompatible change: renamed `led_high_active` to `act_high`, maybe setting must be changed after update +* merge PR #861 do not send channel metric if channel is disabled + +## 0.6.4 - 2023-04-06 +* merge PR #846, improved NRF24 communication and MI, thx @beegee3 & @rejoe2 +* merge PR #859, fix burger menu height, thx @ThomasPohl + +## 0.6.3 - 2023-04-04 +* fix login, password length was not checked #852 +* merge PR #854 optimize browser caching, thx @tastendruecker123 #828 +* fix WiFi reconnect not working #851 +* updated issue templates #822 + +## 0.6.2 - 2023-04-04 +* fix login from multiple clients #819 +* fix login screen on small displays + +## 0.6.1 - 2023-04-01 +* merge LED fix - LED1 shows MqTT state, LED configurable active high/low #839 +* only publish new inverter data #826 +* potential fix of WiFi hostname during boot up #752 + +# RELEASE 0.6.0 - 2023-03-27 + +## 0.5.110 +* MQTT fix reconnection by new lib version #780 +* add `about` page +* improved documentation regarding SPI pins #814 +* improved documentation (getting started) #815 #816 +* improved MI 4-ch inverter #820 + +## 0.5.109 +* reduced heap fragmentation by optimizing MqTT #768 +* ePaper: centered text thx @knickohr + +## 0.5.108 +* merge: PR SPI pins configurable (ESP32) #807, #806 (requires manual set of MISO=19, MOSI=23, SCLK=18 in GUI for existing installs) +* merge: PR MI serial outputs #809 +* fix: no MQTT `total` sensor for autodiscover if only one inverter was found #805 +* fix: MQTT `total` renamed to `device_name` + `_TOTOL` for better visibility #805 + +## 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 +* fixed MQTT autodiscover #794, #632 + +## 0.5.105 +* merged MI, thx @rejoe2 #788 +* fixed reboot message #793 + +## 0.5.104 +* further improved save settings +* 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 +* changed display inverter online message +* merged heap improvements #772 + +## 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 +* 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 +* 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` +* 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 +* repaired inverter wise limit control +* fix upload settings #686 + +## 0.5.97 +* Attention: re-ordered display types, check your settings! #746 +* improved saving settings of display #747, #746 +* disabled contrast for Nokia display #746 +* added Prometheus as compile option #719, #615 +* update MQTT lib to v1.4.1 +* limit decimal places to 2 in `live` +* added `-DPIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48` to esp8266 debug build #657 +* a `max-module-power` of `0` disables channel in live view `setup` +* merge MI improvements, get firmware information #753 + +## 0.5.96 +* added Nokia display again for ESP8266 #764 +* changed `var` / `VAr` to SI unit `var` #732 +* fix MQTT retained flags for totals (P_AC, P_DC) #726, #721 + +## 0.5.95 +* merged #742 MI Improvements +* merged #736 remove obsolete JSON Endpoint + +## 0.5.94 +* added ePaper (for ESP32 only!), thx @dAjaY85 #735 +* improved `/live` margins #732 +* renamed `var` to `VAr` #732 + +## 0.5.93 +* improved web API for `live` +* added dark mode option +* converted all forms to reponsive design +* repaired menu with password protection #720, #716, #709 +* merged MI series fixes #729 + +## 0.5.92 +* fix mobile menu +* fix inverters in select `serial.html` #709 + +## 0.5.91 +* improved html and navi, navi is visible even when API dies #660 +* reduced maximum allowed JSON size for API to 6000Bytes #660 +* small fix: output command at `prepareDevInformCmd` #692 +* improved inverter handling #671 + +## 0.5.90 +* merged PR #684, #698, #705 +* webserial minor overflow fix #660 +* web `index.html` improve version information #701 +* fix MQTT sets power limit to zero (0) #692 +* changed `reset at midnight` with timezone #697 + +## 0.5.89 +* reduced heap fragmentation (removed `strtok` completely) #644, #645, #682 +* added part of mac address to MQTT client ID to separate multiple ESPs in same network +* added dictionary for MQTT to reduce heap-fragmentation +* removed `last Alarm` from Live view, because it showed always the same alarm - will change in future + +## 0.5.88 +* MQTT Yield Day zero, next try to fix #671, thx @beegee3 +* added Solenso inverter to supported devices +* improved reconnection of MQTT #650 + +## 0.5.87 +* fix yield total correction as module (inverter input) value #570 +* reneabled instant start communication (once NTP is synced) #674 + +## 0.5.86 +* prevent send devcontrol request during disabled night communication +* changed yield total correction as module (inverter input) value #570 +* MQTT Yield Day zero, next try to fix #671 + +## 0.5.85 +* fix power-limit was not checked for max retransmits #667 +* fix blue LED lights up all the time #672 +* fix installing schedulers if NTP server isn't available +* improved zero values on triggers #671 +* hardcoded MQTT subtopics, because wildcard `#` leads to errors +* rephrased some messages on webif, thx to @Argafal #638 +* fixed 'polling stop message' on `index.html` #639 + +## 0.5.84 +* fix blue LED lights up all the time #672 +* added an instant start communication (once NTP is synced) +* add MI 3rd generation inverters (10x2 serial numbers) +* first decodings of messages from MI 2nd generation inverters + +## 0.5.83 +* fix MQTT publishing, `callback` was set but reset by following `setup()` + +## 0.5.82 +* fixed communication error #652 +* reset values is no bound to MQTT any more, setting moved to `inverter` #649 +* fixed wording on `index.hmtl` #661 + +## 0.5.81 +* started implementation of MI inverters (setup.html, own processing `MiPayload.h`) + +## 0.5.80 +* fixed communication #656 + +## 0.5.79 +* fixed mixed reset flags #648 +* fixed `mCbAlarm` if MQTT is not used #653 +* fixed MQTT `autodiscover` #630 thanks to @antibill51 +* next changes from @beegee many thanks for your contribution! +* replaced `CircularBuffer` by `std::queue` +* reworked `hmRadio.h` completely (interrupts, packaging) +* fix exception while `reboot` +* cleanup MQTT coding + +## 0.5.78 +* further improvements regarding wifi #611, fix connection if only one AP with same SSID is there +* fix endless loop in `zerovalues` #564 +* fix auto discover again #565 +* added total values to autodiscover #630 +* improved zero at midnight #625 + +## 0.5.77 +* fix wrong filename for automatically created manifest (online installer) #620 +* added rotate display feature #619 +* improved Prometheus endpoint #615, thx to @fsck-block +* improved wifi to connect always to strongest RSSI, thx to @beegee3 #611 + +## 0.5.76 +* reduce MQTT retry interval from maximum speed to one second +* fixed homeassistant autodiscovery #565 +* implemented `getNTPTime` improvements #609 partially #611 +* added alarm messages to MQTT #177, #600, #608 + +## 0.5.75 +* fix wakeup issue, once wifi was lost during night the communication didn't start in the morning +* re-enabled FlashStringHelper because of lacking RAM +* complete rewrite of monochrome display class, thx to @dAjaY85 -> displays are now configurable in setup +* fix power limit not possible #607 + +## 0.5.74 +* improved payload handling (retransmit all fragments on CRC error) +* improved `isAvailable`, checks all record structs, inverter becomes available more early because version is check first +* fix tickers were not set if NTP is not available +* disabled annoying `FlashStringHelper` it gives randomly Exceptions during development, feels more stable since then +* moved erase button to the bottom in settings, not nice but more functional +* split `tx_count` to `tx_cnt` and `retransmits` in `system.html` +* fix mqtt retransmit IP address #602 +* added debug infos for `scheduler` (web -> `/debug` as trigger prints list of tickers to serial console) + +## 0.5.73 +* improved payload handling (request / retransmit) #464 +* included alarm ID parse to serial console (in development) + +## 0.5.72 +* repaired system, scheduler was not called any more #596 + +## 0.5.71 +* improved wifi handling and tickers, many thanks to @beegee3 #571 +* fixed YieldTotal correction calculation #589 +* fixed serial output of power limit acknowledge #569 +* reviewed `sendDiscoveryConfig` #565 +* merged PR `Monodisplay`, many thanks to @dAjaY85 #566, Note: (settings are introduced but not able to be modified, will be included in next version) + +## 0.5.70 +* corrected MQTT `comm_disabled` #529 +* fix Prometheus and JSON endpoints (`config_override.h`) #561 +* publish MQTT with fixed interval even if inverter is not available #542 +* added JSON settings upload. NOTE: settings JSON download changed, so only settings should be uploaded starting from version `0.5.70` #551 +* MQTT topic and inverter name have more allowed characters: `[A-Za-z0-9./#$%&=+_-]+`, thx: @Mo Demman +* improved potential issue with `checkTicker`, thx @cbscpe +* MQTT option for reset values on midnight / not avail / communication stop #539 +* small fix in `tickIVCommunication` #534 +* add `YieldTotal` correction, eg. to have the option to zero at year start #512 + +## 0.5.69 +* merged SH1106 1.3" Display, thx @dAjaY85 +* added SH1106 to automatic build +* added IP address to MQTT (version, device and IP are retained and only transmitted once after boot) #556 +* added `set_power_limit` acknowledge MQTT publish #553 +* changed: version, device name are only published via MQTT once after boot +* added `Login` to menu if admin password is set #554 +* added `development` to second changelog link in `index.html` #543 +* added interval for MQTT (as option). With this settings MQTT live data is published in a fixed timing (only if inverter is available) #542, #523 +* added MQTT `comm_disabled` #529 +* changed name of binaries, moved GIT-Sha to the front #538 + +## 0.5.68 +* repaired receive payload +* Powerlimit is transferred immediately to inverter + +## 0.5.67 +* changed calculation of start / stop communication to 1 min after last comm. stop #515 +* moved payload send to `payload.h`, function `ivSend` #515 +* payload: if last frame is missing, request all frames again + +# RELEASE 0.5.66 - 2022-12-30 + +## 0.5.65 +* wifi, code optimization #509 + +## 0.5.64 +* channel name can use any character, not limited any more +* added `/` to MQTT topic and Inverter name +* trigger for `calcSunrise` is now using local time #515 +* fix reconnect timeout for WiFi #509 +* start AP only after boot, not on WiFi connection loss +* improved /system `free_heap` value (measured before JSON-tree is built) + +## 0.5.63 +* fix Update button protection (prevent double click #527) +* optimized scheduler #515 (thx @beegee3) +* potential fix of #526 duplicates in API `/api/record/live` +* added update information to `index.html` + +## 0.5.62 +* fix MQTT `status` update +* removed MQTT `available_text` (can be deducted from `available`) +* enhanced MQTT documentation in `User_Manual.md` +* removed `tickSunset` and `tickSunrise` from MQTT. It's not needed any more because of minute wise check of status (`processIvStatus`) +* changed MQTT topic `status` to nummeric value, check documentation in `User_Manual.md` +* fix regular expression of `setup.html` for inverter name and channel name + +## 0.5.61 +* fix #521 no reconnect at beginning of day +* added immediate (each minute) report of inverter status MQTT #522 +* added protection mask to select which pages should be protected +* update of monochrome display, show values also if nothing changed + +## 0.5.60 +* added regex to inverter name and MQTT topic (setup.html) +* beautified serial.html +* added ticker for wifi loop #515 + +## 0.5.59 +* fix night communication enable +* improved different WiFi connection scenarios (STA WiFi not found, reconnect #509, redirect for AP to configuration) +* increased MQTT user, pwd and topic length to 64 characters + `\0`. (The string end `\0` reduces the available size by one) #516 + +## 0.5.58 +* improved stability +* improved WiFi initial connection - especially if station WiFi is not available +* removed new operators from web.h (reduce dynamic allocation) +* improved sun calculation #515, #505 +* fixed WiFi auto reconnect #509 +* added disable night communication flag to MQTT #505 +* changed MQTT publish of `available` and `available_text` to sunset #468 + +## 0.5.57 +* improved stability +* added icons to index.html, added WiFi-strength symbol on each page +* moved packet stats and sun to system.html +* refactored communication offset (adjustable in minutes now) + +## 0.5.56 +* factory reset formats entire little fs +* renamed sunrise / sunset on index.html to start / stop communication +* show system information only if called directly from menu +* beautified system.html + +## 0.5.55 +* fixed static IP save + +## 0.5.54 +* changed sunrise / sunset calculation, angle is now `-3.5` instead of original `-0.83` +* improved scheduler (removed -1 from `reload`) #483 +* improved reboot flag in `app.h` +* fixed #493 no MQTT payload once display is defined + +## 0.5.53 +* Mono-Display: show values in offline mode #498 +* improved WiFi class #483 +* added communication enable / disable (to test multiple DTUs with the same inverter) +* fix factory reset #495 + +## 0.5.52 +* improved ahoyWifi class +* added interface class for app +* refactored web and webApi -> RestApi +* fix calcSunrise was not called every day +* added MQTT RX counter to index.html +* all values are displayed on /live even if they are 0 +* added MQTT /status to show status over all inverters + +## 0.5.51 +* improved scheduler, @beegee3 #483 +* refactored get NTP time, @beegee3 #483 +* generate `bin.gz` only for 1M device ESP8285 +* fix calcSunrise was not called every day +* increased number of allowed characters for MQTT user, broker and password, @DanielR92 +* added NRF24 info to Systeminfo, @DanielR92 +* added timezone for monochrome displays, @gh-fx2 +* added support for second inverter for monochrome displays, @gh-fx2 + +## 0.5.50 +* fixed scheduler, uptime and timestamp counted too fast +* added / renamed automatically build outputs +* fixed MQTT ESP uptime on reconnect (not zero any more) +* changed uptime on index.html to count each second, synced with ESP each 10 seconds + +## 0.5.49 +* fixed AP mode on brand new ESP modules +* fixed `last_success` MQTT message +* fixed MQTT inverter available status at sunset +* reordered enqueue commands after boot up to prevent same payload length for successive commands +* added automatic build for Nokia5110 and SSD1306 displays (ESP8266) + +## 0.5.48 +* added MQTT message send at sunset +* added monochrome display support +* added `once` and `onceAt` to scheduler to make code cleaner +* improved sunrise / sunset calculation + +## 0.5.47 +* refactored ahoyWifi class: AP is opened on every boot, once station connection is successful the AP will be closed +* improved NTP sync after boot, faster sync +* fix NRF24 details only on valid SPI connection + +## 0.5.46 +* fix sunrise / sunset calculation +* improved setup.html: `reboot on save` is checked as default + +## 0.5.45 +* changed MQTT last will topic from `status` to `mqtt` +* fix sunrise / sunset calculation +* fix time of serial web console + +## 0.5.44 +* marked some MQTT messages as retained +* moved global functions to global location (no duplicates) +* changed index.html interval to static 10 seconds +* fix static IP +* fix NTP with static IP +* print MQTT info only if MQTT was configured + +## 0.5.43 +* updated REST API and MQTT (both of them use the same functionality) +* added ESP-heap information as MQTT message +* changed output name of automatic development build to fixed name (to have a static link from https://ahoydtu.de) +* updated user manual to latest MQTT and API changes + +## 0.5.42 +* fix web logout (auto logout) +* switched MQTT library + +# RELEASE 0.5.41 - 2022-11-22 + +# RELEASE 0.5.28 - 2022-10-30 + +# RELEASE 0.5.17 - 2022-09-06 + +# RELEASE 0.5.16 - 2022-09-04 -full version log: [Development Log](https://github.com/lumapu/ahoy/blob/development03/src/CHANGES.md) \ No newline at end of file diff --git a/src/app.cpp b/src/app.cpp index 22e2f045..5a5a54a0 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -102,14 +102,14 @@ void app::setup() { //----------------------------------------------------------------------------- void app::loop(void) { - ah::Scheduler::loop(); - if(mConfig->nrf.enabled) mNrfRadio.loop(); #if defined(ESP32) if(mConfig->cmt.enabled) mCmtRadio.loop(); #endif + + ah::Scheduler::loop(); mCommunication.loop(); if (mMqttEnabled && mNetworkConnected) @@ -449,22 +449,22 @@ void app::mqttSubRxCb(JsonObject obj) { //----------------------------------------------------------------------------- void app::setupLed(void) { - uint8_t led_off = (mConfig->led.led_high_active) ? LOW : HIGH; + uint8_t led_off = (mConfig->led.high_active) ? 0 : 255; if (mConfig->led.led0 != DEF_PIN_OFF) { pinMode(mConfig->led.led0, OUTPUT); - digitalWrite(mConfig->led.led0, led_off); + analogWrite(mConfig->led.led0, led_off); } if (mConfig->led.led1 != DEF_PIN_OFF) { pinMode(mConfig->led.led1, OUTPUT); - digitalWrite(mConfig->led.led1, led_off); + analogWrite(mConfig->led.led1, led_off); } } //----------------------------------------------------------------------------- void app::updateLed(void) { - uint8_t led_off = (mConfig->led.led_high_active) ? LOW : HIGH; - uint8_t led_on = (mConfig->led.led_high_active) ? HIGH : LOW; + uint8_t led_off = (mConfig->led.high_active) ? 0 : 255; + uint8_t led_on = (mConfig->led.high_active) ? (mConfig->led.luminance) : (255-mConfig->led.luminance); if (mConfig->led.led0 != DEF_PIN_OFF) { Inverter<> *iv; @@ -473,20 +473,20 @@ void app::updateLed(void) { if (NULL != iv) { if (iv->isProducing()) { // turn on when at least one inverter is producing - digitalWrite(mConfig->led.led0, led_on); + analogWrite(mConfig->led.led0, led_on); break; } else if(iv->config->enabled) - digitalWrite(mConfig->led.led0, led_off); + analogWrite(mConfig->led.led0, led_off); } } } if (mConfig->led.led1 != DEF_PIN_OFF) { if (getMqttIsConnected()) { - digitalWrite(mConfig->led.led1, led_on); + analogWrite(mConfig->led.led1, led_on); } else { - digitalWrite(mConfig->led.led1, led_off); + analogWrite(mConfig->led.led1, led_off); } } } diff --git a/src/config/settings.h b/src/config/settings.h index 8acb0942..c797cad8 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -30,7 +30,7 @@ * https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html#flash-layout * */ -#define CONFIG_VERSION 6 +#define CONFIG_VERSION 7 #define PROT_MASK_INDEX 0x0001 @@ -117,9 +117,10 @@ typedef struct { } cfgSerial_t; typedef struct { - uint8_t led0; // first LED pin - uint8_t led1; // second LED pin - bool led_high_active; // determines if LEDs are high or low active + uint8_t led0; // first LED pin + uint8_t led1; // second LED pin + bool high_active; // determines if LEDs are high or low active + uint8_t luminance; // luminance of LED } cfgLed_t; typedef struct { @@ -450,9 +451,10 @@ class settings { mCfg.inst.iv[i].add2Total = true; } - mCfg.led.led0 = DEF_LED0; - mCfg.led.led1 = DEF_LED1; - mCfg.led.led_high_active = LED_HIGH_ACTIVE; + mCfg.led.led0 = DEF_LED0; + mCfg.led.led1 = DEF_LED1; + mCfg.led.high_active = LED_HIGH_ACTIVE; + mCfg.led.luminance = 255; memset(&mCfg.inst, 0, sizeof(cfgInst_t)); @@ -493,6 +495,9 @@ class settings { mCfg.inst.gapMs = 500; mCfg.inst.readGrid = true; } + if(mCfg.configVersion < 7) { + mCfg.led.luminance = 255; + } } } @@ -667,13 +672,15 @@ class settings { void jsonLed(JsonObject obj, bool set = false) { if(set) { - obj[F("0")] = mCfg.led.led0; - obj[F("1")] = mCfg.led.led1; - obj[F("act_high")] = mCfg.led.led_high_active; + obj[F("0")] = mCfg.led.led0; + obj[F("1")] = mCfg.led.led1; + obj[F("act_high")] = mCfg.led.high_active; + obj[F("lum")] = mCfg.led.luminance; } else { getVal(obj, F("0"), &mCfg.led.led0); getVal(obj, F("1"), &mCfg.led.led1); - getVal(obj, F("act_high"), &mCfg.led.led_high_active); + getVal(obj, F("act_high"), &mCfg.led.high_active); + getVal(obj, F("lum"), &mCfg.led.luminance); } } diff --git a/src/defines.h b/src/defines.h index ff7e9772..2b0909cd 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 34 +#define VERSION_PATCH 35 //------------------------------------- typedef struct { diff --git a/src/web/RestApi.h b/src/web/RestApi.h index f3d70d26..169e1d2d 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -564,7 +564,8 @@ class RestApi { obj[F("miso")] = mConfig->nrf.pinMiso; obj[F("led0")] = mConfig->led.led0; obj[F("led1")] = mConfig->led.led1; - obj[F("led_high_active")] = mConfig->led.led_high_active; + obj[F("led_high_active")] = mConfig->led.high_active; + obj[F("led_lum")] = mConfig->led.luminance; } #if defined(ESP32) diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 8e415c2c..f172f925 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -918,8 +918,12 @@ ml("div", { class: "row mb-3" }, [ ml("div", { class: "col-12 col-sm-3 my-2" }, "LED polarity"), ml("div", { class: "col-12 col-sm-9" }, - sel('pinLedHighActive', led_high_active, obj['led_high_active']) + sel('pinLedHighActive', led_high_active, obj.led_high_active) ) + ]), + ml("div", { class: "row mb-3" }, [ + ml("div", { class: "col-12 col-sm-3 my-2" }, "LED luminance (0-255)"), + ml("div", { class: "col-12 col-sm-9" }, ml("input", {class: "text", type: "number", name: "pinLedLum", value: obj.led_lum, min: 0, max: 255}, null)) ]) ) } diff --git a/src/web/web.h b/src/web/web.h index 451dc656..b60e6791 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -39,7 +39,7 @@ #define WEB_SERIAL_BUF_SIZE 2048 -const char* const pinArgNames[] = {"pinCs", "pinCe", "pinIrq", "pinSclk", "pinMosi", "pinMiso", "pinLed0", "pinLed1", "pinLedHighActive", "pinCmtSclk", "pinSdio", "pinCsb", "pinFcsb", "pinGpio3"}; +const char* const pinArgNames[] = {"pinCs", "pinCe", "pinIrq", "pinSclk", "pinMosi", "pinMiso", "pinLed0", "pinLed1", "pinLedHighActive", "pinLedLum", "pinCmtSclk", "pinSdio", "pinCsb", "pinFcsb", "pinGpio3"}; template class Web { @@ -284,12 +284,18 @@ class Web { bool reboot = (!Update.hasError()); - String html = F("UpdateUpdate: "); + String html = F("UpdateUpdate: "); if (reboot) html += "success"; else html += "failed"; - html += F("

rebooting ... auto reload after 20s"); + html += F("

rebooting ..."); AsyncWebServerResponse *response = request->beginResponse(200, F("text/html; charset=UTF-8"), html); response->addHeader("Connection", "close"); @@ -521,7 +527,7 @@ class Web { // pinout uint8_t pin; - for (uint8_t i = 0; i < 14; i++) { + for (uint8_t i = 0; i < 15; i++) { pin = request->arg(String(pinArgNames[i])).toInt(); switch(i) { case 0: mConfig->nrf.pinCs = ((pin != 0xff) ? pin : DEF_NRF_CS_PIN); break; @@ -530,14 +536,15 @@ class Web { case 3: mConfig->nrf.pinSclk = ((pin != 0xff) ? pin : DEF_NRF_SCLK_PIN); break; case 4: mConfig->nrf.pinMosi = ((pin != 0xff) ? pin : DEF_NRF_MOSI_PIN); break; case 5: mConfig->nrf.pinMiso = ((pin != 0xff) ? pin : DEF_NRF_MISO_PIN); break; - case 6: mConfig->led.led0 = pin; break; - case 7: mConfig->led.led1 = pin; break; - case 8: mConfig->led.led_high_active = pin; break; // this is not really a pin but a polarity, but handling it close to here makes sense - case 9: mConfig->cmt.pinSclk = pin; break; - case 10: mConfig->cmt.pinSdio = pin; break; - case 11: mConfig->cmt.pinCsb = pin; break; - case 12: mConfig->cmt.pinFcsb = pin; break; - case 13: mConfig->cmt.pinIrq = pin; break; + case 6: mConfig->led.led0 = pin; break; + case 7: mConfig->led.led1 = pin; break; + case 8: mConfig->led.high_active = pin; break; // this is not really a pin but a polarity, but handling it close to here makes sense + case 9: mConfig->led.luminance = pin; break; // this is not really a pin but a polarity, but handling it close to here makes sense + case 10: mConfig->cmt.pinSclk = pin; break; + case 11: mConfig->cmt.pinSdio = pin; break; + case 12: mConfig->cmt.pinCsb = pin; break; + case 13: mConfig->cmt.pinFcsb = pin; break; + case 14: mConfig->cmt.pinIrq = pin; break; } } From 86ff9f054a166a19f2558f9760019ec97de88dee Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 30 Dec 2023 02:33:57 +0100 Subject: [PATCH 266/267] 0.8.35 * changed reload time for opendtufusion after update to 5s * fix default interval and gap for communication * fix serial number in exported json (was decimal, now correct as hexdecimal number) * beautified factory reset * added second stage for erase settings * increased maximal number of inverters to 32 for opendtufusion board (ESP32-S3) * fixed crash if CMT inverter is enabled, but CMT isn't configured --- .github/workflows/compile_release.yml | 2 +- src/CHANGES.md | 6 ++++ src/app.cpp | 3 ++ src/config/config.h | 6 +++- src/config/settings.h | 6 ++-- src/web/RestApi.h | 48 +++++++++++++++++++++++++++ src/web/html/system.html | 3 +- src/web/web.h | 47 ++++++++------------------ 8 files changed, 79 insertions(+), 42 deletions(-) diff --git a/.github/workflows/compile_release.yml b/.github/workflows/compile_release.yml index e65494ab..a7e3511d 100644 --- a/.github/workflows/compile_release.yml +++ b/.github/workflows/compile_release.yml @@ -77,7 +77,7 @@ jobs: VERSION: ${{ steps.rename-binary-files.outputs.name }} - name: Create Artifact - run: zip --junk-paths ${{ steps.rename-binary-files.outputs.name }}.zip src/firmware/* User_Manual.md + run: zip --junk-paths ${{ steps.rename-binary-files.outputs.name }}.zip src/firmware/* User_Manual.md - name: Upload Release id: upload-release diff --git a/src/CHANGES.md b/src/CHANGES.md index 52f185f3..7c243356 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -3,6 +3,12 @@ ## 0.8.35 - 2023-12-30 * added dim option for LEDS * changed reload time for opendtufusion after update to 5s +* fix default interval and gap for communication +* fix serial number in exported json (was decimal, now correct as hexdecimal number) +* beautified factory reset +* added second stage for erase settings +* increased maximal number of inverters to 32 for opendtufusion board (ESP32-S3) +* fixed crash if CMT inverter is enabled, but CMT isn't configured # RELEASE 0.8.34 - 2023-12-29 diff --git a/src/app.cpp b/src/app.cpp index 5a5a54a0..0bba14da 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -354,6 +354,9 @@ void app::tickSend(void) { continue; } + if(!iv->radio->isChipConnected()) + continue; + iv->tickSend([this, iv](uint8_t cmd, bool isDevControl) { if(isDevControl) mCommunication.addImportant(iv, cmd); diff --git a/src/config/config.h b/src/config/config.h index c8fd86dc..2cb9bcd3 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -153,7 +153,11 @@ // number of configurable inverters #if defined(ESP32) - #define MAX_NUM_INVERTERS 16 + #if defined(CONFIG_IDF_TARGET_ESP32S3) + #define MAX_NUM_INVERTERS 32 + #else + #define MAX_NUM_INVERTERS 16 + #endif #else #define MAX_NUM_INVERTERS 4 #endif diff --git a/src/config/settings.h b/src/config/settings.h index c797cad8..fe2ad1b0 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -425,7 +425,7 @@ class settings { mCfg.serial.showIv = false; mCfg.serial.debug = false; mCfg.serial.privacyLog = true; - mCfg.serial.printWholeTrace = true; + mCfg.serial.printWholeTrace = false; mCfg.mqtt.port = DEF_MQTT_PORT; snprintf(mCfg.mqtt.broker, MQTT_ADDR_LEN, "%s", DEF_MQTT_BROKER); @@ -441,7 +441,7 @@ class settings { mCfg.inst.startWithoutTime = false; mCfg.inst.rstMaxValsMidNight = false; mCfg.inst.yieldEffiency = 1.0f; - mCfg.inst.gapMs = 2000; + mCfg.inst.gapMs = 500; mCfg.inst.readGrid = true; for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { @@ -456,8 +456,6 @@ class settings { mCfg.led.high_active = LED_HIGH_ACTIVE; mCfg.led.luminance = 255; - memset(&mCfg.inst, 0, sizeof(cfgInst_t)); - mCfg.plugin.display.pwrSaveAtIvOffline = false; mCfg.plugin.display.contrast = 60; mCfg.plugin.display.screenSaver = 1; // default: 1 .. pixelshift for OLED for downward compatibility diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 169e1d2d..a74f4f14 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -88,6 +88,10 @@ class RestApi { else if(path == "html/logout") getHtmlLogout(request, root); else if(path == "html/reboot") getHtmlReboot(request, root); else if(path == "html/save") getHtmlSave(request, root); + else if(path == "html/erase") getHtmlErase(request, root); + else if(path == "html/erasetrue") getHtmlEraseTrue(request, root); + else if(path == "html/factory") getHtmlFactory(request, root); + else if(path == "html/factorytrue") getHtmlFactoryTrue(request, root); else if(path == "system") getSysInfo(request, root); else if(path == "generic") getGeneric(request, root); else if(path == "reboot") getReboot(request, root); @@ -214,6 +218,16 @@ class RestApi { tmp.remove(i, tmp.indexOf("\"", i)-i); } } + i = 0; + // convert all serial numbers to hexadecimal + while (i != -1) { + i = tmp.indexOf("\"sn\":", i); + if(-1 != i) { + i+=5; + String sn = tmp.substring(i, tmp.indexOf("\"", i)-1); + tmp.replace(sn, String(atoll(sn.c_str()), HEX)); + } + } response = request->beginResponse(200, F("application/json; charset=utf-8"), tmp); } @@ -337,6 +351,40 @@ class RestApi { #endif } + void getHtmlErase(AsyncWebServerRequest *request, JsonObject obj) { + getGeneric(request, obj.createNestedObject(F("generic"))); + obj[F("html")] = F("Erase settings (not WiFi)?
yes no"); + } + + void getHtmlEraseTrue(AsyncWebServerRequest *request, JsonObject obj) { + getGeneric(request, obj.createNestedObject(F("generic"))); + mApp->eraseSettings(false); + mApp->setRebootFlag(); + obj[F("html")] = F("Erase settings: success"); + #if defined(ETHERNET) && defined(CONFIG_IDF_TARGET_ESP32S3) + obj[F("reload")] = 5; + #else + obj[F("reload")] = 20; + #endif + } + + void getHtmlFactory(AsyncWebServerRequest *request, JsonObject obj) { + getGeneric(request, obj.createNestedObject(F("generic"))); + obj[F("html")] = F("Factory reset? yes no"); + } + + void getHtmlFactoryTrue(AsyncWebServerRequest *request, JsonObject obj) { + getGeneric(request, obj.createNestedObject(F("generic"))); + mApp->eraseSettings(true); + mApp->setRebootFlag(); + obj[F("html")] = F("Factory reset: success"); + #if defined(ETHERNET) && defined(CONFIG_IDF_TARGET_ESP32S3) + obj[F("reload")] = 5; + #else + obj[F("reload")] = 20; + #endif + } + void getReboot(AsyncWebServerRequest *request, JsonObject obj) { getGeneric(request, obj.createNestedObject(F("generic"))); obj[F("refresh")] = 10; diff --git a/src/web/html/system.html b/src/web/html/system.html index ef487ad5..eb25d5fa 100644 --- a/src/web/html/system.html +++ b/src/web/html/system.html @@ -126,8 +126,7 @@ meta.httpEquiv = "refresh" meta.content = obj.refresh + "; URL=" + obj.refresh_url; document.getElementsByTagName('head')[0].appendChild(meta); - } - else { + } else if(null != obj.system) { parseRadio(obj.system); parseMqtt(obj.system.mqtt); parseSysInfo(obj.system); diff --git a/src/web/web.h b/src/web/web.h index b60e6791..1e87547b 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -71,14 +71,15 @@ class Web { mWeb.onNotFound ( std::bind(&Web::showNotFound, this, std::placeholders::_1)); mWeb.on("/reboot", HTTP_ANY, std::bind(&Web::onReboot, this, std::placeholders::_1)); mWeb.on("/system", HTTP_ANY, std::bind(&Web::onSystem, this, std::placeholders::_1)); - mWeb.on("/erase", HTTP_ANY, std::bind(&Web::showErase, this, std::placeholders::_1)); - mWeb.on("/factory", HTTP_ANY, std::bind(&Web::showFactoryRst, this, std::placeholders::_1)); + mWeb.on("/erase", HTTP_ANY, std::bind(&Web::showHtml, this, std::placeholders::_1)); + mWeb.on("/erasetrue", HTTP_ANY, std::bind(&Web::showHtml, this, std::placeholders::_1)); + mWeb.on("/factory", HTTP_ANY, std::bind(&Web::showHtml, this, std::placeholders::_1)); + mWeb.on("/factorytrue", HTTP_ANY, std::bind(&Web::showHtml, this, std::placeholders::_1)); 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("/live", HTTP_ANY, std::bind(&Web::onLive, this, std::placeholders::_1)); - //mWeb.on("/api1", HTTP_POST, std::bind(&Web::showWebApi, this, std::placeholders::_1)); #ifdef ENABLE_PROMETHEUS_EP mWeb.on("/metrics", HTTP_ANY, std::bind(&Web::showMetrics, this, std::placeholders::_1)); @@ -197,6 +198,11 @@ class Web { #if !defined(ETHERNET) strncpy(mConfig->sys.stationPwd, pwd, PWD_LEN); // restore WiFi PWD #endif + for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { + if((mConfig->inst.iv[i].serial.u64 != 0) && (mConfig->inst.iv[i].serial.u64 < 138999999999)) { // hexadecimal + mConfig->inst.iv[i].serial.u64 = ah::Serial2u64(String(mConfig->inst.iv[i].serial.u64).c_str()); + } + } mApp->saveSettings(true); } if (!mUploadFail) @@ -426,39 +432,12 @@ class Web { request->send(response); } - void showErase(AsyncWebServerRequest *request) { + void showHtml(AsyncWebServerRequest *request) { checkProtection(request); - DPRINTLN(DBG_VERBOSE, F("showErase")); - mApp->eraseSettings(false); - onReboot(request); - } - - void showFactoryRst(AsyncWebServerRequest *request) { - checkProtection(request); - - DPRINTLN(DBG_VERBOSE, F("showFactoryRst")); - String content = ""; - int refresh = 3; - if (request->args() > 0) { - if (request->arg("reset").toInt() == 1) { - refresh = 10; - if (mApp->eraseSettings(true)) - content = F("factory reset: success\n\nrebooting ... "); - else - content = F("factory reset: failed\n\nrebooting ... "); - } else { - content = F("factory reset: aborted"); - refresh = 3; - } - } else { - content = F("

Factory Reset

" - "

RESET

CANCEL

"); - refresh = 120; - } - request->send(200, F("text/html; charset=UTF-8"), F("Factory Reset") + content + F("")); - if (refresh == 10) - onReboot(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 onSetup(AsyncWebServerRequest *request) { From 6fb05359398f24e14f4ddc3e7304b55b24fdd53c Mon Sep 17 00:00:00 2001 From: lumapu Date: Sat, 30 Dec 2023 02:49:21 +0100 Subject: [PATCH 267/267] 0.8.36 release --- README.md | 13 +- src/CHANGES.md | 996 +------------------------------------------------ src/defines.h | 2 +- 3 files changed, 14 insertions(+), 997 deletions(-) diff --git a/README.md b/README.md index f774b568..e352e414 100644 --- a/README.md +++ b/README.md @@ -18,19 +18,26 @@ This work is licensed under a # 🖐 Ahoy! -![Logo](https://github.com/grindylow/ahoy/blob/main/doc/logo1_small.png?raw=true) +![Logo](https://github.com/lumapu/ahoy/blob/main/doc/logo1_small.png?raw=true) This repository offers hardware and software solutions for communicating with Hoymiles inverters via radio. With our system, you can easily obtain real-time values such as power, current, and daily energy. Additionally, you can set parameters like the power limit of your inverter to achieve zero export. You can access these functionalities through our user-friendly web interface, MQTT, or JSON. Whether you're monitoring your solar panel system's performance or fine-tuning its settings, our solutions make it easy to achieve your goals. +## Changelog +[latest Release](https://github.com/lumapu/ahoy/blob/main/src/CHANGES.md) +[Development Version](https://github.com/lumapu/ahoy/blob/development03/src/CHANGES.md) + + Table of approaches: | Board | MI | HM | HMS/HMT | comment | HowTo start | | ------ | -- | -- | ------- | ------- | ---------- | -| [ESP8266/ESP32, C++](Getting_Started.md) | ✔️ | ✔️ | ✔️ ✨ | 👈 the most effort is spent here | [create your own DTU](https://ahoydtu.de/getting_started/) | +| [ESP8266/ESP32, C++](Getting_Started.md) | ✔️ | ✔️ | ✔️ | 👈 the most effort is spent here | [create your own DTU](https://ahoydtu.de/getting_started/) | | [Arduino Nano, C++](tools/nano/NRF24_SendRcv/) | ❌ | ✔️ | ❌ | | | [Raspberry Pi, Python](tools/rpi/) | ❌ | ✔️ | ❌ | | | [Others, C/C++](tools/nano/NRF24_SendRcv/) | ❌ | ✔️ | ❌ | | +⚠️ **Warning: HMS-XXXXW-2T WiFi inverters are not supported. They have a 'W' in their name and a DTU serial number on its sticker** + ## Getting Started [Guide how to start with a ESP module](Getting_Started.md) @@ -54,3 +61,5 @@ If you run into any issues, please feel free to use the issue tracker here on Gi ### Related Projects - [OpenDTU](https://github.com/tbnobody/OpenDTU) <- Our sister project ✨ for Hoymiles HM- and HMS-/HMT-series (for ESP32 only!) +- [hms-mqtt-publisher](https://github.com/DennisOSRM/hms-mqtt-publisher) + <- a project which can handle WiFi inverters like HMS-XXXXW-2T \ No newline at end of file diff --git a/src/CHANGES.md b/src/CHANGES.md index 7c243356..e67748fd 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,6 +1,5 @@ -# Development Changes +Changelog v0.8.36 -## 0.8.35 - 2023-12-30 * added dim option for LEDS * changed reload time for opendtufusion after update to 5s * fix default interval and gap for communication @@ -10,995 +9,4 @@ * increased maximal number of inverters to 32 for opendtufusion board (ESP32-S3) * fixed crash if CMT inverter is enabled, but CMT isn't configured -# RELEASE 0.8.34 - 2023-12-29 - -## 0.8.33 - 2023-12-29 -* improved communication thx @rejoe2 - -## 0.8.32 - 2023-12-29 -* fix `start` / `stop` / `restart` commands #1287 -* added message, if profile was not read until now #1300 -* added developer option to use 'syslog-server' instead of 'web-serail' #1299 - -## 0.8.31 - 2023-12-29 -* added class to handle timeouts PR #1298 - -## 0.8.30 - 2023-12-28 -* added info if grid profile was not found -* merge PR #1293 -* merge PR #1295 fix ESP8266 pin settings -* merge PR #1297 fix layout for OLED displays - -## 0.8.29 - 2023-12-27 -* fix MqTT generic topic `comm_disabled` #1265 #1286 -* potential fix of #1285 (reset yield day) -* fix fraction of yield correction #1280 -* fix crash if `getLossRate` was read from inverter #1288 #1290 -* reduce reload time for opendtufusion ethernet variant to 5 seconds -* added basic grid parser -* added ESP32-C3 mini environment #1289 - -## 0.8.28 - 2023-12-23 -* fix bug heuristic -* add version information to clipboard once 'copy' was clicked -* add get loss rate @rejoe2 -* improve communication @rejoe2 - -## 0.8.27 - 2023-12-18 -* fix set power limit #1276 - -## 0.8.26 - 2023-12-17 -* read grid profile as HEX (`live` -> click inverter name -> `show grid profile`) - -## 0.8.25 - 2023-12-17 -* RX channel ID starts with fixed value #1277 -* fix static IP for Ethernet - -## 0.8.24 - 2023-12-16 -* fix NRF communication for opendtufusion ethernet variant - -## 0.8.23 - 2023-12-14 -* heuristics fix #1269 #1270 -* moved `sendInterval` in settings, **important:** *will be reseted to 15s after update to this version* -* try to prevent access to radio classes if they are not activated -* fixed millis in serial log -* changed 'print whole trace' = `false` as default -* added communication loop duration in [ms] to serial console -* don't print Hex-Payload if 'print whole trace' == `false` - -## 0.8.22 - 2023-12-13 -* fix communication state-machine regarding zero export #1267 - -## 0.8.21 - 2023-12-12 -* fix ethernet save inverter parameters #886 -* fix ethernet OTA update #886 -* improved radio statistics, fixed heuristic output for HMS and HMT inverters - -## 0.8.20 - 2023-12-12 -* improved HM communication #1259 #1249 -* fix `loadDefaults` for ethernet builds #1263 -* don't loop through radios which aren't in use #1264 - -## 0.8.19 - 2023-12-11 -* added ms to serial log -* added (debug) option to configure gap between inverter requests - -## 0.8.18 - 2023-12-10 -* copied even more from the original heuristic code #1259 -* added mDNS support #1262 - -## 0.8.17 - 2023-12-10 -* possible fix of NRF with opendtufusion (without ETH) -* small fix in heuristics (if conditions made assignment not comparisson) - -## 0.8.16 - 2023-12-09 -* fix crash if NRF is not enabled -* updated heuristic #1080 #1259 -* fix compile opendtufusion fusion ethernet - -## 0.8.15 - 2023-12-09 -* added support for opendtufusion fusion ethernet shield #886 -* fixed range of HMS / HMT frequencies to 863 to 870 MHz #1238 -* changed `yield effiency` per default to `1.0` #1243 -* small heuristics improvements #1258 -* added class to combine inverter heuristics fields #1258 - -## 0.8.14 - 2023-12-07 -* fixed decimal points for temperature (WebUI) PR #1254 #1251 -* fixed inverter statemachine available state PR #1252 #1253 -* fixed NTP update and sunrise calculation #1240 #886 -* display improvments #1248 #1247 -* fixed overflow in `hmRadio.h` #1244 - -## 0.8.13 - 2023-11-28 -* merge PR #1239 symbolic layout for OLED 128x64 + motion senser functionality -* fix MqTT IP addr for ETH connections PR #1240 -* added ethernet build for fusion board, not tested so far - -## 0.8.12 - 2023-11-20 -* added button `copy to clipboard` to `/serial` - -## 0.8.11 - 2023-11-20 -* improved communication, thx @rejoe2 -* improved heuristics, thx @rejoe2, @Oberfritze -* added option to strip payload of frames to significant area - -## 0.8.10 - 2023-11-19 -* fix Mi and HM inverter communication #1235 -* added privacy mode option #1211 -* changed serial debug option to work without reboot - -## 0.8.9 - 2023-11-19 -* merged PR #1234 -* added new alarm codes -* removed serial interval, was not in use anymore - -## 0.8.8 - 2023-11-16 -* fix ESP8266 save inverter #1232 - -## 0.8.7 - 2023-11-13 -* fix ESP8266 inverter settings #1226 -* send radio statistics via MqTT #1227 -* made night communication inverter depended -* added option to prevent adding values of inverter to total values (MqTT only) #1199 - -## 0.8.6 - 2023-11-12 -* merged PR #1225 -* improved heuristics (prevent update of statitistic during testing) - -## 0.8.5 - 2023-11-12 -* fixed endless loop while switching CMT frequency -* removed obsolete "retries" field from settings #1224 -* fixed crash while defining new invertes #1224 -* fixed default frequency settings -* added default input power to `400` while adding new inverters -* fixed color of wifi RSSI icon #1224 - -## 0.8.4 - 2023-11-10 -* changed MqTT alarm topic, removed retained flag #1212 -* reduce last_success MQTT messages (#1124) -* introduced tabs in WebGUI (inverter settings) -* added inverter-wise power level and frequency - -## 0.8.3 - 2023-11-09 -* fix yield day reset during day #848 -* add total AC Max Power to WebUI -* fix opendtufusion build (GxEPD patch) -* fix null ptr PR #1222 - -## 0.8.2 - 2023-11-08 -* beautified inverter settings in `setup` (preperation for future, settings become more inverter dependent) - -## 0.8.1 - 2023-11-05 -* added tx channel heuristics (per inverter) -* fix statistics counter - -## 0.8.0 - 2023-10-?? -* switched to new communication scheme - -## 0.7.66 - 2023-10-04 -* prepared PA-Level for CMT -* removed settings for number of retransmits, its fixed to `5` now -* added parentheses to have a excactly defined behaviour - -## 0.7.65 - 2023-10-02 -* MI control command review #1197 - -## 0.7.64 - 2023-10-02 -* moved active power control to modal in `live` view (per inverter) by click on current APC state - -## 0.7.63 - 2023-10-01 -* fix NRF24 communication #1200 - -## 0.7.62 - 2023-10-01 -* fix communication to inverters #1198 -* add timeout before payload is tried to process (necessary for HMS/HMT) - -## 0.7.61 - 2023-10-01 -* merged `hmPayload` and `hmsPayload` into single class -* merged generic radio functions into new parent class `radio.h` -* moved radio statistics into the inverter - each inverter has now seperate statistics which can be accessed by click on the footer in `/live` -* fix compiler warnings #1191 -* fix ePaper logo during night time #1151 - -## 0.7.60 - 2023-09-27 -* fixed typos in changelog #1172 -* fixed MqTT manual clientId storage #1174 -* fixed inverter name length in setup #1181 -* added inverter name to the header of alarm list #1181 -* improved code to avoid warning during compilation #1182 -* fix scheduler #1188, #1179 - -## 0.7.59 - 2023-09-20 -* re-add another HM-400 hardware serial number accidentally removed with `0.7.45` (#1169) -* merge PR #1170 -* reduce last_success MQTT messages (#1124) -* add re-request if inverter is known to be online and first try fails -* add alarm reporting to MI (might need review!) -* rebuild MI limiting code closer to DTUSimMI example -* round APC in `W` to an integer #1171 - -## 0.7.58 -* fix ESP8266 save settings issue #1166 - -## 0.7.57 - 2023-09-18 -* fix Alarms are always in queue (since 0.7.56) -* fix display active power control to long for small devices #1165 - -## 0.7.56 - 2023-09-17 -* only request alarms which were not received before #1113 -* added flag if alarm was requested but not received and re-request it #1105 -* merge PR #1163 - -## 0.7.55 - 2023-09-17 -* fix prometheus builds -* fix ESP32 default pinout #1159 -* added `opendtufusion-dev` because of annoying `-DARDUINO_USB_CDC_ON_BOOT=1` flag -* fix display of current power on `index` -* fix OTA, was damaged by version `0.7.51`, need to use webinstaller (from `0.7.51` to `0.7.54`) - -## 0.7.54 - 2023-09-16 -* added active power control in `W` to live view #201, #673 -* updated docu, active power control related #706 -* added current AC-Power to `index` page and removed version #763 -* improved statistic data, moved to entire struct -* removed `/api/statistics` endpoint from REST-API - -## 0.7.53 - 2023-09-16 -* fix ePaper / display night behaviour #1151 -* fix ESP8266 compile error - -## 0.7.52 - 2023-09-16 -* fix CMT configurable pins #1150, #1159 -* update MqTT lib to version `1.4.5` - -## 0.7.51 - 2023-09-16 -* fix CMT configurable pins #1150 -* fix default CMT pins for opendtufusion -* beautified `system` -* changed main loops, fix resets #1125, #1135 - -## 0.7.50 - 2023-09-12 -* moved MqTT info to `system` -* added CMT info for ESP32 devices -* improved CMT settings, now `SCLK` and `SDIO` are configurable #1046, #1150 -* changed `Power-Limit` in live-view to `Active Power Control` -* increase length of update file selector #1132 - -## 0.7.49 - 2023-09-11 -* merge PR: symbolic icons for mono displays, PR #1136 -* merge MI code restructuring PR #1145 -* merge Prometheus PR #1148 -* add option to strip webUI for ESP8266 (reduce code size, add ESP32 special features; `IF_ESP32` directives) -* started to get CMT info into `system` - not finished - -## 0.7.48 - 2023-09-10 -* fix SSD1309 2.42" display pinout -* improved setup page: save and delete of inverters - -## 0.7.47 - 2023-09-07 -* fix boot loop #1140 -* fix regex in `setup` page -* fix MI serial number display `max-module-power` in `setup` #1142 -* renamed `opendtufusionv1` to `opendtufusion` - -## 0.7.46 - 2023-09-04 -* removed `delay` from ePaper -* started improvements of `/system` -* fix LEDs to check all configured inverters -* send loop skip disabled inverters fix -* print generated DTU SN to console -* HW Versions for MI series PR #1133 -* 2.42" display (SSD1309) integration PR #1139 -* update user manual PR #1121 -* add / rename alarm codes PR #1118 -* revert default pin ESP32 for NRF23-CE #1132 -* luminance of display can be changed during runtime #1106 - -## 0.7.45 - 2023-08-29 -* change ePaper text to symbols PR #1131 -* added some invertes to dev info list #1111 - -## 0.7.44 - 2023-08-28 -* fix `last_success` transmitted to often #1124 - -## 0.7.43 - 2023-08-28 -* improved RSSI for NRF24, now it's read per package (and inverter) #1129 -* arranged `heap` related info together in `/system` -* fix display navi during save -* clean up binary output, separated to folders - -## 0.7.42 - 2023-08-27 -* fix ePaper for opendtufusion_v2.x boards (Software SPI) -* add signal strength for NRF24 - PR #1119 -* refactor wifi class to support ESP32 S2 PR #1127 -* update platform for ESP32 to 6.3.2 -* fix opendtufusion LED (were mixed) -* fix `last_success` transmitted to often #1124 -* added ESP32-S3-mini to github actions -* added old Changelog Entries, to have full log of changes - -## 0.7.41 - 2023-08-26 -* merge PR #1117 code spelling fixes #1112 -* alarms were not read after the first day - -## 0.7.40 - 2023-08-21 -* added default pins for opendtu-fusion-v1 board -* fixed hw version display in `live` -* removed development builds, renamed environments in `platform.ini` - -## 0.7.39 - 2023-08-21 -* fix background color of invalid inputs -* add hardware info (click in `live` on inverter name) - -## 0.7.38 - 2023-08-21 -* reset alarms at midnight (if inverter is not available) #1105, #1096 -* add option to reset 'max' values on midnight #1102 -* added default pins for CMT2300A (matching OpenDTU) - -## 0.7.37 - 2023-08-18 -* fix alarm time on WebGui #1099 -* added RSSI info for HMS and HMT inverters (MqTT + REST API) - -# RELEASE 0.7.36 - 2023-08-18 - -## 0.7.35 - 2023-08-17 -* fixed timestamp for alarms send over MqTT -* auto-patch of `AsyncWebServer` #834, #1036 -* Update documentation in Git regarding `ESP8266` default NRF24 pin assignments - -## 0.7.34 - 2023-08-16 -* fixed timezone offset of alarms -* added `AC` and `DC` to `/live` #1098 -* changed `ESP8266` default NRF24 pin assignments (`D3` = `CE` and `D4` = `IRQ`) -* fixed background of modal window for bright color -* fix MI crashes -* fix some lost debug messages -* merged PR #1095, MI fixes for 0.7.x versions -* fix scheduled reboot #1097 -* added vector graphic logo `/doc/logo.svg` -* merge PR #1093, improved Nokia5110 display layout - -## 0.7.33 - 2023-08-15 -* add alarms overview to WebGui #608 -* fix webGui total values #1084 - -## 0.7.32 - 2023-08-14 -* fix colors of live view #1091 - -## 0.7.31 - 2023-08-13 -* fixed docu #1085 -* changed active power limit MqTT messages to QOS2 #1072 -* improved alarm messages, added alarm-id to log #1089 -* trigger power limit read on next day (if inverter was offline meanwhile) -* disabled improv implementation to check if it is related to 'Schwuppdizitaet' -* changed live view to gray once inverter isn't available -* added inverter status to API -* changed sum of totals on WebGui depending on inverter status #1084 -* merge maximum power (AC and DC) from PR #1080 - -## 0.7.30 - 2023-08-10 -* attempt to improve speed / response times (Schwuppdizitaet) #1075 - -## 0.7.29 - 2023-08-09 -* MqTT alarm data was never sent, fixed -* REST API: added alarm data -* REST API: made get record obsolete -* REST API: added power limit acknowledge `/api/inverter/id/[0-x]` #1072 - -## 0.7.28 - 2023-08-08 -* fix MI inverter support #1078 - -## 0.7.27 - 2023-08-08 -* added compile option for ethernet #886 -* fix ePaper configuration, missing `Busy`-Pin #1075 - -# RELEASE 0.7.26 - 2023-08-06 - -* fix MqTT `last_success` - -# RELEASE 0.7.25 - 2023-08-06 - -## 0.7.24 - 2023-08-05 -* merge PR #1069 make MqTT client ID configurable -* fix #1016, general MqTT status depending on inverter state machine -* changed icon for fully available inverter to a filled check mark #1070 -* fixed `last_success` update with MqTT #1068 -* removed `improv` esp-web-installer script, because it is not fully functional at this time - -## 0.7.23 - 2023-08-04 -* merge PR #1056, visualization html -* update MqTT library to 1.4.4 -* update RF24 library to 1.4.7 -* update ArduinoJson library to 6.21.3 -* set minimum invervall for `/live` to 5 seconds - -## 0.7.22 - 2023-08-04 -* attempt to fix homeassistant auto discovery #1066 - -## 0.7.21 - 2023-07-30 -* fix MqTT YieldDay Total goes to 0 several times #1016 - -## 0.7.20 - 2023-07-28 -* merge PR #1048 version and hash in API, fixes #1045 -* fix: no yield day update if yield day reads `0` after inverter reboot (mostly on evening) #848 -* try to fix Wifi override #1047 -* added information after NTP sync to WebUI #1040 - -## 0.7.19 - 2023-07-27 -* next attempt to fix yield day for multiple inverters #1016 -* reduced threshold for inverter state machine from 60min to 15min to go from state `WAS_ON` to `OFF` - -## 0.7.18 - 2023-07-26 -* next attempt to fix yield day for multiple inverters #1016 - -## 0.7.17 - 2023-07-25 -* next attempt to fix yield day for multiple inverters #1016 -* added two more states for the inverter status (also docu) - -## 0.7.16 - 2023-07-24 -* next attempt to fix yield day for multiple inverters #1016 -* fix export settings date #1040 -* fix time on WebUI (timezone was not observed) #913 #1016 - -## 0.7.15 - 2023-07-23 -* add NTP sync interval #1019 -* adjusted range of contrast / luminance setting #1041 -* use only ISO time format in Web-UI #913 - -## 0.7.14 - 2023-07-23 -* fix Contrast for Nokia Display #1041 -* attempt to fix #1016 by improving inverter status -* added option to adjust efficiency for yield (day/total) #1028 - -## 0.7.13 - 2023-07-19 -* merged display PR #1027 -* add date, time and version to export json #1024 - -## 0.7.12 - 2023-07-09 -* added inverter status - state-machine #1016 - -## 0.7.11 - 2023-07-09 -* fix MqTT endless loop #1013 - -## 0.7.10 - 2023-07-08 -* fix MqTT endless loop #1013 - -## 0.7.9 - 2023-07-08 -* added 'improve' functions to set wifi password directly with ESP web tools #1014 -* fixed MqTT publish while applying power limit #1013 -* slightly improved HMT live view (Voltage & Current) - -## 0.7.8 - 2023-07-05 -* fix `YieldDay`, `YieldTotal` and `P_AC` in `TotalValues` #929 -* fix some serial debug prints -* merge PR #1005 which fixes issue #889 -* merge homeassistant PR #963 -* merge PR #890 which gives option for scheduled reboot at midnight (default off) - -## 0.7.7 - 2023-07-03 -* attempt to fix MqTT `YieldDay` in `TotalValues` #927 -* attempt to fix MqTT `YieldDay` and `YieldTotal` even if inverters are not completely available #929 -* fix wrong message 'NRF not connected' if it is disabled #1007 - -## 0.7.6 - 2023-06-17 -* fix display of hidden SSID checkbox -* changed yield correction data type to `double`, now decimal places are supported -* corrected name of 0.91" display in settings -* attempt to fix MqTT zero values only if setting is there #980, #957 -* made AP password configurable #951 -* added option to start without time-sync, eg. for AP-only-mode #951 - -## 0.7.5 - 2023-06-16 -* fix yield day reset on midnight #957 -* improved tickers in `app.cpp` - -## 0.7.4 - 2023-06-15 -* fix MqTT `P_AC` send if inverters are available #987 -* fix assignments for HMS 1CH and 2CH devices -* fixed uptime overflow #990 - -## 0.7.3 - 2023-06-09 -* fix hidden SSID scan #983 -* improved NRF24 missing message on home screen #981 -* fix MqTT publishing only updated values #982 - -## 0.7.2 - 2023-06-08 -* fix HMS-800 and HMS-1000 assignments #981 -* make nrf enabled all the time for ESP8266 -* fix menu item `active` highlight for 'API' and 'Doku' -* fix MqTT totals issue #927, #980 -* reduce maximum number of inverters to 4 for ESP8266, increase to 16 for ESP32 - -## 0.7.1 - 2023-06-05 -* enabled power limit control for HMS / HMT devices -* changed NRF24 lib version back to 1.4.5 because of compile problems for EPS8266 - -## 0.7.0 - 2023-06-04 -* HMS / HMT support for ESP32 devices - -## 0.6.15 - 2023-05-25 -* improved Prometheus Endpoint PR #958 -* fix turn off ePaper only if setting was set #956 -* improved reset values and update MqTT #957 - -## 0.6.14 - 2023-05-21 -* merge PR #902 Mono-Display - -## 0.6.13 - 2023-05-16 -* merge PR #934 (fix JSON API) and #944 (update manual) - -## 0.6.12 - 2023-04-28 -* improved MqTT -* fix menu active item - -## 0.6.11 - 2023-04-27 -* added MqTT class for publishing all values in Arduino `loop` - -## 0.6.10 - HMS -* Version available in `HMS` branch - -# RELEASE 0.6.9 - 2023-04-19 - -## 0.6.8 - 2023-04-19 -* fix #892 `zeroYieldDay` loop was not applied to all channels - -## 0.6.7 - 2023-04-13 -* merge PR #883, improved store of settings and javascript, thx @tastendruecker123 -* support `.` and `,` as floating point separator in setup #881 - -## 0.6.6 - 2023-04-12 -* increased distance for `import` button in mobile view #879 -* changed `led_high_active` to `bool` #879 - -## 0.6.5 - 2023-04-11 -* fix #845 MqTT subscription for `ctrl/power/[IV-ID]` was missing -* merge PR #876, check JSON settings during read for existence -* **NOTE:** incompatible change: renamed `led_high_active` to `act_high`, maybe setting must be changed after update -* merge PR #861 do not send channel metric if channel is disabled - -## 0.6.4 - 2023-04-06 -* merge PR #846, improved NRF24 communication and MI, thx @beegee3 & @rejoe2 -* merge PR #859, fix burger menu height, thx @ThomasPohl - -## 0.6.3 - 2023-04-04 -* fix login, password length was not checked #852 -* merge PR #854 optimize browser caching, thx @tastendruecker123 #828 -* fix WiFi reconnect not working #851 -* updated issue templates #822 - -## 0.6.2 - 2023-04-04 -* fix login from multiple clients #819 -* fix login screen on small displays - -## 0.6.1 - 2023-04-01 -* merge LED fix - LED1 shows MqTT state, LED configurable active high/low #839 -* only publish new inverter data #826 -* potential fix of WiFi hostname during boot up #752 - -# RELEASE 0.6.0 - 2023-03-27 - -## 0.5.110 -* MQTT fix reconnection by new lib version #780 -* add `about` page -* improved documentation regarding SPI pins #814 -* improved documentation (getting started) #815 #816 -* improved MI 4-ch inverter #820 - -## 0.5.109 -* reduced heap fragmentation by optimizing MqTT #768 -* ePaper: centered text thx @knickohr - -## 0.5.108 -* merge: PR SPI pins configurable (ESP32) #807, #806 (requires manual set of MISO=19, MOSI=23, SCLK=18 in GUI for existing installs) -* merge: PR MI serial outputs #809 -* fix: no MQTT `total` sensor for autodiscover if only one inverter was found #805 -* fix: MQTT `total` renamed to `device_name` + `_TOTOL` for better visibility #805 - -## 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 -* fixed MQTT autodiscover #794, #632 - -## 0.5.105 -* merged MI, thx @rejoe2 #788 -* fixed reboot message #793 - -## 0.5.104 -* further improved save settings -* 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 -* changed display inverter online message -* merged heap improvements #772 - -## 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 -* 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 -* 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` -* 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 -* repaired inverter wise limit control -* fix upload settings #686 - -## 0.5.97 -* Attention: re-ordered display types, check your settings! #746 -* improved saving settings of display #747, #746 -* disabled contrast for Nokia display #746 -* added Prometheus as compile option #719, #615 -* update MQTT lib to v1.4.1 -* limit decimal places to 2 in `live` -* added `-DPIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48` to esp8266 debug build #657 -* a `max-module-power` of `0` disables channel in live view `setup` -* merge MI improvements, get firmware information #753 - -## 0.5.96 -* added Nokia display again for ESP8266 #764 -* changed `var` / `VAr` to SI unit `var` #732 -* fix MQTT retained flags for totals (P_AC, P_DC) #726, #721 - -## 0.5.95 -* merged #742 MI Improvements -* merged #736 remove obsolete JSON Endpoint - -## 0.5.94 -* added ePaper (for ESP32 only!), thx @dAjaY85 #735 -* improved `/live` margins #732 -* renamed `var` to `VAr` #732 - -## 0.5.93 -* improved web API for `live` -* added dark mode option -* converted all forms to reponsive design -* repaired menu with password protection #720, #716, #709 -* merged MI series fixes #729 - -## 0.5.92 -* fix mobile menu -* fix inverters in select `serial.html` #709 - -## 0.5.91 -* improved html and navi, navi is visible even when API dies #660 -* reduced maximum allowed JSON size for API to 6000Bytes #660 -* small fix: output command at `prepareDevInformCmd` #692 -* improved inverter handling #671 - -## 0.5.90 -* merged PR #684, #698, #705 -* webserial minor overflow fix #660 -* web `index.html` improve version information #701 -* fix MQTT sets power limit to zero (0) #692 -* changed `reset at midnight` with timezone #697 - -## 0.5.89 -* reduced heap fragmentation (removed `strtok` completely) #644, #645, #682 -* added part of mac address to MQTT client ID to separate multiple ESPs in same network -* added dictionary for MQTT to reduce heap-fragmentation -* removed `last Alarm` from Live view, because it showed always the same alarm - will change in future - -## 0.5.88 -* MQTT Yield Day zero, next try to fix #671, thx @beegee3 -* added Solenso inverter to supported devices -* improved reconnection of MQTT #650 - -## 0.5.87 -* fix yield total correction as module (inverter input) value #570 -* reneabled instant start communication (once NTP is synced) #674 - -## 0.5.86 -* prevent send devcontrol request during disabled night communication -* changed yield total correction as module (inverter input) value #570 -* MQTT Yield Day zero, next try to fix #671 - -## 0.5.85 -* fix power-limit was not checked for max retransmits #667 -* fix blue LED lights up all the time #672 -* fix installing schedulers if NTP server isn't available -* improved zero values on triggers #671 -* hardcoded MQTT subtopics, because wildcard `#` leads to errors -* rephrased some messages on webif, thx to @Argafal #638 -* fixed 'polling stop message' on `index.html` #639 - -## 0.5.84 -* fix blue LED lights up all the time #672 -* added an instant start communication (once NTP is synced) -* add MI 3rd generation inverters (10x2 serial numbers) -* first decodings of messages from MI 2nd generation inverters - -## 0.5.83 -* fix MQTT publishing, `callback` was set but reset by following `setup()` - -## 0.5.82 -* fixed communication error #652 -* reset values is no bound to MQTT any more, setting moved to `inverter` #649 -* fixed wording on `index.hmtl` #661 - -## 0.5.81 -* started implementation of MI inverters (setup.html, own processing `MiPayload.h`) - -## 0.5.80 -* fixed communication #656 - -## 0.5.79 -* fixed mixed reset flags #648 -* fixed `mCbAlarm` if MQTT is not used #653 -* fixed MQTT `autodiscover` #630 thanks to @antibill51 -* next changes from @beegee many thanks for your contribution! -* replaced `CircularBuffer` by `std::queue` -* reworked `hmRadio.h` completely (interrupts, packaging) -* fix exception while `reboot` -* cleanup MQTT coding - -## 0.5.78 -* further improvements regarding wifi #611, fix connection if only one AP with same SSID is there -* fix endless loop in `zerovalues` #564 -* fix auto discover again #565 -* added total values to autodiscover #630 -* improved zero at midnight #625 - -## 0.5.77 -* fix wrong filename for automatically created manifest (online installer) #620 -* added rotate display feature #619 -* improved Prometheus endpoint #615, thx to @fsck-block -* improved wifi to connect always to strongest RSSI, thx to @beegee3 #611 - -## 0.5.76 -* reduce MQTT retry interval from maximum speed to one second -* fixed homeassistant autodiscovery #565 -* implemented `getNTPTime` improvements #609 partially #611 -* added alarm messages to MQTT #177, #600, #608 - -## 0.5.75 -* fix wakeup issue, once wifi was lost during night the communication didn't start in the morning -* re-enabled FlashStringHelper because of lacking RAM -* complete rewrite of monochrome display class, thx to @dAjaY85 -> displays are now configurable in setup -* fix power limit not possible #607 - -## 0.5.74 -* improved payload handling (retransmit all fragments on CRC error) -* improved `isAvailable`, checks all record structs, inverter becomes available more early because version is check first -* fix tickers were not set if NTP is not available -* disabled annoying `FlashStringHelper` it gives randomly Exceptions during development, feels more stable since then -* moved erase button to the bottom in settings, not nice but more functional -* split `tx_count` to `tx_cnt` and `retransmits` in `system.html` -* fix mqtt retransmit IP address #602 -* added debug infos for `scheduler` (web -> `/debug` as trigger prints list of tickers to serial console) - -## 0.5.73 -* improved payload handling (request / retransmit) #464 -* included alarm ID parse to serial console (in development) - -## 0.5.72 -* repaired system, scheduler was not called any more #596 - -## 0.5.71 -* improved wifi handling and tickers, many thanks to @beegee3 #571 -* fixed YieldTotal correction calculation #589 -* fixed serial output of power limit acknowledge #569 -* reviewed `sendDiscoveryConfig` #565 -* merged PR `Monodisplay`, many thanks to @dAjaY85 #566, Note: (settings are introduced but not able to be modified, will be included in next version) - -## 0.5.70 -* corrected MQTT `comm_disabled` #529 -* fix Prometheus and JSON endpoints (`config_override.h`) #561 -* publish MQTT with fixed interval even if inverter is not available #542 -* added JSON settings upload. NOTE: settings JSON download changed, so only settings should be uploaded starting from version `0.5.70` #551 -* MQTT topic and inverter name have more allowed characters: `[A-Za-z0-9./#$%&=+_-]+`, thx: @Mo Demman -* improved potential issue with `checkTicker`, thx @cbscpe -* MQTT option for reset values on midnight / not avail / communication stop #539 -* small fix in `tickIVCommunication` #534 -* add `YieldTotal` correction, eg. to have the option to zero at year start #512 - -## 0.5.69 -* merged SH1106 1.3" Display, thx @dAjaY85 -* added SH1106 to automatic build -* added IP address to MQTT (version, device and IP are retained and only transmitted once after boot) #556 -* added `set_power_limit` acknowledge MQTT publish #553 -* changed: version, device name are only published via MQTT once after boot -* added `Login` to menu if admin password is set #554 -* added `development` to second changelog link in `index.html` #543 -* added interval for MQTT (as option). With this settings MQTT live data is published in a fixed timing (only if inverter is available) #542, #523 -* added MQTT `comm_disabled` #529 -* changed name of binaries, moved GIT-Sha to the front #538 - -## 0.5.68 -* repaired receive payload -* Powerlimit is transferred immediately to inverter - -## 0.5.67 -* changed calculation of start / stop communication to 1 min after last comm. stop #515 -* moved payload send to `payload.h`, function `ivSend` #515 -* payload: if last frame is missing, request all frames again - -# RELEASE 0.5.66 - 2022-12-30 - -## 0.5.65 -* wifi, code optimization #509 - -## 0.5.64 -* channel name can use any character, not limited any more -* added `/` to MQTT topic and Inverter name -* trigger for `calcSunrise` is now using local time #515 -* fix reconnect timeout for WiFi #509 -* start AP only after boot, not on WiFi connection loss -* improved /system `free_heap` value (measured before JSON-tree is built) - -## 0.5.63 -* fix Update button protection (prevent double click #527) -* optimized scheduler #515 (thx @beegee3) -* potential fix of #526 duplicates in API `/api/record/live` -* added update information to `index.html` - -## 0.5.62 -* fix MQTT `status` update -* removed MQTT `available_text` (can be deducted from `available`) -* enhanced MQTT documentation in `User_Manual.md` -* removed `tickSunset` and `tickSunrise` from MQTT. It's not needed any more because of minute wise check of status (`processIvStatus`) -* changed MQTT topic `status` to nummeric value, check documentation in `User_Manual.md` -* fix regular expression of `setup.html` for inverter name and channel name - -## 0.5.61 -* fix #521 no reconnect at beginning of day -* added immediate (each minute) report of inverter status MQTT #522 -* added protection mask to select which pages should be protected -* update of monochrome display, show values also if nothing changed - -## 0.5.60 -* added regex to inverter name and MQTT topic (setup.html) -* beautified serial.html -* added ticker for wifi loop #515 - -## 0.5.59 -* fix night communication enable -* improved different WiFi connection scenarios (STA WiFi not found, reconnect #509, redirect for AP to configuration) -* increased MQTT user, pwd and topic length to 64 characters + `\0`. (The string end `\0` reduces the available size by one) #516 - -## 0.5.58 -* improved stability -* improved WiFi initial connection - especially if station WiFi is not available -* removed new operators from web.h (reduce dynamic allocation) -* improved sun calculation #515, #505 -* fixed WiFi auto reconnect #509 -* added disable night communication flag to MQTT #505 -* changed MQTT publish of `available` and `available_text` to sunset #468 - -## 0.5.57 -* improved stability -* added icons to index.html, added WiFi-strength symbol on each page -* moved packet stats and sun to system.html -* refactored communication offset (adjustable in minutes now) - -## 0.5.56 -* factory reset formats entire little fs -* renamed sunrise / sunset on index.html to start / stop communication -* show system information only if called directly from menu -* beautified system.html - -## 0.5.55 -* fixed static IP save - -## 0.5.54 -* changed sunrise / sunset calculation, angle is now `-3.5` instead of original `-0.83` -* improved scheduler (removed -1 from `reload`) #483 -* improved reboot flag in `app.h` -* fixed #493 no MQTT payload once display is defined - -## 0.5.53 -* Mono-Display: show values in offline mode #498 -* improved WiFi class #483 -* added communication enable / disable (to test multiple DTUs with the same inverter) -* fix factory reset #495 - -## 0.5.52 -* improved ahoyWifi class -* added interface class for app -* refactored web and webApi -> RestApi -* fix calcSunrise was not called every day -* added MQTT RX counter to index.html -* all values are displayed on /live even if they are 0 -* added MQTT /status to show status over all inverters - -## 0.5.51 -* improved scheduler, @beegee3 #483 -* refactored get NTP time, @beegee3 #483 -* generate `bin.gz` only for 1M device ESP8285 -* fix calcSunrise was not called every day -* increased number of allowed characters for MQTT user, broker and password, @DanielR92 -* added NRF24 info to Systeminfo, @DanielR92 -* added timezone for monochrome displays, @gh-fx2 -* added support for second inverter for monochrome displays, @gh-fx2 - -## 0.5.50 -* fixed scheduler, uptime and timestamp counted too fast -* added / renamed automatically build outputs -* fixed MQTT ESP uptime on reconnect (not zero any more) -* changed uptime on index.html to count each second, synced with ESP each 10 seconds - -## 0.5.49 -* fixed AP mode on brand new ESP modules -* fixed `last_success` MQTT message -* fixed MQTT inverter available status at sunset -* reordered enqueue commands after boot up to prevent same payload length for successive commands -* added automatic build for Nokia5110 and SSD1306 displays (ESP8266) - -## 0.5.48 -* added MQTT message send at sunset -* added monochrome display support -* added `once` and `onceAt` to scheduler to make code cleaner -* improved sunrise / sunset calculation - -## 0.5.47 -* refactored ahoyWifi class: AP is opened on every boot, once station connection is successful the AP will be closed -* improved NTP sync after boot, faster sync -* fix NRF24 details only on valid SPI connection - -## 0.5.46 -* fix sunrise / sunset calculation -* improved setup.html: `reboot on save` is checked as default - -## 0.5.45 -* changed MQTT last will topic from `status` to `mqtt` -* fix sunrise / sunset calculation -* fix time of serial web console - -## 0.5.44 -* marked some MQTT messages as retained -* moved global functions to global location (no duplicates) -* changed index.html interval to static 10 seconds -* fix static IP -* fix NTP with static IP -* print MQTT info only if MQTT was configured - -## 0.5.43 -* updated REST API and MQTT (both of them use the same functionality) -* added ESP-heap information as MQTT message -* changed output name of automatic development build to fixed name (to have a static link from https://ahoydtu.de) -* updated user manual to latest MQTT and API changes - -## 0.5.42 -* fix web logout (auto logout) -* switched MQTT library - -# RELEASE 0.5.41 - 2022-11-22 - -# RELEASE 0.5.28 - 2022-10-30 - -# RELEASE 0.5.17 - 2022-09-06 - -# RELEASE 0.5.16 - 2022-09-04 - +full version log: [Development Log](https://github.com/lumapu/ahoy/blob/development03/src/CHANGES.md) diff --git a/src/defines.h b/src/defines.h index 2b0909cd..23919899 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 8 -#define VERSION_PATCH 35 +#define VERSION_PATCH 36 //------------------------------------- typedef struct {