diff --git a/.github/workflows/compile_esp8266.yml b/.github/workflows/compile_esp8266.yml index 19d9995c..245a5aac 100644 --- a/.github/workflows/compile_esp8266.yml +++ b/.github/workflows/compile_esp8266.yml @@ -1,4 +1,4 @@ -name: ESP8266 +name: Ahoy Release for ESP8266 on: push: @@ -13,33 +13,63 @@ jobs: - uses: actions/checkout@v3 with: ref: main - - name: Cache pip + - uses: benjlevesque/short-sha@v1.2 + id: short-sha + with: + length: 7 + - name: cache-pip uses: actions/cache@v3 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} restore-keys: | ${{ runner.os }}-pip- - - name: Cache PlatformIO + - name: cache-platformio uses: actions/cache@v3 with: path: ~/.platformio key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} - - name: Set up Python + - name: setup-python uses: actions/setup-python@v3 - - name: Install PlatformIO + - name: install-platformio run: | python -m pip install --upgrade pip pip install --upgrade platformio - - name: Update html + - name: update-html working-directory: tools/esp8266/html run: python convert.py - name: Run PlatformIO - run: pio run -d tools/esp8266 - - name: rename + run: pio run -d tools/esp8266 --environment esp8266-release + - name: rename-binary-files + id: rename-binary-files working-directory: tools/esp8266/scripts run: python getVersion.py - - uses: actions/upload-artifact@v3 + - name: create-release + id: create-release + uses: actions/create-release@v1 + with: + draft: false + prerelease: false + release_name: ${{ steps.rename-binary-files.outputs.name }} + tag_name: ${{ github.ref }} + body_path: tools/esp8266/CHANGES.md + env: + GITHUB_TOKEN: ${{ github.token }} + - name: set-version + uses: cschleiden/replace-tokens@v1 + with: + files: tools/esp8266/User_Manual.md + env: + VERSION: ${{ steps.rename-binary-files.outputs.name }} + - name: create-artifact + run: zip --junk-paths ${{ steps.rename-binary-files.outputs.name }}.zip tools/esp8266/.pio/build/out/* tools/esp8266/User_Manual.md + - name: upload-release + id: upload-release + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: - name: esp8266_ahoy - path: tools/esp8266/.pio/build/out/*.bin + upload_url: ${{ steps.create-release.outputs.upload_url }} + asset_path: ./${{ steps.rename-binary-files.outputs.name }}.zip + asset_name: ${{ steps.rename-binary-files.outputs.name }}.zip + asset_content_type: application/zip \ No newline at end of file diff --git a/.gitignore b/.gitignore index da27a66d..f9432353 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ tools/esp8266/binaries tools/esp8266/.vscode/extensions.json .DS_Store .vscode +tools/esp8266/platformio-device-monitor-*.log diff --git a/tools/esp8266/CHANGES.md b/tools/esp8266/CHANGES.md new file mode 100644 index 00000000..3e0714be --- /dev/null +++ b/tools/esp8266/CHANGES.md @@ -0,0 +1,79 @@ +# Changelog + +- v0.5.15 + * Bug fix: mqtt payload handling (thx @klahus1, silverserver) + * Bug fix: eeprom alignment fixed (thx @klahus1) + * mqtt reconnect improvements (thx @tastendruecker123 , @HorstG-57 ) + * simple command scheduler (one place fifo) + * InverterDevInform_All Command parser and output to mqtt + * New workflow to build github release + * Introduction of a command queue (like OpenDTU) + * Feedback from inverter for actual power limit via InfoCmd -> SystemConfigPara (0x05) placed in visualization + * REST API will enqueue a new info command (all commands supported) + * Change in power limit will (Setup, MQTT or REST API) enqueues a new infocmd request to get actual power limit + * Actual power limit is available under MQTT topic //ch0/PowerLimit ALWAYS in percent + * Firmware information will be requested automatically up on start of dtu + * Added User_Manual.md + +- v0.5.14 +- v0.5.13 +- v0.5.12 +- v0.5.11 +- v0.5.10 +- v0.5.9 *fix PowerLimit PowerPFDev.Desc=0x0001 for permanent +- v0.5.8 *fix #146 device name in setup +- v0.5.7 *add collapsible setup +- v0.5.6 *fix only MQTT sub after the first loop in a conenction +- v0.5.5 *fixed MQTT sub only after connection is established (HorstG-57) + + added in app.cpp some compiler if statements + *fix: compile possible for non repository versions (if project was download as zip - lumapu) + *fix README.md - Update line 69 (`RF24` 1.4.2 -> 1.4.5) (DanielR92) + *Update hmRadio.h (lumapu) +- v0.5.4 + added Github report text with a URL (aschiffler) + + added auto_firmware_version.py for GIT_HASH + + added switch case AlarmData/AlarmUpdate +- v0.5.3 #Bugfix #125 PowerLimit + + prototype webapi to get info, improved pwr limit (aschiffler) + + Merge remote-tracking branch 'upstream/main' into pwrlimit +- v0.5.2 add #114 ntp_server_name and port to eeprom + + stefan123t added some functions (devcontrol/cbMqtt/...) +- v0.5.1 *Merge branch 'upstream/HEAD' into control + *update revision (0.4.26 -> 0.5.1) +- v0.4.26 first poc for power set via mqtt +- v0.4.25 added default SERIAL/MQTT/SEND_INTERVAL #100, fixed env:node_mcu_v2 build #101 +- v0.4.24 added fixes for #63, #88, #93. revert #36 (*) EEPROM changes +- v0.4.23 added workflow, fix index.html to load inverter info immediately, changed timestamp to 1 for stand alone ESP #90, Implement MQTT discovery for Home Assistant +- v0.4.22 compiles with PlatformIO +- v0.4.21 reduced warnings +- v0.4.20 improved setup (if no data is in EEprom), improved NRF24 Pinout regarding to #36, Standard Pinout should be now: #36 (comment), add JSON output, fix favicon, improve eeprom default settings (*) EEPROM changes +- v0.4.19 updated debug messages: now 5 different levels are available, fixed CRC loop issue, add fritzing/schematics for Arduino, Raspberry Pi and NodeMCU +- v0.4.18 Creative Commons NC-SA-BY v3.0 license included, tried to increase stability, fix NRF24 CRClength, add debug & documentation links, added variable error messages using #pragma error +- v0.4.17 add printed circuit board layout, more debug output (#retransmits), improved loop counters (*) EEPROM changes +- v0.4.16 request only one inverter per loop (#53 (comment)), mqtt loop interval calculated by # of inverters and inverter request interval, limit maximum number of retries, added feature request #62 (readable names for channels), improved setup page, added javascript to hide / show channel fields (*) EEPROM changes +- v0.4.15 reduced debug messages, fixes after merge +- v0.4.14 added RX channel 40, improved RF24 ISR, reduced AP active time to 60s (will be increase once a client is connected), added `yield` without success -> random reboot (cause 4) (*) EEPROM changes +- v0.4.13 rename to AHOY-DTU, add RX channel 40, update stats on index based on mSendInterval, MQTT Interval, EEPROM CRC settings, fix #56 v0.4.10 ESP8266 stuck in boot loop +- v0.4.12 version skipped ? +- v0.4.11 inverter dependent mqtt (is avail), implemented heap stats #58, inserted 'break' in ISR while loop +- v0.4.10 reduced heap size (>50%) by using 'F()' for (nearly) all static strings, added Wemos D1 case STL files +- v0.4.9 try to fix mqtt and wifi loss issue #52, document libraries (*) EEPROM changes +- v0.4.8 moved mqtt loop out of checkTicker as mentioned in #49, added irritation and efficiency calculations, improved style (*) EEPROM changes +- v0.4.7 version skipped ? +- v0.4.6 version skipped ? +- v0.4.5 fix #38 4-channel inverter current assignment, added last received timestamp in /hoymiles livedata web page #47, improved style.css, improved NTP as described in #46 +- v0.4.4 added free heap, mentioned in #24 (added in serial print, status on index and mqtt), fixed #45, AC current by factor 10 too high, fixed failed payload counter +- v0.4.3 fixed #41 HM800 Yield total and Yield day were mixed around. Found issue while comparing to Python version, fixed #43 HM350 channel 2 is displayed in Live-View, added #42 YieldTotal and YieldTotal Day for HM600 - HM800 inverters +- v0.4.2 fix #39 Assignment 2-Channel inverters (HM-600, HM-700, HM-800) +- v0.4.1 multi inverter support, full re transmit included +- v0.4.0 complete payload processed (and crc checked), inverter type is defined by serial number, serial debug can be switched live (using setup), Note: only one inverter is supported for now! +- v0.3.9 fix #26 ticker / interval in app.cpp +- v0.3.8 improved stability (in comparison to 0.3.7), reset wifi AP timout once a client is detected, fix #26 wrong variable reset +- v0.3.7 added rx channel switching, switched to crc8 check for valid packet-payload +- v0.3.6 improved tickers, only one ticker is active, added feature to use the ESP as access point for all the time, added serial features to setup +- v0.3.5 fixed erase settings, fixed behavior if no MQTT IP is set (the system was nearly unusable because of delayed responses), fixed Station / AP WiFi on startup -> more information will be printed to the serial console, added new ticker for serial value dump +- v0.3.4 added config.h for general configuration, added option to compile WiFi SSID + PWD to firmware, added option to configure WiFi access point name and password, added feature to retry connect to station WiFi (configurable timeouts), updated index.html, added option for factory reset, added info about project on index.html, moved "update" and "home" to footer, fixed #23 HM1200 yield day unit, fixed DNS name of ESP after setup (some commits before) +- v0.3.3 converted to "poor-man-ticker" using millis() for uptime, send and mqtt, added inverter overview, added send count to statistics +- v0.3.2 compile of merge, binary published on https://www.mikrocontroller.net/topic/525778?goto=7051413#7051413 +- v0.3.1 fix: doCalculations was not called +- v0.3.0 version 0.3.0, added unit test +(*) EEPROM changes require settings to be changed, your settings will be overwritten and need to be set again! diff --git a/tools/esp8266/CircularBuffer.h b/tools/esp8266/CircularBuffer.h index 8ad3d5df..b784f639 100644 --- a/tools/esp8266/CircularBuffer.h +++ b/tools/esp8266/CircularBuffer.h @@ -24,6 +24,9 @@ #ifdef ESP8266 #define DISABLE_IRQ noInterrupts() #define RESTORE_IRQ interrupts() +#elif defined(ESP32) +#define DISABLE_IRQ noInterrupts() +#define RESTORE_IRQ interrupts() #else #define DISABLE_IRQ \ uint8_t sreg = SREG; \ diff --git a/tools/esp8266/README.md b/tools/esp8266/README.md index d2c4114f..8ea1ade0 100644 --- a/tools/esp8266/README.md +++ b/tools/esp8266/README.md @@ -68,64 +68,4 @@ For now the following inverters should work out of the box: - `Time` 1.6.1 - `RF24` 1.4.5 - `PubSubClient` 2.8 -- `ArduinoJson` 6.19.4 - -## Changelog - -(*) EEPROM changes require settings to be changed, your settings will be overwritten and need to be set again! -- v0.5.9 *fix PowerLimit PowerPFDev.Desc=0x0001 for permanent -- v0.5.8 *fix #146 device name in setup -- v0.5.7 *add collapsible setup -- v0.5.6 *fix only MQTT sub after the first loop in a conenction -- v0.5.5 *fixed MQTT sub only after connection is established (HorstG-57) - + added in app.cpp some compiler if statements - *fix: compile possible for non repository versions (if project was download as zip - lumapu) - *fix README.md - Update line 69 (`RF24` 1.4.2 -> 1.4.5) (DanielR92) - *Update hmRadio.h (lumapu) -- v0.5.4 + added Github report text with a URL (aschiffler) - + added auto_firmware_version.py for GIT_HASH - + added switch case AlarmData/AlarmUpdate -- v0.5.3 #Bugfix #125 PowerLimit - + prototype webapi to get info, improved pwr limit (aschiffler) - + Merge remote-tracking branch 'upstream/main' into pwrlimit -- v0.5.2 add #114 ntp_server_name and port to eeprom - + stefan123t added some functions (devcontrol/cbMqtt/...) -- v0.5.1 *Merge branch 'upstream/HEAD' into control - *update revision (0.4.26 -> 0.5.1) -- v0.4.26 first poc for power set via mqtt -- v0.4.25 added default SERIAL/MQTT/SEND_INTERVAL #100, fixed env:node_mcu_v2 build #101 -- v0.4.24 added fixes for #63, #88, #93. revert #36 (*) EEPROM changes -- v0.4.23 added workflow, fix index.html to load inverter info immediately, changed timestamp to 1 for stand alone ESP #90, Implement MQTT discovery for Home Assistant -- v0.4.22 compiles with PlatformIO -- v0.4.21 reduced warnings -- v0.4.20 improved setup (if no data is in EEprom), improved NRF24 Pinout regarding to #36, Standard Pinout should be now: #36 (comment), add JSON output, fix favicon, improve eeprom default settings (*) EEPROM changes -- v0.4.19 updated debug messages: now 5 different levels are available, fixed CRC loop issue, add fritzing/schematics for Arduino, Raspberry Pi and NodeMCU -- v0.4.18 Creative Commons NC-SA-BY v3.0 license included, tried to increase stability, fix NRF24 CRClength, add debug & documentation links, added variable error messages using #pragma error -- v0.4.17 add printed circuit board layout, more debug output (#retransmits), improved loop counters (*) EEPROM changes -- v0.4.16 request only one inverter per loop (#53 (comment)), mqtt loop interval calculated by # of inverters and inverter request interval, limit maximum number of retries, added feature request #62 (readable names for channels), improved setup page, added javascript to hide / show channel fields (*) EEPROM changes -- v0.4.15 reduced debug messages, fixes after merge -- v0.4.14 added RX channel 40, improved RF24 ISR, reduced AP active time to 60s (will be increase once a client is connected), added `yield` without success -> random reboot (cause 4) (*) EEPROM changes -- v0.4.13 rename to AHOY-DTU, add RX channel 40, update stats on index based on mSendInterval, MQTT Interval, EEPROM CRC settings, fix #56 v0.4.10 ESP8266 stuck in boot loop -- v0.4.12 version skipped ? -- v0.4.11 inverter dependent mqtt (is avail), implemented heap stats #58, inserted 'break' in ISR while loop -- v0.4.10 reduced heap size (>50%) by using 'F()' for (nearly) all static strings, added Wemos D1 case STL files -- v0.4.9 try to fix mqtt and wifi loss issue #52, document libraries (*) EEPROM changes -- v0.4.8 moved mqtt loop out of checkTicker as mentioned in #49, added irritation and efficiency calculations, improved style (*) EEPROM changes -- v0.4.7 version skipped ? -- v0.4.6 version skipped ? -- v0.4.5 fix #38 4-channel inverter current assignment, added last received timestamp in /hoymiles livedata web page #47, improved style.css, improved NTP as described in #46 -- v0.4.4 added free heap, mentioned in #24 (added in serial print, status on index and mqtt), fixed #45, AC current by factor 10 too high, fixed failed payload counter -- v0.4.3 fixed #41 HM800 Yield total and Yield day were mixed around. Found issue while comparing to Python version, fixed #43 HM350 channel 2 is displayed in Live-View, added #42 YieldTotal and YieldTotal Day for HM600 - HM800 inverters -- v0.4.2 fix #39 Assignment 2-Channel inverters (HM-600, HM-700, HM-800) -- v0.4.1 multi inverter support, full re transmit included -- v0.4.0 complete payload processed (and crc checked), inverter type is defined by serial number, serial debug can be switched live (using setup), Note: only one inverter is supported for now! -- v0.3.9 fix #26 ticker / interval in app.cpp -- v0.3.8 improved stability (in comparison to 0.3.7), reset wifi AP timout once a client is detected, fix #26 wrong variable reset -- v0.3.7 added rx channel switching, switched to crc8 check for valid packet-payload -- v0.3.6 improved tickers, only one ticker is active, added feature to use the ESP as access point for all the time, added serial features to setup -- v0.3.5 fixed erase settings, fixed behavior if no MQTT IP is set (the system was nearly unusable because of delayed responses), fixed Station / AP WiFi on startup -> more information will be printed to the serial console, added new ticker for serial value dump -- v0.3.4 added config.h for general configuration, added option to compile WiFi SSID + PWD to firmware, added option to configure WiFi access point name and password, added feature to retry connect to station WiFi (configurable timeouts), updated index.html, added option for factory reset, added info about project on index.html, moved "update" and "home" to footer, fixed #23 HM1200 yield day unit, fixed DNS name of ESP after setup (some commits before) -- v0.3.3 converted to "poor-man-ticker" using millis() for uptime, send and mqtt, added inverter overview, added send count to statistics -- v0.3.2 compile of merge, binary published on https://www.mikrocontroller.net/topic/525778?goto=7051413#7051413 -- v0.3.1 fix: doCalculations was not called -- v0.3.0 version 0.3.0, added unit test +- `ArduinoJson` 6.19.4 \ No newline at end of file diff --git a/tools/esp8266/User_Manual.md b/tools/esp8266/User_Manual.md index df568bc8..47879889 100644 --- a/tools/esp8266/User_Manual.md +++ b/tools/esp8266/User_Manual.md @@ -10,7 +10,7 @@ In the initial case or after click "erase settings" the fields for the inverter Set at least the serial number and a name for each inverter, check the "reboot after save" and click the "Save" button. ## Active Power Limit via Setup Page -If you leave the field "Active Power Limit" empty during the setup and reboot the ahoy-dtu a value of 65535 will be filled in. +If you leave the field "Active Power Limit" empty during the setup and reboot the ahoy-dtu will set a value of 65535 in the setup. That is the value you have to fill in case you want to operate the inverter without a active power limit. If the value is 65535 or -1 after another reboot the value will be set automatically to "100" and in the drop-down menu "relative in percent persistent" will be set. Of course you can do this also by your self. @@ -24,12 +24,12 @@ and if this settings shall be after a power cycle of the inverter (P_DC=0 and P_AC=0 for at least 10 seconds) The user has to ensure correct settings. Remember that for the inverters of 3rd generation the relative active power limit is in the range of 2% up to 100%. -Also an absolute active power limit below approx. 30Watt is not correct because of the control capabilities and reactive power load. +Also an absolute active power limit below approx. 30 Watt seems to be not meanful because of the control capabilities and reactive power load. ## Active Power Limit via MQTT -The ahoy-dtu subscribes on the topic /devcontrol/# if the mqtt broker is set-up correctly. The default topic is inverter/devcontrol/#. +The ahoy-dtu subscribes on the topic ``/devcontrol/#`` if the mqtt broker is set-up correctly. The default topic is ``inverter/devcontrol/#``. -To set the absolut active power limit you have four options. +To set the active power limit (controled value is the AC Power of the inverter) you have four options. (Only single phase inverters are actually in focus). | topic | payload | active power limit in | Condition | @@ -40,9 +40,9 @@ To set the absolut active power limit you have four options. | /devcontrol//11/257 | [2...100] | % | persistent ### Developer Information MQTT Interface -/devcontrol/// +``/devcontrol///`` -The implementation allows to set any of the available Commands: +The implementation allows to set any of the available ```` Commands: ```C typedef enum { TurnOn = 0, // 0x00 @@ -58,9 +58,34 @@ The implementation allows to set any of the available Commands: Init = 0xff } DevControlCmdType; ``` -The MQTT payload will be set on first to bytes and DATA2 will be set on the second two bytes if the corresponding DevControlCmdType supports 4 byte data. +The MQTT payload will be set on first to bytes and ````, which is taken from the topic path will be set on the second two bytes if the corresponding DevControlCmdType supports 4 byte data. +See here the actual implementation to set the send buffer bytes. +```C + void sendControlPacket(uint64_t invId, uint8_t cmd, uint16_t *data) { + sendCmdPacket(invId, TX_REQ_DEVCONTROL, ALL_FRAMES, false); + int cnt = 0; + // cmd --> 0x0b => Type_ActivePowerContr, 0 on, 1 off, 2 restart, 12 reactive power, 13 power factor + mTxBuf[10] = cmd; + mTxBuf[10 + (++cnt)] = 0x00; + if (cmd >= ActivePowerContr && cmd <= PFSet){ + mTxBuf[10 + (++cnt)] = ((data[0] * 10) >> 8) & 0xff; // power limit || high byte from MQTT payload + mTxBuf[10 + (++cnt)] = ((data[0] * 10) ) & 0xff; // power limit || low byte from MQTT payload + mTxBuf[10 + (++cnt)] = ((data[1] ) >> 8) & 0xff; // high byte from MQTT topic value + mTxBuf[10 + (++cnt)] = ((data[1] ) ) & 0xff; // low byte from MQTT topic value + } + // crc control data + uint16_t crc = Hoymiles::crc16(&mTxBuf[10], cnt+1); + mTxBuf[10 + (++cnt)] = (crc >> 8) & 0xff; + mTxBuf[10 + (++cnt)] = (crc ) & 0xff; + // crc over all + cnt +=1; + mTxBuf[10 + cnt] = Hoymiles::crc8(mTxBuf, 10 + cnt); + + sendPacket(invId, mTxBuf, 10 + (++cnt), true); + } +``` -So as example sending any payload on inverter/devcontrol/0/1 will switch off the inverter. +So as example sending any payload on ``inverter/devcontrol/0/1`` will switch off the inverter. ## Active Power Limit via REST API It is also implemented to set the power limit via REST API call. Therefore send a POST request to the endpoint /api. @@ -107,7 +132,16 @@ Example to set the active power limit persistent to 600Watt ``` ### Developer Information REST API -In the same approach as for MQTT any other SubCmd can be applied and the response payload can be observed in the serial logs. Eg. request the Alarm Data. +In the same approach as for MQTT any other SubCmd and also MainCmd can be applied and the response payload can be observed in the serial logs. Eg. request the Alarm-Data from the Alarm-Index 5 from inverter 0 will look like this: +```json +{ + "inverter":0, + "tx_request": 21, + "cmd": 17, + "payload": 5, + "payload2": 0 +} +``` ## Issues and Debuging for active power limit settings @@ -120,13 +154,30 @@ In case of issues please report: **Developer Information General for Active Power Limit** -⚡To be verified by field tests and feedback +⚡Was verified by field tests and feedback from three users Internally this values will be set for the second two bytes for MainCmd: 0x51 SubCmd: 0x0b --> DevControl set ActivePowerLimit ```C -typedef enum { // ToDo: to be verified by field tests - AbsolutNonPersistent = 0x0000, // 0 - RelativNonPersistent = 0x0001, // 1 - AbsolutPersistent = 0x0100, // 256 - RelativPersistent = 0x0101 // 257 +typedef enum { + AbsolutNonPersistent = 0x0000, // 0 + RelativNonPersistent = 0x0001, // 1 + AbsolutPersistent = 0x0100, // 256 + RelativPersistent = 0x0101 // 257 } PowerLimitControlType; ``` + +## Firmware Version collection +Gather user inverter information here to understand what differs between some inverters. + +| 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 | | | +| 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 | | | +| | | | | | | | | | +| | | | | | | | | | +| | | | | | | | | | +| | | | | | | | | | diff --git a/tools/esp8266/wifi.cpp b/tools/esp8266/ahoywifi.cpp similarity index 93% rename from tools/esp8266/wifi.cpp rename to tools/esp8266/ahoywifi.cpp index f0cc8f84..af1729fa 100644 --- a/tools/esp8266/wifi.cpp +++ b/tools/esp8266/ahoywifi.cpp @@ -3,7 +3,11 @@ // Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ //----------------------------------------------------------------------------- -#include "wifi.h" +#if defined(ESP32) && defined(F) + #undef F + #define F(sl) (sl) +#endif +#include "ahoywifi.h" // NTP CONFIG @@ -12,7 +16,7 @@ //----------------------------------------------------------------------------- -wifi::wifi(app *main, sysConfig_t *sysCfg, config_t *config) { +ahoywifi::ahoywifi(app *main, sysConfig_t *sysCfg, config_t *config) { mMain = main; mSysCfg = sysCfg; mConfig = config; @@ -29,7 +33,7 @@ wifi::wifi(app *main, sysConfig_t *sysCfg, config_t *config) { //----------------------------------------------------------------------------- -void wifi::setup(uint32_t timeout, bool settingValid) { +void ahoywifi::setup(uint32_t timeout, bool settingValid) { mWifiStationTimeout = timeout; #ifndef AP_ONLY if(false == mApActive) @@ -58,7 +62,7 @@ void wifi::setup(uint32_t timeout, bool settingValid) { //----------------------------------------------------------------------------- -bool wifi::loop(void) { +bool ahoywifi::loop(void) { if(mApActive) { mDns->processNextRequest(); #ifndef AP_ONLY @@ -98,7 +102,7 @@ bool wifi::loop(void) { //----------------------------------------------------------------------------- -void wifi::setupAp(const char *ssid, const char *pwd) { +void ahoywifi::setupAp(const char *ssid, const char *pwd) { DPRINTLN(DBG_VERBOSE, F("app::setupAp")); IPAddress apIp(192, 168, 1, 1); @@ -118,7 +122,7 @@ void wifi::setupAp(const char *ssid, const char *pwd) { //----------------------------------------------------------------------------- -bool wifi::setupStation(uint32_t timeout) { +bool ahoywifi::setupStation(uint32_t timeout) { DPRINTLN(DBG_VERBOSE, F("app::setupStation")); int32_t cnt; bool startAp = false; @@ -166,12 +170,12 @@ bool wifi::setupStation(uint32_t timeout) { //----------------------------------------------------------------------------- -bool wifi::getApActive(void) { +bool ahoywifi::getApActive(void) { return mApActive; } //----------------------------------------------------------------------------- -time_t wifi::getNtpTime(void) { +time_t ahoywifi::getNtpTime(void) { //DPRINTLN(DBG_VERBOSE, F("wifi::getNtpTime")); time_t date = 0; IPAddress timeServer; @@ -209,7 +213,7 @@ time_t wifi::getNtpTime(void) { //----------------------------------------------------------------------------- -void wifi::sendNTPpacket(IPAddress& address) { +void ahoywifi::sendNTPpacket(IPAddress& address) { //DPRINTLN(DBG_VERBOSE, F("wifi::sendNTPpacket")); uint8_t buf[NTP_PACKET_SIZE] = {0}; @@ -232,7 +236,7 @@ void wifi::sendNTPpacket(IPAddress& address) { //----------------------------------------------------------------------------- // calculates the daylight saving time for middle Europe. Input: Unixtime in UTC // from: https://forum.arduino.cc/index.php?topic=172044.msg1278536#msg1278536 -time_t wifi::offsetDayLightSaving (uint32_t local_t) { +time_t ahoywifi::offsetDayLightSaving (uint32_t local_t) { //DPRINTLN(DBG_VERBOSE, F("wifi::offsetDayLightSaving")); int m = month (local_t); if(m < 3 || m > 10) return 0; // no DSL in Jan, Feb, Nov, Dez diff --git a/tools/esp8266/wifi.h b/tools/esp8266/ahoywifi.h similarity index 76% rename from tools/esp8266/wifi.h rename to tools/esp8266/ahoywifi.h index 4a1bc32e..5e79568f 100644 --- a/tools/esp8266/wifi.h +++ b/tools/esp8266/ahoywifi.h @@ -3,12 +3,17 @@ // Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ //----------------------------------------------------------------------------- -#ifndef __WIFI_H__ -#define __WIFI_H__ +#ifndef __AHOYWIFI_H__ +#define __AHOYWIFI_H__ #include "dbg.h" -#include -#include +#ifdef ESP8266 + #include + #include +#elif defined(ESP32) + #include + #include +#endif // NTP #include @@ -21,10 +26,10 @@ class app; -class wifi { +class ahoywifi { public: - wifi(app *main, sysConfig_t *sysCfg, config_t *config); - ~wifi() {} + ahoywifi(app *main, sysConfig_t *sysCfg, config_t *config); + ~ahoywifi() {} void setup(uint32_t timeout, bool settingValid); bool loop(void); @@ -32,7 +37,7 @@ class wifi { bool setupStation(uint32_t timeout); bool getApActive(void); time_t getNtpTime(void); - + private: void sendNTPpacket(IPAddress& address); time_t offsetDayLightSaving (uint32_t local_t); @@ -52,4 +57,4 @@ class wifi { bool wifiWasEstablished; }; -#endif /*__WIFI_H__*/ +#endif /*__AHOYWIFI_H__*/ diff --git a/tools/esp8266/app.cpp b/tools/esp8266/app.cpp index a657f875..75fe77df 100644 --- a/tools/esp8266/app.cpp +++ b/tools/esp8266/app.cpp @@ -3,23 +3,24 @@ // Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ //----------------------------------------------------------------------------- +#if defined(ESP32) && defined(F) + #undef F + #define F(sl) (sl) +#endif + #include "app.h" #include //----------------------------------------------------------------------------- app::app() { + Serial.begin(115200); DPRINTLN(DBG_VERBOSE, F("app::app")); mEep = new eep(); - Serial.begin(115200); - - mWifi = new wifi(this, &mSysConfig, &mConfig); - - mWebInst = new web(this, &mSysConfig, &mConfig, mVersion); - mWebInst->setup(); + mWifi = new ahoywifi(this, &mSysConfig, &mConfig); resetSystem(); - loadDefaultConfig(); + loadDefaultConfig(); mSys = new HmSystemType(); } @@ -39,6 +40,9 @@ void app::setup(uint32_t timeout) { setupMqtt(); #endif mSys->setup(&mConfig); + + mWebInst = new web(this, &mSysConfig, &mConfig, mVersion); + mWebInst->setup(); } //----------------------------------------------------------------------------- @@ -107,41 +111,6 @@ void app::loop(void) { } } } - switch (mSys->InfoCmd){ - case InverterDevInform_Simple: - { - DPRINT(DBG_INFO, "Response from inform simple\n"); - mSys->InfoCmd = RealTimeRunData_Debug; // Set back to default - break; - } - case InverterDevInform_All: - { - DPRINT(DBG_INFO, "Response from inform all\n"); - break; - } - case GetLossRate: - { - DPRINT(DBG_INFO, "Response from get loss rate\n"); - mSys->InfoCmd = RealTimeRunData_Debug; // Set back to default - break; - } - case AlarmData: - { - DPRINT(DBG_INFO, "Response from AlarmData\n"); - mSys->InfoCmd = RealTimeRunData_Debug; // Set back to default - break; - } - case AlarmUpdate: - { - DPRINT(DBG_INFO, "Response from AlarmUpdate\n"); - mSys->InfoCmd = RealTimeRunData_Debug; // Set back to default - break; - } - case RealTimeRunData_Debug: - { - break; - } - } } if(NULL != iv && p->packet[0] == (TX_REQ_DEVCONTROL + 0x80)) { // response from dev control command DPRINTLN(DBG_DEBUG, F("Response from devcontrol request received")); @@ -149,7 +118,7 @@ void app::loop(void) { switch (p->packet[12]){ case ActivePowerContr: if (iv->devControlCmd >= ActivePowerContr && iv->devControlCmd <= PFSet){ // ok inverter accepted the set point copy it to dtu eeprom - if (iv->powerLimit[1]>0){ // User want to have it persistent + if ((iv->powerLimit[1] & 0xff00) >0){ // User want to have it persistent mEep->write(ADDR_INV_PWR_LIM + iv->id * 2,iv->powerLimit[0]); mEep->write(ADDR_INV_PWR_LIM_CON + iv->id * 2,iv->powerLimit[1]); updateCrc(); @@ -180,7 +149,7 @@ void app::loop(void) { if(rxRdy) { - processPayload(true,mSys->InfoCmd); + processPayload(true); } } @@ -190,7 +159,7 @@ void app::loop(void) { if(checkTicker(&mTicker, 1000)) { if((++mMqttTicker >= mMqttInterval) && (mMqttInterval != 0xffff) && mMqttActive) { mMqttTicker = 0; - mMqtt.isConnected(true); + mMqtt.isConnected(true); // really needed? See comment from HorstG-57 #176 char topic[30], val[10]; for(uint8_t id = 0; id < mSys->getNumInverters(); id++) { Inverter<> *iv = mSys->getInverterByPos(id); @@ -266,7 +235,7 @@ void app::loop(void) { if(NULL != iv) { if(!mPayload[iv->id].complete) - processPayload(false,mSys->InfoCmd); + processPayload(false); if(!mPayload[iv->id].complete) { mRxFailed++; @@ -286,8 +255,9 @@ void app::loop(void) { if(mConfig.serialDebug) DPRINTLN(DBG_INFO, F("Devcontrol request ") + String(iv->devControlCmd) + F(" power limit ") + String(iv->powerLimit[0])); mSys->Radio.sendControlPacket(iv->radioId.u64,iv->devControlCmd ,iv->powerLimit); + iv->enqueCommand(SystemConfigPara); } else { - mSys->Radio.sendTimePacket(iv->radioId.u64, mSys->InfoCmd, mPayload[iv->id].ts,iv->alarmMesIndex); + mSys->Radio.sendTimePacket(iv->radioId.u64,iv->getQueuedCmd(), mPayload[iv->id].ts,iv->alarmMesIndex); mRxTicker = 0; } } @@ -333,10 +303,7 @@ bool app::buildPayload(uint8_t id) { //----------------------------------------------------------------------------- -void app::processPayload(bool retransmit) { - processPayload(retransmit, RealTimeRunData_Debug); -} -void app::processPayload(bool retransmit, uint8_t cmd = RealTimeRunData_Debug) { // cmd value decides which parser is used to decode payload +void app::processPayload(bool retransmit) { #ifdef __MQTT_AFTER_RX__ boolean doMQTT = false; @@ -369,7 +336,7 @@ void app::processPayload(bool retransmit, uint8_t cmd = RealTimeRunData_Debug) { if(0x00 != mLastPacketId) mSys->Radio.sendCmdPacket(iv->radioId.u64, TX_REQ_INFO, mLastPacketId, true); else - mSys->Radio.sendTimePacket(iv->radioId.u64, mSys->InfoCmd, mPayload[iv->id].ts,iv->alarmMesIndex); + mSys->Radio.sendTimePacket(iv->radioId.u64, iv->getQueuedCmd(), mPayload[iv->id].ts,iv->alarmMesIndex); } mSys->Radio.switchRxCh(100); } @@ -392,19 +359,18 @@ void app::processPayload(bool retransmit, uint8_t cmd = RealTimeRunData_Debug) { mSys->Radio.dumpBuf(NULL, payload, offs); } mRxSuccess++; - mSys->InfoCmd = RealTimeRunData_Debug; // On success set back to default - - iv->getAssignment(cmd); // choose the parser + + iv->getAssignment(); // choose the parser for(uint8_t i = 0; i < iv->listLen; i++) { - iv->addValue(i, payload,cmd); // cmd value decides which parser is used to decode payload + iv->addValue(i, payload); // cmd value decides which parser is used to decode payload yield(); } - iv->doCalculations(cmd); // cmd value decides which parser is used to decode payload + iv->doCalculations(); // cmd value decides which parser is used to decode payload #ifdef __MQTT_AFTER_RX__ doMQTT = true; #endif - + iv->setQueuedCmdFinished(); } } yield(); @@ -433,7 +399,7 @@ void app::cbMqtt(char* topic, byte* payload, unsigned int length) { const char *token = strtok(topic, "/"); while (token != NULL) { - if (std::strcmp(token,"devcontrol")==0){ + if (strcmp(token,"devcontrol")==0){ token = strtok(NULL, "/"); uint8_t iv_id = std::stoi(token); if (iv_id >= 0 && iv_id <= MAX_NUM_INVERTERS){ @@ -481,7 +447,7 @@ void app::cbMqtt(char* topic, byte* payload, unsigned int length) { iv->devControlCmd = ReactivePowerContr; if (true){ // if (std::stoi((char*)payload) > 0) error handling powerlimit needed? iv->devControlCmd = ReactivePowerContr; - iv->powerLimit[0] = std::stoi((char*)payload); + iv->powerLimit[0] = std::stoi(std::string((char*)payload, (unsigned int)length)); iv->powerLimit[1] = 0x0000; // if reactivepower limit is set via external interface --> set it temporay DPRINTLN(DBG_DEBUG, F("Reactivepower limit for inverter ") + String(iv->id) + F(" set to ") + String(iv->powerLimit[0]) + F("W") ); iv->devControlRequest = true; @@ -559,32 +525,48 @@ String app::getStatistics(void) { //----------------------------------------------------------------------------- -String app::getLiveData(void) { +String app::getLiveData(void) +{ String modHtml; - for(uint8_t id = 0; id < mSys->getNumInverters(); id++) { + for (uint8_t id = 0; id < mSys->getNumInverters(); id++) + { Inverter<> *iv = mSys->getInverterByPos(id); - if(NULL != iv) { + if (NULL != iv) + { #ifdef LIVEDATA_VISUALIZED uint8_t modNum, pos; - switch(iv->type) { - default: - case INV_TYPE_1CH: modNum = 1; break; - case INV_TYPE_2CH: modNum = 2; break; - case INV_TYPE_4CH: modNum = 4; break; + switch (iv->type) + { + default: + case INV_TYPE_1CH: + modNum = 1; + break; + case INV_TYPE_2CH: + modNum = 2; + break; + case INV_TYPE_4CH: + modNum = 4; + break; } modHtml += F("
" - "
") + String(iv->name) + F(" Limit ") + String(iv->powerLimit[0]); - if (iv->powerLimit[1] & 0x0001){ + "
") + + String(iv->name) + F(" Limit ") + String(iv->actPowerLimit); + if (true) + { // live Power Limit from inverter is always in % modHtml += F(" %"); - } else { + } + else + { modHtml += F(" W"); } uint8_t list[] = {FLD_UAC, FLD_IAC, FLD_PAC, FLD_F, FLD_PCT, FLD_T, FLD_YT, FLD_YD, FLD_PDC, FLD_EFF, FLD_PRA, FLD_ALARM_MES_ID}; - for(uint8_t fld = 0; fld < 12; fld++) { + for (uint8_t fld = 0; fld < 12; fld++) + { pos = (iv->getPosByChFld(CH0, list[fld])); - if(0xff != pos) { + if (0xff != pos) + { modHtml += F("
"); modHtml += F("") + String(iv->getValue(pos)); modHtml += F("") + String(iv->getUnit(pos)) + F(""); @@ -594,23 +576,39 @@ String app::getLiveData(void) { } modHtml += "
"; - for(uint8_t ch = 1; ch <= modNum; ch ++) { + for (uint8_t ch = 1; ch <= modNum; ch++) + { modHtml += F("
"); - if(iv->chName[ch-1][0] == 0) + if (iv->chName[ch - 1][0] == 0) modHtml += F("CHANNEL ") + String(ch); else - modHtml += String(iv->chName[ch-1]); + modHtml += String(iv->chName[ch - 1]); modHtml += F(""); - for(uint8_t j = 0; j < 6; j++) { - switch(j) { - default: pos = (iv->getPosByChFld(ch, FLD_UDC)); break; - case 1: pos = (iv->getPosByChFld(ch, FLD_IDC)); break; - case 2: pos = (iv->getPosByChFld(ch, FLD_PDC)); break; - case 3: pos = (iv->getPosByChFld(ch, FLD_YD)); break; - case 4: pos = (iv->getPosByChFld(ch, FLD_YT)); break; - case 5: pos = (iv->getPosByChFld(ch, FLD_IRR)); break; + for (uint8_t j = 0; j < 6; j++) + { + switch (j) + { + default: + pos = (iv->getPosByChFld(ch, FLD_UDC)); + break; + case 1: + pos = (iv->getPosByChFld(ch, FLD_IDC)); + break; + case 2: + pos = (iv->getPosByChFld(ch, FLD_PDC)); + break; + case 3: + pos = (iv->getPosByChFld(ch, FLD_YD)); + break; + case 4: + pos = (iv->getPosByChFld(ch, FLD_YT)); + break; + case 5: + pos = (iv->getPosByChFld(ch, FLD_IRR)); + break; } - if(0xff != pos) { + if (0xff != pos) + { modHtml += F("") + String(iv->getValue(pos)); modHtml += F("") + String(iv->getUnit(pos)) + F(""); modHtml += F("") + String(iv->getFieldName(pos)) + F(""); @@ -625,7 +623,8 @@ String app::getLiveData(void) { // dump all data to web frontend modHtml = F("
");
             char topic[30], val[10];
