From 70972ccf6a5af3507313fcc199331d0ceaee4a03 Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 15 Jun 2019 15:53:06 +0200 Subject: [PATCH 01/89] preparing for next 1.9.0dev --- CHANGELOG.md | 12 +++++++++--- src/version.h | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 718620ec4..f8aed6c99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,13 +5,19 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.9.0dev] 2019-06- + +### Added + +### Fixed + ## [1.8.0] 2019-06-15 ### Added -- Support for HeatPump (e.g. the Nefit Enviline) +- HeatPump support (e.g. the Nefit Enviline) - new device: Buderus MM50 Mixer -- new devices: Junkers FW100 and ISM1 (thanks @Vuego123) +- new devices: Junkers FW100 and ISM1 (thanks Vuego123) - Improved Tx logic to support EMS, EMS+ and Heatronics (thanks kwertie01, susisstrolch, philrich) - MQTT heartbeat @@ -376,4 +382,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.1.0] 2018-05-14 -- Initial development version \ No newline at end of file +- Initial development version diff --git a/src/version.h b/src/version.h index fa69ef04e..1c6b9dc14 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.8.0" +#define APP_VERSION "1.9.0b0" #define APP_HOSTNAME "ems-esp" From 1872a0d57a78fc324f09890127eaf46fbe590572 Mon Sep 17 00:00:00 2001 From: Vuego123 Date: Sun, 16 Jun 2019 15:56:18 +0200 Subject: [PATCH 02/89] Added extra values for ISM1 Add measures for energy production (in Wh) and solar pomp (on/off) --- src/ems.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/ems.cpp b/src/ems.cpp index 33bbb2adb..3e10e4d0b 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -1284,10 +1284,12 @@ void _process_RCPLUSStatusMode(_EMS_RxTelegram * EMS_RxTelegram) { * FR10 Junkers - type x6F01 */ void _process_JunkersStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { + if (EMS_RxTelegram->offset == 0) { // e.g. for FR10: 90 00 FF 00 00 6F 03 01 00 BE 00 BF // e.g. for FW100: 90 00 FF 00 00 6F 03 02 00 D7 00 DA F3 34 00 C4 EMS_Thermostat.curr_roomTemp = _toShort(EMS_OFFSET_JunkersStatusMessage_curr); // value is * 10 EMS_Thermostat.setpoint_roomTemp = _toShort(EMS_OFFSET_JunkersStatusMessage_setpoint); // value is * 10 + } } /** @@ -1450,10 +1452,21 @@ void _process_HPMonitor2(_EMS_RxTelegram * EMS_RxTelegram) { * Junkers ISM1 Solar Module - type 0x0003 EMS+ for energy readings */ void _process_ISM1StatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { - // e.g. B0 00 FF 00 00 03 32 00 00 00 00 13 00 D6 00 00 00 FB D0 F0 + + if (EMS_RxTelegram->offset == 0) { + // e.g. B0 00 FF 00 00 03 32 00 00 00 00 13 00 D6 00 00 00 FB D0 F0 EMS_Other.SMcollectorTemp = _toShort(4); // Collector Temperature EMS_Other.SMbottomTemp = _toShort(6); // Temperature Bottom of Solar Boiler + EMS_Other.SMEnergyLastHour = _toShort(2) * 10; // Solar Energy produced in last hour + EMS_Other.SMpump = _bitRead(8,0); // Solar pump on (1) or off (0) EMS_Other.SM = true; + } + + if (EMS_RxTelegram->offset == 4) { + // e.g. B0 00 FF 04 00 03 02 E5 + EMS_Other.SMcollectorTemp = _toShort(0); // Collector Temperature + EMS_Other.SM = true; + } } /** From 07e1f74da25042357635206fba2aaf28aa115a64 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 16 Jun 2019 16:32:20 +0200 Subject: [PATCH 03/89] add esp8266 dev core for testing 2.5.3 --- platformio.ini-example | 1 + 1 file changed, 1 insertion(+) diff --git a/platformio.ini-example b/platformio.ini-example index 027670d7b..90b3fda9f 100644 --- a/platformio.ini-example +++ b/platformio.ini-example @@ -18,6 +18,7 @@ arduino_core_2_4_2 = espressif8266@1.8.0 arduino_core_2_5_0 = espressif8266@2.0.4 arduino_core_2_5_1 = espressif8266@2.1.1 arduino_core_2_5_2 = espressif8266@2.2.1 +arduino_core_dev = https://github.com/platformio/platform-espressif8266.git arduino_core_latest = espressif8266 [env] From f2810a5f7f2a3a6d38a9706b87de8519e2711669 Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 17 Jun 2019 21:29:18 +0200 Subject: [PATCH 04/89] 1.8.1 --- CHANGELOG.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8aed6c99..f777ff531 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,12 +5,18 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [1.9.0dev] 2019-06- +## [1.8.1dev] 2019-06-17 ### Added +- Added back -DCRASH in Debug build target for capturing any ESP8266 stack dumps during crashes + ### Fixed +### Changed + +- `publish_wait` renamed to `publish_time`, a value of 0 means no sending to MQTT + ## [1.8.0] 2019-06-15 ### Added From 196be7f886a01ae58d7755bc3a5b66087617798e Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 17 Jun 2019 21:29:33 +0200 Subject: [PATCH 05/89] added dev arduino core --- platformio.ini-example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini-example b/platformio.ini-example index 90b3fda9f..4b893b11a 100644 --- a/platformio.ini-example +++ b/platformio.ini-example @@ -8,7 +8,7 @@ default_envs = debug [common] -debug_flags = -Wall -Wextra -Werror -Wno-missing-field-initializers -Wno-unused-parameter -Wno-unused-variable -DTESTS +debug_flags = -Wall -Wextra -Werror -Wno-missing-field-initializers -Wno-unused-parameter -Wno-unused-variable -DTESTS -DCRASH general_flags = -g -w -DNO_GLOBAL_EEPROM arduino_core_2_3_0 = espressif8266@1.5.0 From 4ccec0a6f3f41817d061e122f16765303f385549 Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 17 Jun 2019 21:29:49 +0200 Subject: [PATCH 06/89] 1.8.1 --- src/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h b/src/version.h index 1c6b9dc14..725125dc1 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.9.0b0" +#define APP_VERSION "1.8.1b1" #define APP_HOSTNAME "ems-esp" From 47f2636a538c916c48d64628ff57854cd8bece56 Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 17 Jun 2019 21:30:07 +0200 Subject: [PATCH 07/89] publish_wait to publish_time --- lib/MyESP/MyESP.cpp | 171 ++++++++++++++++++++++++++++++++++++++------ lib/MyESP/MyESP.h | 56 +++++++-------- src/ems-esp.cpp | 41 +++++------ 3 files changed, 195 insertions(+), 73 deletions(-) diff --git a/lib/MyESP/MyESP.cpp b/lib/MyESP/MyESP.cpp index 48d7d4422..f8e278cb8 100644 --- a/lib/MyESP/MyESP.cpp +++ b/lib/MyESP/MyESP.cpp @@ -8,7 +8,9 @@ #include "MyESP.h" +#ifdef CRASH EEPROM_Rotate EEPROMr; +#endif union system_rtcmem_t { struct { @@ -144,7 +146,7 @@ bool MyESP::getHeartbeat() { } // init heap ram -uint32_t MyESP::getInitialFreeHeap() { +uint32_t MyESP::_getInitialFreeHeap() { static uint32_t _heap = 0; if (0 == _heap) { @@ -154,8 +156,10 @@ uint32_t MyESP::getInitialFreeHeap() { return _heap; } -uint32_t MyESP::getUsedHeap() { - return getInitialFreeHeap() - ESP.getFreeHeap(); +// used heap mem +// note calls to getFreeHeap sometimes causes some ESPs to crash +uint32_t MyESP::_getUsedHeap() { + return _getInitialFreeHeap() - ESP.getFreeHeap(); } // called when WiFi is connected, and used to start OTA, MQTT @@ -198,7 +202,7 @@ void MyESP::_wifiCallback(justwifi_messages_t code, char * parameter) { _wifi_callback(); } - jw.enableAPFallback(false); // Disable AP mode after initial connect was succesfull. Thanks @JewelZB + jw.enableAPFallback(false); // Disable AP mode after initial connect was successful } if (code == MESSAGE_ACCESSPOINT_CREATED) { @@ -237,6 +241,66 @@ void MyESP::_wifiCallback(justwifi_messages_t code, char * parameter) { myDebug_P(PSTR("[WIFI] Disconnected")); _wifi_connected = false; } + + if (code == MESSAGE_SCANNING) { + myDebug_P(PSTR("[WIFI] Scanning\n")); + } + + if (code == MESSAGE_SCAN_FAILED) { + myDebug_P(PSTR("[WIFI] Scan failed\n")); + } + + if (code == MESSAGE_NO_NETWORKS) { + myDebug_P(PSTR("[WIFI] No networks found\n")); + } + + if (code == MESSAGE_NO_KNOWN_NETWORKS) { + myDebug_P(PSTR("[WIFI] No known networks found\n")); + } + + if (code == MESSAGE_FOUND_NETWORK) { + myDebug_P(PSTR("[WIFI] %s\n"), parameter); + } + + if (code == MESSAGE_CONNECT_WAITING) { + // too much noise + } + + if (code == MESSAGE_ACCESSPOINT_CREATING) { + myDebug_P(PSTR("[WIFI] Creating access point\n")); + } + + if (code == MESSAGE_ACCESSPOINT_FAILED) { + myDebug_P(PSTR("[WIFI] Could not create access point\n")); + } + + if (code == MESSAGE_ACCESSPOINT_DESTROYED) { + myDebug_P(PSTR("[WIFI] Access point destroyed\n")); + } + + if (code == MESSAGE_WPS_START) { + myDebug_P(PSTR("[WIFI] WPS started\n")); + } + + if (code == MESSAGE_WPS_SUCCESS) { + myDebug_P(PSTR("[WIFI] WPS succeeded!\n")); + } + + if (code == MESSAGE_WPS_ERROR) { + myDebug_P(PSTR("[WIFI] WPS failed\n")); + } + + if (code == MESSAGE_SMARTCONFIG_START) { + myDebug_P(PSTR("[WIFI] Smart Config started\n")); + } + + if (code == MESSAGE_SMARTCONFIG_SUCCESS) { + myDebug_P(PSTR("[WIFI] Smart Config succeeded!\n")); + } + + if (code == MESSAGE_SMARTCONFIG_ERROR) { + myDebug_P(PSTR("[WIFI] Smart Config failed\n")); + } } // return true if in WiFi AP mode @@ -395,6 +459,7 @@ void MyESP::setOTA(ota_callback_f OTACallback_pre, ota_callback_f OTACallback_po void MyESP::_OTACallback() { myDebug_P(PSTR("[OTA] Start")); +#ifdef CRASH // If we are not specifically reserving the sectors we are using as // EEPROM in the memory layout then any OTA upgrade will overwrite // all but the last one. @@ -407,6 +472,7 @@ void MyESP::_OTACallback() { // See onError callback below. EEPROMr.rotate(false); EEPROMr.commit(); +#endif if (_ota_pre_callback) { (_ota_pre_callback)(); // call custom function @@ -449,8 +515,10 @@ void MyESP::_ota_setup() { else if (error == OTA_END_ERROR) myDebug_P(PSTR("[OTA] End Failed")); - // There's been an error, reenable rotation +#ifdef CRASH + // There's been an error, reenable eeprom rotation EEPROMr.rotate(true); +#endif }); } @@ -464,8 +532,10 @@ void MyESP::setBoottime(const char * boottime) { // eeprom void MyESP::_eeprom_setup() { +#ifdef CRASH EEPROMr.size(4); EEPROMr.begin(SPI_FLASH_SEC_SIZE); +#endif } // Set callback of sketch function to process project messages @@ -480,6 +550,7 @@ void MyESP::_telnetConnected() { myDebug_P(PSTR("[TELNET] Telnet connection established")); _consoleShowHelp(); // Show the initial message +#ifdef CRASH // show crash dump if just restarted after a fatal crash uint32_t crash_time; EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_CRASH_TIME, crash_time); @@ -492,6 +563,7 @@ void MyESP::_telnetConnected() { EEPROMr.commit(); */ } +#endif // call callback if (_telnet_callback) { @@ -539,7 +611,9 @@ void MyESP::_consoleShowHelp() { myDebug_P(PSTR("* Commands:")); myDebug_P(PSTR("* ?=help, CTRL-D/quit=exit telnet session")); myDebug_P(PSTR("* set, system, reboot")); - myDebug_P(PSTR("* crash ")); +#ifdef CRASH + myDebug_P(PSTR("* crash ")); +#endif // print custom commands if available. Taken from progmem if (_telnetcommand_callback) { @@ -842,19 +916,23 @@ void MyESP::_telnetCommand(char * commandLine) { return; } - +#ifdef CRASH // crash command - if ((strcmp(ptrToCommandName, "crash") == 0) && (wc == 2)) { + if ((strcmp(ptrToCommandName, "crash") == 0) && (wc >= 2)) { char * cmd = _telnet_readWord(false); if (strcmp(cmd, "dump") == 0) { crashDump(); } else if (strcmp(cmd, "clear") == 0) { crashClear(); + } else if ((strcmp(cmd, "test") == 0) && (wc == 3)) { + char * value = _telnet_readWord(false); + crashTest(atoi(value)); } else { - myDebug_P(PSTR("Error. Usage: crash ")); + myDebug_P(PSTR("Error. Usage: crash ")); } return; // don't call custom command line callback } +#endif // call callback function (_telnetcommand_callback)(wc, commandLine); @@ -960,6 +1038,7 @@ void MyESP::_setCustomResetReason(uint8_t reason) { _setSystemResetReason(reason); } +// returns false if not set and needs to be intialized bool MyESP::_rtcmemStatus() { bool readable; @@ -978,12 +1057,12 @@ bool MyESP::_rtcmemStatus() { return readable; } -bool MyESP::rtcmemStatus() { +bool MyESP::_getRtcmemStatus() { return _rtcmem_status; } -unsigned char MyESP::_getCustomResetReason() { - static unsigned char status = 255; +uint8_t MyESP::_getCustomResetReason() { + static uint8_t status = 255; if (status == 255) { if (_rtcmemStatus()) status = _getSystemResetReason(); @@ -995,7 +1074,7 @@ unsigned char MyESP::_getCustomResetReason() { return status; } -void MyESP::_deferredReset(unsigned long delaytime, unsigned char reason) { +void MyESP::_deferredReset(unsigned long delaytime, uint8_t reason) { delay(delaytime); _setCustomResetReason(reason); } @@ -1010,7 +1089,7 @@ void MyESP::_setSystemCheck(bool stable) { value = 0; // system is ok // myDebug_P(PSTR("[SYSTEM] System OK\n")); } else { - if (!rtcmemStatus()) { + if (!_getRtcmemStatus()) { _setSystemStabilityCounter(1); return; } @@ -1083,6 +1162,7 @@ void MyESP::showSystemStats() { myDebug_P(PSTR(" [WIFI] WiFi MAC: %s"), WiFi.macAddress().c_str()); +#ifdef CRASH char output_str[80] = {0}; char buffer[16] = {0}; myDebug_P(PSTR(" [EEPROM] EEPROM size: %u"), EEPROMr.reserved() * SPI_FLASH_SEC_SIZE); @@ -1094,6 +1174,7 @@ void MyESP::showSystemStats() { strlcat(output_str, " ", sizeof(output_str)); } myDebug(output_str); +#endif #ifdef ARDUINO_BOARD myDebug_P(PSTR(" [SYSTEM] Board: %s"), ARDUINO_BOARD); @@ -1107,7 +1188,6 @@ void MyESP::showSystemStats() { myDebug_P(PSTR(" [SYSTEM] Core version: %s"), ESP.getCoreVersion().c_str()); myDebug_P(PSTR(" [SYSTEM] Boot version: %d"), ESP.getBootVersion()); myDebug_P(PSTR(" [SYSTEM] Boot mode: %d"), ESP.getBootMode()); - //myDebug_P(PSTR("[SYSTEM] Firmware MD5: %s"), (char *)ESP.getSketchMD5().c_str()); unsigned char reason = _getCustomResetReason(); if (reason > 0) { char buffer[32]; @@ -1140,7 +1220,7 @@ void MyESP::showSystemStats() { myDebug_P(PSTR(" [MEM] Max OTA size: %d"), (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000); myDebug_P(PSTR(" [MEM] OTA Reserved: %d"), 4 * SPI_FLASH_SEC_SIZE); - uint32_t total_memory = getInitialFreeHeap(); + uint32_t total_memory = _getInitialFreeHeap(); uint32_t free_memory = ESP.getFreeHeap(); myDebug(" [MEM] Free Heap: %d bytes initially | %d bytes used (%2u%%) | %d bytes free (%2u%%)", @@ -1166,7 +1246,7 @@ void MyESP::_heartbeatCheck(bool force = false) { return; } - uint32_t total_memory = getInitialFreeHeap(); + uint32_t total_memory = _getInitialFreeHeap(); uint32_t free_memory = ESP.getFreeHeap(); uint8_t mem_available = 100 * free_memory / total_memory; // as a % @@ -1531,7 +1611,6 @@ bool MyESP::fs_saveConfig() { return false; } - // Serialize JSON to file if (serializeJson(json, configFile) == 0) { myDebug_P(PSTR("[FS] Failed to write config file")); @@ -1630,6 +1709,7 @@ int MyESP::getWifiQuality() { return 2 * (dBm + 100); } +#ifdef CRASH /** * Save crash information in EEPROM * This function is called automatically if ESP8266 suffers an exception @@ -1779,15 +1859,66 @@ void MyESP::crashDump() { myDebug_P(PSTR("\nTo clean this dump use the command: %scrash clear%s\n"), COLOR_BOLD_ON, COLOR_BOLD_OFF); } +void MyESP::crashTest(uint8_t t) { + if (t == 1) { + myDebug_P(PSTR("[CRASH] Attempting to divide by zero ...")); + int result, zero; + zero = 0; + result = 1 / zero; + Serial.printf("Result = %d", result); + } + + if (t == 2) { + myDebug_P(PSTR("[CRASH] Attempting to read through a pointer to no object ...")); + int * nullPointer; + nullPointer = NULL; + // null pointer dereference - read + // attempt to read a value through a null pointer + Serial.println(*nullPointer); + } + + if (t == 3) { + myDebug_P(PSTR("[CRASH] Crashing with hardware WDT (%ld ms) ...\n"), millis()); + ESP.wdtDisable(); + while (true) { + // stay in an infinite loop doing nothing + // this way other process can not be executed + // + // Note: + // Hardware wdt kicks in if software wdt is unable to perfrom + // Nothing will be saved in EEPROM for the hardware wdt + } + } + + if (t == 4) { + myDebug_P(PSTR("[CRASH] Crashing with software WDT (%ld ms) ...\n"), millis()); + while (true) { + // stay in an infinite loop doing nothing + // this way other process can not be executed + } + } +} + +#else +void MyESP::crashTest(uint8_t t) { +} +void MyESP::crashClear() { +} +void MyESP::crashDump() { +} +void MyESP::crashInfo() { +} +#endif + // setup MyESP void MyESP::begin(const char * app_hostname, const char * app_name, const char * app_version) { _app_hostname = strdup(app_hostname); _app_name = strdup(app_name); _app_version = strdup(app_version); - getInitialFreeHeap(); // get initial free mem + _getInitialFreeHeap(); // get initial free mem - _rtcmemSetup(); + _rtcmemSetup(); // rtc internal mem setup _telnet_setup(); // Telnet setup, called first to set Serial _eeprom_setup(); // set up EEPROM for storing crash data, if compiled with -DCRASH _fs_setup(); // SPIFFS setup, do this first to get values diff --git a/lib/MyESP/MyESP.h b/lib/MyESP/MyESP.h index 733d1e0c5..79c13922c 100644 --- a/lib/MyESP/MyESP.h +++ b/lib/MyESP/MyESP.h @@ -9,7 +9,7 @@ #ifndef MyEMS_h #define MyEMS_h -#define MYESP_VERSION "1.1.16" +#define MYESP_VERSION "1.1.17" #include #include @@ -231,17 +231,15 @@ class MyESP { void crashInfo(); // general - void end(); - void loop(); - void begin(const char * app_hostname, const char * app_name, const char * app_version); - void setBoottime(const char * boottime); - void resetESP(); - int getWifiQuality(); - void showSystemStats(); - bool getHeartbeat(); - - // rtcmem and reset reason - bool rtcmemStatus(); + void end(); + void loop(); + void begin(const char * app_hostname, const char * app_name, const char * app_version); + void setBoottime(const char * boottime); + void resetESP(); + int getWifiQuality(); + void showSystemStats(); + bool getHeartbeat(); + uint32_t getSystemLoadAverage(); uint32_t getSystemResetReason(); private: @@ -328,33 +326,29 @@ class MyESP { String _buildTime(); // reset reason and rtcmem - bool _rtcmemStatus(); - void _rtcmemInit(); - void _rtcmemSetup(); - - void _deferredReset(unsigned long delay, uint8_t reason); - + bool _rtcmemStatus(); + void _rtcmemInit(); + void _rtcmemSetup(); + void _deferredReset(unsigned long delay, uint8_t reason); uint8_t _getSystemStabilityCounter(); void _setSystemStabilityCounter(uint8_t counter); - - uint8_t _getSystemResetReason(); void _setSystemResetReason(uint8_t reason); + uint8_t _getCustomResetReason(); + void _setCustomResetReason(uint8_t reason); + bool _systemStable; - unsigned char _getCustomResetReason(); - void _setCustomResetReason(unsigned char reason); - - bool _systemStable; - - bool getSystemCheck(); - void _systemCheckLoop(); - void _setSystemCheck(bool stable); + // rtcmem and reset reason + bool _getRtcmemStatus(); + uint8_t _getSystemResetReason(); + bool getSystemCheck(); + void _systemCheckLoop(); + void _setSystemCheck(bool stable); // load average (0..100) and heap ram - uint32_t getSystemLoadAverage(); void _calculateLoad(); uint32_t _load_average; - uint32_t getInitialFreeHeap(); - uint32_t getUsedHeap(); + uint32_t _getInitialFreeHeap(); + uint32_t _getUsedHeap(); // heartbeat void _heartbeatCheck(bool force); diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index 097f9de63..6ed516e39 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -37,7 +37,7 @@ DS18 ds18; #define DEFAULT_HEATINGCIRCUIT 1 // default to HC1 for thermostats that support multiple heating circuits like the RC35 // timers, all values are in seconds -#define DEFAULT_PUBLISHWAIT 120 // every 2 minutes publish MQTT values, including Dallas sensors +#define DEFAULT_PUBLISHTIME 120 // every 2 minutes publish MQTT values, including Dallas sensors Ticker publishValuesTimer; Ticker publishSensorValuesTimer; @@ -78,7 +78,7 @@ typedef struct { bool shower_alert; // true if we want the alert of cold water bool led; // LED on/off bool listen_mode; // stop automatic Tx on/off - uint16_t publish_wait; // frequency of MQTT publish in seconds + uint16_t publish_time; // frequency of MQTT publish in seconds uint8_t led_gpio; // pin for LED uint8_t dallas_gpio; // pin for attaching external dallas temperature sensors bool dallas_parasite; // on/off is using parasite @@ -104,7 +104,7 @@ command_t project_cmds[] = { {true, "listen_mode ", "when on all automatic Tx is disabled"}, {true, "shower_timer ", "notify via MQTT all shower durations"}, {true, "shower_alert ", "send a warning of cold water after shower time is exceeded"}, - {true, "publish_wait ", "set frequency for publishing to MQTT"}, + {true, "publish_time ", "set frequency for publishing to MQTT (0=off)"}, {true, "heating_circuit <1 | 2>", "set the thermostat HC to work with if using multiple heating circuits"}, {false, "info", "show data captured on the EMS bus"}, @@ -481,13 +481,11 @@ void showInfo() { // Temperatures are *100 _renderShortValue("Set room temperature", "C", EMS_Thermostat.setpoint_roomTemp, 10); // *100 _renderShortValue("Current room temperature", "C", EMS_Thermostat.curr_roomTemp, 10); // *100 - } - else if ((ems_getThermostatModel() == EMS_MODEL_FR10) || (ems_getThermostatModel() == EMS_MODEL_FW100)) { + } else if ((ems_getThermostatModel() == EMS_MODEL_FR10) || (ems_getThermostatModel() == EMS_MODEL_FW100)) { // Temperatures are *10 _renderShortValue("Set room temperature", "C", EMS_Thermostat.setpoint_roomTemp, 1); // *10 _renderShortValue("Current room temperature", "C", EMS_Thermostat.curr_roomTemp, 1); // *10 - } - else { + } else { // because we store in 2 bytes short, when converting to a single byte we'll loose the negative value if its unset if (EMS_Thermostat.setpoint_roomTemp <= 0) { EMS_Thermostat.setpoint_roomTemp = EMS_VALUE_INT_NOTSET; @@ -888,7 +886,7 @@ void do_publishSensorValues() { // call PublishValues without forcing, so using CRC to see if we really need to publish void do_publishValues() { // don't publish if we're not connected to the EMS bus - if ((ems_getBusConnected()) && (!myESP.getUseSerial()) && myESP.isMQTTConnected()) { + if ((ems_getBusConnected()) && (!myESP.getUseSerial()) && myESP.isMQTTConnected() && EMSESP_Status.publish_time != 0) { publishValues(true); // force publish } } @@ -935,8 +933,8 @@ void do_regularUpdates() { // stop devices scan and restart all other timers void stopDeviceScan() { - publishValuesTimer.attach(EMSESP_Status.publish_wait, do_publishValues); // post MQTT EMS values - publishSensorValuesTimer.attach(EMSESP_Status.publish_wait, do_publishSensorValues); // post MQTT sensor values + publishValuesTimer.attach(EMSESP_Status.publish_time, do_publishValues); // post MQTT EMS values + publishSensorValuesTimer.attach(EMSESP_Status.publish_time, do_publishSensorValues); // post MQTT sensor values regularUpdatesTimer.attach(REGULARUPDATES_TIME, do_regularUpdates); // regular reads from the EMS systemCheckTimer.attach(SYSTEMCHECK_TIME, do_systemCheck); // check if Boiler is online scanThermostat_count = 0; @@ -1056,9 +1054,9 @@ bool FSCallback(MYESP_FSACTION action, const JsonObject json) { // shower_alert EMSESP_Status.shower_alert = json["shower_alert"]; - // publish_wait - if (!(EMSESP_Status.publish_wait = json["publish_wait"])) { - EMSESP_Status.publish_wait = DEFAULT_PUBLISHWAIT; // default value + // publish_time + if (!(EMSESP_Status.publish_time = json["publish_time"])) { + EMSESP_Status.publish_time = DEFAULT_PUBLISHTIME; // default value } // heating_circuit @@ -1080,7 +1078,7 @@ bool FSCallback(MYESP_FSACTION action, const JsonObject json) { json["listen_mode"] = EMSESP_Status.listen_mode; json["shower_timer"] = EMSESP_Status.shower_timer; json["shower_alert"] = EMSESP_Status.shower_alert; - json["publish_wait"] = EMSESP_Status.publish_wait; + json["publish_time"] = EMSESP_Status.publish_time; json["heating_circuit"] = EMSESP_Status.heating_circuit; return true; @@ -1194,9 +1192,9 @@ bool SettingsCallback(MYESP_FSACTION action, uint8_t wc, const char * setting, c } } - // publish_wait - if ((strcmp(setting, "publish_wait") == 0) && (wc == 2)) { - EMSESP_Status.publish_wait = atoi(value); + // publish_time + if ((strcmp(setting, "publish_time") == 0) && (wc == 2)) { + EMSESP_Status.publish_time = atoi(value); ok = true; } @@ -1211,7 +1209,6 @@ bool SettingsCallback(MYESP_FSACTION action, uint8_t wc, const char * setting, c myDebug_P(PSTR("Error. Usage: set heating_circuit <1 | 2>")); } } - } if (action == MYESP_FSACTION_LIST) { @@ -1237,7 +1234,7 @@ bool SettingsCallback(MYESP_FSACTION action, uint8_t wc, const char * setting, c myDebug_P(PSTR(" listen_mode=%s"), EMSESP_Status.listen_mode ? "on" : "off"); myDebug_P(PSTR(" shower_timer=%s"), EMSESP_Status.shower_timer ? "on" : "off"); myDebug_P(PSTR(" shower_alert=%s"), EMSESP_Status.shower_alert ? "on" : "off"); - myDebug_P(PSTR(" publish_wait=%d"), EMSESP_Status.publish_wait); + myDebug_P(PSTR(" publish_time=%d"), EMSESP_Status.publish_time); } return ok; @@ -1583,7 +1580,7 @@ void initEMSESP() { EMSESP_Status.shower_alert = false; EMSESP_Status.led = true; // LED is on by default EMSESP_Status.listen_mode = false; - EMSESP_Status.publish_wait = DEFAULT_PUBLISHWAIT; + EMSESP_Status.publish_time = DEFAULT_PUBLISHTIME; EMSESP_Status.timestamp = millis(); EMSESP_Status.dallas_sensors = 0; EMSESP_Status.led_gpio = EMSESP_LED_GPIO; @@ -1696,8 +1693,8 @@ void setup() { // enable regular checks if not in test mode if (!EMSESP_Status.listen_mode) { - publishValuesTimer.attach(EMSESP_Status.publish_wait, do_publishValues); // post MQTT EMS values - publishSensorValuesTimer.attach(EMSESP_Status.publish_wait, do_publishSensorValues); // post MQTT sensor values + publishValuesTimer.attach(EMSESP_Status.publish_time, do_publishValues); // post MQTT EMS values + publishSensorValuesTimer.attach(EMSESP_Status.publish_time, do_publishSensorValues); // post MQTT sensor values regularUpdatesTimer.attach(REGULARUPDATES_TIME, do_regularUpdates); // regular reads from the EMS } From 6cfa03af7d5af0e4a43beeb3f2f7b68db61b9580 Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 18 Jun 2019 14:12:09 +0200 Subject: [PATCH 08/89] added env --- scripts/rename_fw.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/rename_fw.py b/scripts/rename_fw.py index 7b4d42299..c8a9a5a02 100644 --- a/scripts/rename_fw.py +++ b/scripts/rename_fw.py @@ -1,8 +1,7 @@ #!/usr/bin/env python -from subprocess import call -import os Import("env") # see http://docs.platformio.org/en/latest/projectconf/advanced_scripting.html#before-pre-and-after-post-actions # env.Replace(PROGNAME="firmware_%s" % defines.get("VERSION")) -env.Replace(PROGNAME="firmware_%s" % env['BOARD']) +# print env.Dump() +env.Replace(PROGNAME="firmware_%s" % env['BOARD'] + "_" + env['PIOENV']) From 32ca320afeeb9c70843adbeedb6de1699307425f Mon Sep 17 00:00:00 2001 From: proddy Date: Tue, 18 Jun 2019 14:12:20 +0200 Subject: [PATCH 09/89] removed warnings from release --- platformio.ini-example | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/platformio.ini-example b/platformio.ini-example index 4b893b11a..a8f2a4bf8 100644 --- a/platformio.ini-example +++ b/platformio.ini-example @@ -8,8 +8,9 @@ default_envs = debug [common] -debug_flags = -Wall -Wextra -Werror -Wno-missing-field-initializers -Wno-unused-parameter -Wno-unused-variable -DTESTS -DCRASH -general_flags = -g -w -DNO_GLOBAL_EEPROM +debug_flags = -Wall -DTESTS -DCRASH +release_flags = -w +general_flags = -g -DNO_GLOBAL_EEPROM arduino_core_2_3_0 = espressif8266@1.5.0 arduino_core_2_4_0 = espressif8266@1.6.0 @@ -49,9 +50,9 @@ extra_scripts = pre:scripts/rename_fw.py extra_scripts = pre:scripts/clean_fw.py [env:release] -build_flags = ${common.general_flags} +build_flags = ${common.general_flags} ${common.release_flags} extra_scripts = pre:scripts/rename_fw.py [env:checkcode] -build_flags = ${common.general_flags} +build_flags = ${common.general_flags} ${common.debug_flags} extra_scripts = scripts/checkcode.py From ffacc66d9e79eeac064114f005bb2b68343484c7 Mon Sep 17 00:00:00 2001 From: Paul Date: Tue, 18 Jun 2019 22:13:30 +0200 Subject: [PATCH 10/89] fix how json default values are set --- lib/MyESP/MyESP.cpp | 8 ++--- src/ems-esp.cpp | 73 +++++++++++++-------------------------------- 2 files changed, 23 insertions(+), 58 deletions(-) diff --git a/lib/MyESP/MyESP.cpp b/lib/MyESP/MyESP.cpp index f8e278cb8..b552132b5 100644 --- a/lib/MyESP/MyESP.cpp +++ b/lib/MyESP/MyESP.cpp @@ -274,10 +274,6 @@ void MyESP::_wifiCallback(justwifi_messages_t code, char * parameter) { myDebug_P(PSTR("[WIFI] Could not create access point\n")); } - if (code == MESSAGE_ACCESSPOINT_DESTROYED) { - myDebug_P(PSTR("[WIFI] Access point destroyed\n")); - } - if (code == MESSAGE_WPS_START) { myDebug_P(PSTR("[WIFI] WPS started\n")); } @@ -1562,9 +1558,9 @@ bool MyESP::_fs_loadConfig() { value = json["mqtt_password"]; _mqtt_password = (value) ? strdup(value) : NULL; - _use_serial = (bool)json["use_serial"]; + _use_serial = (bool)json["use_serial"]; // defaults to off - _heartbeat = (bool)json["heartbeat"]; + _heartbeat = (bool)json["heartbeat"]; // defaults to off // callback for loading custom settings // ok is false if there's a problem loading a custom setting (e.g. does not exist) diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index 6ed516e39..d1c084506 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -96,18 +96,18 @@ typedef struct { command_t project_cmds[] = { {true, "led ", "toggle status LED on/off"}, - {true, "led_gpio ", "set the LED pin. Default is the onboard LED (D1=5)"}, - {true, "dallas_gpio ", "set the pin for external Dallas temperature sensors (D5=14)"}, - {true, "dallas_parasite ", "set to on if powering Dallas via parasite"}, - {true, "thermostat_type ", "set the thermostat type id (e.g. 10 for 0x10)"}, - {true, "boiler_type ", "set the boiler type id (e.g. 8 for 0x08)"}, - {true, "listen_mode ", "when on all automatic Tx is disabled"}, - {true, "shower_timer ", "notify via MQTT all shower durations"}, - {true, "shower_alert ", "send a warning of cold water after shower time is exceeded"}, - {true, "publish_time ", "set frequency for publishing to MQTT (0=off)"}, - {true, "heating_circuit <1 | 2>", "set the thermostat HC to work with if using multiple heating circuits"}, + {true, "led_gpio ", "set the LED pin. Default is the onboard LED 2. For external D1 use 5"}, + {true, "dallas_gpio ", "set the external Dallas temperature sensors pin. Default is 14 for D5"}, + {true, "dallas_parasite ", "set to on if powering Dallas sesnsors via parasite power"}, + {true, "thermostat_type ", "set the thermostat type ID (e.g. 10 for 0x10)"}, + {true, "boiler_type ", "set the boiler type ID (e.g. 8 for 0x08)"}, + {true, "listen_mode ", "when set to on all automatic Tx are disabled"}, + {true, "shower_timer ", "send MQTT notification on all shower durations"}, + {true, "shower_alert ", "stop hot water to send 3 cold burst warnings after max shower time is exceeded"}, + {true, "publish_time ", "set frequency for publishing data to MQTT (0=off)"}, + {true, "heating_circuit <1 | 2>", "set the main thermostat HC to work with (if using multiple heating circuits)"}, - {false, "info", "show data captured on the EMS bus"}, + {false, "info", "show current captured on the devices"}, {false, "log ", "set logging mode to none, basic, thermostat only, raw or verbose"}, #ifdef TESTS @@ -1016,56 +1016,25 @@ void runUnitTest(uint8_t test_num) { // callback for loading/saving settings to the file system (SPIFFS) bool FSCallback(MYESP_FSACTION action, const JsonObject json) { if (action == MYESP_FSACTION_LOAD) { - bool recreate_config = true; - - // led - EMSESP_Status.led = json["led"]; - - // led_gpio - if (!(EMSESP_Status.led_gpio = json["led_gpio"])) { - EMSESP_Status.led_gpio = EMSESP_LED_GPIO; // default value - } - - // dallas_gpio - if (!(EMSESP_Status.dallas_gpio = json["dallas_gpio"])) { - EMSESP_Status.dallas_gpio = EMSESP_DALLAS_GPIO; // default value - } - - // dallas_parasite + EMSESP_Status.led = json["led"]; + EMSESP_Status.led_gpio = json["led_gpio"] | EMSESP_LED_GPIO; + EMSESP_Status.dallas_gpio = json["dallas_gpio"] | EMSESP_DALLAS_GPIO; EMSESP_Status.dallas_parasite = json["dallas_parasite"]; - // thermostat_type - if (!(EMS_Thermostat.device_id = json["thermostat_type"])) { - EMS_Thermostat.device_id = EMSESP_THERMOSTAT_TYPE; // set default - } + EMS_Thermostat.device_id = json["thermostat_type"] | EMSESP_THERMOSTAT_TYPE; + EMS_Boiler.device_id = json["boiler_type"] | EMSESP_BOILER_TYPE; - // boiler_type - if (!(EMS_Boiler.device_id = json["boiler_type"])) { - EMS_Boiler.device_id = EMSESP_BOILER_TYPE; // set default - } + EMSESP_Status.shower_timer = json["shower_timer"]; + EMSESP_Status.shower_alert = json["shower_alert"]; + EMSESP_Status.publish_time = json["publish_time"] | DEFAULT_PUBLISHTIME; - // listen mode EMSESP_Status.listen_mode = json["listen_mode"]; ems_setTxDisabled(EMSESP_Status.listen_mode); - // shower_timer - EMSESP_Status.shower_timer = json["shower_timer"]; - - // shower_alert - EMSESP_Status.shower_alert = json["shower_alert"]; - - // publish_time - if (!(EMSESP_Status.publish_time = json["publish_time"])) { - EMSESP_Status.publish_time = DEFAULT_PUBLISHTIME; // default value - } - - // heating_circuit - if (!(EMSESP_Status.heating_circuit = json["heating_circuit"])) { - EMSESP_Status.heating_circuit = DEFAULT_HEATINGCIRCUIT; // default value - } + EMSESP_Status.heating_circuit = json["heating_circuit"] | DEFAULT_HEATINGCIRCUIT; ems_setThermostatHC(EMSESP_Status.heating_circuit); - return recreate_config; // return false if some settings are missing and we need to rebuild the file + return true; // return false if some settings are missing and we need to rebuild the file } if (action == MYESP_FSACTION_SAVE) { From 1171608d33b4d1644c706945b51c6a261a041dba Mon Sep 17 00:00:00 2001 From: proddy Date: Wed, 19 Jun 2019 14:40:49 +0200 Subject: [PATCH 11/89] added Easy for Nefit --- src/ems_devices.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ems_devices.h b/src/ems_devices.h index 01bc29532..eed586eca 100644 --- a/src/ems_devices.h +++ b/src/ems_devices.h @@ -193,7 +193,7 @@ const _Other_Type Other_Types[] = { const _Thermostat_Type Thermostat_Types[] = { // Easy devices - not currently supporting write operations - {EMS_MODEL_EASY, 202, 0x18, "TC100/Nefit Easy", EMS_THERMOSTAT_WRITE_NO}, + {EMS_MODEL_EASY, 202, 0x18, "Logamatic TC100/Nefit Easy", EMS_THERMOSTAT_WRITE_NO}, {EMS_MODEL_EASY, 203, 0x18, "Bosch EasyControl CT200", EMS_THERMOSTAT_WRITE_NO}, {EMS_MODEL_EASY, 206, 0x02, "Bosch Easy", EMS_THERMOSTAT_WRITE_NO}, {EMS_MODEL_CW100, 157, 0x18, "CW100", EMS_THERMOSTAT_WRITE_NO}, From f320095034119f13362decb435eca930f3f3d313 Mon Sep 17 00:00:00 2001 From: proddy Date: Wed, 19 Jun 2019 14:41:05 +0200 Subject: [PATCH 12/89] fix rendering for unset SM values --- src/ems-esp.cpp | 10 +++++----- src/ems.cpp | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index d1c084506..138e2974e 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -767,10 +767,10 @@ void publishValues(bool force) { doc.clear(); JsonObject rootSM = doc.to(); - if (abs(EMS_Other.SMcollectorTemp) < EMS_VALUE_SHORT_NOTSET) + if (abs(EMS_Other.SMcollectorTemp) != EMS_VALUE_SHORT_NOTSET) rootSM[SM_COLLECTORTEMP] = (double)EMS_Other.SMcollectorTemp / 10; - if (abs(EMS_Other.SMbottomTemp) < EMS_VALUE_SHORT_NOTSET) + if (abs(EMS_Other.SMbottomTemp) != EMS_VALUE_SHORT_NOTSET) rootSM[SM_BOTTOMTEMP] = (double)EMS_Other.SMbottomTemp / 10; if (EMS_Other.SMpumpModulation != EMS_VALUE_INT_NOTSET) @@ -780,13 +780,13 @@ void publishValues(bool force) { rootSM[SM_PUMP] = _bool_to_char(s, EMS_Other.SMpump); } - if (abs(EMS_Other.SMEnergyLastHour) < EMS_VALUE_SHORT_NOTSET) + if (abs(EMS_Other.SMEnergyLastHour) != EMS_VALUE_SHORT_NOTSET) rootSM[SM_ENERGYLASTHOUR] = (double)EMS_Other.SMEnergyLastHour / 10; - if (abs(EMS_Other.SMEnergyToday) < EMS_VALUE_SHORT_NOTSET) + if (abs(EMS_Other.SMEnergyToday) != EMS_VALUE_SHORT_NOTSET) rootSM[SM_ENERGYTODAY] = EMS_Other.SMEnergyToday; - if (abs(EMS_Other.SMEnergyTotal) < EMS_VALUE_SHORT_NOTSET) + if (abs(EMS_Other.SMEnergyTotal) != EMS_VALUE_SHORT_NOTSET) rootSM[SM_ENERGYTOTAL] = (double)EMS_Other.SMEnergyTotal / 10; data[0] = '\0'; // reset data for next package diff --git a/src/ems.cpp b/src/ems.cpp index 3e10e4d0b..48ae1dc66 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -1829,7 +1829,8 @@ void ems_getOtherValues() { } /** - * returns current thermostat type as a string + * returns current thermostat type as a string + * by looking up the product_id */ char * ems_getThermostatDescription(char * buffer) { uint8_t size = 128; From f20621a3b322b702864a1a1bbcfb39898b0d1f0d Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 19 Jun 2019 18:35:46 +0200 Subject: [PATCH 13/89] added stackdump decoder for linux --- scripts/analyze_stackdmp.py | 4 + scripts/decoder_linux.py | 307 ++++++++++++++++++++++++++++++++++++ 2 files changed, 311 insertions(+) create mode 100644 scripts/decoder_linux.py diff --git a/scripts/analyze_stackdmp.py b/scripts/analyze_stackdmp.py index f8ff39353..17a63e218 100644 --- a/scripts/analyze_stackdmp.py +++ b/scripts/analyze_stackdmp.py @@ -18,3 +18,7 @@ import os # <<[0-9]*)\\):$") +COUNTER_REGEX = re.compile('^epc1=(?P0x[0-9a-f]+) epc2=(?P0x[0-9a-f]+) epc3=(?P0x[0-9a-f]+) ' + 'excvaddr=(?P0x[0-9a-f]+) depc=(?P0x[0-9a-f]+)$') +CTX_REGEX = re.compile("^ctx: (?P.+)$") +POINTER_REGEX = re.compile('^sp: (?P[0-9a-f]+) end: (?P[0-9a-f]+) offset: (?P[0-9a-f]+)$') +STACK_BEGIN = '>>>stack>>>' +STACK_END = '<<[0-9a-f]+):\W+(?P[0-9a-f]+) (?P[0-9a-f]+) (?P[0-9a-f]+) (?P[0-9a-f]+)(\W.*)?$') + +StackLine = namedtuple("StackLine", ["offset", "content"]) + + +class ExceptionDataParser(object): + def __init__(self): + self.exception = None + + self.epc1 = None + self.epc2 = None + self.epc3 = None + self.excvaddr = None + self.depc = None + + self.ctx = None + + self.sp = None + self.end = None + self.offset = None + + self.stack = [] + + def _parse_exception(self, line): + match = EXCEPTION_REGEX.match(line) + if match is not None: + self.exception = int(match.group('exc')) + return self._parse_counters + return self._parse_exception + + def _parse_counters(self, line): + match = COUNTER_REGEX.match(line) + if match is not None: + self.epc1 = match.group("epc1") + self.epc2 = match.group("epc2") + self.epc3 = match.group("epc3") + self.excvaddr = match.group("excvaddr") + self.depc = match.group("depc") + return self._parse_ctx + return self._parse_counters + + def _parse_ctx(self, line): + match = CTX_REGEX.match(line) + if match is not None: + self.ctx = match.group("ctx") + return self._parse_pointers + return self._parse_ctx + + def _parse_pointers(self, line): + match = POINTER_REGEX.match(line) + if match is not None: + self.sp = match.group("sp") + self.end = match.group("end") + self.offset = match.group("offset") + return self._parse_stack_begin + return self._parse_pointers + + def _parse_stack_begin(self, line): + if line == STACK_BEGIN: + return self._parse_stack_line + return self._parse_stack_begin + + def _parse_stack_line(self, line): + if line != STACK_END: + match = STACK_REGEX.match(line) + if match is not None: + self.stack.append(StackLine(offset=match.group("off"), + content=(match.group("c1"), match.group("c2"), match.group("c3"), + match.group("c4")))) + return self._parse_stack_line + return None + + def parse_file(self, file, stack_only=False): + func = self._parse_exception + if stack_only: + func = self._parse_stack_begin + + for line in file: + func = func(line.strip()) + if func is None: + break + + if func is not None: + print("ERROR: Parser not complete!") + sys.exit(1) + + +class AddressResolver(object): + def __init__(self, tool_path, elf_path): + self._tool = tool_path + self._elf = elf_path + self._address_map = {} + + def _lookup(self, addresses): + cmd = [self._tool, "-aipfC", "-e", self._elf] + [addr for addr in addresses if addr is not None] + + if sys.version_info[0] < 3: + output = subprocess.check_output(cmd) + else: + output = subprocess.check_output(cmd, encoding="utf-8") + + line_regex = re.compile("^(?P[0-9a-fx]+): (?P.+)$") + + last = None + for line in output.splitlines(): + line = line.strip() + match = line_regex.match(line) + + if match is None: + if last is not None and line.startswith('(inlined by)'): + line = line [12:].strip() + self._address_map[last] += ("\n \-> inlined by: " + line) + continue + + if match.group("result") == '?? ??:0': + continue + + self._address_map[match.group("addr")] = match.group("result") + last = match.group("addr") + + def fill(self, parser): + addresses = [parser.epc1, parser.epc2, parser.epc3, parser.excvaddr, parser.sp, parser.end, parser.offset] + for line in parser.stack: + addresses.extend(line.content) + + self._lookup(addresses) + + def _sanitize_addr(self, addr): + if addr.startswith("0x"): + addr = addr[2:] + + fill = "0" * (8 - len(addr)) + return "0x" + fill + addr + + def resolve_addr(self, addr): + out = self._sanitize_addr(addr) + + if out in self._address_map: + out += ": " + self._address_map[out] + + return out + + def resolve_stack_addr(self, addr, full=True): + addr = self._sanitize_addr(addr) + if addr in self._address_map: + return addr + ": " + self._address_map[addr] + + if full: + return "[DATA (0x" + addr + ")]" + + return None + + +def print_addr(name, value, resolver): + print("{}:{} {}".format(name, " " * (8 - len(name)), resolver.resolve_addr(value))) + + +def print_stack_full(lines, resolver): + print("stack:") + for line in lines: + print(line.offset + ":") + for content in line.content: + print(" " + resolver.resolve_stack_addr(content)) + + +def print_stack(lines, resolver): + print("stack:") + for line in lines: + for content in line.content: + out = resolver.resolve_stack_addr(content, full=False) + if out is None: + continue + print(out) + + +def print_result(parser, resolver, full=True, stack_only=False): + if not stack_only: + print('Exception: {} ({})'.format(parser.exception, EXCEPTIONS[parser.exception])) + + print("") + print_addr("epc1", parser.epc1, resolver) + print_addr("epc2", parser.epc2, resolver) + print_addr("epc3", parser.epc3, resolver) + print_addr("excvaddr", parser.excvaddr, resolver) + print_addr("depc", parser.depc, resolver) + + print("") + print("ctx: " + parser.ctx) + + print("") + print_addr("sp", parser.sp, resolver) + print_addr("end", parser.end, resolver) + print_addr("offset", parser.offset, resolver) + + print("") + if full: + print_stack_full(parser.stack, resolver) + else: + print_stack(parser.stack, resolver) + + +def parse_args(): + parser = argparse.ArgumentParser(description="decode ESP Stacktraces.") + + parser.add_argument("-p", "--platform", help="The platform to decode from", choices=PLATFORMS.keys(), + default="ESP8266") + parser.add_argument("-t", "--tool", help="Path to the xtensa toolchain", + default="~/.platformio/packages/toolchain-xtensa/") + parser.add_argument("-e", "--elf", help="path to elf file", required=True) + parser.add_argument("-f", "--full", help="Print full stack dump", action="store_true") + parser.add_argument("-s", "--stack_only", help="Decode only a stractrace", action="store_true") + parser.add_argument("file", help="The file to read the exception data from ('-' for STDIN)", default="-") + + return parser.parse_args() + + +if __name__ == "__main__": + args = parse_args() + + if args.file == "-": + file = sys.stdin + else: + if not os.path.exists(args.file): + print("ERROR: file " + args.file + " not found") + sys.exit(1) + file = open(args.file, "r") + + addr2line = os.path.join(os.path.abspath(os.path.expanduser(args.tool)), + "bin/xtensa-" + PLATFORMS[args.platform] + "-elf-addr2line") + if not os.path.exists(addr2line): + print("ERROR: addr2line not found (" + addr2line + ")") + + elf_file = os.path.abspath(os.path.expanduser(args.elf)) + if not os.path.exists(elf_file): + print("ERROR: elf file not found (" + elf_file + ")") + + parser = ExceptionDataParser() + resolver = AddressResolver(addr2line, elf_file) + + parser.parse_file(file, args.stack_only) + resolver.fill(parser) + + print_result(parser, resolver, args.full, args.stack_only) From 1a125763c3bc05e41bd8c11771615fcd039814d6 Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 19 Jun 2019 19:25:44 +0200 Subject: [PATCH 14/89] fix typo --- scripts/analyze_stackdmp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/analyze_stackdmp.py b/scripts/analyze_stackdmp.py index 17a63e218..1e29b2449 100644 --- a/scripts/analyze_stackdmp.py +++ b/scripts/analyze_stackdmp.py @@ -17,7 +17,7 @@ import os # 3fffffb0: feefeffe feefeffe 3ffe8558 40100b01 # << Date: Thu, 20 Jun 2019 00:16:34 +0200 Subject: [PATCH 15/89] SplitSolarModuleFromOtherDevices Solar modules upgrades: a separate Solar Module types list (no longer part of other devices). Made a separate _EMS_SolarModule class (no longer part of _EMS_Other). And updated all code that was impacted by that change. Also added a device description for solar modules. Tests on my setup (telnet & MQTT) work as before. --- src/ems-esp.cpp | 50 ++++----- src/ems.cpp | 260 ++++++++++++++++++++++++++++++++++++---------- src/ems.h | 51 +++++++-- src/ems_devices.h | 22 +++- 4 files changed, 290 insertions(+), 93 deletions(-) diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index 138e2974e..950b19802 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -450,22 +450,24 @@ void showInfo() { } // For SM10/SM100 Solar Module - if (EMS_Other.SM) { + if (ems_getThermostatEnabled()) { myDebug_P(PSTR("")); // newline myDebug_P(PSTR("%sSolar Module stats:%s"), COLOR_BOLD_ON, COLOR_BOLD_OFF); - _renderShortValue("Collector temperature", "C", EMS_Other.SMcollectorTemp); - _renderShortValue("Bottom temperature", "C", EMS_Other.SMbottomTemp); - _renderIntValue("Pump modulation", "%", EMS_Other.SMpumpModulation); - _renderBoolValue("Pump active", EMS_Other.SMpump); - _renderShortValue("Energy Last Hour", "Wh", EMS_Other.SMEnergyLastHour, 1); // *10 - _renderShortValue("Energy Today", "Wh", EMS_Other.SMEnergyToday, 0); - _renderShortValue("Energy Total", "kWH", EMS_Other.SMEnergyTotal, 1); // *10 + myDebug_P(PSTR(" Solar Module: %s"), ems_getSolarModuleDescription(buffer_type)); + _renderShortValue("Collector temperature", "C", EMS_SolarModule.collectorTemp); + _renderShortValue("Bottom temperature", "C", EMS_SolarModule.bottomTemp); + _renderIntValue("Pump modulation", "%", EMS_SolarModule.pumpModulation); + _renderBoolValue("Pump active", EMS_SolarModule.pump); + _renderShortValue("Energy Last Hour", "Wh", EMS_SolarModule.EnergyLastHour, 1); // *10 + _renderShortValue("Energy Today", "Wh", EMS_SolarModule.EnergyToday, 0); + _renderShortValue("Energy Total", "kWH", EMS_SolarModule.EnergyTotal, 1); // *10 } // For HeatPumps if (EMS_Other.HP) { myDebug_P(PSTR("")); // newline myDebug_P(PSTR("%sHeat Pump stats:%s"), COLOR_BOLD_ON, COLOR_BOLD_OFF); + myDebug_P(PSTR(" Solar Module: %s"), ems_getHeatPumpDescription(buffer_type)); _renderIntValue("Pump modulation", "%", EMS_Other.HPModulation); _renderIntValue("Pump speed", "%", EMS_Other.HPSpeed); } @@ -762,32 +764,32 @@ void publishValues(bool force) { // handle the other values separately // For SM10 and SM100 Solar Modules - if (EMS_Other.SM) { + if (ems_getSolarModuleEnabled()) { // build new json object doc.clear(); JsonObject rootSM = doc.to(); - if (abs(EMS_Other.SMcollectorTemp) != EMS_VALUE_SHORT_NOTSET) - rootSM[SM_COLLECTORTEMP] = (double)EMS_Other.SMcollectorTemp / 10; + if (abs(EMS_SolarModule.collectorTemp) != EMS_VALUE_SHORT_NOTSET) + rootSM[SM_COLLECTORTEMP] = (double)EMS_SolarModule.collectorTemp / 10; - if (abs(EMS_Other.SMbottomTemp) != EMS_VALUE_SHORT_NOTSET) - rootSM[SM_BOTTOMTEMP] = (double)EMS_Other.SMbottomTemp / 10; + if (abs(EMS_SolarModule.bottomTemp) != EMS_VALUE_SHORT_NOTSET) + rootSM[SM_BOTTOMTEMP] = (double)EMS_SolarModule.bottomTemp / 10; - if (EMS_Other.SMpumpModulation != EMS_VALUE_INT_NOTSET) - rootSM[SM_PUMPMODULATION] = EMS_Other.SMpumpModulation; + if (EMS_SolarModule.pumpModulation != EMS_VALUE_INT_NOTSET) + rootSM[SM_PUMPMODULATION] = EMS_SolarModule.pumpModulation; - if (EMS_Other.SMpump != EMS_VALUE_INT_NOTSET) { - rootSM[SM_PUMP] = _bool_to_char(s, EMS_Other.SMpump); + if (EMS_SolarModule.pump != EMS_VALUE_INT_NOTSET) { + rootSM[SM_PUMP] = _bool_to_char(s, EMS_SolarModule.pump); } - if (abs(EMS_Other.SMEnergyLastHour) != EMS_VALUE_SHORT_NOTSET) - rootSM[SM_ENERGYLASTHOUR] = (double)EMS_Other.SMEnergyLastHour / 10; + if (abs(EMS_SolarModule.EnergyLastHour) != EMS_VALUE_SHORT_NOTSET) + rootSM[SM_ENERGYLASTHOUR] = (double)EMS_SolarModule.EnergyLastHour / 10; - if (abs(EMS_Other.SMEnergyToday) != EMS_VALUE_SHORT_NOTSET) - rootSM[SM_ENERGYTODAY] = EMS_Other.SMEnergyToday; + if (abs(EMS_SolarModule.EnergyToday) != EMS_VALUE_SHORT_NOTSET) + rootSM[SM_ENERGYTODAY] = EMS_SolarModule.EnergyToday; - if (abs(EMS_Other.SMEnergyTotal) != EMS_VALUE_SHORT_NOTSET) - rootSM[SM_ENERGYTOTAL] = (double)EMS_Other.SMEnergyTotal / 10; + if (abs(EMS_SolarModule.EnergyTotal) != EMS_VALUE_SHORT_NOTSET) + rootSM[SM_ENERGYTOTAL] = (double)EMS_SolarModule.EnergyTotal / 10; data[0] = '\0'; // reset data for next package serializeJson(doc, data, sizeof(data)); @@ -927,7 +929,7 @@ void do_regularUpdates() { myDebugLog("Requesting scheduled EMS device data"); ems_getThermostatValues(); ems_getBoilerValues(); - ems_getOtherValues(); + ems_getSolarModuleValues(); } } diff --git a/src/ems.cpp b/src/ems.cpp index 48ae1dc66..a41185152 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -182,15 +182,17 @@ const _EMS_Type EMS_Types[] = { }; // calculate sizes of arrays at compile -uint8_t _EMS_Types_max = ArraySize(EMS_Types); // number of defined types -uint8_t _Boiler_Types_max = ArraySize(Boiler_Types); // number of boiler models -uint8_t _Other_Types_max = ArraySize(Other_Types); // number of other ems devices -uint8_t _Thermostat_Types_max = ArraySize(Thermostat_Types); // number of defined thermostat types +uint8_t _EMS_Types_max = ArraySize(EMS_Types); // number of defined types +uint8_t _Boiler_Types_max = ArraySize(Boiler_Types); // number of boiler models +uint8_t _Solar_Module_Types_max = ArraySize(SolarModule_Types);// number of solar module types +uint8_t _Other_Types_max = ArraySize(Other_Types); // number of other ems devices +uint8_t _Thermostat_Types_max = ArraySize(Thermostat_Types); // number of defined thermostat types // these structs contain the data we store from the Boiler and Thermostat -_EMS_Boiler EMS_Boiler; // for boiler -_EMS_Thermostat EMS_Thermostat; // for thermostat -_EMS_Other EMS_Other; // for other known EMS devices +_EMS_Boiler EMS_Boiler; // for boiler +_EMS_Thermostat EMS_Thermostat; // for thermostat +_EMS_SolarModule EMS_SolarModule; // for solar modules +_EMS_Other EMS_Other; // for other known EMS devices // CRC lookup table with poly 12 for faster checking const uint8_t ems_crc_table[] = {0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, 0x20, 0x22, 0x24, 0x26, @@ -298,16 +300,24 @@ void ems_init() { EMS_Boiler.pump_mod_max = EMS_VALUE_INT_NOTSET; // Boiler circuit pump modulation max. power EMS_Boiler.pump_mod_min = EMS_VALUE_INT_NOTSET; // Boiler circuit pump modulation min. power + // Solar Module values + EMS_SolarModule.collectorTemp = EMS_VALUE_SHORT_NOTSET; // collector temp from SM10/SM100 + EMS_SolarModule.bottomTemp = EMS_VALUE_SHORT_NOTSET; // bottom temp from SM10/SM100 + EMS_SolarModule.pumpModulation = EMS_VALUE_INT_NOTSET; // modulation solar pump SM10/SM100 + EMS_SolarModule.pump = EMS_VALUE_INT_NOTSET; // pump active + EMS_SolarModule.EnergyLastHour = EMS_VALUE_SHORT_NOTSET; + EMS_SolarModule.EnergyToday = EMS_VALUE_SHORT_NOTSET; + EMS_SolarModule.EnergyTotal = EMS_VALUE_SHORT_NOTSET; + EMS_SolarModule.device_id = EMS_ID_NONE; + EMS_SolarModule.model_id = EMS_MODEL_NONE; + EMS_SolarModule.product_id = EMS_ID_NONE; + // Other EMS devices values - EMS_Other.SMcollectorTemp = EMS_VALUE_SHORT_NOTSET; // collector temp from SM10/SM100 - EMS_Other.SMbottomTemp = EMS_VALUE_SHORT_NOTSET; // bottom temp from SM10/SM100 - EMS_Other.SMpumpModulation = EMS_VALUE_INT_NOTSET; // modulation solar pump SM10/SM100 - EMS_Other.SMpump = EMS_VALUE_INT_NOTSET; // pump active - EMS_Other.SMEnergyLastHour = EMS_VALUE_SHORT_NOTSET; - EMS_Other.SMEnergyToday = EMS_VALUE_SHORT_NOTSET; - EMS_Other.SMEnergyTotal = EMS_VALUE_SHORT_NOTSET; EMS_Other.HPModulation = EMS_VALUE_INT_NOTSET; EMS_Other.HPSpeed = EMS_VALUE_INT_NOTSET; + EMS_Other.device_id = EMS_ID_NONE; + EMS_Other.model_id = EMS_MODEL_NONE; + EMS_Other.product_id = EMS_ID_NONE; // calculated values EMS_Boiler.tapwaterActive = EMS_VALUE_INT_NOTSET; // Hot tap water is on/off @@ -323,7 +333,6 @@ void ems_init() { strlcpy(EMS_Thermostat.version, "?", sizeof(EMS_Thermostat.version)); // set other types - EMS_Other.SM = false; EMS_Other.HP = false; // default logging is none @@ -360,10 +369,22 @@ bool ems_getThermostatEnabled() { return (EMS_Thermostat.device_id != EMS_ID_NONE); } +bool ems_getSolarModuleEnabled() { + return (EMS_SolarModule.device_id != EMS_ID_NONE); +} + uint8_t ems_getThermostatModel() { return (EMS_Thermostat.model_id); } +uint8_t ems_getOtherModel() { + return (EMS_Other.model_id); +} + +uint8_t ems_getSolarModuleModel() { + return (EMS_SolarModule.model_id); +} + void ems_setTxDisabled(bool b) { EMS_Sys_Status.emsTxDisabled = b; } @@ -1350,12 +1371,12 @@ void _process_RCOutdoorTempMessage(_EMS_RxTelegram * EMS_RxTelegram) { * SM10Monitor - type 0x97 */ void _process_SM10Monitor(_EMS_RxTelegram * EMS_RxTelegram) { - EMS_Other.SMcollectorTemp = _toShort(2); // collector temp from SM10, is *10 - EMS_Other.SMbottomTemp = _toShort(5); // bottom temp from SM10, is *10 - EMS_Other.SMpumpModulation = _toByte(4); // modulation solar pump - EMS_Other.SMpump = _bitRead(7, 1); // active if bit 1 is set + EMS_SolarModule.collectorTemp = _toShort(2); // collector temp from SM10, is *10 + EMS_SolarModule.bottomTemp = _toShort(5); // bottom temp from SM10, is *10 + EMS_SolarModule.pumpModulation = _toByte(4); // modulation solar pump + EMS_SolarModule.pump = _bitRead(7, 1); // active if bit 1 is set - EMS_Other.SM = true; + // EMS_Other.SM = true; EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT } @@ -1371,13 +1392,13 @@ void _process_SM100Monitor(_EMS_RxTelegram * EMS_RxTelegram) { return; } - EMS_Other.SMcollectorTemp = _toShort(0); // collector temp from SM100, is *10 + EMS_SolarModule.collectorTemp = _toShort(0); // collector temp from SM100, is *10 if (EMS_RxTelegram->data_length > 2) { - EMS_Other.SMbottomTemp = _toShort(2); // bottom temp from SM100, is *10 + EMS_SolarModule.bottomTemp = _toShort(2); // bottom temp from SM100, is *10 } - EMS_Other.SM = true; + // EMS_Other.SM = true; EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT } @@ -1389,13 +1410,13 @@ void _process_SM100Monitor(_EMS_RxTelegram * EMS_RxTelegram) { void _process_SM100Status(_EMS_RxTelegram * EMS_RxTelegram) { // check for complete telegram if (EMS_RxTelegram->offset == 0) { - EMS_Other.SMpumpModulation = _toByte(9); // modulation solar pump + EMS_SolarModule.pumpModulation = _toByte(9); // modulation solar pump } else if (EMS_RxTelegram->offset == 0x09) { // or short telegram with a single byte with offset 09 - EMS_Other.SMpumpModulation = _toByte(0); // modulation solar pump + EMS_SolarModule.pumpModulation = _toByte(0); // modulation solar pump } - EMS_Other.SM = true; + // EMS_Other.SM = true; EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT } @@ -1405,13 +1426,13 @@ void _process_SM100Status(_EMS_RxTelegram * EMS_RxTelegram) { void _process_SM100Status2(_EMS_RxTelegram * EMS_RxTelegram) { // check for complete telegram if (EMS_RxTelegram->offset == 0) { - EMS_Other.SMpump = _bitRead(10, 2); // 03=off 04=on at offset 10 which is byte 10 + EMS_SolarModule.pump = _bitRead(10, 2); // 03=off 04=on at offset 10 which is byte 10 } else if (EMS_RxTelegram->offset == 0x0A) { // or short telegram with a single byte with offset 0A - EMS_Other.SMpump = _bitRead(0, 2); // 03=off 04=on + EMS_SolarModule.pump = _bitRead(0, 2); // 03=off 04=on } - EMS_Other.SM = true; + // EMS_Other.SM = true; EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT } @@ -1420,11 +1441,11 @@ void _process_SM100Status2(_EMS_RxTelegram * EMS_RxTelegram) { * e.g. 30 00 FF 00 02 8E 00 00 00 00 00 00 06 C5 00 00 76 35 */ void _process_SM100Energy(_EMS_RxTelegram * EMS_RxTelegram) { - EMS_Other.SMEnergyLastHour = _toShort(2); // last hour / 10 in Wh - EMS_Other.SMEnergyToday = _toShort(6); // todays in Wh - EMS_Other.SMEnergyTotal = _toShort(10); // total / 10 in kWh + EMS_SolarModule.EnergyLastHour = _toShort(2); // last hour / 10 in Wh + EMS_SolarModule.EnergyToday = _toShort(6); // todays in Wh + EMS_SolarModule.EnergyTotal = _toShort(10); // total / 10 in kWh - EMS_Other.SM = true; + // EMS_Other.SM = true; EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT } @@ -1455,17 +1476,17 @@ void _process_ISM1StatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { if (EMS_RxTelegram->offset == 0) { // e.g. B0 00 FF 00 00 03 32 00 00 00 00 13 00 D6 00 00 00 FB D0 F0 - EMS_Other.SMcollectorTemp = _toShort(4); // Collector Temperature - EMS_Other.SMbottomTemp = _toShort(6); // Temperature Bottom of Solar Boiler - EMS_Other.SMEnergyLastHour = _toShort(2) * 10; // Solar Energy produced in last hour - EMS_Other.SMpump = _bitRead(8,0); // Solar pump on (1) or off (0) - EMS_Other.SM = true; + EMS_SolarModule.collectorTemp = _toShort(4); // Collector Temperature + EMS_SolarModule.bottomTemp = _toShort(6); // Temperature Bottom of Solar Boiler + EMS_SolarModule.EnergyLastHour = _toShort(2) * 10; // Solar Energy produced in last hour + EMS_SolarModule.pump = _bitRead(8,0); // Solar pump on (1) or off (0) + // EMS_Other.SM = true; } if (EMS_RxTelegram->offset == 4) { // e.g. B0 00 FF 04 00 03 02 E5 - EMS_Other.SMcollectorTemp = _toShort(0); // Collector Temperature - EMS_Other.SM = true; + EMS_SolarModule.collectorTemp = _toShort(0); // Collector Temperature + // EMS_Other.SM = true; } } @@ -1521,7 +1542,6 @@ void ems_clearDeviceList() { */ void _addDevice(uint8_t product_id, uint8_t device_id, char * version, const char * model_string) { _Generic_Type device; - // if its a duplicate don't add bool found = false; for (std::list<_Generic_Type>::iterator it = Devices.begin(); it != Devices.end(); it++) { @@ -1529,7 +1549,6 @@ void _addDevice(uint8_t product_id, uint8_t device_id, char * version, const cha found = true; } } - if (!found) { device.product_id = product_id; device.device_id = device_id; @@ -1644,6 +1663,37 @@ void _process_Version(_EMS_RxTelegram * EMS_RxTelegram) { return; } + + // finally look for Solar Modules + i = 0; + while (i < _Solar_Module_Types_max) { + if (SolarModule_Types[i].product_id == product_id) { + typeFound = true; // we have a matching product id. i is the index. + break; + } + i++; + } + + if (typeFound) { + myDebug_P(PSTR("Solar Module found: %s (DeviceID:0x%02X ProductID:%d Version:%s)"), SolarModule_Types[i].model_string, SolarModule_Types[i].device_id, product_id, version); + + // add to list + _addDevice(product_id, SolarModule_Types[i].device_id, version, SolarModule_Types[i].model_string); + + // EMS_Other.SM = true; // we have detected a Solar Module (SM10, SM100, ISM1 ...) + myDebug_P(PSTR("Solar Module support enabled.")); + EMS_SolarModule.model_id = Other_Types[i].model_id; + EMS_SolarModule.device_id = Other_Types[i].device_id; + EMS_SolarModule.product_id = product_id; + strlcpy(EMS_SolarModule.version, version, sizeof(EMS_SolarModule.version)); + + // fetch Solar Module values + ems_getSolarModuleValues(); + return; + + } + + // finally look for the other EMS devices i = 0; while (i < _Other_Types_max) { @@ -1660,20 +1710,18 @@ void _process_Version(_EMS_RxTelegram * EMS_RxTelegram) { // add to list _addDevice(product_id, Other_Types[i].device_id, version, Other_Types[i].model_string); - // see if this is a Solar Module SM10 - if (Other_Types[i].device_id == EMS_ID_SM) { - EMS_Other.SM = true; // we have detected a SM10 - myDebug_P(PSTR("SM10 Solar Module support enabled.")); - } - // see if this is a HeatPump if (Other_Types[i].device_id == EMS_ID_HP) { EMS_Other.HP = true; // we have detected a HP myDebug_P(PSTR("HeatPump support enabled.")); + EMS_Other.model_id = Other_Types[i].model_id; + EMS_Other.device_id = Other_Types[i].device_id; + EMS_Other.product_id = product_id; + strlcpy(EMS_Other.version, version, sizeof(EMS_Other.version)); + // fetch Solar Module values > not yet implemented + } - // fetch other values - ems_getOtherValues(); return; } else { @@ -1822,9 +1870,18 @@ void ems_getBoilerValues() { /* * Get other values from EMS devices */ -void ems_getOtherValues() { - if (EMS_Other.SM) { - ems_doReadCommand(EMS_TYPE_SM10Monitor, EMS_ID_SM); // fetch all from SM10Monitor +void ems_getSolarModuleValues() { + + uint8_t product_id = EMS_SolarModule.product_id; + + if (ems_getSolarModuleEnabled()) { + if (product_id == EMS_PRODUCTID_SM10) { + ems_doReadCommand(EMS_TYPE_SM10Monitor, EMS_ID_SM); // fetch all from SM10Monitor + } + else if (product_id == EMS_PRODUCTID_SM100) { + ems_doReadCommand(EMS_TYPE_SM100Monitor, EMS_ID_SM); // fetch all from SM100Monitor + } + } } @@ -1912,6 +1969,88 @@ char * ems_getBoilerDescription(char * buffer) { return buffer; } +/** + * returns current Solar Module type as a string + */ +char * ems_getSolarModuleDescription(char * buffer) { + uint8_t size = 128; + if (!ems_getSolarModuleEnabled()) { + strlcpy(buffer, "", size); + } else { + int i = 0; + bool found = false; + char tmp[6] = {0}; + + // scan through known ID types + while (i < _Solar_Module_Types_max) { + if (SolarModule_Types[i].product_id == EMS_SolarModule.product_id) { + found = true; // we have a match + break; + } + i++; + } + if (found) { + strlcpy(buffer, SolarModule_Types[i].model_string, size); + } else { + strlcpy(buffer, "DeviceID: 0x", size); + strlcat(buffer, _hextoa(EMS_SolarModule.device_id, tmp), size); + } + + strlcat(buffer, " (ProductID:", size); + if (EMS_SolarModule.product_id == EMS_ID_NONE) { + strlcat(buffer, "?", size); + } else { + strlcat(buffer, itoa(EMS_SolarModule.product_id, tmp, 10), size); + } + strlcat(buffer, " Version:", size); + strlcat(buffer, EMS_SolarModule.version, size); + strlcat(buffer, ")", size); + } + + return buffer; +} + +/** + * returns current Heat Pump type as a string + */ +char * ems_getHeatPumpDescription(char * buffer) { + uint8_t size = 128; + if (!EMS_Other.HP) { + strlcpy(buffer, "", size); + } else { + int i = 0; + bool found = false; + char tmp[6] = {0}; + + // scan through known ID types + while (i < _Other_Types_max) { + if (Other_Types[i].product_id == EMS_Other.product_id) { + found = true; // we have a match + break; + } + i++; + } + if (found) { + strlcpy(buffer, Other_Types[i].model_string, size); + } else { + strlcpy(buffer, "DeviceID: 0x", size); + strlcat(buffer, _hextoa(EMS_Other.device_id, tmp), size); + } + + strlcat(buffer, " (ProductID:", size); + if (EMS_Other.product_id == EMS_ID_NONE) { + strlcat(buffer, "?", size); + } else { + strlcat(buffer, itoa(EMS_Other.product_id, tmp, 10), size); + } + strlcat(buffer, " Version:", size); + strlcat(buffer, EMS_Other.version, size); + strlcat(buffer, ")", size); + } + + return buffer; +} + /** * Find the versions of our connected devices */ @@ -1928,6 +2067,11 @@ void ems_scanDevices() { Device_Ids.push_back(tt.device_id); } + // copy over solar modules + for (_SolarModule_Type sm : SolarModule_Types) { + Device_Ids.push_back(sm.device_id); + } + // copy over others for (_Other_Type ot : Other_Types) { Device_Ids.push_back(ot.device_id); @@ -1963,6 +2107,16 @@ void ems_printAllDevices() { Boiler_Types[i].product_id); } + myDebug_P(PSTR("\nThese %d devices are supported as solar module devices:"), _Solar_Module_Types_max); + for (i = 0; i < _Solar_Module_Types_max; i++) { + myDebug_P(PSTR(" %s%s%s (DeviceID:0x%02X ProductID:%d)"), + COLOR_BOLD_ON, + SolarModule_Types[i].model_string, + COLOR_BOLD_OFF, + SolarModule_Types[i].device_id, + SolarModule_Types[i].product_id); + } + myDebug_P(PSTR("\nThese %d devices are supported as other known EMS devices:"), _Other_Types_max); for (i = 0; i < _Other_Types_max; i++) { myDebug_P(PSTR(" %s%s%s (DeviceID:0x%02X ProductID:%d)"), diff --git a/src/ems.h b/src/ems.h index e20ca7660..63680b903 100644 --- a/src/ems.h +++ b/src/ems.h @@ -17,12 +17,17 @@ // Fixed EMS IDs #define EMS_ID_ME 0x0B // our device, hardcoded as the "Service Key" #define EMS_ID_BOILER 0x08 // all UBA Boilers have 0x08 -#define EMS_ID_SM 0x30 // Solar Module SM10 and SM100 +#define EMS_ID_SM 0x30 // Solar Module SM10, SM100 and ISM1 #define EMS_ID_HP 0x38 // HeatPump #define EMS_ID_GATEWAY 0x48 // KM200 Web Gateway #define EMS_PRODUCTID_HEATRONICS 95 // ProductID for a Junkers Heatronic3 device +#define EMS_PRODUCTID_SM10 73 // ProductID for SM10 solar module +#define EMS_PRODUCTID_SM100 163 // ProductID for SM10 solar module +#define EMS_PRODUCTID_ISM1 101 // ProductID for SM10 solar module + + #define EMS_MIN_TELEGRAM_LENGTH 6 // minimal length for a validation telegram, including CRC // max length of a telegram, including CRC, for Rx and Tx. @@ -154,6 +159,13 @@ typedef struct { char model_string[50]; } _Boiler_Type; +typedef struct { + uint8_t model_id; + uint8_t product_id; + uint8_t device_id; + char model_string[50]; +} _SolarModule_Type; + typedef struct { uint8_t model_id; uint8_t product_id; @@ -241,21 +253,32 @@ typedef struct { // UBAParameterWW * Telegram package defintions for Other EMS devices */ -// SM Solar Module - SM10Monitor/SM100Monitor +// Other ems devices than solar modules, thermostats and boilers typedef struct { - bool SM; // set true if there is a Solar Module available bool HP; // set true if there is a Heat Pump available - int16_t SMcollectorTemp; // collector temp - int16_t SMbottomTemp; // bottom temp - uint8_t SMpumpModulation; // modulation solar pump - uint8_t SMpump; // pump active - int16_t SMEnergyLastHour; - int16_t SMEnergyToday; - int16_t SMEnergyTotal; uint8_t HPModulation; // heatpump modulation in % uint8_t HPSpeed; // speed 0-100 % + uint8_t device_id; // the device ID of the Solar Module / Heat Pump (e.g. 0x30) + uint8_t model_id; // Solar Module / Heat Pump model (e.g. 3 > EMS_MODEL_OTHER ) + uint8_t product_id; // (e.g. 101) + char version[10]; } _EMS_Other; +// SM Solar Module - SM10/SM100/ISM1 +typedef struct { + int16_t collectorTemp; // collector temp + int16_t bottomTemp; // bottom temp + uint8_t pumpModulation; // modulation solar pump + uint8_t pump; // pump active + int16_t EnergyLastHour; + int16_t EnergyToday; + int16_t EnergyTotal; + uint8_t device_id; // the device ID of the Solar Module / Heat Pump (e.g. 0x30) + uint8_t model_id; // Solar Module / Heat Pump model (e.g. 3 > EMS_MODEL_OTHER ) + uint8_t product_id; // (e.g. 101) + char version[10]; +} _EMS_SolarModule; + // Thermostat data typedef struct { uint8_t device_id; // the device ID of the thermostat @@ -322,17 +345,22 @@ void ems_setTxDisabled(bool b); char * ems_getThermostatDescription(char * buffer); char * ems_getBoilerDescription(char * buffer); +char * ems_getSolarModuleDescription(char * buffer); +char * ems_getHeatPumpDescription(char * buffer); void ems_getThermostatValues(); void ems_getBoilerValues(); -void ems_getOtherValues(); +void ems_getSolarModuleValues(); bool ems_getPoll(); bool ems_getTxEnabled(); bool ems_getThermostatEnabled(); bool ems_getBoilerEnabled(); +bool ems_getSolarModuleEnabled(); bool ems_getBusConnected(); _EMS_SYS_LOGGING ems_getLogging(); bool ems_getEmsRefreshed(); uint8_t ems_getThermostatModel(); +uint8_t ems_getSolarModuleModel(); +uint8_t ems_getOtherModel(); void ems_discoverModels(); bool ems_getTxCapable(); uint32_t ems_getPollFrequency(); @@ -350,4 +378,5 @@ void _removeTxQueue(); extern _EMS_Sys_Status EMS_Sys_Status; extern _EMS_Boiler EMS_Boiler; extern _EMS_Thermostat EMS_Thermostat; +extern _EMS_SolarModule EMS_SolarModule; extern _EMS_Other EMS_Other; diff --git a/src/ems_devices.h b/src/ems_devices.h index eed586eca..f10262018 100644 --- a/src/ems_devices.h +++ b/src/ems_devices.h @@ -124,6 +124,9 @@ typedef enum { // generic ID for the boiler EMS_MODEL_UBA, + // generic ID for the solar module + EMS_MODEL_SOLAR_MODULE, + // generic ID for all the other weird devices EMS_MODEL_OTHER, @@ -147,7 +150,7 @@ typedef enum { } _EMS_MODEL_ID; -// EMS types for known devices. This list will be extended when new devices are recognized. +// EMS types for known boilers. This list will be extended when new devices are recognized. // The device_id is always 0x08 // format is MODEL_ID, PRODUCT ID, DESCRIPTION const _Boiler_Type Boiler_Types[] = { @@ -164,7 +167,19 @@ const _Boiler_Type Boiler_Types[] = { }; -// Other EMS devices which are not considered boilers or thermostats +/* + * Known Solar Module types + */ +const _SolarModule_Type SolarModule_Types[] = { + + {EMS_MODEL_OTHER, EMS_PRODUCTID_SM10, EMS_ID_SM, "SM10 Solar Module"}, + {EMS_MODEL_OTHER, EMS_PRODUCTID_SM100, EMS_ID_SM, "SM100 Solar Module"}, + {EMS_MODEL_OTHER, EMS_PRODUCTID_ISM1, EMS_ID_SM, "Junkers ISM1 Solar Module"} + +}; + + +// Other EMS devices which are not considered boilers, thermostats or solar modules const _Other_Type Other_Types[] = { {EMS_MODEL_OTHER, 69, 0x21, "MM10 Mixer Module"}, @@ -178,11 +193,8 @@ const _Other_Type Other_Types[] = { {EMS_MODEL_OTHER, 125, 0x09, "BC25 Base Controller"}, {EMS_MODEL_OTHER, 152, 0x09, "Junkers Controller"}, {EMS_MODEL_OTHER, 205, 0x02, "Nefit Moduline Easy Connect"}, - {EMS_MODEL_OTHER, 73, EMS_ID_SM, "SM10 Solar Module"}, - {EMS_MODEL_OTHER, 163, EMS_ID_SM, "SM100 Solar Module"}, {EMS_MODEL_OTHER, 171, 0x02, "EMS-OT OpenTherm converter"}, {EMS_MODEL_OTHER, 252, EMS_ID_HP, "HeatPump Module"}, // warning, fake product id! - {EMS_MODEL_OTHER, 101, 0x30, "Junkers ISM1 Solar Controller"}, {EMS_MODEL_OTHER, 189, EMS_ID_GATEWAY, "Web Gateway KM200"} }; From 54922fe9cbc55b08b02a0bf056adc8d29e59963c Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 20 Jun 2019 09:30:28 +0200 Subject: [PATCH 16/89] https://github.com/proddy/EMS-ESP/issues/133 --- src/ems_devices.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/ems_devices.h b/src/ems_devices.h index f10262018..eb20985fa 100644 --- a/src/ems_devices.h +++ b/src/ems_devices.h @@ -161,7 +161,7 @@ const _Boiler_Type Boiler_Types[] = { {EMS_MODEL_UBA, 203, "Buderus Logamax U122/Junkers Cerapur"}, {EMS_MODEL_UBA, 208, "Buderus Logamax plus/GB192"}, {EMS_MODEL_UBA, 64, "Sieger BK15/Nefit Smartline/Buderus GB152"}, - {EMS_MODEL_UBA, EMS_PRODUCTID_HEATRONICS, "Bosch Condens 2500/Junkers Heatronics3"}, // Junkers + {EMS_MODEL_UBA, EMS_PRODUCTID_HEATRONICS, "Bosch Condens 2500/Junkers Heatronics3"}, {EMS_MODEL_UBA, 122, "Nefit Proline"}, {EMS_MODEL_UBA, 172, "Nefit Enviline"} @@ -170,7 +170,7 @@ const _Boiler_Type Boiler_Types[] = { /* * Known Solar Module types */ -const _SolarModule_Type SolarModule_Types[] = { +const _SolarModule_Type SolarModule_Types[] = { {EMS_MODEL_OTHER, EMS_PRODUCTID_SM10, EMS_ID_SM, "SM10 Solar Module"}, {EMS_MODEL_OTHER, EMS_PRODUCTID_SM100, EMS_ID_SM, "SM100 Solar Module"}, @@ -193,8 +193,9 @@ const _Other_Type Other_Types[] = { {EMS_MODEL_OTHER, 125, 0x09, "BC25 Base Controller"}, {EMS_MODEL_OTHER, 152, 0x09, "Junkers Controller"}, {EMS_MODEL_OTHER, 205, 0x02, "Nefit Moduline Easy Connect"}, + {EMS_MODEL_EASY, 206, 0x02, "Bosch Easy Connect"}, {EMS_MODEL_OTHER, 171, 0x02, "EMS-OT OpenTherm converter"}, - {EMS_MODEL_OTHER, 252, EMS_ID_HP, "HeatPump Module"}, // warning, fake product id! + {EMS_MODEL_OTHER, 252, EMS_ID_HP, "HeatPump Module"}, {EMS_MODEL_OTHER, 189, EMS_ID_GATEWAY, "Web Gateway KM200"} }; @@ -205,10 +206,9 @@ const _Other_Type Other_Types[] = { const _Thermostat_Type Thermostat_Types[] = { // Easy devices - not currently supporting write operations - {EMS_MODEL_EASY, 202, 0x18, "Logamatic TC100/Nefit Easy", EMS_THERMOSTAT_WRITE_NO}, + {EMS_MODEL_EASY, 202, 0x18, "Logamatic TC100/Nefit Moduline Easy", EMS_THERMOSTAT_WRITE_NO}, {EMS_MODEL_EASY, 203, 0x18, "Bosch EasyControl CT200", EMS_THERMOSTAT_WRITE_NO}, - {EMS_MODEL_EASY, 206, 0x02, "Bosch Easy", EMS_THERMOSTAT_WRITE_NO}, - {EMS_MODEL_CW100, 157, 0x18, "CW100", EMS_THERMOSTAT_WRITE_NO}, + {EMS_MODEL_CW100, 157, 0x18, "Bosch CW100", EMS_THERMOSTAT_WRITE_NO}, // Buderus/Nefit {EMS_MODEL_RC10, 79, 0x17, "RC10/Nefit Moduline 100", EMS_THERMOSTAT_WRITE_YES}, @@ -229,5 +229,4 @@ const _Thermostat_Type Thermostat_Types[] = { {EMS_MODEL_FR110, 108, 0x18, "Junkers FR110", EMS_THERMOSTAT_WRITE_NO}, {EMS_MODEL_FW120, 192, 0x10, "Junkers FW120", EMS_THERMOSTAT_WRITE_NO} - }; From 0b0f65c841748963273ae473c1162ef52ab43773 Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 20 Jun 2019 09:30:42 +0200 Subject: [PATCH 17/89] auto formatting --- src/ems.cpp | 88 ++++++++++++++++++++++++++--------------------------- 1 file changed, 43 insertions(+), 45 deletions(-) diff --git a/src/ems.cpp b/src/ems.cpp index a41185152..93eb0c018 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -182,17 +182,17 @@ const _EMS_Type EMS_Types[] = { }; // calculate sizes of arrays at compile -uint8_t _EMS_Types_max = ArraySize(EMS_Types); // number of defined types -uint8_t _Boiler_Types_max = ArraySize(Boiler_Types); // number of boiler models -uint8_t _Solar_Module_Types_max = ArraySize(SolarModule_Types);// number of solar module types -uint8_t _Other_Types_max = ArraySize(Other_Types); // number of other ems devices -uint8_t _Thermostat_Types_max = ArraySize(Thermostat_Types); // number of defined thermostat types +uint8_t _EMS_Types_max = ArraySize(EMS_Types); // number of defined types +uint8_t _Boiler_Types_max = ArraySize(Boiler_Types); // number of boiler models +uint8_t _Solar_Module_Types_max = ArraySize(SolarModule_Types); // number of solar module types +uint8_t _Other_Types_max = ArraySize(Other_Types); // number of other ems devices +uint8_t _Thermostat_Types_max = ArraySize(Thermostat_Types); // number of defined thermostat types // these structs contain the data we store from the Boiler and Thermostat -_EMS_Boiler EMS_Boiler; // for boiler -_EMS_Thermostat EMS_Thermostat; // for thermostat +_EMS_Boiler EMS_Boiler; // for boiler +_EMS_Thermostat EMS_Thermostat; // for thermostat _EMS_SolarModule EMS_SolarModule; // for solar modules -_EMS_Other EMS_Other; // for other known EMS devices +_EMS_Other EMS_Other; // for other known EMS devices // CRC lookup table with poly 12 for faster checking const uint8_t ems_crc_table[] = {0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, 0x20, 0x22, 0x24, 0x26, @@ -308,16 +308,16 @@ void ems_init() { EMS_SolarModule.EnergyLastHour = EMS_VALUE_SHORT_NOTSET; EMS_SolarModule.EnergyToday = EMS_VALUE_SHORT_NOTSET; EMS_SolarModule.EnergyTotal = EMS_VALUE_SHORT_NOTSET; - EMS_SolarModule.device_id = EMS_ID_NONE; - EMS_SolarModule.model_id = EMS_MODEL_NONE; - EMS_SolarModule.product_id = EMS_ID_NONE; - + EMS_SolarModule.device_id = EMS_ID_NONE; + EMS_SolarModule.model_id = EMS_MODEL_NONE; + EMS_SolarModule.product_id = EMS_ID_NONE; + // Other EMS devices values - EMS_Other.HPModulation = EMS_VALUE_INT_NOTSET; - EMS_Other.HPSpeed = EMS_VALUE_INT_NOTSET; - EMS_Other.device_id = EMS_ID_NONE; - EMS_Other.model_id = EMS_MODEL_NONE; - EMS_Other.product_id = EMS_ID_NONE; + EMS_Other.HPModulation = EMS_VALUE_INT_NOTSET; + EMS_Other.HPSpeed = EMS_VALUE_INT_NOTSET; + EMS_Other.device_id = EMS_ID_NONE; + EMS_Other.model_id = EMS_MODEL_NONE; + EMS_Other.product_id = EMS_ID_NONE; // calculated values EMS_Boiler.tapwaterActive = EMS_VALUE_INT_NOTSET; // Hot tap water is on/off @@ -1306,10 +1306,10 @@ void _process_RCPLUSStatusMode(_EMS_RxTelegram * EMS_RxTelegram) { */ void _process_JunkersStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { if (EMS_RxTelegram->offset == 0) { - // e.g. for FR10: 90 00 FF 00 00 6F 03 01 00 BE 00 BF - // e.g. for FW100: 90 00 FF 00 00 6F 03 02 00 D7 00 DA F3 34 00 C4 - EMS_Thermostat.curr_roomTemp = _toShort(EMS_OFFSET_JunkersStatusMessage_curr); // value is * 10 - EMS_Thermostat.setpoint_roomTemp = _toShort(EMS_OFFSET_JunkersStatusMessage_setpoint); // value is * 10 + // e.g. for FR10: 90 00 FF 00 00 6F 03 01 00 BE 00 BF + // e.g. for FW100: 90 00 FF 00 00 6F 03 02 00 D7 00 DA F3 34 00 C4 + EMS_Thermostat.curr_roomTemp = _toShort(EMS_OFFSET_JunkersStatusMessage_curr); // value is * 10 + EMS_Thermostat.setpoint_roomTemp = _toShort(EMS_OFFSET_JunkersStatusMessage_setpoint); // value is * 10 } } @@ -1473,20 +1473,19 @@ void _process_HPMonitor2(_EMS_RxTelegram * EMS_RxTelegram) { * Junkers ISM1 Solar Module - type 0x0003 EMS+ for energy readings */ void _process_ISM1StatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { - if (EMS_RxTelegram->offset == 0) { - // e.g. B0 00 FF 00 00 03 32 00 00 00 00 13 00 D6 00 00 00 FB D0 F0 - EMS_SolarModule.collectorTemp = _toShort(4); // Collector Temperature - EMS_SolarModule.bottomTemp = _toShort(6); // Temperature Bottom of Solar Boiler - EMS_SolarModule.EnergyLastHour = _toShort(2) * 10; // Solar Energy produced in last hour - EMS_SolarModule.pump = _bitRead(8,0); // Solar pump on (1) or off (0) - // EMS_Other.SM = true; + // e.g. B0 00 FF 00 00 03 32 00 00 00 00 13 00 D6 00 00 00 FB D0 F0 + EMS_SolarModule.collectorTemp = _toShort(4); // Collector Temperature + EMS_SolarModule.bottomTemp = _toShort(6); // Temperature Bottom of Solar Boiler + EMS_SolarModule.EnergyLastHour = _toShort(2) * 10; // Solar Energy produced in last hour + EMS_SolarModule.pump = _bitRead(8, 0); // Solar pump on (1) or off (0) + // EMS_Other.SM = true; } if (EMS_RxTelegram->offset == 4) { - // e.g. B0 00 FF 04 00 03 02 E5 - EMS_SolarModule.collectorTemp = _toShort(0); // Collector Temperature - // EMS_Other.SM = true; + // e.g. B0 00 FF 04 00 03 02 E5 + EMS_SolarModule.collectorTemp = _toShort(0); // Collector Temperature + // EMS_Other.SM = true; } } @@ -1675,22 +1674,25 @@ void _process_Version(_EMS_RxTelegram * EMS_RxTelegram) { } if (typeFound) { - myDebug_P(PSTR("Solar Module found: %s (DeviceID:0x%02X ProductID:%d Version:%s)"), SolarModule_Types[i].model_string, SolarModule_Types[i].device_id, product_id, version); + myDebug_P(PSTR("Solar Module found: %s (DeviceID:0x%02X ProductID:%d Version:%s)"), + SolarModule_Types[i].model_string, + SolarModule_Types[i].device_id, + product_id, + version); // add to list _addDevice(product_id, SolarModule_Types[i].device_id, version, SolarModule_Types[i].model_string); // EMS_Other.SM = true; // we have detected a Solar Module (SM10, SM100, ISM1 ...) myDebug_P(PSTR("Solar Module support enabled.")); - EMS_SolarModule.model_id = Other_Types[i].model_id; - EMS_SolarModule.device_id = Other_Types[i].device_id; - EMS_SolarModule.product_id = product_id; + EMS_SolarModule.model_id = Other_Types[i].model_id; + EMS_SolarModule.device_id = Other_Types[i].device_id; + EMS_SolarModule.product_id = product_id; strlcpy(EMS_SolarModule.version, version, sizeof(EMS_SolarModule.version)); - + // fetch Solar Module values ems_getSolarModuleValues(); return; - } @@ -1714,12 +1716,11 @@ void _process_Version(_EMS_RxTelegram * EMS_RxTelegram) { if (Other_Types[i].device_id == EMS_ID_HP) { EMS_Other.HP = true; // we have detected a HP myDebug_P(PSTR("HeatPump support enabled.")); - EMS_Other.model_id = Other_Types[i].model_id; - EMS_Other.device_id = Other_Types[i].device_id; - EMS_Other.product_id = product_id; + EMS_Other.model_id = Other_Types[i].model_id; + EMS_Other.device_id = Other_Types[i].device_id; + EMS_Other.product_id = product_id; strlcpy(EMS_Other.version, version, sizeof(EMS_Other.version)); // fetch Solar Module values > not yet implemented - } return; @@ -1871,17 +1872,14 @@ void ems_getBoilerValues() { * Get other values from EMS devices */ void ems_getSolarModuleValues() { - uint8_t product_id = EMS_SolarModule.product_id; if (ems_getSolarModuleEnabled()) { if (product_id == EMS_PRODUCTID_SM10) { ems_doReadCommand(EMS_TYPE_SM10Monitor, EMS_ID_SM); // fetch all from SM10Monitor - } - else if (product_id == EMS_PRODUCTID_SM100) { + } else if (product_id == EMS_PRODUCTID_SM100) { ems_doReadCommand(EMS_TYPE_SM100Monitor, EMS_ID_SM); // fetch all from SM100Monitor } - } } From f2da43f7598670d12a822f4776619ad9238d19ca Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 20 Jun 2019 09:31:21 +0200 Subject: [PATCH 18/89] https://github.com/proddy/EMS-ESP/pull/135 --- src/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h b/src/version.h index 725125dc1..43d0fb49d 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.8.1b1" +#define APP_VERSION "1.8.1b2" #define APP_HOSTNAME "ems-esp" From 95a436c5f3f7d4a9b4bc0e971e0681315cec231c Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 20 Jun 2019 10:10:11 +0200 Subject: [PATCH 19/89] updates to 1.8.1 --- CHANGELOG.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f777ff531..1015b094e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [1.8.1dev] 2019-06-17 +## [1.8.1dev] 2019-06-20 ### Added @@ -13,9 +13,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Detecting unset values in the SPIFFS and setting default values +- Bosch Easy Connect wrongly classified as a thermostat + ### Changed -- `publish_wait` renamed to `publish_time`, a value of 0 means no sending to MQTT +- Improved handling of Solar Modules (thanks @Vuego123) +- `publish_wait` renamed to `publish_time`, a value of 0 means disabling all MQTT sending ## [1.8.0] 2019-06-15 From 22a91a11f1b577a68a88a87c0214ba248568a495 Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 20 Jun 2019 10:53:16 +0200 Subject: [PATCH 20/89] added devices --- README.md | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fa2bc1c2c..d0acb1539 100644 --- a/README.md +++ b/README.md @@ -10,14 +10,65 @@ The code is writen for the Espressif **ESP8266** microcontroller and supports a **An example of the Home Assistant integration:** -![ha](https://github.com/proddy/EMS-ESP/raw/dev/doc/home_assistant/ha.png) +![ha](https://github.com/proddy/EMS-ESP/raw/master/doc/home_assistant/ha.png) **Using BBQKees' [EMS Gateway](https://shop.hotgoodies.nl/ems/) circuit:** -| ![on boiler](https://github.com/proddy/EMS-ESP/raw/dev/doc/ems%20gateway/on-boiler.jpg) | ![kit](https://github.com/proddy/EMS-ESP/raw/dev/doc/ems%20gateway/ems-kit-2.jpg) | ![basic circuit](https://github.com/proddy/EMS-ESP/raw/dev/doc/ems%20gateway/ems-board-white.jpg) | +| ![on boiler](https://github.com/proddy/EMS-ESP/raw/master/doc/ems%20gateway/on-boiler.jpg) | ![kit](https://github.com/proddy/EMS-ESP/raw/master/doc/ems%20gateway/ems-kit-2.jpg) | ![basic circuit](https://github.com/proddy/EMS-ESP/raw/master/doc/ems%20gateway/ems-board-white.jpg) | | - | - | - | **Example of the EMS-ESP's telnet console:** -| ![telnet menu](https://github.com/proddy/EMS-ESP/raw/dev/doc/telnet/telnet_menu.jpg) | ![telnet menu](https://github.com/proddy/EMS-ESP/raw/dev/doc/telnet/telnet_stats.PNG) | +| ![telnet menu](https://github.com/proddy/EMS-ESP/raw/master/doc/telnet/telnet_menu.jpg) | ![telnet menu](https://github.com/proddy/EMS-ESP/raw/master/doc/telnet/telnet_stats.PNG) | | - | - | + +--- + +## The latest list of support EMS devices + +### Thermostats: + +* Sieger ES73 +* RC10/Nefit Moduline 100 +* RC20/Nefit Moduline 300 +* RC20F +* RC30/Nefit Moduline 400 +* RC35 (only a single HC) +* RC300/RC310 +* Nefit Moduline 1010 +* Junkers FR10 +* TC100/Nefit Easy (read-only) +* Bosch Easy (read-only) +* Bosch CW100 (read-only) + +### Boilers: + +* Buderus GB172/Nefit Trendline +* Nefit Topline Compact/Buderus GB162 +* Buderus Logamax U122 +* Buderus Logamax plus/GB192 +* Sieger BK15 Boiler/Nefit Smartline +* Bosch Condens 2500/Junkers Cerapur Comfort +* Nefit Proline + +### Solar Modules: + +* SM10 Solar Module +* SM100 Solar Module +* Junkers ISM1 Solar Module + +### Other devices: + +* MM10 Mixer Module +* MC10 Module +* WM10 Switch Module +* MM100 Mixing Module +* MM100 Mixing Module +* BC10/RFM20 Receiver +* BC10 Base Controller +* BC25 Base Controller +* Nefit Moduline Easy Connect +* Bosch Easy Connect +* EMS-OT OpenTherm converter +* Web Gateway KM200 +* HeatPump Module From 4b28a1d9b532700332129c7a9740e415604beab0 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 23 Jun 2019 23:55:16 +0200 Subject: [PATCH 21/89] add check for max telegram length --- src/emsuart.cpp | 20 +++++--------------- src/emsuart.h | 2 +- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/src/emsuart.cpp b/src/emsuart.cpp index 0afcccd56..8f52e7c72 100644 --- a/src/emsuart.cpp +++ b/src/emsuart.cpp @@ -67,9 +67,9 @@ static void ICACHE_FLASH_ATTR emsuart_recvTask(os_event_t * events) { // validate and transmit the EMS buffer, excluding the BRK if (length == 2) { - // it's a poll or status code, single byte + // it's a poll or status code, single byte and ok to send on ems_parseTelegram((uint8_t *)pCurrent->buffer, 1); - } else if ((length > 4) && (pCurrent->buffer[length - 2] != 0x00)) { + } else if ((length > 4) && (length <= EMS_MAXBUFFERSIZE) && (pCurrent->buffer[length - 2] != 0x00)) { // ignore double BRK at the end, possibly from the Tx loopback // also telegrams with no data value ems_parseTelegram((uint8_t *)pCurrent->buffer, length - 1); // transmit EMS buffer, excluding the BRK @@ -159,16 +159,6 @@ void ICACHE_FLASH_ATTR emsuart_start() { ETS_UART_INTR_ENABLE(); } -/* - * set loopback mode and clear Tx/Rx FIFO - */ -static inline void ICACHE_FLASH_ATTR emsuart_loopback(bool enable) { - if (enable) - USC0(EMSUART_UART) |= (1 << UCLBE); // enable loopback - else - USC0(EMSUART_UART) &= ~(1 << UCLBE); // disable loopback -} - /* * Send to Tx, ending with a */ @@ -205,7 +195,7 @@ void ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) { // worst case, we'll see an additional Rx-BRK... if (!(USIS(EMSUART_UART) & (1 << UIBD))) { // no bus collision - send terminating BRK signal - emsuart_loopback(true); + USC0(EMSUART_UART) |= (1 << UCLBE); // enable loopback USC0(EMSUART_UART) |= (1 << UCBRK); // set // wait until BRK detected... @@ -215,8 +205,8 @@ void ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) { USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear - USIC(EMSUART_UART) = (1 << UIBD); // clear BRK detect IRQ - emsuart_loopback(false); // disable loopback mode + USIC(EMSUART_UART) = (1 << UIBD); // clear BRK detect IRQ + USC0(EMSUART_UART) &= ~(1 << UCLBE); // disable loopback } ETS_UART_INTR_ENABLE(); // receive anything from FIFO... diff --git a/src/emsuart.h b/src/emsuart.h index cd57cd4da..e59d72024 100644 --- a/src/emsuart.h +++ b/src/emsuart.h @@ -13,7 +13,7 @@ #define EMSUART_CONFIG 0x1C // 8N1 (8 bits, no stop bits, 1 parity) #define EMSUART_BAUD 9600 // uart baud rate for the EMS circuit -#define EMS_MAXBUFFERS 10 // buffers for circular filling to avoid collisions +#define EMS_MAXBUFFERS 5 // buffers for circular filling to avoid collisions #define EMS_MAXBUFFERSIZE 32 // max size of the buffer. packets are max 32 bytes to support EMS 1.0 #define EMSUART_BIT_TIME 104 // bit time @9600 baud From 9c4e2b5da094f1965c446b2190961fb9addb388b Mon Sep 17 00:00:00 2001 From: Vuego123 Date: Sun, 23 Jun 2019 23:57:57 +0200 Subject: [PATCH 22/89] SolarLoggingOnly&Bugfix - Added solar only logging option - Added a callback message to set the setpoint of the maximum solar boiler temperature. -fixed bug with wrong device_id for solar --- src/ems-esp.cpp | 7 +++++- src/ems.cpp | 54 +++++++++++++++++++++++++++++++++++------------ src/ems.h | 2 ++ src/ems_devices.h | 3 +++ 4 files changed, 51 insertions(+), 15 deletions(-) diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index 950b19802..a13d2bf68 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -323,6 +323,8 @@ void showInfo() { myDebug_P(PSTR(" System logging set to Verbose")); } else if (sysLog == EMS_SYS_LOGGING_THERMOSTAT) { myDebug_P(PSTR(" System logging set to Thermostat only")); + } else if (sysLog == EMS_SYS_LOGGING_SOLARMODULE ) { + myDebug_P(PSTR(" System logging set to Solar Module only")); } else { myDebug_P(PSTR(" System logging set to None")); } @@ -1298,7 +1300,10 @@ void TelnetCommandCallback(uint8_t wc, const char * commandLine) { } else if (strcmp(second_cmd, "t") == 0) { ems_setLogging(EMS_SYS_LOGGING_THERMOSTAT); ok = true; - } else if (strcmp(second_cmd, "r") == 0) { + } else if (strcmp(second_cmd, "s") == 0) { + ems_setLogging(EMS_SYS_LOGGING_SOLARMODULE ); + ok = true; + }else if (strcmp(second_cmd, "r") == 0) { ems_setLogging(EMS_SYS_LOGGING_RAW); ok = true; } else if (strcmp(second_cmd, "n") == 0) { diff --git a/src/ems.cpp b/src/ems.cpp index 93eb0c018..4b1906a56 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -63,6 +63,7 @@ void _process_SM100Energy(_EMS_RxTelegram * EMS_RxTelegram); // ISM1 void _process_ISM1StatusMessage(_EMS_RxTelegram * EMS_RxTelegram); +void _process_ISM1Set(_EMS_RxTelegram * EMS_RxTelegram); // HeatPump HP void _process_HPMonitor1(_EMS_RxTelegram * EMS_RxTelegram); @@ -129,6 +130,8 @@ const _EMS_Type EMS_Types[] = { {EMS_MODEL_OTHER, EMS_TYPE_HPMonitor1, "HeatPumpMonitor1", _process_HPMonitor1}, {EMS_MODEL_OTHER, EMS_TYPE_HPMonitor2, "HeatPumpMonitor2", _process_HPMonitor2}, {EMS_MODEL_OTHER, EMS_TYPE_ISM1StatusMessage, "ISM1StatusMessage", _process_ISM1StatusMessage}, + {EMS_MODEL_OTHER, EMS_TYPE_ISM1Set, "ISM1Set", _process_ISM1Set}, + // RC10 {EMS_MODEL_RC10, EMS_TYPE_RCTime, "RCTime", _process_RCTime}, @@ -301,16 +304,17 @@ void ems_init() { EMS_Boiler.pump_mod_min = EMS_VALUE_INT_NOTSET; // Boiler circuit pump modulation min. power // Solar Module values - EMS_SolarModule.collectorTemp = EMS_VALUE_SHORT_NOTSET; // collector temp from SM10/SM100 - EMS_SolarModule.bottomTemp = EMS_VALUE_SHORT_NOTSET; // bottom temp from SM10/SM100 - EMS_SolarModule.pumpModulation = EMS_VALUE_INT_NOTSET; // modulation solar pump SM10/SM100 - EMS_SolarModule.pump = EMS_VALUE_INT_NOTSET; // pump active - EMS_SolarModule.EnergyLastHour = EMS_VALUE_SHORT_NOTSET; - EMS_SolarModule.EnergyToday = EMS_VALUE_SHORT_NOTSET; - EMS_SolarModule.EnergyTotal = EMS_VALUE_SHORT_NOTSET; - EMS_SolarModule.device_id = EMS_ID_NONE; - EMS_SolarModule.model_id = EMS_MODEL_NONE; - EMS_SolarModule.product_id = EMS_ID_NONE; + EMS_SolarModule.collectorTemp = EMS_VALUE_SHORT_NOTSET; // collector temp from SM10/SM100 + EMS_SolarModule.bottomTemp = EMS_VALUE_SHORT_NOTSET; // bottom temp from SM10/SM100 + EMS_SolarModule.pumpModulation = EMS_VALUE_INT_NOTSET; // modulation solar pump SM10/SM100 + EMS_SolarModule.pump = EMS_VALUE_INT_NOTSET; // pump active + EMS_SolarModule.setpoint_maxBottomTemp = EMS_VALUE_SHORT_NOTSET; //setpoint for maximum solar boiler temperature + EMS_SolarModule.EnergyLastHour = EMS_VALUE_SHORT_NOTSET; + EMS_SolarModule.EnergyToday = EMS_VALUE_SHORT_NOTSET; + EMS_SolarModule.EnergyTotal = EMS_VALUE_SHORT_NOTSET; + EMS_SolarModule.device_id = EMS_ID_NONE; + EMS_SolarModule.model_id = EMS_MODEL_NONE; + EMS_SolarModule.product_id = EMS_ID_NONE; // Other EMS devices values EMS_Other.HPModulation = EMS_VALUE_INT_NOTSET; @@ -422,11 +426,13 @@ void ems_setLogging(_EMS_SYS_LOGGING loglevel) { myDebug_P(PSTR("System Logging set to Verbose")); } else if (loglevel == EMS_SYS_LOGGING_THERMOSTAT) { myDebug_P(PSTR("System Logging set to Thermostat only")); - } else if (loglevel == EMS_SYS_LOGGING_RAW) { + } else if (loglevel == EMS_SYS_LOGGING_SOLARMODULE) { + myDebug_P(PSTR("System Logging set to Solar Module only")); + }else if (loglevel == EMS_SYS_LOGGING_RAW) { myDebug_P(PSTR("System Logging set to Raw mode")); } } -} +} /** * Calculate CRC checksum using lookup table for speed @@ -886,12 +892,18 @@ void _printMessage(_EMS_RxTelegram * EMS_RxTelegram) { if ((src == EMS_Thermostat.device_id) || (dest == EMS_Thermostat.device_id)) { _debugPrintTelegram(output_str, EMS_RxTelegram, color_s); } + } else if (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_SOLARMODULE) { + // only print ones to/from thermostat if logging is set to thermostat only + if ((src == EMS_SolarModule.device_id) || (dest == EMS_SolarModule.device_id)) { + _debugPrintTelegram(output_str, EMS_RxTelegram, color_s); + } } else { // always print _debugPrintTelegram(output_str, EMS_RxTelegram, color_s); } } + /** * print detailed telegram * and then call its callback if there is one defined @@ -1489,6 +1501,20 @@ void _process_ISM1StatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { } } + +/* + * Junkers ISM1 Solar Module - type 0x0001 EMS+ for setting values + */ +void _process_ISM1Set(_EMS_RxTelegram * EMS_RxTelegram) { + + + if (EMS_RxTelegram->offset == 6) { + // e.g. 90 30 FF 06 00 01 50 (CRC=2C) + // to implement: change max solar boiler temperature + EMS_SolarModule.setpoint_maxBottomTemp = _toByte(0); + } +} + /** * UBASetPoint 0x1A */ @@ -1685,8 +1711,8 @@ void _process_Version(_EMS_RxTelegram * EMS_RxTelegram) { // EMS_Other.SM = true; // we have detected a Solar Module (SM10, SM100, ISM1 ...) myDebug_P(PSTR("Solar Module support enabled.")); - EMS_SolarModule.model_id = Other_Types[i].model_id; - EMS_SolarModule.device_id = Other_Types[i].device_id; + EMS_SolarModule.model_id = SolarModule_Types[i].model_id; + EMS_SolarModule.device_id = SolarModule_Types[i].device_id; EMS_SolarModule.product_id = product_id; strlcpy(EMS_SolarModule.version, version, sizeof(EMS_SolarModule.version)); diff --git a/src/ems.h b/src/ems.h index 63680b903..d4a158879 100644 --- a/src/ems.h +++ b/src/ems.h @@ -83,6 +83,7 @@ typedef enum { EMS_SYS_LOGGING_RAW, // raw data mode EMS_SYS_LOGGING_BASIC, // only basic read/write messages EMS_SYS_LOGGING_THERMOSTAT, // only telegrams sent from thermostat + EMS_SYS_LOGGING_SOLARMODULE, // only telegrams sent from thermostat EMS_SYS_LOGGING_VERBOSE // everything } _EMS_SYS_LOGGING; @@ -270,6 +271,7 @@ typedef struct { int16_t bottomTemp; // bottom temp uint8_t pumpModulation; // modulation solar pump uint8_t pump; // pump active + int16_t setpoint_maxBottomTemp; // setpoint for maximum collector temp int16_t EnergyLastHour; int16_t EnergyToday; int16_t EnergyTotal; diff --git a/src/ems_devices.h b/src/ems_devices.h index eb20985fa..fc02e8395 100644 --- a/src/ems_devices.h +++ b/src/ems_devices.h @@ -48,7 +48,10 @@ #define EMS_TYPE_SM100Energy 0x028E // SM100Energy #define EMS_TYPE_HPMonitor1 0xE3 // HeatPump Monitor 1 #define EMS_TYPE_HPMonitor2 0xE5 // HeatPump Monitor 2 + #define EMS_TYPE_ISM1StatusMessage 0x0003 // Solar Module Junkers ISM1 Status +#define EMS_TYPE_ISM1Set 0x0001 // for setting values of the solar module like max boiler temp +#define EMS_OFFSET_ISM1Set_MaxBoilerTemp 6 // position of max boiler temp e.g. 50 in the following example: 90 30 FF 06 00 01 50 (CRC=2C) /* * Thermostats... From bdf18b091d6d939a3d34fea67c7c41896387bc0a Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 24 Jun 2019 23:40:01 +0200 Subject: [PATCH 23/89] support for web server and reset firmware option --- CHANGELOG.md | 4 +- lib/MyESP/MyESP.cpp | 398 +++++++++++++++++++++++++++++------- lib/MyESP/MyESP.h | 107 ++++++++-- lib/TelnetSpy/TelnetSpy.cpp | 1 + src/ems-esp.cpp | 57 +++++- src/ems.cpp | 17 ++ src/ems.h | 25 +-- src/version.h | 2 +- 8 files changed, 492 insertions(+), 119 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1015b094e..56358d8ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,11 +5,13 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [1.8.1dev] 2019-06-20 +## [1.8.1dev] 2019-06-24 ### Added - Added back -DCRASH in Debug build target for capturing any ESP8266 stack dumps during crashes +- Web Interface, for checking stats and setting wifi credentials. See wiki for more details. +- reset firmware option. If the reset button on the ESP is pressed during boot up sequence (the LED is flashing very fast) all settings are erased and goes into AP mode. ### Fixed diff --git a/lib/MyESP/MyESP.cpp b/lib/MyESP/MyESP.cpp index b552132b5..de12cf146 100644 --- a/lib/MyESP/MyESP.cpp +++ b/lib/MyESP/MyESP.cpp @@ -1,7 +1,7 @@ /* * MyESP - my ESP helper class to handle WiFi, MQTT and Telnet * - * Paul Derbyshire - December 2018 + * Paul Derbyshire - first revision: December 2018 * * Ideas borrowed from Espurna https://github.com/xoseperez/espurna */ @@ -14,9 +14,10 @@ EEPROM_Rotate EEPROMr; union system_rtcmem_t { struct { - uint8_t stability_counter; - uint8_t reset_reason; - uint16_t _reserved_; + uint8_t stability_counter; + uint8_t reset_reason; + uint8_t boot_status; + uint8_t _reserved_; } parts; uint32_t value; }; @@ -41,10 +42,12 @@ MyESP::MyESP() { _fs_callback = NULL; _fs_settings_callback = NULL; + _web_callback = NULL; + _helpProjectCmds = NULL; _helpProjectCmds_count = 0; - _use_serial = false; + _serial = false; _heartbeat = false; _mqtt_host = NULL; _mqtt_password = NULL; @@ -61,6 +64,8 @@ MyESP::MyESP() { _mqtt_last_connection = 0; _mqtt_connecting = false; + _firstInstall = false; + _wifi_password = NULL; _wifi_ssid = NULL; _wifi_callback = NULL; @@ -137,7 +142,7 @@ void MyESP::myDebug_P(PGM_P format_P, ...) { // use Serial? bool MyESP::getUseSerial() { - return (_use_serial); + return (_serial); } // heartbeat @@ -191,7 +196,7 @@ void MyESP::_wifiCallback(justwifi_messages_t code, char * parameter) { _wifi_connected = true; // finally if we don't want Serial anymore, turn it off - if (!_use_serial) { + if (!_serial) { myDebug_P(PSTR("Disabling serial port communication.")); SerialAndTelnet.flush(); // flush so all buffer is printed to serial SerialAndTelnet.setSerial(NULL); @@ -213,14 +218,6 @@ void MyESP::_wifiCallback(justwifi_messages_t code, char * parameter) { myDebug_P(PSTR("[WIFI] IP %s"), WiFi.softAPIP().toString().c_str()); myDebug_P(PSTR("[WIFI] MAC %s"), WiFi.softAPmacAddress().c_str()); - // we could be in panic mode so enable Serial again - if (!_use_serial) { - SerialAndTelnet.setSerial(&Serial); - _use_serial = true; - } - - myDebug_P(PSTR("Enabling serial port output")); - // call any final custom settings if (_wifi_callback) { _wifi_callback(); @@ -326,7 +323,7 @@ void MyESP::_mqttOnMessage(char * topic, char * payload, size_t len) { // Restart the device if (strcmp(topic, MQTT_TOPIC_RESTART) == 0) { myDebug_P(PSTR("[MQTT] Received restart command"), message); - myESP.resetESP(); + resetESP(); return; } @@ -334,7 +331,7 @@ void MyESP::_mqttOnMessage(char * topic, char * payload, size_t len) { // for example with HA it sends the system time from the server if (strcmp(topic, MQTT_TOPIC_START) == 0) { myDebug_P(PSTR("[MQTT] Received boottime: %s"), message); - myESP.setBoottime(message); + setBoottime(message); return; } @@ -487,7 +484,7 @@ void MyESP::_ota_setup() { ArduinoOTA.onStart([this]() { _OTACallback(); }); ArduinoOTA.onEnd([this]() { myDebug_P(PSTR("[OTA] Done, restarting...")); - _deferredReset(100, CUSTOM_RESET_OTA); + _deferredReset(500, CUSTOM_RESET_OTA); }); ArduinoOTA.onProgress([this](unsigned int progress, unsigned int total) { @@ -551,13 +548,7 @@ void MyESP::_telnetConnected() { uint32_t crash_time; EEPROMr.get(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_CRASH_TIME, crash_time); if ((crash_time != 0) && (crash_time != 0xFFFFFFFF)) { - crashDump(); - /* - // clear crash data - crash_time = 0xFFFFFFFF; - EEPROMr.put(SAVE_CRASH_EEPROM_OFFSET + SAVE_CRASH_CRASH_TIME, crash_time); - EEPROMr.commit(); - */ + myDebug_P(PSTR("[SYSTEM] There is stack data available from the last system crash. Use 'crash dump' to view and 'crash clear' to reset")); } #endif @@ -692,7 +683,7 @@ void MyESP::_printSetCommands() { } myDebug_P(PSTR("")); // newline - myDebug_P(PSTR(" serial=%s"), (_use_serial) ? "on" : "off"); + myDebug_P(PSTR(" serial=%s"), (_serial) ? "on" : "off"); myDebug_P(PSTR(" heartbeat=%s"), (_heartbeat) ? "on" : "off"); // print any custom settings @@ -704,7 +695,7 @@ void MyESP::_printSetCommands() { // reset / restart void MyESP::resetESP() { myDebug_P(PSTR("* Reboot ESP...")); - _deferredReset(100, CUSTOM_RESET_TERMINAL); + _deferredReset(500, CUSTOM_RESET_TERMINAL); end(); #if defined(ARDUINO_ARCH_ESP32) ESP.restart(); @@ -781,16 +772,16 @@ bool MyESP::_changeSetting(uint8_t wc, const char * setting, const char * value) ok = true; } else if (strcmp(setting, "serial") == 0) { - ok = true; - _use_serial = false; + ok = true; + _serial = false; if (value) { if (strcmp(value, "on") == 0) { - _use_serial = true; - ok = true; + _serial = true; + ok = true; myDebug_P(PSTR("Reboot ESP to activate Serial mode.")); } else if (strcmp(value, "off") == 0) { - _use_serial = false; - ok = true; + _serial = false; + ok = true; myDebug_P(PSTR("Reboot ESP to deactivate Serial mode.")); } else { ok = false; @@ -842,10 +833,10 @@ void MyESP::setUseSerial(bool toggle) { if (toggle) { SerialAndTelnet.setSerial(&Serial); - _use_serial = true; + _serial = true; } else { SerialAndTelnet.setSerial(NULL); - _use_serial = false; + _serial = false; } } @@ -987,12 +978,26 @@ unsigned long MyESP::_getUptime() { return uptime_seconds; } -// reason code +// init RTC mem void MyESP::_rtcmemInit() { memset((uint32_t *)RTCMEM_ADDR, 0, sizeof(uint32_t) * RTCMEM_BLOCKS); Rtcmem->magic = RTCMEM_MAGIC; } +uint8_t MyESP::getSystemBootStatus() { + system_rtcmem_t data; + data.value = Rtcmem->sys; + return data.parts.boot_status; +} + +void MyESP::_setSystemBootStatus(uint8_t status) { + system_rtcmem_t data; + data.value = Rtcmem->sys; + data.parts.boot_status = status; + Rtcmem->sys = data.value; + // myDebug("*** setting boot status to %d", data.parts.boot_status); +} + uint8_t MyESP::_getSystemStabilityCounter() { system_rtcmem_t data; data.value = Rtcmem->sys; @@ -1019,6 +1024,7 @@ void MyESP::_setSystemResetReason(uint8_t reason) { Rtcmem->sys = data.value; } +// system_get_rst_info() result is cached by the Core init for internal use uint32_t MyESP::getSystemResetReason() { return resetInfo.reason; } @@ -1034,14 +1040,26 @@ void MyESP::_setCustomResetReason(uint8_t reason) { _setSystemResetReason(reason); } -// returns false if not set and needs to be intialized +// returns false if not set and needs to be intialized, causing all rtcmem data to be wiped bool MyESP::_rtcmemStatus() { bool readable; - switch (getSystemResetReason()) { - case REASON_EXT_SYS_RST: - case REASON_WDT_RST: - case REASON_DEFAULT_RST: + uint32_t reason = getSystemResetReason(); + + // the last reset could have been caused by manually pressing the reset button + // so before wiping, capture the boot sequence + if (reason == REASON_EXT_SYS_RST) { // external system reset + if (getSystemBootStatus() == MYESP_BOOTSTATUS_BOOTING) { + _setSystemBootStatus(MYESP_BOOTSTATUS_RESETNEEDED); + } else { + _setSystemBootStatus(MYESP_BOOTSTATUS_POWERON); + } + } + + switch (reason) { + //case REASON_EXT_SYS_RST: // external system reset + case REASON_WDT_RST: // hardware watch dog reset + case REASON_DEFAULT_RST: // normal startup by power on readable = false; break; default: @@ -1071,12 +1089,13 @@ uint8_t MyESP::_getCustomResetReason() { } void MyESP::_deferredReset(unsigned long delaytime, uint8_t reason) { - delay(delaytime); + _setSystemBootStatus(MYESP_BOOTSTATUS_POWERON); _setCustomResetReason(reason); + delay(delaytime); } -// Call this method on boot with start=true to increase the crash counter -// Call it again once the system is stable to decrease the counter +// Call this method on boot with stable=true to reset the crash counter +// Each call increments the counter // If the counter reaches SYSTEM_CHECK_MAX then the system is flagged as unstable void MyESP::_setSystemCheck(bool stable) { uint8_t value = 0; @@ -1095,17 +1114,25 @@ void MyESP::_setSystemCheck(bool stable) { if (++value > SYSTEM_CHECK_MAX) { _systemStable = false; value = 0; // system is unstable - myDebug_P(PSTR("[SYSTEM] Warning, system UNSTABLE\n")); + myDebug_P(PSTR("[SYSTEM] Warning, system UNSTABLE. Serial mode is enabled.")); + + // enable Serial again + if (!_serial) { + SerialAndTelnet.setSerial(&Serial); + _serial = true; + } } } _setSystemStabilityCounter(value); } -bool MyESP::getSystemCheck() { +// return if system is stable (false=bad) +bool MyESP::_getSystemCheck() { return _systemStable; } +// periodically check if system is stable void MyESP::_systemCheckLoop() { static bool checked = false; if (!checked && (millis() > SYSTEM_CHECK_TIME)) { @@ -1144,7 +1171,7 @@ void MyESP::showSystemStats() { myDebug_P(PSTR(" [APP] System Load: %d%%"), getSystemLoadAverage()); - if (!getSystemCheck()) { + if (!_getSystemCheck()) { myDebug_P(PSTR(" [SYSTEM] Device is in SAFE MODE")); } @@ -1158,6 +1185,12 @@ void MyESP::showSystemStats() { myDebug_P(PSTR(" [WIFI] WiFi MAC: %s"), WiFi.macAddress().c_str()); + if (isMQTTConnected()) { + myDebug_P(PSTR(" [MQTT] connected (heartbeat %s)"), getHeartbeat() ? "enabled" : "disabled"); + } else { + myDebug_P(PSTR(" [MQTT] disconnected")); + } + #ifdef CRASH char output_str[80] = {0}; char buffer[16] = {0}; @@ -1195,7 +1228,7 @@ void MyESP::showSystemStats() { } myDebug_P(PSTR(" [SYSTEM] Restart count: %d"), _getSystemStabilityCounter()); - myDebug_P(PSTR(" [SYSTEM] rtcmem status:%u blocks:%u addr:0x%p"), _rtcmemStatus(), RtcmemSize, Rtcmem); + myDebug_P(PSTR(" [SYSTEM] rtcmem status: blocks:%u addr:0x%p"), RtcmemSize, Rtcmem); for (uint8_t block = 0; block < RtcmemSize; ++block) { myDebug_P(PSTR(" [SYSTEM] rtcmem %02u: %u"), block, reinterpret_cast(RTCMEM_ADDR)[block]); } @@ -1289,7 +1322,7 @@ void MyESP::_telnetHandle() { if (charsRead > 0) { charsRead = 0; // is static, so have to reset _suspendOutput = false; - if (_use_serial) { + if (_serial) { SerialAndTelnet.serialPrint('\n'); // force newline if in Serial } _telnetCommand(_command); @@ -1378,14 +1411,14 @@ void MyESP::_mqttConnect() { // Setup everything we need void MyESP::setWIFI(const char * wifi_ssid, const char * wifi_password, wifi_callback_f callback) { // Check SSID too long or missing - if (!wifi_ssid || *wifi_ssid == 0x00 || strlen(wifi_ssid) > 31) { + if (!wifi_ssid || *wifi_ssid == 0x00 || strlen(wifi_ssid) > MAX_STR_LEN) { _wifi_ssid = NULL; } else { _wifi_ssid = strdup(wifi_ssid); } // Check PASS too long - if (!wifi_password || *wifi_ssid == 0x00 || strlen(wifi_password) > 31) { + if (!wifi_password || *wifi_ssid == 0x00 || strlen(wifi_password) > MAX_STR_LEN) { _wifi_password = NULL; } else { _wifi_password = strdup(wifi_password); @@ -1501,15 +1534,21 @@ void MyESP::_fs_printConfig() { // format File System void MyESP::_fs_eraseConfig() { - myDebug_P(PSTR("[FS] Erasing settings, please wait a few seconds. ESP will " + myDebug_P(PSTR("[FS] Erasing all settings, please wait a few seconds. ESP will " "automatically restart when finished.")); - if (SPIFFS.format()) { + if (SPIFFS.remove(MYEMS_CONFIG_FILE)) { delay(1000); // wait 1 second - resetESP(); + SerialAndTelnet.flush(); + resetESP(); // hard reset } } +// custom callback for web info +void MyESP::setWeb(web_callback_f callback_web) { + _web_callback = callback_web; +} + void MyESP::setSettings(fs_callback_f callback_fs, fs_settings_callback_f callback_settings_fs) { _fs_callback = callback_fs; _fs_settings_callback = callback_settings_fs; @@ -1525,8 +1564,6 @@ bool MyESP::_fs_loadConfig() { return false; } else if (size == 0) { myDebug_P(PSTR("[FS] Failed to open config file")); - // file does not exist, so assume its the first install. Set serial to on - _use_serial = true; return false; } @@ -1558,10 +1595,13 @@ bool MyESP::_fs_loadConfig() { value = json["mqtt_password"]; _mqtt_password = (value) ? strdup(value) : NULL; - _use_serial = (bool)json["use_serial"]; // defaults to off + _serial = (bool)json["serial"]; // defaults to off + + // _serial = true; // uncomment for debugging everything to serial _heartbeat = (bool)json["heartbeat"]; // defaults to off + // callback for loading custom settings // ok is false if there's a problem loading a custom setting (e.g. does not exist) bool ok = (_fs_callback)(MYESP_FSACTION_LOAD, json); @@ -1589,7 +1629,7 @@ bool MyESP::fs_saveConfig() { json["mqtt_host"] = _mqtt_host; json["mqtt_username"] = _mqtt_username; json["mqtt_password"] = _mqtt_password; - json["use_serial"] = _use_serial; + json["serial"] = _serial; json["heartbeat"] = _heartbeat; // callback for saving custom settings @@ -1632,10 +1672,23 @@ void MyESP::_fs_setup() { return; } + // if its flagged as a first install, re-create the initial config file and quit function + if (_firstInstall) { + myDebug_P(PSTR("[FS] Re-creating config file for initial install")); + fs_saveConfig(); + return; + } + // load the config file. if it doesn't exist (function returns false) create it if (!_fs_loadConfig()) { //myDebug_P(PSTR("[FS] Re-creating config file")); fs_saveConfig(); + _firstInstall = true; // flag as a first install + } + + // assume if the wifi ssid is empty, its a fresh install too + if ((_wifi_ssid == NULL)) { + _firstInstall = true; // flag as a first install } // _fs_printConfig(); // enable for debugging @@ -1671,14 +1724,6 @@ bool MyESP::isMQTTConnected() { } // return true if wifi is connected -// WL_NO_SHIELD = 255, // for compatibility with WiFi Shield library -// WL_IDLE_STATUS = 0, -// WL_NO_SSID_AVAIL = 1, -// WL_SCAN_COMPLETED = 2, -// WL_CONNECTED = 3, -// WL_CONNECT_FAILED = 4, -// WL_CONNECTION_LOST = 5, -// WL_DISCONNECTED = 6 bool MyESP::isWifiConnected() { return (_wifi_connected); } @@ -1855,6 +1900,9 @@ void MyESP::crashDump() { myDebug_P(PSTR("\nTo clean this dump use the command: %scrash clear%s\n"), COLOR_BOLD_ON, COLOR_BOLD_OFF); } +/* + * Force some crashes to test if stack collection and debugging works + */ void MyESP::crashTest(uint8_t t) { if (t == 1) { myDebug_P(PSTR("[CRASH] Attempting to divide by zero ...")); @@ -1906,20 +1954,188 @@ void MyESP::crashInfo() { } #endif +// default home web page +void MyESP::_webRootPage() { + char s[1000] = {0}; + + strlcpy(s, webCommonPage_start, sizeof(s)); + + strlcat(s, "

", sizeof(s)); + strlcat(s, _app_name, sizeof(s)); + strlcat(s, " version ", sizeof(s)); + strlcat(s, _app_version, sizeof(s)); + strlcat(s, "

", sizeof(s)); + + strlcat(s, "

System stats:
", sizeof(s)); + strlcat(s, isMQTTConnected() ? " MQTT is connected\n" : " MQTT is disconnected\n", sizeof(s)); + strlcat(s, "
", sizeof(s)); + + // uptime + char buffer[200]; + uint32_t t = _getUptime(); // seconds + uint32_t d = t / 86400L; + uint32_t h = ((t % 86400L) / 3600L) % 60; + uint32_t rem = t % 3600L; + uint8_t m = rem / 60; + uint8_t sec = rem % 60; + sprintf(buffer, " System uptime: %d days %d hours %d minutes %d seconds
", d, h, m, sec); + strlcat(s, buffer, sizeof(s)); + + // memory + uint32_t total_memory = _getInitialFreeHeap(); + uint32_t free_memory = ESP.getFreeHeap(); + sprintf(buffer, " Memory: %d bytes free (%2u%%)
", free_memory, 100 * free_memory / total_memory); + strlcat(s, buffer, sizeof(s)); + + strlcat(s, "

", sizeof(s)); + if (_web_callback) { + char custom[MYESP_MAXCHARBUFFER]; + (_web_callback)(custom); + strlcat(s, custom, sizeof(s)); + } + strlcat(s, "


", sizeof(s)); + + // check why we're here + if ((_firstInstall) || (_wifi_ssid == NULL)) { + strlcat(s, "

Looks like a first install! Go here to connect the System to your network.

", sizeof(s)); + } else { + strlcat(s, "

Go here to connect the System to your wireless network.

", sizeof(s)); + } + + strlcat(s, webCommonPage_end, sizeof(s)); + webServer.sendHeader("Content-Length", String(strlen(s))); + webServer.send(200, "text/html", s); +} + +// Creates a webpage that allows the user to change the SSID and Password from the browser +void MyESP::_webResetPage() { + char s[1000] = {0}; + + strlcpy(s, webCommonPage_start, sizeof(s)); + + strlcat(s, "

", sizeof(s)); + strlcat(s, _app_name, sizeof(s)); + strlcat(s, " version ", sizeof(s)); + strlcat(s, _app_version, sizeof(s)); + strlcat(s, "

", sizeof(s)); + + // Check to see if we've been sent any arguments and instantly return if not + if (webServer.args() == 0) { + strlcat(s, "

", sizeof(s)); + + if (_wifi_ssid != NULL) { + strlcat(s, "Current wifi SSID is ", sizeof(s)); + strlcat(s, _wifi_ssid, sizeof(s)); + strlcat(s, ".
", sizeof(s)); + } + + strlcat(s, "
Please enter your new wifi credentials below.

", sizeof(s)); + + strlcat(s, webResetPage_form, sizeof(s)); + strlcat(s, webCommonPage_end, sizeof(s)); + webServer.sendHeader("Content-Length", String(strlen(s))); + webServer.send(200, "text/html", s); + + } else { + // Create a string containing all the arguments + // Check to see if there are new values (also doubles to check the length of the new value is long enough) + if (webServer.arg("newssid").length() < MAX_STR_LEN) { + if (webServer.arg("newssid").length() == 0) { + _wifi_ssid = NULL; + } else { + _wifi_ssid = strdup(webServer.arg("newssid").c_str()); + } + } + + if (webServer.arg("newpassword").length() < MAX_STR_LEN) { + if (webServer.arg("newpassword").length() == 0) { + _wifi_password = NULL; + } else { + _wifi_password = strdup(webServer.arg("newpassword").c_str()); + } + } + + // Store the new settings + fs_saveConfig(); + + // Reply with a web page to indicate success or failure + strlcat(s, webResetPage_post, sizeof(s)); + strlcat(s, webCommonPage_end, sizeof(s)); + webServer.sendHeader("Content-Length", String(strlen(s))); + webServer.send(200, "text/html", s); + + delay(500); + resetESP(); + } +} + +// reset all settings +void MyESP::_webResetAllPage() { + char s[1000] = {0}; + + strlcpy(s, webCommonPage_start, sizeof(s)); + + strlcat(s, "

", sizeof(s)); + strlcat(s, _app_name, sizeof(s)); + strlcat(s, " version ", sizeof(s)); + strlcat(s, _app_version, sizeof(s)); + strlcat(s, "

", sizeof(s)); + + // Check to see if we've been sent any arguments and instantly return if not + if (webServer.args() == 0) { + strlcat(s, + "

Are you absolutely sure you want to erase all settings?
Typing 'yes' will restart the System and you'll need to reconnect to the wifi " + "Access Point called ems-esp.

", + sizeof(s)); + + strlcat(s, webResetAllPage_form, sizeof(s)); + strlcat(s, webCommonPage_end, sizeof(s)); + webServer.sendHeader("Content-Length", String(strlen(s))); + webServer.send(200, "text/html", s); + } else { + // delete all settings + if (webServer.arg("confirm") == "yes") { + _fs_eraseConfig(); + delay(1000); // wait 1 sec + resetESP(); + } + } +} + +// set up web server +void MyESP::_webserver_setup() { + webServer.on("/", [this]() { _webRootPage(); }); + webServer.on("/reset", [this]() { _webResetPage(); }); + webServer.on("/resetall", [this]() { _webResetAllPage(); }); + + webServer.begin(); +} + // setup MyESP void MyESP::begin(const char * app_hostname, const char * app_name, const char * app_version) { _app_hostname = strdup(app_hostname); _app_name = strdup(app_name); _app_version = strdup(app_version); - _getInitialFreeHeap(); // get initial free mem + // set up onboard LED + pinMode(LED_BUILTIN, OUTPUT); + digitalWrite(LED_BUILTIN, HIGH); + + _getInitialFreeHeap(); // get initial free mem + _telnet_setup(); // Telnet setup, called first to set Serial + _rtcmemSetup(); // rtc internal mem setup + + if (getSystemBootStatus() == MYESP_BOOTSTATUS_RESETNEEDED) { + myDebug_P(PSTR("** resetting all settings")); + _firstInstall = true; // flag as an initial install so the config file will be recreated + } - _rtcmemSetup(); // rtc internal mem setup - _telnet_setup(); // Telnet setup, called first to set Serial _eeprom_setup(); // set up EEPROM for storing crash data, if compiled with -DCRASH - _fs_setup(); // SPIFFS setup, do this first to get values - _wifi_setup(); // WIFI setup - _ota_setup(); // init OTA + + _fs_setup(); // SPIFFS setup, do this first to get values + _wifi_setup(); // WIFI setup + _ota_setup(); // init OTA + _webserver_setup(); // init web server // print a welcome message myDebug_P(PSTR("\n* %s version %s"), _app_name, _app_version); @@ -1929,6 +2145,36 @@ void MyESP::begin(const char * app_hostname, const char * app_name, const char * _heartbeatCheck(true); // force heartbeat } +// bootup sequence +// quickly flash LED until we get a Wifi connection, or AP established +// fast way is to use WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + (state ? 4 : 8), (1 << EMSESP_Status.led_gpio)); // 4 is on, 8 is off +void MyESP::_bootupSequence() { + uint8_t boot_status = getSystemBootStatus(); + + if ((boot_status == MYESP_BOOTSTATUS_BOOTED) || (millis() <= MYESP_BOOTUP_DELAY)) { + return; // already booted, or still starting up + } + + // only kick in after a few seconds + if (boot_status == MYESP_BOOTSTATUS_POWERON) { + _setSystemBootStatus(MYESP_BOOTSTATUS_BOOTING); + } + + static uint32_t last_bootupflash = 0; + + // flash LED quickly + if ((millis() - last_bootupflash > MYESP_BOOTUP_FLASHDELAY)) { + last_bootupflash = millis(); + int state = digitalRead(LED_BUILTIN); + digitalWrite(LED_BUILTIN, !state); + } + + if (isWifiConnected()) { + _setSystemBootStatus(MYESP_BOOTSTATUS_BOOTED); // completed, reset flag + digitalWrite(LED_BUILTIN, LOW); // turn off LED + } +} + /* * Loop. This is called as often as possible and it handles wifi, telnet, mqtt etc */ @@ -1936,8 +2182,14 @@ void MyESP::loop() { _calculateLoad(); _systemCheckLoop(); _heartbeatCheck(); + _bootupSequence(); + webServer.handleClient(); // web server client requests + + // if we're in AP mode, use the web server, otherwise switch to telnet + if (!isAPmode()) { + _telnetHandle(); + } - _telnetHandle(); jw.loop(); // WiFi ArduinoOTA.handle(); // OTA _mqttConnect(); // MQTT diff --git a/lib/MyESP/MyESP.h b/lib/MyESP/MyESP.h index 79c13922c..082075edd 100644 --- a/lib/MyESP/MyESP.h +++ b/lib/MyESP/MyESP.h @@ -9,20 +9,23 @@ #ifndef MyEMS_h #define MyEMS_h -#define MYESP_VERSION "1.1.17" +#define MYESP_VERSION "1.1.18" #include #include #include // https://github.com/marvinroger/async-mqtt-client and for ESP32 see https://github.com/marvinroger/async-mqtt-client/issues/127 -#include +#include #include #include // https://github.com/xoseperez/justwifi #include // modified from https://github.com/yasheena/telnetspy +#ifdef CRASH #include +#endif + extern "C" { +void custom_crash_callback(struct rst_info *, uint32_t, uint32_t); #include "user_interface.h" -void custom_crash_callback(struct rst_info *, uint32_t, uint32_t); extern struct rst_info resetInfo; } @@ -38,10 +41,10 @@ extern struct rst_info resetInfo; #define MYEMS_CONFIG_FILE "/config.json" -#define LOADAVG_INTERVAL 30000 // Interval between calculating load average (in ms) +#define LOADAVG_INTERVAL 30000 // Interval between calculating load average (in ms) = 30 seconds // WIFI -#define WIFI_CONNECT_TIMEOUT 10000 // Connecting timeout for WIFI in ms +#define WIFI_CONNECT_TIMEOUT 10000 // Connecting timeout for WIFI in ms (10 seconds) #define WIFI_RECONNECT_INTERVAL 600000 // If could not connect to WIFI, retry after this time in ms. 10 minutes // MQTT @@ -143,12 +146,11 @@ PROGMEM const char * const custom_reset_string[] = {custom_reset_hardware, cus #define RTCMEM_OFFSET 32u #define RTCMEM_ADDR (RTCMEM_ADDR_BASE + (RTCMEM_OFFSET * 4u)) #define RTCMEM_BLOCKS 96u -#define RTCMEM_MAGIC 0x45535075 +#define RTCMEM_MAGIC 0x45535076 struct RtcmemData { - uint32_t magic; // RTCMEM_MAGIC - uint32_t sys; // system reset reason (1-4) - uint32_t energy; // store energy count + uint32_t magic; // RTCMEM_MAGIC + uint32_t sys; // system details }; static_assert(sizeof(RtcmemData) <= (RTCMEM_BLOCKS * 4u), "RTCMEM struct is too big"); @@ -165,6 +167,13 @@ typedef struct { typedef enum { MYESP_FSACTION_SET, MYESP_FSACTION_LIST, MYESP_FSACTION_SAVE, MYESP_FSACTION_LOAD } MYESP_FSACTION; +typedef enum { + MYESP_BOOTSTATUS_POWERON = 0, + MYESP_BOOTSTATUS_BOOTED = 1, + MYESP_BOOTSTATUS_BOOTING = 2, + MYESP_BOOTSTATUS_RESETNEEDED = 3 +} MYESP_BOOTSTATUS; // boot messages + typedef std::function mqtt_callback_f; typedef std::function wifi_callback_f; typedef std::function ota_callback_f; @@ -172,6 +181,7 @@ typedef std::function typedef std::function telnet_callback_f; typedef std::function fs_callback_f; typedef std::function fs_settings_callback_f; +typedef std::function web_callback_f; // calculates size of an 2d array at compile time template @@ -181,12 +191,46 @@ constexpr size_t ArraySize(T (&)[N]) { #define UPTIME_OVERFLOW 4294967295 // Uptime overflow value +// web min and max length of wifi ssid and password +#define MAX_STR_LEN 16 + +#define MYESP_BOOTUP_FLASHDELAY 50 // flash duration for LED at bootup sequence +#define MYESP_BOOTUP_DELAY 2000 // time before we open the window to reset. This is to stop resetting values when uploading firmware via USB + +// max size of char buffer for storing web page +#define MYESP_MAXCHARBUFFER 800 + +// Holds the admin webpage in the program memory +const char webCommonPage_start[] = "" + "" + "" + "" + ""; + +const char webCommonPage_end[] = ""; + +const char webResetPage_form[] = "
" + "" + "" + "" + "
"; + +const char webResetPage_post[] = "

New wifi credentials set. System is now rebooting. Please wait a few seconds and then reconnect via telnet or browser to its new IP given address.

"; + +const char webResetAllPage_form[] = "
" + "" + "" + "
"; + // class definition class MyESP { public: MyESP(); ~MyESP(); + ESP8266WebServer webServer; // Web server on port 80 + // wifi void setWIFICallback(void (*callback)()); void setWIFI(const char * wifi_ssid, const char * wifi_password, wifi_callback_f callback); @@ -224,6 +268,9 @@ class MyESP { void setSettings(fs_callback_f callback, fs_settings_callback_f fs_settings_callback); bool fs_saveConfig(); + // Web + void setWeb(web_callback_f callback_web); + // Crash void crashClear(); void crashDump(); @@ -241,6 +288,7 @@ class MyESP { bool getHeartbeat(); uint32_t getSystemLoadAverage(); uint32_t getSystemResetReason(); + uint8_t getSystemBootStatus(); private: // mqtt @@ -269,7 +317,6 @@ class MyESP { bool _rtcmem_status; // wifi - DNSServer dnsServer; // For Access Point (AP) support void _wifiCallback(justwifi_messages_t code, char * parameter); void _wifi_setup(); wifi_callback_f _wifi_callback; @@ -314,35 +361,45 @@ class MyESP { fs_settings_callback_f _fs_settings_callback; void _printSetCommands(); + // web + web_callback_f _web_callback; + // general char * _app_hostname; char * _app_name; char * _app_version; char * _boottime; bool _suspendOutput; - bool _use_serial; + bool _serial; bool _heartbeat; unsigned long _getUptime(); String _buildTime(); + bool _firstInstall; // reset reason and rtcmem - bool _rtcmemStatus(); - void _rtcmemInit(); - void _rtcmemSetup(); - void _deferredReset(unsigned long delay, uint8_t reason); + bool _rtcmemStatus(); + bool _getRtcmemStatus(); + + void _rtcmemInit(); + void _rtcmemSetup(); + + void _deferredReset(unsigned long delay, uint8_t reason); + uint8_t _getSystemStabilityCounter(); void _setSystemStabilityCounter(uint8_t counter); + void _setSystemResetReason(uint8_t reason); uint8_t _getCustomResetReason(); void _setCustomResetReason(uint8_t reason); - bool _systemStable; - - // rtcmem and reset reason - bool _getRtcmemStatus(); uint8_t _getSystemResetReason(); - bool getSystemCheck(); - void _systemCheckLoop(); - void _setSystemCheck(bool stable); + + void _setSystemBootStatus(uint8_t status); + + bool _systemStable; + void _bootupSequence(); + bool _getSystemCheck(); + void _systemCheckLoop(); + void _setSystemCheck(bool stable); // load average (0..100) and heap ram void _calculateLoad(); @@ -352,6 +409,12 @@ class MyESP { // heartbeat void _heartbeatCheck(bool force); + + // webserver + void _webserver_setup(); + void _webRootPage(); + void _webResetPage(); + void _webResetAllPage(); }; extern MyESP myESP; diff --git a/lib/TelnetSpy/TelnetSpy.cpp b/lib/TelnetSpy/TelnetSpy.cpp index 6acbf9c4a..85716a0d8 100644 --- a/lib/TelnetSpy/TelnetSpy.cpp +++ b/lib/TelnetSpy/TelnetSpy.cpp @@ -573,6 +573,7 @@ void TelnetSpy::handle() { return; } if (!listening) { + if ((WiFi.status() == WL_DISCONNECTED) && (WiFi.getMode() & WIFI_AP)) { if (usedSer) { usedSer->println("[TELNET] in AP mode"); // added by Proddy diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index 950b19802..0f9468a8d 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -41,7 +41,7 @@ DS18 ds18; Ticker publishValuesTimer; Ticker publishSensorValuesTimer; -#define SYSTEMCHECK_TIME 10 // every 10 seconds check if EMS can be reached +#define SYSTEMCHECK_TIME 30 // every 30 seconds check if EMS can be reached Ticker systemCheckTimer; #define REGULARUPDATES_TIME 60 // every minute a call is made to fetch data from EMS devices manually @@ -888,15 +888,15 @@ void do_publishSensorValues() { // call PublishValues without forcing, so using CRC to see if we really need to publish void do_publishValues() { // don't publish if we're not connected to the EMS bus - if ((ems_getBusConnected()) && (!myESP.getUseSerial()) && myESP.isMQTTConnected() && EMSESP_Status.publish_time != 0) { + if ((ems_getBusConnected()) && myESP.isMQTTConnected() && EMSESP_Status.publish_time != 0) { publishValues(true); // force publish } } // callback to light up the LED, called via Ticker every second -// fast way is to use WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + (state ? 4 : 8), (1 << EMSESP_Status.led_gpio)); // 4 is on, 8 is off +// when ESP is booting up, ignore this as the LED is being used for something else void do_ledcheck() { - if (EMSESP_Status.led) { + if ((EMSESP_Status.led) && (myESP.getSystemBootStatus() == MYESP_BOOTSTATUS_BOOTED)) { if (ems_getBusConnected()) { digitalWrite(EMSESP_Status.led_gpio, (EMSESP_Status.led_gpio == LED_BUILTIN) ? LOW : HIGH); // light on. For onboard LED high=off } else { @@ -908,7 +908,7 @@ void do_ledcheck() { // Thermostat scan void do_scanThermostat() { - if ((ems_getBusConnected()) && (!myESP.getUseSerial())) { + if (ems_getBusConnected()) { myDebug_P(PSTR("> Scanning thermostat message type #0x%02X..."), scanThermostat_count); ems_doReadCommand(scanThermostat_count, EMS_Thermostat.device_id); scanThermostat_count++; @@ -917,7 +917,7 @@ void do_scanThermostat() { // do a system health check every now and then to see if we all connections void do_systemCheck() { - if ((!ems_getBusConnected()) && (!myESP.getUseSerial())) { + if (!ems_getBusConnected()) { myDebug_P(PSTR("Error! Unable to read the EMS bus.")); } } @@ -925,7 +925,7 @@ void do_systemCheck() { // force calls to get data from EMS for the types that aren't sent as broadcasts // only if we have a EMS connection void do_regularUpdates() { - if ((ems_getBusConnected()) && (!myESP.getUseSerial())) { + if (ems_getBusConnected()) { myDebugLog("Requesting scheduled EMS device data"); ems_getThermostatValues(); ems_getBoilerValues(); @@ -954,7 +954,7 @@ void do_scanDevices() { return; } - if ((ems_getBusConnected()) && (!myESP.getUseSerial())) { + if (ems_getBusConnected()) { ems_doReadCommand(EMS_TYPE_Version, scanDevices_count++); // ask for version } } @@ -1526,6 +1526,40 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) { } } +// web information for diagnostics +void WebCallback(char * body) { + strlcpy(body, "EMS stats:
", MYESP_MAXCHARBUFFER); + + if (ems_getBusConnected()) { + char s[10]; + strlcat(body, "EMS Bus is connected
", MYESP_MAXCHARBUFFER); + strlcat(body, "Rx: # successful read requests=", MYESP_MAXCHARBUFFER); + strlcat(body, itoa(EMS_Sys_Status.emsRxPgks, s, 10), MYESP_MAXCHARBUFFER); + strlcat(body, ", # CRC errors=", MYESP_MAXCHARBUFFER); + strlcat(body, itoa(EMS_Sys_Status.emxCrcErr, s, 10), MYESP_MAXCHARBUFFER); + if (ems_getTxCapable()) { + strlcat(body, "
Tx: # successful write requests=", MYESP_MAXCHARBUFFER); + strlcat(body, itoa(EMS_Sys_Status.emsTxPkgs, s, 10), MYESP_MAXCHARBUFFER); + } else { + strlcat(body, "
Tx: no signal

", MYESP_MAXCHARBUFFER); + } + + // show device list + strlcpy(body, "EMS devices found:
", MYESP_MAXCHARBUFFER); + + char buffer[MYESP_MAXCHARBUFFER] = {0}; + uint8_t num_devices = ems_printDevices_s(buffer, MYESP_MAXCHARBUFFER); + if (num_devices == 0) { + strlcat(body, "no compatible EMS devices detected yet. (wait a few seconds)", MYESP_MAXCHARBUFFER); + } else { + strlcat(body, buffer, MYESP_MAXCHARBUFFER); + } + + } else { + strlcat(body, "Unable to establish a connection to the EMS Bus.", MYESP_MAXCHARBUFFER); + } +} + // Init callback, which is used to set functions and call methods after a wifi connection has been established void WIFICallback() { // This is where we enable the UART service to scan the incoming serial Tx/Rx bus signals @@ -1641,11 +1675,11 @@ void setup() { // call ems.cpp's init function to set all the internal params ems_init(); - systemCheckTimer.attach(SYSTEMCHECK_TIME, do_systemCheck); // check if Boiler is online + systemCheckTimer.attach(SYSTEMCHECK_TIME, do_systemCheck); // check if EMS is reachable // set up myESP for Wifi, MQTT, MDNS and Telnet myESP.setTelnet(project_cmds, ArraySize(project_cmds), TelnetCommandCallback, TelnetCallback); // set up Telnet commands - myESP.setWIFI(NULL, NULL, WIFICallback); + myESP.setWIFI(NULL, NULL, WIFICallback); // empty ssid and password as we take this from the config file // MQTT host, username and password taken from the SPIFFS settings myESP.setMQTT( @@ -1657,6 +1691,9 @@ void setup() { // custom settings in SPIFFS myESP.setSettings(FSCallback, SettingsCallback); + // web custom settings + myESP.setWeb(WebCallback); + // start up all the services myESP.begin(APP_HOSTNAME, APP_NAME, APP_VERSION); diff --git a/src/ems.cpp b/src/ems.cpp index 93eb0c018..ac8655ed9 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -2170,6 +2170,23 @@ void ems_printDevices() { } } +/* + * prints the device list to a string for html parsing + */ +uint8_t ems_printDevices_s(char * buffer, uint16_t len) { + if (Devices.size() == 0) { + return 0; + } + + char s[100]; + for (std::list<_Generic_Type>::iterator it = Devices.begin(); it != Devices.end(); it++) { + sprintf(s, "%s (DeviceID:0x%02X ProductID:%d Version:%s)
", (it)->model_string, (it)->device_id, (it)->product_id, (it)->version); + strlcat(buffer, s, len); + } + + return Devices.size(); +} + /** * Send a command to UART Tx to Read from another device * Read commands when sent must respond by the destination (target) immediately (or within 10ms) diff --git a/src/ems.h b/src/ems.h index 63680b903..dc7a1bc86 100644 --- a/src/ems.h +++ b/src/ems.h @@ -23,9 +23,9 @@ #define EMS_PRODUCTID_HEATRONICS 95 // ProductID for a Junkers Heatronic3 device -#define EMS_PRODUCTID_SM10 73 // ProductID for SM10 solar module +#define EMS_PRODUCTID_SM10 73 // ProductID for SM10 solar module #define EMS_PRODUCTID_SM100 163 // ProductID for SM10 solar module -#define EMS_PRODUCTID_ISM1 101 // ProductID for SM10 solar module +#define EMS_PRODUCTID_ISM1 101 // ProductID for SM10 solar module #define EMS_MIN_TELEGRAM_LENGTH 6 // minimal length for a validation telegram, including CRC @@ -255,12 +255,12 @@ typedef struct { // UBAParameterWW // Other ems devices than solar modules, thermostats and boilers typedef struct { - bool HP; // set true if there is a Heat Pump available + bool HP; // set true if there is a Heat Pump available uint8_t HPModulation; // heatpump modulation in % uint8_t HPSpeed; // speed 0-100 % - uint8_t device_id; // the device ID of the Solar Module / Heat Pump (e.g. 0x30) - uint8_t model_id; // Solar Module / Heat Pump model (e.g. 3 > EMS_MODEL_OTHER ) - uint8_t product_id; // (e.g. 101) + uint8_t device_id; // the device ID of the Solar Module / Heat Pump (e.g. 0x30) + uint8_t model_id; // Solar Module / Heat Pump model (e.g. 3 > EMS_MODEL_OTHER ) + uint8_t product_id; // (e.g. 101) char version[10]; } _EMS_Other; @@ -273,8 +273,8 @@ typedef struct { int16_t EnergyLastHour; int16_t EnergyToday; int16_t EnergyTotal; - uint8_t device_id; // the device ID of the Solar Module / Heat Pump (e.g. 0x30) - uint8_t model_id; // Solar Module / Heat Pump model (e.g. 3 > EMS_MODEL_OTHER ) + uint8_t device_id; // the device ID of the Solar Module / Heat Pump (e.g. 0x30) + uint8_t model_id; // Solar Module / Heat Pump model (e.g. 3 > EMS_MODEL_OTHER ) uint8_t product_id; // (e.g. 101) char version[10]; } _EMS_SolarModule; @@ -323,6 +323,7 @@ void ems_sendRawTelegram(char * telegram); void ems_scanDevices(); void ems_printAllDevices(); void ems_printDevices(); +uint8_t ems_printDevices_s(char * buffer, uint16_t len); void ems_printTxQueue(); void ems_testTelegram(uint8_t test_num); void ems_startupTelegrams(); @@ -375,8 +376,8 @@ bool _ems_setModel(uint8_t model_id); void _removeTxQueue(); // global so can referenced in other classes -extern _EMS_Sys_Status EMS_Sys_Status; -extern _EMS_Boiler EMS_Boiler; -extern _EMS_Thermostat EMS_Thermostat; +extern _EMS_Sys_Status EMS_Sys_Status; +extern _EMS_Boiler EMS_Boiler; +extern _EMS_Thermostat EMS_Thermostat; extern _EMS_SolarModule EMS_SolarModule; -extern _EMS_Other EMS_Other; +extern _EMS_Other EMS_Other; diff --git a/src/version.h b/src/version.h index 43d0fb49d..ce9ea11d1 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.8.1b2" +#define APP_VERSION "1.8.1b4" #define APP_HOSTNAME "ems-esp" From 5740a8ee0d7e1713c3e4dd3fcd5c54cdec7c1eb1 Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 26 Jun 2019 22:01:56 +0200 Subject: [PATCH 24/89] dont use program for help text --- lib/MyESP/MyESP.cpp | 8 ++++---- lib/MyESP/MyESP.h | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/MyESP/MyESP.cpp b/lib/MyESP/MyESP.cpp index de12cf146..2b7e63bb0 100644 --- a/lib/MyESP/MyESP.cpp +++ b/lib/MyESP/MyESP.cpp @@ -614,12 +614,12 @@ void MyESP::_consoleShowHelp() { for (uint8_t i = 0; i < _helpProjectCmds_count; i++) { if (!_helpProjectCmds[i].set) { - SerialAndTelnet.print(FPSTR("* ")); - SerialAndTelnet.print(FPSTR(_helpProjectCmds[i].key)); + SerialAndTelnet.print("* "); + SerialAndTelnet.print(_helpProjectCmds[i].key); for (uint8_t j = 0; j < ((max_len + 5) - strlen(_helpProjectCmds[i].key)); j++) { // account for longest string length - SerialAndTelnet.print(FPSTR(" ")); // padding + SerialAndTelnet.print(" "); // padding } - SerialAndTelnet.println(FPSTR(_helpProjectCmds[i].description)); + SerialAndTelnet.println(_helpProjectCmds[i].description); } } } diff --git a/lib/MyESP/MyESP.h b/lib/MyESP/MyESP.h index 082075edd..5b4b9c073 100644 --- a/lib/MyESP/MyESP.h +++ b/lib/MyESP/MyESP.h @@ -216,7 +216,8 @@ const char webResetPage_form[] = "
"" "
"; -const char webResetPage_post[] = "

New wifi credentials set. System is now rebooting. Please wait a few seconds and then reconnect via telnet or browser to its new IP given address.

"; +const char webResetPage_post[] = + "

New wifi credentials set. System is now rebooting. Please wait a few seconds and then reconnect via telnet or browser to its new IP given address.

"; const char webResetAllPage_form[] = "
" "" From 4e50d13bd153d65fad97a2444c51eff41c691be2 Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 26 Jun 2019 22:02:16 +0200 Subject: [PATCH 25/89] add tx_mode back as new tx code can cause resets --- CHANGELOG.md | 1 + lib/MyESP/MyESP.h | 2 +- src/ems-esp.cpp | 19 ++++++-- src/ems.cpp | 52 +++++++++++++------- src/ems.h | 49 ++++++++++--------- src/emsuart.cpp | 118 ++++++++++++++++++++++++++++++++++------------ src/emsuart.h | 6 +++ src/version.h | 2 +- 8 files changed, 171 insertions(+), 78 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56358d8ff..8d1fea31b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added back -DCRASH in Debug build target for capturing any ESP8266 stack dumps during crashes - Web Interface, for checking stats and setting wifi credentials. See wiki for more details. - reset firmware option. If the reset button on the ESP is pressed during boot up sequence (the LED is flashing very fast) all settings are erased and goes into AP mode. +- Added tx_mode back with options 0,1 and 2 until we've fixed option 2 that works for everyone and doesn't reset ESP ### Fixed diff --git a/lib/MyESP/MyESP.h b/lib/MyESP/MyESP.h index 5b4b9c073..ca2902ad3 100644 --- a/lib/MyESP/MyESP.h +++ b/lib/MyESP/MyESP.h @@ -9,7 +9,7 @@ #ifndef MyEMS_h #define MyEMS_h -#define MYESP_VERSION "1.1.18" +#define MYESP_VERSION "1.1.19" #include #include diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index c63ce7c53..41231e951 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -106,6 +106,7 @@ command_t project_cmds[] = { {true, "shower_alert ", "stop hot water to send 3 cold burst warnings after max shower time is exceeded"}, {true, "publish_time ", "set frequency for publishing data to MQTT (0=off)"}, {true, "heating_circuit <1 | 2>", "set the main thermostat HC to work with (if using multiple heating circuits)"}, + {true, "tx_mode ", "0=classic ems logic, 1=@kwertie01 ems+ logic, 2=@susisstrolch logic, 3=@philrich logic for Junkers"}, {false, "info", "show current captured on the devices"}, {false, "log ", "set logging mode to none, basic, thermostat only, raw or verbose"}, @@ -323,7 +324,7 @@ void showInfo() { myDebug_P(PSTR(" System logging set to Verbose")); } else if (sysLog == EMS_SYS_LOGGING_THERMOSTAT) { myDebug_P(PSTR(" System logging set to Thermostat only")); - } else if (sysLog == EMS_SYS_LOGGING_SOLARMODULE ) { + } else if (sysLog == EMS_SYS_LOGGING_SOLARMODULE) { myDebug_P(PSTR(" System logging set to Solar Module only")); } else { myDebug_P(PSTR(" System logging set to None")); @@ -1032,6 +1033,8 @@ bool FSCallback(MYESP_FSACTION action, const JsonObject json) { EMSESP_Status.shower_alert = json["shower_alert"]; EMSESP_Status.publish_time = json["publish_time"] | DEFAULT_PUBLISHTIME; + ems_setTxMode(json["tx_mode"]); + EMSESP_Status.listen_mode = json["listen_mode"]; ems_setTxDisabled(EMSESP_Status.listen_mode); @@ -1053,6 +1056,7 @@ bool FSCallback(MYESP_FSACTION action, const JsonObject json) { json["shower_alert"] = EMSESP_Status.shower_alert; json["publish_time"] = EMSESP_Status.publish_time; json["heating_circuit"] = EMSESP_Status.heating_circuit; + json["tx_mode"] = ems_getTxMode(); return true; } @@ -1182,6 +1186,12 @@ bool SettingsCallback(MYESP_FSACTION action, uint8_t wc, const char * setting, c myDebug_P(PSTR("Error. Usage: set heating_circuit <1 | 2>")); } } + + // tx delay/ tx mode + if (((strcmp(setting, "tx_mode") == 0) || (strcmp(setting, "tx_delay") == 0)) && (wc == 2)) { + ems_setTxMode(atoi(value)); + ok = true; + } } if (action == MYESP_FSACTION_LIST) { @@ -1208,6 +1218,7 @@ bool SettingsCallback(MYESP_FSACTION action, uint8_t wc, const char * setting, c myDebug_P(PSTR(" shower_timer=%s"), EMSESP_Status.shower_timer ? "on" : "off"); myDebug_P(PSTR(" shower_alert=%s"), EMSESP_Status.shower_alert ? "on" : "off"); myDebug_P(PSTR(" publish_time=%d"), EMSESP_Status.publish_time); + myDebug_P(PSTR(" tx_mode=%d"), ems_getTxMode()); } return ok; @@ -1301,9 +1312,9 @@ void TelnetCommandCallback(uint8_t wc, const char * commandLine) { ems_setLogging(EMS_SYS_LOGGING_THERMOSTAT); ok = true; } else if (strcmp(second_cmd, "s") == 0) { - ems_setLogging(EMS_SYS_LOGGING_SOLARMODULE ); + ems_setLogging(EMS_SYS_LOGGING_SOLARMODULE); ok = true; - }else if (strcmp(second_cmd, "r") == 0) { + } else if (strcmp(second_cmd, "r") == 0) { ems_setLogging(EMS_SYS_LOGGING_RAW); ok = true; } else if (strcmp(second_cmd, "n") == 0) { @@ -1553,7 +1564,7 @@ void WebCallback(char * body) { strlcpy(body, "EMS devices found:
", MYESP_MAXCHARBUFFER); char buffer[MYESP_MAXCHARBUFFER] = {0}; - uint8_t num_devices = ems_printDevices_s(buffer, MYESP_MAXCHARBUFFER); + uint8_t num_devices = ems_printDevices_s(buffer, MYESP_MAXCHARBUFFER); if (num_devices == 0) { strlcat(body, "no compatible EMS devices detected yet. (wait a few seconds)", MYESP_MAXCHARBUFFER); } else { diff --git a/src/ems.cpp b/src/ems.cpp index 7bade270e..f04cc9546 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -234,6 +234,7 @@ void ems_init() { EMS_Sys_Status.emsPollFrequency = 0; EMS_Sys_Status.txRetryCount = 0; EMS_Sys_Status.emsReverse = false; + EMS_Sys_Status.emsTxMode = 0; // thermostat EMS_Thermostat.setpoint_roomTemp = EMS_VALUE_SHORT_NOTSET; @@ -304,17 +305,17 @@ void ems_init() { EMS_Boiler.pump_mod_min = EMS_VALUE_INT_NOTSET; // Boiler circuit pump modulation min. power // Solar Module values - EMS_SolarModule.collectorTemp = EMS_VALUE_SHORT_NOTSET; // collector temp from SM10/SM100 - EMS_SolarModule.bottomTemp = EMS_VALUE_SHORT_NOTSET; // bottom temp from SM10/SM100 - EMS_SolarModule.pumpModulation = EMS_VALUE_INT_NOTSET; // modulation solar pump SM10/SM100 - EMS_SolarModule.pump = EMS_VALUE_INT_NOTSET; // pump active - EMS_SolarModule.setpoint_maxBottomTemp = EMS_VALUE_SHORT_NOTSET; //setpoint for maximum solar boiler temperature - EMS_SolarModule.EnergyLastHour = EMS_VALUE_SHORT_NOTSET; - EMS_SolarModule.EnergyToday = EMS_VALUE_SHORT_NOTSET; - EMS_SolarModule.EnergyTotal = EMS_VALUE_SHORT_NOTSET; - EMS_SolarModule.device_id = EMS_ID_NONE; - EMS_SolarModule.model_id = EMS_MODEL_NONE; - EMS_SolarModule.product_id = EMS_ID_NONE; + EMS_SolarModule.collectorTemp = EMS_VALUE_SHORT_NOTSET; // collector temp from SM10/SM100 + EMS_SolarModule.bottomTemp = EMS_VALUE_SHORT_NOTSET; // bottom temp from SM10/SM100 + EMS_SolarModule.pumpModulation = EMS_VALUE_INT_NOTSET; // modulation solar pump SM10/SM100 + EMS_SolarModule.pump = EMS_VALUE_INT_NOTSET; // pump active + EMS_SolarModule.setpoint_maxBottomTemp = EMS_VALUE_SHORT_NOTSET; //setpoint for maximum solar boiler temperature + EMS_SolarModule.EnergyLastHour = EMS_VALUE_SHORT_NOTSET; + EMS_SolarModule.EnergyToday = EMS_VALUE_SHORT_NOTSET; + EMS_SolarModule.EnergyTotal = EMS_VALUE_SHORT_NOTSET; + EMS_SolarModule.device_id = EMS_ID_NONE; + EMS_SolarModule.model_id = EMS_MODEL_NONE; + EMS_SolarModule.product_id = EMS_ID_NONE; // Other EMS devices values EMS_Other.HPModulation = EMS_VALUE_INT_NOTSET; @@ -353,6 +354,23 @@ bool ems_getPoll() { return EMS_Sys_Status.emsPollEnabled; } +void ems_setTxMode(uint8_t mode) { + EMS_Sys_Status.emsTxMode = mode; + + // special case for Junkers. If tx_mode is 3 then set the reverse poll flag + // https://github.com/proddy/EMS-ESP/issues/103#issuecomment-495945850 + if (mode == 3) { + EMS_Sys_Status.emsReverse = true; + myDebug_P(PSTR("Forcing emsReverse for Junkers")); + } else { + EMS_Sys_Status.emsReverse = false; + } +} + +uint8_t ems_getTxMode() { + return EMS_Sys_Status.emsTxMode; +} + bool ems_getEmsRefreshed() { return EMS_Sys_Status.emsRefreshed; } @@ -428,11 +446,11 @@ void ems_setLogging(_EMS_SYS_LOGGING loglevel) { myDebug_P(PSTR("System Logging set to Thermostat only")); } else if (loglevel == EMS_SYS_LOGGING_SOLARMODULE) { myDebug_P(PSTR("System Logging set to Solar Module only")); - }else if (loglevel == EMS_SYS_LOGGING_RAW) { + } else if (loglevel == EMS_SYS_LOGGING_RAW) { myDebug_P(PSTR("System Logging set to Raw mode")); } } -} +} /** * Calculate CRC checksum using lookup table for speed @@ -1506,12 +1524,10 @@ void _process_ISM1StatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { * Junkers ISM1 Solar Module - type 0x0001 EMS+ for setting values */ void _process_ISM1Set(_EMS_RxTelegram * EMS_RxTelegram) { - - if (EMS_RxTelegram->offset == 6) { - // e.g. 90 30 FF 06 00 01 50 (CRC=2C) - // to implement: change max solar boiler temperature - EMS_SolarModule.setpoint_maxBottomTemp = _toByte(0); + // e.g. 90 30 FF 06 00 01 50 (CRC=2C) + // to implement: change max solar boiler temperature + EMS_SolarModule.setpoint_maxBottomTemp = _toByte(0); } } diff --git a/src/ems.h b/src/ems.h index b7c075244..d47ff3546 100644 --- a/src/ems.h +++ b/src/ems.h @@ -79,12 +79,12 @@ typedef enum { /* EMS logging */ typedef enum { - EMS_SYS_LOGGING_NONE, // no messages - EMS_SYS_LOGGING_RAW, // raw data mode - EMS_SYS_LOGGING_BASIC, // only basic read/write messages - EMS_SYS_LOGGING_THERMOSTAT, // only telegrams sent from thermostat + EMS_SYS_LOGGING_NONE, // no messages + EMS_SYS_LOGGING_RAW, // raw data mode + EMS_SYS_LOGGING_BASIC, // only basic read/write messages + EMS_SYS_LOGGING_THERMOSTAT, // only telegrams sent from thermostat EMS_SYS_LOGGING_SOLARMODULE, // only telegrams sent from thermostat - EMS_SYS_LOGGING_VERBOSE // everything + EMS_SYS_LOGGING_VERBOSE // everything } _EMS_SYS_LOGGING; // status/counters since last power on @@ -104,6 +104,7 @@ typedef struct { bool emsTxDisabled; // true to prevent all Tx uint8_t txRetryCount; // # times the last Tx was re-sent bool emsReverse; // if true, poll logic is reversed + uint8_t emsTxMode; // handles Tx logic } _EMS_Sys_Status; // The Tx send package @@ -267,11 +268,11 @@ typedef struct { // SM Solar Module - SM10/SM100/ISM1 typedef struct { - int16_t collectorTemp; // collector temp - int16_t bottomTemp; // bottom temp - uint8_t pumpModulation; // modulation solar pump - uint8_t pump; // pump active - int16_t setpoint_maxBottomTemp; // setpoint for maximum collector temp + int16_t collectorTemp; // collector temp + int16_t bottomTemp; // bottom temp + uint8_t pumpModulation; // modulation solar pump + uint8_t pump; // pump active + int16_t setpoint_maxBottomTemp; // setpoint for maximum collector temp int16_t EnergyLastHour; int16_t EnergyToday; int16_t EnergyTotal; @@ -331,20 +332,22 @@ void ems_testTelegram(uint8_t test_num); void ems_startupTelegrams(); bool ems_checkEMSBUSAlive(); void ems_clearDeviceList(); +void ems_setTxMode(uint8_t mode); -void ems_setThermostatTemp(float temperature, uint8_t temptype = 0); -void ems_setThermostatMode(uint8_t mode); -void ems_setThermostatHC(uint8_t hc); -void ems_setWarmWaterTemp(uint8_t temperature); -void ems_setFlowTemp(uint8_t temperature); -void ems_setWarmWaterActivated(bool activated); -void ems_setWarmTapWaterActivated(bool activated); -void ems_setPoll(bool b); -void ems_setLogging(_EMS_SYS_LOGGING loglevel); -void ems_setEmsRefreshed(bool b); -void ems_setWarmWaterModeComfort(uint8_t comfort); -void ems_setModels(); -void ems_setTxDisabled(bool b); +void ems_setThermostatTemp(float temperature, uint8_t temptype = 0); +void ems_setThermostatMode(uint8_t mode); +void ems_setThermostatHC(uint8_t hc); +void ems_setWarmWaterTemp(uint8_t temperature); +void ems_setFlowTemp(uint8_t temperature); +void ems_setWarmWaterActivated(bool activated); +void ems_setWarmTapWaterActivated(bool activated); +void ems_setPoll(bool b); +void ems_setLogging(_EMS_SYS_LOGGING loglevel); +void ems_setEmsRefreshed(bool b); +void ems_setWarmWaterModeComfort(uint8_t comfort); +void ems_setModels(); +void ems_setTxDisabled(bool b); +uint8_t ems_getTxMode(); char * ems_getThermostatDescription(char * buffer); char * ems_getBoilerDescription(char * buffer); diff --git a/src/emsuart.cpp b/src/emsuart.cpp index 8f52e7c72..d17c69f78 100644 --- a/src/emsuart.cpp +++ b/src/emsuart.cpp @@ -159,6 +159,35 @@ void ICACHE_FLASH_ATTR emsuart_start() { ETS_UART_INTR_ENABLE(); } +/* + * Send a BRK signal + * Which is a 11-bit set of zero's (11 cycles) + */ +void ICACHE_FLASH_ATTR emsuart_tx_brk() { + uint32_t tmp; + + // must make sure Tx FIFO is empty + while (((USS(EMSUART_UART) >> USTXC) & 0xFF) != 0) + ; + + tmp = ((1 << UCRXRST) | (1 << UCTXRST)); // bit mask + USC0(EMSUART_UART) |= (tmp); // set bits + USC0(EMSUART_UART) &= ~(tmp); // clear bits + + // To create a 11-bit we set TXD_BRK bit so the break signal will + // automatically be sent when the tx fifo is empty + tmp = (1 << UCBRK); + USC0(EMSUART_UART) |= (tmp); // set bit + + if (EMS_Sys_Status.emsTxMode <= 1) { // classic mode and ems+ (0, 1) + delayMicroseconds(EMSUART_TX_BRK_WAIT); + } else if (EMS_Sys_Status.emsTxMode == 3) { // junkers mode + delayMicroseconds(EMSUART_TX_WAIT_BRK - EMSUART_TX_LAG); // 1144 (11 Bits) + } + + USC0(EMSUART_UART) &= ~(tmp); // clear bit +} + /* * Send to Tx, ending with a */ @@ -166,7 +195,33 @@ void ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) { if (len == 0) return; - /* + // temp code until we get mode 2 working without resets + + if (EMS_Sys_Status.emsTxMode == 0) { // classic mode logic + for (uint8_t i = 0; i < len; i++) { + USF(EMSUART_UART) = buf[i]; + } + emsuart_tx_brk(); // send + } else if (EMS_Sys_Status.emsTxMode == 1) { // With extra tx delay for EMS+ + for (uint8_t i = 0; i < len; i++) { + USF(EMSUART_UART) = buf[i]; + delayMicroseconds(EMSUART_TX_BRK_WAIT); // https://github.com/proddy/EMS-ESP/issues/23# + } + emsuart_tx_brk(); // send + } else if (EMS_Sys_Status.emsTxMode == 3) { // Junkers logic by @philrich + for (uint8_t i = 0; i < len; i++) { + USF(EMSUART_UART) = buf[i]; + + // just to be safe wait for tx fifo empty (needed?) + while (((USS(EMSUART_UART) >> USTXC) & 0xff) != 0) + ; + + // wait until bits are sent on wire + delayMicroseconds(EMSUART_TX_WAIT_BYTE - EMSUART_TX_LAG + EMSUART_TX_WAIT_GAP); + } + emsuart_tx_brk(); // send + } else if (EMS_Sys_Status.emsTxMode == 2) { + /* * based on code from https://github.com/proddy/EMS-ESP/issues/103 by @susisstrolch * we emit the whole telegram, with Rx interrupt disabled, collecting busmaster response in FIFO. * after sending the last char we poll the Rx status until either @@ -174,42 +229,43 @@ void ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) { * - is detected * At end of receive we re-enable Rx-INT and send a Tx-BRK in loopback mode. */ - ETS_UART_INTR_DISABLE(); // disable rx interrupt + ETS_UART_INTR_DISABLE(); // disable rx interrupt - // clear Rx status register - USC0(EMSUART_UART) |= (1 << UCRXRST); // reset uart rx fifo - emsuart_flush_fifos(); + // clear Rx status register + USC0(EMSUART_UART) |= (1 << UCRXRST); // reset uart rx fifo + emsuart_flush_fifos(); - // throw out the telegram... - for (uint8_t i = 0; i < len;) { - USF(EMSUART_UART) = buf[i++]; // send each Tx byte - // wait for echo from busmaster - while ((((USS(EMSUART_UART) >> USRXC) & 0xFF) < i || (USIS(EMSUART_UART) & (1 << UIBD)))) { - delayMicroseconds(EMSUART_BIT_TIME); // burn CPU cycles... - } - } - - // we got the whole telegram in the Rx buffer - // on Rx-BRK (bus collision), we simply enable Rx and leave it - // otherwise we send the final Tx-BRK in the loopback and re=enable Rx-INT. - // worst case, we'll see an additional Rx-BRK... - if (!(USIS(EMSUART_UART) & (1 << UIBD))) { - // no bus collision - send terminating BRK signal - USC0(EMSUART_UART) |= (1 << UCLBE); // enable loopback - USC0(EMSUART_UART) |= (1 << UCBRK); // set - - // wait until BRK detected... - while (!(USIS(EMSUART_UART) & (1 << UIBD))) { - delayMicroseconds(EMSUART_BIT_TIME); + // throw out the telegram... + for (uint8_t i = 0; i < len;) { + USF(EMSUART_UART) = buf[i++]; // send each Tx byte + // wait for echo from busmaster + while ((((USS(EMSUART_UART) >> USRXC) & 0xFF) < i || (USIS(EMSUART_UART) & (1 << UIBD)))) { + delayMicroseconds(EMSUART_BIT_TIME); // burn CPU cycles... + } } - USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear + // we got the whole telegram in the Rx buffer + // on Rx-BRK (bus collision), we simply enable Rx and leave it + // otherwise we send the final Tx-BRK in the loopback and re=enable Rx-INT. + // worst case, we'll see an additional Rx-BRK... + if (!(USIS(EMSUART_UART) & (1 << UIBD))) { + // no bus collision - send terminating BRK signal + USC0(EMSUART_UART) |= (1 << UCLBE); // enable loopback + USC0(EMSUART_UART) |= (1 << UCBRK); // set - USIC(EMSUART_UART) = (1 << UIBD); // clear BRK detect IRQ - USC0(EMSUART_UART) &= ~(1 << UCLBE); // disable loopback + // wait until BRK detected... + while (!(USIS(EMSUART_UART) & (1 << UIBD))) { + delayMicroseconds(EMSUART_BIT_TIME); + } + + USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear + + USIC(EMSUART_UART) = (1 << UIBD); // clear BRK detect IRQ + USC0(EMSUART_UART) &= ~(1 << UCLBE); // disable loopback + } + + ETS_UART_INTR_ENABLE(); // receive anything from FIFO... } - - ETS_UART_INTR_ENABLE(); // receive anything from FIFO... } /* diff --git a/src/emsuart.h b/src/emsuart.h index e59d72024..8fd0c14b3 100644 --- a/src/emsuart.h +++ b/src/emsuart.h @@ -18,6 +18,12 @@ #define EMSUART_BIT_TIME 104 // bit time @9600 baud +#define EMSUART_TX_BRK_WAIT 2070 // the BRK from Boiler master is roughly 1.039ms, so accounting for hardware lag using around 2078 (for half-duplex) - 8 (lag) +#define EMSUART_TX_WAIT_BYTE EMSUART_BIT_TIME * 10 // Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit) +#define EMSUART_TX_WAIT_BRK EMSUART_BIT_TIME * 11 // Time to send a BRK Signal (11 Bit) +#define EMSUART_TX_WAIT_GAP EMSUART_BIT_TIME * 7 // Gap between to Bytes +#define EMSUART_TX_LAG 8 + #define EMSUART_recvTaskPrio 1 #define EMSUART_recvTaskQueueLen 64 diff --git a/src/version.h b/src/version.h index ce9ea11d1..91042b4bc 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.8.1b4" +#define APP_VERSION "1.8.1b5" #define APP_HOSTNAME "ems-esp" From 55ff2678288d98ea7f83c4e0e75f2fbdae732452 Mon Sep 17 00:00:00 2001 From: Vuego123 Date: Thu, 27 Jun 2019 22:58:12 +0200 Subject: [PATCH 26/89] AddedISM1SolarPumpWorkingTime Added ISM1 Solar Pump Working Time --- src/ems-esp.cpp | 8 ++++++++ src/ems.cpp | 23 ++++++++++++----------- src/ems.h | 1 + src/my_config.h | 1 + 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index 41231e951..1f045485a 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -461,6 +461,10 @@ void showInfo() { _renderShortValue("Bottom temperature", "C", EMS_SolarModule.bottomTemp); _renderIntValue("Pump modulation", "%", EMS_SolarModule.pumpModulation); _renderBoolValue("Pump active", EMS_SolarModule.pump); + myDebug_P(PSTR("Pump working time: %d days %d hours %d minutes"), + EMS_SolarModule.pumpWorkMin / 1440, + (EMS_SolarModule.pumpWorkMin % 1440) / 60, + EMS_SolarModule.pumpWorkMin % 60); _renderShortValue("Energy Last Hour", "Wh", EMS_SolarModule.EnergyLastHour, 1); // *10 _renderShortValue("Energy Today", "Wh", EMS_SolarModule.EnergyToday, 0); _renderShortValue("Energy Total", "kWH", EMS_SolarModule.EnergyTotal, 1); // *10 @@ -785,6 +789,10 @@ void publishValues(bool force) { rootSM[SM_PUMP] = _bool_to_char(s, EMS_SolarModule.pump); } + if (EMS_SolarModule.pumpWorkMin != EMS_VALUE_LONG_NOTSET) { + rootSM[SM_PUMPWORKMIN] = (double)EMS_SolarModule.pumpWorkMin; + } + if (abs(EMS_SolarModule.EnergyLastHour) != EMS_VALUE_SHORT_NOTSET) rootSM[SM_ENERGYLASTHOUR] = (double)EMS_SolarModule.EnergyLastHour / 10; diff --git a/src/ems.cpp b/src/ems.cpp index f04cc9546..05a79ece1 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -305,17 +305,17 @@ void ems_init() { EMS_Boiler.pump_mod_min = EMS_VALUE_INT_NOTSET; // Boiler circuit pump modulation min. power // Solar Module values - EMS_SolarModule.collectorTemp = EMS_VALUE_SHORT_NOTSET; // collector temp from SM10/SM100 - EMS_SolarModule.bottomTemp = EMS_VALUE_SHORT_NOTSET; // bottom temp from SM10/SM100 - EMS_SolarModule.pumpModulation = EMS_VALUE_INT_NOTSET; // modulation solar pump SM10/SM100 - EMS_SolarModule.pump = EMS_VALUE_INT_NOTSET; // pump active - EMS_SolarModule.setpoint_maxBottomTemp = EMS_VALUE_SHORT_NOTSET; //setpoint for maximum solar boiler temperature - EMS_SolarModule.EnergyLastHour = EMS_VALUE_SHORT_NOTSET; - EMS_SolarModule.EnergyToday = EMS_VALUE_SHORT_NOTSET; - EMS_SolarModule.EnergyTotal = EMS_VALUE_SHORT_NOTSET; - EMS_SolarModule.device_id = EMS_ID_NONE; - EMS_SolarModule.model_id = EMS_MODEL_NONE; - EMS_SolarModule.product_id = EMS_ID_NONE; + EMS_SolarModule.collectorTemp = EMS_VALUE_SHORT_NOTSET; // collector temp from SM10/SM100 + EMS_SolarModule.bottomTemp = EMS_VALUE_SHORT_NOTSET; // bottom temp from SM10/SM100 + EMS_SolarModule.pumpModulation = EMS_VALUE_INT_NOTSET; // modulation solar pump SM10/SM100 + EMS_SolarModule.pump = EMS_VALUE_INT_NOTSET; // pump active + EMS_SolarModule.EnergyLastHour = EMS_VALUE_SHORT_NOTSET; + EMS_SolarModule.EnergyToday = EMS_VALUE_SHORT_NOTSET; + EMS_SolarModule.EnergyTotal = EMS_VALUE_SHORT_NOTSET; + EMS_SolarModule.device_id = EMS_ID_NONE; + EMS_SolarModule.model_id = EMS_MODEL_NONE; + EMS_SolarModule.product_id = EMS_ID_NONE; + EMS_SolarModule.pumpWorkMin = EMS_VALUE_LONG_NOTSET; // Other EMS devices values EMS_Other.HPModulation = EMS_VALUE_INT_NOTSET; @@ -1509,6 +1509,7 @@ void _process_ISM1StatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { EMS_SolarModule.bottomTemp = _toShort(6); // Temperature Bottom of Solar Boiler EMS_SolarModule.EnergyLastHour = _toShort(2) * 10; // Solar Energy produced in last hour EMS_SolarModule.pump = _bitRead(8, 0); // Solar pump on (1) or off (0) + EMS_SolarModule.pumpWorkMin = _toLong(10); // EMS_Other.SM = true; } diff --git a/src/ems.h b/src/ems.h index d47ff3546..cc5d0f3ce 100644 --- a/src/ems.h +++ b/src/ems.h @@ -276,6 +276,7 @@ typedef struct { int16_t EnergyLastHour; int16_t EnergyToday; int16_t EnergyTotal; + uint32_t pumpWorkMin; // Total solar pump operating time uint8_t device_id; // the device ID of the Solar Module / Heat Pump (e.g. 0x30) uint8_t model_id; // Solar Module / Heat Pump model (e.g. 3 > EMS_MODEL_OTHER ) uint8_t product_id; // (e.g. 101) diff --git a/src/my_config.h b/src/my_config.h index c12218e00..20575b25d 100644 --- a/src/my_config.h +++ b/src/my_config.h @@ -57,6 +57,7 @@ #define SM_ENERGYLASTHOUR "energylasthour" // energy last hour #define SM_ENERGYTODAY "energytoday" // energy today #define SM_ENERGYTOTAL "energytotal" // energy total +#define SM_PUMPWORKMIN "pumpWorkMin" // Total minutes // MQTT for HP (HeatPump) #define TOPIC_HP_DATA "hp_data" // topic name From 712e0b3e8cddca5b14cb30490e0da6e77df21f0a Mon Sep 17 00:00:00 2001 From: Vuego123 Date: Thu, 27 Jun 2019 23:26:02 +0200 Subject: [PATCH 27/89] FixedSpacingForSolarPumpTime fixed spacing --- src/ems-esp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index 1f045485a..427025dfc 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -461,7 +461,7 @@ void showInfo() { _renderShortValue("Bottom temperature", "C", EMS_SolarModule.bottomTemp); _renderIntValue("Pump modulation", "%", EMS_SolarModule.pumpModulation); _renderBoolValue("Pump active", EMS_SolarModule.pump); - myDebug_P(PSTR("Pump working time: %d days %d hours %d minutes"), + myDebug_P(PSTR(" Pump working time: %d days %d hours %d minutes"), EMS_SolarModule.pumpWorkMin / 1440, (EMS_SolarModule.pumpWorkMin % 1440) / 60, EMS_SolarModule.pumpWorkMin % 60); From a7869e45b35dc97b1918395a815e9ffdbec4c768 Mon Sep 17 00:00:00 2001 From: Paul Derbyshire Date: Fri, 28 Jun 2019 10:35:21 +0200 Subject: [PATCH 28/89] added .DS_Store for OSX --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ebd9e5140..b1ecb8047 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ .gcc-flags.json .vscode .env +.DS_Store platformio.ini lib/readme.txt .travis.yml From 0ef73b61dcff30f22ea353707aa00bd1babdf710 Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 29 Jun 2019 08:56:05 +0200 Subject: [PATCH 29/89] removed -DTESTS --- platformio.ini-example | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platformio.ini-example b/platformio.ini-example index a8f2a4bf8..4a816c41e 100644 --- a/platformio.ini-example +++ b/platformio.ini-example @@ -8,7 +8,8 @@ default_envs = debug [common] -debug_flags = -Wall -DTESTS -DCRASH +; -DMYESP_TIMESTAMP -DTESTS -DCRASH +debug_flags = -Wall -DCRASH release_flags = -w general_flags = -g -DNO_GLOBAL_EEPROM From 1ea9bc0d9175bd1639f15294ce02adefb4b67f4b Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 29 Jun 2019 08:56:19 +0200 Subject: [PATCH 30/89] added test 48 for outdoor temp --- src/test_data.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test_data.h b/src/test_data.h index 30f9c3c31..27e5b1444 100644 --- a/src/test_data.h +++ b/src/test_data.h @@ -49,7 +49,8 @@ static const char * TEST_DATA[] = { "90 00 FF 00 00 6F 03 01 00 BE 00 BF", // test 44 - FR10 "08 00 E3 00 01 00 01 00 00 00 00 00 00 00 00 00 DF 00 64 55", // test 45 - heatpump Enviline "08 00 E5 00 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0A", // test 46 - heatpump Enviline - "38 10 FF 00 03 2B 00 C7 07 C3 01" // test 47 - heatpump Enviline + "38 10 FF 00 03 2B 00 C7 07 C3 01", // test 47 - heatpump Enviline + "08 0B 19 00 00 F7 80 00 80 00 00 00 00 00 03 58 97 0C 7B 1F 00 00 00 06 C4 DF 02 64 48 80 00" // test 48 - outdoor temp check }; From b56d775d5ddca6ddc5e43a164f171e57c65cbab5 Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 29 Jun 2019 08:56:50 +0200 Subject: [PATCH 31/89] formatting --- src/ems.h | 24 ++++++++++++------------ src/emsuart.h | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/ems.h b/src/ems.h index cc5d0f3ce..5b6ade639 100644 --- a/src/ems.h +++ b/src/ems.h @@ -268,19 +268,19 @@ typedef struct { // SM Solar Module - SM10/SM100/ISM1 typedef struct { - int16_t collectorTemp; // collector temp - int16_t bottomTemp; // bottom temp - uint8_t pumpModulation; // modulation solar pump - uint8_t pump; // pump active - int16_t setpoint_maxBottomTemp; // setpoint for maximum collector temp - int16_t EnergyLastHour; - int16_t EnergyToday; - int16_t EnergyTotal; + int16_t collectorTemp; // collector temp + int16_t bottomTemp; // bottom temp + uint8_t pumpModulation; // modulation solar pump + uint8_t pump; // pump active + int16_t setpoint_maxBottomTemp; // setpoint for maximum collector temp + int16_t EnergyLastHour; + int16_t EnergyToday; + int16_t EnergyTotal; uint32_t pumpWorkMin; // Total solar pump operating time - uint8_t device_id; // the device ID of the Solar Module / Heat Pump (e.g. 0x30) - uint8_t model_id; // Solar Module / Heat Pump model (e.g. 3 > EMS_MODEL_OTHER ) - uint8_t product_id; // (e.g. 101) - char version[10]; + uint8_t device_id; // the device ID of the Solar Module / Heat Pump (e.g. 0x30) + uint8_t model_id; // Solar Module / Heat Pump model (e.g. 3 > EMS_MODEL_OTHER ) + uint8_t product_id; // (e.g. 101) + char version[10]; } _EMS_SolarModule; // Thermostat data diff --git a/src/emsuart.h b/src/emsuart.h index 8fd0c14b3..c49e2f6a8 100644 --- a/src/emsuart.h +++ b/src/emsuart.h @@ -13,7 +13,7 @@ #define EMSUART_CONFIG 0x1C // 8N1 (8 bits, no stop bits, 1 parity) #define EMSUART_BAUD 9600 // uart baud rate for the EMS circuit -#define EMS_MAXBUFFERS 5 // buffers for circular filling to avoid collisions +#define EMS_MAXBUFFERS 5 // buffers for circular filling to avoid collisions #define EMS_MAXBUFFERSIZE 32 // max size of the buffer. packets are max 32 bytes to support EMS 1.0 #define EMSUART_BIT_TIME 104 // bit time @9600 baud @@ -22,7 +22,7 @@ #define EMSUART_TX_WAIT_BYTE EMSUART_BIT_TIME * 10 // Time to send one Byte (8 Bits, 1 Start Bit, 1 Stop Bit) #define EMSUART_TX_WAIT_BRK EMSUART_BIT_TIME * 11 // Time to send a BRK Signal (11 Bit) #define EMSUART_TX_WAIT_GAP EMSUART_BIT_TIME * 7 // Gap between to Bytes -#define EMSUART_TX_LAG 8 +#define EMSUART_TX_LAG 8 #define EMSUART_recvTaskPrio 1 #define EMSUART_recvTaskQueueLen 64 From 27692e80ca25b53d8c7ec8b837e5a3d1d2016b04 Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 29 Jun 2019 08:56:57 +0200 Subject: [PATCH 32/89] mention new SM changes --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d1fea31b..4c13a3b2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Web Interface, for checking stats and setting wifi credentials. See wiki for more details. - reset firmware option. If the reset button on the ESP is pressed during boot up sequence (the LED is flashing very fast) all settings are erased and goes into AP mode. - Added tx_mode back with options 0,1 and 2 until we've fixed option 2 that works for everyone and doesn't reset ESP +- More solar module data captured, thanks to @Vuego123 ### Fixed From 8a46340979f8b709414f350374773bf47ae4f9d6 Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 29 Jun 2019 08:57:07 +0200 Subject: [PATCH 33/89] bump --- src/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h b/src/version.h index 91042b4bc..f67796aa1 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.8.1b5" +#define APP_VERSION "1.8.1b6" #define APP_HOSTNAME "ems-esp" From 688e1940111dfb3f57585b010b31f8d2745a758e Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 29 Jun 2019 08:57:28 +0200 Subject: [PATCH 34/89] minor fixes to SM output --- src/ems-esp.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index 427025dfc..213dd17f4 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -335,9 +335,10 @@ void showInfo() { myDebug_P(PSTR(" %d external temperature sensor%s found"), EMSESP_Status.dallas_sensors, (EMSESP_Status.dallas_sensors == 1) ? "" : "s"); } - myDebug_P(PSTR(" Thermostat is %s, Boiler is %s, Shower Timer is %s, Shower Alert is %s"), - (ems_getThermostatEnabled() ? "enabled" : "disabled"), + myDebug_P(PSTR(" Boiler is %s, Thermostat is %s, Solar Module is %s, Shower Timer is %s, Shower Alert is %s"), (ems_getBoilerEnabled() ? "enabled" : "disabled"), + (ems_getThermostatEnabled() ? "enabled" : "disabled"), + (ems_getSolarModuleEnabled() ? "enabled" : "disabled"), ((EMSESP_Status.shower_timer) ? "enabled" : "disabled"), ((EMSESP_Status.shower_alert) ? "enabled" : "disabled")); @@ -453,7 +454,7 @@ void showInfo() { } // For SM10/SM100 Solar Module - if (ems_getThermostatEnabled()) { + if (ems_getSolarModuleEnabled()) { myDebug_P(PSTR("")); // newline myDebug_P(PSTR("%sSolar Module stats:%s"), COLOR_BOLD_ON, COLOR_BOLD_OFF); myDebug_P(PSTR(" Solar Module: %s"), ems_getSolarModuleDescription(buffer_type)); From d37911e9547405ec9158766d23351b921d985c34 Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 30 Jun 2019 19:56:53 +0200 Subject: [PATCH 35/89] https://github.com/proddy/EMS-ESP/issues/140 https://github.com/proddy/EMS-ESP/issues/142 --- lib/MyESP/MyESP.cpp | 15 +++++++++++---- lib/MyESP/MyESP.h | 16 ++++++++++------ src/ems-esp.cpp | 2 +- src/version.h | 2 +- 4 files changed, 23 insertions(+), 12 deletions(-) diff --git a/lib/MyESP/MyESP.cpp b/lib/MyESP/MyESP.cpp index 2b7e63bb0..ea6e44581 100644 --- a/lib/MyESP/MyESP.cpp +++ b/lib/MyESP/MyESP.cpp @@ -467,6 +467,9 @@ void MyESP::_OTACallback() { EEPROMr.commit(); #endif + // stop the web server + webServer.close(); + if (_ota_pre_callback) { (_ota_pre_callback)(); // call custom function } @@ -1411,14 +1414,14 @@ void MyESP::_mqttConnect() { // Setup everything we need void MyESP::setWIFI(const char * wifi_ssid, const char * wifi_password, wifi_callback_f callback) { // Check SSID too long or missing - if (!wifi_ssid || *wifi_ssid == 0x00 || strlen(wifi_ssid) > MAX_STR_LEN) { + if (!wifi_ssid || *wifi_ssid == 0x00 || strlen(wifi_ssid) > MAX_SSID_LEN) { _wifi_ssid = NULL; } else { _wifi_ssid = strdup(wifi_ssid); } // Check PASS too long - if (!wifi_password || *wifi_ssid == 0x00 || strlen(wifi_password) > MAX_STR_LEN) { + if (!wifi_password || *wifi_ssid == 0x00 || strlen(wifi_password) > MAX_PWD_LEN) { _wifi_password = NULL; } else { _wifi_password = strdup(wifi_password); @@ -1959,6 +1962,8 @@ void MyESP::_webRootPage() { char s[1000] = {0}; strlcpy(s, webCommonPage_start, sizeof(s)); + strlcat(s, webCommonPage_start_refresh, sizeof(s)); + strlcat(s, webCommonPage_start_body, sizeof(s)); strlcat(s, "

", sizeof(s)); strlcat(s, _app_name, sizeof(s)); @@ -2012,6 +2017,7 @@ void MyESP::_webResetPage() { char s[1000] = {0}; strlcpy(s, webCommonPage_start, sizeof(s)); + strlcat(s, webCommonPage_start_body, sizeof(s)); strlcat(s, "

", sizeof(s)); strlcat(s, _app_name, sizeof(s)); @@ -2039,7 +2045,7 @@ void MyESP::_webResetPage() { } else { // Create a string containing all the arguments // Check to see if there are new values (also doubles to check the length of the new value is long enough) - if (webServer.arg("newssid").length() < MAX_STR_LEN) { + if (webServer.arg("newssid").length() < MAX_SSID_LEN) { if (webServer.arg("newssid").length() == 0) { _wifi_ssid = NULL; } else { @@ -2047,7 +2053,7 @@ void MyESP::_webResetPage() { } } - if (webServer.arg("newpassword").length() < MAX_STR_LEN) { + if (webServer.arg("newpassword").length() < MAX_PWD_LEN) { if (webServer.arg("newpassword").length() == 0) { _wifi_password = NULL; } else { @@ -2074,6 +2080,7 @@ void MyESP::_webResetAllPage() { char s[1000] = {0}; strlcpy(s, webCommonPage_start, sizeof(s)); + strlcat(s, webCommonPage_start_body, sizeof(s)); strlcat(s, "

", sizeof(s)); strlcat(s, _app_name, sizeof(s)); diff --git a/lib/MyESP/MyESP.h b/lib/MyESP/MyESP.h index ca2902ad3..e91203b3e 100644 --- a/lib/MyESP/MyESP.h +++ b/lib/MyESP/MyESP.h @@ -192,7 +192,8 @@ constexpr size_t ArraySize(T (&)[N]) { #define UPTIME_OVERFLOW 4294967295 // Uptime overflow value // web min and max length of wifi ssid and password -#define MAX_STR_LEN 16 +#define MAX_SSID_LEN 32 +#define MAX_PWD_LEN 64 #define MYESP_BOOTUP_FLASHDELAY 50 // flash duration for LED at bootup sequence #define MYESP_BOOTUP_DELAY 2000 // time before we open the window to reset. This is to stop resetting values when uploading firmware via USB @@ -204,15 +205,18 @@ constexpr size_t ArraySize(T (&)[N]) { const char webCommonPage_start[] = "" "" "" - "" - ""; + "body {background-color: #FFA500;font: normal 18px Verdana, Arial, sans-serif;} "; + + +const char webCommonPage_start_refresh[] = ""; + +const char webCommonPage_start_body[] = ""; const char webCommonPage_end[] = ""; const char webResetPage_form[] = "" - "" - "" + "" + "" "" ""; diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index 213dd17f4..554ce189a 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -1575,7 +1575,7 @@ void WebCallback(char * body) { char buffer[MYESP_MAXCHARBUFFER] = {0}; uint8_t num_devices = ems_printDevices_s(buffer, MYESP_MAXCHARBUFFER); if (num_devices == 0) { - strlcat(body, "no compatible EMS devices detected yet. (wait a few seconds)", MYESP_MAXCHARBUFFER); + strlcat(body, "(any detected and compatible EMS devices will show up here)", MYESP_MAXCHARBUFFER); } else { strlcat(body, buffer, MYESP_MAXCHARBUFFER); } diff --git a/src/version.h b/src/version.h index f67796aa1..8cd9a181e 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.8.1b6" +#define APP_VERSION "1.8.1b7" #define APP_HOSTNAME "ems-esp" From 74abec2591bd5cebb4568e8d9b0f4443999d3aad Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 1 Jul 2019 09:15:06 +0200 Subject: [PATCH 36/89] https://github.com/proddy/EMS-ESP/issues/143 --- CHANGELOG.md | 4 +++- src/emsuart.cpp | 2 +- src/test_data.h | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c13a3b2a..db10a3c73 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [1.8.1dev] 2019-06-24 +## [1.8.1dev] 2019-07-01 ### Added @@ -19,11 +19,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Detecting unset values in the SPIFFS and setting default values - Bosch Easy Connect wrongly classified as a thermostat +- Correctly handle telegrams who's size are exactly 32 bytes (e.g. 0x19 MonitorSlow) ### Changed - Improved handling of Solar Modules (thanks @Vuego123) - `publish_wait` renamed to `publish_time`, a value of 0 means disabling all MQTT sending +- How signed shorts are handled such as the current and setpoint temps on RC300s ## [1.8.0] 2019-06-15 diff --git a/src/emsuart.cpp b/src/emsuart.cpp index d17c69f78..2b6e166e0 100644 --- a/src/emsuart.cpp +++ b/src/emsuart.cpp @@ -69,7 +69,7 @@ static void ICACHE_FLASH_ATTR emsuart_recvTask(os_event_t * events) { if (length == 2) { // it's a poll or status code, single byte and ok to send on ems_parseTelegram((uint8_t *)pCurrent->buffer, 1); - } else if ((length > 4) && (length <= EMS_MAXBUFFERSIZE) && (pCurrent->buffer[length - 2] != 0x00)) { + } else if ((length > 4) && (length <= EMS_MAXBUFFERSIZE + 1) && (pCurrent->buffer[length - 2] != 0x00)) { // ignore double BRK at the end, possibly from the Tx loopback // also telegrams with no data value ems_parseTelegram((uint8_t *)pCurrent->buffer, length - 1); // transmit EMS buffer, excluding the BRK diff --git a/src/test_data.h b/src/test_data.h index 27e5b1444..91f1f40fc 100644 --- a/src/test_data.h +++ b/src/test_data.h @@ -50,7 +50,8 @@ static const char * TEST_DATA[] = { "08 00 E3 00 01 00 01 00 00 00 00 00 00 00 00 00 DF 00 64 55", // test 45 - heatpump Enviline "08 00 E5 00 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0A", // test 46 - heatpump Enviline "38 10 FF 00 03 2B 00 C7 07 C3 01", // test 47 - heatpump Enviline - "08 0B 19 00 00 F7 80 00 80 00 00 00 00 00 03 58 97 0C 7B 1F 00 00 00 06 C4 DF 02 64 48 80 00" // test 48 - outdoor temp check + "08 0B 19 00 00 F7 80 00 80 00 00 00 00 00 03 58 97 0C 7B 1F 00 00 00 06 C4 DF 02 64 48 80 00", // test 48 - outdoor temp check + "88 00 19 00 00 DC 80 00 80 00 FF FF 00 00 00 21 9A 06 E1 7C 00 00 00 06 C2 13 00 1E 90 80 00" // test 49 - check max length }; From 6fb30c73521c5208c051402ead25be9348c6d99d Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 1 Jul 2019 09:15:14 +0200 Subject: [PATCH 37/89] bump --- src/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h b/src/version.h index 8cd9a181e..85543c971 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.8.1b7" +#define APP_VERSION "1.8.1b8" #define APP_HOSTNAME "ems-esp" From 533a3b34084a2168155343a2b5ba852759add917 Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 1 Jul 2019 09:15:38 +0200 Subject: [PATCH 38/89] stop all other processes when updating via OTA for speed --- lib/MyESP/MyESP.cpp | 17 ++++++++++++++--- lib/MyESP/MyESP.h | 3 ++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/lib/MyESP/MyESP.cpp b/lib/MyESP/MyESP.cpp index ea6e44581..7e891615a 100644 --- a/lib/MyESP/MyESP.cpp +++ b/lib/MyESP/MyESP.cpp @@ -73,6 +73,7 @@ MyESP::MyESP() { _ota_pre_callback = NULL; _ota_post_callback = NULL; + _ota_doing_update = false; _suspendOutput = false; @@ -470,6 +471,8 @@ void MyESP::_OTACallback() { // stop the web server webServer.close(); + _ota_doing_update = true; + if (_ota_pre_callback) { (_ota_pre_callback)(); // call custom function } @@ -487,9 +490,11 @@ void MyESP::_ota_setup() { ArduinoOTA.onStart([this]() { _OTACallback(); }); ArduinoOTA.onEnd([this]() { myDebug_P(PSTR("[OTA] Done, restarting...")); + _ota_doing_update = false; _deferredReset(500, CUSTOM_RESET_OTA); }); + /* ArduinoOTA.onProgress([this](unsigned int progress, unsigned int total) { static unsigned int _progOld; unsigned int _prog = (progress / (total / 100)); @@ -498,6 +503,7 @@ void MyESP::_ota_setup() { _progOld = _prog; } }); + */ ArduinoOTA.onError([this](ota_error_t error) { if (error == OTA_AUTH_ERROR) @@ -2186,6 +2192,13 @@ void MyESP::_bootupSequence() { * Loop. This is called as often as possible and it handles wifi, telnet, mqtt etc */ void MyESP::loop() { + jw.loop(); // WiFi + ArduinoOTA.handle(); // OTA + + if (_ota_doing_update) { + return; // quit if in the middle of an update + } + _calculateLoad(); _systemCheckLoop(); _heartbeatCheck(); @@ -2197,9 +2210,7 @@ void MyESP::loop() { _telnetHandle(); } - jw.loop(); // WiFi - ArduinoOTA.handle(); // OTA - _mqttConnect(); // MQTT + _mqttConnect(); // MQTT yield(); // ...and breath } diff --git a/lib/MyESP/MyESP.h b/lib/MyESP/MyESP.h index e91203b3e..4ed582196 100644 --- a/lib/MyESP/MyESP.h +++ b/lib/MyESP/MyESP.h @@ -9,7 +9,7 @@ #ifndef MyEMS_h #define MyEMS_h -#define MYESP_VERSION "1.1.19" +#define MYESP_VERSION "1.1.20" #include #include @@ -335,6 +335,7 @@ class MyESP { ota_callback_f _ota_post_callback; void _ota_setup(); void _OTACallback(); + bool _ota_doing_update; // crash void _eeprom_setup(); From 83d12ecba27907b80db976ab19f436543f604d4b Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 1 Jul 2019 09:47:09 +0200 Subject: [PATCH 39/89] max ssid/password lengths --- lib/MyESP/MyESP.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/MyESP/MyESP.cpp b/lib/MyESP/MyESP.cpp index 7e891615a..8eb3d00c2 100644 --- a/lib/MyESP/MyESP.cpp +++ b/lib/MyESP/MyESP.cpp @@ -2051,7 +2051,7 @@ void MyESP::_webResetPage() { } else { // Create a string containing all the arguments // Check to see if there are new values (also doubles to check the length of the new value is long enough) - if (webServer.arg("newssid").length() < MAX_SSID_LEN) { + if (webServer.arg("newssid").length() <= MAX_SSID_LEN) { if (webServer.arg("newssid").length() == 0) { _wifi_ssid = NULL; } else { @@ -2059,7 +2059,7 @@ void MyESP::_webResetPage() { } } - if (webServer.arg("newpassword").length() < MAX_PWD_LEN) { + if (webServer.arg("newpassword").length() <= MAX_PWD_LEN) { if (webServer.arg("newpassword").length() == 0) { _wifi_password = NULL; } else { From 21ae6ebc0dd753958c38f8ccc24bd395330bffde Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 1 Jul 2019 09:47:29 +0200 Subject: [PATCH 40/89] handle rendering of signed shorts nicer --- src/ems-esp.cpp | 68 +++++++++++++++++++++++++------------------------ src/ems.h | 9 ++++--- 2 files changed, 40 insertions(+), 37 deletions(-) diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index 554ce189a..664368f95 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -174,11 +174,12 @@ char * _bool_to_char(char * s, uint8_t value) { } // convert short (two bytes) to text string -// decimals: 0 = no division, 1=divide value by 10, 10=divide value by 100 +// decimals: 0 = no division, 1=divide value by 10, 2=divide by 2, 10=divide value by 100 // negative values are assumed stored as 1-compliment (https://medium.com/@LeeJulija/how-integers-are-stored-in-memory-using-twos-complement-5ba04d61a56c) char * _short_to_char(char * s, int16_t value, uint8_t decimals = 1) { + // remove errors or invalid values - if (abs(value) >= EMS_VALUE_SHORT_NOTSET) { + if (value == EMS_VALUE_SHORT_NOTSET) { strlcpy(s, "?", 10); return (s); } @@ -194,18 +195,25 @@ char * _short_to_char(char * s, int16_t value, uint8_t decimals = 1) { // check for negative values if (value < 0) { strlcpy(s, "-", 10); - value = abs(value); + value *= -1; // convert to positive } - strlcpy(s, ltoa(value / (decimals * 10), s2, 10), 10); - strlcat(s, ".", 10); - strlcat(s, ltoa(value % (decimals * 10), s2, 10), 10); + if (decimals == 2) { + // divide by 2 + strlcpy(s, ltoa(value / 2, s2, 10), 10); + strlcat(s, ".", 10); + strlcat(s, ltoa(value % 2, s2, 10), 10); + } else { + strlcpy(s, ltoa(value / (decimals * 10), s2, 10), 10); + strlcat(s, ".", 10); + strlcat(s, ltoa(value % (decimals * 10), s2, 10), 10); + } return s; } // takes a short value (2 bytes), converts to a fraction -// decimals: 0 = no division, 1=divide value by 10, 10=divide value by 100 +// decimals: 0 = no division, 1=divide value by 10, 2=divide by 2, 10=divide value by 100 void _renderShortValue(const char * prefix, const char * postfix, int16_t value, uint8_t decimals = 1) { static char buffer[200] = {0}; static char s[20] = {0}; @@ -428,7 +436,7 @@ void showInfo() { _renderIntValue("Boiler circuit pump modulation min power", "%", EMS_Boiler.pump_mod_min); // UBAMonitorSlow - if (EMS_Boiler.extTemp != (int16_t)EMS_VALUE_SHORT_NOTSET) { + if (EMS_Boiler.extTemp != EMS_VALUE_SHORT_NOTSET) { _renderShortValue("Outside temperature", "C", EMS_Boiler.extTemp); } _renderShortValue("Boiler temperature", "C", EMS_Boiler.boilTemp); @@ -497,14 +505,8 @@ void showInfo() { _renderShortValue("Current room temperature", "C", EMS_Thermostat.curr_roomTemp, 1); // *10 } else { // because we store in 2 bytes short, when converting to a single byte we'll loose the negative value if its unset - if (EMS_Thermostat.setpoint_roomTemp <= 0) { - EMS_Thermostat.setpoint_roomTemp = EMS_VALUE_INT_NOTSET; - } - if (EMS_Thermostat.curr_roomTemp <= 0) { - EMS_Thermostat.curr_roomTemp = EMS_VALUE_INT_NOTSET; - } - _renderIntValue("Setpoint room temperature", "C", EMS_Thermostat.setpoint_roomTemp, 2); // convert to a single byte * 2 - _renderIntValue("Current room temperature", "C", EMS_Thermostat.curr_roomTemp, 10); // is *10 + _renderShortValue("Setpoint room temperature", "C", EMS_Thermostat.setpoint_roomTemp, 2); // convert to a single byte * 2 + _renderShortValue("Current room temperature", "C", EMS_Thermostat.curr_roomTemp, 1); // is *10 } // Render Day/Night/Holiday Temperature @@ -629,19 +631,19 @@ void publishValues(bool force) { if (EMS_Boiler.pumpMod != EMS_VALUE_INT_NOTSET) rootBoiler["pumpMod"] = EMS_Boiler.pumpMod; - if (abs(EMS_Boiler.extTemp) < EMS_VALUE_SHORT_NOTSET) + if (EMS_Boiler.extTemp != EMS_VALUE_SHORT_NOTSET) rootBoiler["outdoorTemp"] = (double)EMS_Boiler.extTemp / 10; - if (abs(EMS_Boiler.wWCurTmp) < EMS_VALUE_SHORT_NOTSET) + if (EMS_Boiler.wWCurTmp != EMS_VALUE_SHORT_NOTSET) rootBoiler["wWCurTmp"] = (double)EMS_Boiler.wWCurTmp / 10; - if (abs(EMS_Boiler.wWCurFlow) != EMS_VALUE_INT_NOTSET) + if (EMS_Boiler.wWCurFlow != EMS_VALUE_INT_NOTSET) rootBoiler["wWCurFlow"] = (double)EMS_Boiler.wWCurFlow / 10; - if (abs(EMS_Boiler.curFlowTemp) < EMS_VALUE_SHORT_NOTSET) + if (EMS_Boiler.curFlowTemp != EMS_VALUE_SHORT_NOTSET) rootBoiler["curFlowTemp"] = (double)EMS_Boiler.curFlowTemp / 10; - if (abs(EMS_Boiler.retTemp) < EMS_VALUE_SHORT_NOTSET) + if (EMS_Boiler.retTemp != EMS_VALUE_SHORT_NOTSET) rootBoiler["retTemp"] = (double)EMS_Boiler.retTemp / 10; - if (abs(EMS_Boiler.sysPress) != EMS_VALUE_INT_NOTSET) + if (EMS_Boiler.sysPress != EMS_VALUE_INT_NOTSET) rootBoiler["sysPress"] = (double)EMS_Boiler.sysPress / 10; - if (abs(EMS_Boiler.boilTemp) < EMS_VALUE_SHORT_NOTSET) + if (EMS_Boiler.boilTemp != EMS_VALUE_SHORT_NOTSET) rootBoiler["boilTemp"] = (double)EMS_Boiler.boilTemp / 10; if (EMS_Boiler.wWActivated != EMS_VALUE_INT_NOTSET) @@ -696,7 +698,7 @@ void publishValues(bool force) { // handle the thermostat values separately if (ems_getThermostatEnabled()) { // only send thermostat values if we actually have them - if ((EMS_Thermostat.curr_roomTemp <= 0) && (EMS_Thermostat.setpoint_roomTemp <= 0)) + if ((EMS_Thermostat.curr_roomTemp == EMS_VALUE_SHORT_NOTSET) || (EMS_Thermostat.setpoint_roomTemp == EMS_VALUE_SHORT_NOTSET)) return; // build new json object @@ -707,15 +709,15 @@ void publishValues(bool force) { // different logic depending on thermostat types if ((ems_getThermostatModel() == EMS_MODEL_EASY) || (ems_getThermostatModel() == EMS_MODEL_FR10) || (ems_getThermostatModel() == EMS_MODEL_FW100)) { - if (abs(EMS_Thermostat.setpoint_roomTemp) < EMS_VALUE_SHORT_NOTSET) + if (EMS_Thermostat.setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET) rootThermostat[THERMOSTAT_SELTEMP] = (double)EMS_Thermostat.setpoint_roomTemp / 10; - if (abs(EMS_Thermostat.curr_roomTemp) < EMS_VALUE_SHORT_NOTSET) + if (EMS_Thermostat.curr_roomTemp != EMS_VALUE_SHORT_NOTSET) rootThermostat[THERMOSTAT_CURRTEMP] = (double)EMS_Thermostat.curr_roomTemp / 10; } else { - if (EMS_Thermostat.setpoint_roomTemp != EMS_VALUE_INT_NOTSET) + if (EMS_Thermostat.setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET) rootThermostat[THERMOSTAT_SELTEMP] = (double)EMS_Thermostat.setpoint_roomTemp / 2; - if (EMS_Thermostat.curr_roomTemp != EMS_VALUE_INT_NOTSET) + if (EMS_Thermostat.curr_roomTemp != EMS_VALUE_SHORT_NOTSET) rootThermostat[THERMOSTAT_CURRTEMP] = (double)EMS_Thermostat.curr_roomTemp / 10; if (EMS_Thermostat.daytemp != EMS_VALUE_INT_NOTSET) @@ -777,10 +779,10 @@ void publishValues(bool force) { doc.clear(); JsonObject rootSM = doc.to(); - if (abs(EMS_SolarModule.collectorTemp) != EMS_VALUE_SHORT_NOTSET) + if (EMS_SolarModule.collectorTemp != EMS_VALUE_SHORT_NOTSET) rootSM[SM_COLLECTORTEMP] = (double)EMS_SolarModule.collectorTemp / 10; - if (abs(EMS_SolarModule.bottomTemp) != EMS_VALUE_SHORT_NOTSET) + if (EMS_SolarModule.bottomTemp != EMS_VALUE_SHORT_NOTSET) rootSM[SM_BOTTOMTEMP] = (double)EMS_SolarModule.bottomTemp / 10; if (EMS_SolarModule.pumpModulation != EMS_VALUE_INT_NOTSET) @@ -794,13 +796,13 @@ void publishValues(bool force) { rootSM[SM_PUMPWORKMIN] = (double)EMS_SolarModule.pumpWorkMin; } - if (abs(EMS_SolarModule.EnergyLastHour) != EMS_VALUE_SHORT_NOTSET) + if (EMS_SolarModule.EnergyLastHour != EMS_VALUE_SHORT_NOTSET) rootSM[SM_ENERGYLASTHOUR] = (double)EMS_SolarModule.EnergyLastHour / 10; - if (abs(EMS_SolarModule.EnergyToday) != EMS_VALUE_SHORT_NOTSET) + if (EMS_SolarModule.EnergyToday != EMS_VALUE_SHORT_NOTSET) rootSM[SM_ENERGYTODAY] = EMS_SolarModule.EnergyToday; - if (abs(EMS_SolarModule.EnergyTotal) != EMS_VALUE_SHORT_NOTSET) + if (EMS_SolarModule.EnergyTotal != EMS_VALUE_SHORT_NOTSET) rootSM[SM_ENERGYTOTAL] = (double)EMS_SolarModule.EnergyTotal / 10; data[0] = '\0'; // reset data for next package diff --git a/src/ems.h b/src/ems.h index 5b6ade639..346c2fbbb 100644 --- a/src/ems.h +++ b/src/ems.h @@ -34,10 +34,11 @@ #define EMS_MAX_TELEGRAM_LENGTH 32 // default values -#define EMS_VALUE_INT_ON 1 // boolean true -#define EMS_VALUE_INT_OFF 0 // boolean false -#define EMS_VALUE_INT_NOTSET 0xFF // for 8-bit ints -#define EMS_VALUE_SHORT_NOTSET 0x8000 // for 2-byte signed shorts +#define EMS_VALUE_INT_ON 1 // boolean true +#define EMS_VALUE_INT_OFF 0 // boolean false +#define EMS_VALUE_INT_NOTSET 0xFF // for 8-bit unsigned ints/bytes +//#define EMS_VALUE_SHORT_NOTSET 0x8000 // for 2-byte signed shorts +#define EMS_VALUE_SHORT_NOTSET -32768 // for 2-byte signed shorts #define EMS_VALUE_LONG_NOTSET 0xFFFFFF // for 3-byte longs #define EMS_THERMOSTAT_WRITE_YES true From 18cb01b57fec02322952a13f472ed5171d01cd58 Mon Sep 17 00:00:00 2001 From: Paul Date: Tue, 2 Jul 2019 22:46:24 +0200 Subject: [PATCH 41/89] renamed previousSMPublishCRC --- src/ems-esp.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index 664368f95..affad8330 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -177,7 +177,6 @@ char * _bool_to_char(char * s, uint8_t value) { // decimals: 0 = no division, 1=divide value by 10, 2=divide by 2, 10=divide value by 100 // negative values are assumed stored as 1-compliment (https://medium.com/@LeeJulija/how-integers-are-stored-in-memory-using-twos-complement-5ba04d61a56c) char * _short_to_char(char * s, int16_t value, uint8_t decimals = 1) { - // remove errors or invalid values if (value == EMS_VALUE_SHORT_NOTSET) { strlcpy(s, "?", 10); @@ -608,7 +607,7 @@ void publishValues(bool force) { static uint8_t last_boilerActive = 0xFF; // for remembering last setting of the tap water or heating on/off static uint32_t previousBoilerPublishCRC = 0; // CRC check for boiler values static uint32_t previousThermostatPublishCRC = 0; // CRC check for thermostat values - static uint32_t previousOtherPublishCRC = 0; // CRC check for other values (e.g. SM10) + static uint32_t previousSMPublishCRC = 0; // CRC check for Solar Module values (e.g. SM10) JsonObject rootBoiler = doc.to(); @@ -814,8 +813,8 @@ void publishValues(bool force) { crc.update(data[i]); } fchecksum = crc.finalize(); - if ((previousOtherPublishCRC != fchecksum) || force) { - previousOtherPublishCRC = fchecksum; + if ((previousSMPublishCRC != fchecksum) || force) { + previousSMPublishCRC = fchecksum; myDebugLog("Publishing SM data via MQTT"); // send values via MQTT From 6368b122559e171b69d1dede02142318be44584f Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 3 Jul 2019 22:43:44 +0200 Subject: [PATCH 42/89] https://github.com/proddy/EMS-ESP/issues/144 --- src/ems-esp.cpp | 3 ++- src/ems_devices.h | 22 +++++++++++----------- src/version.h | 2 +- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index affad8330..c285b09fd 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -201,7 +201,8 @@ char * _short_to_char(char * s, int16_t value, uint8_t decimals = 1) { // divide by 2 strlcpy(s, ltoa(value / 2, s2, 10), 10); strlcat(s, ".", 10); - strlcat(s, ltoa(value % 2, s2, 10), 10); + strlcat(s, ((value & 0x01) ? "5" : "0"), 10); + } else { strlcpy(s, ltoa(value / (decimals * 10), s2, 10), 10); strlcat(s, ".", 10); diff --git a/src/ems_devices.h b/src/ems_devices.h index fc02e8395..30f2105ba 100644 --- a/src/ems_devices.h +++ b/src/ems_devices.h @@ -41,17 +41,17 @@ #define EMS_OFFSET_UBASetPoints_flowtemp 0 // flow temp // Other -#define EMS_TYPE_SM10Monitor 0x97 // SM10Monitor -#define EMS_TYPE_SM100Monitor 0x0262 // SM100Monitor -#define EMS_TYPE_SM100Status 0x0264 // SM100Status -#define EMS_TYPE_SM100Status2 0x026A // SM100Status2 -#define EMS_TYPE_SM100Energy 0x028E // SM100Energy -#define EMS_TYPE_HPMonitor1 0xE3 // HeatPump Monitor 1 -#define EMS_TYPE_HPMonitor2 0xE5 // HeatPump Monitor 2 +#define EMS_TYPE_SM10Monitor 0x97 // SM10Monitor +#define EMS_TYPE_SM100Monitor 0x0262 // SM100Monitor +#define EMS_TYPE_SM100Status 0x0264 // SM100Status +#define EMS_TYPE_SM100Status2 0x026A // SM100Status2 +#define EMS_TYPE_SM100Energy 0x028E // SM100Energy +#define EMS_TYPE_HPMonitor1 0xE3 // HeatPump Monitor 1 +#define EMS_TYPE_HPMonitor2 0xE5 // HeatPump Monitor 2 -#define EMS_TYPE_ISM1StatusMessage 0x0003 // Solar Module Junkers ISM1 Status -#define EMS_TYPE_ISM1Set 0x0001 // for setting values of the solar module like max boiler temp -#define EMS_OFFSET_ISM1Set_MaxBoilerTemp 6 // position of max boiler temp e.g. 50 in the following example: 90 30 FF 06 00 01 50 (CRC=2C) +#define EMS_TYPE_ISM1StatusMessage 0x0003 // Solar Module Junkers ISM1 Status +#define EMS_TYPE_ISM1Set 0x0001 // for setting values of the solar module like max boiler temp +#define EMS_OFFSET_ISM1Set_MaxBoilerTemp 6 // position of max boiler temp e.g. 50 in the following example: 90 30 FF 06 00 01 50 (CRC=2C) /* * Thermostats... @@ -219,7 +219,7 @@ const _Thermostat_Type Thermostat_Types[] = { {EMS_MODEL_RC20F, 93, 0x18, "RC20F", EMS_THERMOSTAT_WRITE_YES}, {EMS_MODEL_RC30, 78, 0x10, "RC30/Nefit Moduline 400", EMS_THERMOSTAT_WRITE_YES}, {EMS_MODEL_RC35, 86, 0x10, "RC35", EMS_THERMOSTAT_WRITE_YES}, - {EMS_MODEL_RC310, 158, 0x10, "RC3x0/Nefit Moduline 1010H", EMS_THERMOSTAT_WRITE_NO}, + {EMS_MODEL_RC310, 158, 0x10, "RC300/RC310/Nefit Moduline 1010/3000", EMS_THERMOSTAT_WRITE_NO}, {EMS_MODEL_1010, 165, 0x18, "Nefit Moduline 1010", EMS_THERMOSTAT_WRITE_NO}, // Sieger diff --git a/src/version.h b/src/version.h index 85543c971..e18b217c5 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.8.1b8" +#define APP_VERSION "1.8.1b9" #define APP_HOSTNAME "ems-esp" From e2804cabc08c0be04ba345a94d7f886a7f66bdef Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 4 Jul 2019 22:58:33 +0200 Subject: [PATCH 43/89] added option to enable serial on new installations --- lib/MyESP/MyESP.cpp | 85 ++++++++++++++++++++---------------------- lib/MyESP/MyESP.h | 3 +- platformio.ini-example | 5 ++- 3 files changed, 45 insertions(+), 48 deletions(-) diff --git a/lib/MyESP/MyESP.cpp b/lib/MyESP/MyESP.cpp index 8eb3d00c2..22354bd4a 100644 --- a/lib/MyESP/MyESP.cpp +++ b/lib/MyESP/MyESP.cpp @@ -47,7 +47,9 @@ MyESP::MyESP() { _helpProjectCmds = NULL; _helpProjectCmds_count = 0; - _serial = false; + _serial = false; + _serial_default = false; + _heartbeat = false; _mqtt_host = NULL; _mqtt_password = NULL; @@ -198,7 +200,7 @@ void MyESP::_wifiCallback(justwifi_messages_t code, char * parameter) { // finally if we don't want Serial anymore, turn it off if (!_serial) { - myDebug_P(PSTR("Disabling serial port communication.")); + myDebug_P(PSTR("[SYSTEM] Disabling serial port communication.")); SerialAndTelnet.flush(); // flush so all buffer is printed to serial SerialAndTelnet.setSerial(NULL); } @@ -837,16 +839,9 @@ bool MyESP::_changeSetting(uint8_t wc, const char * setting, const char * value) } // force the serial on/off -void MyESP::setUseSerial(bool toggle) { - //(void)fs_saveConfig(); // save the setting for next reboot - - if (toggle) { - SerialAndTelnet.setSerial(&Serial); - _serial = true; - } else { - SerialAndTelnet.setSerial(NULL); - _serial = false; - } +void MyESP::setUseSerial(bool b) { + _serial_default = _serial = b; + SerialAndTelnet.setSerial(b ? &Serial : NULL); } void MyESP::_telnetCommand(char * commandLine) { @@ -1604,9 +1599,7 @@ bool MyESP::_fs_loadConfig() { value = json["mqtt_password"]; _mqtt_password = (value) ? strdup(value) : NULL; - _serial = (bool)json["serial"]; // defaults to off - - // _serial = true; // uncomment for debugging everything to serial + _serial = json["serial"] | _serial_default; _heartbeat = (bool)json["heartbeat"]; // defaults to off @@ -2122,6 +2115,38 @@ void MyESP::_webserver_setup() { webServer.on("/resetall", [this]() { _webResetAllPage(); }); webServer.begin(); + + myDebug_P(PSTR("[WEB] Web server started.")); +} + +// bootup sequence +// quickly flash LED until we get a Wifi connection, or AP established +// fast way is to use WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + (state ? 4 : 8), (1 << EMSESP_Status.led_gpio)); // 4 is on, 8 is off +void MyESP::_bootupSequence() { + uint8_t boot_status = getSystemBootStatus(); + + if ((boot_status == MYESP_BOOTSTATUS_BOOTED) || (millis() <= MYESP_BOOTUP_DELAY)) { + return; // already booted, or still starting up + } + + // only kick in after a few seconds + if (boot_status == MYESP_BOOTSTATUS_POWERON) { + _setSystemBootStatus(MYESP_BOOTSTATUS_BOOTING); + } + + static uint32_t last_bootupflash = 0; + + // flash LED quickly + if ((millis() - last_bootupflash > MYESP_BOOTUP_FLASHDELAY)) { + last_bootupflash = millis(); + int state = digitalRead(LED_BUILTIN); + digitalWrite(LED_BUILTIN, !state); + } + + if (isWifiConnected()) { + _setSystemBootStatus(MYESP_BOOTSTATUS_BOOTED); // completed, reset flag + digitalWrite(LED_BUILTIN, LOW); // turn off LED + } } // setup MyESP @@ -2158,36 +2183,6 @@ void MyESP::begin(const char * app_hostname, const char * app_name, const char * _heartbeatCheck(true); // force heartbeat } -// bootup sequence -// quickly flash LED until we get a Wifi connection, or AP established -// fast way is to use WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + (state ? 4 : 8), (1 << EMSESP_Status.led_gpio)); // 4 is on, 8 is off -void MyESP::_bootupSequence() { - uint8_t boot_status = getSystemBootStatus(); - - if ((boot_status == MYESP_BOOTSTATUS_BOOTED) || (millis() <= MYESP_BOOTUP_DELAY)) { - return; // already booted, or still starting up - } - - // only kick in after a few seconds - if (boot_status == MYESP_BOOTSTATUS_POWERON) { - _setSystemBootStatus(MYESP_BOOTSTATUS_BOOTING); - } - - static uint32_t last_bootupflash = 0; - - // flash LED quickly - if ((millis() - last_bootupflash > MYESP_BOOTUP_FLASHDELAY)) { - last_bootupflash = millis(); - int state = digitalRead(LED_BUILTIN); - digitalWrite(LED_BUILTIN, !state); - } - - if (isWifiConnected()) { - _setSystemBootStatus(MYESP_BOOTSTATUS_BOOTED); // completed, reset flag - digitalWrite(LED_BUILTIN, LOW); // turn off LED - } -} - /* * Loop. This is called as often as possible and it handles wifi, telnet, mqtt etc */ diff --git a/lib/MyESP/MyESP.h b/lib/MyESP/MyESP.h index 4ed582196..330a3b7f2 100644 --- a/lib/MyESP/MyESP.h +++ b/lib/MyESP/MyESP.h @@ -9,7 +9,7 @@ #ifndef MyEMS_h #define MyEMS_h -#define MYESP_VERSION "1.1.20" +#define MYESP_VERSION "1.1.21" #include #include @@ -377,6 +377,7 @@ class MyESP { char * _boottime; bool _suspendOutput; bool _serial; + bool _serial_default; bool _heartbeat; unsigned long _getUptime(); String _buildTime(); diff --git a/platformio.ini-example b/platformio.ini-example index 4a816c41e..bc05a1bea 100644 --- a/platformio.ini-example +++ b/platformio.ini-example @@ -8,10 +8,11 @@ default_envs = debug [common] -; -DMYESP_TIMESTAMP -DTESTS -DCRASH +; -DMYESP_TIMESTAMP -DTESTS -DCRASH -DNO_SERIAL +; -DNO_SERIAL if you want a fresh install to use the Serial port debug_flags = -Wall -DCRASH release_flags = -w -general_flags = -g -DNO_GLOBAL_EEPROM +general_flags = -g -DNO_GLOBAL_EEPROM -DDNO_SERIAL arduino_core_2_3_0 = espressif8266@1.5.0 arduino_core_2_4_0 = espressif8266@1.6.0 From 335692c2ef33352abb4f7b96cf5acd5f038b4cc6 Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 4 Jul 2019 22:58:44 +0200 Subject: [PATCH 44/89] bump --- src/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h b/src/version.h index e18b217c5..ca2730cd0 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.8.1b9" +#define APP_VERSION "1.8.1b10" #define APP_HOSTNAME "ems-esp" From 9bc8b3d81189fc70a833ab823b62975a247aa64a Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 4 Jul 2019 22:59:03 +0200 Subject: [PATCH 45/89] cleanup other devices & SM --- src/ems-esp.cpp | 23 ++++++--- src/ems.cpp | 124 +++++++++++++++++++++++----------------------- src/ems.h | 37 ++++++++------ src/ems_devices.h | 83 +++++++++++++++++-------------- 4 files changed, 146 insertions(+), 121 deletions(-) diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index c285b09fd..da6a8559a 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -480,12 +480,12 @@ void showInfo() { } // For HeatPumps - if (EMS_Other.HP) { + if (ems_getHeatPumpEnabled()) { myDebug_P(PSTR("")); // newline myDebug_P(PSTR("%sHeat Pump stats:%s"), COLOR_BOLD_ON, COLOR_BOLD_OFF); myDebug_P(PSTR(" Solar Module: %s"), ems_getHeatPumpDescription(buffer_type)); - _renderIntValue("Pump modulation", "%", EMS_Other.HPModulation); - _renderIntValue("Pump speed", "%", EMS_Other.HPSpeed); + _renderIntValue("Pump modulation", "%", EMS_HeatPump.HPModulation); + _renderIntValue("Pump speed", "%", EMS_HeatPump.HPSpeed); } // Thermostat stats @@ -824,16 +824,16 @@ void publishValues(bool force) { } // handle HeatPump - if (EMS_Other.HP) { + if (ems_getHeatPumpEnabled()) { // build new json object doc.clear(); JsonObject rootSM = doc.to(); - if (EMS_Other.HPModulation != EMS_VALUE_INT_NOTSET) - rootSM[HP_PUMPMODULATION] = EMS_Other.HPModulation; + if (EMS_HeatPump.HPModulation != EMS_VALUE_INT_NOTSET) + rootSM[HP_PUMPMODULATION] = EMS_HeatPump.HPModulation; - if (EMS_Other.HPSpeed != EMS_VALUE_INT_NOTSET) - rootSM[HP_PUMPSPEED] = EMS_Other.HPSpeed; + if (EMS_HeatPump.HPSpeed != EMS_VALUE_INT_NOTSET) + rootSM[HP_PUMPSPEED] = EMS_HeatPump.HPSpeed; data[0] = '\0'; // reset data for next package serializeJson(doc, data, sizeof(data)); @@ -1721,6 +1721,13 @@ void setup() { // web custom settings myESP.setWeb(WebCallback); +// serial off as default for fresh installs +#ifdef NO_SERIAL + myESP.setUseSerial(false); +#else + myESP.setUseSerial(true); +#endif + // start up all the services myESP.begin(APP_HOSTNAME, APP_NAME, APP_VERSION); diff --git a/src/ems.cpp b/src/ems.cpp index 05a79ece1..7d3402dde 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -121,17 +121,18 @@ const _EMS_Type EMS_Types[] = { {EMS_MODEL_UBA, EMS_TYPE_UBAParametersMessage, "UBAParametersMessage", _process_UBAParametersMessage}, {EMS_MODEL_UBA, EMS_TYPE_UBASetPoints, "UBASetPoints", _process_SetPoints}, - // Other devices - {EMS_MODEL_OTHER, EMS_TYPE_SM10Monitor, "SM10Monitor", _process_SM10Monitor}, - {EMS_MODEL_OTHER, EMS_TYPE_SM100Monitor, "SM100Monitor", _process_SM100Monitor}, - {EMS_MODEL_OTHER, EMS_TYPE_SM100Status, "SM100Status", _process_SM100Status}, - {EMS_MODEL_OTHER, EMS_TYPE_SM100Status2, "SM100Status2", _process_SM100Status2}, - {EMS_MODEL_OTHER, EMS_TYPE_SM100Energy, "SM100Energy", _process_SM100Energy}, - {EMS_MODEL_OTHER, EMS_TYPE_HPMonitor1, "HeatPumpMonitor1", _process_HPMonitor1}, - {EMS_MODEL_OTHER, EMS_TYPE_HPMonitor2, "HeatPumpMonitor2", _process_HPMonitor2}, - {EMS_MODEL_OTHER, EMS_TYPE_ISM1StatusMessage, "ISM1StatusMessage", _process_ISM1StatusMessage}, - {EMS_MODEL_OTHER, EMS_TYPE_ISM1Set, "ISM1Set", _process_ISM1Set}, + // SM devices + {EMS_MODEL_SM, EMS_TYPE_SM10Monitor, "SM10Monitor", _process_SM10Monitor}, + {EMS_MODEL_SM, EMS_TYPE_SM100Monitor, "SM100Monitor", _process_SM100Monitor}, + {EMS_MODEL_SM, EMS_TYPE_SM100Status, "SM100Status", _process_SM100Status}, + {EMS_MODEL_SM, EMS_TYPE_SM100Status2, "SM100Status2", _process_SM100Status2}, + {EMS_MODEL_SM, EMS_TYPE_SM100Energy, "SM100Energy", _process_SM100Energy}, + {EMS_MODEL_SM, EMS_TYPE_ISM1StatusMessage, "ISM1StatusMessage", _process_ISM1StatusMessage}, + {EMS_MODEL_SM, EMS_TYPE_ISM1Set, "ISM1Set", _process_ISM1Set}, + // heatpunps + {EMS_MODEL_HP, EMS_TYPE_HPMonitor1, "HeatPumpMonitor1", _process_HPMonitor1}, + {EMS_MODEL_HP, EMS_TYPE_HPMonitor2, "HeatPumpMonitor2", _process_HPMonitor2}, // RC10 {EMS_MODEL_RC10, EMS_TYPE_RCTime, "RCTime", _process_RCTime}, @@ -190,11 +191,13 @@ uint8_t _Boiler_Types_max = ArraySize(Boiler_Types); // number of boi uint8_t _Solar_Module_Types_max = ArraySize(SolarModule_Types); // number of solar module types uint8_t _Other_Types_max = ArraySize(Other_Types); // number of other ems devices uint8_t _Thermostat_Types_max = ArraySize(Thermostat_Types); // number of defined thermostat types +uint8_t _HeatPump_Types_max = ArraySize(HeatPump_Types); // number of defined heatpuimp types -// these structs contain the data we store from the Boiler and Thermostat +// these structs contain the data we store from the specific EMS devices _EMS_Boiler EMS_Boiler; // for boiler _EMS_Thermostat EMS_Thermostat; // for thermostat _EMS_SolarModule EMS_SolarModule; // for solar modules +_EMS_HeatPump EMS_HeatPump; // for heatpumps _EMS_Other EMS_Other; // for other known EMS devices // CRC lookup table with poly 12 for faster checking @@ -318,11 +321,11 @@ void ems_init() { EMS_SolarModule.pumpWorkMin = EMS_VALUE_LONG_NOTSET; // Other EMS devices values - EMS_Other.HPModulation = EMS_VALUE_INT_NOTSET; - EMS_Other.HPSpeed = EMS_VALUE_INT_NOTSET; - EMS_Other.device_id = EMS_ID_NONE; - EMS_Other.model_id = EMS_MODEL_NONE; - EMS_Other.product_id = EMS_ID_NONE; + EMS_HeatPump.HPModulation = EMS_VALUE_INT_NOTSET; + EMS_HeatPump.HPSpeed = EMS_VALUE_INT_NOTSET; + EMS_HeatPump.device_id = EMS_ID_NONE; + EMS_HeatPump.model_id = EMS_MODEL_NONE; + EMS_HeatPump.product_id = EMS_ID_NONE; // calculated values EMS_Boiler.tapwaterActive = EMS_VALUE_INT_NOTSET; // Hot tap water is on/off @@ -337,8 +340,6 @@ void ems_init() { EMS_Thermostat.product_id = EMS_ID_NONE; strlcpy(EMS_Thermostat.version, "?", sizeof(EMS_Thermostat.version)); - // set other types - EMS_Other.HP = false; // default logging is none ems_setLogging(EMS_SYS_LOGGING_DEFAULT); @@ -395,12 +396,12 @@ bool ems_getSolarModuleEnabled() { return (EMS_SolarModule.device_id != EMS_ID_NONE); } -uint8_t ems_getThermostatModel() { - return (EMS_Thermostat.model_id); +bool ems_getHeatPumpEnabled() { + return (EMS_HeatPump.device_id != EMS_ID_NONE); } -uint8_t ems_getOtherModel() { - return (EMS_Other.model_id); +uint8_t ems_getThermostatModel() { + return (EMS_Thermostat.model_id); } uint8_t ems_getSolarModuleModel() { @@ -1406,7 +1407,6 @@ void _process_SM10Monitor(_EMS_RxTelegram * EMS_RxTelegram) { EMS_SolarModule.pumpModulation = _toByte(4); // modulation solar pump EMS_SolarModule.pump = _bitRead(7, 1); // active if bit 1 is set - // EMS_Other.SM = true; EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT } @@ -1428,7 +1428,6 @@ void _process_SM100Monitor(_EMS_RxTelegram * EMS_RxTelegram) { EMS_SolarModule.bottomTemp = _toShort(2); // bottom temp from SM100, is *10 } - // EMS_Other.SM = true; EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT } @@ -1446,7 +1445,6 @@ void _process_SM100Status(_EMS_RxTelegram * EMS_RxTelegram) { EMS_SolarModule.pumpModulation = _toByte(0); // modulation solar pump } - // EMS_Other.SM = true; EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT } @@ -1462,7 +1460,6 @@ void _process_SM100Status2(_EMS_RxTelegram * EMS_RxTelegram) { EMS_SolarModule.pump = _bitRead(0, 2); // 03=off 04=on } - // EMS_Other.SM = true; EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT } @@ -1475,7 +1472,6 @@ void _process_SM100Energy(_EMS_RxTelegram * EMS_RxTelegram) { EMS_SolarModule.EnergyToday = _toShort(6); // todays in Wh EMS_SolarModule.EnergyTotal = _toShort(10); // total / 10 in kWh - // EMS_Other.SM = true; EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT } @@ -1483,20 +1479,16 @@ void _process_SM100Energy(_EMS_RxTelegram * EMS_RxTelegram) { * Type 0xE3 - HeatPump Monitor 1 */ void _process_HPMonitor1(_EMS_RxTelegram * EMS_RxTelegram) { - EMS_Other.HPModulation = _toByte(14); // modulation % - - EMS_Other.HP = true; - EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT + EMS_HeatPump.HPModulation = _toByte(14); // modulation % + EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT } /* * Type 0xE5 - HeatPump Monitor 2 */ void _process_HPMonitor2(_EMS_RxTelegram * EMS_RxTelegram) { - EMS_Other.HPSpeed = _toByte(25); // speed % - - EMS_Other.HP = true; - EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT + EMS_HeatPump.HPSpeed = _toByte(25); // speed % + EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT } /* @@ -1510,13 +1502,11 @@ void _process_ISM1StatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { EMS_SolarModule.EnergyLastHour = _toShort(2) * 10; // Solar Energy produced in last hour EMS_SolarModule.pump = _bitRead(8, 0); // Solar pump on (1) or off (0) EMS_SolarModule.pumpWorkMin = _toLong(10); - // EMS_Other.SM = true; } if (EMS_RxTelegram->offset == 4) { // e.g. B0 00 FF 04 00 03 02 E5 EMS_SolarModule.collectorTemp = _toShort(0); // Collector Temperature - // EMS_Other.SM = true; } } @@ -1706,7 +1696,7 @@ void _process_Version(_EMS_RxTelegram * EMS_RxTelegram) { } - // finally look for Solar Modules + // look for Solar Modules i = 0; while (i < _Solar_Module_Types_max) { if (SolarModule_Types[i].product_id == product_id) { @@ -1726,9 +1716,7 @@ void _process_Version(_EMS_RxTelegram * EMS_RxTelegram) { // add to list _addDevice(product_id, SolarModule_Types[i].device_id, version, SolarModule_Types[i].model_string); - // EMS_Other.SM = true; // we have detected a Solar Module (SM10, SM100, ISM1 ...) myDebug_P(PSTR("Solar Module support enabled.")); - EMS_SolarModule.model_id = SolarModule_Types[i].model_id; EMS_SolarModule.device_id = SolarModule_Types[i].device_id; EMS_SolarModule.product_id = product_id; strlcpy(EMS_SolarModule.version, version, sizeof(EMS_SolarModule.version)); @@ -1738,6 +1726,32 @@ void _process_Version(_EMS_RxTelegram * EMS_RxTelegram) { return; } + // look for heatpumps + i = 0; + while (i < _HeatPump_Types_max) { + if (HeatPump_Types[i].product_id == product_id) { + typeFound = true; // we have a matching product id. i is the index. + break; + } + i++; + } + + if (typeFound) { + myDebug_P(PSTR("Heat Pump found: %s (DeviceID:0x%02X ProductID:%d Version:%s)"), + HeatPump_Types[i].model_string, + HeatPump_Types[i].device_id, + product_id, + version); + + // add to list + _addDevice(product_id, HeatPump_Types[i].device_id, version, HeatPump_Types[i].model_string); + + myDebug_P(PSTR("Heat Pump support enabled.")); + EMS_HeatPump.device_id = SolarModule_Types[i].device_id; + EMS_HeatPump.product_id = product_id; + strlcpy(EMS_HeatPump.version, version, sizeof(EMS_HeatPump.version)); + return; + } // finally look for the other EMS devices i = 0; @@ -1754,23 +1768,9 @@ void _process_Version(_EMS_RxTelegram * EMS_RxTelegram) { // add to list _addDevice(product_id, Other_Types[i].device_id, version, Other_Types[i].model_string); - - // see if this is a HeatPump - if (Other_Types[i].device_id == EMS_ID_HP) { - EMS_Other.HP = true; // we have detected a HP - myDebug_P(PSTR("HeatPump support enabled.")); - EMS_Other.model_id = Other_Types[i].model_id; - EMS_Other.device_id = Other_Types[i].device_id; - EMS_Other.product_id = product_id; - strlcpy(EMS_Other.version, version, sizeof(EMS_Other.version)); - // fetch Solar Module values > not yet implemented - } - return; - } else { myDebug_P(PSTR("Unrecognized device found: %s (DeviceID:0x%02X ProductID:%d Version:%s)"), EMS_RxTelegram->src, product_id, version); - // add to list _addDevice(product_id, EMS_RxTelegram->src, version, "unknown?"); } @@ -2056,7 +2056,7 @@ char * ems_getSolarModuleDescription(char * buffer) { */ char * ems_getHeatPumpDescription(char * buffer) { uint8_t size = 128; - if (!EMS_Other.HP) { + if (!ems_getHeatPumpEnabled()) { strlcpy(buffer, "", size); } else { int i = 0; @@ -2064,28 +2064,28 @@ char * ems_getHeatPumpDescription(char * buffer) { char tmp[6] = {0}; // scan through known ID types - while (i < _Other_Types_max) { - if (Other_Types[i].product_id == EMS_Other.product_id) { + while (i < _HeatPump_Types_max) { + if (HeatPump_Types[i].product_id == EMS_HeatPump.product_id) { found = true; // we have a match break; } i++; } if (found) { - strlcpy(buffer, Other_Types[i].model_string, size); + strlcpy(buffer, HeatPump_Types[i].model_string, size); } else { strlcpy(buffer, "DeviceID: 0x", size); - strlcat(buffer, _hextoa(EMS_Other.device_id, tmp), size); + strlcat(buffer, _hextoa(EMS_HeatPump.device_id, tmp), size); } strlcat(buffer, " (ProductID:", size); - if (EMS_Other.product_id == EMS_ID_NONE) { + if (EMS_HeatPump.product_id == EMS_ID_NONE) { strlcat(buffer, "?", size); } else { - strlcat(buffer, itoa(EMS_Other.product_id, tmp, 10), size); + strlcat(buffer, itoa(EMS_HeatPump.product_id, tmp, 10), size); } strlcat(buffer, " Version:", size); - strlcat(buffer, EMS_Other.version, size); + strlcat(buffer, EMS_HeatPump.version, size); strlcat(buffer, ")", size); } diff --git a/src/ems.h b/src/ems.h index 346c2fbbb..623f4f369 100644 --- a/src/ems.h +++ b/src/ems.h @@ -156,27 +156,30 @@ const _EMS_TxTelegram EMS_TX_TELEGRAM_NEW = { {0x00} // data }; +// where defintions are stored typedef struct { - uint8_t model_id; uint8_t product_id; char model_string[50]; } _Boiler_Type; typedef struct { - uint8_t model_id; uint8_t product_id; uint8_t device_id; char model_string[50]; } _SolarModule_Type; typedef struct { - uint8_t model_id; uint8_t product_id; uint8_t device_id; char model_string[50]; } _Other_Type; -// Definition for thermostat devices +typedef struct { + uint8_t product_id; + uint8_t device_id; + char model_string[50]; +} _HeatPump_Type; + typedef struct { uint8_t model_id; uint8_t product_id; @@ -185,6 +188,8 @@ typedef struct { bool write_supported; } _Thermostat_Type; + +// for consolidating all types typedef struct { uint8_t product_id; uint8_t device_id; @@ -256,14 +261,19 @@ typedef struct { // UBAParameterWW * Telegram package defintions for Other EMS devices */ -// Other ems devices than solar modules, thermostats and boilers typedef struct { - bool HP; // set true if there is a Heat Pump available uint8_t HPModulation; // heatpump modulation in % uint8_t HPSpeed; // speed 0-100 % - uint8_t device_id; // the device ID of the Solar Module / Heat Pump (e.g. 0x30) + uint8_t device_id; // the device ID of the Heat Pump (e.g. 0x30) uint8_t model_id; // Solar Module / Heat Pump model (e.g. 3 > EMS_MODEL_OTHER ) - uint8_t product_id; // (e.g. 101) + uint8_t product_id; + char version[10]; +} _EMS_HeatPump; + +typedef struct { + uint8_t device_id; + uint8_t model_id; + uint8_t product_id; char version[10]; } _EMS_Other; @@ -278,9 +288,9 @@ typedef struct { int16_t EnergyToday; int16_t EnergyTotal; uint32_t pumpWorkMin; // Total solar pump operating time - uint8_t device_id; // the device ID of the Solar Module / Heat Pump (e.g. 0x30) - uint8_t model_id; // Solar Module / Heat Pump model (e.g. 3 > EMS_MODEL_OTHER ) - uint8_t product_id; // (e.g. 101) + uint8_t device_id; // the device ID of the Solar Module + uint8_t model_id; // Solar Module + uint8_t product_id; char version[10]; } _EMS_SolarModule; @@ -363,12 +373,12 @@ bool ems_getTxEnabled(); bool ems_getThermostatEnabled(); bool ems_getBoilerEnabled(); bool ems_getSolarModuleEnabled(); +bool ems_getHeatPumpEnabled(); bool ems_getBusConnected(); _EMS_SYS_LOGGING ems_getLogging(); bool ems_getEmsRefreshed(); uint8_t ems_getThermostatModel(); uint8_t ems_getSolarModuleModel(); -uint8_t ems_getOtherModel(); void ems_discoverModels(); bool ems_getTxCapable(); uint32_t ems_getPollFrequency(); @@ -378,8 +388,6 @@ uint8_t _crcCalculator(uint8_t * data, uint8_t len); void _processType(_EMS_RxTelegram * EMS_RxTelegram); void _debugPrintPackage(const char * prefix, _EMS_RxTelegram * EMS_RxTelegram, const char * color); void _ems_clearTxData(); -int _ems_findBoilerModel(uint8_t model_id); -bool _ems_setModel(uint8_t model_id); void _removeTxQueue(); // global so can referenced in other classes @@ -387,4 +395,5 @@ extern _EMS_Sys_Status EMS_Sys_Status; extern _EMS_Boiler EMS_Boiler; extern _EMS_Thermostat EMS_Thermostat; extern _EMS_SolarModule EMS_SolarModule; +extern _EMS_HeatPump EMS_HeatPump; extern _EMS_Other EMS_Other; diff --git a/src/ems_devices.h b/src/ems_devices.h index 30f2105ba..acc85d39f 100644 --- a/src/ems_devices.h +++ b/src/ems_devices.h @@ -121,19 +121,19 @@ // Known EMS types typedef enum { - EMS_MODEL_NONE, + EMS_MODEL_NONE, // unset EMS_MODEL_ALL, // common for all devices - // generic ID for the boiler + // heatpump + EMS_MODEL_HP, + + // solar module + EMS_MODEL_SM, + + // boiler EMS_MODEL_UBA, - // generic ID for the solar module - EMS_MODEL_SOLAR_MODULE, - - // generic ID for all the other weird devices - EMS_MODEL_OTHER, - - // and finally the thermostats + // and the thermostats EMS_MODEL_ES73, EMS_MODEL_RC10, EMS_MODEL_RC20, @@ -155,56 +155,65 @@ typedef enum { // EMS types for known boilers. This list will be extended when new devices are recognized. // The device_id is always 0x08 -// format is MODEL_ID, PRODUCT ID, DESCRIPTION +// format is PRODUCT ID, DESCRIPTION const _Boiler_Type Boiler_Types[] = { - {EMS_MODEL_UBA, 72, "MC10 Module"}, - {EMS_MODEL_UBA, 123, "Buderus GB172/Nefit Trendline/Junkers Cerapur"}, - {EMS_MODEL_UBA, 115, "Nefit Topline Compact/Buderus GB162"}, - {EMS_MODEL_UBA, 203, "Buderus Logamax U122/Junkers Cerapur"}, - {EMS_MODEL_UBA, 208, "Buderus Logamax plus/GB192"}, - {EMS_MODEL_UBA, 64, "Sieger BK15/Nefit Smartline/Buderus GB152"}, - {EMS_MODEL_UBA, EMS_PRODUCTID_HEATRONICS, "Bosch Condens 2500/Junkers Heatronics3"}, - {EMS_MODEL_UBA, 122, "Nefit Proline"}, - {EMS_MODEL_UBA, 172, "Nefit Enviline"} + {72, "MC10 Module"}, + {123, "Buderus GB172/Nefit Trendline/Junkers Cerapur"}, + {115, "Nefit Topline Compact/Buderus GB162"}, + {203, "Buderus Logamax U122/Junkers Cerapur"}, + {208, "Buderus Logamax plus/GB192"}, + {64, "Sieger BK15/Nefit Smartline/Buderus GB152"}, + {EMS_PRODUCTID_HEATRONICS, "Bosch Condens 2500/Junkers Heatronics3"}, + {122, "Nefit Proline"}, + {172, "Nefit Enviline"} }; /* * Known Solar Module types + * format is PRODUCT ID, DEVICE ID, DESCRIPTION */ const _SolarModule_Type SolarModule_Types[] = { - {EMS_MODEL_OTHER, EMS_PRODUCTID_SM10, EMS_ID_SM, "SM10 Solar Module"}, - {EMS_MODEL_OTHER, EMS_PRODUCTID_SM100, EMS_ID_SM, "SM100 Solar Module"}, - {EMS_MODEL_OTHER, EMS_PRODUCTID_ISM1, EMS_ID_SM, "Junkers ISM1 Solar Module"} + {EMS_PRODUCTID_SM10, EMS_ID_SM, "SM10 Solar Module"}, + {EMS_PRODUCTID_SM100, EMS_ID_SM, "SM100 Solar Module"}, + {EMS_PRODUCTID_ISM1, EMS_ID_SM, "Junkers ISM1 Solar Module"} }; // Other EMS devices which are not considered boilers, thermostats or solar modules +// format is PRODUCT ID, DEVICE ID, DESCRIPTION const _Other_Type Other_Types[] = { - {EMS_MODEL_OTHER, 69, 0x21, "MM10 Mixer Module"}, - {EMS_MODEL_OTHER, 71, 0x11, "WM10 Switch Module"}, - {EMS_MODEL_OTHER, 160, 0x20, "MM100 Mixing Module"}, - {EMS_MODEL_OTHER, 160, 0x21, "MM100 Mixing Module"}, - {EMS_MODEL_OTHER, 159, 0x21, "MM50 Mixing Module"}, - {EMS_MODEL_OTHER, 68, 0x09, "BC10/RFM20 Receiver"}, - {EMS_MODEL_OTHER, 190, 0x09, "BC10 Base Controller"}, - {EMS_MODEL_OTHER, 114, 0x09, "BC10 Base Controller"}, - {EMS_MODEL_OTHER, 125, 0x09, "BC25 Base Controller"}, - {EMS_MODEL_OTHER, 152, 0x09, "Junkers Controller"}, - {EMS_MODEL_OTHER, 205, 0x02, "Nefit Moduline Easy Connect"}, - {EMS_MODEL_EASY, 206, 0x02, "Bosch Easy Connect"}, - {EMS_MODEL_OTHER, 171, 0x02, "EMS-OT OpenTherm converter"}, - {EMS_MODEL_OTHER, 252, EMS_ID_HP, "HeatPump Module"}, - {EMS_MODEL_OTHER, 189, EMS_ID_GATEWAY, "Web Gateway KM200"} + {69, 0x21, "MM10 Mixer Module"}, + {71, 0x11, "WM10 Switch Module"}, + {160, 0x20, "MM100 Mixing Module"}, + {160, 0x21, "MM100 Mixing Module"}, + {159, 0x21, "MM50 Mixing Module"}, + {68, 0x09, "BC10/RFM20 Receiver"}, + {190, 0x09, "BC10 Base Controller"}, + {114, 0x09, "BC10 Base Controller"}, + {125, 0x09, "BC25 Base Controller"}, + {152, 0x09, "Junkers Controller"}, + {205, 0x02, "Nefit Moduline Easy Connect"}, + {206, 0x02, "Bosch Easy Connect"}, + {171, 0x02, "EMS-OT OpenTherm converter"}, + {252, EMS_ID_HP, "HeatPump Module"}, + {189, EMS_ID_GATEWAY, "Web Gateway KM200"} }; +// heatpump +// format is PRODUCT ID, DEVICE ID, DESCRIPTION +const _HeatPump_Type HeatPump_Types[] = { + {252, EMS_ID_HP, "HeatPump Module"} +}; + /* * Known thermostat types and their capabilities + * format is MODEL_ID, PRODUCT ID, DEVICE ID, DESCRIPTION */ const _Thermostat_Type Thermostat_Types[] = { From d190446f0fa511381065bef376bf2578aad3460a Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 5 Jul 2019 12:17:12 +0200 Subject: [PATCH 46/89] clean up --- platformio.ini-example | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio.ini-example b/platformio.ini-example index bc05a1bea..8719f8148 100644 --- a/platformio.ini-example +++ b/platformio.ini-example @@ -11,8 +11,8 @@ default_envs = debug ; -DMYESP_TIMESTAMP -DTESTS -DCRASH -DNO_SERIAL ; -DNO_SERIAL if you want a fresh install to use the Serial port debug_flags = -Wall -DCRASH -release_flags = -w -general_flags = -g -DNO_GLOBAL_EEPROM -DDNO_SERIAL +release_flags = -w -DDNO_SERIAL +general_flags = -g -DNO_GLOBAL_EEPROM arduino_core_2_3_0 = espressif8266@1.5.0 arduino_core_2_4_0 = espressif8266@1.6.0 From daaed4d5f323b01a3184c81051602f93c50007b0 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 5 Jul 2019 12:17:34 +0200 Subject: [PATCH 47/89] serial on as default and then off even in AP mode --- lib/MyESP/MyESP.cpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/MyESP/MyESP.cpp b/lib/MyESP/MyESP.cpp index 22354bd4a..51159eb8f 100644 --- a/lib/MyESP/MyESP.cpp +++ b/lib/MyESP/MyESP.cpp @@ -221,6 +221,13 @@ void MyESP::_wifiCallback(justwifi_messages_t code, char * parameter) { myDebug_P(PSTR("[WIFI] IP %s"), WiFi.softAPIP().toString().c_str()); myDebug_P(PSTR("[WIFI] MAC %s"), WiFi.softAPmacAddress().c_str()); + // finally if we don't want Serial anymore, turn it off + if (!_serial) { + myDebug_P(PSTR("[SYSTEM] Disabling serial port communication.")); + SerialAndTelnet.flush(); // flush so all buffer is printed to serial + SerialAndTelnet.setSerial(NULL); + } + // call any final custom settings if (_wifi_callback) { _wifi_callback(); @@ -584,6 +591,13 @@ void MyESP::_telnet_setup() { SerialAndTelnet.setDebugOutput(false); SerialAndTelnet.begin(TELNET_SERIAL_BAUD); // default baud is 115200 +// serial is only on when booting +#ifdef DEFAULT_NO_SERIAL + _serial_default = false; +#else + _serial_default = true; +#endif + // init command buffer for console commands memset(_command, 0, TELNET_MAX_COMMAND_LENGTH); } @@ -1567,7 +1581,6 @@ bool MyESP::_fs_loadConfig() { myDebug_P(PSTR("[FS] Config file size is too large")); return false; } else if (size == 0) { - myDebug_P(PSTR("[FS] Failed to open config file")); return false; } @@ -1683,7 +1696,7 @@ void MyESP::_fs_setup() { // load the config file. if it doesn't exist (function returns false) create it if (!_fs_loadConfig()) { - //myDebug_P(PSTR("[FS] Re-creating config file")); + myDebug_P(PSTR("[FS] Re-creating config file")); fs_saveConfig(); _firstInstall = true; // flag as a first install } @@ -2155,12 +2168,13 @@ void MyESP::begin(const char * app_hostname, const char * app_name, const char * _app_name = strdup(app_name); _app_version = strdup(app_version); + _telnet_setup(); // Telnet setup, called first to set Serial + // set up onboard LED pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, HIGH); _getInitialFreeHeap(); // get initial free mem - _telnet_setup(); // Telnet setup, called first to set Serial _rtcmemSetup(); // rtc internal mem setup if (getSystemBootStatus() == MYESP_BOOTSTATUS_RESETNEEDED) { From f231c863ec1f9dc9908b020fb94e6c8575dbf5c9 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 5 Jul 2019 12:17:40 +0200 Subject: [PATCH 48/89] https://github.com/proddy/EMS-ESP/issues/146 --- src/ems-esp.cpp | 101 +++++++++++++++++++++++++++++++++------------- src/ems.cpp | 79 +++++++++++++++++++----------------- src/ems.h | 23 +++++------ src/ems_devices.h | 6 +-- src/test_data.h | 3 +- src/version.h | 2 +- 6 files changed, 131 insertions(+), 83 deletions(-) diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index da6a8559a..9678f7a7e 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -212,7 +212,40 @@ char * _short_to_char(char * s, int16_t value, uint8_t decimals = 1) { return s; } -// takes a short value (2 bytes), converts to a fraction +// convert short (two bytes) to text string +// decimals: 0 = no division, 1=divide value by 10, 2=divide by 2, 10=divide value by 100 +char * _ushort_to_char(char * s, uint16_t value, uint8_t decimals = 1) { + // remove errors or invalid values + if (value == EMS_VALUE_USHORT_NOTSET) { + strlcpy(s, "?", 10); + return (s); + } + + // just print + if (decimals == 0) { + ltoa(value, s, 10); + return (s); + } + + // do floating point + char s2[10] = {0}; + + if (decimals == 2) { + // divide by 2 + strlcpy(s, ltoa(value / 2, s2, 10), 10); + strlcat(s, ".", 10); + strlcat(s, ((value & 0x01) ? "5" : "0"), 10); + + } else { + strlcpy(s, ltoa(value / (decimals * 10), s2, 10), 10); + strlcat(s, ".", 10); + strlcat(s, ltoa(value % (decimals * 10), s2, 10), 10); + } + + return s; +} + +// takes a signed short value (2 bytes), converts to a fraction // decimals: 0 = no division, 1=divide value by 10, 2=divide by 2, 10=divide value by 100 void _renderShortValue(const char * prefix, const char * postfix, int16_t value, uint8_t decimals = 1) { static char buffer[200] = {0}; @@ -231,6 +264,25 @@ void _renderShortValue(const char * prefix, const char * postfix, int16_t value, myDebug(buffer); } +// takes a unsigned short value (2 bytes), converts to a fraction +// decimals: 0 = no division, 1=divide value by 10, 2=divide by 2, 10=divide value by 100 +void _renderUShortValue(const char * prefix, const char * postfix, uint16_t value, uint8_t decimals = 1) { + static char buffer[200] = {0}; + static char s[20] = {0}; + strlcpy(buffer, " ", sizeof(buffer)); + strlcat(buffer, prefix, sizeof(buffer)); + strlcat(buffer, ": ", sizeof(buffer)); + + strlcat(buffer, _ushort_to_char(s, value, decimals), sizeof(buffer)); + + if (postfix != NULL) { + strlcat(buffer, " ", sizeof(buffer)); + strlcat(buffer, postfix, sizeof(buffer)); + } + + myDebug(buffer); +} + // convert int (single byte) to text value char * _int_to_char(char * s, uint8_t value, uint8_t div = 1) { if (value == EMS_VALUE_INT_NOTSET) { @@ -400,7 +452,7 @@ void showInfo() { _renderIntValue("Warm Water desired temperature", "C", EMS_Boiler.wWDesiredTemp); // UBAMonitorWWMessage - _renderShortValue("Warm Water current temperature", "C", EMS_Boiler.wWCurTmp); + _renderUShortValue("Warm Water current temperature", "C", EMS_Boiler.wWCurTmp); _renderIntValue("Warm Water current tap water flow", "l/min", EMS_Boiler.wWCurFlow, 10); _renderLongValue("Warm Water # starts", "times", EMS_Boiler.wWStarts); if (EMS_Boiler.wWWorkM != EMS_VALUE_LONG_NOTSET) { @@ -413,8 +465,8 @@ void showInfo() { // UBAMonitorFast _renderIntValue("Selected flow temperature", "C", EMS_Boiler.selFlowTemp); - _renderShortValue("Current flow temperature", "C", EMS_Boiler.curFlowTemp); - _renderShortValue("Return temperature", "C", EMS_Boiler.retTemp); + _renderUShortValue("Current flow temperature", "C", EMS_Boiler.curFlowTemp); + _renderUShortValue("Return temperature", "C", EMS_Boiler.retTemp); _renderBoolValue("Gas", EMS_Boiler.burnGas); _renderBoolValue("Boiler pump", EMS_Boiler.heatPmp); _renderBoolValue("Fan", EMS_Boiler.fanWork); @@ -439,7 +491,7 @@ void showInfo() { if (EMS_Boiler.extTemp != EMS_VALUE_SHORT_NOTSET) { _renderShortValue("Outside temperature", "C", EMS_Boiler.extTemp); } - _renderShortValue("Boiler temperature", "C", EMS_Boiler.boilTemp); + _renderUShortValue("Boiler temperature", "C", EMS_Boiler.boilTemp); _renderIntValue("Pump modulation", "%", EMS_Boiler.pumpMod); _renderLongValue("Burner # starts", "times", EMS_Boiler.burnStarts); if (EMS_Boiler.burnWorkMin != EMS_VALUE_LONG_NOTSET) { @@ -470,13 +522,15 @@ void showInfo() { _renderShortValue("Bottom temperature", "C", EMS_SolarModule.bottomTemp); _renderIntValue("Pump modulation", "%", EMS_SolarModule.pumpModulation); _renderBoolValue("Pump active", EMS_SolarModule.pump); - myDebug_P(PSTR(" Pump working time: %d days %d hours %d minutes"), - EMS_SolarModule.pumpWorkMin / 1440, - (EMS_SolarModule.pumpWorkMin % 1440) / 60, - EMS_SolarModule.pumpWorkMin % 60); - _renderShortValue("Energy Last Hour", "Wh", EMS_SolarModule.EnergyLastHour, 1); // *10 - _renderShortValue("Energy Today", "Wh", EMS_SolarModule.EnergyToday, 0); - _renderShortValue("Energy Total", "kWH", EMS_SolarModule.EnergyTotal, 1); // *10 + if (EMS_SolarModule.pumpWorkMin != EMS_VALUE_LONG_NOTSET) { + myDebug_P(PSTR(" Pump working time: %d days %d hours %d minutes"), + EMS_SolarModule.pumpWorkMin / 1440, + (EMS_SolarModule.pumpWorkMin % 1440) / 60, + EMS_SolarModule.pumpWorkMin % 60); + } + _renderUShortValue("Energy Last Hour", "Wh", EMS_SolarModule.EnergyLastHour, 1); // *10 + _renderUShortValue("Energy Today", "Wh", EMS_SolarModule.EnergyToday, 0); + _renderUShortValue("Energy Total", "kWH", EMS_SolarModule.EnergyTotal, 1); // *10 } // For HeatPumps @@ -633,17 +687,17 @@ void publishValues(bool force) { if (EMS_Boiler.extTemp != EMS_VALUE_SHORT_NOTSET) rootBoiler["outdoorTemp"] = (double)EMS_Boiler.extTemp / 10; - if (EMS_Boiler.wWCurTmp != EMS_VALUE_SHORT_NOTSET) + if (EMS_Boiler.wWCurTmp != EMS_VALUE_USHORT_NOTSET) rootBoiler["wWCurTmp"] = (double)EMS_Boiler.wWCurTmp / 10; if (EMS_Boiler.wWCurFlow != EMS_VALUE_INT_NOTSET) rootBoiler["wWCurFlow"] = (double)EMS_Boiler.wWCurFlow / 10; - if (EMS_Boiler.curFlowTemp != EMS_VALUE_SHORT_NOTSET) + if (EMS_Boiler.curFlowTemp != EMS_VALUE_USHORT_NOTSET) rootBoiler["curFlowTemp"] = (double)EMS_Boiler.curFlowTemp / 10; - if (EMS_Boiler.retTemp != EMS_VALUE_SHORT_NOTSET) + if (EMS_Boiler.retTemp != EMS_VALUE_USHORT_NOTSET) rootBoiler["retTemp"] = (double)EMS_Boiler.retTemp / 10; if (EMS_Boiler.sysPress != EMS_VALUE_INT_NOTSET) rootBoiler["sysPress"] = (double)EMS_Boiler.sysPress / 10; - if (EMS_Boiler.boilTemp != EMS_VALUE_SHORT_NOTSET) + if (EMS_Boiler.boilTemp != EMS_VALUE_USHORT_NOTSET) rootBoiler["boilTemp"] = (double)EMS_Boiler.boilTemp / 10; if (EMS_Boiler.wWActivated != EMS_VALUE_INT_NOTSET) @@ -796,13 +850,13 @@ void publishValues(bool force) { rootSM[SM_PUMPWORKMIN] = (double)EMS_SolarModule.pumpWorkMin; } - if (EMS_SolarModule.EnergyLastHour != EMS_VALUE_SHORT_NOTSET) + if (EMS_SolarModule.EnergyLastHour != EMS_VALUE_USHORT_NOTSET) rootSM[SM_ENERGYLASTHOUR] = (double)EMS_SolarModule.EnergyLastHour / 10; - if (EMS_SolarModule.EnergyToday != EMS_VALUE_SHORT_NOTSET) + if (EMS_SolarModule.EnergyToday != EMS_VALUE_USHORT_NOTSET) rootSM[SM_ENERGYTODAY] = EMS_SolarModule.EnergyToday; - if (EMS_SolarModule.EnergyTotal != EMS_VALUE_SHORT_NOTSET) + if (EMS_SolarModule.EnergyTotal != EMS_VALUE_USHORT_NOTSET) rootSM[SM_ENERGYTOTAL] = (double)EMS_SolarModule.EnergyTotal / 10; data[0] = '\0'; // reset data for next package @@ -1035,7 +1089,7 @@ bool FSCallback(MYESP_FSACTION action, const JsonObject json) { EMSESP_Status.led = json["led"]; EMSESP_Status.led_gpio = json["led_gpio"] | EMSESP_LED_GPIO; EMSESP_Status.dallas_gpio = json["dallas_gpio"] | EMSESP_DALLAS_GPIO; - EMSESP_Status.dallas_parasite = json["dallas_parasite"]; + EMSESP_Status.dallas_parasite = json["dallas_parasite"] | EMSESP_DALLAS_PARASITE; EMS_Thermostat.device_id = json["thermostat_type"] | EMSESP_THERMOSTAT_TYPE; EMS_Boiler.device_id = json["boiler_type"] | EMSESP_BOILER_TYPE; @@ -1721,13 +1775,6 @@ void setup() { // web custom settings myESP.setWeb(WebCallback); -// serial off as default for fresh installs -#ifdef NO_SERIAL - myESP.setUseSerial(false); -#else - myESP.setUseSerial(true); -#endif - // start up all the services myESP.begin(APP_HOSTNAME, APP_NAME, APP_VERSION); diff --git a/src/ems.cpp b/src/ems.cpp index 7d3402dde..f05540c17 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -268,35 +268,35 @@ void ems_init() { EMS_Boiler.wWComfort = EMS_VALUE_INT_NOTSET; // UBAMonitorFast - EMS_Boiler.selFlowTemp = EMS_VALUE_INT_NOTSET; // Selected flow temperature - EMS_Boiler.curFlowTemp = EMS_VALUE_SHORT_NOTSET; // Current flow temperature - EMS_Boiler.retTemp = EMS_VALUE_SHORT_NOTSET; // Return temperature - EMS_Boiler.burnGas = EMS_VALUE_INT_NOTSET; // Gas on/off - EMS_Boiler.fanWork = EMS_VALUE_INT_NOTSET; // Fan on/off - EMS_Boiler.ignWork = EMS_VALUE_INT_NOTSET; // Ignition on/off - EMS_Boiler.heatPmp = EMS_VALUE_INT_NOTSET; // Boiler pump on/off - EMS_Boiler.wWHeat = EMS_VALUE_INT_NOTSET; // 3-way valve on WW - EMS_Boiler.wWCirc = EMS_VALUE_INT_NOTSET; // Circulation on/off - EMS_Boiler.selBurnPow = EMS_VALUE_INT_NOTSET; // Burner max power - EMS_Boiler.curBurnPow = EMS_VALUE_INT_NOTSET; // Burner current power - EMS_Boiler.flameCurr = EMS_VALUE_SHORT_NOTSET; // Flame current in micro amps - EMS_Boiler.sysPress = EMS_VALUE_INT_NOTSET; // System pressure + EMS_Boiler.selFlowTemp = EMS_VALUE_INT_NOTSET; // Selected flow temperature + EMS_Boiler.curFlowTemp = EMS_VALUE_USHORT_NOTSET; // Current flow temperature + EMS_Boiler.retTemp = EMS_VALUE_USHORT_NOTSET; // Return temperature + EMS_Boiler.burnGas = EMS_VALUE_INT_NOTSET; // Gas on/off + EMS_Boiler.fanWork = EMS_VALUE_INT_NOTSET; // Fan on/off + EMS_Boiler.ignWork = EMS_VALUE_INT_NOTSET; // Ignition on/off + EMS_Boiler.heatPmp = EMS_VALUE_INT_NOTSET; // Boiler pump on/off + EMS_Boiler.wWHeat = EMS_VALUE_INT_NOTSET; // 3-way valve on WW + EMS_Boiler.wWCirc = EMS_VALUE_INT_NOTSET; // Circulation on/off + EMS_Boiler.selBurnPow = EMS_VALUE_INT_NOTSET; // Burner max power + EMS_Boiler.curBurnPow = EMS_VALUE_INT_NOTSET; // Burner current power + EMS_Boiler.flameCurr = EMS_VALUE_SHORT_NOTSET; // Flame current in micro amps + EMS_Boiler.sysPress = EMS_VALUE_INT_NOTSET; // System pressure strlcpy(EMS_Boiler.serviceCodeChar, "??", sizeof(EMS_Boiler.serviceCodeChar)); EMS_Boiler.serviceCode = EMS_VALUE_SHORT_NOTSET; // UBAMonitorSlow - EMS_Boiler.extTemp = EMS_VALUE_SHORT_NOTSET; // Outside temperature - EMS_Boiler.boilTemp = EMS_VALUE_SHORT_NOTSET; // Boiler temperature - EMS_Boiler.pumpMod = EMS_VALUE_INT_NOTSET; // Pump modulation - EMS_Boiler.burnStarts = EMS_VALUE_LONG_NOTSET; // # burner restarts - EMS_Boiler.burnWorkMin = EMS_VALUE_LONG_NOTSET; // Total burner operating time - EMS_Boiler.heatWorkMin = EMS_VALUE_LONG_NOTSET; // Total heat operating time + EMS_Boiler.extTemp = EMS_VALUE_SHORT_NOTSET; // Outside temperature + EMS_Boiler.boilTemp = EMS_VALUE_USHORT_NOTSET; // Boiler temperature + EMS_Boiler.pumpMod = EMS_VALUE_INT_NOTSET; // Pump modulation + EMS_Boiler.burnStarts = EMS_VALUE_LONG_NOTSET; // # burner restarts + EMS_Boiler.burnWorkMin = EMS_VALUE_LONG_NOTSET; // Total burner operating time + EMS_Boiler.heatWorkMin = EMS_VALUE_LONG_NOTSET; // Total heat operating time // UBAMonitorWWMessage - EMS_Boiler.wWCurTmp = EMS_VALUE_SHORT_NOTSET; // Warm Water current temperature - EMS_Boiler.wWStarts = EMS_VALUE_LONG_NOTSET; // Warm Water # starts - EMS_Boiler.wWWorkM = EMS_VALUE_LONG_NOTSET; // Warm Water # minutes - EMS_Boiler.wWOneTime = EMS_VALUE_INT_NOTSET; // Warm Water one time function on/off + EMS_Boiler.wWCurTmp = EMS_VALUE_USHORT_NOTSET; // Warm Water current temperature + EMS_Boiler.wWStarts = EMS_VALUE_LONG_NOTSET; // Warm Water # starts + EMS_Boiler.wWWorkM = EMS_VALUE_LONG_NOTSET; // Warm Water # minutes + EMS_Boiler.wWOneTime = EMS_VALUE_INT_NOTSET; // Warm Water one time function on/off EMS_Boiler.wWCurFlow = EMS_VALUE_INT_NOTSET; // UBATotalUptimeMessage @@ -308,17 +308,18 @@ void ems_init() { EMS_Boiler.pump_mod_min = EMS_VALUE_INT_NOTSET; // Boiler circuit pump modulation min. power // Solar Module values - EMS_SolarModule.collectorTemp = EMS_VALUE_SHORT_NOTSET; // collector temp from SM10/SM100 - EMS_SolarModule.bottomTemp = EMS_VALUE_SHORT_NOTSET; // bottom temp from SM10/SM100 - EMS_SolarModule.pumpModulation = EMS_VALUE_INT_NOTSET; // modulation solar pump SM10/SM100 - EMS_SolarModule.pump = EMS_VALUE_INT_NOTSET; // pump active - EMS_SolarModule.EnergyLastHour = EMS_VALUE_SHORT_NOTSET; - EMS_SolarModule.EnergyToday = EMS_VALUE_SHORT_NOTSET; - EMS_SolarModule.EnergyTotal = EMS_VALUE_SHORT_NOTSET; - EMS_SolarModule.device_id = EMS_ID_NONE; - EMS_SolarModule.model_id = EMS_MODEL_NONE; - EMS_SolarModule.product_id = EMS_ID_NONE; - EMS_SolarModule.pumpWorkMin = EMS_VALUE_LONG_NOTSET; + EMS_SolarModule.collectorTemp = EMS_VALUE_SHORT_NOTSET; // collector temp from SM10/SM100 + EMS_SolarModule.bottomTemp = EMS_VALUE_SHORT_NOTSET; // bottom temp from SM10/SM100 + EMS_SolarModule.pumpModulation = EMS_VALUE_INT_NOTSET; // modulation solar pump SM10/SM100 + EMS_SolarModule.pump = EMS_VALUE_INT_NOTSET; // pump active + EMS_SolarModule.EnergyLastHour = EMS_VALUE_USHORT_NOTSET; + EMS_SolarModule.EnergyToday = EMS_VALUE_USHORT_NOTSET; + EMS_SolarModule.EnergyTotal = EMS_VALUE_USHORT_NOTSET; + EMS_SolarModule.device_id = EMS_ID_NONE; + EMS_SolarModule.model_id = EMS_MODEL_NONE; + EMS_SolarModule.product_id = EMS_ID_NONE; + EMS_SolarModule.pumpWorkMin = EMS_VALUE_LONG_NOTSET; + EMS_SolarModule.setpoint_maxBottomTemp = EMS_VALUE_SHORT_NOTSET; // Other EMS devices values EMS_HeatPump.HPModulation = EMS_VALUE_INT_NOTSET; @@ -1480,6 +1481,7 @@ void _process_SM100Energy(_EMS_RxTelegram * EMS_RxTelegram) { */ void _process_HPMonitor1(_EMS_RxTelegram * EMS_RxTelegram) { EMS_HeatPump.HPModulation = _toByte(14); // modulation % + EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT } @@ -1488,6 +1490,7 @@ void _process_HPMonitor1(_EMS_RxTelegram * EMS_RxTelegram) { */ void _process_HPMonitor2(_EMS_RxTelegram * EMS_RxTelegram) { EMS_HeatPump.HPSpeed = _toByte(25); // speed % + EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT } @@ -1497,10 +1500,10 @@ void _process_HPMonitor2(_EMS_RxTelegram * EMS_RxTelegram) { void _process_ISM1StatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { if (EMS_RxTelegram->offset == 0) { // e.g. B0 00 FF 00 00 03 32 00 00 00 00 13 00 D6 00 00 00 FB D0 F0 - EMS_SolarModule.collectorTemp = _toShort(4); // Collector Temperature - EMS_SolarModule.bottomTemp = _toShort(6); // Temperature Bottom of Solar Boiler - EMS_SolarModule.EnergyLastHour = _toShort(2) * 10; // Solar Energy produced in last hour - EMS_SolarModule.pump = _bitRead(8, 0); // Solar pump on (1) or off (0) + EMS_SolarModule.collectorTemp = _toShort(4); // Collector Temperature + EMS_SolarModule.bottomTemp = _toShort(6); // Temperature Bottom of Solar Boiler + EMS_SolarModule.EnergyLastHour = _toShort(2); // Solar Energy produced in last hour - is * 10 and handled in ems-esp.cpp + EMS_SolarModule.pump = _bitRead(8, 0); // Solar pump on (1) or off (0) EMS_SolarModule.pumpWorkMin = _toLong(10); } diff --git a/src/ems.h b/src/ems.h index 623f4f369..f3cec99ab 100644 --- a/src/ems.h +++ b/src/ems.h @@ -34,11 +34,11 @@ #define EMS_MAX_TELEGRAM_LENGTH 32 // default values -#define EMS_VALUE_INT_ON 1 // boolean true -#define EMS_VALUE_INT_OFF 0 // boolean false -#define EMS_VALUE_INT_NOTSET 0xFF // for 8-bit unsigned ints/bytes -//#define EMS_VALUE_SHORT_NOTSET 0x8000 // for 2-byte signed shorts +#define EMS_VALUE_INT_ON 1 // boolean true +#define EMS_VALUE_INT_OFF 0 // boolean false +#define EMS_VALUE_INT_NOTSET 0xFF // for 8-bit unsigned ints/bytes #define EMS_VALUE_SHORT_NOTSET -32768 // for 2-byte signed shorts +#define EMS_VALUE_USHORT_NOTSET 0xFFFF // for 2-byte unsigned shorts #define EMS_VALUE_LONG_NOTSET 0xFFFFFF // for 3-byte longs #define EMS_THERMOSTAT_WRITE_YES true @@ -188,7 +188,6 @@ typedef struct { bool write_supported; } _Thermostat_Type; - // for consolidating all types typedef struct { uint8_t product_id; @@ -209,8 +208,8 @@ typedef struct { // UBAParameterWW // UBAMonitorFast uint8_t selFlowTemp; // Selected flow temperature - int16_t curFlowTemp; // Current flow temperature - int16_t retTemp; // Return temperature + uint16_t curFlowTemp; // Current flow temperature + uint16_t retTemp; // Return temperature uint8_t burnGas; // Gas on/off uint8_t fanWork; // Fan on/off uint8_t ignWork; // Ignition on/off @@ -226,14 +225,14 @@ typedef struct { // UBAParameterWW // UBAMonitorSlow int16_t extTemp; // Outside temperature - int16_t boilTemp; // Boiler temperature + uint16_t boilTemp; // Boiler temperature uint8_t pumpMod; // Pump modulation uint32_t burnStarts; // # burner starts uint32_t burnWorkMin; // Total burner operating time uint32_t heatWorkMin; // Total heat operating time // UBAMonitorWWMessage - int16_t wWCurTmp; // Warm Water current temperature: + uint16_t wWCurTmp; // Warm Water current temperature uint32_t wWStarts; // Warm Water # starts uint32_t wWWorkM; // Warm Water # minutes uint8_t wWOneTime; // Warm Water one time function on/off @@ -284,9 +283,9 @@ typedef struct { uint8_t pumpModulation; // modulation solar pump uint8_t pump; // pump active int16_t setpoint_maxBottomTemp; // setpoint for maximum collector temp - int16_t EnergyLastHour; - int16_t EnergyToday; - int16_t EnergyTotal; + uint16_t EnergyLastHour; + uint16_t EnergyToday; + uint16_t EnergyTotal; uint32_t pumpWorkMin; // Total solar pump operating time uint8_t device_id; // the device ID of the Solar Module uint8_t model_id; // Solar Module diff --git a/src/ems_devices.h b/src/ems_devices.h index acc85d39f..21e154f3d 100644 --- a/src/ems_devices.h +++ b/src/ems_devices.h @@ -122,7 +122,7 @@ // Known EMS types typedef enum { EMS_MODEL_NONE, // unset - EMS_MODEL_ALL, // common for all devices + EMS_MODEL_ALL, // common for all devices // heatpump EMS_MODEL_HP, @@ -207,9 +207,7 @@ const _Other_Type Other_Types[] = { // heatpump // format is PRODUCT ID, DEVICE ID, DESCRIPTION -const _HeatPump_Type HeatPump_Types[] = { - {252, EMS_ID_HP, "HeatPump Module"} -}; +const _HeatPump_Type HeatPump_Types[] = {{252, EMS_ID_HP, "HeatPump Module"}}; /* * Known thermostat types and their capabilities diff --git a/src/test_data.h b/src/test_data.h index 91f1f40fc..0f9edf3b7 100644 --- a/src/test_data.h +++ b/src/test_data.h @@ -51,7 +51,8 @@ static const char * TEST_DATA[] = { "08 00 E5 00 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0A", // test 46 - heatpump Enviline "38 10 FF 00 03 2B 00 C7 07 C3 01", // test 47 - heatpump Enviline "08 0B 19 00 00 F7 80 00 80 00 00 00 00 00 03 58 97 0C 7B 1F 00 00 00 06 C4 DF 02 64 48 80 00", // test 48 - outdoor temp check - "88 00 19 00 00 DC 80 00 80 00 FF FF 00 00 00 21 9A 06 E1 7C 00 00 00 06 C2 13 00 1E 90 80 00" // test 49 - check max length + "88 00 19 00 00 DC 80 00 80 00 FF FF 00 00 00 21 9A 06 E1 7C 00 00 00 06 C2 13 00 1E 90 80 00", // test 49 - check max length + "30 00 FF 00 02 8E 00 00 41 82 00 00 28 36 00 00 82 21" // test 50 - SM100 }; diff --git a/src/version.h b/src/version.h index ca2730cd0..8e757aa09 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.8.1b10" +#define APP_VERSION "1.8.1b11" #define APP_HOSTNAME "ems-esp" From bfbb1808a7415d0010dd40385bf02b9301e8aeb0 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 5 Jul 2019 15:36:58 +0200 Subject: [PATCH 49/89] text changes --- lib/MyESP/MyESP.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/MyESP/MyESP.cpp b/lib/MyESP/MyESP.cpp index 51159eb8f..5e69316f5 100644 --- a/lib/MyESP/MyESP.cpp +++ b/lib/MyESP/MyESP.cpp @@ -397,7 +397,7 @@ void MyESP::_mqttOnConnect() { // MQTT setup void MyESP::_mqtt_setup() { if (!_mqtt_host) { - myDebug_P(PSTR("[MQTT] disabled")); + myDebug_P(PSTR("[MQTT] is disabled")); } mqttClient.onConnect([this](bool sessionPresent) { _mqttOnConnect(); }); @@ -1204,9 +1204,9 @@ void MyESP::showSystemStats() { myDebug_P(PSTR(" [WIFI] WiFi MAC: %s"), WiFi.macAddress().c_str()); if (isMQTTConnected()) { - myDebug_P(PSTR(" [MQTT] connected (heartbeat %s)"), getHeartbeat() ? "enabled" : "disabled"); + myDebug_P(PSTR(" [MQTT] is connected (with heartbeat %s)"), getHeartbeat() ? "enabled" : "disabled"); } else { - myDebug_P(PSTR(" [MQTT] disconnected")); + myDebug_P(PSTR(" [MQTT] is disconnected")); } #ifdef CRASH From 9c9f2771fc633efd3ac01203381196261dbb2cdb Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 5 Jul 2019 21:54:21 +0200 Subject: [PATCH 50/89] https://github.com/proddy/EMS-ESP/issues/146 --- src/ems-esp.cpp | 9 ++------- src/version.h | 2 +- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index 9678f7a7e..c839ae14f 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -750,11 +750,8 @@ void publishValues(bool force) { } // handle the thermostat values separately - if (ems_getThermostatEnabled()) { - // only send thermostat values if we actually have them - if ((EMS_Thermostat.curr_roomTemp == EMS_VALUE_SHORT_NOTSET) || (EMS_Thermostat.setpoint_roomTemp == EMS_VALUE_SHORT_NOTSET)) - return; - + // only send thermostat values if we actually have them + if (ems_getThermostatEnabled() && ((EMS_Thermostat.curr_roomTemp != EMS_VALUE_SHORT_NOTSET) && (EMS_Thermostat.setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET))) { // build new json object doc.clear(); JsonObject rootThermostat = doc.to(); @@ -825,8 +822,6 @@ void publishValues(bool force) { } } - // handle the other values separately - // For SM10 and SM100 Solar Modules if (ems_getSolarModuleEnabled()) { // build new json object diff --git a/src/version.h b/src/version.h index 8e757aa09..5e6f58bb3 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.8.1b11" +#define APP_VERSION "1.8.1b12" #define APP_HOSTNAME "ems-esp" From 3d66c5897a1d88c520c87d30ded80dda178cd260 Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 6 Jul 2019 16:13:56 +0200 Subject: [PATCH 51/89] https://github.com/proddy/EMS-ESP/issues/146 --- lib/MyESP/MyESP.cpp | 4 +--- src/ems-esp.cpp | 4 ++-- src/version.h | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/MyESP/MyESP.cpp b/lib/MyESP/MyESP.cpp index 5e69316f5..f36384a7d 100644 --- a/lib/MyESP/MyESP.cpp +++ b/lib/MyESP/MyESP.cpp @@ -503,7 +503,6 @@ void MyESP::_ota_setup() { _deferredReset(500, CUSTOM_RESET_OTA); }); - /* ArduinoOTA.onProgress([this](unsigned int progress, unsigned int total) { static unsigned int _progOld; unsigned int _prog = (progress / (total / 100)); @@ -512,8 +511,7 @@ void MyESP::_ota_setup() { _progOld = _prog; } }); - */ - + ArduinoOTA.onError([this](ota_error_t error) { if (error == OTA_AUTH_ERROR) myDebug_P(PSTR("[OTA] Auth Failed")); diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index c839ae14f..18b3c9bd2 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -178,7 +178,7 @@ char * _bool_to_char(char * s, uint8_t value) { // negative values are assumed stored as 1-compliment (https://medium.com/@LeeJulija/how-integers-are-stored-in-memory-using-twos-complement-5ba04d61a56c) char * _short_to_char(char * s, int16_t value, uint8_t decimals = 1) { // remove errors or invalid values - if (value == EMS_VALUE_SHORT_NOTSET) { + if ((value == EMS_VALUE_SHORT_NOTSET) || (value == 0x8000)) { strlcpy(s, "?", 10); return (s); } @@ -216,7 +216,7 @@ char * _short_to_char(char * s, int16_t value, uint8_t decimals = 1) { // decimals: 0 = no division, 1=divide value by 10, 2=divide by 2, 10=divide value by 100 char * _ushort_to_char(char * s, uint16_t value, uint8_t decimals = 1) { // remove errors or invalid values - if (value == EMS_VALUE_USHORT_NOTSET) { + if ((value == EMS_VALUE_USHORT_NOTSET) || (value == 0x8000)) { strlcpy(s, "?", 10); return (s); } diff --git a/src/version.h b/src/version.h index 5e6f58bb3..6eb8a81cf 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.8.1b12" +#define APP_VERSION "1.8.1b13" #define APP_HOSTNAME "ems-esp" From e0f07e52e22762157c04bd1f60a79b2cb6258790 Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 6 Jul 2019 17:13:46 +0200 Subject: [PATCH 52/89] minor changes to web layout --- lib/MyESP/MyESP.cpp | 30 ++++++++++++++++++++++-------- lib/MyESP/MyESP.h | 2 +- src/version.h | 2 +- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/lib/MyESP/MyESP.cpp b/lib/MyESP/MyESP.cpp index f36384a7d..16c1a6879 100644 --- a/lib/MyESP/MyESP.cpp +++ b/lib/MyESP/MyESP.cpp @@ -511,7 +511,7 @@ void MyESP::_ota_setup() { _progOld = _prog; } }); - + ArduinoOTA.onError([this](ota_error_t error) { if (error == OTA_AUTH_ERROR) myDebug_P(PSTR("[OTA] Auth Failed")); @@ -1982,8 +1982,22 @@ void MyESP::_webRootPage() { strlcat(s, "

", sizeof(s)); strlcat(s, "

System stats:
", sizeof(s)); - strlcat(s, isMQTTConnected() ? " MQTT is connected\n" : " MQTT is disconnected\n", sizeof(s)); - strlcat(s, "
", sizeof(s)); + + if (isAPmode()) { + strlcat(s, " Device is in Wifi Access Point mode with SSID ", sizeof(s)); + strlcat(s, jw.getAPSSID().c_str(), sizeof(s)); + strlcat(s, "", sizeof(s)); + } else { + char buf[4]; + strlcat(s, " Connected to wireless network ", sizeof(s)); + strlcat(s, _getESPhostname().c_str(), sizeof(s)); + strlcat(s, " with signal strength ", sizeof(s)); + strlcat(s, itoa(getWifiQuality(), buf, 10), sizeof(s)); + strlcat(s, "%", sizeof(s)); + } + + strlcat(s, isMQTTConnected() ? "
MQTT is connected\n" : " MQTT is disconnected\n", sizeof(s)); + strlcat(s, "
", sizeof(s)); // uptime char buffer[200]; @@ -1993,14 +2007,14 @@ void MyESP::_webRootPage() { uint32_t rem = t % 3600L; uint8_t m = rem / 60; uint8_t sec = rem % 60; - sprintf(buffer, " System uptime: %d days %d hours %d minutes %d seconds
", d, h, m, sec); + sprintf(buffer, " System uptime: %d days %d hours %d minutes %d seconds", d, h, m, sec); strlcat(s, buffer, sizeof(s)); // memory - uint32_t total_memory = _getInitialFreeHeap(); - uint32_t free_memory = ESP.getFreeHeap(); - sprintf(buffer, " Memory: %d bytes free (%2u%%)
", free_memory, 100 * free_memory / total_memory); - strlcat(s, buffer, sizeof(s)); + //uint32_t total_memory = _getInitialFreeHeap(); + //uint32_t free_memory = ESP.getFreeHeap(); + //sprintf(buffer, " Memory: %d bytes free (%2u%%)
", free_memory, 100 * free_memory / total_memory); + //strlcat(s, buffer, sizeof(s)); strlcat(s, "

", sizeof(s)); if (_web_callback) { diff --git a/lib/MyESP/MyESP.h b/lib/MyESP/MyESP.h index 330a3b7f2..d2c8cdf3f 100644 --- a/lib/MyESP/MyESP.h +++ b/lib/MyESP/MyESP.h @@ -208,7 +208,7 @@ const char webCommonPage_start[] = "" "body {background-color: #FFA500;font: normal 18px Verdana, Arial, sans-serif;} "; -const char webCommonPage_start_refresh[] = ""; +const char webCommonPage_start_refresh[] = ""; const char webCommonPage_start_body[] = ""; diff --git a/src/version.h b/src/version.h index 6eb8a81cf..a5bd2e845 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.8.1b13" +#define APP_VERSION "1.8.1b14" #define APP_HOSTNAME "ems-esp" From 61e8f093de30e618a28dc976ce13cb8af196ef51 Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 6 Jul 2019 17:14:02 +0200 Subject: [PATCH 53/89] ignore n/a values iin mqtt too --- src/ems-esp.cpp | 6 ++++-- src/ems.h | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index 18b3c9bd2..8018f2c8c 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -178,7 +178,7 @@ char * _bool_to_char(char * s, uint8_t value) { // negative values are assumed stored as 1-compliment (https://medium.com/@LeeJulija/how-integers-are-stored-in-memory-using-twos-complement-5ba04d61a56c) char * _short_to_char(char * s, int16_t value, uint8_t decimals = 1) { // remove errors or invalid values - if ((value == EMS_VALUE_SHORT_NOTSET) || (value == 0x8000)) { + if (value == EMS_VALUE_SHORT_NOTSET) { strlcpy(s, "?", 10); return (s); } @@ -216,7 +216,7 @@ char * _short_to_char(char * s, int16_t value, uint8_t decimals = 1) { // decimals: 0 = no division, 1=divide value by 10, 2=divide by 2, 10=divide value by 100 char * _ushort_to_char(char * s, uint16_t value, uint8_t decimals = 1) { // remove errors or invalid values - if ((value == EMS_VALUE_USHORT_NOTSET) || (value == 0x8000)) { + if (value == EMS_VALUE_USHORT_NOTSET) { strlcpy(s, "?", 10); return (s); } @@ -643,6 +643,8 @@ void publishSensorValues() { } } + + // send values via MQTT // a json object is created for the boiler and one for the thermostat // CRC check is done to see if there are changes in the values since the last send to avoid too much wifi traffic diff --git a/src/ems.h b/src/ems.h index f3cec99ab..34a0662ba 100644 --- a/src/ems.h +++ b/src/ems.h @@ -33,12 +33,12 @@ // max length of a telegram, including CRC, for Rx and Tx. #define EMS_MAX_TELEGRAM_LENGTH 32 -// default values +// default values for null values #define EMS_VALUE_INT_ON 1 // boolean true #define EMS_VALUE_INT_OFF 0 // boolean false #define EMS_VALUE_INT_NOTSET 0xFF // for 8-bit unsigned ints/bytes #define EMS_VALUE_SHORT_NOTSET -32768 // for 2-byte signed shorts -#define EMS_VALUE_USHORT_NOTSET 0xFFFF // for 2-byte unsigned shorts +#define EMS_VALUE_USHORT_NOTSET 0x8000 // for 2-byte unsigned shorts #define EMS_VALUE_LONG_NOTSET 0xFFFFFF // for 3-byte longs #define EMS_THERMOSTAT_WRITE_YES true From 32b61f67cf0275a7c8002991336b2ec4682cc2d7 Mon Sep 17 00:00:00 2001 From: Paul Derbyshire Date: Mon, 8 Jul 2019 11:23:00 +0200 Subject: [PATCH 54/89] telnet works in AP mode, no more automatic web refresh --- CHANGELOG.md | 5 ++++- lib/MyESP/MyESP.cpp | 11 +++-------- lib/MyESP/MyESP.h | 5 +---- src/version.h | 2 +- 4 files changed, 9 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index db10a3c73..3351cd6e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [1.8.1dev] 2019-07-01 +## [1.8.1dev] 2019-07-08 ### Added @@ -14,18 +14,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - reset firmware option. If the reset button on the ESP is pressed during boot up sequence (the LED is flashing very fast) all settings are erased and goes into AP mode. - Added tx_mode back with options 0,1 and 2 until we've fixed option 2 that works for everyone and doesn't reset ESP - More solar module data captured, thanks to @Vuego123 +- -DNO_SERIAL option added to determine if the Serial port should be enabled on fresh installs ### Fixed - Detecting unset values in the SPIFFS and setting default values - Bosch Easy Connect wrongly classified as a thermostat - Correctly handle telegrams who's size are exactly 32 bytes (e.g. 0x19 MonitorSlow) +- Telnet also available when in AP mode ### Changed - Improved handling of Solar Modules (thanks @Vuego123) - `publish_wait` renamed to `publish_time`, a value of 0 means disabling all MQTT sending - How signed shorts are handled such as the current and setpoint temps on RC300s +- Stopped automatic refresh of web page, which causes crashes/memory loss after a short time ## [1.8.0] 2019-06-15 diff --git a/lib/MyESP/MyESP.cpp b/lib/MyESP/MyESP.cpp index 16c1a6879..9fd14b039 100644 --- a/lib/MyESP/MyESP.cpp +++ b/lib/MyESP/MyESP.cpp @@ -1972,7 +1972,7 @@ void MyESP::_webRootPage() { char s[1000] = {0}; strlcpy(s, webCommonPage_start, sizeof(s)); - strlcat(s, webCommonPage_start_refresh, sizeof(s)); + // strlcat(s, webCommonPage_start_refresh, sizeof(s)); strlcat(s, webCommonPage_start_body, sizeof(s)); strlcat(s, "

", sizeof(s)); @@ -2217,7 +2217,7 @@ void MyESP::loop() { ArduinoOTA.handle(); // OTA if (_ota_doing_update) { - return; // quit if in the middle of an update + return; // quit if in the middle of an OTA update } _calculateLoad(); @@ -2225,12 +2225,7 @@ void MyESP::loop() { _heartbeatCheck(); _bootupSequence(); webServer.handleClient(); // web server client requests - - // if we're in AP mode, use the web server, otherwise switch to telnet - if (!isAPmode()) { - _telnetHandle(); - } - + _telnetHandle(); _mqttConnect(); // MQTT yield(); // ...and breath diff --git a/lib/MyESP/MyESP.h b/lib/MyESP/MyESP.h index d2c8cdf3f..f04551d2a 100644 --- a/lib/MyESP/MyESP.h +++ b/lib/MyESP/MyESP.h @@ -9,7 +9,7 @@ #ifndef MyEMS_h #define MyEMS_h -#define MYESP_VERSION "1.1.21" +#define MYESP_VERSION "1.1.22" #include #include @@ -207,9 +207,6 @@ const char webCommonPage_start[] = "" ""; - -const char webCommonPage_start_refresh[] = ""; - const char webCommonPage_start_body[] = ""; const char webCommonPage_end[] = ""; diff --git a/src/version.h b/src/version.h index a5bd2e845..cec3620a1 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.8.1b14" +#define APP_VERSION "1.8.1b15" #define APP_HOSTNAME "ems-esp" From 2f4d58bef4ba3f56398f6086244b09ced909f616 Mon Sep 17 00:00:00 2001 From: Paul Derbyshire Date: Mon, 8 Jul 2019 13:42:45 +0200 Subject: [PATCH 55/89] fix typo with DEFAULT_NO_SERIAL --- CHANGELOG.md | 2 +- platformio.ini-example | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3351cd6e5..27870abe2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - reset firmware option. If the reset button on the ESP is pressed during boot up sequence (the LED is flashing very fast) all settings are erased and goes into AP mode. - Added tx_mode back with options 0,1 and 2 until we've fixed option 2 that works for everyone and doesn't reset ESP - More solar module data captured, thanks to @Vuego123 -- -DNO_SERIAL option added to determine if the Serial port should be enabled on fresh installs +- -DDEFAULT_NO_SERIAL option added to determine if the Serial port should be enabled on fresh installs ### Fixed diff --git a/platformio.ini-example b/platformio.ini-example index 8719f8148..6ff32ab56 100644 --- a/platformio.ini-example +++ b/platformio.ini-example @@ -9,9 +9,9 @@ default_envs = debug [common] ; -DMYESP_TIMESTAMP -DTESTS -DCRASH -DNO_SERIAL -; -DNO_SERIAL if you want a fresh install to use the Serial port +; -DDEFAULT_NO_SERIAL if you want a fresh install to use the Serial port debug_flags = -Wall -DCRASH -release_flags = -w -DDNO_SERIAL +release_flags = -w -DDEFAULT_NO_SERIAL general_flags = -g -DNO_GLOBAL_EEPROM arduino_core_2_3_0 = espressif8266@1.5.0 From 7b6dc38c3daba9dcd3ef97579c41709789f8d125 Mon Sep 17 00:00:00 2001 From: Paul Derbyshire Date: Mon, 15 Jul 2019 10:54:15 +0200 Subject: [PATCH 56/89] https://github.com/proddy/EMS-ESP/issues/145 --- src/ems.cpp | 21 +++++++++++++-------- src/ems_devices.h | 1 + src/version.h | 2 +- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/ems.cpp b/src/ems.cpp index f05540c17..f5eaa5cea 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -1300,9 +1300,7 @@ void _process_RCPLUSStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { EMS_Thermostat.day_mode = _bitRead(EMS_OFFSET_RCPLUSGet_mode_day, 1); // get day mode flag - // room night setpoint is _toByte(2) (value is *2) - // boiler set temp is _toByte(4) (value is *2) - // day night is byte(8), 0x01 for night, 0x00 for day + EMS_Thermostat.mode = _bitRead(EMS_OFFSET_RCPLUSStatusMessage_mode, 1); // bit 1, mode (auto or manual) } // actual set point @@ -1316,6 +1314,13 @@ void _process_RCPLUSStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { if (EMS_RxTelegram->offset == 6) { // to add... } + + // thermostat mode auto/manual, examples: + // manual : 10 00 FF 0A 01 A5 02 (CRC=16) #data=1 + // auto : Thermostat -> all, type 0x01A5 telegram: 10 00 FF 0A 01 A5 03 (CRC=17) #data=1 + if (EMS_RxTelegram->offset == EMS_OFFSET_RCPLUSStatusMessage_mode) { + EMS_Thermostat.mode = _bitRead(0, 1); // bit 1 + } } /** @@ -1480,18 +1485,18 @@ void _process_SM100Energy(_EMS_RxTelegram * EMS_RxTelegram) { * Type 0xE3 - HeatPump Monitor 1 */ void _process_HPMonitor1(_EMS_RxTelegram * EMS_RxTelegram) { - EMS_HeatPump.HPModulation = _toByte(14); // modulation % + EMS_HeatPump.HPModulation = _toByte(14); // modulation % - EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT + EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT } /* * Type 0xE5 - HeatPump Monitor 2 */ void _process_HPMonitor2(_EMS_RxTelegram * EMS_RxTelegram) { - EMS_HeatPump.HPSpeed = _toByte(25); // speed % - - EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT + EMS_HeatPump.HPSpeed = _toByte(25); // speed % + + EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT } /* diff --git a/src/ems_devices.h b/src/ems_devices.h index 21e154f3d..882f859bb 100644 --- a/src/ems_devices.h +++ b/src/ems_devices.h @@ -112,6 +112,7 @@ #define EMS_OFFSET_RCPLUSStatusMessage_setpoint 3 // setpoint temp #define EMS_OFFSET_RCPLUSStatusMessage_curr 0 // current temp #define EMS_OFFSET_RCPLUSGet_mode_day 8 // day/night mode +#define EMS_OFFSET_RCPLUSStatusMessage_mode 0x0A // thermostat mode (auto, manual) // Junkers FR10, FW100 (EMS Plus) #define EMS_TYPE_JunkersStatusMessage 0x6F // is an automatic thermostat broadcast giving us temps diff --git a/src/version.h b/src/version.h index cec3620a1..56c7f85f6 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.8.1b15" +#define APP_VERSION "1.8.1b16" #define APP_HOSTNAME "ems-esp" From 03106d27c5522df805aff543645f22973efecdad Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 15 Jul 2019 21:34:17 +0200 Subject: [PATCH 57/89] updated with v4 pio --- platformio.ini-example | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/platformio.ini-example b/platformio.ini-example index 6ff32ab56..f2fa1f1a2 100644 --- a/platformio.ini-example +++ b/platformio.ini-example @@ -1,6 +1,5 @@ ; ; PlatformIO Project Configuration File for EMS-ESP -; Uses PlatformIO 4.0 ; [platformio] @@ -8,28 +7,15 @@ default_envs = debug [common] -; -DMYESP_TIMESTAMP -DTESTS -DCRASH -DNO_SERIAL -; -DDEFAULT_NO_SERIAL if you want a fresh install to use the Serial port -debug_flags = -Wall -DCRASH -release_flags = -w -DDEFAULT_NO_SERIAL -general_flags = -g -DNO_GLOBAL_EEPROM - -arduino_core_2_3_0 = espressif8266@1.5.0 -arduino_core_2_4_0 = espressif8266@1.6.0 -arduino_core_2_4_1 = espressif8266@1.7.3 -arduino_core_2_4_2 = espressif8266@1.8.0 -arduino_core_2_5_0 = espressif8266@2.0.4 -arduino_core_2_5_1 = espressif8266@2.1.1 -arduino_core_2_5_2 = espressif8266@2.2.1 -arduino_core_dev = https://github.com/platformio/platform-espressif8266.git -arduino_core_latest = espressif8266 +; -DMYESP_TIMESTAMP -DTESTS -DCRASH -DNO_SERIAL -DNO_GLOBAL_EEPROM +extra_flags = -DNO_GLOBAL_EEPROM [env] board = d1_mini ; board = nodemcuv2 ; board = d1_mini_pro framework = arduino -platform = ${common.arduino_core_latest} +platform = espressif8266 lib_deps = CRC32 CircularBuffer @@ -45,16 +31,17 @@ monitor_speed = 115200 ;upload_port = ems-esp.local [env:debug] -build_flags = ${common.general_flags} ${common.debug_flags} +build_type = debug +build_flags = ${common.extra_flags} -DCRASH extra_scripts = pre:scripts/rename_fw.py [env:clean] extra_scripts = pre:scripts/clean_fw.py [env:release] -build_flags = ${common.general_flags} ${common.release_flags} +build_flags = ${common.extra_flags} extra_scripts = pre:scripts/rename_fw.py [env:checkcode] -build_flags = ${common.general_flags} ${common.debug_flags} +build_flags = ${common.extra_flags} extra_scripts = scripts/checkcode.py From 2fd84b2ba40013fac7eb6d546aa3e7e59fe2574e Mon Sep 17 00:00:00 2001 From: Paul Derbyshire Date: Tue, 16 Jul 2019 11:29:20 +0200 Subject: [PATCH 58/89] https://github.com/proddy/EMS-ESP/issues/145 --- src/ems-esp.cpp | 76 +++++++++++++++++++++++++++++++++++++++++-------- src/version.h | 2 +- 2 files changed, 65 insertions(+), 13 deletions(-) diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index 8018f2c8c..ad586cc65 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -579,13 +579,44 @@ void showInfo() { EMS_Thermostat.month, EMS_Thermostat.year + 2000); + // thermostat mode (-1=unknown, 0=low, 1=manual, 2=auto, 3=night, 4=day) + int thermoMode = -1; + + if (ems_getThermostatModel() == EMS_MODEL_RC20) { + if (EMS_Thermostat.mode == 0) { + thermoMode = 0; // low + } else if (EMS_Thermostat.mode == 1) { + thermoMode = 1; // manual + } else { + thermoMode = 2; // auto + } + } else if (ems_getThermostatModel() == EMS_MODEL_1010) { + if (EMS_Thermostat.mode == 0) { + thermoMode = 1; // manual + } else if (EMS_Thermostat.mode == 1) { + thermoMode = 2; // auto + } + } else { // default for all thermostats + if (EMS_Thermostat.mode == 0) { + thermoMode = 3; // night + } else if (EMS_Thermostat.mode == 1) { + thermoMode = 4; // day + } else { + thermoMode = 2; // auto + } + } + // Render Termostat Mode - if (EMS_Thermostat.mode == 0) { + if (thermoMode == 0) { myDebug_P(PSTR(" Mode is set to low")); - } else if (EMS_Thermostat.mode == 1) { + } else if (thermoMode == 1) { myDebug_P(PSTR(" Mode is set to manual")); - } else if (EMS_Thermostat.mode == 2) { + } else if (thermoMode == 2) { myDebug_P(PSTR(" Mode is set to auto")); + } else if (thermoMode == 3) { + myDebug_P(PSTR(" Mode is set to night")); + } else if (thermoMode == 4) { + myDebug_P(PSTR(" Mode is set to day")); } else { myDebug_P(PSTR(" Mode is set to ?")); } @@ -787,23 +818,44 @@ void publishValues(bool force) { rootThermostat[THERMOSTAT_CIRCUITCALCTEMP] = EMS_Thermostat.circuitcalctemp; } - // RC20 has different mode settings + // thermostat mode (-1=unknown, 0=low, 1=manual, 2=auto, 3=night, 4=day) + int thermoMode = -1; + if (ems_getThermostatModel() == EMS_MODEL_RC20) { if (EMS_Thermostat.mode == 0) { - rootThermostat[THERMOSTAT_MODE] = "low"; + thermoMode = 0; // low } else if (EMS_Thermostat.mode == 1) { - rootThermostat[THERMOSTAT_MODE] = "manual"; + thermoMode = 1; // manual } else { - rootThermostat[THERMOSTAT_MODE] = "auto"; + thermoMode = 2; // auto } - } else { + } else if (ems_getThermostatModel() == EMS_MODEL_1010) { if (EMS_Thermostat.mode == 0) { - rootThermostat[THERMOSTAT_MODE] = "night"; + thermoMode = 1; // manual } else if (EMS_Thermostat.mode == 1) { - rootThermostat[THERMOSTAT_MODE] = "day"; - } else { - rootThermostat[THERMOSTAT_MODE] = "auto"; + thermoMode = 2; // auto } + } else { // default for all thermostats + if (EMS_Thermostat.mode == 0) { + thermoMode = 3; // night + } else if (EMS_Thermostat.mode == 1) { + thermoMode = 4; // day + } else { + thermoMode = 2; // auto + } + } + + // Termostat Mode + if (thermoMode == 0) { + rootThermostat[THERMOSTAT_MODE] = "low"; + } else if (thermoMode == 1) { + rootThermostat[THERMOSTAT_MODE] = "manual"; + } else if (thermoMode == 2) { + rootThermostat[THERMOSTAT_MODE] = "auto"; + } else if (thermoMode == 3) { + rootThermostat[THERMOSTAT_MODE] = "night"; + } else if (thermoMode == 4) { + rootThermostat[THERMOSTAT_MODE] = "day"; } data[0] = '\0'; // reset data for next package diff --git a/src/version.h b/src/version.h index 56c7f85f6..2c4cbdaf4 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.8.1b16" +#define APP_VERSION "1.8.1b17" #define APP_HOSTNAME "ems-esp" From c3bc82cbc85b3ca323ccbbfdf4dba3a9cbdb5562 Mon Sep 17 00:00:00 2001 From: Paul Derbyshire Date: Tue, 16 Jul 2019 11:38:27 +0200 Subject: [PATCH 59/89] RC300/3000 rename --- src/ems-esp.cpp | 4 ++-- src/ems_devices.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index ad586cc65..b4c7da1f5 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -590,7 +590,7 @@ void showInfo() { } else { thermoMode = 2; // auto } - } else if (ems_getThermostatModel() == EMS_MODEL_1010) { + } else if (ems_getThermostatModel() == EMS_MODEL_RC300) { if (EMS_Thermostat.mode == 0) { thermoMode = 1; // manual } else if (EMS_Thermostat.mode == 1) { @@ -829,7 +829,7 @@ void publishValues(bool force) { } else { thermoMode = 2; // auto } - } else if (ems_getThermostatModel() == EMS_MODEL_1010) { + } else if (ems_getThermostatModel() == EMS_MODEL_RC300) { if (EMS_Thermostat.mode == 0) { thermoMode = 1; // manual } else if (EMS_Thermostat.mode == 1) { diff --git a/src/ems_devices.h b/src/ems_devices.h index 882f859bb..f8bea7e73 100644 --- a/src/ems_devices.h +++ b/src/ems_devices.h @@ -142,7 +142,7 @@ typedef enum { EMS_MODEL_RC30, EMS_MODEL_RC35, EMS_MODEL_EASY, - EMS_MODEL_RC310, + EMS_MODEL_RC300, EMS_MODEL_CW100, EMS_MODEL_1010, EMS_MODEL_OT, @@ -227,7 +227,7 @@ const _Thermostat_Type Thermostat_Types[] = { {EMS_MODEL_RC20F, 93, 0x18, "RC20F", EMS_THERMOSTAT_WRITE_YES}, {EMS_MODEL_RC30, 78, 0x10, "RC30/Nefit Moduline 400", EMS_THERMOSTAT_WRITE_YES}, {EMS_MODEL_RC35, 86, 0x10, "RC35", EMS_THERMOSTAT_WRITE_YES}, - {EMS_MODEL_RC310, 158, 0x10, "RC300/RC310/Nefit Moduline 1010/3000", EMS_THERMOSTAT_WRITE_NO}, + {EMS_MODEL_RC300, 158, 0x10, "RC300/RC310/Nefit Moduline 3000", EMS_THERMOSTAT_WRITE_NO}, {EMS_MODEL_1010, 165, 0x18, "Nefit Moduline 1010", EMS_THERMOSTAT_WRITE_NO}, // Sieger From d5c717c812d77ef35119de3c8601daac962df5c6 Mon Sep 17 00:00:00 2001 From: Paul Derbyshire Date: Tue, 16 Jul 2019 16:25:56 +0200 Subject: [PATCH 60/89] added version to firmware filename --- scripts/rename_fw.py | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/scripts/rename_fw.py b/scripts/rename_fw.py index c8a9a5a02..d8cc79ba9 100644 --- a/scripts/rename_fw.py +++ b/scripts/rename_fw.py @@ -1,7 +1,27 @@ #!/usr/bin/env python +import re Import("env") -# see http://docs.platformio.org/en/latest/projectconf/advanced_scripting.html#before-pre-and-after-post-actions -# env.Replace(PROGNAME="firmware_%s" % defines.get("VERSION")) -# print env.Dump() -env.Replace(PROGNAME="firmware_%s" % env['BOARD'] + "_" + env['PIOENV']) +bag = {} +exprs = [ + (re.compile(r'^#define APP_VERSION\s+"(\S+)"'), 'app_version'), + (re.compile(r'^#define APP_NAME\s+"(\S+)"'), 'app_name'), + (re.compile(r'^#define APP_HOSTNAME\s+"(\S+)"'), 'app_hostname'), + +] +with open('./src/version.h', 'r') as f: + for l in f.readlines(): + for expr, var in exprs: + m = expr.match(l) + if m and len(m.groups()) > 0: + bag[var] = m.group(1) + +app_version = bag.get('app_version') +app_name = bag.get('app_name') +app_hostname = bag.get('app_hostname') + +board = env['BOARD'] +branch = env['PIOENV'] + +# build filename, replacing . with _ for the version +env.Replace(PROGNAME="firmware_%s" % branch + "_" + app_version.replace(".", "_")) From bac3f53613fb6d4ce6a4bc889b7778684524ea67 Mon Sep 17 00:00:00 2001 From: Paul Derbyshire Date: Tue, 16 Jul 2019 16:26:30 +0200 Subject: [PATCH 61/89] minor cleanup --- scripts/rename_fw.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/rename_fw.py b/scripts/rename_fw.py index d8cc79ba9..42a11881a 100644 --- a/scripts/rename_fw.py +++ b/scripts/rename_fw.py @@ -6,8 +6,7 @@ bag = {} exprs = [ (re.compile(r'^#define APP_VERSION\s+"(\S+)"'), 'app_version'), (re.compile(r'^#define APP_NAME\s+"(\S+)"'), 'app_name'), - (re.compile(r'^#define APP_HOSTNAME\s+"(\S+)"'), 'app_hostname'), - + (re.compile(r'^#define APP_HOSTNAME\s+"(\S+)"'), 'app_hostname') ] with open('./src/version.h', 'r') as f: for l in f.readlines(): From ed25e897802f7bf44de846cebbbabcf745d4d1b6 Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 17 Jul 2019 23:17:45 +0200 Subject: [PATCH 62/89] https://github.com/proddy/EMS-ESP/issues/145 --- src/ems.cpp | 4 ++-- src/version.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ems.cpp b/src/ems.cpp index f5eaa5cea..fd492b5b6 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -1300,7 +1300,7 @@ void _process_RCPLUSStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { EMS_Thermostat.day_mode = _bitRead(EMS_OFFSET_RCPLUSGet_mode_day, 1); // get day mode flag - EMS_Thermostat.mode = _bitRead(EMS_OFFSET_RCPLUSStatusMessage_mode, 1); // bit 1, mode (auto or manual) + EMS_Thermostat.mode = _bitRead(EMS_OFFSET_RCPLUSStatusMessage_mode, 0); // bit 1, mode (auto=1 or manual=0) } // actual set point @@ -1319,7 +1319,7 @@ void _process_RCPLUSStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { // manual : 10 00 FF 0A 01 A5 02 (CRC=16) #data=1 // auto : Thermostat -> all, type 0x01A5 telegram: 10 00 FF 0A 01 A5 03 (CRC=17) #data=1 if (EMS_RxTelegram->offset == EMS_OFFSET_RCPLUSStatusMessage_mode) { - EMS_Thermostat.mode = _bitRead(0, 1); // bit 1 + EMS_Thermostat.mode = _bitRead(0, 0); // bit 0 } } diff --git a/src/version.h b/src/version.h index 2c4cbdaf4..19c02c23d 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.8.1b17" +#define APP_VERSION "1.8.1b18" #define APP_HOSTNAME "ems-esp" From 7d361061c6550745dc74542b527b5840f9cd72f7 Mon Sep 17 00:00:00 2001 From: Susis Strolch Date: Wed, 17 Jul 2019 14:25:54 +0200 Subject: [PATCH 63/89] add marker pins (GPIO12, GPIO14) for logic analyser MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ° use faster macros for LA markers --- lib/MyESP/MyESP.cpp | 5 ----- src/ems-esp.cpp | 4 ++++ src/ems.h | 45 ++++++++++++++++++++++++++++++++++++++++++++- src/emsuart.cpp | 7 +++++++ 4 files changed, 55 insertions(+), 6 deletions(-) diff --git a/lib/MyESP/MyESP.cpp b/lib/MyESP/MyESP.cpp index 9fd14b039..bd50785ab 100644 --- a/lib/MyESP/MyESP.cpp +++ b/lib/MyESP/MyESP.cpp @@ -2195,16 +2195,11 @@ void MyESP::begin(const char * app_hostname, const char * app_name, const char * } _eeprom_setup(); // set up EEPROM for storing crash data, if compiled with -DCRASH - _fs_setup(); // SPIFFS setup, do this first to get values _wifi_setup(); // WIFI setup _ota_setup(); // init OTA _webserver_setup(); // init web server - - // print a welcome message - myDebug_P(PSTR("\n* %s version %s"), _app_name, _app_version); SerialAndTelnet.flush(); - _setSystemCheck(false); // reset system check _heartbeatCheck(true); // force heartbeat } diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index b4c7da1f5..9e8593317 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -1799,6 +1799,10 @@ void showerCheck() { // SETUP // void setup() { + // LA trigger create a small puls to show setup is starting... + INIT_MARKERS(0); + LA_PULSE(50); + // init our own parameters initEMSESP(); diff --git a/src/ems.h b/src/ems.h index 34a0662ba..4c05d12fb 100644 --- a/src/ems.h +++ b/src/ems.h @@ -12,6 +12,47 @@ #include +/* debug helper for logic analyzer + * create marker puls on GPIOx + * ° for Rx, we use GPIO14 + * ° for Tx, we use GPIO12 + */ +#define LOGICANALYZER +#ifdef LOGICANALYZER + #define RX_MARK_PIN 14 + #define TX_MARK_PIN 12 + + #define RX_MARK_MASK (1<> USTXC) & 0xFF) != 0) ; + TX_PULSE(EMSUART_BIT_TIME/2); tmp = ((1 << UCRXRST) | (1 << UCTXRST)); // bit mask USC0(EMSUART_UART) |= (tmp); // set bits USC0(EMSUART_UART) &= ~(tmp); // clear bits @@ -199,17 +201,20 @@ void ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) { if (EMS_Sys_Status.emsTxMode == 0) { // classic mode logic for (uint8_t i = 0; i < len; i++) { + TX_PULSE(EMSUART_BIT_TIME/4); USF(EMSUART_UART) = buf[i]; } emsuart_tx_brk(); // send } else if (EMS_Sys_Status.emsTxMode == 1) { // With extra tx delay for EMS+ for (uint8_t i = 0; i < len; i++) { + TX_PULSE(EMSUART_BIT_TIME/4); USF(EMSUART_UART) = buf[i]; delayMicroseconds(EMSUART_TX_BRK_WAIT); // https://github.com/proddy/EMS-ESP/issues/23# } emsuart_tx_brk(); // send } else if (EMS_Sys_Status.emsTxMode == 3) { // Junkers logic by @philrich for (uint8_t i = 0; i < len; i++) { + TX_PULSE(EMSUART_BIT_TIME/4); USF(EMSUART_UART) = buf[i]; // just to be safe wait for tx fifo empty (needed?) @@ -237,6 +242,7 @@ void ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) { // throw out the telegram... for (uint8_t i = 0; i < len;) { + TX_PULSE(EMSUART_BIT_TIME/4); USF(EMSUART_UART) = buf[i++]; // send each Tx byte // wait for echo from busmaster while ((((USS(EMSUART_UART) >> USRXC) & 0xFF) < i || (USIS(EMSUART_UART) & (1 << UIBD)))) { @@ -249,6 +255,7 @@ void ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) { // otherwise we send the final Tx-BRK in the loopback and re=enable Rx-INT. // worst case, we'll see an additional Rx-BRK... if (!(USIS(EMSUART_UART) & (1 << UIBD))) { + TX_PULSE(EMSUART_BIT_TIME/2); // no bus collision - send terminating BRK signal USC0(EMSUART_UART) |= (1 << UCLBE); // enable loopback USC0(EMSUART_UART) |= (1 << UCBRK); // set From 7743ff5d56dbc57051c61749969cef71282fd4dd Mon Sep 17 00:00:00 2001 From: Susis Strolch Date: Thu, 18 Jul 2019 16:26:42 +0200 Subject: [PATCH 64/89] add burnStarts, burnWorkMin, heatWorkMin to boiler data set --- src/ems-esp.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index 9e8593317..06e39a463 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -754,6 +754,14 @@ void publishValues(bool force) { if (EMS_Boiler.wWHeat != EMS_VALUE_INT_NOTSET) rootBoiler["wWHeat"] = _bool_to_char(s, EMS_Boiler.wWHeat); + // **** also add burnStarts, burnWorkMin, heatWorkMin + if (abs(EMS_Boiler.burnStarts) != EMS_VALUE_LONG_NOTSET) + rootBoiler["burnStarts"] = (double)EMS_Boiler.burnStarts; + if (abs(EMS_Boiler.burnWorkMin) != EMS_VALUE_LONG_NOTSET) + rootBoiler["burnWorkMin"] = (double)EMS_Boiler.burnWorkMin; + if (abs(EMS_Boiler.heatWorkMin) != EMS_VALUE_LONG_NOTSET) + rootBoiler["heatWorkMin"] = (double)EMS_Boiler.heatWorkMin; + rootBoiler["ServiceCode"] = EMS_Boiler.serviceCodeChar; rootBoiler["ServiceCodeNumber"] = EMS_Boiler.serviceCode; From 3b986c2e2846fd2c42d1ab301ef906e14d5d00d7 Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 18 Jul 2019 23:06:36 +0200 Subject: [PATCH 65/89] https://github.com/proddy/EMS-ESP/issues/153 --- doc/home_assistant/climate.yaml | 4 ++-- src/ems-esp.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/home_assistant/climate.yaml b/doc/home_assistant/climate.yaml index b344c66fb..a308f0f03 100644 --- a/doc/home_assistant/climate.yaml +++ b/doc/home_assistant/climate.yaml @@ -21,7 +21,7 @@ - platform: mqtt name: boiler modes: - - "on" + - "auto" - "off" min_temp: 40 max_temp: 60 @@ -31,6 +31,6 @@ temperature_command_topic: "home/ems-esp/boiler_cmd_wwtemp" current_temperature_template: "{{ value_json.wWCurTmp }}" temperature_state_template: "{{ value_json.wWSelTemp }}" - mode_state_template: "{{ value_json.wWActivated }}" + mode_state_template: "{% if value_json.wWActivated == 'off' %} off {% else %} auto {% endif %}" mode_state_topic: "home/ems-esp/boiler_data" mode_command_topic: "home/ems-esp/wwactivated" diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index b4c7da1f5..ebdef1a65 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -1602,7 +1602,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) { // wwActivated if (strcmp(topic, TOPIC_BOILER_WWACTIVATED) == 0) { - if (message[0] == '1' || strcmp(message, "on") == 0) { + if ((message[0] == '1' || strcmp(message, "on") == 0) || (strcmp(message, "auto") == 0)) { ems_setWarmWaterActivated(true); } else if (message[0] == '0' || strcmp(message, "off") == 0) { ems_setWarmWaterActivated(false); From e2da47afc7b2b44d1593934dbb7f05496a793847 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 19 Jul 2019 00:05:04 +0200 Subject: [PATCH 66/89] tidy up HA config --- CHANGELOG.md | 4 +++- doc/home_assistant/climate.yaml | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27870abe2..d5716abcb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [1.8.1dev] 2019-07-08 +## [1.8.1dev] 2019-07-19 ### Added @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added tx_mode back with options 0,1 and 2 until we've fixed option 2 that works for everyone and doesn't reset ESP - More solar module data captured, thanks to @Vuego123 - -DDEFAULT_NO_SERIAL option added to determine if the Serial port should be enabled on fresh installs +- Detect thermostat mode for EMS+ RC300/Moduline 3000 ### Fixed @@ -29,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `publish_wait` renamed to `publish_time`, a value of 0 means disabling all MQTT sending - How signed shorts are handled such as the current and setpoint temps on RC300s - Stopped automatic refresh of web page, which causes crashes/memory loss after a short time +- Support HA 0.96 climate component changes ## [1.8.0] 2019-06-15 diff --git a/doc/home_assistant/climate.yaml b/doc/home_assistant/climate.yaml index a308f0f03..f23edba77 100644 --- a/doc/home_assistant/climate.yaml +++ b/doc/home_assistant/climate.yaml @@ -21,8 +21,8 @@ - platform: mqtt name: boiler modes: - - "auto" - - "off" + - "auto" + - "off" min_temp: 40 max_temp: 60 temp_step: 1 @@ -34,3 +34,4 @@ mode_state_template: "{% if value_json.wWActivated == 'off' %} off {% else %} auto {% endif %}" mode_state_topic: "home/ems-esp/boiler_data" mode_command_topic: "home/ems-esp/wwactivated" + \ No newline at end of file From 80a9c98658d5011ed0c813d396441f1403dbec26 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 19 Jul 2019 00:23:10 +0200 Subject: [PATCH 67/89] auto get temps from RC300/3000 --- src/ems.cpp | 28 +++++++++++++++++++--------- src/version.h | 2 +- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/src/ems.cpp b/src/ems.cpp index fd492b5b6..8238c7d1a 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -1887,22 +1887,32 @@ void ems_getThermostatValues() { uint8_t type = EMS_Thermostat.device_id; uint8_t hc = EMS_Thermostat.hc; - if (model_id == EMS_MODEL_RC20) { - ems_doReadCommand(EMS_TYPE_RC20StatusMessage, type); // to get the setpoint temp + switch (model_id) { + case EMS_MODEL_RC20: + ems_doReadCommand(EMS_TYPE_RC20StatusMessage, type); // to get the temps ems_doReadCommand(EMS_TYPE_RC20Set, type); // to get the mode - } else if (model_id == EMS_MODEL_RC30) { - ems_doReadCommand(EMS_TYPE_RC30StatusMessage, type); // to get the setpoint temp + break; + case EMS_MODEL_RC30: + ems_doReadCommand(EMS_TYPE_RC30StatusMessage, type); // to get the temps ems_doReadCommand(EMS_TYPE_RC30Set, type); // to get the mode - } else if ((model_id == EMS_MODEL_RC35) || (model_id == EMS_MODEL_ES73)) { + break; + case EMS_MODEL_EASY: + ems_doReadCommand(EMS_TYPE_EasyStatusMessage, type); + break; + case EMS_MODEL_RC35: + case EMS_MODEL_ES73: if (hc == 1) { - ems_doReadCommand(EMS_TYPE_RC35StatusMessage_HC1, type); // to get the setpoint temp + ems_doReadCommand(EMS_TYPE_RC35StatusMessage_HC1, type); // to get the temps ems_doReadCommand(EMS_TYPE_RC35Set_HC1, type); // to get the mode } else if (hc == 2) { - ems_doReadCommand(EMS_TYPE_RC35StatusMessage_HC2, type); // to get the setpoint temp + ems_doReadCommand(EMS_TYPE_RC35StatusMessage_HC2, type); // to get the temps ems_doReadCommand(EMS_TYPE_RC35Set_HC2, type); // to get the mode } - } else if ((model_id == EMS_MODEL_EASY)) { - ems_doReadCommand(EMS_TYPE_EasyStatusMessage, type); + break; + case EMS_MODEL_RC300: + ems_doReadCommand(EMS_TYPE_RCPLUSStatusMessage, type); + default: + break; } ems_doReadCommand(EMS_TYPE_RCTime, type); // get Thermostat time diff --git a/src/version.h b/src/version.h index 19c02c23d..c0cec732e 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.8.1b18" +#define APP_VERSION "1.8.1b19" #define APP_HOSTNAME "ems-esp" From 5587b9d267711418c93926bc110e9718bff65fd5 Mon Sep 17 00:00:00 2001 From: Susis Strolch Date: Fri, 19 Jul 2019 13:16:23 +0200 Subject: [PATCH 68/89] reworks because of 'tx_mode 2' and protocol issues MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ° added markers (GIO12, GPIO14) for logic analyzer debugging ° change UART initialisation - set RxFIFO full to 1 char, so we can detect active telegram on EMS-Bus - set RxTOT to 1 char for the same reason ° in ems_parseTelegram: ignore telegram if emsRxStatus != EMS_RX_STATUS_IDLE because we missed to respond in a timely manner ° ems_tx_buffer is not void anymore, instead we return the Tx status ° extended the emsTxStatus - EMS_TX_WTD_TIMEOUT: timeout while waiting for echo of last Tx byte out telegram was ignored by the bus master, so the byte wasn't echoed - EMS_TX_BRK_DETECT: BRK detected while sending the telegram bus master send us a break because of protocol violation ° add burnStarts, burnWorkMin and heatWorkMin to MQTT boiler message TODO: + take care of ems_tx_buffer return code + accept direct telegram in ems_parse_telegram and do a proper acknowledge + split the heartbeat in static (version, IP-address) and dynamic (RSS etc) + change the hearbeat to a JSON structure so we can easier pick the uptime --- src/ems.cpp | 21 ++++- src/ems.h | 10 +-- src/emsuart.cpp | 203 +++++++++++++++++++++++++++++------------------- src/emsuart.h | 2 +- src/my_config.h | 5 ++ 5 files changed, 151 insertions(+), 90 deletions(-) diff --git a/src/ems.cpp b/src/ems.cpp index fd492b5b6..cbf2a6c2a 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -724,9 +724,23 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) { EMS_RxTelegram.timestamp = millis(); EMS_RxTelegram.length = length; - // check if we just received a single byte - // it could well be a Poll request from the boiler for us, which will have a value of 0x8B (0x0B | 0x80) - // or either a return code like 0x01 or 0x04 from the last Write command + /* + * check if we just received a single byte + * it could well be a Poll request from the boiler for us, which will have a value of 0x8B (0x0B | 0x80) + * or either a return code like 0x01 or 0x04 from the last Write command + * Roger Wilco: we have different types here: + * EMS_ID_ME && length == 1 && EMS_TX_STATUS_IDLE && EMS_RX_STATUS_IDLE: polling request + * EMS_ID_ME && length > 1 && EMS_TX_STATUS_IDLE && EMS_RX_STATUS_IDLE: direct telegram + * (EMS_TX_SUCCESS || EMS_TX_ERROR) && EMS_TX_STATUS_WAIT: response, free the EMS bus + * + * In addition, it may happen that we where interrupted (f.e. by WIFI activity) and the + * buffer isn't valid anymore, so we must not answer at all... + */ + if (EMS_Sys_Status.emsRxStatus != EMS_RX_STATUS_IDLE) { + myDebug_P(PSTR("** We missed the bus - Rx non-idle!")); + return; + } + if (length == 1) { uint8_t value = telegram[0]; // 1st byte of data package @@ -816,6 +830,7 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) { // Assume at this point we have something that vaguely resembles a telegram in the format [src] [dest] [type] [offset] [data] [crc] // validate the CRC, if it's bad ignore it if (telegram[length - 1] != _crcCalculator(telegram, length)) { + LA_PULSE(200); EMS_Sys_Status.emxCrcErr++; if (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_VERBOSE) { _debugPrintTelegram("Corrupt telegram: ", &EMS_RxTelegram, COLOR_RED, true); diff --git a/src/ems.h b/src/ems.h index 4c05d12fb..5d406bef7 100644 --- a/src/ems.h +++ b/src/ems.h @@ -17,7 +17,6 @@ * ° for Rx, we use GPIO14 * ° for Tx, we use GPIO12 */ -#define LOGICANALYZER #ifdef LOGICANALYZER #define RX_MARK_PIN 14 #define TX_MARK_PIN 12 @@ -47,10 +46,10 @@ GPIO_L(MARKERS_MASK); \ } while (0) #else - #define RX_PULSE(pulse) - #define TX_PULSE(pulse) - #define LA_PULSE(pulse) - #define INIT_MARKERS(void) + #define RX_PULSE(pulse) {} + #define TX_PULSE(pulse) {} + #define LA_PULSE(pulse) {} + #define INIT_MARKERS(void) {} #endif #define EMS_ID_NONE 0x00 // used as a dest in broadcast messages and empty device IDs @@ -104,6 +103,7 @@ typedef enum { } _EMS_RX_STATUS; typedef enum { + EMS_TX_STATUS_OK, EMS_TX_STATUS_IDLE, // ready EMS_TX_STATUS_WAIT, // waiting for response from last Tx EMS_TX_WTD_TIMEOUT, // watchdog timeout during send diff --git a/src/emsuart.cpp b/src/emsuart.cpp index 30eb88295..5c19b0296 100644 --- a/src/emsuart.cpp +++ b/src/emsuart.cpp @@ -5,10 +5,10 @@ * Paul Derbyshire - https://github.com/proddy/EMS-ESP */ -#include "emsuart.h" -#include "ems.h" #include #include +#include "ems.h" +#include "emsuart.h" _EMSRxBuf * pEMSRxBuf; _EMSRxBuf * paEMSRxBuf[EMS_MAXBUFFERS]; @@ -29,7 +29,7 @@ static void emsuart_rx_intr_handler(void * para) { EMS_Sys_Status.emsRxStatus = EMS_RX_STATUS_BUSY; // status set to busy length = 0; } - + GPIO_H(RX_MARK_MASK); // fill IRQ buffer, by emptying Rx FIFO if (USIS(EMSUART_UART) & ((1 << UIFF) | (1 << UITO) | (1 << UIBD))) { while ((USS(EMSUART_UART) >> USRXC) & 0xFF) { @@ -39,21 +39,20 @@ static void emsuart_rx_intr_handler(void * para) { // clear Rx FIFO full and Rx FIFO timeout interrupts USIC(EMSUART_UART) = (1 << UIFF) | (1 << UITO); } + GPIO_L(RX_MARK_MASK); // BREAK detection = End of EMS data block if (USIS(EMSUART_UART) & ((1 << UIBD))) { ETS_UART_INTR_DISABLE(); // disable all interrupts and clear them - RX_PULSE(EMSUART_BIT_TIME/2); - USIC(EMSUART_UART) = (1 << UIBD); // INT clear the BREAK detect interrupt pEMSRxBuf->length = length; os_memcpy((void *)pEMSRxBuf->buffer, (void *)&uart_buffer, length); // copy data into transfer buffer, including the BRK 0x00 at the end EMS_Sys_Status.emsRxStatus = EMS_RX_STATUS_IDLE; // set the status flag stating BRK has been received and we can start a new package + ETS_UART_INTR_ENABLE(); // re-enable UART interrupts system_os_post(EMSUART_recvTaskPrio, 0, 0); // call emsuart_recvTask() at next opportunity - - ETS_UART_INTR_ENABLE(); // re-enable UART interrupts + RX_PULSE(EMSUART_BIT_TIME/2); } } @@ -64,21 +63,22 @@ static void emsuart_rx_intr_handler(void * para) { */ static void ICACHE_FLASH_ATTR emsuart_recvTask(os_event_t * events) { _EMSRxBuf * pCurrent = pEMSRxBuf; + pEMSRxBuf = paEMSRxBuf[++emsRxBufIdx % EMS_MAXBUFFERS]; // next free EMS Receive buffer uint8_t length = pCurrent->length; // number of bytes including the BRK at the end + pCurrent->length = 0; // validate and transmit the EMS buffer, excluding the BRK if (length == 2) { + RX_PULSE(20); // it's a poll or status code, single byte and ok to send on ems_parseTelegram((uint8_t *)pCurrent->buffer, 1); } else if ((length > 4) && (length <= EMS_MAXBUFFERSIZE + 1) && (pCurrent->buffer[length - 2] != 0x00)) { // ignore double BRK at the end, possibly from the Tx loopback // also telegrams with no data value + RX_PULSE(40); ems_parseTelegram((uint8_t *)pCurrent->buffer, length - 1); // transmit EMS buffer, excluding the BRK } - - memset(pCurrent->buffer, 0x00, EMS_MAXBUFFERSIZE); // wipe memory just to be safe - - pEMSRxBuf = paEMSRxBuf[++emsRxBufIdx % EMS_MAXBUFFERS]; // next free EMS Receive buffer + // memset(pCurrent->buffer, 0x00, EMS_MAXBUFFERSIZE); // wipe memory just to be safe } /* @@ -118,11 +118,14 @@ void ICACHE_FLASH_ATTR emsuart_init() { // conf1 params // UCTOE = RX TimeOut enable (default is 1) - // UCTOT = RX TimeOut Threshold (7 bit) = want this when no more data after 2 characters (default is 2) + // UCTOT = RX TimeOut Threshold (7 bit) = want this when no more data after 1 characters (default is 2) // UCFFT = RX FIFO Full Threshold (7 bit) = want this to be 31 for 32 bytes of buffer (default was 127) // see https://www.espressif.com/sites/default/files/documentation/esp8266-technical_reference_en.pdf + // + // change: we set UCFFT to 1 to get an immediate indicator about incoming trafffic. + // Otherwise, we're only noticed by UCTOT or RxBRK! USC1(EMSUART_UART) = 0; // reset config first - USC1(EMSUART_UART) = (EMS_MAX_TELEGRAM_LENGTH << UCFFT) | (0x02 << UCTOT) | (1 << UCTOE); // enable interupts + USC1(EMSUART_UART) = (0x01 << UCFFT) | (0x01 << UCTOT) | (1 << UCTOE); // enable interupts // set interrupts for triggers USIC(EMSUART_UART) = 0xFFFF; // clear all interupts @@ -171,7 +174,6 @@ void ICACHE_FLASH_ATTR emsuart_tx_brk() { while (((USS(EMSUART_UART) >> USTXC) & 0xFF) != 0) ; - TX_PULSE(EMSUART_BIT_TIME/2); tmp = ((1 << UCRXRST) | (1 << UCTXRST)); // bit mask USC0(EMSUART_UART) |= (tmp); // set bits USC0(EMSUART_UART) &= ~(tmp); // clear bits @@ -179,6 +181,7 @@ void ICACHE_FLASH_ATTR emsuart_tx_brk() { // To create a 11-bit we set TXD_BRK bit so the break signal will // automatically be sent when the tx fifo is empty tmp = (1 << UCBRK); + GPIO_H(TX_MARK_MASK); USC0(EMSUART_UART) |= (tmp); // set bit if (EMS_Sys_Status.emsTxMode <= 1) { // classic mode and ems+ (0, 1) @@ -188,91 +191,129 @@ void ICACHE_FLASH_ATTR emsuart_tx_brk() { } USC0(EMSUART_UART) &= ~(tmp); // clear bit + GPIO_L(TX_MARK_MASK); } /* * Send to Tx, ending with a */ -void ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) { - if (len == 0) - return; +_EMS_TX_STATUS ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) { + _EMS_TX_STATUS result = EMS_TX_STATUS_OK; + if (len) { + LA_PULSE(50); + // temp code until we get mode 2 working without resets + if (EMS_Sys_Status.emsTxMode == 0) { // classic mode logic + for (uint8_t i = 0; i < len; i++) { + TX_PULSE(EMSUART_BIT_TIME/4); + USF(EMSUART_UART) = buf[i]; + } + emsuart_tx_brk(); // send + } else if (EMS_Sys_Status.emsTxMode == 1) { // With extra tx delay for EMS+ + for (uint8_t i = 0; i < len; i++) { + TX_PULSE(EMSUART_BIT_TIME/4); + USF(EMSUART_UART) = buf[i]; + delayMicroseconds(EMSUART_TX_BRK_WAIT); // https://github.com/proddy/EMS-ESP/issues/23# + } + emsuart_tx_brk(); // send + } else if (EMS_Sys_Status.emsTxMode == 3) { // Junkers logic by @philrich + for (uint8_t i = 0; i < len; i++) { + TX_PULSE(EMSUART_BIT_TIME/4); + USF(EMSUART_UART) = buf[i]; - // temp code until we get mode 2 working without resets + // just to be safe wait for tx fifo empty (needed?) + while (((USS(EMSUART_UART) >> USTXC) & 0xff) != 0) + ; - if (EMS_Sys_Status.emsTxMode == 0) { // classic mode logic - for (uint8_t i = 0; i < len; i++) { - TX_PULSE(EMSUART_BIT_TIME/4); - USF(EMSUART_UART) = buf[i]; - } - emsuart_tx_brk(); // send - } else if (EMS_Sys_Status.emsTxMode == 1) { // With extra tx delay for EMS+ - for (uint8_t i = 0; i < len; i++) { - TX_PULSE(EMSUART_BIT_TIME/4); - USF(EMSUART_UART) = buf[i]; - delayMicroseconds(EMSUART_TX_BRK_WAIT); // https://github.com/proddy/EMS-ESP/issues/23# - } - emsuart_tx_brk(); // send - } else if (EMS_Sys_Status.emsTxMode == 3) { // Junkers logic by @philrich - for (uint8_t i = 0; i < len; i++) { - TX_PULSE(EMSUART_BIT_TIME/4); - USF(EMSUART_UART) = buf[i]; + // wait until bits are sent on wire + delayMicroseconds(EMSUART_TX_WAIT_BYTE - EMSUART_TX_LAG + EMSUART_TX_WAIT_GAP); + } + emsuart_tx_brk(); // send + } else if (EMS_Sys_Status.emsTxMode == 2) { + /* + * based on code from https://github.com/proddy/EMS-ESP/issues/103 by @susisstrolch + * we emit the whole telegram, with Rx interrupt disabled, collecting busmaster response in FIFO. + * after sending the last char we poll the Rx status until either + * - size(Rx FIFO) == size(Tx-Telegram) + * - is detected + * At end of receive we re-enable Rx-INT and send a Tx-BRK in loopback mode. + */ - // just to be safe wait for tx fifo empty (needed?) - while (((USS(EMSUART_UART) >> USTXC) & 0xff) != 0) - ; - - // wait until bits are sent on wire - delayMicroseconds(EMSUART_TX_WAIT_BYTE - EMSUART_TX_LAG + EMSUART_TX_WAIT_GAP); - } - emsuart_tx_brk(); // send - } else if (EMS_Sys_Status.emsTxMode == 2) { /* - * based on code from https://github.com/proddy/EMS-ESP/issues/103 by @susisstrolch - * we emit the whole telegram, with Rx interrupt disabled, collecting busmaster response in FIFO. - * after sending the last char we poll the Rx status until either - * - size(Rx FIFO) == size(Tx-Telegram) - * - is detected - * At end of receive we re-enable Rx-INT and send a Tx-BRK in loopback mode. - */ - ETS_UART_INTR_DISABLE(); // disable rx interrupt + * EMS-Bus error handling + * 1. Busmaster stops echoing on Tx w/o permission + * 2. Busmaster cancel telegram by sending a BRK + * + * Case 1. is handled by a watchdog counter which is reset on each + * Tx attempt. The timeout should be 20x EMSUART_BIT_TIME plus + * some smart guess for processing time on targeted EMS device. + * We set EMS_Sys_Status.emsTxStatus to EMS_TX_WTD_TIMEOUT and return + * + * Case 2. is handled via a BRK chk during transmission. + * We set EMS_Sys_Status.emsTxStatus to EMS_TX_BRK_DETECT and return + * + */ + // shorter busy poll... + #define EMSUART_BUSY_WAIT (EMSUART_BIT_TIME / 8) + #define EMS_TX_TO_COUNT ((20 + 10000 / EMSUART_BIT_TIME) * 8) + uint16_t wdc = EMS_TX_TO_COUNT; - // clear Rx status register - USC0(EMSUART_UART) |= (1 << UCRXRST); // reset uart rx fifo - emsuart_flush_fifos(); + ETS_UART_INTR_DISABLE(); // disable rx interrupt - // throw out the telegram... - for (uint8_t i = 0; i < len;) { - TX_PULSE(EMSUART_BIT_TIME/4); - USF(EMSUART_UART) = buf[i++]; // send each Tx byte - // wait for echo from busmaster - while ((((USS(EMSUART_UART) >> USRXC) & 0xFF) < i || (USIS(EMSUART_UART) & (1 << UIBD)))) { - delayMicroseconds(EMSUART_BIT_TIME); // burn CPU cycles... - } - } + // clear Rx status register + USC0(EMSUART_UART) |= (1 << UCRXRST); // reset uart rx fifo + emsuart_flush_fifos(); - // we got the whole telegram in the Rx buffer - // on Rx-BRK (bus collision), we simply enable Rx and leave it - // otherwise we send the final Tx-BRK in the loopback and re=enable Rx-INT. - // worst case, we'll see an additional Rx-BRK... - if (!(USIS(EMSUART_UART) & (1 << UIBD))) { - TX_PULSE(EMSUART_BIT_TIME/2); - // no bus collision - send terminating BRK signal - USC0(EMSUART_UART) |= (1 << UCLBE); // enable loopback - USC0(EMSUART_UART) |= (1 << UCBRK); // set + // throw out the telegram... + for (uint8_t i = 0; i < len && result == EMS_TX_STATUS_OK;) { + GPIO_H(TX_MARK_MASK); - // wait until BRK detected... - while (!(USIS(EMSUART_UART) & (1 << UIBD))) { - delayMicroseconds(EMSUART_BIT_TIME); + wdc = EMS_TX_TO_COUNT; + volatile uint8_t _usrxc = (USS(EMSUART_UART) >> USRXC) & 0xFF; + USF(EMSUART_UART) = buf[i++]; // send each Tx byte + // wait for echo from busmaster + GPIO_L(TX_MARK_MASK); + + while (((USS(EMSUART_UART) >> USRXC) & 0xFF) == _usrxc) { + delayMicroseconds(EMSUART_BUSY_WAIT); // burn CPU cycles... + if (--wdc == 0) { + EMS_Sys_Status.emsTxStatus = result = EMS_TX_WTD_TIMEOUT; + break; + } + if (USIR(EMSUART_UART) & (1 << UIBD)) { + USIC(EMSUART_UART) = (1 << UIBD); // clear BRK detect IRQ + EMS_Sys_Status.emsTxStatus = result = EMS_TX_BRK_DETECT; + } + } } - USC0(EMSUART_UART) &= ~(1 << UCBRK); // clear + // we got the whole telegram in the Rx buffer + // on Rx-BRK (bus collision), we simply enable Rx and leave it + // otherwise we send the final Tx-BRK in the loopback and re=enable Rx-INT. + // worst case, we'll see an additional Rx-BRK... + if (result != EMS_TX_STATUS_OK) { + LA_PULSE(200); // mark Tx error + } else { + // neither bus collision nor timeout - send terminating BRK signal + GPIO_H(TX_MARK_MASK); + if (!(USIS(EMSUART_UART) & (1 << UIBD))) { - USIC(EMSUART_UART) = (1 << UIBD); // clear BRK detect IRQ - USC0(EMSUART_UART) &= ~(1 << UCLBE); // disable loopback + // no bus collision - send terminating BRK signal + USC0(EMSUART_UART) |= (1 << UCLBE)|(1 << UCBRK); // enable loopback & set + + // wait until BRK detected... + while (!(USIR(EMSUART_UART) & (1 << UIBD))) { + delayMicroseconds(EMSUART_BUSY_WAIT); + } + + USC0(EMSUART_UART) &= ~((1 << UCBRK)|(1 << UCLBE)); // disable loopback & clear + USIC(EMSUART_UART) = (1 << UIBD); // clear BRK detect IRQ + } + GPIO_L(TX_MARK_MASK); + } + ETS_UART_INTR_ENABLE(); // receive anything from FIFO... } - - ETS_UART_INTR_ENABLE(); // receive anything from FIFO... } + return result; } /* diff --git a/src/emsuart.h b/src/emsuart.h index c49e2f6a8..9424ac7cf 100644 --- a/src/emsuart.h +++ b/src/emsuart.h @@ -35,5 +35,5 @@ typedef struct { void ICACHE_FLASH_ATTR emsuart_init(); void ICACHE_FLASH_ATTR emsuart_stop(); void ICACHE_FLASH_ATTR emsuart_start(); -void ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len); +_EMS_TX_STATUS ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len); void ICACHE_FLASH_ATTR emsuart_tx_poll(); diff --git a/src/my_config.h b/src/my_config.h index 20575b25d..f83ff92b9 100644 --- a/src/my_config.h +++ b/src/my_config.h @@ -84,10 +84,15 @@ // can be enabled and disabled via the 'set led' command and pin set by 'set led_gpio' #define EMSESP_LED_GPIO LED_BUILTIN +#ifdef LOGICANALYZER +#define EMSESP_DALLAS_GPIO D1 +#define EMSESP_DALLAS_PARASITE false +#else // set this if using an external temperature sensor like a DS18B20 // D5 is the default on a bbqkees board #define EMSESP_DALLAS_GPIO D5 #define EMSESP_DALLAS_PARASITE false +#endif // By default the EMS bus will be scanned for known devices based on the product ids in ems_devices.h // You can override the Thermostat and Boiler types here From 0a700b945171d929e5d74b1797ee28469330ab54 Mon Sep 17 00:00:00 2001 From: Susis Strolch Date: Fri, 19 Jul 2019 15:46:18 +0200 Subject: [PATCH 69/89] in ems-esp:setup: set GPIO15 to HIGH so we don't disturb the EMS-Bus during boot --- src/ems-esp.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index 06e39a463..9af65f956 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -1811,6 +1811,10 @@ void setup() { INIT_MARKERS(0); LA_PULSE(50); + // GPIO15 has a pull down, so we must set it to HIGH + pinMode(15, OUTPUT); + digitalWrite(15,1); + // init our own parameters initEMSESP(); From a1e7b7f9994d46c898cb167ec84aedb458d3df0a Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 19 Jul 2019 16:12:04 +0200 Subject: [PATCH 70/89] move commands back to PROGMEM --- lib/MyESP/MyESP.cpp | 123 ++++++++++++-------------------------------- lib/MyESP/MyESP.h | 13 +++-- src/ems-esp.cpp | 110 ++++++++++++++++++++++++++++----------- src/version.h | 2 +- 4 files changed, 122 insertions(+), 126 deletions(-) diff --git a/lib/MyESP/MyESP.cpp b/lib/MyESP/MyESP.cpp index 9fd14b039..7e8dd644c 100644 --- a/lib/MyESP/MyESP.cpp +++ b/lib/MyESP/MyESP.cpp @@ -44,9 +44,6 @@ MyESP::MyESP() { _web_callback = NULL; - _helpProjectCmds = NULL; - _helpProjectCmds_count = 0; - _serial = false; _serial_default = false; @@ -250,23 +247,23 @@ void MyESP::_wifiCallback(justwifi_messages_t code, char * parameter) { } if (code == MESSAGE_SCANNING) { - myDebug_P(PSTR("[WIFI] Scanning\n")); + myDebug_P(PSTR("[WIFI] Scanning")); } if (code == MESSAGE_SCAN_FAILED) { - myDebug_P(PSTR("[WIFI] Scan failed\n")); + myDebug_P(PSTR("[WIFI] Scan failed")); } if (code == MESSAGE_NO_NETWORKS) { - myDebug_P(PSTR("[WIFI] No networks found\n")); + myDebug_P(PSTR("[WIFI] No networks found")); } if (code == MESSAGE_NO_KNOWN_NETWORKS) { - myDebug_P(PSTR("[WIFI] No known networks found\n")); + myDebug_P(PSTR("[WIFI] No known networks found")); } if (code == MESSAGE_FOUND_NETWORK) { - myDebug_P(PSTR("[WIFI] %s\n"), parameter); + myDebug_P(PSTR("[WIFI] %s"), parameter); } if (code == MESSAGE_CONNECT_WAITING) { @@ -274,35 +271,11 @@ void MyESP::_wifiCallback(justwifi_messages_t code, char * parameter) { } if (code == MESSAGE_ACCESSPOINT_CREATING) { - myDebug_P(PSTR("[WIFI] Creating access point\n")); + myDebug_P(PSTR("[WIFI] Creating access point")); } if (code == MESSAGE_ACCESSPOINT_FAILED) { - myDebug_P(PSTR("[WIFI] Could not create access point\n")); - } - - if (code == MESSAGE_WPS_START) { - myDebug_P(PSTR("[WIFI] WPS started\n")); - } - - if (code == MESSAGE_WPS_SUCCESS) { - myDebug_P(PSTR("[WIFI] WPS succeeded!\n")); - } - - if (code == MESSAGE_WPS_ERROR) { - myDebug_P(PSTR("[WIFI] WPS failed\n")); - } - - if (code == MESSAGE_SMARTCONFIG_START) { - myDebug_P(PSTR("[WIFI] Smart Config started\n")); - } - - if (code == MESSAGE_SMARTCONFIG_SUCCESS) { - myDebug_P(PSTR("[WIFI] Smart Config succeeded!\n")); - } - - if (code == MESSAGE_SMARTCONFIG_ERROR) { - myDebug_P(PSTR("[WIFI] Smart Config failed\n")); + myDebug_P(PSTR("[WIFI] Could not create access point")); } } @@ -548,9 +521,7 @@ void MyESP::_eeprom_setup() { } // Set callback of sketch function to process project messages -void MyESP::setTelnet(command_t * cmds, uint8_t count, telnetcommand_callback_f callback_cmd, telnet_callback_f callback) { - _helpProjectCmds = cmds; // command list - _helpProjectCmds_count = count; // number of commands +void MyESP::setTelnet(telnetcommand_callback_f callback_cmd, telnet_callback_f callback) { _telnetcommand_callback = callback_cmd; // external function to handle commands _telnet_callback = callback; } @@ -625,27 +596,11 @@ void MyESP::_consoleShowHelp() { myDebug_P(PSTR("* crash ")); #endif - // print custom commands if available. Taken from progmem - if (_telnetcommand_callback) { - // find the longest key length so we can right align it - uint8_t max_len = 0; - for (uint8_t i = 0; i < _helpProjectCmds_count; i++) { - if ((strlen(_helpProjectCmds[i].key) > max_len) && (!_helpProjectCmds[i].set)) { - max_len = strlen(_helpProjectCmds[i].key); - } - } - - for (uint8_t i = 0; i < _helpProjectCmds_count; i++) { - if (!_helpProjectCmds[i].set) { - SerialAndTelnet.print("* "); - SerialAndTelnet.print(_helpProjectCmds[i].key); - for (uint8_t j = 0; j < ((max_len + 5) - strlen(_helpProjectCmds[i].key)); j++) { // account for longest string length - SerialAndTelnet.print(" "); // padding - } - SerialAndTelnet.println(_helpProjectCmds[i].description); - } - } + // call callback function + if (_telnet_callback) { + (_telnet_callback)(TELNET_EVENT_SHOWCMD); } + myDebug_P(PSTR("")); // newline } @@ -654,31 +609,14 @@ void MyESP::_printSetCommands() { myDebug_P(PSTR("")); // newline myDebug_P(PSTR("The following set commands are available:")); myDebug_P(PSTR("")); // newline - myDebug_P(PSTR("* set erase")); - myDebug_P(PSTR("* set [value]")); - myDebug_P(PSTR("* set [value]")); - myDebug_P(PSTR("* set serial ")); + myDebug_P(PSTR(" set erase")); + myDebug_P(PSTR(" set [value]")); + myDebug_P(PSTR(" set [value]")); + myDebug_P(PSTR(" set serial ")); - // print custom commands if available. Taken from progmem - if (_telnetcommand_callback) { - // find the longest key length so we can right align it - uint8_t max_len = 0; - for (uint8_t i = 0; i < _helpProjectCmds_count; i++) { - if ((strlen(_helpProjectCmds[i].key) > max_len) && (_helpProjectCmds[i].set)) { - max_len = strlen(_helpProjectCmds[i].key); - } - } - - for (uint8_t i = 0; i < _helpProjectCmds_count; i++) { - if (_helpProjectCmds[i].set) { - SerialAndTelnet.print(FPSTR("* set ")); - SerialAndTelnet.print(FPSTR(_helpProjectCmds[i].key)); - for (uint8_t j = 0; j < ((max_len + 5) - strlen(_helpProjectCmds[i].key)); j++) { // account for longest string length - SerialAndTelnet.print(FPSTR(" ")); // padding - } - SerialAndTelnet.println(FPSTR(_helpProjectCmds[i].description)); - } - } + // call callback function + if (_telnet_callback) { + (_telnet_callback)(TELNET_EVENT_SHOWSET); } myDebug_P(PSTR("")); // newline @@ -938,7 +876,9 @@ void MyESP::_telnetCommand(char * commandLine) { #endif // call callback function - (_telnetcommand_callback)(wc, commandLine); + if (_telnetcommand_callback) { + (_telnetcommand_callback)(wc, commandLine); + } } // returns WiFi hostname as a String object @@ -1118,7 +1058,6 @@ void MyESP::_setSystemCheck(bool stable) { if (stable) { value = 0; // system is ok - // myDebug_P(PSTR("[SYSTEM] System OK\n")); } else { if (!_getRtcmemStatus()) { _setSystemStabilityCounter(1); @@ -1704,6 +1643,8 @@ void MyESP::_fs_setup() { _firstInstall = true; // flag as a first install } + myDebug_P(PSTR("[FS] Settings loaded from SPIFFS")); + // _fs_printConfig(); // enable for debugging } @@ -2141,7 +2082,7 @@ void MyESP::_webserver_setup() { webServer.begin(); - myDebug_P(PSTR("[WEB] Web server started.")); + myDebug_P(PSTR("[WEB] Web server started")); } // bootup sequence @@ -2182,6 +2123,9 @@ void MyESP::begin(const char * app_hostname, const char * app_name, const char * _telnet_setup(); // Telnet setup, called first to set Serial + // print a welcome message + myDebug_P(PSTR("\n\n* %s version %s"), _app_name, _app_version); + // set up onboard LED pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, HIGH); @@ -2194,19 +2138,16 @@ void MyESP::begin(const char * app_hostname, const char * app_name, const char * _firstInstall = true; // flag as an initial install so the config file will be recreated } - _eeprom_setup(); // set up EEPROM for storing crash data, if compiled with -DCRASH - + _eeprom_setup(); // set up EEPROM for storing crash data, if compiled with -DCRASH _fs_setup(); // SPIFFS setup, do this first to get values _wifi_setup(); // WIFI setup _ota_setup(); // init OTA _webserver_setup(); // init web server - // print a welcome message - myDebug_P(PSTR("\n* %s version %s"), _app_name, _app_version); - SerialAndTelnet.flush(); - _setSystemCheck(false); // reset system check - _heartbeatCheck(true); // force heartbeat + _heartbeatCheck(true); // force heartbeat check (not the MQTT one) + + SerialAndTelnet.flush(); } /* diff --git a/lib/MyESP/MyESP.h b/lib/MyESP/MyESP.h index f04551d2a..d6eedb803 100644 --- a/lib/MyESP/MyESP.h +++ b/lib/MyESP/MyESP.h @@ -9,7 +9,7 @@ #ifndef MyEMS_h #define MyEMS_h -#define MYESP_VERSION "1.1.22" +#define MYESP_VERSION "1.1.23" #include #include @@ -68,6 +68,8 @@ extern struct rst_info resetInfo; #define TELNET_MAX_COMMAND_LENGTH 80 // length of a command #define TELNET_EVENT_CONNECT 1 #define TELNET_EVENT_DISCONNECT 0 +#define TELNET_EVENT_SHOWCMD 10 +#define TELNET_EVENT_SHOWSET 20 // ANSI Colors #define COLOR_RESET "\x1B[0m" @@ -189,6 +191,11 @@ constexpr size_t ArraySize(T (&)[N]) { return N; } +template +void PROGMEM_readAnything(const T * sce, T & dest) { + memcpy_P(&dest, sce, sizeof(T)); +} + #define UPTIME_OVERFLOW 4294967295 // Uptime overflow value // web min and max length of wifi ssid and password @@ -262,7 +269,7 @@ class MyESP { // debug & telnet void myDebug(const char * format, ...); void myDebug_P(PGM_P format_P, ...); - void setTelnet(command_t * cmds, uint8_t count, telnetcommand_callback_f callback_cmd, telnet_callback_f callback); + void setTelnet(telnetcommand_callback_f callback_cmd, telnet_callback_f callback); bool getUseSerial(); void setUseSerial(bool toggle); @@ -346,8 +353,6 @@ class MyESP { char * _telnet_readWord(bool allow_all_chars); void _telnet_setup(); char _command[TELNET_MAX_COMMAND_LENGTH]; // the input command from either Serial or Telnet - command_t * _helpProjectCmds; // Help of commands setted by project - uint8_t _helpProjectCmds_count; // # available commands void _consoleShowHelp(); telnetcommand_callback_f _telnetcommand_callback; // Callable for projects commands telnet_callback_f _telnet_callback; // callback for connect/disconnect diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index ebdef1a65..d1a80600f 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -93,7 +93,7 @@ typedef struct { bool doingColdShot; // true if we've just sent a jolt of cold water } _EMSESP_Shower; -command_t project_cmds[] = { +static const command_t project_cmds[] PROGMEM = { {true, "led ", "toggle status LED on/off"}, {true, "led_gpio ", "set the LED pin. Default is the onboard LED 2. For external D1 use 5"}, @@ -133,6 +133,7 @@ command_t project_cmds[] = { {false, "boiler comfort ", "set boiler warm water comfort setting"} }; +uint8_t _project_cmds_count = ArraySize(project_cmds); // store for overall system status _EMSESP_Status EMSESP_Status; @@ -980,13 +981,13 @@ float _readFloatNumber() { return atof(numTextPtr); } -// used to read the next string from an input buffer as a hex value and convert to an 8 bit int -uint8_t _readHexNumber() { +// used to read the next string from an input buffer as a hex value and convert to a 16 bit int +uint16_t _readHexNumber() { char * numTextPtr = strtok(NULL, ", \n"); if (numTextPtr == nullptr) { return 0; } - return (uint8_t)strtol(numTextPtr, 0, 16); + return (uint16_t)strtol(numTextPtr, 0, 16); } // used to read the next string from an input buffer @@ -1338,6 +1339,40 @@ bool SettingsCallback(MYESP_FSACTION action, uint8_t wc, const char * setting, c return ok; } +// print settings +void _showCommands(uint8_t event) { + bool mode = (event == TELNET_EVENT_SHOWSET); // show set commands or normal commands + command_t cmd; + + // find the longest key length so we can right-align the text + uint8_t max_len = 0; + uint8_t i; + for (i = 0; i < _project_cmds_count; i++) { + memcpy_P(&cmd, &project_cmds[i], sizeof(cmd)); + if ((strlen(cmd.key) > max_len) && (cmd.set == mode)) { + max_len = strlen(cmd.key); + } + } + + char line[200] = {0}; + for (i = 0; i < _project_cmds_count; i++) { + memcpy_P(&cmd, &project_cmds[i], sizeof(cmd)); + if (cmd.set == mode) { + if (event == TELNET_EVENT_SHOWSET) { + strlcpy(line, " set ", sizeof(line)); + } else { + strlcpy(line, "* ", sizeof(line)); + } + strlcat(line, cmd.key, sizeof(line)); + for (uint8_t j = 0; j < ((max_len + 5) - strlen(cmd.key)); j++) { // account for longest string length + strlcat(line, " ", sizeof(line)); // padding + } + strlcat(line, cmd.description, sizeof(line)); + myDebug(line); // print the line + } + } +} + // call back when a telnet client connects or disconnects // we set the logging here void TelnetCallback(uint8_t event) { @@ -1345,6 +1380,8 @@ void TelnetCallback(uint8_t event) { ems_setLogging(EMS_SYS_LOGGING_DEFAULT); } else if (event == TELNET_EVENT_DISCONNECT) { ems_setLogging(EMS_SYS_LOGGING_NONE); + } else if ((event == TELNET_EVENT_SHOWCMD) || (event == TELNET_EVENT_SHOWSET)) { + _showCommands(event); } } @@ -1694,7 +1731,9 @@ void WebCallback(char * body) { void WIFICallback() { // This is where we enable the UART service to scan the incoming serial Tx/Rx bus signals // This is done after we have a WiFi signal to avoid any resource conflicts + system_uart_swap(); // TODO check + /* if (myESP.getUseSerial()) { myDebug_P(PSTR("Warning! EMS bus communication disabled when Serial mode enabled. Use 'set serial off' to start communication.")); } else { @@ -1705,6 +1744,7 @@ void WIFICallback() { ems_discoverModels(); } } + */ } // Initialize the boiler settings and shower settings @@ -1727,6 +1767,9 @@ void initEMSESP() { EMSESP_Shower.timerPause = 0; EMSESP_Shower.duration = 0; EMSESP_Shower.doingColdShot = false; + + // call ems.cpp's init function to set all the internal params + ems_init(); } /* @@ -1799,35 +1842,40 @@ void showerCheck() { // SETUP // void setup() { - // init our own parameters - initEMSESP(); + initEMSESP(); // init parameters - // call ems.cpp's init function to set all the internal params - ems_init(); - - systemCheckTimer.attach(SYSTEMCHECK_TIME, do_systemCheck); // check if EMS is reachable - - // set up myESP for Wifi, MQTT, MDNS and Telnet - myESP.setTelnet(project_cmds, ArraySize(project_cmds), TelnetCommandCallback, TelnetCallback); // set up Telnet commands - myESP.setWIFI(NULL, NULL, WIFICallback); // empty ssid and password as we take this from the config file - - // MQTT host, username and password taken from the SPIFFS settings - myESP.setMQTT( - NULL, NULL, NULL, MQTT_BASE, MQTT_KEEPALIVE, MQTT_QOS, MQTT_RETAIN, MQTT_WILL_TOPIC, MQTT_WILL_ONLINE_PAYLOAD, MQTT_WILL_OFFLINE_PAYLOAD, MQTTCallback); - - // OTA callback which is called when OTA is starting and stopping - myESP.setOTA(OTACallback_pre, OTACallback_post); - - // custom settings in SPIFFS - myESP.setSettings(FSCallback, SettingsCallback); - - // web custom settings - myESP.setWeb(WebCallback); - - // start up all the services - myESP.begin(APP_HOSTNAME, APP_NAME, APP_VERSION); + myESP.setTelnet(TelnetCommandCallback, TelnetCallback); // set up Telnet commands + myESP.setWIFI(NULL, NULL, WIFICallback); // empty ssid and password as we take this from the config file + myESP.setMQTT(NULL, + NULL, + NULL, + MQTT_BASE, + MQTT_KEEPALIVE, + MQTT_QOS, + MQTT_RETAIN, + MQTT_WILL_TOPIC, + MQTT_WILL_ONLINE_PAYLOAD, + MQTT_WILL_OFFLINE_PAYLOAD, + MQTTCallback); // MQTT host, username and password taken from the SPIFFS settings + myESP.setOTA(OTACallback_pre, OTACallback_post); // OTA callback which is called when OTA is starting and stopping + myESP.setSettings(FSCallback, SettingsCallback); // custom settings in SPIFFS + myESP.setWeb(WebCallback); // web custom settings + myESP.begin(APP_HOSTNAME, APP_NAME, APP_VERSION); // start up all the services // at this point we have all the settings from our internall SPIFFS config file + // fire up the UART now + if (myESP.getUseSerial()) { + myDebug_P(PSTR("Warning! EMS bus communication disabled when Serial mode enabled. Use 'set serial off' to start communication.")); + } else { + Serial.println("Note: Serial output will now be disabled. Please use Telnet."); + Serial.flush(); + emsuart_init(); + myDebug_P(PSTR("[UART] Opened Rx/Tx connection")); + if (!EMSESP_Status.listen_mode) { + // go and find the boiler and thermostat types, if not in listen mode + ems_discoverModels(); + } + } // enable regular checks if not in test mode if (!EMSESP_Status.listen_mode) { @@ -1845,6 +1893,8 @@ void setup() { // check for Dallas sensors EMSESP_Status.dallas_sensors = ds18.setup(EMSESP_Status.dallas_gpio, EMSESP_Status.dallas_parasite); // returns #sensors + + systemCheckTimer.attach(SYSTEMCHECK_TIME, do_systemCheck); // check if EMS is reachable } // diff --git a/src/version.h b/src/version.h index c0cec732e..6c7a7827f 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.8.1b19" +#define APP_VERSION "1.8.1b20" #define APP_HOSTNAME "ems-esp" From 0eeb5c882346170e36c60915416c90680ec7508e Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 19 Jul 2019 16:12:28 +0200 Subject: [PATCH 71/89] support ems+ with read comands --- src/ems.cpp | 96 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 58 insertions(+), 38 deletions(-) diff --git a/src/ems.cpp b/src/ems.cpp index 8238c7d1a..ae996911f 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -504,7 +504,7 @@ char * _smallitoa3(uint16_t value, char * buffer) { * Find the pointer to the EMS_Types array for a given type ID * or -1 if not found */ -int _ems_findType(uint8_t type) { +int _ems_findType(uint16_t type) { uint8_t i = 0; bool typeFound = false; // scan through known ID types @@ -545,7 +545,7 @@ void _debugPrintTelegram(const char * prefix, _EMS_RxTelegram * EMS_RxTelegram, strlcat(output_str, prefix, sizeof(output_str)); if (!raw) { - strlcat(output_str, " telegram: ", sizeof(output_str)); + strlcat(output_str, "telegram: ", sizeof(output_str)); } for (int i = 0; i < (length - 1); i++) { @@ -627,19 +627,27 @@ void _ems_sendTelegram() { // for a READ or VALIDATE EMS_TxTelegram.data[1] = EMS_TxTelegram.dest | 0x80; // read has 8th bit set } - EMS_TxTelegram.data[2] = EMS_TxTelegram.type; // type - EMS_TxTelegram.data[3] = EMS_TxTelegram.offset; // offset - // see if it has data, add the single data value byte - // otherwise leave it alone and assume the data has been pre-populated - if (EMS_TxTelegram.length == EMS_MIN_TELEGRAM_LENGTH) { - // for reading this is #bytes we want to read (the size) - // for writing its the value we want to write - EMS_TxTelegram.data[4] = EMS_TxTelegram.dataValue; + // complete the rest of the header depending on EMS or EMS+ + if (EMS_TxTelegram.type > 0xFF) { + // EMS 2.0 / emsplus + EMS_TxTelegram.data[2] = 0xFF; // fixed value indicating an extended message + EMS_TxTelegram.data[3] = EMS_TxTelegram.offset; + EMS_TxTelegram.data[4] = EMS_TxTelegram.dataValue; // for read its #bytes to return, for write it the value to set + EMS_TxTelegram.data[5] = EMS_TxTelegram.type >> 8; // type, 1st byte + EMS_TxTelegram.data[6] = EMS_TxTelegram.type & 0xFF; // type, 2nd byte + EMS_TxTelegram.length += 2; // add 2 bytes to length to compensate the extra FF and byte for the type + } else { + // EMS 1.0 + EMS_TxTelegram.data[2] = EMS_TxTelegram.type; // type + EMS_TxTelegram.data[3] = EMS_TxTelegram.offset; // offset + if (EMS_TxTelegram.length == EMS_MIN_TELEGRAM_LENGTH) { + EMS_TxTelegram.data[4] = EMS_TxTelegram.dataValue; // for read its #bytes to return, for write it the value to set + } } + // finally calculate CRC and add it to the end - uint8_t crc = _crcCalculator(EMS_TxTelegram.data, EMS_TxTelegram.length); - EMS_TxTelegram.data[EMS_TxTelegram.length - 1] = crc; + EMS_TxTelegram.data[EMS_TxTelegram.length - 1] = _crcCalculator(EMS_TxTelegram.data, EMS_TxTelegram.length); // print debug info if (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_VERBOSE) { @@ -843,9 +851,10 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) { */ void _printMessage(_EMS_RxTelegram * EMS_RxTelegram) { // header info - uint8_t src = EMS_RxTelegram->src; - uint8_t dest = EMS_RxTelegram->dest; - uint16_t type = EMS_RxTelegram->type; + uint8_t src = EMS_RxTelegram->src; + uint8_t dest = EMS_RxTelegram->dest; + uint16_t type = EMS_RxTelegram->type; + uint8_t length = EMS_RxTelegram->data_length; char output_str[200] = {0}; char buffer[16] = {0}; @@ -897,16 +906,21 @@ void _printMessage(_EMS_RxTelegram * EMS_RxTelegram) { strlcpy(color_s, COLOR_MAGENTA, sizeof(color_s)); } - // type - strlcat(output_str, ", type 0x", sizeof(output_str)); + if (length != 0) { + // type + strlcat(output_str, ", type 0x", sizeof(output_str)); - if (EMS_RxTelegram->emsplus) { - strlcat(output_str, _hextoa(type >> 8, buffer), sizeof(output_str)); - strlcat(output_str, _hextoa(type & 0xFF, buffer), sizeof(output_str)); - } else { - strlcat(output_str, _hextoa(type, buffer), sizeof(output_str)); + if (EMS_RxTelegram->emsplus) { + strlcat(output_str, _hextoa(type >> 8, buffer), sizeof(output_str)); + strlcat(output_str, _hextoa(type & 0xFF, buffer), sizeof(output_str)); + } else { + strlcat(output_str, _hextoa(type, buffer), sizeof(output_str)); + } } + strlcat(output_str, ", ", sizeof(output_str)); + + if (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_THERMOSTAT) { // only print ones to/from thermostat if logging is set to thermostat only if ((src == EMS_Thermostat.device_id) || (dest == EMS_Thermostat.device_id)) { @@ -1043,21 +1057,27 @@ void _processType(_EMS_RxTelegram * EMS_RxTelegram) { if (((EMS_RxTelegram->src & 0x7F) == (EMS_TxTelegram.dest & 0x7F)) && (EMS_RxTelegram->type == EMS_TxTelegram.type)) { // all checks out, read was successful, remove tx from queue and continue to process telegram _removeTxQueue(); - EMS_Sys_Status.emsRxPgks++; // increment counter + EMS_Sys_Status.emsRxPgks++; // increment Rx happy counter ems_setEmsRefreshed(EMS_TxTelegram.forceRefresh); // does mqtt need refreshing? } else { // read not OK, we didn't get back a telegram we expected - // leave on queue and try again, but continue to process what we received as it may be important - EMS_Sys_Status.txRetryCount++; - // if retried too many times, give up and remove it - if (EMS_Sys_Status.txRetryCount >= TX_WRITE_TIMEOUT_COUNT) { - if (EMS_Sys_Status.emsLogging >= EMS_SYS_LOGGING_BASIC) { - myDebug_P(PSTR("Read failed. Giving up, removing from queue")); - } + + // first see if we got a response back from the sender saying its an unknown command + if (EMS_RxTelegram->data_length == 0) { _removeTxQueue(); } else { - if (EMS_Sys_Status.emsLogging >= EMS_SYS_LOGGING_BASIC) { - myDebug_P(PSTR("Read failed. Retrying attempt %d/%d..."), EMS_Sys_Status.txRetryCount, TX_WRITE_TIMEOUT_COUNT); + // leave on queue and try again, but continue to process what we received as it may be important + EMS_Sys_Status.txRetryCount++; + // if retried too many times, give up and remove it + if (EMS_Sys_Status.txRetryCount >= TX_WRITE_TIMEOUT_COUNT) { + if (EMS_Sys_Status.emsLogging >= EMS_SYS_LOGGING_BASIC) { + myDebug_P(PSTR("Read failed. Giving up, removing from queue")); + } + _removeTxQueue(); + } else { + if (EMS_Sys_Status.emsLogging >= EMS_SYS_LOGGING_BASIC) { + myDebug_P(PSTR("Read failed. Retrying attempt %d/%d..."), EMS_Sys_Status.txRetryCount, TX_WRITE_TIMEOUT_COUNT); + } } } } @@ -1066,7 +1086,7 @@ void _processType(_EMS_RxTelegram * EMS_RxTelegram) { if (EMS_TxTelegram.action == EMS_TX_TELEGRAM_WRITE) { // should not get here, since this is handled earlier receiving a 01 or 04 - myDebug_P(PSTR("** Error ! Write - should not be here")); + myDebug_P(PSTR("** Error! Write - should not be here")); } if (EMS_TxTelegram.action == EMS_TX_TELEGRAM_VALIDATE) { @@ -2280,17 +2300,17 @@ void ems_doReadCommand(uint16_t type, uint8_t dest, bool forceRefresh) { myDebug_P(PSTR("Requesting type %s(0x%02X) from dest 0x%02X"), EMS_Types[i].typeString, type, dest); } } - EMS_TxTelegram.action = EMS_TX_TELEGRAM_READ; // read command - EMS_TxTelegram.dest = dest; // 8th bit will be set to indicate a read - EMS_TxTelegram.offset = 0; // 0 for all data - EMS_TxTelegram.length = EMS_MIN_TELEGRAM_LENGTH; // is always 6 bytes long (including CRC at end) + EMS_TxTelegram.action = EMS_TX_TELEGRAM_READ; // read command + EMS_TxTelegram.dest = dest; // 8th bit will be set to indicate a read + EMS_TxTelegram.offset = 0; // 0 for all data EMS_TxTelegram.type = type; + EMS_TxTelegram.length = EMS_MIN_TELEGRAM_LENGTH; // EMS 1.0: 6 bytes long (including CRC at end), EMS+ will add 2 bytes. includes CRC EMS_TxTelegram.dataValue = EMS_MAX_TELEGRAM_LENGTH; // for a read this is the # bytes we want back EMS_TxTelegram.type_validate = EMS_ID_NONE; EMS_TxTelegram.comparisonValue = 0; EMS_TxTelegram.comparisonOffset = 0; EMS_TxTelegram.comparisonPostRead = EMS_ID_NONE; - EMS_TxTelegram.forceRefresh = forceRefresh; // should we send to MQTT after a successful read? + EMS_TxTelegram.forceRefresh = forceRefresh; // send to MQTT after a successful read EMS_TxQueue.push(EMS_TxTelegram); } From 3ba81d4e7664e5fb5b76409a9402582ccd8dfa86 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 19 Jul 2019 16:12:40 +0200 Subject: [PATCH 72/89] delay uart swap until after wifi connected --- src/emsuart.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/emsuart.cpp b/src/emsuart.cpp index 2b6e166e0..ddd7edb54 100644 --- a/src/emsuart.cpp +++ b/src/emsuart.cpp @@ -138,7 +138,7 @@ void ICACHE_FLASH_ATTR emsuart_init() { system_set_os_print(0); // swap Rx and Tx pins to use GPIO13 (D7) and GPIO15 (D8) respectively - system_uart_swap(); + //system_uart_swap(); ETS_UART_INTR_ATTACH(emsuart_rx_intr_handler, NULL); ETS_UART_INTR_ENABLE(); From 32e189ec671ce68981eed159ba440d11dab09fe0 Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 20 Jul 2019 10:23:26 +0200 Subject: [PATCH 73/89] https://github.com/proddy/EMS-ESP/pull/154 --- src/emsuart.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/emsuart.cpp b/src/emsuart.cpp index 35727a407..d856a7bff 100644 --- a/src/emsuart.cpp +++ b/src/emsuart.cpp @@ -251,7 +251,7 @@ _EMS_TX_STATUS ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) { * We set EMS_Sys_Status.emsTxStatus to EMS_TX_BRK_DETECT and return * */ - + // shorter busy poll... #define EMSUART_BUSY_WAIT (EMSUART_BIT_TIME / 8) #define EMS_TX_TO_COUNT ((20 + 10000 / EMSUART_BIT_TIME) * 8) From 3fdd086160458aac4c8f97dde1e6d819f5996b46 Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 22 Jul 2019 20:06:22 +0200 Subject: [PATCH 74/89] https://github.com/proddy/EMS-ESP/issues/156 --- src/ems-esp.cpp | 123 ++++++++++++++++++++++-------------------------- src/ems.cpp | 5 +- src/version.h | 2 +- 3 files changed, 58 insertions(+), 72 deletions(-) diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index a95f8ed7f..6a0c5e2d4 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -371,6 +371,38 @@ void _renderBoolValue(const char * prefix, uint8_t value) { myDebug(buffer); } +// figures out the thermostat mode +// returns 0xFF=unknown, 0=low, 1=manual, 2=auto, 3=night, 4=day +uint8_t _getThermostatMode() { + int thermoMode = EMS_VALUE_INT_NOTSET; + + if (ems_getThermostatModel() == EMS_MODEL_RC20) { + if (EMS_Thermostat.mode == 0) { + thermoMode = 0; // low + } else if (EMS_Thermostat.mode == 1) { + thermoMode = 1; // manual + } else if (EMS_Thermostat.mode == 2) { + thermoMode = 2; // auto + } + } else if (ems_getThermostatModel() == EMS_MODEL_RC300) { + if (EMS_Thermostat.mode == 0) { + thermoMode = 1; // manual + } else if (EMS_Thermostat.mode == 1) { + thermoMode = 2; // auto + } + } else { // default for all thermostats + if (EMS_Thermostat.mode == 0) { + thermoMode = 3; // night + } else if (EMS_Thermostat.mode == 1) { + thermoMode = 4; // day + } else if (EMS_Thermostat.mode == 2) { + thermoMode = 2; // auto + } + } + + return thermoMode; +} + // Show command - display stats on an 's' command void showInfo() { // General stats from EMS bus @@ -550,7 +582,7 @@ void showInfo() { myDebug_P(PSTR(" Thermostat: %s"), ems_getThermostatDescription(buffer_type)); // Render Current & Setpoint Room Temperature - if ((ems_getThermostatModel() == EMS_MODEL_EASY)) { + if (ems_getThermostatModel() == EMS_MODEL_EASY) { // Temperatures are *100 _renderShortValue("Set room temperature", "C", EMS_Thermostat.setpoint_roomTemp, 10); // *100 _renderShortValue("Current room temperature", "C", EMS_Thermostat.curr_roomTemp, 10); // *100 @@ -572,42 +604,20 @@ void showInfo() { } // Render Thermostat Date & Time - myDebug_P(PSTR(" Thermostat time is %02d:%02d:%02d %d/%d/%d"), - EMS_Thermostat.hour, - EMS_Thermostat.minute, - EMS_Thermostat.second, - EMS_Thermostat.day, - EMS_Thermostat.month, - EMS_Thermostat.year + 2000); - - // thermostat mode (-1=unknown, 0=low, 1=manual, 2=auto, 3=night, 4=day) - int thermoMode = -1; - - if (ems_getThermostatModel() == EMS_MODEL_RC20) { - if (EMS_Thermostat.mode == 0) { - thermoMode = 0; // low - } else if (EMS_Thermostat.mode == 1) { - thermoMode = 1; // manual - } else { - thermoMode = 2; // auto - } - } else if (ems_getThermostatModel() == EMS_MODEL_RC300) { - if (EMS_Thermostat.mode == 0) { - thermoMode = 1; // manual - } else if (EMS_Thermostat.mode == 1) { - thermoMode = 2; // auto - } - } else { // default for all thermostats - if (EMS_Thermostat.mode == 0) { - thermoMode = 3; // night - } else if (EMS_Thermostat.mode == 1) { - thermoMode = 4; // day - } else { - thermoMode = 2; // auto - } + // not for EASY + if ((ems_getThermostatModel() != EMS_MODEL_EASY)) { + myDebug_P(PSTR(" Thermostat time is %02d:%02d:%02d %d/%d/%d"), + EMS_Thermostat.hour, + EMS_Thermostat.minute, + EMS_Thermostat.second, + EMS_Thermostat.day, + EMS_Thermostat.month, + EMS_Thermostat.year + 2000); } - // Render Termostat Mode + // Render Termostat Mode, if we have a mode + uint8_t thermoMode = _getThermostatMode(); // 0xFF=unknown, 0=low, 1=manual, 2=auto, 3=night, 4=day + if (thermoMode == 0) { myDebug_P(PSTR(" Mode is set to low")); } else if (thermoMode == 1) { @@ -618,8 +628,6 @@ void showInfo() { myDebug_P(PSTR(" Mode is set to night")); } else if (thermoMode == 4) { myDebug_P(PSTR(" Mode is set to day")); - } else { - myDebug_P(PSTR(" Mode is set to ?")); } } @@ -801,12 +809,16 @@ void publishValues(bool force) { rootThermostat[THERMOSTAT_HC] = _int_to_char(s, EMSESP_Status.heating_circuit); // different logic depending on thermostat types - if ((ems_getThermostatModel() == EMS_MODEL_EASY) || (ems_getThermostatModel() == EMS_MODEL_FR10) || (ems_getThermostatModel() == EMS_MODEL_FW100)) { + if (ems_getThermostatModel() == EMS_MODEL_EASY) { + if (EMS_Thermostat.setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET) + rootThermostat[THERMOSTAT_SELTEMP] = (double)EMS_Thermostat.setpoint_roomTemp / 100; + if (EMS_Thermostat.curr_roomTemp != EMS_VALUE_SHORT_NOTSET) + rootThermostat[THERMOSTAT_CURRTEMP] = (double)EMS_Thermostat.curr_roomTemp / 100; + } else if ((ems_getThermostatModel() == EMS_MODEL_FR10) || (ems_getThermostatModel() == EMS_MODEL_FW100)) { if (EMS_Thermostat.setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET) rootThermostat[THERMOSTAT_SELTEMP] = (double)EMS_Thermostat.setpoint_roomTemp / 10; if (EMS_Thermostat.curr_roomTemp != EMS_VALUE_SHORT_NOTSET) rootThermostat[THERMOSTAT_CURRTEMP] = (double)EMS_Thermostat.curr_roomTemp / 10; - } else { if (EMS_Thermostat.setpoint_roomTemp != EMS_VALUE_SHORT_NOTSET) rootThermostat[THERMOSTAT_SELTEMP] = (double)EMS_Thermostat.setpoint_roomTemp / 2; @@ -827,32 +839,7 @@ void publishValues(bool force) { rootThermostat[THERMOSTAT_CIRCUITCALCTEMP] = EMS_Thermostat.circuitcalctemp; } - // thermostat mode (-1=unknown, 0=low, 1=manual, 2=auto, 3=night, 4=day) - int thermoMode = -1; - - if (ems_getThermostatModel() == EMS_MODEL_RC20) { - if (EMS_Thermostat.mode == 0) { - thermoMode = 0; // low - } else if (EMS_Thermostat.mode == 1) { - thermoMode = 1; // manual - } else { - thermoMode = 2; // auto - } - } else if (ems_getThermostatModel() == EMS_MODEL_RC300) { - if (EMS_Thermostat.mode == 0) { - thermoMode = 1; // manual - } else if (EMS_Thermostat.mode == 1) { - thermoMode = 2; // auto - } - } else { // default for all thermostats - if (EMS_Thermostat.mode == 0) { - thermoMode = 3; // night - } else if (EMS_Thermostat.mode == 1) { - thermoMode = 4; // day - } else { - thermoMode = 2; // auto - } - } + uint8_t thermoMode = _getThermostatMode(); // 0xFF=unknown, 0=low, 1=manual, 2=auto, 3=night, 4=day // Termostat Mode if (thermoMode == 0) { @@ -1854,9 +1841,9 @@ void setup() { INIT_MARKERS(0); LA_PULSE(50); - // GPIO15 has a pull down, so we must set it to HIGH + // GPIO15 has a pull down, so we must set it to HIGH pinMode(15, OUTPUT); - digitalWrite(15,1); + digitalWrite(15, 1); // init our own parameters initEMSESP(); @@ -1868,7 +1855,7 @@ void setup() { // set up myESP for Wifi, MQTT, MDNS and Telnet myESP.setTelnet(TelnetCommandCallback, TelnetCallback); // set up Telnet commands - myESP.setWIFI(NULL, NULL, WIFICallback); // empty ssid and password as we take this from the config file + myESP.setWIFI(NULL, NULL, WIFICallback); // empty ssid and password as we take this from the config file // MQTT host, username and password taken from the SPIFFS settings myESP.setMQTT( diff --git a/src/ems.cpp b/src/ems.cpp index 68d0e2ff3..45d723786 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -220,7 +220,6 @@ const uint32_t EMS_BUS_TIMEOUT = 15000; // timeout in ms before recogni const uint32_t EMS_POLL_TIMEOUT = 5000000; // timeout in microseconds before recognizing the ems bus is offline (5 seconds) // init stats and counters and buffers -// uses -255 or 255 for values that haven't been set yet (EMS_VALUE_INT_NOTSET and EMS_VALUE_FLOAT_NOTSET) void ems_init() { // overall status EMS_Sys_Status.emsRxPgks = 0; @@ -248,8 +247,8 @@ void ems_init() { EMS_Thermostat.day = 0; EMS_Thermostat.month = 0; EMS_Thermostat.year = 0; - EMS_Thermostat.mode = 255; // dummy value - EMS_Thermostat.day_mode = 255; // dummy value + EMS_Thermostat.mode = EMS_VALUE_INT_NOTSET; + EMS_Thermostat.day_mode = EMS_VALUE_INT_NOTSET; EMS_Thermostat.device_id = EMS_ID_NONE; EMS_Thermostat.write_supported = false; EMS_Thermostat.hc = 1; // default heating circuit is 1 diff --git a/src/version.h b/src/version.h index 69c10001e..3151ef23c 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.8.1b21" +#define APP_VERSION "1.8.1b22" #define APP_HOSTNAME "ems-esp" From cac7bfae31104411fc679d8c05c20f41cb6a9065 Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 25 Jul 2019 10:30:34 +0200 Subject: [PATCH 75/89] force serial off --- lib/MyESP/MyESP.cpp | 20 ++++++++------------ lib/MyESP/MyESP.h | 1 - platformio.ini-example | 2 +- src/ems.cpp | 2 +- 4 files changed, 10 insertions(+), 15 deletions(-) diff --git a/lib/MyESP/MyESP.cpp b/lib/MyESP/MyESP.cpp index 8e68bd862..853b4b381 100644 --- a/lib/MyESP/MyESP.cpp +++ b/lib/MyESP/MyESP.cpp @@ -44,8 +44,7 @@ MyESP::MyESP() { _web_callback = NULL; - _serial = false; - _serial_default = false; + _serial = false; _heartbeat = false; _mqtt_host = NULL; @@ -560,13 +559,6 @@ void MyESP::_telnet_setup() { SerialAndTelnet.setDebugOutput(false); SerialAndTelnet.begin(TELNET_SERIAL_BAUD); // default baud is 115200 -// serial is only on when booting -#ifdef DEFAULT_NO_SERIAL - _serial_default = false; -#else - _serial_default = true; -#endif - // init command buffer for console commands memset(_command, 0, TELNET_MAX_COMMAND_LENGTH); } @@ -790,7 +782,7 @@ bool MyESP::_changeSetting(uint8_t wc, const char * setting, const char * value) // force the serial on/off void MyESP::setUseSerial(bool b) { - _serial_default = _serial = b; + _serial = b; SerialAndTelnet.setSerial(b ? &Serial : NULL); } @@ -1549,10 +1541,14 @@ bool MyESP::_fs_loadConfig() { value = json["mqtt_password"]; _mqtt_password = (value) ? strdup(value) : NULL; - _serial = json["serial"] | _serial_default; - _heartbeat = (bool)json["heartbeat"]; // defaults to off +// serial is only on when booting +#ifdef FORCE_SERIAL + _serial_ = true; +#else + _serial = json["serial"]; +#endif // callback for loading custom settings // ok is false if there's a problem loading a custom setting (e.g. does not exist) diff --git a/lib/MyESP/MyESP.h b/lib/MyESP/MyESP.h index d6eedb803..d4d5f4573 100644 --- a/lib/MyESP/MyESP.h +++ b/lib/MyESP/MyESP.h @@ -379,7 +379,6 @@ class MyESP { char * _boottime; bool _suspendOutput; bool _serial; - bool _serial_default; bool _heartbeat; unsigned long _getUptime(); String _buildTime(); diff --git a/platformio.ini-example b/platformio.ini-example index c99ece822..3293cefdb 100644 --- a/platformio.ini-example +++ b/platformio.ini-example @@ -7,7 +7,7 @@ default_envs = debug [common] -; -DMYESP_TIMESTAMP -DTESTS -DCRASH -DNO_SERIAL -DNO_GLOBAL_EEPROM -DLOGICANALYZER +; -DMYESP_TIMESTAMP -DTESTS -DCRASH -DFORCE_SERIAL -DNO_GLOBAL_EEPROM -DLOGICANALYZER extra_flags = -DNO_GLOBAL_EEPROM [env] diff --git a/src/ems.cpp b/src/ems.cpp index 45d723786..a217ddb25 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -2747,6 +2747,6 @@ void ems_testTelegram(uint8_t test_num) { // go an parse it ems_parseTelegram(telegram, length + 1); // include CRC in length #else - myDebug_P(PSTR("Firmware not compiled with test data set")); + myDebug_P(PSTR("Firmware not compiled with test data. Use -DTESTS")); #endif } From a7065cd24b519f7367e202b1468b31f50fef61c8 Mon Sep 17 00:00:00 2001 From: Paul Date: Thu, 25 Jul 2019 10:31:33 +0200 Subject: [PATCH 76/89] serial default typo fix --- lib/MyESP/MyESP.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/MyESP/MyESP.cpp b/lib/MyESP/MyESP.cpp index 853b4b381..7a4d21cca 100644 --- a/lib/MyESP/MyESP.cpp +++ b/lib/MyESP/MyESP.cpp @@ -1545,7 +1545,7 @@ bool MyESP::_fs_loadConfig() { // serial is only on when booting #ifdef FORCE_SERIAL - _serial_ = true; + _serial = true; #else _serial = json["serial"]; #endif From 99b3125201e72777cb36f1d4dc48f165ab05d8a7 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 26 Jul 2019 12:44:55 +0200 Subject: [PATCH 77/89] bump --- src/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h b/src/version.h index 3151ef23c..f7beee713 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.8.1b22" +#define APP_VERSION "1.8.1b23" #define APP_HOSTNAME "ems-esp" From 367c73d8fe1d86632a5ff32bac90ae6709727c47 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 26 Jul 2019 12:45:41 +0200 Subject: [PATCH 78/89] room temps for RC10 also 2-byte shorts --- src/ems.cpp | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/ems.cpp b/src/ems.cpp index a217ddb25..74a19893d 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -412,6 +412,10 @@ void ems_setTxDisabled(bool b) { EMS_Sys_Status.emsTxDisabled = b; } +bool ems_getTxDisabled() { + return (EMS_Sys_Status.emsTxDisabled); +} + uint32_t ems_getPollFrequency() { return EMS_Sys_Status.emsPollFrequency; } @@ -723,13 +727,7 @@ void _createValidate() { * When a telegram is processed we forcefully erase it from the stack to prevent overflow */ void ems_parseTelegram(uint8_t * telegram, uint8_t length) { - // create the Rx package - static _EMS_RxTelegram EMS_RxTelegram; - static uint32_t _last_emsPollFrequency = 0; - - EMS_RxTelegram.telegram = telegram; - EMS_RxTelegram.timestamp = millis(); - EMS_RxTelegram.length = length; + static uint32_t _last_emsPollFrequency = 0; /* * check if we just received a single byte @@ -744,7 +742,7 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) { * buffer isn't valid anymore, so we must not answer at all... */ if (EMS_Sys_Status.emsRxStatus != EMS_RX_STATUS_IDLE) { - myDebug_P(PSTR("** We missed the bus - Rx non-idle!")); + myDebug_P(PSTR("** We missed the bus - Rx non-idle!")); //TODO tidy up error logging return; } @@ -796,7 +794,11 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) { return; } - // fill in the rest of the telegram + static _EMS_RxTelegram EMS_RxTelegram; // create the Rx package + EMS_RxTelegram.telegram = telegram; + EMS_RxTelegram.timestamp = millis(); + EMS_RxTelegram.length = length; + EMS_RxTelegram.src = telegram[0] & 0x7F; // removing 8th bit as we deal with both reads and writes here EMS_RxTelegram.dest = telegram[1] & 0x7F; // remove 8th bit (don't care if read or write) EMS_RxTelegram.offset = telegram[3]; // offset is always 4th byte @@ -834,6 +836,12 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) { EMS_RxTelegram.data_length = length - 5; // remove 4 bytes header plus CRC } + // if we are in raw logging mode then just print out the telegram as it is + // but still continue to process it + if (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_RAW) { + _debugPrintTelegram("", &EMS_RxTelegram, COLOR_WHITE, true); + } + // Assume at this point we have something that vaguely resembles a telegram in the format [src] [dest] [type] [offset] [data] [crc] // validate the CRC, if it's bad ignore it if (telegram[length - 1] != _crcCalculator(telegram, length)) { @@ -845,12 +853,6 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) { return; } - // if we are in raw logging mode then just print out the telegram as it is - // but still continue to process it - if (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_RAW) { - _debugPrintTelegram("", &EMS_RxTelegram, COLOR_WHITE, true); - } - // here we know its a valid incoming telegram of at least 6 bytes // we use this to see if we always have a connection to the boiler, in case of drop outs EMS_Sys_Status.emsRxTimestamp = EMS_RxTelegram.timestamp; // timestamp of last read @@ -1260,7 +1262,7 @@ void _process_UBAMonitorSlow(_EMS_RxTelegram * EMS_RxTelegram) { */ void _process_RC10StatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { EMS_Thermostat.setpoint_roomTemp = _toByte(EMS_OFFSET_RC10StatusMessage_setpoint); // is * 2 - EMS_Thermostat.curr_roomTemp = _toByte(EMS_OFFSET_RC10StatusMessage_curr); // is * 10 + EMS_Thermostat.curr_roomTemp = _toShort(EMS_OFFSET_RC10StatusMessage_curr); // is * 10 EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT } From 93c51ad2701e8e001caaa2a19e5f61ea23928419 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 26 Jul 2019 12:45:49 +0200 Subject: [PATCH 79/89] ignore bins --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b1ecb8047..07cb21044 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ platformio.ini lib/readme.txt .travis.yml scripts/stackdmp.txt +*.bin From eb3cd7da014f95e082ae07f67755d7a1e433a46d Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 26 Jul 2019 12:46:11 +0200 Subject: [PATCH 80/89] added ems_getTxDisabled() --- src/ems-esp.cpp | 9 +++--- src/ems.h | 77 +++++++++++++++++++++++++++-------------------- src/ems_devices.h | 2 +- src/emsuart.h | 2 +- 4 files changed, 52 insertions(+), 38 deletions(-) diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index 6a0c5e2d4..075c2bef9 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -106,7 +106,7 @@ static const command_t project_cmds[] PROGMEM = { {true, "shower_alert ", "stop hot water to send 3 cold burst warnings after max shower time is exceeded"}, {true, "publish_time ", "set frequency for publishing data to MQTT (0=off)"}, {true, "heating_circuit <1 | 2>", "set the main thermostat HC to work with (if using multiple heating circuits)"}, - {true, "tx_mode ", "0=classic ems logic, 1=@kwertie01 ems+ logic, 2=@susisstrolch logic, 3=@philrich logic for Junkers"}, + {true, "tx_mode ", "changes Tx logic. 0=ems 1.0, 1=ems+, 2=generic (experimental!), 3=HT3"}, {false, "info", "show current captured on the devices"}, {false, "log ", "set logging mode to none, basic, thermostat only, raw or verbose"}, @@ -141,7 +141,7 @@ _EMSESP_Shower EMSESP_Shower; // logging messages with fixed strings void myDebugLog(const char * s) { - if (ems_getLogging() >= EMS_SYS_LOGGING_BASIC) { + if (ems_getLogging() != EMS_SYS_LOGGING_NONE) { myDebug(s); } } @@ -1038,11 +1038,13 @@ void do_systemCheck() { // force calls to get data from EMS for the types that aren't sent as broadcasts // only if we have a EMS connection void do_regularUpdates() { - if (ems_getBusConnected()) { + if (ems_getBusConnected() & !ems_getTxDisabled()) { myDebugLog("Requesting scheduled EMS device data"); ems_getThermostatValues(); ems_getBoilerValues(); ems_getSolarModuleValues(); + } else { + myDebugLog("System is either not connect to the EMS bus or listen_mode is enabled"); } } @@ -1398,7 +1400,6 @@ void TelnetCommandCallback(uint8_t wc, const char * commandLine) { } if (strcmp(first_cmd, "refresh") == 0) { - myDebug_P(PSTR("Fetching data from EMS devices...")); do_regularUpdates(); ok = true; } diff --git a/src/ems.h b/src/ems.h index 406714a05..0d9be5b30 100644 --- a/src/ems.h +++ b/src/ems.h @@ -18,42 +18,54 @@ * ° for Tx, we use GPIO12 */ #ifdef LOGICANALYZER - #define RX_MARK_PIN 14 - #define TX_MARK_PIN 12 +#define RX_MARK_PIN 14 +#define TX_MARK_PIN 12 - #define RX_MARK_MASK (1< Date: Fri, 26 Jul 2019 12:50:04 +0200 Subject: [PATCH 81/89] updated to b23 --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d5716abcb..7a7e00041 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [1.8.1dev] 2019-07-19 +## [1.8.1dev] 2019-07-26 ### Added @@ -14,7 +14,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - reset firmware option. If the reset button on the ESP is pressed during boot up sequence (the LED is flashing very fast) all settings are erased and goes into AP mode. - Added tx_mode back with options 0,1 and 2 until we've fixed option 2 that works for everyone and doesn't reset ESP - More solar module data captured, thanks to @Vuego123 -- -DDEFAULT_NO_SERIAL option added to determine if the Serial port should be enabled on fresh installs - Detect thermostat mode for EMS+ RC300/Moduline 3000 ### Fixed @@ -23,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Bosch Easy Connect wrongly classified as a thermostat - Correctly handle telegrams who's size are exactly 32 bytes (e.g. 0x19 MonitorSlow) - Telnet also available when in AP mode +- Handling of thermostat temperatures that were single bytes and couldn't exceed 25.5 (0xFF) degrees! ### Changed @@ -31,6 +31,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - How signed shorts are handled such as the current and setpoint temps on RC300s - Stopped automatic refresh of web page, which causes crashes/memory loss after a short time - Support HA 0.96 climate component changes +- -DDEFAULT_NO_SERIAL changed to -DFORCE_SERIAL ## [1.8.0] 2019-06-15 From 05a11f7c3138a5b3550c7110f137f0c82d7247ea Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 26 Jul 2019 12:52:00 +0200 Subject: [PATCH 82/89] typo --- src/ems-esp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index 075c2bef9..c75b5f57f 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -1038,7 +1038,7 @@ void do_systemCheck() { // force calls to get data from EMS for the types that aren't sent as broadcasts // only if we have a EMS connection void do_regularUpdates() { - if (ems_getBusConnected() & !ems_getTxDisabled()) { + if (ems_getBusConnected() && !ems_getTxDisabled()) { myDebugLog("Requesting scheduled EMS device data"); ems_getThermostatValues(); ems_getBoilerValues(); From d2a129e5c82c501b3af24bdb27a642c5704b5867 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 26 Jul 2019 13:00:23 +0200 Subject: [PATCH 83/89] https://github.com/proddy/EMS-ESP/issues/152 --- lib/MyESP/MyESP.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/MyESP/MyESP.cpp b/lib/MyESP/MyESP.cpp index 7a4d21cca..6d0077954 100644 --- a/lib/MyESP/MyESP.cpp +++ b/lib/MyESP/MyESP.cpp @@ -212,7 +212,7 @@ void MyESP::_wifiCallback(justwifi_messages_t code, char * parameter) { if (code == MESSAGE_ACCESSPOINT_CREATED) { _wifi_connected = true; - myDebug_P(PSTR("[WIFI] MODE AP --------------------------------------")); + myDebug_P(PSTR("[WIFI] MODE AP")); myDebug_P(PSTR("[WIFI] SSID %s"), jw.getAPSSID().c_str()); myDebug_P(PSTR("[WIFI] IP %s"), WiFi.softAPIP().toString().c_str()); myDebug_P(PSTR("[WIFI] MAC %s"), WiFi.softAPmacAddress().c_str()); @@ -1061,13 +1061,15 @@ void MyESP::_setSystemCheck(bool stable) { if (++value > SYSTEM_CHECK_MAX) { _systemStable = false; value = 0; // system is unstable - myDebug_P(PSTR("[SYSTEM] Warning, system UNSTABLE. Serial mode is enabled.")); + myDebug_P(PSTR("[SYSTEM] Warning, system UNSTABLE.")); + /* // enable Serial again if (!_serial) { SerialAndTelnet.setSerial(&Serial); _serial = true; } + */ } } From caad7c8173b64b9534da73e99af62fbd30e9c285 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 26 Jul 2019 15:16:26 +0200 Subject: [PATCH 84/89] EMS_MAXBUFFERSIZE set to 34 for 2 additional BRKs --- src/emsuart.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/emsuart.h b/src/emsuart.h index 67f2edaa9..0777dcfd5 100644 --- a/src/emsuart.h +++ b/src/emsuart.h @@ -14,8 +14,8 @@ #define EMSUART_CONFIG 0x1C // 8N1 (8 bits, no stop bits, 1 parity) #define EMSUART_BAUD 9600 // uart baud rate for the EMS circuit -#define EMS_MAXBUFFERS 5 // buffers for circular filling to avoid collisions -#define EMS_MAXBUFFERSIZE 33 // max size of the buffer. EMS packets are max 32 bytes, plus 1 for BRK +#define EMS_MAXBUFFERS 5 // buffers for circular filling to avoid collisions +#define EMS_MAXBUFFERSIZE (EMS_MAX_TELEGRAM_LENGTH + 2) // max size of the buffer. EMS packets are max 32 bytes, plus extra 2 for BRKs #define EMSUART_BIT_TIME 104 // bit time @9600 baud From 93ac421d2fc1abfaa622edbe6a47d5e899341af6 Mon Sep 17 00:00:00 2001 From: Paul Date: Fri, 26 Jul 2019 15:19:29 +0200 Subject: [PATCH 85/89] added clang-format around code sections to prevent defines getting screwed with autoformat --- src/ems.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ems.h b/src/ems.h index 0d9be5b30..800577200 100644 --- a/src/ems.h +++ b/src/ems.h @@ -17,6 +17,7 @@ * ° for Rx, we use GPIO14 * ° for Tx, we use GPIO12 */ +// clang-format off #ifdef LOGICANALYZER #define RX_MARK_PIN 14 #define TX_MARK_PIN 12 @@ -67,6 +68,7 @@ #define GPIO_H(mask) #define GPIO_L(mask) #endif +// clang-format on #define EMS_ID_NONE 0x00 // used as a dest in broadcast messages and empty device IDs @@ -83,7 +85,6 @@ #define EMS_PRODUCTID_SM100 163 // ProductID for SM10 solar module #define EMS_PRODUCTID_ISM1 101 // ProductID for SM10 solar module - #define EMS_MIN_TELEGRAM_LENGTH 6 // minimal length for a validation telegram, including CRC // max length of a telegram, including CRC, for Rx and Tx. From 6c32c562f4b8477a13c72e591c99a9322f9c2e60 Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 27 Jul 2019 09:44:26 +0200 Subject: [PATCH 86/89] 1.8.1b24 --- CHANGELOG.md | 4 +++- src/version.h | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a7e00041..4e81e9f93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [1.8.1dev] 2019-07-26 +## [1.8.1dev] 2019-07-27 ### Added @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added tx_mode back with options 0,1 and 2 until we've fixed option 2 that works for everyone and doesn't reset ESP - More solar module data captured, thanks to @Vuego123 - Detect thermostat mode for EMS+ RC300/Moduline 3000 +- MQTT message to set boiler flowtemp (`boiler_cmd_flowtemp`). See [wiki](https://github.com/proddy/EMS-ESP/wiki/MQTT). ### Fixed @@ -32,6 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Stopped automatic refresh of web page, which causes crashes/memory loss after a short time - Support HA 0.96 climate component changes - -DDEFAULT_NO_SERIAL changed to -DFORCE_SERIAL +- some code cleanups, removing NULLS and moving some things fron heap to stack to prevent memory fragmentation ## [1.8.0] 2019-06-15 diff --git a/src/version.h b/src/version.h index f7beee713..742cca2da 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.8.1b23" +#define APP_VERSION "1.8.1b24" #define APP_HOSTNAME "ems-esp" From 33bd95c07829752471733b52f2a93ff04b60ec00 Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 27 Jul 2019 09:45:18 +0200 Subject: [PATCH 87/89] replace NULLs with nullptr to be C++11 friendly --- lib/MyESP/MyESP.h | 6 +++--- src/ds18.cpp | 2 +- src/ems.cpp | 10 +++++----- src/emsuart.cpp | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/MyESP/MyESP.h b/lib/MyESP/MyESP.h index d4d5f4573..74dcc2a4a 100644 --- a/lib/MyESP/MyESP.h +++ b/lib/MyESP/MyESP.h @@ -6,10 +6,10 @@ #pragma once -#ifndef MyEMS_h -#define MyEMS_h +#ifndef MyESP_h +#define MyESP_h -#define MYESP_VERSION "1.1.23" +#define MYESP_VERSION "1.1.24" #include #include diff --git a/src/ds18.cpp b/src/ds18.cpp index 547eb88cd..37aa6540b 100644 --- a/src/ds18.cpp +++ b/src/ds18.cpp @@ -11,7 +11,7 @@ std::vector _devices; DS18::DS18() { - _wire = NULL; + _wire = nullptr; _count = 0; _gpio = GPIO_NONE; _parasite = 0; diff --git a/src/ems.cpp b/src/ems.cpp index 74a19893d..e6b58833c 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -117,7 +117,7 @@ const _EMS_Type EMS_Types[] = { {EMS_MODEL_UBA, EMS_TYPE_UBAMonitorWWMessage, "UBAMonitorWWMessage", _process_UBAMonitorWWMessage}, {EMS_MODEL_UBA, EMS_TYPE_UBAParameterWW, "UBAParameterWW", _process_UBAParameterWW}, {EMS_MODEL_UBA, EMS_TYPE_UBATotalUptimeMessage, "UBATotalUptimeMessage", _process_UBATotalUptimeMessage}, - {EMS_MODEL_UBA, EMS_TYPE_UBAMaintenanceSettingsMessage, "UBAMaintenanceSettingsMessage", NULL}, + {EMS_MODEL_UBA, EMS_TYPE_UBAMaintenanceSettingsMessage, "UBAMaintenanceSettingsMessage", nullptr}, {EMS_MODEL_UBA, EMS_TYPE_UBAParametersMessage, "UBAParametersMessage", _process_UBAParametersMessage}, {EMS_MODEL_UBA, EMS_TYPE_UBASetPoints, "UBASetPoints", _process_SetPoints}, @@ -742,7 +742,7 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) { * buffer isn't valid anymore, so we must not answer at all... */ if (EMS_Sys_Status.emsRxStatus != EMS_RX_STATUS_IDLE) { - myDebug_P(PSTR("** We missed the bus - Rx non-idle!")); //TODO tidy up error logging + myDebug_P(PSTR("** [DEBUG MODE] We missed the bus - Rx non-idle!")); //TODO tidy up error logging return; } @@ -992,7 +992,7 @@ void _ems_processTelegram(_EMS_RxTelegram * EMS_RxTelegram) { // if it's a common type (across ems devices) or something specifically for us process it. // dest will be EMS_ID_NONE and offset 0x00 for a broadcast message if (typeFound) { - if ((EMS_Types[i].processType_cb) != (void *)NULL) { + if ((EMS_Types[i].processType_cb) != nullptr) { // print non-verbose message if ((EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_BASIC) || (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_VERBOSE)) { myDebug_P(PSTR("<--- %s(0x%02X)"), EMS_Types[i].typeString, type); @@ -2355,7 +2355,7 @@ void ems_sendRawTelegram(char * telegram) { } // and interate until end while (p != 0) { - if ((p = strtok(NULL, " ,"))) { + if ((p = strtok(nullptr, " ,"))) { strlcpy(value, p, sizeof(value)); uint8_t val = (uint8_t)strtol(value, 0, 16); EMS_TxTelegram.data[++count] = val; @@ -2734,7 +2734,7 @@ void ems_testTelegram(uint8_t test_num) { // and interate until end while (p != 0) { - if ((p = strtok(NULL, " ,"))) { + if ((p = strtok(nullptr, " ,"))) { strlcpy(value, p, sizeof(value)); uint8_t val = (uint8_t)strtol(value, 0, 16); telegram[++length] = val; diff --git a/src/emsuart.cpp b/src/emsuart.cpp index d856a7bff..a701d25c3 100644 --- a/src/emsuart.cpp +++ b/src/emsuart.cpp @@ -95,7 +95,7 @@ static inline void ICACHE_FLASH_ATTR emsuart_flush_fifos() { */ void ICACHE_FLASH_ATTR emsuart_init() { ETS_UART_INTR_DISABLE(); - ETS_UART_INTR_ATTACH(NULL, NULL); + ETS_UART_INTR_ATTACH(nullptr, nullptr); // allocate and preset EMS Receive buffers for (int i = 0; i < EMS_MAXBUFFERS; i++) { @@ -144,7 +144,7 @@ void ICACHE_FLASH_ATTR emsuart_init() { // swap Rx and Tx pins to use GPIO13 (D7) and GPIO15 (D8) respectively //system_uart_swap(); - ETS_UART_INTR_ATTACH(emsuart_rx_intr_handler, NULL); + ETS_UART_INTR_ATTACH(emsuart_rx_intr_handler, nullptr); ETS_UART_INTR_ENABLE(); } From 6baa16667ec07893ef73c9d7cd4082abb10e8358 Mon Sep 17 00:00:00 2001 From: Paul Date: Sat, 27 Jul 2019 09:45:38 +0200 Subject: [PATCH 88/89] added MQTT "home/ems-esp/boiler_cmd_flowtemp" --- src/ems-esp.cpp | 24 ++++++++++++++++-------- src/ems_devices.h | 1 - src/my_config.h | 13 +++++++------ 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index c75b5f57f..5733a8367 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -257,7 +257,7 @@ void _renderShortValue(const char * prefix, const char * postfix, int16_t value, strlcat(buffer, _short_to_char(s, value, decimals), sizeof(buffer)); - if (postfix != NULL) { + if (postfix != nullptr) { strlcat(buffer, " ", sizeof(buffer)); strlcat(buffer, postfix, sizeof(buffer)); } @@ -276,7 +276,7 @@ void _renderUShortValue(const char * prefix, const char * postfix, uint16_t valu strlcat(buffer, _ushort_to_char(s, value, decimals), sizeof(buffer)); - if (postfix != NULL) { + if (postfix != nullptr) { strlcat(buffer, " ", sizeof(buffer)); strlcat(buffer, postfix, sizeof(buffer)); } @@ -328,7 +328,7 @@ void _renderIntValue(const char * prefix, const char * postfix, uint8_t value, u strlcat(buffer, _int_to_char(s, value, div), sizeof(buffer)); - if (postfix != NULL) { + if (postfix != nullptr) { strlcat(buffer, " ", sizeof(buffer)); strlcat(buffer, postfix, sizeof(buffer)); } @@ -350,7 +350,7 @@ void _renderLongValue(const char * prefix, const char * postfix, uint32_t value) strlcat(buffer, ltoa(value, s, 10), sizeof(buffer)); } - if (postfix != NULL) { + if (postfix != nullptr) { strlcat(buffer, " ", sizeof(buffer)); strlcat(buffer, postfix, sizeof(buffer)); } @@ -960,7 +960,7 @@ void set_showerAlert() { // used to read the next string from an input buffer and convert to an 8 bit int uint8_t _readIntNumber() { - char * numTextPtr = strtok(NULL, ", \n"); + char * numTextPtr = strtok(nullptr, ", \n"); if (numTextPtr == nullptr) { return 0; } @@ -969,7 +969,7 @@ uint8_t _readIntNumber() { // used to read the next string from an input buffer and convert to a double float _readFloatNumber() { - char * numTextPtr = strtok(NULL, ", \n"); + char * numTextPtr = strtok(nullptr, ", \n"); if (numTextPtr == nullptr) { return 0; } @@ -978,7 +978,7 @@ float _readFloatNumber() { // used to read the next string from an input buffer as a hex value and convert to a 16 bit int uint16_t _readHexNumber() { - char * numTextPtr = strtok(NULL, ", \n"); + char * numTextPtr = strtok(nullptr, ", \n"); if (numTextPtr == nullptr) { return 0; } @@ -987,7 +987,7 @@ uint16_t _readHexNumber() { // used to read the next string from an input buffer char * _readWord() { - char * word = strtok(NULL, ", \n"); + char * word = strtok(nullptr, ", \n"); return word; } @@ -1563,6 +1563,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) { myESP.mqttSubscribe(TOPIC_BOILER_WWACTIVATED); myESP.mqttSubscribe(TOPIC_BOILER_CMD_WWTEMP); myESP.mqttSubscribe(TOPIC_BOILER_CMD_COMFORT); + myESP.mqttSubscribe(TOPIC_BOILER_CMD_FLOWTEMP); myESP.mqttSubscribe(TOPIC_SHOWER_TIMER); myESP.mqttSubscribe(TOPIC_SHOWER_ALERT); myESP.mqttSubscribe(TOPIC_SHOWER_COLDSHOT); @@ -1662,6 +1663,13 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) { } } + // boiler flowtemp setting + if (strcmp(topic, TOPIC_BOILER_CMD_FLOWTEMP) == 0) { + uint8_t t = atoi((char *)message); + myDebug_P(PSTR("MQTT topic: boiler flowtemp value %d"), t); + ems_setFlowTemp(t); + } + // shower timer if (strcmp(topic, TOPIC_SHOWER_TIMER) == 0) { if (message[0] == '1') { diff --git a/src/ems_devices.h b/src/ems_devices.h index 81ce39a8b..f33a1c88a 100644 --- a/src/ems_devices.h +++ b/src/ems_devices.h @@ -183,7 +183,6 @@ const _SolarModule_Type SolarModule_Types[] = { }; - // Other EMS devices which are not considered boilers, thermostats or solar modules // format is PRODUCT ID, DEVICE ID, DESCRIPTION const _Other_Type Other_Types[] = { diff --git a/src/my_config.h b/src/my_config.h index f83ff92b9..1dc9c16b4 100644 --- a/src/my_config.h +++ b/src/my_config.h @@ -41,12 +41,13 @@ #define THERMOSTAT_CIRCUITCALCTEMP "thermostat_circuitcalctemp" // RC35 specific // MQTT for boiler -#define TOPIC_BOILER_DATA "boiler_data" // for sending boiler values to MQTT -#define TOPIC_BOILER_TAPWATER_ACTIVE "tapwater_active" // if hot tap water is running -#define TOPIC_BOILER_HEATING_ACTIVE "heating_active" // if heating is on -#define TOPIC_BOILER_WWACTIVATED "wwactivated" // for receiving MQTT message to change water on/off -#define TOPIC_BOILER_CMD_WWTEMP "boiler_cmd_wwtemp" // for received boiler wwtemp changes via MQTT -#define TOPIC_BOILER_CMD_COMFORT "boiler_cmd_comfort" // for received boiler ww comfort setting via MQTT +#define TOPIC_BOILER_DATA "boiler_data" // for sending boiler values to MQTT +#define TOPIC_BOILER_TAPWATER_ACTIVE "tapwater_active" // if hot tap water is running +#define TOPIC_BOILER_HEATING_ACTIVE "heating_active" // if heating is on +#define TOPIC_BOILER_WWACTIVATED "wwactivated" // for receiving MQTT message to change water on/off +#define TOPIC_BOILER_CMD_WWTEMP "boiler_cmd_wwtemp" // for received boiler wwtemp changes via MQTT +#define TOPIC_BOILER_CMD_COMFORT "boiler_cmd_comfort" // for received boiler ww comfort setting via MQTT +#define TOPIC_BOILER_CMD_FLOWTEMP "boiler_cmd_flowtemp" // for received boiler flowtemp value via MQTT // MQTT for SM10/SM100 Solar Module #define TOPIC_SM_DATA "sm_data" // topic name From f2b3c7b2d7f85c07ae177b916a896693d11db3ba Mon Sep 17 00:00:00 2001 From: Paul Date: Sun, 28 Jul 2019 20:23:13 +0200 Subject: [PATCH 89/89] onlyh show missed bus if logging is enabled --- src/ems.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ems.cpp b/src/ems.cpp index e6b58833c..b33c6c597 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -742,7 +742,9 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) { * buffer isn't valid anymore, so we must not answer at all... */ if (EMS_Sys_Status.emsRxStatus != EMS_RX_STATUS_IDLE) { - myDebug_P(PSTR("** [DEBUG MODE] We missed the bus - Rx non-idle!")); //TODO tidy up error logging + if (EMS_Sys_Status.emsLogging > EMS_SYS_LOGGING_NONE) { + myDebug_P(PSTR("** [DEBUG MODE] We missed the bus - Rx non-idle!")); //TODO tidy up error logging + } return; }