This commit is contained in:
proddy
2019-02-04 21:44:13 +01:00
parent f2556aa203
commit a0303f0704
8 changed files with 109 additions and 53 deletions

View File

@@ -5,11 +5,23 @@ 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.2] 2019-02-04
### Changed
- Change wifi settings using the `set wifi <ssid> <password>` command
### Added
- Added incoming MQTT "TOPIC_BOILER_WWACTIVATED" to set the warm water on/off. Payload is 1 or 0. See [issue](https://github.com/proddy/EMS-ESP/issues/46#issuecomment-460375689).
- Added the list of all MQTT topics to the README file
## [1.5.1] 2019-02-03
### Fixed
- issue with Serial monitoring conflicting with UART when both running
- Fixed typo with -D settings in the example platformio.ini
### Changed

View File

@@ -5,7 +5,7 @@ EMS-ESP is a project to build an electronic controller circuit using an Espressi
There are 3 parts to this project, first the design of the circuit, secondly the code for the ESP8266 microcontroller firmware with telnet and MQTT support, and lastly an example configuration for Home Assistant to monitor the data and issue direct commands via a MQTT broker.
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/b8880625bdf841d4adb2829732030887)](https://app.codacy.com/app/proddy/EMS-ESP?utm_source=github.com&utm_medium=referral&utm_content=proddy/EMS-ESP&utm_campaign=Badge_Grade_Settings)
[![version](https://img.shields.io/badge/version-1.4.0-brightgreen.svg)](CHANGELOG.md)
[![version](https://img.shields.io/badge/version-1.5.2-brightgreen.svg)](CHANGELOG.md)
- [EMS-ESP](#ems-esp)
- [Introduction](#introduction)
@@ -233,7 +233,15 @@ Similarly the thermostat values are also sent as a JSON package with the topic `
`{"thermostat_currtemp":"19.8","thermostat_seltemp":"16.0","thermostat_mode":"manual"}`
If MQTT is not used set the MQTT_HOST to `NULL`.
These incoming MQTT topics are also handled:
| topic | ID in my_config.h | Payload | Description |
| ------------------- | ------------------------- | ---------------------- | ---------------------------------------- |
| thermostat_cmd_temp | TOPIC_THERMOSTAT_CMD_TEMP | temperature as a float | sets the thermostat current setpoint |
| thermostat_cmd_mode | TOPIC_THERMOSTAT_CMD_MODE | auto, day, night | sets the thermostat mode |
| wwactivated | TOPIC_BOILER_WWACTIVATED | 0 or 1 | turns boiler warm water on/off (not tap) |
If MQTT is not used use 'set mqtt_host' to remove it.
Some home automation systems such as Domoticz and OpenHab have special formats for their MQTT messages so I would advise to use [node-red](https://nodered.org/) as a parser like in [this example](https://www.domoticz.com/forum/download/file.php?id=18977&sid=67d048f1b4c8833822175eac6b55ecff).
@@ -305,9 +313,11 @@ pre-baked firmwares for some ESP8266 devices are available in the directory `/fi
3. Connect the ESP via USB, figure out the COM port
4. run `esptool.py -p <com> write_flash 0x00000 <firmware>` where firmware is the `.bin` file and \<com\> is the COM port, e.g. `COM3`
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 command to configure your own network settings. Alternatively connect the ESP8266 to your PC and open a Serial monitor to configure the settings. Make sure you disable Serial support before connecting the EMS lines using `set serial off`.
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 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 show all settings.
`set erase` will clear all settings.
`set` wil list all currently stored settings.
## Troubleshooting

View File

@@ -410,9 +410,11 @@ void MyESP::_consoleShowHelp() {
SerialAndTelnet.println(FPSTR("*"));
SerialAndTelnet.println(FPSTR("* Commands:"));
SerialAndTelnet.println(FPSTR("* ?=help, CTRL-D=quit, !=reboot"));
SerialAndTelnet.println(FPSTR("* ?=help, CTRL-D=quit"));
SerialAndTelnet.println(FPSTR("* reboot"));
SerialAndTelnet.println(FPSTR("* set"));
SerialAndTelnet.println(FPSTR("* set <wifi_ssid | wifi_password | mqtt_host | mqtt_username | mqtt_password> [value]"));
SerialAndTelnet.println(FPSTR("* set wifi <ssid> <password>"));
SerialAndTelnet.println(FPSTR("* set <mqtt_host | mqtt_username | mqtt_password> [value]"));
SerialAndTelnet.println(FPSTR("* set erase"));
SerialAndTelnet.println(FPSTR("* set serial"));
@@ -456,8 +458,32 @@ char * MyESP::_telnet_readWord() {
return word;
}
// change setting for 2 params (set <command> <value1> <value2>)
void MyESP::_changeSetting2(const char * setting, const char * value1, const char * value2) {
if (strcmp(setting, "wifi") == 0) {
if (_wifi_ssid)
free(_wifi_ssid);
if (_wifi_password)
free(_wifi_password);
_wifi_ssid = NULL;
_wifi_password = NULL;
if (value1) {
_wifi_ssid = strdup(value1);
}
if (value2) {
_wifi_password = strdup(value2);
}
(void)fs_saveConfig();
SerialAndTelnet.println("Wifi credentials set. Type 'reboot' to restart...");
}
}
// change settings - always as strings
// messy code but effective since we don't have too many settings
// wc is word count, number of parameters after the 'set' command
void MyESP::_changeSetting(uint8_t wc, const char * setting, const char * value) {
bool ok = false;
@@ -465,24 +491,14 @@ void MyESP::_changeSetting(uint8_t wc, const char * setting, const char * value)
if (strcmp(setting, "erase") == 0) {
_fs_eraseConfig();
return;
}
if (strcmp(setting, "wifi_ssid") == 0) {
} else if ((strcmp(setting, "wifi") == 0) && (wc == 1)) { // erase wifi settings
if (_wifi_ssid)
free(_wifi_ssid);
_wifi_ssid = NULL; // just to be sure
if (value) {
_wifi_ssid = strdup(value);
}
ok = true;
} else if (strcmp(setting, "wifi_password") == 0) {
if (_wifi_password)
free(_wifi_password);
_wifi_password = NULL; // just to be sure
if (value) {
_wifi_password = strdup(value);
}
ok = true;
_wifi_ssid = NULL;
_wifi_password = NULL;
ok = true;
} else if (strcmp(setting, "mqtt_host") == 0) {
if (_mqtt_host)
free(_mqtt_host);
@@ -533,16 +549,14 @@ void MyESP::_changeSetting(uint8_t wc, const char * setting, const char * value)
// check for 2 params
if (value == nullptr) {
SerialAndTelnet.printf("%s setting reset to its default value", setting);
SerialAndTelnet.printf("%s setting reset to its default value.", setting);
} else {
// must be 3 params
SerialAndTelnet.printf("%s changed to %s", setting, value);
SerialAndTelnet.printf("%s changed.", setting);
}
SerialAndTelnet.println();
if (fs_saveConfig()) {
SerialAndTelnet.println("Note, some changes will only have effect after the ESP is restarted (use ! command)");
}
(void)fs_saveConfig();
}
void MyESP::_telnetCommand(char * commandLine) {
@@ -563,13 +577,13 @@ void MyESP::_telnetCommand(char * commandLine) {
// check first for reserved commands
char * temp = strdup(commandLine); // because strotok kills original string buffer
char * ptrToCommandName = strtok((char *)temp, ", \n");
// set command
if (strcmp(ptrToCommandName, "set") == 0) {
if (wc == 1) {
SerialAndTelnet.println();
SerialAndTelnet.println("Stored settings:");
SerialAndTelnet.printf(" wifi_ssid=%s", (!_wifi_ssid) ? "<not set>" : _wifi_ssid);
SerialAndTelnet.println();
SerialAndTelnet.printf(" wifi_password=");
SerialAndTelnet.printf(" wifi=%s ", (!_wifi_ssid) ? "<not set>" : _wifi_ssid);
if (!_wifi_password) {
SerialAndTelnet.print("<not set>");
} else {
@@ -598,7 +612,7 @@ void MyESP::_telnetCommand(char * commandLine) {
(_fs_settings_callback)(MYESP_FSACTION_LIST, 0, NULL, NULL);
SerialAndTelnet.println();
SerialAndTelnet.println("Usage: set <setting> [value]");
SerialAndTelnet.println("Usage: set <setting> [value...]");
} else if (wc == 2) {
char * setting = _telnet_readWord();
_changeSetting(1, setting, NULL);
@@ -606,10 +620,20 @@ void MyESP::_telnetCommand(char * commandLine) {
char * setting = _telnet_readWord();
char * value = _telnet_readWord();
_changeSetting(2, setting, value);
} else if (wc == 4) {
char * setting = _telnet_readWord();
char * value1 = _telnet_readWord();
char * value2 = _telnet_readWord();
_changeSetting2(setting, value1, value2);
}
return;
}
// reboot command
if ((strcmp(ptrToCommandName, "reboot") == 0) && (wc == 1)) {
resetESP();
}
// call callback function
(_telnetcommand_callback)(wc, commandLine);
}
@@ -632,7 +656,7 @@ void MyESP::_telnetHandle() {
case '\n':
_command[charsRead] = '\0'; // null terminate our command char array
if (charsRead > 0) {
charsRead = 0; // is static, so have to reset
charsRead = 0; // is static, so have to reset
_suspendOutput = false;
if (_use_serial) {
SerialAndTelnet.println(); // force newline if in Telnet
@@ -640,19 +664,20 @@ void MyESP::_telnetHandle() {
_telnetCommand(_command);
}
break;
case '\b': // handle backspace in input: put a space in last char
if (charsRead > 0) { // and adjust commandLine and charsRead
case '\b': // handle backspace in input: put a space in last char
if (charsRead > 0) {
_command[--charsRead] = '\0';
SerialAndTelnet << byte('\b') << byte(' ') << byte('\b'); //no idea how this works, found it on the Internet
SerialAndTelnet << byte('\b') << byte(' ') << byte('\b');
}
break;
case '?':
_consoleShowHelp();
if (!_suspendOutput) {
_consoleShowHelp();
} else {
_command[charsRead++] = c; // add it to buffer as its part of the string entered
}
break;
case '!':
resetESP();
break;
case 0x04: // EOT
case 0x04: // EOT, CTRL-D
myDebug_P(PSTR("* exiting telnet session"));
SerialAndTelnet.disconnectClient();
break;
@@ -825,7 +850,7 @@ void MyESP::_fs_eraseConfig() {
myDebug_P(PSTR("[FS] Erasing settings, please wait a few seconds. ESP will automatically restart when finished."));
if (SPIFFS.format()) {
delay(2000); // wait 2 seconds
delay(1000); // wait 1 seconds
resetESP();
}
}
@@ -928,7 +953,7 @@ void MyESP::_fs_setup() {
return;
}
//_fs_printConfig(); // for debugging
// _fs_printConfig(); // for debugging
// load the config file. if it doesn't exist create it
if (!_fs_loadConfig()) {

View File

@@ -178,6 +178,7 @@ class MyESP {
telnetcommand_callback_f _telnetcommand_callback; // Callable for projects commands
telnet_callback_f _telnet_callback; // callback for connect/disconnect
void _changeSetting(uint8_t wc, const char * setting, const char * value);
void _changeSetting2(const char * setting, const char * value1, const char * value2);
// fs
void _fs_setup();

View File

@@ -82,7 +82,6 @@ command_t PROGMEM project_cmds[] = {
{"set dallas_gpio <pin>", "set the pin for the external Dallas temperature sensor (D5=14)"},
{"set thermostat_type <hex type ID>", "set the thermostat type id (e.g. 10 for 0x10)"},
{"set boiler_type <hex type ID>", "set the boiler type id (e.g. 8 for 0x08)"},
{"info", "show the values"},
{"log <n | b | t | r | v>", "set logging mode to none, basic, thermostat only, raw or verbose"},
{"publish", "publish values to MQTT"},
@@ -845,6 +844,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
if (type == MQTT_CONNECT_EVENT) {
myESP.mqttSubscribe(TOPIC_THERMOSTAT_CMD_TEMP);
myESP.mqttSubscribe(TOPIC_THERMOSTAT_CMD_MODE);
myESP.mqttSubscribe(TOPIC_BOILER_WWACTIVATED);
myESP.mqttSubscribe(TOPIC_SHOWER_TIMER);
myESP.mqttSubscribe(TOPIC_SHOWER_ALERT);
myESP.mqttSubscribe(TOPIC_SHOWER_COLDSHOT);
@@ -888,6 +888,16 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
}
}
// wwActivated
if (strcmp(topic, TOPIC_BOILER_WWACTIVATED) == 0) {
if (message[0] == '1') {
ems_setWarmWaterActivated(true);
} else if (message[0] == '0') {
ems_setWarmWaterActivated(false);
}
publishValues(true); // publish back immediately
}
// shower timer
if (strcmp(topic, TOPIC_SHOWER_TIMER) == 0) {
if (message[0] == '1') {

View File

@@ -768,9 +768,10 @@ void _processType(uint8_t * telegram, uint8_t length) {
EMS_Sys_Status.emsTxStatus = EMS_TX_STATUS_IDLE;
// at this point we can assume Txstatus is EMS_TX_STATUS_WAIT
// for READ, WRITE or VALIDATE the dest is always us, so check this
// if not just process and quit
// for READ, WRITE or VALIDATE the dest (telegram[1]) is always us, so check for this
// if not we probably didn't get any response so remove the last Tx from the queue and process the telegram
if ((telegram[1] & 0x7F) != EMS_ID_ME) {
_removeTxQueue();
_ems_processTelegram(telegram, length);
return;
}
@@ -1443,11 +1444,7 @@ char * ems_getBoilerDescription(char * buffer) {
* Find the versions of our connected devices
*/
void ems_scanDevices() {
myDebug("Scanning EMS bus for devices...");
// start refresh when scanning and forget anything devices we may have already set
EMS_Thermostat.type_id = EMS_ID_NONE; // forget thermostat
EMS_Thermostat.model_id = EMS_MODEL_NONE;
myDebug("Scanning EMS bus for devices.");
std::list<uint8_t> Device_Ids; // new list

View File

@@ -23,17 +23,18 @@
#define MQTT_QOS 1
// MQTT for thermostat
#define TOPIC_THERMOSTAT_DATA "thermostat_data" // for sending thermostat values
#define TOPIC_THERMOSTAT_CMD_TEMP "thermostat_cmd_temp" // for received thermostat temp changes
#define TOPIC_THERMOSTAT_CMD_MODE "thermostat_cmd_mode" // for received thermostat mode changes
#define TOPIC_THERMOSTAT_DATA "thermostat_data" // for sending thermostat values to MQTT
#define TOPIC_THERMOSTAT_CMD_TEMP "thermostat_cmd_temp" // for received thermostat temp changes via MQTT
#define TOPIC_THERMOSTAT_CMD_MODE "thermostat_cmd_mode" // for received thermostat mode changes via MQTT
#define THERMOSTAT_CURRTEMP "thermostat_currtemp" // current temperature
#define THERMOSTAT_SELTEMP "thermostat_seltemp" // selected temperature
#define THERMOSTAT_MODE "thermostat_mode" // mode
// MQTT for boiler
#define TOPIC_BOILER_DATA "boiler_data" // for sending boiler values
#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
// shower time
#define TOPIC_SHOWERTIME "showertime" // for sending shower time results

View File

@@ -6,5 +6,5 @@
#pragma once
#define APP_NAME "EMS-ESP"
#define APP_VERSION "1.5.1"
#define APP_VERSION "1.5.2"
#define APP_HOSTNAME "ems-esp"