diff --git a/CHANGELOG.md b/CHANGELOG.md index 35df4f9c2..6df4f4787 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,11 +5,11 @@ 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.7.0 dev] 2019-03- +## [1.6.1 dev] 2019-03- ### Added -- EMS Plus support +- Buderus Logamax plus ## [1.6.0] 2019-03-24 diff --git a/lib/MyESP/MyESP.cpp b/lib/MyESP/MyESP.cpp index 0072d3822..ed852d840 100644 --- a/lib/MyESP/MyESP.cpp +++ b/lib/MyESP/MyESP.cpp @@ -155,8 +155,6 @@ void MyESP::_wifiCallback(justwifi_messages_t code, char * parameter) { // finally if we don't want Serial anymore, turn it off if (!_use_serial) { myDebug_P(PSTR("Disabling serial port")); - Serial.flush(); - Serial.end(); SerialAndTelnet.setSerial(NULL); } else { myDebug_P(PSTR("Using serial port output")); @@ -679,6 +677,19 @@ bool MyESP::_changeSetting(uint8_t wc, const char * setting, const char * value) return ok; } +// force the serial on/off +void MyESP::setUseSerial(bool toggle) { + //(void)fs_saveConfig(); // save the setting for next reboot + + if (toggle) { + SerialAndTelnet.setSerial(&Serial); + _use_serial = true; + } else { + SerialAndTelnet.setSerial(NULL); + _use_serial = false; + } +} + void MyESP::_telnetCommand(char * commandLine) { char * str = commandLine; bool state = false; @@ -792,14 +803,14 @@ String MyESP::_buildTime() { } // returns system uptime in seconds - copied for espurna. see (c) -unsigned long MyESP::_getUptime() { - static unsigned long last_uptime = 0; +uint32_t MyESP::_getUptime() { + static uint32_t last_uptime = 0; static unsigned char uptime_overflows = 0; if (millis() < last_uptime) ++uptime_overflows; - last_uptime = millis(); - unsigned long uptime_seconds = uptime_overflows * (UPTIME_OVERFLOW / 1000) + (last_uptime / 1000); + last_uptime = millis(); + uint32_t uptime_seconds = uptime_overflows * (UPTIME_OVERFLOW / 1000) + (last_uptime / 1000); return uptime_seconds; } @@ -884,9 +895,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); myDebug_P(PSTR(" [MEM] Free Heap: %d"), ESP.getFreeHeap()); -#if defined(ESP8266) - myDebug_P(PSTR(" [MEM] Stack: %d"), ESP.getFreeContStack()); -#endif + myDebug_P(PSTR("")); } @@ -1019,8 +1028,8 @@ void MyESP::setMQTT(const char * mqtt_host, const char * mqtt_username, const char * mqtt_password, const char * mqtt_base, - unsigned long mqtt_keepalive, - unsigned char mqtt_qos, + uint32_t mqtt_keepalive, + uint8_t mqtt_qos, bool mqtt_retain, const char * mqtt_will_topic, const char * mqtt_will_online_payload, @@ -1155,7 +1164,7 @@ bool MyESP::_fs_loadConfig() { // Deserialize the JSON document DeserializationError error = deserializeJson(doc, configFile); if (error) { - Serial.println(F("[FS] Failed to read file")); + myDebug_P(PSTR("[FS] Failed to read config file")); return false; } @@ -1264,13 +1273,13 @@ uint16_t MyESP::getSystemLoadAverage() { // calculate load average void MyESP::_calculateLoad() { - static unsigned long last_loadcheck = 0; - static unsigned long load_counter_temp = 0; + static uint32_t last_loadcheck = 0; + static uint32_t load_counter_temp = 0; load_counter_temp++; if (millis() - last_loadcheck > LOADAVG_INTERVAL) { - static unsigned long load_counter = 0; - static unsigned long load_counter_max = 1; + static uint32_t load_counter = 0; + static uint32_t load_counter_max = 1; load_counter = load_counter_temp; load_counter_temp = 0; @@ -1478,7 +1487,7 @@ void MyESP::begin(const char * app_hostname, const char * app_name, const char * _eeprom_setup(); // set up eeprom for storing crash data _fs_setup(); // SPIFFS setup, do this first to get values _wifi_setup(); // WIFI setup - _ota_setup(); + _ota_setup(); // init OTA } /* @@ -1490,12 +1499,10 @@ void MyESP::loop() { jw.loop(); // WiFi - /* // do nothing else until we've got a wifi connection if (WiFi.getMode() & WIFI_AP) { return; } - */ ArduinoOTA.handle(); // OTA _mqttConnect(); // MQTT diff --git a/lib/MyESP/MyESP.h b/lib/MyESP/MyESP.h index 9e76ed77a..fc7a7a7c5 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.6" +#define MYESP_VERSION "1.1.7" #include #include @@ -50,7 +50,6 @@ void custom_crash_callback(struct rst_info *, uint32_t, uint32_t); #define MQTT_RECONNECT_DELAY_MIN 2000 // Try to reconnect in 3 seconds upon disconnection #define MQTT_RECONNECT_DELAY_STEP 3000 // Increase the reconnect delay in 3 seconds after each failed attempt #define MQTT_RECONNECT_DELAY_MAX 120000 // Set reconnect time to 2 minutes at most -#define MQTT_MAX_SIZE 600 // max length of MQTT message #define MQTT_MAX_TOPIC_SIZE 50 // max length of MQTT message // Internal MQTT events @@ -155,7 +154,7 @@ class MyESP { const char * mqtt_username, const char * mqtt_password, const char * mqtt_base, - unsigned long mqtt_keepalive, + uint32_t mqtt_keepalive, unsigned char mqtt_qos, bool mqtt_retain, const char * mqtt_will_topic, @@ -171,6 +170,7 @@ class MyESP { void myDebug_P(PGM_P format_P, ...); void setTelnet(command_t * cmds, uint8_t count, telnetcommand_callback_f callback_cmd, telnet_callback_f callback); bool getUseSerial(); + void setUseSerial(bool toggle); // FS void setSettings(fs_callback_f callback, fs_settings_callback_f fs_settings_callback); @@ -195,7 +195,7 @@ class MyESP { private: // mqtt AsyncMqttClient mqttClient; - unsigned long _mqtt_reconnect_delay; + uint32_t _mqtt_reconnect_delay; void _mqttOnMessage(char * topic, char * payload, size_t len); void _mqttConnect(); void _mqtt_setup(); @@ -207,14 +207,14 @@ class MyESP { char * _mqtt_username; char * _mqtt_password; char * _mqtt_base; - unsigned long _mqtt_keepalive; - unsigned char _mqtt_qos; + uint32_t _mqtt_keepalive; + uint8_t _mqtt_qos; bool _mqtt_retain; char * _mqtt_will_topic; char * _mqtt_will_online_payload; char * _mqtt_will_offline_payload; char * _mqtt_topic; - unsigned long _mqtt_last_connection; + uint32_t _mqtt_last_connection; bool _mqtt_connecting; // wifi @@ -264,14 +264,14 @@ class MyESP { void _printSetCommands(); // general - char * _app_hostname; - char * _app_name; - char * _app_version; - char * _boottime; - bool _suspendOutput; - bool _use_serial; - unsigned long _getUptime(); - String _buildTime(); + char * _app_hostname; + char * _app_name; + char * _app_version; + char * _boottime; + bool _suspendOutput; + bool _use_serial; + uint32_t _getUptime(); + String _buildTime(); // load average (0..100) void _calculateLoad(); diff --git a/lib/TelnetSpy/TelnetSpy.cpp b/lib/TelnetSpy/TelnetSpy.cpp index ea1762fa4..482a0fa97 100644 --- a/lib/TelnetSpy/TelnetSpy.cpp +++ b/lib/TelnetSpy/TelnetSpy.cpp @@ -343,9 +343,11 @@ void TelnetSpy::flush(void) { #ifdef ESP8266 void TelnetSpy::begin(unsigned long baud, SerialConfig config, SerialMode mode, uint8_t tx_pin) { + if (usedSer) { usedSer->begin(baud, config, mode, tx_pin); } + started = true; } @@ -433,6 +435,7 @@ TelnetSpy::operator bool() const { } void TelnetSpy::setDebugOutput(bool en) { + debugOutput = en; // TODO: figure out how to disable system printing for the ESP32 diff --git a/src/ds18.cpp b/src/ds18.cpp index 6a827970f..547eb88cd 100644 --- a/src/ds18.cpp +++ b/src/ds18.cpp @@ -50,7 +50,7 @@ uint8_t DS18::setup(uint8_t gpio, bool parasite) { // scan every 2 seconds void DS18::loop() { - static unsigned long last = 0; + static uint32_t last = 0; if (millis() - last < DS18_READ_INTERVAL) return; last = millis(); diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index b03ef638b..bf683b5fd 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -63,8 +63,8 @@ Ticker showerColdShotStopTimer; #define SHOWER_MAX_DURATION 420000 // in ms. 7 minutes, before trigger a shot of cold water typedef struct { - unsigned long timestamp; // for internal timings, via millis() - uint8_t dallas_sensors; // count of dallas sensors + uint32_t timestamp; // for internal timings, via millis() + uint8_t dallas_sensors; // count of dallas sensors // custom params bool shower_timer; // true if we want to report back on shower times @@ -78,11 +78,11 @@ typedef struct { } _EMSESP_Status; typedef struct { - bool showerOn; - unsigned long timerStart; // ms - unsigned long timerPause; // ms - unsigned long duration; // ms - bool doingColdShot; // true if we've just sent a jolt of cold water + bool showerOn; + uint32_t timerStart; // ms + uint32_t timerPause; // ms + uint32_t duration; // ms + bool doingColdShot; // true if we've just sent a jolt of cold water } _EMSESP_Shower; command_t PROGMEM project_cmds[] = { @@ -312,7 +312,9 @@ void showInfo() { } myDebug(" LED is %s, Silent mode is %s", EMSESP_Status.led ? "on" : "off", EMSESP_Status.silent_mode ? "on" : "off"); - myDebug(" %d external temperature sensor%s connected", EMSESP_Status.dallas_sensors, (EMSESP_Status.dallas_sensors > 1) ? "s" : ""); + if (EMSESP_Status.dallas_sensors > 0) { + myDebug(" %d external temperature sensor%s connected", EMSESP_Status.dallas_sensors, (EMSESP_Status.dallas_sensors == 1) ? "" : "s"); + } myDebug(" Thermostat is %s, Boiler is %s, Shower Timer is %s, Shower Alert is %s", (ems_getThermostatEnabled() ? "enabled" : "disabled"), @@ -321,12 +323,23 @@ void showInfo() { ((EMSESP_Status.shower_alert) ? "enabled" : "disabled")); myDebug("\n%sEMS Bus stats:%s", COLOR_BOLD_ON, COLOR_BOLD_OFF); - myDebug(" Bus Connected=%s, Tx is %s, # Rx telegrams=%d, # Tx telegrams=%d, # Crc Errors=%d", - (ems_getBusConnected() ? "yes" : "no"), - (ems_getTxCapable() ? "active" : "not active"), - EMS_Sys_Status.emsRxPgks, - EMS_Sys_Status.emsTxPkgs, - EMS_Sys_Status.emxCrcErr); + + if (ems_getBusConnected()) { + myDebug(" Bus is connected"); + + myDebug(" Rx: Poll=%d ms, # Rx telegrams read=%d, # Crc Errors=%d", + ems_getPollFrequency(), + EMS_Sys_Status.emsRxPgks, + EMS_Sys_Status.emxCrcErr); + + if (ems_getTxCapable()) { + myDebug(" Tx: available, # Tx telegrams sent=%d", EMS_Sys_Status.emsTxPkgs); + } else { + myDebug(" Tx: no signal"); + } + } else { + myDebug(" No connection can be made to the EMS bus"); + } myDebug(""); myDebug("%sBoiler stats:%s", COLOR_BOLD_ON, COLOR_BOLD_OFF); @@ -493,8 +506,8 @@ void showInfo() { // send all dallas sensor values as a JSON package to MQTT void publishSensorValues() { - StaticJsonDocument doc; - JsonObject sensors = doc.to(); + StaticJsonDocument<200> doc; + JsonObject sensors = doc.to(); bool hasdata = false; char label[8] = {0}; @@ -511,7 +524,7 @@ void publishSensorValues() { } if (hasdata) { - char data[MQTT_MAX_SIZE] = {0}; + char data[200] = {0}; serializeJson(doc, data, sizeof(data)); myESP.mqttPublish(TOPIC_EXTERNAL_SENSORS, data); } diff --git a/src/ems.cpp b/src/ems.cpp index 2e640915c..5425f6d63 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -157,9 +157,9 @@ const uint8_t ems_crc_table[] = {0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0xCD, 0xCF, 0xC1, 0xC3, 0xC5, 0xC7, 0xF9, 0xFB, 0xFD, 0xFF, 0xF1, 0xF3, 0xF5, 0xF7, 0xE9, 0xEB, 0xED, 0xEF, 0xE1, 0xE3, 0xE5, 0xE7}; -const uint8_t TX_WRITE_TIMEOUT_COUNT = 2; // 3 retries before timeout -const unsigned long EMS_BUS_TIMEOUT = 15000; // timeout in ms before recognizing the ems bus is offline (15 seconds) -const unsigned long EMS_POLL_TIMEOUT = 5000; // timeout in ms before recognizing the ems bus is offline (5 seconds) +const uint8_t TX_WRITE_TIMEOUT_COUNT = 2; // 3 retries before timeout +const uint32_t EMS_BUS_TIMEOUT = 15000; // timeout in ms before recognizing the ems bus is offline (15 seconds) +const uint32_t EMS_POLL_TIMEOUT = 5000; // timeout in ms 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) @@ -176,7 +176,7 @@ void ems_init() { EMS_Sys_Status.emsRxTimestamp = 0; EMS_Sys_Status.emsTxCapable = false; EMS_Sys_Status.emsTxDisabled = false; - EMS_Sys_Status.emsPollTimestamp = 0; + EMS_Sys_Status.emsPollFrequency = 0; EMS_Sys_Status.txRetryCount = 0; // thermostat @@ -302,8 +302,12 @@ void ems_setTxDisabled(bool b) { EMS_Sys_Status.emsTxDisabled = b; } +uint32_t ems_getPollFrequency() { + return EMS_Sys_Status.emsPollFrequency; +} + bool ems_getTxCapable() { - if ((millis() - EMS_Sys_Status.emsPollTimestamp) > EMS_POLL_TIMEOUT) { + if ((EMS_Sys_Status.emsPollFrequency == 0) || (EMS_Sys_Status.emsPollFrequency > EMS_POLL_TIMEOUT)) { EMS_Sys_Status.emsTxCapable = false; } return EMS_Sys_Status.emsTxCapable; @@ -577,7 +581,6 @@ void _createValidate() { EMS_TxQueue.unshift(new_EMS_TxTelegram); // add back to queue making it first to be picked up next (FIFO) } - /* * Entry point triggered by an interrupt in emsuart.cpp * length is only data bytes, excluding the BRK @@ -588,9 +591,9 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) { if ((length != 0) && (telegram[0] != 0x00)) { _ems_readTelegram(telegram, length); } - // now clear the Rx buffer just be safe and prevent duplicates - for (uint8_t i = 0; i < EMS_MAXBUFFERSIZE; telegram[i++] = 0x00) - ; + + // clear the Rx buffer just be safe and prevent duplicates + memset(telegram, 0, EMS_MAXBUFFERSIZE); } /** @@ -600,9 +603,10 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) { void _ems_readTelegram(uint8_t * telegram, uint8_t length) { // create the Rx package static _EMS_RxTelegram EMS_RxTelegram; - EMS_RxTelegram.length = length; - EMS_RxTelegram.telegram = telegram; - EMS_RxTelegram.timestamp = millis(); + static uint32_t _last_emsPollFrequency = 0; + EMS_RxTelegram.length = length; + EMS_RxTelegram.telegram = telegram; + EMS_RxTelegram.timestamp = millis(); // 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) @@ -610,10 +614,12 @@ void _ems_readTelegram(uint8_t * telegram, uint8_t length) { if (length == 1) { uint8_t value = telegram[0]; // 1st byte of data package + EMS_Sys_Status.emsPollFrequency = (EMS_RxTelegram.timestamp - _last_emsPollFrequency); + _last_emsPollFrequency = EMS_RxTelegram.timestamp; + // check first for a Poll for us if (value == (EMS_ID_ME | 0x80)) { - EMS_Sys_Status.emsPollTimestamp = EMS_RxTelegram.timestamp; // store when we received a last poll - EMS_Sys_Status.emsTxCapable = true; + EMS_Sys_Status.emsTxCapable = true; // do we have something to send thats waiting in the Tx queue? // if so send it if the Queue is not in a wait state @@ -1396,8 +1402,8 @@ void ems_printTxQueue() { strlcpy(sType, "?", sizeof(sType)); } - char addedTime[15] = {0}; - unsigned long upt = EMS_TxTelegram.timestamp; + char addedTime[15] = {0}; + uint32_t upt = EMS_TxTelegram.timestamp; snprintf(addedTime, sizeof(addedTime), "(%02d:%02d:%02d)", diff --git a/src/ems.h b/src/ems.h index e1e97f33a..73551e1cc 100644 --- a/src/ems.h +++ b/src/ems.h @@ -89,8 +89,8 @@ typedef struct { _EMS_SYS_LOGGING emsLogging; // logging bool emsRefreshed; // fresh data, needs to be pushed out to MQTT bool emsBusConnected; // is there an active bus - unsigned long emsRxTimestamp; // timestamp of last EMS message received - unsigned long emsPollTimestamp; // timestamp of last EMS poll sent to us + uint32_t emsRxTimestamp; // timestamp of last EMS message received + uint32_t emsPollFrequency; // time between EMS polls bool emsTxCapable; // able to send via Tx bool emsTxDisabled; // true to prevent all Tx uint8_t txRetryCount; // # times the last Tx was re-sent @@ -109,7 +109,7 @@ typedef struct { uint8_t comparisonOffset; // offset of where the byte is we want to compare too later uint8_t comparisonPostRead; // after a successful write call this to read bool forceRefresh; // should we send to MQTT after a successful Tx? - unsigned long timestamp; // when created + uint32_t timestamp; // when created uint8_t data[EMS_MAX_TELEGRAM_LENGTH]; } _EMS_TxTelegram; @@ -120,7 +120,6 @@ typedef struct { uint8_t length; // length in bytes } _EMS_RxTelegram; - // default empty Tx const _EMS_TxTelegram EMS_TX_TELEGRAM_NEW = { EMS_TX_TELEGRAM_INIT, // action @@ -297,6 +296,7 @@ bool ems_getEmsRefreshed(); uint8_t ems_getThermostatModel(); void ems_discoverModels(); bool ems_getTxCapable(); +uint32_t ems_getPollFrequency(); void ems_scanDevices(); void ems_printAllTypes(); diff --git a/src/ems_devices.h b/src/ems_devices.h index e959895a0..e3cda412c 100644 --- a/src/ems_devices.h +++ b/src/ems_devices.h @@ -122,6 +122,7 @@ const _Boiler_Type Boiler_Types[] = { {EMS_MODEL_UBA, 123, 0x08, "Buderus GB172/Nefit Trendline"}, {EMS_MODEL_UBA, 115, 0x08, "Nefit Topline Compact"}, {EMS_MODEL_UBA, 203, 0x08, "Buderus Logamax U122"}, + {EMS_MODEL_UBA, 208, 0x08, "Buderus Logamax plus"}, {EMS_MODEL_UBA, 64, 0x08, "Sieger BK15 Boiler/Nefit Smartline"}, {EMS_MODEL_UBA, 95, 0x08, "Bosch Condens 2500"} diff --git a/src/emsuart.cpp b/src/emsuart.cpp index 65b479b0b..4815d3d03 100644 --- a/src/emsuart.cpp +++ b/src/emsuart.cpp @@ -177,6 +177,7 @@ void ICACHE_FLASH_ATTR emsuart_tx_brk() { void ICACHE_FLASH_ATTR emsuart_tx_buffer(uint8_t * buf, uint8_t len) { for (uint8_t i = 0; i < len; i++) { USF(EMSUART_UART) = buf[i]; + //delayMicroseconds(EMS_TX_BRK_WAIT); } emsuart_tx_brk(); } diff --git a/src/my_config.h b/src/my_config.h index 8f55c891f..0cc8fb30a 100644 --- a/src/my_config.h +++ b/src/my_config.h @@ -22,6 +22,7 @@ #define MQTT_RETAIN false #define MQTT_KEEPALIVE 120 // 2 minutes #define MQTT_QOS 1 +#define MQTT_MAX_SIZE 700 // max size of a JSON object. See https://arduinojson.org/v6/assistant/ // MQTT for thermostat #define TOPIC_THERMOSTAT_DATA "thermostat_data" // for sending thermostat values to MQTT diff --git a/src/version.h b/src/version.h index 69498c119..11aef61d0 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.7.0b1" +#define APP_VERSION "1.6.1b1" #define APP_HOSTNAME "ems-esp"