diff --git a/src/boiler.ino b/src/boiler.ino index 974be4a02..93a007697 100644 --- a/src/boiler.ino +++ b/src/boiler.ino @@ -15,10 +15,11 @@ #include // https://github.com/bblanchon/ArduinoJson #include // https://github.com/bakercp/CRC32 -// standard libs +// standard arduino libs #include // https://github.com/esp8266/Arduino/tree/master/libraries/Ticker +#include -// these are set as -D build flags. If you're not using PlatformIO hard code them +// these are set as -D build flags during compilation //#define WIFI_SSID "" //#define WIFI_PASSWORD "" //#define MQTT_IP "" @@ -38,25 +39,6 @@ Ticker showerColdShotStopTimer; uint8_t regularUpdatesCount = 0; #define MAX_MANUAL_CALLS 2 // number of ems reads we do during the fetch cycle (in regularUpdates) -// Project commands for telnet -// Note: ?, *, $, ! and & are reserved -#define PROJECT_CMDS \ - "* s show statistics\n\r" \ - "* P publish stats to MQTT\n\r" \ - "* v [n] set logging (0=none, 1=basic, 2=verbose)\n\r" \ - "* p poll response on/off\n\r" \ - "* T thermostat Support on/off\n\r" \ - "* S shower timer on/off\n\r" \ - "* A shower alert on/off\n\r" \ - "* r [n] request for data from EMS. Examples:\n\r" \ - "* from Boiler: 33=UBAParameterWW, 18=UBAMonitorFast, 19=UBAMonitorSlow, 34=UBAMonitorWWMessage\n\r" \ - "* from Thermostat: 91=RC20StatusMessage, A8=RC20Temperature, 6=RC20Time, 2=Version\n\r" \ - "* t [n] set thermostat temperature to n\n\r" \ - "* m [n] set thermostat mode (0=low, 1=manual, 2=clock)\n\r" \ - "* w [n] set boiler warm water temperature to n (min 30)\n\r" \ - "* a [n] boiler warm water on (n=1) or off (n=0)\n\r" \ - "* x [n] experimental (warning: for debugging only!)" - // GPIOs #define LED_RX D1 // GPIO5 #define LED_TX D2 // GPIO4 @@ -137,6 +119,28 @@ netInfo homeNet = {.mqttHost = MQTT_IP, ESPHelper myESP(&homeNet); +command_t PROGMEM + project_cmds[] = {{"s", "show statistics"}, + {"h", "show which EMS telegram types have special logic"}, + {"P", "publish data to MQTT"}, + {"v", "[n] set logging (0=none, 1=basic, 2=verbose)"}, + {"p", "poll response on/off (default is off)"}, + {"T", "thermostat Support on/off"}, + {"S", "shower timer on/off"}, + {"A", "shower alert on/off"}, + {"r", "[n] send EMS request (n=telegram type id. Use 'h' to list which are the common ones)"}, + {"t", "[n] set thermostat temperature to n"}, + {"m", "[n] set thermostat mode (0=low, 1=manual, 2=clock)"}, + {"w", "[n] set boiler warm water temperature to n (min 30)"}, + {"a", "[n] boiler warm water on (n=1) or off (n=0)"}, + {"x", "[n] experimental (warning: for debugging only!)"}}; + +// calculates size of an 2d array at compile time +template +constexpr size_t ArraySize(T (&)[N]) { + return N; +} + // store for overall system status _Boiler_Status Boiler_Status; _Boiler_Shower Boiler_Shower; @@ -259,7 +263,9 @@ void showInfo() { myDebug("None"); } - myDebug("\n Thermostat is %s, Poll is %s, Shower timer is %s, Shower alert is %s\n", + myDebug("\n # EMS type handlers: %d\n", ems_getEmsTypesCount()); + + myDebug(" Thermostat is %s, Poll is %s, Shower timer is %s, Shower alert is %s\n", ((Boiler_Status.thermostat_enabled) ? "enabled" : "disabled"), ((EMS_Sys_Status.emsPollEnabled) ? "enabled" : "disabled"), ((Boiler_Status.shower_timer) ? "enabled" : "disabled"), @@ -496,6 +502,9 @@ void myDebugCallback() { case 't': // set thermostat temp ems_setThermostatTemp(strtof(&cmd[2], 0)); break; + case 'h': // show type handlers + ems_printAllTypes(); + break; case 'm': // set thermostat mode ems_setThermostatMode(cmd[2] - '0'); break; @@ -645,7 +654,7 @@ void _initBoiler() { // init boiler Boiler_Status.wifi_connected = false; - Boiler_Status.boiler_online = true; // assume we have a connection, it will be checked in the loop() anyway + Boiler_Status.boiler_online = false; // init shower Boiler_Shower.timerStart = 0; @@ -694,11 +703,8 @@ void setup() { myESP.addSubscription(TOPIC_BOILER_WARM_WATER_SELECTED_TEMPERATURE); myESP.addSubscription(TOPIC_SHOWER_COLDSHOT); - // set up Telnet - - myESP.consoleSetHelpProjectsCmds(PROJECT_CMDS); - myESP.consoleSetCallBackProjectCmds(myDebugCallback); - myESP.begin(HOSTNAME); + myESP.consoleSetCallBackProjectCmds(project_cmds, ArraySize(project_cmds), myDebugCallback); // set up Telnet commands + myESP.begin(HOSTNAME); // start wifi and mqtt services // init ems stats ems_init(); diff --git a/src/ems.cpp b/src/ems.cpp index 9de0034e2..5b69e470c 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -21,11 +21,15 @@ extern ESPHelper myESP; #define myDebug(x, ...) myESP.printf(x, ##__VA_ARGS__) #endif +// calculates size of an 2d array at compile time +template +constexpr size_t ArraySize(T (&)[N]) { + return N; +} + _EMS_Sys_Status EMS_Sys_Status; // EMS Status _EMS_TxTelegram EMS_TxTelegram; // Empty buffer for sending telegrams -// and call backs -#define MAX_TYPECALLBACK 13 // make sure it matches the #types you have // callbacks per type bool _process_UBAMonitorFast(uint8_t * data, uint8_t length); bool _process_UBAMonitorSlow(uint8_t * data, uint8_t length); @@ -37,7 +41,7 @@ bool _process_RC20Temperature(uint8_t * data, uint8_t length); bool _process_RCTempMessage(uint8_t * data, uint8_t length); bool _process_Version(uint8_t * data, uint8_t length); -const _EMS_Types EMS_Types[MAX_TYPECALLBACK] = +const _EMS_Types EMS_Types[] = {{EMS_ID_BOILER, EMS_TYPE_UBAMonitorFast, "UBAMonitorFast", _process_UBAMonitorFast}, {EMS_ID_BOILER, EMS_TYPE_UBAMonitorSlow, "UBAMonitorSlow", _process_UBAMonitorSlow}, {EMS_ID_BOILER, EMS_TYPE_UBAMonitorWWMessage, "UBAMonitorWWMessage", _process_UBAMonitorWWMessage}, @@ -52,6 +56,7 @@ const _EMS_Types EMS_Types[MAX_TYPECALLBACK] = {EMS_ID_THERMOSTAT, EMS_TYPE_RC20Temperature, "RC20Temperature", _process_RC20Temperature}, {EMS_ID_THERMOSTAT, EMS_TYPE_RCTempMessage, "RCTempMessage", _process_RCTempMessage}, {EMS_ID_THERMOSTAT, EMS_TYPE_Version, "Version", _process_Version}}; +uint8_t _EMS_Types_max = ArraySize(EMS_Types); // number of defined types // reserve space for the data we collect from the Boiler and Thermostat _EMS_Boiler EMS_Boiler; @@ -181,6 +186,10 @@ _EMS_SYS_LOGGING ems_getLogging() { return EMS_Sys_Status.emsLogging; } +uint8_t ems_getEmsTypesCount() { + return _EMS_Types_max; +} + void ems_setLogging(_EMS_SYS_LOGGING loglevel) { if (loglevel <= EMS_SYS_LOGGING_VERBOSE) { EMS_Sys_Status.emsLogging = loglevel; @@ -224,6 +233,18 @@ uint16_t _toLong(uint8_t i, uint8_t * data) { return (((data[i]) << 16) + ((data[i + 1]) << 8) + (data[i + 2])); } +// debugging only - print out all handled types +void ems_printAllTypes() { + myDebug("These %d telegram types are recognized:\n", _EMS_Types_max); + + for (uint8_t i = 0; i < _EMS_Types_max; i++) { + myDebug(" %s:\ttype:%02x (%s)\n", + EMS_Types[i].src == EMS_ID_THERMOSTAT ? "Thermostat" : "Boiler", + EMS_Types[i].type, + EMS_Types[i].typeString); + } +} + /* * Find the pointer to the EMS_Types array for a given type ID */ @@ -231,7 +252,7 @@ int ems_findType(uint8_t type) { uint8_t i = 0; bool typeFound = false; // scan through known ID types - while (i < MAX_TYPECALLBACK) { + while (i < _EMS_Types_max) { if (EMS_Types[i].type == type) { typeFound = true; // we have a match break; @@ -396,7 +417,7 @@ void _processType(uint8_t * telegram, uint8_t length) { // set typeFound if we found a match int i = 0; bool typeFound = false; - while (i < MAX_TYPECALLBACK) { + while (i < _EMS_Types_max) { if ((EMS_Types[i].src == src) && (EMS_Types[i].type == type)) { // we have a match typeFound = true; diff --git a/src/ems.h b/src/ems.h index 140e658d6..47c6dc8e1 100644 --- a/src/ems.h +++ b/src/ems.h @@ -163,10 +163,9 @@ typedef bool (*EMS_processType_cb)(uint8_t * data, uint8_t length); // Definition for each type, including the relative callback function typedef struct { - uint8_t src; - uint8_t type; - const char typeString[50]; - //uint8_t size; // size of telegram, excluding the 4-byte header and crc + uint8_t src; + uint8_t type; + const char typeString[50]; EMS_processType_cb processType_cb; } _EMS_Types; @@ -184,23 +183,22 @@ typedef struct { #define COLOR_BOLD_OFF "\x1B[21m" // function definitions -extern void ems_parseTelegram(uint8_t * telegram, uint8_t len); -void ems_init(); -void ems_doReadCommand(uint8_t type); -void ems_setThermostatTemp(float temp); -void ems_setThermostatMode(uint8_t mode); -void ems_setWarmWaterTemp(uint8_t temperature); -void ems_setWarmWaterActivated(bool activated); -void ems_setExperimental(uint8_t value); - -void ems_setPoll(bool b); -bool ems_getPoll(); - -bool ems_getThermostatEnabled(); -void ems_setThermostatEnabled(bool b); - +extern void ems_parseTelegram(uint8_t * telegram, uint8_t len); +void ems_init(); +void ems_doReadCommand(uint8_t type); +void ems_setThermostatTemp(float temp); +void ems_setThermostatMode(uint8_t mode); +void ems_setWarmWaterTemp(uint8_t temperature); +void ems_setWarmWaterActivated(bool activated); +void ems_setExperimental(uint8_t value); +void ems_setPoll(bool b); +bool ems_getPoll(); +bool ems_getThermostatEnabled(); +void ems_setThermostatEnabled(bool b); void ems_setLogging(_EMS_SYS_LOGGING loglevel); _EMS_SYS_LOGGING ems_getLogging(); +uint8_t ems_getEmsTypesCount(); +void ems_printAllTypes(); // private functions uint8_t _crcCalculator(uint8_t * data, uint8_t len);