From fbb3a46b8524852519b67e81a19e58473bcba884 Mon Sep 17 00:00:00 2001 From: proddy Date: Fri, 3 May 2019 12:47:25 +0200 Subject: [PATCH] EMS+ updates --- CHANGELOG.md | 9 +++--- src/ems-esp.cpp | 10 +++---- src/ems.cpp | 75 ++++++++++++++++++++++++++--------------------- src/ems.h | 7 ++--- src/ems_devices.h | 2 +- src/test_data.h | 29 ++++++++++++++++++ src/unit_tests.h | 28 ------------------ 7 files changed, 84 insertions(+), 76 deletions(-) create mode 100644 src/test_data.h delete mode 100644 src/unit_tests.h diff --git a/CHANGELOG.md b/CHANGELOG.md index 7eb359eab..79b97e079 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.7.0 dev] 2019-04-17 +## [1.7.0 dev] 2019-05 ### Added @@ -15,16 +15,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Support for multiple thermostat heating circuits like the HC1/HC2 on a RC35, also via MQTT (thanks @lobocobra) - `boiler flowtemp` command to set the flow temperature [(issue 59)](https://github.com/proddy/EMS-ESP/issues/59) - `tx_delay` setting for circuits where we needed to slow down Tx transmission -- nefit proline hrc 24 cw4 thermostat -- support for Buderus RC300 and RC310 thermostats [(issue 37)](https://github.com/proddy/EMS-ESP/issues/37) +- new boiler: Nefit proline hrc 24 cw4 thermostat +- new thermostats: Buderus RC300 and RC310 thermostats [(issue 37)](https://github.com/proddy/EMS-ESP/issues/37) - added a test harness to try out response to various telegrams -- EMS_ID_GATEWAY for Buderus Web Gateway KM200 +- new devices: Buderus Web Gateway KM200, Solar Module SM100 ### Changed - `types` renamed to `devices` to also show all detected devices - EMS Plus logic optimized - `silent_mode` to `listen_mode` +- increased Tx queue to 100 ## [1.6.0] 2019-03-24 diff --git a/src/ems-esp.cpp b/src/ems-esp.cpp index 8553077f1..3d818d118 100644 --- a/src/ems-esp.cpp +++ b/src/ems-esp.cpp @@ -57,7 +57,7 @@ uint8_t scanThermostat_count = 0; // ems bus scan Ticker scanDevices; -#define SCANDEVICES_TIME 250 // ms +#define SCANDEVICES_TIME 350 // ms uint8_t scanDevices_count; Ticker showerColdShotStopTimer; @@ -324,7 +324,7 @@ void showInfo() { myDebug(" System logging set to None"); } - myDebug(" LED is %s, Silent mode is %s", EMSESP_Status.led ? "on" : "off", EMSESP_Status.listen_mode ? "on" : "off"); + myDebug(" LED is %s, Listen mode is %s", EMSESP_Status.led ? "on" : "off", EMSESP_Status.listen_mode ? "on" : "off"); if (EMSESP_Status.dallas_sensors > 0) { myDebug(" %d external temperature sensor%s found", EMSESP_Status.dallas_sensors, (EMSESP_Status.dallas_sensors == 1) ? "" : "s"); } @@ -893,7 +893,7 @@ void startDeviceScan() { publishSensorValuesTimer.detach(); scanDevices_count = 1; // starts at 1 ems_setLogging(EMS_SYS_LOGGING_NONE); - myDebug("Starting a deep EMS device scan. This will take about 1 minute. Please wait..."); + myDebug("Starting a deep EMS device scan. This can take up to 2 minutes. Please wait..."); scanThermostat.attach_ms(SCANDEVICES_TIME, do_scanDevices); } @@ -971,7 +971,7 @@ bool FSCallback(MYESP_FSACTION action, const JsonObject json) { EMS_Boiler.device_id = EMSESP_BOILER_TYPE; // set default } - // silent mode + // listen mode EMSESP_Status.listen_mode = json["listen_mode"]; ems_setTxDisabled(EMSESP_Status.listen_mode); @@ -1512,7 +1512,7 @@ void WIFICallback() { emsuart_init(); myDebug("[UART] Opened Rx/Tx connection"); if (!EMSESP_Status.listen_mode) { - // go and find the boiler and thermostat types, if not in silent mode + // go and find the boiler and thermostat types, if not in listen mode ems_discoverModels(); } } diff --git a/src/ems.cpp b/src/ems.cpp index 4e1bfa837..830a3b3f4 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -15,7 +15,7 @@ #include // std::list #ifdef TESTS -#include "unit_tests.h" +#include "test_data.h" uint8_t _TEST_DATA_max = ArraySize(TEST_DATA); #endif @@ -382,8 +382,7 @@ void ems_setLogging(_EMS_SYS_LOGGING loglevel) { /** * Calculate CRC checksum using lookup table for speed - * len is length of data in bytes (including the CRC byte at end) - * So its the complete telegram with the header. CRC is calculated only over the data bytes + * len is length of all the data in bytes (including the header & CRC byte at end) */ uint8_t _crcCalculator(uint8_t * data, uint8_t len) { uint8_t crc = 0; @@ -456,8 +455,8 @@ void _debugPrintTelegram(const char * prefix, _EMS_RxTelegram * EMS_RxTelegram, char output_str[200] = {0}; char buffer[16] = {0}; uint8_t * data = EMS_RxTelegram->telegram; - uint8_t len = EMS_RxTelegram->data_length; // length of data block - uint8_t full_len = EMS_RxTelegram->length - 1; // no CRC + uint8_t data_len = EMS_RxTelegram->data_length; // length of data block + uint8_t length = EMS_RxTelegram->length; // includes CRC strlcpy(output_str, "(", sizeof(output_str)); strlcat(output_str, COLOR_CYAN, sizeof(output_str)); @@ -475,19 +474,19 @@ void _debugPrintTelegram(const char * prefix, _EMS_RxTelegram * EMS_RxTelegram, strlcat(output_str, prefix, sizeof(output_str)); strlcat(output_str, " telegram: ", sizeof(output_str)); - for (int i = 0; i < full_len; i++) { + for (int i = 0; i < (length - 1); i++) { strlcat(output_str, _hextoa(data[i], buffer), sizeof(output_str)); strlcat(output_str, " ", sizeof(output_str)); // add space } strlcat(output_str, "(CRC=", sizeof(output_str)); - strlcat(output_str, _hextoa(data[full_len], buffer), sizeof(output_str)); + strlcat(output_str, _hextoa(data[length - 1], buffer), sizeof(output_str)); strlcat(output_str, ")", sizeof(output_str)); // print number of data bytes only if its a valid telegram - if (len > 5) { - strlcat(output_str, ", #data=", sizeof(output_str)); - strlcat(output_str, itoa(len, buffer, 10), sizeof(output_str)); + if (data_len) { + strlcat(output_str, " #data=", sizeof(output_str)); + strlcat(output_str, itoa(data_len, buffer, 10), sizeof(output_str)); } strlcat(output_str, COLOR_RESET, sizeof(output_str)); @@ -638,7 +637,7 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) { /** * the main logic that parses the telegram message * When we receive a Poll Request we need to send any Tx packages quickly within a 200ms window - * length is total number of bytes of the telegram including the CRC byte at the end if it exists + * length is total number of bytes of the telegram including the CRC byte at the end (if it exists) */ void _ems_readTelegram(uint8_t * telegram, uint8_t length) { // create the Rx package @@ -712,7 +711,7 @@ void _ems_readTelegram(uint8_t * telegram, uint8_t length) { if (length <= 7) { EMS_RxTelegram.data_length = 0; // special broadcast on ems+ have no data values } else { - EMS_RxTelegram.data_length = length - 8; // remove 5 bytes header plus CRC + length byte + 0x00 at end + EMS_RxTelegram.data_length = length - 7; // remove 6 byte header plus CRC } } else { EMS_RxTelegram.emsplus = false; @@ -832,16 +831,21 @@ void _printMessage(_EMS_RxTelegram * EMS_RxTelegram) { * and then call its callback if there is one defined */ void _ems_processTelegram(_EMS_RxTelegram * EMS_RxTelegram) { - // header - uint8_t src = EMS_RxTelegram->src; - uint16_t type = EMS_RxTelegram->type; - uint8_t offset = EMS_RxTelegram->offset; - // print out the telegram + // print out the telegram for verbose mode if (EMS_Sys_Status.emsLogging >= EMS_SYS_LOGGING_THERMOSTAT) { _printMessage(EMS_RxTelegram); } + // ignore telegrams that don't have any data + if (EMS_RxTelegram->data_length == 0) { + return; + } + + // header + uint8_t src = EMS_RxTelegram->src; + uint16_t type = EMS_RxTelegram->type; + // see if we recognize the type first by scanning our known EMS types list bool typeFound = false; uint8_t i = 0; @@ -866,14 +870,13 @@ void _ems_processTelegram(_EMS_RxTelegram * EMS_RxTelegram) { if ((EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_BASIC) || (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_VERBOSE)) { myDebug("<--- %s(0x%02X) received", EMS_Types[i].typeString, type); } - // call callback function to process it - // as we only handle complete telegrams (not partial) check that the offset is 0 - // if EMS+ always proces it + // call callback function to process the telegram, only if there is data if (EMS_RxTelegram->emsplus) { + // if EMS+ always proces it (void)EMS_Types[i].processType_cb(EMS_RxTelegram); } else { // only if the offset is 0 as we want to handle full telegrams and not partial - if (offset == EMS_ID_NONE) { + if (EMS_RxTelegram->offset == EMS_ID_NONE) { (void)EMS_Types[i].processType_cb(EMS_RxTelegram); } } @@ -1193,7 +1196,8 @@ void _process_EasyStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { void _process_RCPLUSStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { if (EMS_RxTelegram->offset == 0) { // the whole telegram - // e.g. Thermostat -> all, telegram: 10 00 FF 00 01 A5 00 D7 21 00 00 00 00 30 01 84 01 01 03 01 84 01 F1 00 00 11 01 00 08 63 00 (CRC=CC), #data=27 + // e.g. Thermostat -> all, telegram: 10 00 FF 00 01 A5 00 D7 21 00 00 00 00 30 01 84 01 01 03 01 84 01 F1 00 00 11 01 00 08 63 00 + // 10 00 FF 00 01 A5 80 00 01 30 28 00 30 28 01 54 03 03 01 01 54 02 A8 00 00 11 01 03 FF FF 00 EMS_Thermostat.curr_roomTemp = _toShort(EMS_OFFSET_RCPLUSStatusMessage_curr); // value is * 10 EMS_Thermostat.setpoint_roomTemp = _toByte(EMS_OFFSET_RCPLUSStatusMessage_setpoint); // value is * 2 @@ -1202,14 +1206,14 @@ void _process_RCPLUSStatusMessage(_EMS_RxTelegram * EMS_RxTelegram) { // day night is byte(8), 0x01 for night, 0x00 for day } - // this is a temp value but not sure which one - // e.g. Thermostat -> all, telegram: 10 00 FF 07 01 A5 32 (CRC=4E), #data=3 + // actual set point + // e.g. Thermostat -> all, telegram: 10 00 FF 07 01 A5 32 if (EMS_RxTelegram->offset == 7) { // to add... } - // this is a temp value but not sure which one - // e.g. Thermostat -> all, telegram: 18 00 FF 06 01 A5 22 (CRC=64), #data=3 + // next set point + // e.g. Thermostat -> all, telegram: 18 00 FF 06 01 A5 22 if (EMS_RxTelegram->offset == 6) { // to add... } @@ -1286,8 +1290,13 @@ void _process_SM10Monitor(_EMS_RxTelegram * EMS_RxTelegram) { * SM100Monitor - type 0x0262 EMS+ */ void _process_SM100Monitor(_EMS_RxTelegram * EMS_RxTelegram) { - EMS_Other.SMcollectorTemp = _toShort(0); // collector temp from SM100, is *10 - EMS_Other.SMbottomTemp = _toShort(2); // bottom temp from SM100, is *10 + if (EMS_RxTelegram->data_length <= 2) { + EMS_Other.SMcollectorTemp = _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_Other.SM = true; EMS_Sys_Status.emsRefreshed = true; // triggers a send the values back via MQTT @@ -1819,7 +1828,7 @@ void ems_doReadCommand(uint16_t type, uint8_t dest, bool forceRefresh) { // if we're preventing all outbound traffic, quit if (EMS_Sys_Status.emsTxDisabled) { - myDebug("in Silent Mode. All Tx is disabled."); + myDebug("in Listen Mode. All Tx is disabled."); return; } @@ -2202,18 +2211,16 @@ void ems_setWarmTapWaterActivated(bool activated) { */ void ems_startupTelegrams() { if ((EMS_Sys_Status.emsTxDisabled) || (!EMS_Sys_Status.emsBusConnected)) { - myDebug("Unable to send startup sequence when in silent mode or bus is disabled"); + myDebug("Unable to send startup sequence when in listen mode or the bus is disabled"); } myDebug("Sending startup sequence..."); char s[20] = {0}; - // (00:07:27.512) Telegram echo: telegram: 0B 08 1D 00 00 (CRC=84), #data=1 // Write type 0x1D to get out of function test mode snprintf(s, sizeof(s), "%02X %02X 1D 00 00", EMS_ID_ME, EMS_Boiler.device_id); ems_sendRawTelegram(s); - // (00:07:35.555) Telegram echo: telegram: 0B 88 01 00 1B (CRC=8B), #data=1 // Read type 0x01 snprintf(s, sizeof(s), "%02X %02X 01 00 1B", EMS_ID_ME, EMS_Boiler.device_id | 0x80); ems_sendRawTelegram(s); @@ -2262,11 +2269,11 @@ void ems_testTelegram(uint8_t test_num) { length++; // this is the total amount of bytes telegram[length] = _crcCalculator(telegram, length + 1); // add the CRC - myDebug("[TEST %d] Injecting telegram %s (data length %d)", test_num, TEST_DATA[test_num - 1], length); + myDebug("[TEST %d] Injecting telegram %s", test_num, TEST_DATA[test_num - 1]); // go an parse it _ems_readTelegram(telegram, length + 1); // include CRC in length #else - myDebug("Firmware not compiled with tests"); + myDebug("Firmware not compiled with test data set"); #endif } diff --git a/src/ems.h b/src/ems.h index 8a44e8242..937b1624d 100644 --- a/src/ems.h +++ b/src/ems.h @@ -20,7 +20,6 @@ #define EMS_ID_SM 0x30 // Solar Module SM10 and SM100 #define EMS_ID_GATEWAY 0x48 // KM200 Web Gateway - #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. @@ -40,12 +39,12 @@ #define EMS_BOILER_BURNPOWER_TAPWATER 100 #define EMS_BOILER_SELFLOWTEMP_HEATING 70 -//define maximum settable tapwater temperature, not every installation supports 90 degrees +// define maximum settable tapwater temperature #define EMS_BOILER_TAPWATER_TEMPERATURE_MAX 60 -#define EMS_TX_TELEGRAM_QUEUE_MAX 50 // max size of Tx FIFO queue +#define EMS_TX_TELEGRAM_QUEUE_MAX 100 // max size of Tx FIFO queue -//#define EMS_SYS_LOGGING_DEFAULT EMS_SYS_LOGGING_VERBOSE +// #define EMS_SYS_LOGGING_DEFAULT EMS_SYS_LOGGING_VERBOSE #define EMS_SYS_LOGGING_DEFAULT EMS_SYS_LOGGING_NONE /* EMS UART transfer status */ diff --git a/src/ems_devices.h b/src/ems_devices.h index e743a10a2..367601c1e 100644 --- a/src/ems_devices.h +++ b/src/ems_devices.h @@ -99,7 +99,7 @@ // RC1010,RC310 and RC300 specific (EMS Plus) #define EMS_TYPE_RCPLUSStatusMessage 0x01A5 // is an automatic thermostat broadcast giving us temps #define EMS_TYPE_RCPLUSSet 0x03 // setpoint temp message - this is incorrect! -#define EMS_OFFSET_RCPLUSStatusMessage_setpoint 2 // setpoint temp +#define EMS_OFFSET_RCPLUSStatusMessage_setpoint 3 // setpoint temp #define EMS_OFFSET_RCPLUSStatusMessage_curr 0 // current temp // Known EMS types diff --git a/src/test_data.h b/src/test_data.h new file mode 100644 index 000000000..ff8fb3e87 --- /dev/null +++ b/src/test_data.h @@ -0,0 +1,29 @@ + +#ifdef TESTS + +static const char * TEST_DATA[] = { + + "08 00 34 00 3E 02 1D 80 00 31 00 00 01 00 01 0B AE 02", // test 1 - EMS + "10 00 FF 00 01 A5 80 00 01 30 28 00 30 28 01 54 03 03 01 01 54 02 A8 00 00 11 01 03 FF FF 00", // test 2 - RC310 ems+ + "10 00 FF 19 01 A5 06 04 00 00 00 00 FF 64 37 00 3C 01 FF 01", // test 3 - RC310 ems+ + "30 00 FF 00 02 62 00 A1 01 3F 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00", // test 4 - SM100 + "10 00 FF 00 01 A5 00 D7 21 00 00 00 00 30 01 84 01 01 03 01 84 01 F1 00 00 11 01 00 08 63 00", // test 5 - RC1010 + "18 00 FF 00 01 A5 00 DD 21 23 00 00 23 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00", // test 6 - RC300 + "90 00 FF 00 00 6F 01 01 00 46 00 B9", // test 7 - FR10 + "30 00 FF 00 02 62 01 FB 01 9E 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00 2B", // test 8 - SM100 + "30 00 FF 00 02 64 00 00 00 04 00 00 FF 00 00 1E 0C 20 64 00 00 00 00 E9", // test 9 - SM100 + "30 09 FF 00 00 01", // test 10 - EMS+ + "30 0B 97 00", // test 11 - SM100 + "30 00 FF 00 02 62 1 CA", // test 12 - SM100 + "30 00 FF 00 02 8E 00 00 00 00 00 00 05 19 00 00 75 D3", // test 13 - SM100 + "30 00 FF 00 02 63 80 00 80 00 00 00 80 00 80 00 80 00 00", // test 14 - SM100 + "30 00 FF 00 02 64 00 00 00 04 00 00 FF 00 00 1E 0B 09 64 00 00 00 00", // test 15 - SM100 + "30 00 FF 00 02 62 01 CA 01 93 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00", // test 16 - SM100 + "30 00 FF 00 02 6A 03 03 03 00 03 03 03 03 03 00 03 03", // test 17 - SM100 + "30 00 FF 00 02 6A 03 03 03 00 03 03 03 03 03 00 04 03", // test 18 - SM100 + "30 00 FF 00 02 64 00 00 00 04 00 00 FF 00 00 1E 09 08 64 00 00 00 00", // test 19 - SM100 + "10 00 FF 07 01 A5 32" // test 20 - RC EMS+ + +}; + +#endif diff --git a/src/unit_tests.h b/src/unit_tests.h deleted file mode 100644 index 0dbd4b42a..000000000 --- a/src/unit_tests.h +++ /dev/null @@ -1,28 +0,0 @@ - -#ifdef TESTS - - static const char * TEST_DATA[] = { - - "08 00 34 00 3E 02 1D 80 00 31 00 00 01 00 01 0B AE 02", // test 1 - EMS - "10 00 FF 00 01 A5 80 00 01 30 28 00 30 28 01 54 03 03 01 01 54 02 A8 00 00 11 01 03 FF FF 00", // test 2 - RC310 ems+ - "10 00 FF 19 01 A5 06 04 00 00 00 00 FF 64 37 00 3C 01 FF 01", // test 3 - RC310 ems+ - "30 00 FF 00 02 62 00 A1 01 3F 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00", // test 4 - SM100 - "10 00 FF 00 01 A5 00 D7 21 00 00 00 00 30 01 84 01 01 03 01 84 01 F1 00 00 11 01 00 08 63 00", // test 5 - RC1010 - "18 00 FF 00 01 A5 00 DD 21 23 00 00 23 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00", // test 6 - RC300 - "90 00 FF 00 00 6F 01 01 00 46 00 B9", // test 7 - FR10 - "30 00 FF 00 02 62 01 FB 01 9E 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00 2B", // test 8 - SM100 - "30 00 FF 00 02 64 00 00 00 04 00 00 FF 00 00 1E 0C 20 64 00 00 00 00 E9", // test 9 - SM100 - "30 09 FF 00 00 01", // test 10 - EMS+ - "30 0B 97 00", // test 11 - SM100 - "30 00 FF 00 02 62 1 CA", // test 12 - SM100 - "30 00 FF 00 02 8E 00 00 00 00 00 00 05 19 00 00 75 D3", // test 13 - SM100 - "30 00 FF 00 02 63 80 00 80 00 00 00 80 00 80 00 80 00 00", // test 14 - SM100 - "30 00 FF 00 02 64 00 00 00 04 00 00 FF 00 00 1E 0B 09 64 00 00 00 00", // test 15 - SM100 - "30 00 FF 00 02 62 01 CA 01 93 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00 80 00", // test 16 - SM100 - "30 00 FF 00 02 6A 03 03 03 00 03 03 03 03 03 00 03 03", // test 17 - SM100 - "30 00 FF 00 02 6A 03 03 03 00 03 03 03 03 03 00 04 03", // test 18 - SM100 - "30 00 FF 00 02 64 00 00 00 04 00 00 FF 00 00 1E 09 08 64 00 00 00 00" // test 19 - SM100 - - }; - -#endif