-            for(uint8_t i = 0; i < iv->listLen; i++) {
+            for (uint8_t i = 0; i < iv->listLen; i++)
+            {
                 snprintf(topic, 30, "%s/ch%d/%s", iv->name, iv->assign[i].ch, iv->getFieldName(i));
                 snprintf(val, 10, "%.3f %s", iv->getValue(i), iv->getUnit(i));
                 modHtml += String(topic) + ": " + String(val) + "\n";
@@ -637,7 +636,6 @@ String app::getLiveData(void) {
     return modHtml;
 }
 
-
 //-----------------------------------------------------------------------------
 String app::getJson(void) {
     DPRINTLN(DBG_VERBOSE, F("app::showJson"));
@@ -854,7 +852,6 @@ void app::loadEEpconfig(void) {
                     // it is "doppelt-gemoppelt" because the inverter shall remember the setting if the dtu makes a power cycle / reboot
                     if (iv->powerLimit[0] != 0xffff) { 
                         iv->devControlCmd = ActivePowerContr; // set active power limit
-                        iv->devControlRequest = true; // set to true to update the active power limit from setup html page
                         if (iv->powerLimit[1] & 0x0001){
                             DPRINTLN(DBG_INFO, F("add inverter: ") + String(name) + ", SN: " + String(invSerial, HEX) + ", Power Limit: " + String(iv->powerLimit[0]) + " in %");    
                         } else {
diff --git a/tools/esp8266/app.h b/tools/esp8266/app.h
index 00967f76..0e09701a 100644
--- a/tools/esp8266/app.h
+++ b/tools/esp8266/app.h
@@ -21,7 +21,7 @@
 #include "CircularBuffer.h"
 #include "hmSystem.h"
 #include "mqtt.h"
-#include "wifi.h"
+#include "ahoywifi.h"
 #include "web.h"
 
 //  hier läst sich das Verhalten der app in Bezug auf MQTT
@@ -56,7 +56,7 @@ typedef struct {
 } invPayload_t;
 
 
-class wifi;
+class ahoywifi;
 class web;
 
 class app {
@@ -200,10 +200,19 @@ class app {
 
         void stats(void) {
             DPRINTLN(DBG_VERBOSE, F("main.h:stats"));
-            uint32_t free;
-            uint16_t max;
-            uint8_t frag;
-            ESP.getHeapStats(&free, &max, &frag);
+            #ifdef ESP8266
+                uint32_t free;
+                uint16_t max;
+                uint8_t frag;
+                ESP.getHeapStats(&free, &max, &frag);
+            #elif defined(ESP32)
+                uint32_t free;
+                uint32_t max;
+                uint8_t frag;
+                free = ESP.getFreeHeap();
+                max = ESP.getMaxAllocHeap();
+                frag = 0;
+            #endif
             DPRINT(DBG_VERBOSE, F("free: ") + String(free));
             DPRINT(DBG_VERBOSE, F(" - max: ") + String(max) + "%");
             DPRINTLN(DBG_VERBOSE, F(" - frag: ") + String(frag));
@@ -224,7 +233,7 @@ class app {
 
         bool mShowRebootRequest;
 
-        wifi *mWifi;
+        ahoywifi *mWifi;
         web *mWebInst;
         sysConfig_t mSysConfig;
         config_t mConfig;
diff --git a/tools/esp8266/config.h b/tools/esp8266/config.h
index a022528e..8331c273 100644
--- a/tools/esp8266/config.h
+++ b/tools/esp8266/config.h
@@ -58,7 +58,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     4
+#define MAX_PAYLOAD_ENTRIES     10
 
 // maximum requests for retransmits per payload (per inverter)
 #define DEF_MAX_RETRANS_PER_PYLD 5
diff --git a/tools/esp8266/defines.h b/tools/esp8266/defines.h
index 339ef89e..31b65b77 100644
--- a/tools/esp8266/defines.h
+++ b/tools/esp8266/defines.h
@@ -13,7 +13,7 @@
 //-------------------------------------
 #define VERSION_MAJOR       0
 #define VERSION_MINOR       5
-#define VERSION_PATCH       14
+#define VERSION_PATCH       15
 
 
 //-------------------------------------
@@ -25,22 +25,22 @@ typedef struct {
 typedef enum {
     InverterDevInform_Simple = 0,   // 0x00
     InverterDevInform_All = 1,      // 0x01
-    //GridOnProFilePara = 2,        // 0x02
-    //HardWareConfig = 3,           // 0x03
-    //SimpleCalibrationPara = 4,    // 0x04
-    //SystemConfigPara = 5,         // 0x05
+    GridOnProFilePara = 2,        // 0x02
+    HardWareConfig = 3,           // 0x03
+    SimpleCalibrationPara = 4,    // 0x04
+    SystemConfigPara = 5,           // 0x05
     RealTimeRunData_Debug = 11,     // 0x0b
-    //RealTimeRunData_Reality = 12, // 0x0c
-    //RealTimeRunData_A_Phase = 13, // 0x0d
-    //RealTimeRunData_B_Phase = 14, // 0x0e
-    //RealTimeRunData_C_Phase = 15, // 0x0f
+    RealTimeRunData_Reality = 12, // 0x0c
+    RealTimeRunData_A_Phase = 13, // 0x0d
+    RealTimeRunData_B_Phase = 14, // 0x0e
+    RealTimeRunData_C_Phase = 15, // 0x0f
     AlarmData = 17,                 // 0x11, Alarm data - all unsent alarms
     AlarmUpdate = 18,               // 0x12, Alarm data - all pending alarms
-    //RecordData = 19,              // 0x13
-    //InternalData = 20,            // 0x14
+    RecordData = 19,              // 0x13
+    InternalData = 20,            // 0x14
     GetLossRate = 21,               // 0x15
-    //GetSelfCheckState = 30,       // 0x1e
-    //InitDataState = 0xff
+    GetSelfCheckState = 30,       // 0x1e
+    InitDataState = 0xff
 } InfoCmdType;
 
 typedef enum {
@@ -109,15 +109,16 @@ typedef enum { // ToDo: to be verified by field tests
 #define SER_DEBUG_LEN           1 // uint8_t
 #define SER_INTERVAL_LEN        2 // uint16_t
 
-
+#pragma pack(push)  // push current alignment to stack
+#pragma pack(1)     // set alignment to 1 byte boundary
 typedef struct {
     char broker[MQTT_ADDR_LEN];
     uint16_t port;
     char user[MQTT_USER_LEN];
     char pwd[MQTT_PWD_LEN];
     char topic[MQTT_TOPIC_LEN];
-} mqttConfig_t;
-
+} /*__attribute__((__packed__))*/ mqttConfig_t;
+#pragma pack(pop)   // restore original alignment from stack
 typedef struct {
     char deviceName[DEVNAME_LEN];
 
@@ -126,6 +127,8 @@ typedef struct {
     char stationPwd[PWD_LEN];
 } sysConfig_t;
 
+#pragma pack(push)  // push current alignment to stack
+#pragma pack(1)     // set alignment to 1 byte boundary
 typedef struct {
     // nrf24
     uint16_t sendInterval;
@@ -146,7 +149,8 @@ typedef struct {
     uint16_t serialInterval;
     bool serialShowIv;
     bool serialDebug;
-} config_t;
+} /*__attribute__((__packed__))*/ config_t;
+#pragma pack(pop)   // restore original alignment from stack
 
 
 #define CFG_MQTT_LEN            MQTT_ADDR_LEN + 2 + MQTT_USER_LEN + MQTT_PWD_LEN +MQTT_TOPIC_LEN
diff --git a/tools/esp8266/eep.h b/tools/esp8266/eep.h
index b66d2cf7..69aff7f5 100644
--- a/tools/esp8266/eep.h
+++ b/tools/esp8266/eep.h
@@ -8,11 +8,23 @@
 
 #include "Arduino.h"
 #include 
+#ifdef ESP32
+    #include 
+#endif
 
 class eep {
     public:
         eep() {
-            EEPROM.begin(4096);
+            
+            #ifdef ESP32
+                if(!EEPROM.begin(4096)) {
+                    nvs_flash_init();
+                    EEPROM.begin(4096);
+                }
+            #else
+                EEPROM.begin(4096);
+            #endif
+
         }
         ~eep() {
             EEPROM.end();
diff --git a/tools/esp8266/hmDefines.h b/tools/esp8266/hmDefines.h
index e69bc071..36139bb2 100644
--- a/tools/esp8266/hmDefines.h
+++ b/tools/esp8266/hmDefines.h
@@ -23,9 +23,9 @@ const char* const units[] = {"V", "A", "W", "Wh", "kWh", "Hz", "°C", "%","VAr",
 
 // field types
 enum {FLD_UDC = 0, FLD_IDC, FLD_PDC, FLD_YD, FLD_YW, FLD_YT,
-        FLD_UAC, FLD_IAC, FLD_PAC, FLD_F, FLD_T, FLD_PCT, FLD_EFF, FLD_IRR, FLD_PRA,FLD_ALARM_MES_ID,FLD_FW_VERSION,FLD_FW_BUILD_YEAR,FLD_FW_BUILD_MONTH_DAY,FLD_HW_ID};
+        FLD_UAC, FLD_IAC, FLD_PAC, FLD_F, FLD_T, FLD_PCT, FLD_EFF, FLD_IRR, FLD_PRA,FLD_ALARM_MES_ID,FLD_FW_VERSION,FLD_FW_BUILD_YEAR,FLD_FW_BUILD_MONTH_DAY,FLD_HW_ID,FLD_ACT_PWR_LIMIT};
 const char* const fields[] = {"U_DC", "I_DC", "P_DC", "YieldDay", "YieldWeek", "YieldTotal",
-        "U_AC", "I_AC", "P_AC", "Freq", "Temp", "Pct", "Efficiency", "Irradiation","P_ACr","ALARM_MES_ID","FWVersion","FWBuildYear","FWBuildMonthDay","HWPartId"};
+        "U_AC", "I_AC", "P_AC", "Freq", "Temp", "Pct", "Efficiency", "Irradiation","P_ACr","ALARM_MES_ID","FWVersion","FWBuildYear","FWBuildMonthDay","HWPartId","PowerLimit"};
 
 // 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};
@@ -92,6 +92,12 @@ const byteAssign_t InfoAssignment[] = {
 };
 #define HMINFO_LIST_LEN     (sizeof(InfoAssignment) / sizeof(byteAssign_t))
 
+const byteAssign_t SystemConfigParaAssignment[] = {
+    { FLD_ACT_PWR_LIMIT,           UNIT_PCT,   CH0,  2, 2, 10 }
+};
+#define HMSYSTEM_LIST_LEN     (sizeof(SystemConfigParaAssignment) / sizeof(byteAssign_t))
+
+
 
 
 //-------------------------------------
diff --git a/tools/esp8266/hmInverter.h b/tools/esp8266/hmInverter.h
index 3b443873..774fd809 100644
--- a/tools/esp8266/hmInverter.h
+++ b/tools/esp8266/hmInverter.h
@@ -6,7 +6,14 @@
 #ifndef __HM_INVERTER_H__
 #define __HM_INVERTER_H__
 
+#if defined(ESP32) && defined(F)
+  #undef F
+  #define F(sl) (sl)
+#endif
+
 #include "hmDefines.h"
+#include 
+#include 
 
 /**
  * For values which are of interest and not transmitted by the inverter can be
@@ -46,9 +53,35 @@ template
 struct calcFunc_t {
     uint8_t funcId; // unique id
     func_t*  func;   // function pointer
-} ;
+};
 
 
+class CommandAbstract {
+    public:
+        CommandAbstract(uint8_t txType = 0, uint8_t cmd = 0){
+            _TxType = txType;
+            _Cmd = cmd;
+        };
+        virtual ~CommandAbstract() {};
+
+        const uint8_t getCmd()
+        {       
+            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[] = {
@@ -72,6 +105,7 @@ class Inverter {
         uint16_t      alarmMesIndex; // Last recorded Alarm Message Index
         uint16_t      fwVersion; // Firmware Version from Info Command Request
         uint16_t      powerLimit[2];  // limit power output
+        uint16_t      actPowerLimit; //
         uint8_t       devControlCmd;  // carries the requested cmd
         bool          devControlRequest; // true if change needed
         serial_u      serial;   // serial number as on barcode
@@ -87,6 +121,7 @@ class Inverter {
             ts = 0;
             powerLimit[0] = 0xffff; // 65535 W Limit -> unlimited
             powerLimit[1] = 0x0000; // 
+            actPowerLimit = 0xffff; // init feedback from inverter to -1
             devControlRequest = false;
             devControlCmd = 0xff;
             initialized = false;
@@ -97,6 +132,30 @@ class Inverter {
             // TODO: cleanup
         }
 
+        template 
+        void enqueCommand(uint8_t cmd)
+        {
+           _commandQueue.push(std::make_shared(cmd));
+           DPRINTLN(DBG_INFO, "enqueuedCmd: " + String(cmd));
+        }
+
+        void setQueuedCmdFinished(){
+            if (!_commandQueue.empty()){
+                _commandQueue.pop(); // Will destroy CommandAbstract Class Object (?)
+            }
+        }
+
+    	uint8_t getQueuedCmd()
+        {
+            if (_commandQueue.empty()){
+                // Fill with default commands
+                enqueCommand(RealTimeRunData_Debug);
+                //enqueCommand(SystemConfigPara);
+            }
+            return _commandQueue.front().get()->getCmd();
+        }
+
+
         void init(void) {
             DPRINTLN(DBG_VERBOSE, F("hmInverter.h:init"));
             getAssignment();
@@ -105,6 +164,8 @@ class Inverter {
             memset(name, 0, MAX_NAME_LENGTH);
             memset(chName, 0, MAX_NAME_LENGTH * 4);
             memset(record, 0, sizeof(RECORDTYPE) * listLen);
+            enqueCommand(InverterDevInform_All);
+            enqueCommand(SystemConfigPara);
             initialized = true;
         }
 
@@ -133,8 +194,9 @@ class Inverter {
             return assign[pos].ch;
         }
 
-        void addValue(uint8_t pos, uint8_t buf[],uint8_t cmd) {
+        void addValue(uint8_t pos, uint8_t buf[]) {
             DPRINTLN(DBG_VERBOSE, F("hmInverter.h:addValue"));
+            uint8_t cmd = getQueuedCmd();
             uint8_t ptr  = assign[pos].start;
             uint8_t end  = ptr + assign[pos].num;
             uint16_t div = assign[pos].div;
@@ -144,8 +206,7 @@ class Inverter {
                     val <<= 8;
                     val |= buf[ptr];
                 } while(++ptr != end);
-
-                record[pos] = (RECORDTYPE)(val) / (RECORDTYPE)(div);
+                record[pos] = (RECORDTYPE)(val) / (RECORDTYPE)(div);                
             }
             if (cmd == RealTimeRunData_Debug) {
                 // get last alarm message index and save it in the inverter object
@@ -160,6 +221,13 @@ class Inverter {
                     DPRINT(DBG_DEBUG, F("Inverter FW-Version: ") + String(fwVersion));
                 }
             }
+            if (cmd == SystemConfigPara) {
+                // get at least the firmware version and save it to the inverter object
+                if (getPosByChFld(0, FLD_ACT_PWR_LIMIT) == pos){ 
+                    actPowerLimit = record[pos];
+                    DPRINT(DBG_DEBUG, F("Inverter actual power limit: ") + String(actPowerLimit));
+                }
+            }
         }
 
         RECORDTYPE getValue(uint8_t pos) {
@@ -167,9 +235,10 @@ class Inverter {
             return record[pos];
         }
 
-        void doCalculations(uint8_t cmd=RealTimeRunData_Debug) {
+        void doCalculations() {
             DPRINTLN(DBG_VERBOSE, F("hmInverter.h:doCalculations"));
-            getAssignment(cmd);
+            uint8_t cmd = getQueuedCmd();
+            getAssignment();
             if (cmd == RealTimeRunData_Debug){
                 for(uint8_t i = 0; i < listLen; i++) {
                     if(CMD_CALC == assign[i].div) {
@@ -199,37 +268,52 @@ class Inverter {
             return ts;
         }
 
-        void getAssignment(uint8_t cmd=RealTimeRunData_Debug) {
-            DPRINTLN(DBG_VERBOSE, F("hmInverter.h:getAssignment"));
-            if(cmd == RealTimeRunData_Debug){
-                if(INV_TYPE_1CH == type) {
-                    listLen  = (uint8_t)(HM1CH_LIST_LEN);
-                    assign   = (byteAssign_t*)hm1chAssignment;
+        void getAssignment() {
+            DPRINTLN(DBG_DEBUG, F("hmInverter.h:getAssignment"));
+            uint8_t cmd = getQueuedCmd();
+            switch (cmd)
+            {
+            case RealTimeRunData_Debug:
+                if (INV_TYPE_1CH == type)
+                {
+                    listLen = (uint8_t)(HM1CH_LIST_LEN);
+                    assign = (byteAssign_t *)hm1chAssignment;
                     channels = 1;
                 }
-                else if(INV_TYPE_2CH == type) {
-                    listLen  = (uint8_t)(HM2CH_LIST_LEN);
-                    assign   = (byteAssign_t*)hm2chAssignment;
+                else if (INV_TYPE_2CH == type)
+                {
+                    listLen = (uint8_t)(HM2CH_LIST_LEN);
+                    assign = (byteAssign_t *)hm2chAssignment;
                     channels = 2;
                 }
-                else if(INV_TYPE_4CH == type) {
-                    listLen  = (uint8_t)(HM4CH_LIST_LEN);
-                    assign   = (byteAssign_t*)hm4chAssignment;
+                else if (INV_TYPE_4CH == type)
+                {
+                    listLen = (uint8_t)(HM4CH_LIST_LEN);
+                    assign = (byteAssign_t *)hm4chAssignment;
                     channels = 4;
                 }
-                else {
-                    listLen  = 0;
+                else
+                {
+                    listLen = 0;
                     channels = 0;
-                    assign   = NULL;
+                    assign = NULL;
                 }
-            }
-            if(cmd == InverterDevInform_All){
-                listLen  = (uint8_t)(HMINFO_LIST_LEN);
-                assign   = (byteAssign_t*)InfoAssignment;
+                break;
+            case InverterDevInform_All:
+                listLen = (uint8_t)(HMINFO_LIST_LEN);
+                assign = (byteAssign_t *)InfoAssignment;
+                break;
+            case SystemConfigPara:
+                listLen = (uint8_t)(HMSYSTEM_LIST_LEN);
+                assign = (byteAssign_t *)SystemConfigParaAssignment;
+                break;
+            default:
+                DPRINTLN(DBG_INFO, "Parser not implemented"); 
             }
         }
 
     private:
+        std::queue> _commandQueue;
         void toRadioId(void) {
             DPRINTLN(DBG_VERBOSE, F("hmInverter.h:toRadioId"));
             radioId.u64  = 0ULL;
diff --git a/tools/esp8266/hmSystem.h b/tools/esp8266/hmSystem.h
index 1070445a..aa9c7645 100644
--- a/tools/esp8266/hmSystem.h
+++ b/tools/esp8266/hmSystem.h
@@ -19,12 +19,10 @@ class HmSystem {
         RadioType Radio;
         typedef BUFFER BufferType;
         BufferType BufCtrl;
-        InfoCmdType InfoCmd;
         //DevControlCmdType DevControlCmd;        
 
         HmSystem() {
             mNumInv = 0;
-            InfoCmd = RealTimeRunData_Debug; // default case
         }
         ~HmSystem() {
             // TODO: cleanup
diff --git a/tools/esp8266/html/h/index_html.h b/tools/esp8266/html/h/index_html.h
index 61dd0cce..c6f769ce 100644
--- a/tools/esp8266/html/h/index_html.h
+++ b/tools/esp8266/html/h/index_html.h
@@ -1,4 +1,4 @@
 #ifndef __INDEX_HTML_H__
 #define __INDEX_HTML_H__
-const char index_html[] PROGMEM = "Index - {DEVICE}

AHOY - {DEVICE}

Visualization

Setup

Uptime:

Statistics:

Every {TS}seconds the values are updated

This project was started from this discussion. (Mikrocontroller.net)
New updates can be found on Github: https://github.com/grindylow/ahoy

Please report issues using the feature provided by Github

Discuss with us on Discord

Creative Commons - https://creativecommons.org/licenses/by-nc-sa/3.0/de/
Check the licenses which are published on https://github.com/grindylow/ahoyas well

© 2022

Update Firmware

AHOY :: {VERSION}

Reboot

Git SHA: {BUILD}

"; +const char index_html[] PROGMEM = "Index - {DEVICE}

AHOY - {DEVICE}

Visualization

Setup

Uptime:

Statistics:

Every {TS}seconds the values are updated

This project was started from this discussion. (Mikrocontroller.net)
New updates can be found on Github: https://github.com/grindylow/ahoy

Please report issues using the feature provided by Github

Discuss with us on Discord

Creative Commons - https://creativecommons.org/licenses/by-nc-sa/3.0/de/
Check the licenses which are published on https://github.com/grindylow/ahoyas well

© 2022

Update Firmware

AHOY :: {VERSION}

Reboot

Git SHA: {BUILD}

"; #endif /*__INDEX_HTML_H__*/ diff --git a/tools/esp8266/html/h/setup_html.h b/tools/esp8266/html/h/setup_html.h index c114fdfc..5ec006e5 100644 --- a/tools/esp8266/html/h/setup_html.h +++ b/tools/esp8266/html/h/setup_html.h @@ -1,4 +1,4 @@ #ifndef __SETUP_HTML_H__ #define __SETUP_HTML_H__ -const char setup_html[] PROGMEM = "Setup - {DEVICE}

Setup

ERASE SETTINGS (not WiFi)

Device Host Name

WiFi

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

Inverter{INVERTERS}

General

NTP Server
MQTT
System Config

Pinout (Wemos)

{PINOUT}

Radio (NRF24L01+)

Serial Console



 

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

Setup

ERASE SETTINGS (not WiFi)
Device Host Name
WiFi

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

Inverter{INVERTERS}

General

NTP Server
MQTT
System Config

Pinout (Wemos)

{PINOUT}

Radio (NRF24L01+)

Serial Console



"; #endif /*__SETUP_HTML_H__*/ diff --git a/tools/esp8266/html/h/style_css.h b/tools/esp8266/html/h/style_css.h index b7fec0cf..24f50e79 100644 --- a/tools/esp8266/html/h/style_css.h +++ b/tools/esp8266/html/h/style_css.h @@ -1,4 +1,4 @@ #ifndef __STYLE_CSS_H__ #define __STYLE_CSS_H__ -const char style_css[] PROGMEM = "h1 {margin:0;padding:20pt;font-size:22pt;color:#fff;background-color:#006ec0;display:block;text-transform:uppercase;}html, body {font-family:Arial;margin:0;padding:0;}p {text-align:justify;font-size:13pt;}p.lic, p.lic a {font-size:8pt;color:#999;}.des {margin-top:20px;font-size:13pt;color:#006ec0;}.s_active, .s_collapsible:hover {background-color:#006ec0;}.s_content {display:none;overflow:hidden;margin-bottom:20px;}.s_collapsible {background-color:#044e86;color:white;cursor:pointer;padding:18px;width:100%;border:none;text-align:left;outline:none;font-size:15px;margin-bottom:4px;}.subdes {font-size:12pt;color:#006ec0;margin-left:7px;}.subsubdes {font-size:12pt;color:#006ec0;margin:0 0 7px 12px;}.hide {display:none;}a:link, a:visited {text-decoration:none;font-size:13pt;color:#006ec0;}a:hover, a:focus {color:#f00;}a.erase {background-color:#006ec0;color:#fff;padding:7px;display:inline-block;margin-top:30px;float:right;}#content {padding:15px 15px 60px 15px;}#footer {position:fixed;bottom:0px;height:45px;background-color:#006ec0;width:100%;border-top:5px solid #fff;}#footer p, #footer a {color:#fff;padding:0 7px 0 7px;font-size:10pt !important;}div.content {background-color:#fff;padding-bottom:65px;overflow:auto;}input, select {padding:7px;font-size:13pt;}input.text, select {width:70%;box-sizing:border-box;margin-bottom:10px;border:1px solid #ccc;}input.sh {max-width:150px !important;margin-right:10px;}input.btn {background-color:#006ec0;color:#fff;border:0px;float:right;margin:10px 0 30px;text-transform:uppercase;}input.cb {margin-bottom:20px;}label {width:20%;display:inline-block;font-size:12pt;padding-right:10px;margin-left:15px;}.left {float:left;}.right {float:right;}div.ch-iv {width:100%;background-color:#32b004;display:inline-block;margin-bottom:15px;padding-bottom:20px;overflow:auto;}div.ch {width:220px;min-height:350px;background-color:#006ec0;display:inline-block;margin:0 10px 15px 10px;overflow:auto;padding-bottom:20px;}div.ch .value, div.ch .info, div.ch .head, div.ch-iv .value, div.ch-iv .info, div.ch-iv .head {color:#fff;display:block;width:100%;text-align:center;}.subgrp {float:left;width:220px;}div.ch .unit, div.ch-iv .unit {font-size:19px;margin-left:10px;}div.ch .value, div.ch-iv .value {margin-top:20px;font-size:24px;}div.ch .info, div.ch-iv .info {margin-top:3px;font-size:10px;}div.ch .head {background-color:#003c80;padding:10px 0 10px 0;}div.ch-iv .head {background-color:#1c6800;padding:10px 0 10px 0;}div.iv {max-width:960px;margin-bottom:40px;}div.ts {font-size:13px;background-color:#ddd;border-top:7px solid #999;padding:7px;}#note {margin:50px 10px 10px 10px;padding-top:10px;width:100%;border-top:1px solid #bbb;}@media(max-width:500px) {div.ch .unit, div.ch-iv .unit {font-size:18px;}div.ch {width:170px;min-height:100px }.subgrp {width:180px;}}"; +const char style_css[] PROGMEM = "h1 {margin:0;padding:20pt;font-size:22pt;color:#fff;background-color:#006ec0;display:block;text-transform:uppercase;}html, body {font-family:Arial;margin:0;padding:0;}p {text-align:justify;font-size:13pt;}p.lic, p.lic a {font-size:8pt;color:#999;}.des {margin-top:20px;font-size:13pt;color:#006ec0;}.s_active, .s_collapsible:hover {background-color:#006ec0;}.s_content {display:none;overflow:hidden;}.s_collapsible {background-color:#044e86;color:white;cursor:pointer;padding:18px;width:100%;border:none;text-align:left;outline:none;font-size:15px;margin-bottom:4px;}.subdes {font-size:12pt;color:#006ec0;margin-left:7px;}.subsubdes {font-size:12pt;color:#006ec0;margin:0 0 7px 12px;}.hide {display:none;}a:link, a:visited {text-decoration:none;font-size:13pt;color:#006ec0;}a:hover, a:focus {color:#f00;}a.erase {background-color:#006ec0;color:#fff;padding:7px;display:inline-block;margin-top:30px;}#content {padding:15px 15px 60px 15px;}#footer {position:fixed;bottom:0px;height:45px;background-color:#006ec0;width:100%;border-top:5px solid #fff;}#footer p, #footer a {color:#fff;padding:0 7px 0 7px;font-size:10pt !important;}div.content {background-color:#fff;padding-bottom:65px;overflow:auto;}input, select {padding:7px;font-size:13pt;}input.text, select {width:70%;box-sizing:border-box;margin-bottom:10px;border:1px solid #ccc;}input.sh {max-width:150px !important;margin-right:10px;}input.btn {background-color:#006ec0;color:#fff;border:0px;float:right;margin:10px 0 30px;text-transform:uppercase;}input.cb {margin-bottom:20px;}label {width:20%;display:inline-block;font-size:12pt;padding-right:10px;margin:10px 0px 0px 15px;vertical-align:top;}fieldset {margin-bottom:15px;}.left {float:left;}.right {float:right;}div.ch-iv {width:100%;background-color:#32b004;display:inline-block;margin-bottom:15px;padding-bottom:20px;overflow:auto;}div.ch {width:220px;min-height:350px;background-color:#006ec0;display:inline-block;margin:0 10px 15px 10px;overflow:auto;padding-bottom:20px;}div.ch .value, div.ch .info, div.ch .head, div.ch-iv .value, div.ch-iv .info, div.ch-iv .head {color:#fff;display:block;width:100%;text-align:center;}.subgrp {float:left;width:220px;}div.ch .unit, div.ch-iv .unit {font-size:19px;margin-left:10px;}div.ch .value, div.ch-iv .value {margin-top:20px;font-size:24px;}div.ch .info, div.ch-iv .info {margin-top:3px;font-size:10px;}div.ch .head {background-color:#003c80;padding:10px 0 10px 0;}div.ch-iv .head {background-color:#1c6800;padding:10px 0 10px 0;}div.iv {max-width:960px;margin-bottom:40px;}div.ts {font-size:13px;background-color:#ddd;border-top:7px solid #999;padding:7px;}div.modpwr, div.modname {width:70%;display:inline-block;}#note {margin:50px 10px 10px 10px;padding-top:10px;width:100%;border-top:1px solid #bbb;}@media(max-width:500px) {div.ch .unit, div.ch-iv .unit {font-size:18px;}div.ch {width:170px;min-height:100px }.subgrp {width:180px;}}"; #endif /*__STYLE_CSS_H__*/ diff --git a/tools/esp8266/html/index.html b/tools/esp8266/html/index.html index d72ae6f3..de381281 100644 --- a/tools/esp8266/html/index.html +++ b/tools/esp8266/html/index.html @@ -25,6 +25,16 @@ } } } + function getInverterInfo(data){ + var http = null; + http = new XMLHttpRequest(); + if(http != null) { + http.open("POST", "/api"); + http.setRequestHeader("Accept", "application/json"); + http.setRequestHeader("Content-Type", "application/json"); + http.send(data); + } + } diff --git a/tools/esp8266/html/setup.html b/tools/esp8266/html/setup.html index 3a970d5e..98a30680 100644 --- a/tools/esp8266/html/setup.html +++ b/tools/esp8266/html/setup.html @@ -55,9 +55,11 @@ ERASE SETTINGS (not WiFi)
-

Device Host Name

- - +
+ Device Host Name + + +
@@ -133,7 +135,6 @@
-

 

diff --git a/tools/esp8266/html/style.css b/tools/esp8266/html/style.css index 6de836e8..8ce9c570 100644 --- a/tools/esp8266/html/style.css +++ b/tools/esp8266/html/style.css @@ -37,7 +37,6 @@ p.lic, p.lic a { .s_content { display: none; overflow: hidden; - margin-bottom: 20px; } @@ -86,7 +85,6 @@ a.erase { padding: 7px; display: inline-block; margin-top: 30px; - float: right; } #content { @@ -149,7 +147,12 @@ label { display: inline-block; font-size: 12pt; padding-right: 10px; - margin-left: 15px; + margin: 10px 0px 0px 15px; + vertical-align: top; +} + +fieldset { + margin-bottom: 15px; } .left { @@ -179,7 +182,7 @@ div.ch { padding-bottom: 20px; } -div.ch .value, div.ch .info, div.ch .head, div.ch-iv .value, div.ch-iv .info, div.ch-iv .head { +div.ch .value, div.ch .info, div.ch .head, div.ch-iv .value, div.ch-iv .info, div.ch-iv .head { color: #fff; display: block; width: 100%; @@ -228,6 +231,11 @@ div.ts { padding: 7px; } +div.modpwr, div.modname { + width:70%; + display: inline-block; +} + #note { margin: 50px 10px 10px 10px; padding-top: 10px; diff --git a/tools/esp8266/include/dbg.h b/tools/esp8266/include/dbg.h index 1b11f959..8eb41f7c 100644 --- a/tools/esp8266/include/dbg.h +++ b/tools/esp8266/include/dbg.h @@ -5,6 +5,10 @@ #ifndef __DBG_H__ #define __DBG_H__ +#if defined(ESP32) && defined(F) + #undef F + #define F(sl) (sl) +#endif //----------------------------------------------------------------------------- // available levels diff --git a/tools/esp8266/mqtt.h b/tools/esp8266/mqtt.h index 789cec0c..74193afa 100644 --- a/tools/esp8266/mqtt.h +++ b/tools/esp8266/mqtt.h @@ -6,7 +6,16 @@ #ifndef __MQTT_H__ #define __MQTT_H__ -#include +#ifdef ESP8266 + #include +#elif defined(ESP32) + #include +#endif + +#if defined(ESP32) && defined(F) + #undef F + #define F(sl) (sl) +#endif #include #include "defines.h" @@ -54,7 +63,7 @@ class mqtt { bool isConnected(bool doRecon = false) { //DPRINTLN(DBG_VERBOSE, F("mqtt.h:isConnected")); - if(doRecon) + if(doRecon && !mClient->connected()) reconnect(); return mClient->connected(); } @@ -70,7 +79,12 @@ class mqtt { void reconnect(void) { DPRINTLN(DBG_DEBUG, F("mqtt.h:reconnect")); DPRINTLN(DBG_DEBUG, F("MQTT mClient->_state ") + String(mClient->state()) ); - DPRINTLN(DBG_DEBUG, F("WIFI mEspClient.status ") + String(mEspClient.status()) ); + + #ifdef ESP8266 + DPRINTLN(DBG_DEBUG, F("WIFI mEspClient.status ") + String(mEspClient.status()) ); + #endif + + boolean resub = false; if(!mClient->connected()) { if(strlen(mDevName) > 0) { // der Server und der Port müssen neu gesetzt werden, @@ -78,16 +92,18 @@ class mqtt { mClient->setServer(mCfg->broker, mCfg->port); mClient->setBufferSize(MQTT_MAX_PACKET_SIZE); if((strlen(mCfg->user) > 0) && (strlen(mCfg->pwd) > 0)) - mClient->connect(mDevName, mCfg->user, mCfg->pwd); + resub = mClient->connect(mDevName, mCfg->user, mCfg->pwd); else - mClient->connect(mDevName); + resub = mClient->connect(mDevName); } // ein Subscribe ist nur nach einem connect notwendig - char topic[MQTT_TOPIC_LEN + 13 ]; // "/devcontrol/#" --> + 6 byte - // ToDo: "/devcontrol/#" is hardcoded - snprintf(topic, MQTT_TOPIC_LEN + 13, "%s/devcontrol/#", mCfg->topic); - DPRINTLN(DBG_INFO, F("subscribe to ") + String(topic)); - mClient->subscribe(topic); // subscribe to mTopic + "/devcontrol/#" + if(resub) { + char topic[MQTT_TOPIC_LEN + 13 ]; // "/devcontrol/#" --> + 6 byte + // ToDo: "/devcontrol/#" is hardcoded + snprintf(topic, MQTT_TOPIC_LEN + 13, "%s/devcontrol/#", mCfg->topic); + DPRINTLN(DBG_INFO, F("subscribe to ") + String(topic)); + mClient->subscribe(topic); // subscribe to mTopic + "/devcontrol/#" + } } } diff --git a/tools/esp8266/platformio.ini b/tools/esp8266/platformio.ini index 10d2a679..ee0ad242 100644 --- a/tools/esp8266/platformio.ini +++ b/tools/esp8266/platformio.ini @@ -12,10 +12,7 @@ src_dir = . [env] -platform = espressif8266 framework = arduino -board = esp12e -board_build.f_cpu = 80000000L ; ;;;;; Possible Debug options ;;;;;; ; https://docs.platformio.org/en/latest/platforms/espressif8266.html#debug-level @@ -46,18 +43,41 @@ lib_deps = ;esp8266/Ticker@^1.0 [env:esp8266-release] +platform = espressif8266 +board = esp12e +board_build.f_cpu = 80000000L build_flags = -D RELEASE monitor_filters = ;default ; Remove typical terminal control codes from input 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:esp8266-debug] +platform = espressif8266 +board = esp12e +board_build.f_cpu = 80000000L build_flags = -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 = ;default ; Remove typical terminal control codes from input 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-release] +platform = espressif32 +board = lolin_d32 +build_flags = -D RELEASE +monitor_filters = + ;default ; Remove typical terminal control codes from input + 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-debug] +platform = espressif32 +board = lolin_d32 +build_flags = -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 = + ;default ; Remove typical terminal control codes from input + 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 \ No newline at end of file diff --git a/tools/esp8266/scripts/getVersion.py b/tools/esp8266/scripts/getVersion.py index 104e8e4c..9907eb55 100644 --- a/tools/esp8266/scripts/getVersion.py +++ b/tools/esp8266/scripts/getVersion.py @@ -9,23 +9,22 @@ def readVersion(path, infile): today = date.today() search = ["_MAJOR", "_MINOR", "_PATCH"] version = today.strftime("%y%m%d") + "_ahoy_" + versionnumber = "ahoy_v" for line in lines: if(line.find("VERSION_") != -1): for s in search: p = line.find(s) if(p != -1): version += line[p+13:].rstrip() + "." + versionnumber += line[p+13:].rstrip() + "." os.mkdir(path + ".pio/build/out/") - - versionout = version[:-1] + "_esp8266_release.bin" + sha = os.getenv("SHA",default="sha") + versionout = version[:-1] + "_esp8266_" + sha + ".bin" src = path + ".pio/build/esp8266-release/firmware.bin" dst = path + ".pio/build/out/" + versionout os.rename(src, dst) + print("::set-output name=name::" + versionnumber[:-1] ) + - versionout = version[:-1] + "_esp8266_debug.bin" - src = path + ".pio/build/esp8266-debug/firmware.bin" - dst = path + ".pio/build/out/" + versionout - os.rename(src, dst) - readVersion("../", "defines.h") diff --git a/tools/esp8266/web.cpp b/tools/esp8266/web.cpp index 77339653..9e4e9802 100644 --- a/tools/esp8266/web.cpp +++ b/tools/esp8266/web.cpp @@ -3,6 +3,11 @@ // Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/ //----------------------------------------------------------------------------- +#if defined(ESP32) && defined(F) + #undef F + #define F(sl) (sl) +#endif + #include "web.h" #include "html/h/index_html.h" @@ -17,15 +22,22 @@ web::web(app *main, sysConfig_t *sysCfg, config_t *config, char version[]) { mSysCfg = sysCfg; mConfig = config; mVersion = version; - mWeb = new ESP8266WebServer(80); - mUpdater = new ESP8266HTTPUpdateServer(); + #ifdef ESP8266 + mWeb = new ESP8266WebServer(80); + mUpdater = new ESP8266HTTPUpdateServer(); + #elif defined(ESP32) + mWeb = new WebServer(80); + mUpdater = new HTTPUpdateServer(); + #endif mUpdater->setup(mWeb); } //----------------------------------------------------------------------------- void web::setup(void) { + DPRINTLN(DBG_VERBOSE, F("app::setup-begin")); mWeb->begin(); + DPRINTLN(DBG_VERBOSE, F("app::setup-on")); mWeb->on("/", std::bind(&web::showIndex, this)); mWeb->on("/style.css", std::bind(&web::showCss, this)); mWeb->on("/favicon.ico", std::bind(&web::showFavicon, this)); @@ -205,21 +217,22 @@ void web::showSetup(void) { // UGLY! But I do not know it a better way --// inv += F(""); + inv += F("ModPwr\">Max Module Power (Wp)
"); for(uint8_t j = 0; j < 4; j++) { inv += F("chMaxPwr[j]); inv += F("\"/ maxlength=\"4\">"); } - inv += F("
"); + inv += F("

"); for(uint8_t j = 0; j < 4; j++) { inv += F("chName[j]); inv += F("\"/ maxlength=\"") + String(MAX_NAME_LENGTH) + "\">"; } + inv += F("
"); } html.replace(F("{INVERTERS}"), String(inv)); @@ -329,6 +342,7 @@ void web::showSave(void) { iv->chMaxPwr[j] = mWeb->arg("inv" + String(i) + "ModPwr" + String(j)).toInt() & 0xffff; mWeb->arg("inv" + String(i) + "ModName" + String(j)).toCharArray(iv->chName[j], MAX_NAME_LENGTH); } + iv->initialized = true; } if(mWeb->arg("invInterval") != "") mConfig->sendInterval = mWeb->arg("invInterval").toInt(); @@ -429,17 +443,19 @@ void web::showWebApi(void) deserializeJson(response, mWeb->arg("plain")); // ToDo: error handling for payload uint8_t iv_id = response["inverter"]; + uint8_t cmd = response["cmd"]; Inverter<> *iv = mMain->mSys->getInverterByPos(iv_id); if (NULL != iv) { if (response["tx_request"] == (uint8_t)TX_REQ_INFO) { - mMain->mSys->InfoCmd = response["cmd"]; - mMain->resetPayload(iv); // start request from new - // process payload from web request corresponding to the cmd - if (mMain->mSys->InfoCmd == AlarmData) + // if the AlarmData is requested set the Alarm Index to the requested one + if (cmd == AlarmData){ iv->alarmMesIndex = response["payload"]; - DPRINTLN(DBG_INFO, F("Will make tx-request 0x15 with subcmd ") + String(mMain->mSys->InfoCmd) + F(" and payload ") + String(response["payload"])); + } + DPRINTLN(DBG_INFO, F("Will make tx-request 0x15 with subcmd ") + String(cmd) + F(" and payload ") + String(response["payload"])); + // process payload from web request corresponding to the cmd + iv->enqueCommand(cmd); } diff --git a/tools/esp8266/web.h b/tools/esp8266/web.h index 0199063d..ad9aa7c6 100644 --- a/tools/esp8266/web.h +++ b/tools/esp8266/web.h @@ -7,8 +7,13 @@ #define __WEB_H__ #include "dbg.h" -#include -#include +#ifdef ESP8266 + #include + #include +#elif defined(ESP32) + #include + #include +#endif #include "app.h" @@ -40,8 +45,13 @@ class web { void showWebApi(void); private: - ESP8266WebServer *mWeb; - ESP8266HTTPUpdateServer *mUpdater; + #ifdef ESP8266 + ESP8266WebServer *mWeb; + ESP8266HTTPUpdateServer *mUpdater; + #elif defined(ESP32) + WebServer *mWeb; + HTTPUpdateServer *mUpdater; + #endif config_t *mConfig; sysConfig_t *mSysCfg;