diff --git a/CHANGELOG.md b/CHANGELOG.md index 784a34b2a..f059cb5f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +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.5.6] 2019-03-09 + +### Added + +- test_mode option + +### Changed + +- upgraded MyESP library +- minor changes + + ## [1.5.5] 2019-03-07 ### Fixed diff --git a/README.md b/README.md index 78371fa9d..0f8e60e71 100644 --- a/README.md +++ b/README.md @@ -341,19 +341,17 @@ Porting to the Arduino IDE can be a little tricky but it did it once. Something ## Using the Pre-built Firmware -pre-baked firmwares for some ESP8266 devices are available in the directory `/firmware` which you can upload yourself using [esptool](https://github.com/espressif/esptool) bootloader. On Windows, follow these instructions: +pre-baked firmware for the Wemos D1 mini is available in the GitHub [releases](https://github.com/proddy/EMS-ESP/releases) which you can upload yourself using the [esptool](https://github.com/espressif/esptool) bootloader like `esptool.py -p write_flash 0x00000 `. Here's how to set it up on Windows: 1. Check if you have **python 2.7** installed. If not [download it](https://www.python.org/downloads/) and make sure you select the option to add Python to the windows PATH -2. Install the ESPTool by running `pip install esptool` from a command prompt -3. Connect the ESP via USB, figure out the COM port -4. run `esptool.py -p write_flash 0x00000 ` where firmware is the `.bin` file and \ is the COM port, e.g. `COM3` +2. Then install the ESPTool by running `pip install esptool` from a command prompt The ESP8266 will start in Access Point (AP) mode. Connect via WiFi to the SSID **EMS-ESP** and telnet to **192.168.4.1**. Then use the `set wifi` command to configure your own network settings like `set wifi your_ssid your_password`. Alternatively connect the ESP8266 to your PC and open a Serial monitor (with baud 115200) to configure the settings. Make sure you disable Serial support before connecting the EMS lines using `set serial off`. -`set erase` will clear all settings. - `set` wil list all currently stored settings. +`set erase` will clear all settings. + ## Troubleshooting When flashing for the first time the Serial port is enabled by default with baud 115200. You can then use a PC with USB to the ESP8266 to set the settings like wifi, mqtt etc and also monitor the boot up procedure. Remember to disable the serial (`set serial off`) when connecting to the EMS lines. diff --git a/firmware/emsesp_155_d1_mini.bin b/firmware/emsesp_155_d1_mini.bin deleted file mode 100644 index 154585dce..000000000 Binary files a/firmware/emsesp_155_d1_mini.bin and /dev/null differ diff --git a/lib/TelnetSpy/TelnetSpy.cpp b/lib/TelnetSpy/TelnetSpy.cpp index 0de899ffd..ea1762fa4 100644 --- a/lib/TelnetSpy/TelnetSpy.cpp +++ b/lib/TelnetSpy/TelnetSpy.cpp @@ -106,14 +106,14 @@ void TelnetSpy::setPort(uint16_t portToUse) { } } -void TelnetSpy::setWelcomeMsg(char * msg) { +void TelnetSpy::setWelcomeMsg(const char * msg) { if (welcomeMsg) { free(welcomeMsg); } welcomeMsg = strdup(msg); } -void TelnetSpy::setRejectMsg(char * msg) { +void TelnetSpy::setRejectMsg(const char * msg) { if (rejectMsg) { free(rejectMsg); } @@ -434,22 +434,24 @@ TelnetSpy::operator bool() const { void TelnetSpy::setDebugOutput(bool en) { debugOutput = en; + + // TODO: figure out how to disable system printing for the ESP32 if (debugOutput) { actualObject = this; + #ifdef ESP8266 os_install_putc1((void *)TelnetSpy_putc); // Set system printing (os_printf) to TelnetSpy system_set_os_print(true); -#else // ESP32 \ - // ToDo: How can be done this for ESP32 ? #endif + } else { if (actualObject == this) { + #ifdef ESP8266 system_set_os_print(false); os_install_putc1((void *)TelnetSpy_ignore_putc); // Ignore system printing -#else // ESP32 \ - // ToDo: How can be done this for ESP32 ? #endif + actualObject = NULL; } } diff --git a/lib/TelnetSpy/TelnetSpy.h b/lib/TelnetSpy/TelnetSpy.h index 0a0f6fa42..1f7b901c7 100644 --- a/lib/TelnetSpy/TelnetSpy.h +++ b/lib/TelnetSpy/TelnetSpy.h @@ -174,8 +174,8 @@ class TelnetSpy : public Stream { ~TelnetSpy(); void handle(void); void setPort(uint16_t portToUse); - void setWelcomeMsg(char * msg); - void setRejectMsg(char * msg); + void setWelcomeMsg(const char * msg); + void setRejectMsg(const char * msg); void setMinBlockSize(uint16_t minSize); void setCollectingTime(uint16_t colTime); void setMaxBlockSize(uint16_t maxSize); diff --git a/lib/myESP/MyESP.cpp b/lib/myESP/MyESP.cpp index 5063a9899..3e39bbe70 100644 --- a/lib/myESP/MyESP.cpp +++ b/lib/myESP/MyESP.cpp @@ -33,7 +33,6 @@ MyESP::MyESP() { _helpProjectCmds = NULL; _helpProjectCmds_count = 0; - _command = (char *)malloc(TELNET_MAX_COMMAND_LENGTH); // reserve buffer for Serial/Telnet commands _use_serial = true; _mqtt_host = NULL; @@ -65,7 +64,6 @@ MyESP::~MyESP() { // end void MyESP::end() { - free(_command); SerialAndTelnet.end(); jw.disconnect(); } @@ -266,7 +264,8 @@ void MyESP::_mqtt_setup() { mqttClient.onDisconnect([this](AsyncMqttClientDisconnectReason reason) { if (reason == AsyncMqttClientDisconnectReason::TCP_DISCONNECTED) { myDebug_P(PSTR("[MQTT] TCP Disconnected. Check mqtt logs.")); - (_mqtt_callback)(MQTT_DISCONNECT_EVENT, NULL, NULL); // call callback with disconnect + (_mqtt_callback)(MQTT_DISCONNECT_EVENT, NULL, + NULL); // call callback with disconnect } if (reason == AsyncMqttClientDisconnectReason::MQTT_IDENTIFIER_REJECTED) { myDebug_P(PSTR("[MQTT] Identifier Rejected")); @@ -391,7 +390,7 @@ void MyESP::_telnetDisconnected() { // Initialize the telnet server void MyESP::_telnet_setup() { - SerialAndTelnet.setWelcomeMsg((char *)""); + SerialAndTelnet.setWelcomeMsg(""); SerialAndTelnet.setCallbackOnConnect([this]() { _telnetConnected(); }); SerialAndTelnet.setCallbackOnDisconnect([this]() { _telnetDisconnected(); }); SerialAndTelnet.setDebugOutput(false); @@ -738,9 +737,7 @@ void MyESP::_telnetHandle() { while (SerialAndTelnet.available()) { char c = SerialAndTelnet.read(); - if (_use_serial) { - SerialAndTelnet.serialPrint(c); // echo to Serial if connected - } + SerialAndTelnet.serialPrint(c); // echo to Serial if connected switch (c) { case '\r': // likely have full command in buffer now, commands are terminated by CR and/or LF @@ -750,17 +747,24 @@ void MyESP::_telnetHandle() { charsRead = 0; // is static, so have to reset _suspendOutput = false; if (_use_serial) { - SerialAndTelnet.println(); // force newline if in Telnet + SerialAndTelnet.serialPrint('\n'); // force newline if in Serial } _telnetCommand(_command); } break; - case '\b': // handle backspace in input: put a space in last char + + case '\b': // (^H) handle backspace in input: put a space in last char - coded by Simon Arlott + case 0x7F: // (^?) + if (charsRead > 0) { _command[--charsRead] = '\0'; - SerialAndTelnet << byte('\b') << byte(' ') << byte('\b'); + + SerialAndTelnet.write(' '); + SerialAndTelnet.write('\b'); } + break; + case '?': if (!_suspendOutput) { _consoleShowHelp(); @@ -814,7 +818,8 @@ void MyESP::_mqttConnect() { // last will if (_mqtt_will_topic) { //myDebug_P(PSTR("[MQTT] Setting last will topic %s"), _mqttTopic(_mqtt_will_topic)); - mqttClient.setWill(_mqttTopic(_mqtt_will_topic), 1, true, _mqtt_will_offline_payload); // retain always true + mqttClient.setWill(_mqttTopic(_mqtt_will_topic), 1, true, + _mqtt_will_offline_payload); // retain always true } if (_mqtt_username && _mqtt_password) { @@ -955,7 +960,8 @@ void MyESP::_fs_printConfig() { // format File System void MyESP::_fs_eraseConfig() { - myDebug_P(PSTR("[FS] Erasing settings, please wait a few seconds. ESP will automatically restart when finished.")); + myDebug_P(PSTR("[FS] Erasing settings, please wait a few seconds. ESP will " + "automatically restart when finished.")); if (SPIFFS.format()) { delay(1000); // wait 1 seconds @@ -1037,6 +1043,12 @@ bool MyESP::fs_saveConfig() { // callback for saving custom settings (void)(_fs_callback)(MYESP_FSACTION_SAVE, json); + // if file exists, remove it just to be safe + if (SPIFFS.exists(MYEMS_CONFIG_FILE)) { + // delete it + SPIFFS.remove(MYEMS_CONFIG_FILE); + } + File configFile = SPIFFS.open(MYEMS_CONFIG_FILE, "w"); if (!configFile) { Serial.println("[FS] Failed to open config file for writing"); @@ -1069,7 +1081,7 @@ void MyESP::_fs_setup() { fs_saveConfig(); } - // _fs_printConfig(); // TODO: for debugging + //_fs_printConfig(); // TODO: for debugging } uint16_t MyESP::getSystemLoadAverage() { diff --git a/lib/myESP/MyESP.h b/lib/myESP/MyESP.h index 773d3014e..7096d351b 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.4" +#define MYESP_VERSION "1.1.5" #include #include @@ -68,7 +68,7 @@ #define COLOR_CYAN "\x1B[0;36m" #define COLOR_WHITE "\x1B[0;37m" #define COLOR_BOLD_ON "\x1B[1m" -#define COLOR_BOLD_OFF "\x1B[21m" +#define COLOR_BOLD_OFF "\x1B[22m" // fixed by Scott Arlott // SPIFFS #define SPIFFS_MAXSIZE 500 // https://arduinojson.org/v5/assistant/ @@ -191,9 +191,9 @@ class MyESP { void _telnetCommand(char * commandLine); char * _telnet_readWord(); void _telnet_setup(); - char * _command; // the input command from either Serial or Telnet - command_t * _helpProjectCmds; // Help of commands setted by project - uint8_t _helpProjectCmds_count; // # available commands + 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.ino b/src/ems-esp.ino index 396e7280e..1c1b733c0 100644 --- a/src/ems-esp.ino +++ b/src/ems-esp.ino @@ -58,9 +58,11 @@ Ticker showerColdShotStopTimer; #define SHOWER_COLDSHOT_DURATION 10 // in seconds. 10 seconds for cold water before turning back hot water typedef struct { - bool shower_timer; // true if we want to report back on shower times - bool shower_alert; // true if we want the alert of cold water - bool led_enabled; // LED on/off + bool shower_timer; // true if we want to report back on shower times + bool shower_alert; // true if we want the alert of cold water + bool led_enabled; // LED on/off + bool test_mode; // test mode to stop automatic Tx on/off + unsigned long timestamp; // for internal timings, via millis() uint8_t dallas_sensors; // count of dallas sensors uint8_t led_gpio; @@ -82,9 +84,10 @@ command_t PROGMEM project_cmds[] = { {"set dallas_gpio ", "set the pin for external Dallas temperature sensors (D5=14)"}, {"set thermostat_type ", "set the thermostat type id (e.g. 10 for 0x10)"}, {"set boiler_type ", "set the boiler type id (e.g. 8 for 0x08)"}, + {"set test_mode ", "test_mode turns off all automatic reads"}, {"info", "show data captured on the EMS bus"}, {"log ", "set logging mode to none, basic, thermostat only, raw or verbose"}, - {"publish", "forice a publish of all values to MQTT"}, + {"publish", "publish all values to MQTT"}, {"types", "list supported EMS telegram type IDs"}, {"queue", "show current Tx queue"}, {"autodetect", "discover EMS devices and attempt to automatically set boiler and thermostat"}, @@ -261,6 +264,7 @@ void showInfo() { } myDebug(" LED is %s", EMSESP_Status.led_enabled ? "on" : "off"); + myDebug(" Test Mode is %s", EMSESP_Status.test_mode ? "on" : "off"); myDebug(" # connected Dallas temperature sensors=%d", EMSESP_Status.dallas_sensors); @@ -469,8 +473,7 @@ void publishValues(bool force) { } // handle the thermostat values separately - //if (ems_getThermostatEnabled()) { - if (true) { + if (ems_getThermostatEnabled()) { // only send thermostat values if we actually have them if (((int)EMS_Thermostat.curr_roomTemp == (int)0) || ((int)EMS_Thermostat.setpoint_roomTemp == (int)0)) return; @@ -607,6 +610,11 @@ bool FSCallback(MYESP_FSACTION action, const JsonObject json) { EMS_Boiler.type_id = EMSESP_BOILER_TYPE; // set default } + // test mode + if (!(EMSESP_Status.test_mode = json["test_mode"])) { + EMSESP_Status.test_mode = false; // default value + } + return false; // always save the settings } @@ -616,9 +624,12 @@ bool FSCallback(MYESP_FSACTION action, const JsonObject json) { json["dallas_gpio"] = EMSESP_Status.dallas_gpio; json["thermostat_type"] = EMS_Thermostat.type_id; json["boiler_type"] = EMS_Boiler.type_id; + json["test_mode"] = EMSESP_Status.test_mode; return true; } + + return false; } // callback for custom settings when showing Stored Settings @@ -641,6 +652,18 @@ bool SettingsCallback(MYESP_FSACTION action, uint8_t wc, const char * setting, c } } + // test mode + if ((strcmp(setting, "test_mode") == 0) && (wc == 2)) { + if (strcmp(value, "on") == 0) { + EMSESP_Status.test_mode = true; + ok = true; + myDebug("* Reboot to go into test mode."); + } else if (strcmp(value, "off") == 0) { + EMSESP_Status.test_mode = false; + ok = true; + } + } + // led_gpio if ((strcmp(setting, "led_gpio") == 0) && (wc == 2)) { EMSESP_Status.led_gpio = atoi(value); @@ -670,6 +693,7 @@ bool SettingsCallback(MYESP_FSACTION action, uint8_t wc, const char * setting, c } if (action == MYESP_FSACTION_LIST) { + myDebug(" test_mode=%s", EMSESP_Status.test_mode ? "on" : "off"); myDebug(" led=%s", EMSESP_Status.led_enabled ? "on" : "off"); myDebug(" led_gpio=%d", EMSESP_Status.led_gpio); myDebug(" dallas_gpio=%d", EMSESP_Status.dallas_gpio); @@ -948,9 +972,11 @@ void WIFICallback() { // Initialize the boiler settings and shower settings void initEMSESP() { // general settings - EMSESP_Status.shower_timer = BOILER_SHOWER_TIMER; - EMSESP_Status.shower_alert = BOILER_SHOWER_ALERT; - EMSESP_Status.led_enabled = true; // LED is on by default + EMSESP_Status.shower_timer = BOILER_SHOWER_TIMER; + EMSESP_Status.shower_alert = BOILER_SHOWER_ALERT; + EMSESP_Status.led_enabled = true; // LED is on by default + EMSESP_Status.test_mode = false; + EMSESP_Status.timestamp = millis(); EMSESP_Status.dallas_sensors = 0; @@ -1108,10 +1134,7 @@ void setup() { // call ems.cpp's init function to set all the internal params ems_init(); - // Timers using Ticker library - publishValuesTimer.attach(PUBLISHVALUES_TIME, do_publishValues); // post MQTT values - systemCheckTimer.attach(SYSTEMCHECK_TIME, do_systemCheck); // check if Boiler is online - regularUpdatesTimer.attach(REGULARUPDATES_TIME, do_regularUpdates); // regular reads from the EMS + systemCheckTimer.attach(SYSTEMCHECK_TIME, do_systemCheck); // check if Boiler is online // set up myESP for Wifi, MQTT, MDNS and Telnet myESP.setTelnet(project_cmds, ArraySize(project_cmds), TelnetCommandCallback, TelnetCallback); // set up Telnet commands @@ -1143,6 +1166,12 @@ void setup() { // start up all the services myESP.begin(APP_HOSTNAME, APP_NAME, APP_VERSION); + // enable regular checks if not in test mode + if (!EMSESP_Status.test_mode) { + publishValuesTimer.attach(PUBLISHVALUES_TIME, do_publishValues); // post MQTT values + regularUpdatesTimer.attach(REGULARUPDATES_TIME, do_regularUpdates); // regular reads from the EMS + } + // set pin for LED if (EMSESP_Status.led_gpio != EMS_VALUE_INT_NOTSET) { pinMode(EMSESP_Status.led_gpio, OUTPUT); @@ -1170,7 +1199,7 @@ void loop() { // publish the values to MQTT, only if the values have changed // although we don't want to publish when doing a deep scan of the thermostat - if (ems_getEmsRefreshed() && (scanThermostat_count == 0)) { + if (ems_getEmsRefreshed() && (scanThermostat_count == 0) && (!EMSESP_Status.test_mode)) { publishValues(false); ems_setEmsRefreshed(false); // reset } diff --git a/src/ems.cpp b/src/ems.cpp index 1e24b5596..da6a6bc89 100644 --- a/src/ems.cpp +++ b/src/ems.cpp @@ -884,7 +884,7 @@ void _processType(uint8_t * telegram, uint8_t length) { * Check if hot tap water or heating is active * using a quick hack for checking the heating. Selected Flow Temp >= 70 */ -bool _checkActive() { +void _checkActive() { // hot tap water, using flow to check insread of the burner power EMS_Boiler.tapwaterActive = ((EMS_Boiler.wWCurFlow != 0) && (EMS_Boiler.burnGas == EMS_VALUE_INT_ON)); @@ -969,7 +969,7 @@ void _process_UBAMonitorFast(uint8_t type, uint8_t * data, uint8_t length) { } // at this point do a quick check to see if the hot water or heating is active - (void)_checkActive(); + _checkActive(); } /** @@ -1587,13 +1587,13 @@ void ems_sendRawTelegram(char * telegram) { EMS_Sys_Status.txRetryCount = 0; // reset retry counter // get first value, which should be the src - if (p = strtok(telegram, " ,")) { // delimiter + if ( (p = strtok(telegram, " ,")) ) { // delimiter strlcpy(value, p, sizeof(value)); EMS_TxTelegram.data[0] = (uint8_t)strtol(value, 0, 16); } // and interate until end while (p != 0) { - if (p = strtok(NULL, " ,")) { + if ( (p = strtok(NULL, " ,")) ) { strlcpy(value, p, sizeof(value)); uint8_t val = (uint8_t)strtol(value, 0, 16); EMS_TxTelegram.data[++count] = val; diff --git a/src/emsuart.h b/src/emsuart.h index a6c04b6d5..f5053bda3 100644 --- a/src/emsuart.h +++ b/src/emsuart.h @@ -25,7 +25,7 @@ #define EMSUART_recvTaskQueueLen 64 typedef struct { - int16_t writePtr; + uint8_t writePtr; uint8_t buffer[EMS_MAXBUFFERSIZE]; } _EMSRxBuf; diff --git a/src/version.h b/src/version.h index f76abbf74..c078e0432 100644 --- a/src/version.h +++ b/src/version.h @@ -6,5 +6,5 @@ #pragma once #define APP_NAME "EMS-ESP" -#define APP_VERSION "1.5.5" +#define APP_VERSION "1.5.6" #define APP_HOSTNAME "ems-esp"