mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 07:49:52 +03:00
version 1.4.0. See ChangeLog
This commit is contained in:
14
CHANGELOG.md
14
CHANGELOG.md
@@ -5,6 +5,20 @@ 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/),
|
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).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.4.0] 2019-01-27
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- last will MQTT topic prefixed with a header like the rest of the topics
|
||||||
|
- All double and float numbers rendered to 2 decimal places (precision = 2)
|
||||||
|
- Default logging set to None when starting a telnet session
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added support for external Dallas sensors (DS1822, DS18S20, DS18B20, DS1825). See readme
|
||||||
|
- Added UBAParametersMessage type to fetch boiler modulation min & max values
|
||||||
|
- Report shows system load average
|
||||||
|
|
||||||
## [1.3.2] 2019-01-23
|
## [1.3.2] 2019-01-23
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
28
README.md
28
README.md
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
EMS-ESP is a project to build an electronic controller circuit using an Espressif ESP8266 microcontroller to communicate with EMS (Energy Management System) based Boilers and Thermostats from the Bosch range and compatibles such as Buderus, Nefit, Junkers etc.
|
EMS-ESP is a project to build an electronic controller circuit using an Espressif ESP8266 microcontroller to communicate with EMS (Energy Management System) based Boilers and Thermostats from the Bosch range and compatibles such as Buderus, Nefit, Junkers etc.
|
||||||
|
|
||||||
There are 3 parts to this project, first the design of the circuit, secondly the code for the ESP8266 microcontroller firmware and lastly an example configuration for Home Assistant to monitor the data and issue direct commands via MQTT.
|
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.
|
||||||
|
|
||||||
[](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)
|
[](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)
|
||||||
[](CHANGELOG.md)
|
[](CHANGELOG.md)
|
||||||
|
|
||||||
- [EMS-ESP](#ems-esp)
|
- [EMS-ESP](#ems-esp)
|
||||||
- [Introduction](#introduction)
|
- [Introduction](#introduction)
|
||||||
@@ -15,6 +15,7 @@ There are 3 parts to this project, first the design of the circuit, secondly the
|
|||||||
- [Monitoring The Output](#monitoring-the-output)
|
- [Monitoring The Output](#monitoring-the-output)
|
||||||
- [Building The Circuit](#building-the-circuit)
|
- [Building The Circuit](#building-the-circuit)
|
||||||
- [Powering The EMS Circuit](#powering-the-ems-circuit)
|
- [Powering The EMS Circuit](#powering-the-ems-circuit)
|
||||||
|
- [Adding external temperature sensors](#adding-external-temperature-sensors)
|
||||||
- [How The EMS Bus Works](#how-the-ems-bus-works)
|
- [How The EMS Bus Works](#how-the-ems-bus-works)
|
||||||
- [EMS IDs](#ems-ids)
|
- [EMS IDs](#ems-ids)
|
||||||
- [EMS Polling](#ems-polling)
|
- [EMS Polling](#ems-polling)
|
||||||
@@ -115,6 +116,10 @@ The EMS circuit will work with both 3.3V and 5V. It's easiest though to power di
|
|||||||
| ------------------------------------------ |
|
| ------------------------------------------ |
|
||||||
|  |
|
|  |
|
||||||
|
|
||||||
|
## Adding external temperature sensors
|
||||||
|
|
||||||
|
The code supports auto-detection of Dallas type temperature sensors. The default gpio pin (DQ) to the ESP8266 is D5 but this can be configured in `my_config.h`. The dallas chips DS1822, DS18S20, DS18B20, DS1825 are supported including their parasite varieties.
|
||||||
|
|
||||||
## How The EMS Bus Works
|
## How The EMS Bus Works
|
||||||
|
|
||||||
Packages are streamed to the EMS "bus" from any other compatible connected device via serial TTL transmission using protocol 9600 baud, 8N1 (8 bytes, no parity, 1 stop bit). Each package is terminated with a break signal `<BRK>`, a 11-bit long low signal of zeros.
|
Packages are streamed to the EMS "bus" from any other compatible connected device via serial TTL transmission using protocol 9600 baud, 8N1 (8 bytes, no parity, 1 stop bit). Each package is terminated with a break signal `<BRK>`, a 11-bit long low signal of zeros.
|
||||||
@@ -203,11 +208,11 @@ In `ems.cpp` you can add scheduled calls to specific EMS types in the functions
|
|||||||
|
|
||||||
### Which thermostats are supported?
|
### Which thermostats are supported?
|
||||||
|
|
||||||
I am still working on adding more support to known thermostats. Any contributions here are welcome. The know types are listed in `ems_devices.h`.
|
I am still working on adding more support to known thermostats. Any contributions here are welcome. The know types are listed in `ems_devices.h` and include
|
||||||
|
|
||||||
- RC20 and RC30 are fully supported
|
- RC20 and RC30, both are fully supported
|
||||||
- RC35 only supports the 1st heating circuit (HC1)
|
- RC35 with support for the 1st heating circuit (HC1)
|
||||||
- TC100/TC200/Easy has only support for reading the temperatures. There seems to be no way to set settings using EMS bus messages. One option is to send XMPP messages but a client is needed.
|
- TC100/TC200/Easy but only with support for reading the temperatures. There seems to be no way to set settings using EMS bus messages that I know of. One option is to send XMPP messages but a special server is needed and out of scope for this project.
|
||||||
|
|
||||||
### Customizing The Code
|
### Customizing The Code
|
||||||
|
|
||||||
@@ -219,16 +224,18 @@ I am still working on adding more support to known thermostats. Any contribution
|
|||||||
|
|
||||||
### Using MQTT
|
### Using MQTT
|
||||||
|
|
||||||
The boiler data is collected and sent as a single JSON object to MQTT TOPIC `home/ems-esp/boiler_data`. The `home` preifx is the MQTT topic prefix and can be customized in `my_config.h`. A hash is generated (CRC32 based) to determine if the payload has changed, otherwise don't send it. An example payload looks roughly like:
|
The boiler data is collected and sent as a single JSON object to MQTT TOPIC `home/ems-esp/boiler_data`. The `home` preifx is the MQTT topic prefix and can be customized in `my_config.h`. A hash is generated (CRC32 based) to determine if the payload has changed, otherwise it will not be sent. An example payload looks like:
|
||||||
|
|
||||||
`{"wWSelTemp":"60","selFlowTemp":"5.0","outdoorTemp":"?","wWActivated":"on","wWComfort":"Comfort","wWCurTmp":"46.0","wWCurFlow":"0.0","wWHeat":"on","curFlowTemp":"54.2","retTemp":"51.5","burnGas":"off","heatPmp":"off","fanWork":"off","ignWork":"off","wWCirc":"off","selBurnPow":"0","curBurnPow":"0","sysPress":"1.2","boilTemp":"56.7","pumpMod":"0","ServiceCode":"0H"}`
|
`{"wWSelTemp":"60","selFlowTemp":"5.0","outdoorTemp":"?","wWActivated":"on","wWComfort":"Comfort","wWCurTmp":"46.0","wWCurFlow":"0.0","wWHeat":"on","curFlowTemp":"54.2","retTemp":"51.5","burnGas":"off","heatPmp":"off","fanWork":"off","ignWork":"off","wWCirc":"off","selBurnPow":"0","curBurnPow":"0","sysPress":"1.2","boilTemp":"56.7","pumpMod":"0","ServiceCode":"0H"}`
|
||||||
|
|
||||||
Similarly the thermostat values are sent as a JSON package under the topic `home/ems-esp/thermostat_data` with the current mode, room temperature and set temperature like
|
Similarly the thermostat values are also sent as a JSON package with the topic `home/ems-esp/thermostat_data` along with the current mode, room temperature and set temperature:
|
||||||
|
|
||||||
`{"thermostat_currtemp":"19.8","thermostat_seltemp":"16.0","thermostat_mode":"manual"}`
|
`{"thermostat_currtemp":"19.8","thermostat_seltemp":"16.0","thermostat_mode":"manual"}`
|
||||||
|
|
||||||
If MQTT is not used set the MQTT_HOST to `NULL`.
|
If MQTT is not used set the MQTT_HOST to `NULL`.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
### The Basic Shower Logic
|
### The Basic Shower Logic
|
||||||
|
|
||||||
Checking whether the shower is running is tricky. We know when the warm water is on and being heated but need to distinguish between the central heating, shower, hot tap and even a bath tap. So this code is a little experimental.
|
Checking whether the shower is running is tricky. We know when the warm water is on and being heated but need to distinguish between the central heating, shower, hot tap and even a bath tap. So this code is a little experimental.
|
||||||
@@ -284,7 +291,7 @@ Porting to the Arduino IDE can be a little tricky but it is possible.
|
|||||||
- Add the ESP8266 boards (from Preferences add Additional Board URL `http://arduino.esp8266.com/stable/package_esp8266com_index.json`)
|
- Add the ESP8266 boards (from Preferences add Additional Board URL `http://arduino.esp8266.com/stable/package_esp8266com_index.json`)
|
||||||
- Go to Boards Manager and install ESP8266 2.4.x platform
|
- Go to Boards Manager and install ESP8266 2.4.x platform
|
||||||
- Select your ESP8266 from Tools->Boards and the correct port with Tools->Port
|
- Select your ESP8266 from Tools->Boards and the correct port with Tools->Port
|
||||||
- From the Library Manager install the needed libraries from platformio.ini. Note make sure you pick ArduinoJson v5 and not v6. See https://arduinojson.org/v5/doc/
|
- From the Library Manager install the needed libraries from platformio.ini. Note make sure you pick ArduinoJson v5 (5.13.4 and above) and not v6. See https://arduinojson.org/v5/doc/
|
||||||
- Put all the files in a single sketch folder
|
- Put all the files in a single sketch folder
|
||||||
- cross your fingers and hit CTRL-R to compile
|
- cross your fingers and hit CTRL-R to compile
|
||||||
|
|
||||||
@@ -320,9 +327,8 @@ Some annoying issues that need fixing:
|
|||||||
- https://github.com/patvdleer/nefit-client-python
|
- https://github.com/patvdleer/nefit-client-python
|
||||||
- https://github.com/marconfus/ha-nefit
|
- https://github.com/marconfus/ha-nefit
|
||||||
- https://github.com/robertklep/nefit-easy-core
|
- https://github.com/robertklep/nefit-easy-core
|
||||||
- Add support for a temperature sensor on the circuit (DS18B20)
|
|
||||||
- Improve detection of Heating Off without checking for selFlowTemp (selected flow temperature)
|
- Improve detection of Heating Off without checking for selFlowTemp (selected flow temperature)
|
||||||
- Split MQTT into smaller chunks. Now the messages can be up to 600 bytes which may cause issues.
|
- Split MQTT into smaller chunks. Now the messages can be up to 600 bytes which may cause issues. Preferably make the items configurable.
|
||||||
|
|
||||||
## Your Comments and Feedback
|
## Your Comments and Feedback
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -13,7 +13,9 @@ MyESP::MyESP() {
|
|||||||
_app_hostname = strdup("MyESP");
|
_app_hostname = strdup("MyESP");
|
||||||
_app_name = strdup("MyESP");
|
_app_name = strdup("MyESP");
|
||||||
_app_version = strdup("1.0.0");
|
_app_version = strdup("1.0.0");
|
||||||
|
|
||||||
_boottime = strdup("unknown");
|
_boottime = strdup("unknown");
|
||||||
|
_load_average = 100; // calculated load average
|
||||||
|
|
||||||
_telnetcommand_callback = NULL;
|
_telnetcommand_callback = NULL;
|
||||||
_telnet_callback = NULL;
|
_telnet_callback = NULL;
|
||||||
@@ -33,6 +35,7 @@ MyESP::MyESP() {
|
|||||||
_mqtt_will_topic = NULL;
|
_mqtt_will_topic = NULL;
|
||||||
_mqtt_will_payload = NULL;
|
_mqtt_will_payload = NULL;
|
||||||
_mqtt_base = NULL;
|
_mqtt_base = NULL;
|
||||||
|
_mqtt_topic = NULL;
|
||||||
_mqtt_qos = 0;
|
_mqtt_qos = 0;
|
||||||
_mqtt_reconnect_delay = MQTT_RECONNECT_DELAY_MIN;
|
_mqtt_reconnect_delay = MQTT_RECONNECT_DELAY_MIN;
|
||||||
|
|
||||||
@@ -180,10 +183,8 @@ void MyESP::_mqttOnMessage(char * topic, char * payload, size_t len) {
|
|||||||
// to MQTT_BASE/app_hostname/topic
|
// to MQTT_BASE/app_hostname/topic
|
||||||
void MyESP::mqttSubscribe(const char * topic) {
|
void MyESP::mqttSubscribe(const char * topic) {
|
||||||
if (mqttClient.connected() && (strlen(topic) > 0)) {
|
if (mqttClient.connected() && (strlen(topic) > 0)) {
|
||||||
char s[100];
|
unsigned int packetId = mqttClient.subscribe(_mqttTopic(topic), _mqtt_qos);
|
||||||
snprintf(s, sizeof(s), "%s/%s/%s", _mqtt_base, _app_hostname, topic);
|
myDebug_P(PSTR("[MQTT] Subscribing to %s (PID %d)"), _mqttTopic(topic), packetId);
|
||||||
unsigned int packetId = mqttClient.subscribe(s, _mqtt_qos);
|
|
||||||
myDebug_P(PSTR("[MQTT] Subscribing to %s (PID %d)"), s, packetId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,19 +192,15 @@ void MyESP::mqttSubscribe(const char * topic) {
|
|||||||
// to MQTT_BASE/app_hostname/topic
|
// to MQTT_BASE/app_hostname/topic
|
||||||
void MyESP::mqttUnsubscribe(const char * topic) {
|
void MyESP::mqttUnsubscribe(const char * topic) {
|
||||||
if (mqttClient.connected() && (strlen(topic) > 0)) {
|
if (mqttClient.connected() && (strlen(topic) > 0)) {
|
||||||
char s[100];
|
unsigned int packetId = mqttClient.unsubscribe(_mqttTopic(topic));
|
||||||
snprintf(s, sizeof(s), "%s/%s/%s", _mqtt_base, _app_hostname, topic);
|
myDebug_P(PSTR("[MQTT] Unsubscribing to %s (PID %d)"), _mqttTopic(topic), packetId);
|
||||||
unsigned int packetId = mqttClient.unsubscribe(s);
|
|
||||||
myDebug_P(PSTR("[MQTT] Unsubscribing to %s (PID %d)"), s, packetId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MQTT Publish
|
// MQTT Publish
|
||||||
void MyESP::mqttPublish(const char * topic, const char * payload) {
|
void MyESP::mqttPublish(const char * topic, const char * payload) {
|
||||||
char s[MQTT_MAX_SIZE];
|
// myDebug_P(PSTR("[MQTT] Sending pubish to %s with payload %s"), _mqttTopic(topic), payload);
|
||||||
snprintf(s, sizeof(s), "%s/%s/%s", _mqtt_base, _app_hostname, topic);
|
mqttClient.publish(_mqttTopic(topic), _mqtt_qos, _mqtt_retain, payload);
|
||||||
// myDebug_P(PSTR("[MQTT] Sending pubish to %s with payload %s"), s, payload);
|
|
||||||
mqttClient.publish(s, _mqtt_qos, _mqtt_retain, payload);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MQTT onConnect - when a connect is established
|
// MQTT onConnect - when a connect is established
|
||||||
@@ -227,7 +224,7 @@ void MyESP::_mqtt_setup() {
|
|||||||
|
|
||||||
mqttClient.onDisconnect([this](AsyncMqttClientDisconnectReason reason) {
|
mqttClient.onDisconnect([this](AsyncMqttClientDisconnectReason reason) {
|
||||||
if (reason == AsyncMqttClientDisconnectReason::TCP_DISCONNECTED) {
|
if (reason == AsyncMqttClientDisconnectReason::TCP_DISCONNECTED) {
|
||||||
myDebug_P(PSTR("[MQTT] 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) {
|
if (reason == AsyncMqttClientDisconnectReason::MQTT_IDENTIFIER_REJECTED) {
|
||||||
@@ -394,8 +391,9 @@ void MyESP::_consoleShowHelp() {
|
|||||||
SerialAndTelnet.printf("* Connected to WiFi SSID: %s\n\r", WiFi.SSID().c_str());
|
SerialAndTelnet.printf("* Connected to WiFi SSID: %s\n\r", WiFi.SSID().c_str());
|
||||||
SerialAndTelnet.printf("* Boot time: %s\n\r", _boottime);
|
SerialAndTelnet.printf("* Boot time: %s\n\r", _boottime);
|
||||||
}
|
}
|
||||||
|
SerialAndTelnet.printf("* Free RAM:%d KB, Load:%d%%\n\r", (ESP.getFreeHeap() / 1024), getSystemLoadAverage());
|
||||||
|
// for battery power is ESP.getVcc()
|
||||||
|
|
||||||
SerialAndTelnet.printf("* Free RAM: %d bytes\n\r", ESP.getFreeHeap());
|
|
||||||
#ifdef DEBUG_SUPPORT
|
#ifdef DEBUG_SUPPORT
|
||||||
SerialAndTelnet.println("* Warning: in DEBUG_SUPPORT mode!");
|
SerialAndTelnet.println("* Warning: in DEBUG_SUPPORT mode!");
|
||||||
#endif
|
#endif
|
||||||
@@ -425,6 +423,8 @@ void MyESP::_consoleShowHelp() {
|
|||||||
SerialAndTelnet.println(FPSTR(_helpProjectCmds[i].description));
|
SerialAndTelnet.println(FPSTR(_helpProjectCmds[i].description));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SerialAndTelnet.println(); // newline
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset / restart
|
// reset / restart
|
||||||
@@ -561,7 +561,7 @@ void MyESP::_telnetCommand(char * commandLine) {
|
|||||||
// print custom settings
|
// print custom settings
|
||||||
(_fs_settings_callback)(MYESP_FSACTION_LIST, 0, NULL, NULL);
|
(_fs_settings_callback)(MYESP_FSACTION_LIST, 0, NULL, NULL);
|
||||||
|
|
||||||
SerialAndTelnet.println("\n\rUsage: set <setting> <value>");
|
SerialAndTelnet.println("\n\rUsage: set <setting> [value]");
|
||||||
} else if (wc == 2) {
|
} else if (wc == 2) {
|
||||||
char * setting = _telnet_readWord();
|
char * setting = _telnet_readWord();
|
||||||
_changeSetting(1, setting, NULL);
|
_changeSetting(1, setting, NULL);
|
||||||
@@ -647,10 +647,15 @@ void MyESP::_mqttConnect() {
|
|||||||
mqttClient.setClientId(_app_hostname);
|
mqttClient.setClientId(_app_hostname);
|
||||||
mqttClient.setKeepAlive(_mqtt_keepalive);
|
mqttClient.setKeepAlive(_mqtt_keepalive);
|
||||||
mqttClient.setCleanSession(false);
|
mqttClient.setCleanSession(false);
|
||||||
mqttClient.setWill(_mqtt_will_topic, _mqtt_qos, _mqtt_retain, _mqtt_will_payload);
|
|
||||||
|
// 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), _mqtt_qos, _mqtt_retain, _mqtt_will_payload);
|
||||||
|
}
|
||||||
|
|
||||||
if (_mqtt_username && _mqtt_password) {
|
if (_mqtt_username && _mqtt_password) {
|
||||||
myDebug_P(PSTR("[MQTT] Connecting to MQTT using user %s"), _mqtt_username);
|
myDebug_P(PSTR("[MQTT] Connecting to MQTT using user %s..."), _mqtt_username);
|
||||||
mqttClient.setCredentials(_mqtt_username, _mqtt_password);
|
mqttClient.setCredentials(_mqtt_username, _mqtt_password);
|
||||||
} else {
|
} else {
|
||||||
myDebug_P(PSTR("[MQTT] Connecting to MQTT..."));
|
myDebug_P(PSTR("[MQTT] Connecting to MQTT..."));
|
||||||
@@ -720,7 +725,7 @@ void MyESP::setMQTT(char * mqtt_host,
|
|||||||
// callback
|
// callback
|
||||||
_mqtt_callback = callback;
|
_mqtt_callback = callback;
|
||||||
|
|
||||||
// other mqtt settings
|
// various mqtt settings
|
||||||
_mqtt_keepalive = mqtt_keepalive;
|
_mqtt_keepalive = mqtt_keepalive;
|
||||||
_mqtt_qos = mqtt_qos;
|
_mqtt_qos = mqtt_qos;
|
||||||
_mqtt_retain = mqtt_retain;
|
_mqtt_retain = mqtt_retain;
|
||||||
@@ -731,7 +736,6 @@ void MyESP::setMQTT(char * mqtt_host,
|
|||||||
} else {
|
} else {
|
||||||
_mqtt_will_topic = strdup(mqtt_will_topic);
|
_mqtt_will_topic = strdup(mqtt_will_topic);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mqtt_will_payload || *mqtt_will_payload == 0x00) {
|
if (!mqtt_will_payload || *mqtt_will_payload == 0x00) {
|
||||||
_mqtt_will_payload = NULL;
|
_mqtt_will_payload = NULL;
|
||||||
} else {
|
} else {
|
||||||
@@ -739,6 +743,27 @@ void MyESP::setMQTT(char * mqtt_host,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// builds up a topic by prefixing the base and hostname
|
||||||
|
char * MyESP::_mqttTopic(const char * topic) {
|
||||||
|
char buffer[MQTT_MAX_TOPIC_SIZE] = {0};
|
||||||
|
|
||||||
|
strlcpy(buffer, _mqtt_base, sizeof(buffer));
|
||||||
|
strlcat(buffer, "/", sizeof(buffer));
|
||||||
|
strlcat(buffer, _app_hostname, sizeof(buffer));
|
||||||
|
strlcat(buffer, "/", sizeof(buffer));
|
||||||
|
strlcat(buffer, topic, sizeof(buffer));
|
||||||
|
|
||||||
|
//snprintf(buffer, sizeof(buffer), "%s/%s/%s", _mqtt_base, _app_hostname, topic);
|
||||||
|
|
||||||
|
if (_mqtt_topic) {
|
||||||
|
free(_mqtt_topic);
|
||||||
|
}
|
||||||
|
_mqtt_topic = strdup(buffer);
|
||||||
|
|
||||||
|
return _mqtt_topic;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// print contents of file
|
// print contents of file
|
||||||
void MyESP::_fs_printConfig() {
|
void MyESP::_fs_printConfig() {
|
||||||
File configFile = SPIFFS.open("/config.json", "r");
|
File configFile = SPIFFS.open("/config.json", "r");
|
||||||
@@ -754,7 +779,7 @@ void MyESP::_fs_printConfig() {
|
|||||||
|
|
||||||
// format File System
|
// format File System
|
||||||
void MyESP::_fs_eraseConfig() {
|
void MyESP::_fs_eraseConfig() {
|
||||||
myDebug_P(PSTR("[FS] Erasing settings. Please wait. ESP will automatically restart when finished."));
|
myDebug_P(PSTR("[FS] Erasing settings, please wait. ESP will automatically restart when finished."));
|
||||||
|
|
||||||
if (SPIFFS.format()) {
|
if (SPIFFS.format()) {
|
||||||
resetESP();
|
resetESP();
|
||||||
@@ -855,6 +880,30 @@ void MyESP::_fs_setup() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned long MyESP::getSystemLoadAverage() {
|
||||||
|
return _load_average;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate load average
|
||||||
|
void MyESP::_calculateLoad() {
|
||||||
|
static unsigned long last_loadcheck = 0;
|
||||||
|
static unsigned long 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;
|
||||||
|
|
||||||
|
load_counter = load_counter_temp;
|
||||||
|
load_counter_temp = 0;
|
||||||
|
if (load_counter > load_counter_max) {
|
||||||
|
load_counter_max = load_counter;
|
||||||
|
}
|
||||||
|
_load_average = 100 - (100 * load_counter / load_counter_max);
|
||||||
|
last_loadcheck = millis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// register new instance
|
// register new instance
|
||||||
void MyESP::begin(char * app_hostname, char * app_name, char * app_version) {
|
void MyESP::begin(char * app_hostname, char * app_name, char * app_version) {
|
||||||
_app_hostname = strdup(app_hostname);
|
_app_hostname = strdup(app_hostname);
|
||||||
@@ -874,9 +923,12 @@ void MyESP::begin(char * app_hostname, char * app_name, char * app_version) {
|
|||||||
* Loop. This is called as often as possible and it handles wifi, telnet, mqtt etc
|
* Loop. This is called as often as possible and it handles wifi, telnet, mqtt etc
|
||||||
*/
|
*/
|
||||||
void MyESP::loop() {
|
void MyESP::loop() {
|
||||||
|
_calculateLoad(); // calculate load
|
||||||
|
|
||||||
jw.loop(); // WiFi
|
jw.loop(); // WiFi
|
||||||
_telnetHandle(); // Telnet/Debugger
|
_telnetHandle(); // Telnet/Debugger
|
||||||
|
|
||||||
|
// do nothing else until we've got a wifi connection
|
||||||
if (WiFi.getMode() & WIFI_AP) {
|
if (WiFi.getMode() & WIFI_AP) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,8 @@
|
|||||||
#include <ESP8266mDNS.h>
|
#include <ESP8266mDNS.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define LOADAVG_INTERVAL 30000 // Interval between calculating load average (in ms)
|
||||||
|
|
||||||
// WIFI
|
// WIFI
|
||||||
#define WIFI_CONNECT_TIMEOUT 10000 // Connecting timeout for WIFI in ms
|
#define WIFI_CONNECT_TIMEOUT 10000 // Connecting timeout for WIFI in ms
|
||||||
#define WIFI_RECONNECT_INTERVAL 60000 // If could not connect to WIFI, retry after this time in ms
|
#define WIFI_RECONNECT_INTERVAL 60000 // If could not connect to WIFI, retry after this time in ms
|
||||||
@@ -38,6 +40,8 @@
|
|||||||
#define MQTT_RECONNECT_DELAY_STEP 5000 // Increase the reconnect delay in 5 seconds after each failed attempt
|
#define MQTT_RECONNECT_DELAY_STEP 5000 // Increase the reconnect delay in 5 seconds after each failed attempt
|
||||||
#define MQTT_RECONNECT_DELAY_MAX 120000 // Set reconnect time to 2 minutes at most
|
#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_SIZE 600 // max length of MQTT message
|
||||||
|
#define MQTT_MAX_TOPIC_SIZE 50 // max length of MQTT message
|
||||||
|
|
||||||
// Internal MQTT events
|
// Internal MQTT events
|
||||||
#define MQTT_CONNECT_EVENT 0
|
#define MQTT_CONNECT_EVENT 0
|
||||||
#define MQTT_DISCONNECT_EVENT 1
|
#define MQTT_DISCONNECT_EVENT 1
|
||||||
@@ -111,11 +115,12 @@ class MyESP {
|
|||||||
void setSettings(fs_callback_f callback, fs_settings_callback_f fs_settings_callback);
|
void setSettings(fs_callback_f callback, fs_settings_callback_f fs_settings_callback);
|
||||||
|
|
||||||
// general
|
// general
|
||||||
void end();
|
void end();
|
||||||
void loop();
|
void loop();
|
||||||
void begin(char * app_hostname, char * app_name, char * app_version);
|
void begin(char * app_hostname, char * app_name, char * app_version);
|
||||||
void setBoottime(const char * boottime);
|
void setBoottime(const char * boottime);
|
||||||
void resetESP();
|
void resetESP();
|
||||||
|
unsigned long getSystemLoadAverage();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// mqtt
|
// mqtt
|
||||||
@@ -127,6 +132,7 @@ class MyESP {
|
|||||||
mqtt_callback_f _mqtt_callback;
|
mqtt_callback_f _mqtt_callback;
|
||||||
void _mqttOnConnect();
|
void _mqttOnConnect();
|
||||||
void _sendStart();
|
void _sendStart();
|
||||||
|
char * _mqttTopic(const char * topic);
|
||||||
char * _mqtt_host;
|
char * _mqtt_host;
|
||||||
char * _mqtt_username;
|
char * _mqtt_username;
|
||||||
char * _mqtt_password;
|
char * _mqtt_password;
|
||||||
@@ -138,6 +144,7 @@ class MyESP {
|
|||||||
bool _mqtt_retain;
|
bool _mqtt_retain;
|
||||||
char * _mqtt_will_topic;
|
char * _mqtt_will_topic;
|
||||||
char * _mqtt_will_payload;
|
char * _mqtt_will_payload;
|
||||||
|
char * _mqtt_topic;
|
||||||
|
|
||||||
// wifi
|
// wifi
|
||||||
DNSServer dnsServer; // For Access Point (AP) support
|
DNSServer dnsServer; // For Access Point (AP) support
|
||||||
@@ -182,6 +189,10 @@ class MyESP {
|
|||||||
char * _app_hostname;
|
char * _app_hostname;
|
||||||
char * _app_name;
|
char * _app_name;
|
||||||
char * _app_version;
|
char * _app_version;
|
||||||
|
|
||||||
|
// load average (0..100)
|
||||||
|
void _calculateLoad();
|
||||||
|
unsigned short int _load_average;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern MyESP myESP;
|
extern MyESP myESP;
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ lib_deps =
|
|||||||
JustWifi
|
JustWifi
|
||||||
AsyncMqttClient
|
AsyncMqttClient
|
||||||
ArduinoJson
|
ArduinoJson
|
||||||
|
OneWire
|
||||||
|
|
||||||
[env:nodemcuv2]
|
[env:nodemcuv2]
|
||||||
board = nodemcuv2
|
board = nodemcuv2
|
||||||
|
|||||||
221
src/ds18.cpp
Normal file
221
src/ds18.cpp
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
/*
|
||||||
|
* Dallas support for external settings
|
||||||
|
* Copied from Espurna - Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
|
||||||
|
*
|
||||||
|
* Paul Derbyshire - https://github.com/proddy/EMS-ESP
|
||||||
|
*
|
||||||
|
* See ChangeLog.md for history
|
||||||
|
* See README.md for Acknowledgments
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ds18.h"
|
||||||
|
|
||||||
|
std::vector<ds_device_t> _devices;
|
||||||
|
|
||||||
|
DS18::DS18() {
|
||||||
|
_wire = NULL;
|
||||||
|
_count = 0;
|
||||||
|
_gpio = GPIO_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
DS18::~DS18() {
|
||||||
|
if (_wire)
|
||||||
|
delete _wire;
|
||||||
|
}
|
||||||
|
|
||||||
|
// init
|
||||||
|
uint8_t DS18::setup(uint8_t gpio) {
|
||||||
|
uint8_t count;
|
||||||
|
|
||||||
|
_gpio = gpio;
|
||||||
|
|
||||||
|
// OneWire
|
||||||
|
if (_wire)
|
||||||
|
delete _wire;
|
||||||
|
_wire = new OneWire(_gpio);
|
||||||
|
|
||||||
|
// Search devices
|
||||||
|
count = loadDevices();
|
||||||
|
|
||||||
|
// If no devices found check again pulling up the line
|
||||||
|
if (count == 0) {
|
||||||
|
pinMode(_gpio, INPUT_PULLUP);
|
||||||
|
count = loadDevices();
|
||||||
|
}
|
||||||
|
|
||||||
|
_count = count;
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// scan every 2 seconds
|
||||||
|
void DS18::loop() {
|
||||||
|
static unsigned long last = 0;
|
||||||
|
if (millis() - last < DS18_READ_INTERVAL)
|
||||||
|
return;
|
||||||
|
last = millis();
|
||||||
|
|
||||||
|
// Every second we either start a conversion or read the scratchpad
|
||||||
|
static bool conversion = true;
|
||||||
|
if (conversion) {
|
||||||
|
// Start conversion
|
||||||
|
_wire->reset();
|
||||||
|
_wire->skip();
|
||||||
|
_wire->write(DS18_CMD_START_CONVERSION, DS18_PARASITE);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Read scratchpads
|
||||||
|
for (unsigned char index = 0; index < _devices.size(); index++) {
|
||||||
|
// Read scratchpad
|
||||||
|
if (_wire->reset() == 0) {
|
||||||
|
// Force a CRC check error
|
||||||
|
_devices[index].data[0] = _devices[index].data[0] + 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_wire->select(_devices[index].address);
|
||||||
|
_wire->write(DS18_CMD_READ_SCRATCHPAD);
|
||||||
|
|
||||||
|
uint8_t data[DS18_DATA_SIZE];
|
||||||
|
for (unsigned char i = 0; i < DS18_DATA_SIZE; i++) {
|
||||||
|
data[i] = _wire->read();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_wire->reset() != 1) {
|
||||||
|
// Force a CRC check error
|
||||||
|
_devices[index].data[0] = _devices[index].data[0] + 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(_devices[index].data, data, DS18_DATA_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
conversion = !conversion;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return string of the device, with name and address
|
||||||
|
char * DS18::getDeviceString(char * buffer, unsigned char index) {
|
||||||
|
uint8_t size = 128;
|
||||||
|
if (index < _count) {
|
||||||
|
uint8_t * address = _devices[index].address;
|
||||||
|
|
||||||
|
unsigned char chip_id = chip(index);
|
||||||
|
if (chip_id == DS18_CHIP_DS18S20) {
|
||||||
|
strlcpy(buffer, "DS18S20", size);
|
||||||
|
} else if (chip_id == DS18_CHIP_DS18B20) {
|
||||||
|
strlcpy(buffer, "DS18B20", size);
|
||||||
|
} else if (chip_id == DS18_CHIP_DS1822) {
|
||||||
|
strlcpy(buffer, "DS1822", size);
|
||||||
|
} else if (chip_id == DS18_CHIP_DS1825) {
|
||||||
|
strlcpy(buffer, "DS1825", size);
|
||||||
|
} else {
|
||||||
|
strlcpy(buffer, "Unknown", size);
|
||||||
|
}
|
||||||
|
|
||||||
|
char a[30] = {0};
|
||||||
|
snprintf(a,
|
||||||
|
sizeof(a),
|
||||||
|
"(%02X%02X%02X%02X%02X%02X%02X%02X) @ GPIO%d",
|
||||||
|
address[0],
|
||||||
|
address[1],
|
||||||
|
address[2],
|
||||||
|
address[3],
|
||||||
|
address[4],
|
||||||
|
address[5],
|
||||||
|
address[6],
|
||||||
|
address[7],
|
||||||
|
_gpio);
|
||||||
|
|
||||||
|
strlcat(buffer, a, size);
|
||||||
|
} else {
|
||||||
|
strlcpy(buffer, "invalid", size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read sensor values
|
||||||
|
*
|
||||||
|
* Registers:
|
||||||
|
byte 0: temperature LSB
|
||||||
|
byte 1: temperature MSB
|
||||||
|
byte 2: high alarm temp
|
||||||
|
byte 3: low alarm temp
|
||||||
|
byte 4: DS18S20: store for crc
|
||||||
|
DS18B20 & DS1822: configuration register
|
||||||
|
byte 5: internal use & crc
|
||||||
|
byte 6: DS18S20: COUNT_REMAIN
|
||||||
|
DS18B20 & DS1822: store for crc
|
||||||
|
byte 7: DS18S20: COUNT_PER_C
|
||||||
|
DS18B20 & DS1822: store for crc
|
||||||
|
byte 8: SCRATCHPAD_CRC
|
||||||
|
*/
|
||||||
|
double DS18::getValue(unsigned char index) {
|
||||||
|
if (index >= _count)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint8_t * data = _devices[index].data;
|
||||||
|
|
||||||
|
if (OneWire::crc8(data, DS18_DATA_SIZE - 1) != data[DS18_DATA_SIZE - 1]) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t raw = (data[1] << 8) | data[0];
|
||||||
|
if (chip(index) == DS18_CHIP_DS18S20) {
|
||||||
|
raw = raw << 3; // 9 bit resolution default
|
||||||
|
if (data[7] == 0x10) {
|
||||||
|
raw = (raw & 0xFFF0) + 12 - data[6]; // "count remain" gives full 12 bit resolution
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
byte cfg = (data[4] & 0x60);
|
||||||
|
if (cfg == 0x00)
|
||||||
|
raw = raw & ~7; // 9 bit res, 93.75 ms
|
||||||
|
else if (cfg == 0x20)
|
||||||
|
raw = raw & ~3; // 10 bit res, 187.5 ms
|
||||||
|
else if (cfg == 0x40)
|
||||||
|
raw = raw & ~1; // 11 bit res, 375 ms
|
||||||
|
// 12 bit res, 750 ms
|
||||||
|
}
|
||||||
|
|
||||||
|
double value = (float)raw / 16.0;
|
||||||
|
if (value == DS18_DISCONNECTED) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for a supported DS chip version
|
||||||
|
bool DS18::validateID(unsigned char id) {
|
||||||
|
return (id == DS18_CHIP_DS18S20) || (id == DS18_CHIP_DS18B20) || (id == DS18_CHIP_DS1822) || (id == DS18_CHIP_DS1825);
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the type
|
||||||
|
unsigned char DS18::chip(unsigned char index) {
|
||||||
|
if (index < _count)
|
||||||
|
return _devices[index].address[0];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// scan for DS sensors and load into the vector
|
||||||
|
uint8_t DS18::loadDevices() {
|
||||||
|
uint8_t address[8];
|
||||||
|
_wire->reset();
|
||||||
|
_wire->reset_search();
|
||||||
|
while (_wire->search(address)) {
|
||||||
|
// Check CRC
|
||||||
|
if (_wire->crc8(address, 7) == address[7]) {
|
||||||
|
// Check ID
|
||||||
|
if (validateID(address[0])) {
|
||||||
|
ds_device_t device;
|
||||||
|
memcpy(device.address, address, 8);
|
||||||
|
_devices.push_back(device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (_devices.size());
|
||||||
|
}
|
||||||
55
src/ds18.h
Normal file
55
src/ds18.h
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Dallas support for external temperature sensors
|
||||||
|
* Copyright (C) 2017-2018 by Xose Pérez <xose dot perez at gmail dot com>
|
||||||
|
*
|
||||||
|
* Paul Derbyshire - https://github.com/proddy/EMS-ESP
|
||||||
|
*
|
||||||
|
* See ChangeLog.md for history
|
||||||
|
* See README.md for Acknowledgments
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <OneWire.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#define DS18_CHIP_DS18S20 0x10
|
||||||
|
#define DS18_CHIP_DS1822 0x22
|
||||||
|
#define DS18_CHIP_DS18B20 0x28
|
||||||
|
#define DS18_CHIP_DS1825 0x3B
|
||||||
|
|
||||||
|
#define DS18_DATA_SIZE 9
|
||||||
|
#define DS18_PARASITE 1
|
||||||
|
#define DS18_DISCONNECTED -127
|
||||||
|
|
||||||
|
#define GPIO_NONE 0x99
|
||||||
|
#define DS18_READ_INTERVAL 2000 // Force sensor read & cache every 2 seconds
|
||||||
|
|
||||||
|
#define DS18_CMD_START_CONVERSION 0x44
|
||||||
|
#define DS18_CMD_READ_SCRATCHPAD 0xBE
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t address[8];
|
||||||
|
uint8_t data[DS18_DATA_SIZE];
|
||||||
|
} ds_device_t;
|
||||||
|
|
||||||
|
class DS18 {
|
||||||
|
public:
|
||||||
|
DS18();
|
||||||
|
~DS18();
|
||||||
|
|
||||||
|
uint8_t setup(uint8_t gpio);
|
||||||
|
void loop();
|
||||||
|
char * getDeviceString(char * s, unsigned char index);
|
||||||
|
double getValue(unsigned char index);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool validateID(unsigned char id);
|
||||||
|
unsigned char chip(unsigned char index);
|
||||||
|
uint8_t loadDevices();
|
||||||
|
|
||||||
|
OneWire * _wire;
|
||||||
|
uint8_t _count; // # devices
|
||||||
|
uint8_t _gpio; // the sensor pin
|
||||||
|
};
|
||||||
@@ -8,13 +8,17 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// local libraries
|
// local libraries
|
||||||
|
#include "ds18.h"
|
||||||
#include "ems.h"
|
#include "ems.h"
|
||||||
#include "ems_devices.h"
|
#include "ems_devices.h"
|
||||||
#include "emsuart.h"
|
#include "emsuart.h"
|
||||||
#include "my_config.h"
|
#include "my_config.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
// my libraries
|
// Dallas external temp sensors
|
||||||
|
DS18 ds18;
|
||||||
|
|
||||||
|
// shared libraries
|
||||||
#include <MyESP.h>
|
#include <MyESP.h>
|
||||||
|
|
||||||
// public libraries
|
// public libraries
|
||||||
@@ -74,10 +78,11 @@ Ticker showerColdShotStopTimer;
|
|||||||
#define SHOWER_COLDSHOT_DURATION 10 // in seconds. 10 seconds for cold water before turning back hot water
|
#define SHOWER_COLDSHOT_DURATION 10 // in seconds. 10 seconds for cold water before turning back hot water
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool shower_timer; // true if we want to report back on shower times
|
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 shower_alert; // true if we want the alert of cold water
|
||||||
bool led_enabled; // LED on/off
|
bool led_enabled; // LED on/off
|
||||||
unsigned long timestamp; // for internal timings, via millis()
|
unsigned long timestamp; // for internal timings, via millis()
|
||||||
|
uint8_t dallas_sensors; // count of dallas sensors
|
||||||
} _EMSESP_Status;
|
} _EMSESP_Status;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -122,7 +127,7 @@ void myDebugLog(const char * s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// convert float to char
|
// convert float to char
|
||||||
char * _float_to_char(char * a, float f, uint8_t precision = 1) {
|
char * _float_to_char(char * a, float f, uint8_t precision = 2) {
|
||||||
long p[] = {0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};
|
long p[] = {0, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000};
|
||||||
|
|
||||||
char * ret = a;
|
char * ret = a;
|
||||||
@@ -202,14 +207,20 @@ void _renderIntfractionalValue(const char * prefix, const char * postfix, uint8_
|
|||||||
strlcpy(buffer, " ", sizeof(buffer));
|
strlcpy(buffer, " ", sizeof(buffer));
|
||||||
strlcat(buffer, prefix, sizeof(buffer));
|
strlcat(buffer, prefix, sizeof(buffer));
|
||||||
strlcat(buffer, ": ", sizeof(buffer));
|
strlcat(buffer, ": ", sizeof(buffer));
|
||||||
strlcat(buffer, _int_to_char(s, value / (decimals * 10)), sizeof(buffer));
|
|
||||||
strlcat(buffer, ".", sizeof(buffer));
|
if (value == EMS_VALUE_INT_NOTSET) {
|
||||||
strlcat(buffer, _int_to_char(s, value % (decimals * 10)), sizeof(buffer));
|
strlcat(buffer, "?", sizeof(buffer));
|
||||||
|
} else {
|
||||||
|
strlcat(buffer, _int_to_char(s, value / (decimals * 10)), sizeof(buffer));
|
||||||
|
strlcat(buffer, ".", sizeof(buffer));
|
||||||
|
strlcat(buffer, _int_to_char(s, value % (decimals * 10)), sizeof(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
if (postfix != NULL) {
|
if (postfix != NULL) {
|
||||||
strlcat(buffer, " ", sizeof(buffer));
|
strlcat(buffer, " ", sizeof(buffer));
|
||||||
strlcat(buffer, postfix, sizeof(buffer));
|
strlcat(buffer, postfix, sizeof(buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
myDebug(buffer);
|
myDebug(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,6 +277,8 @@ void showInfo() {
|
|||||||
|
|
||||||
myDebug(" LED is %s", EMSESP_Status.led_enabled ? "on" : "off");
|
myDebug(" LED is %s", EMSESP_Status.led_enabled ? "on" : "off");
|
||||||
|
|
||||||
|
myDebug(" # connected Dallas temperature sensors = %d", EMSESP_Status.dallas_sensors);
|
||||||
|
|
||||||
myDebug(" Thermostat is %s, Boiler is %s, Poll is %s, Tx is %s, Shower Timer is %s, Shower Alert is %s",
|
myDebug(" Thermostat is %s, Boiler is %s, Poll is %s, Tx is %s, Shower Timer is %s, Shower Alert is %s",
|
||||||
(ems_getThermostatEnabled() ? "enabled" : "disabled"),
|
(ems_getThermostatEnabled() ? "enabled" : "disabled"),
|
||||||
(ems_getBoilerEnabled() ? "enabled" : "disabled"),
|
(ems_getBoilerEnabled() ? "enabled" : "disabled"),
|
||||||
@@ -291,8 +304,10 @@ void showInfo() {
|
|||||||
myDebug(" Boiler type: %s", ems_getBoilerDescription(buffer_type));
|
myDebug(" Boiler type: %s", ems_getBoilerDescription(buffer_type));
|
||||||
|
|
||||||
// active stats
|
// active stats
|
||||||
myDebug(" Hot tap water is %s", (EMS_Boiler.tapwaterActive ? "running" : "off"));
|
if (ems_getBusConnected()) {
|
||||||
myDebug(" Central Heating is %s", (EMS_Boiler.heatingActive ? "active" : "off"));
|
myDebug(" Hot tap water is %s", (EMS_Boiler.tapwaterActive ? "running" : "off"));
|
||||||
|
myDebug(" Central Heating is %s", (EMS_Boiler.heatingActive ? "active" : "off"));
|
||||||
|
}
|
||||||
|
|
||||||
// UBAParameterWW
|
// UBAParameterWW
|
||||||
_renderBoolValue("Warm Water activated", EMS_Boiler.wWActivated);
|
_renderBoolValue("Warm Water activated", EMS_Boiler.wWActivated);
|
||||||
@@ -328,6 +343,11 @@ void showInfo() {
|
|||||||
_renderFloatValue("System pressure", "bar", EMS_Boiler.sysPress);
|
_renderFloatValue("System pressure", "bar", EMS_Boiler.sysPress);
|
||||||
myDebug(" Current System Service Code: %s", EMS_Boiler.serviceCodeChar);
|
myDebug(" Current System Service Code: %s", EMS_Boiler.serviceCodeChar);
|
||||||
|
|
||||||
|
// UBAParametersMessage
|
||||||
|
_renderIntValue("Heating temperature setting on the boiler", "C", EMS_Boiler.heating_temp);
|
||||||
|
_renderIntValue("Boiler circuit pump modulation max. power", "%", EMS_Boiler.pump_mod_max);
|
||||||
|
_renderIntValue("Boiler circuit pump modulation min. power", "%", EMS_Boiler.pump_mod_min);
|
||||||
|
|
||||||
// UBAMonitorSlow
|
// UBAMonitorSlow
|
||||||
_renderFloatValue("Outside temperature", "C", EMS_Boiler.extTemp);
|
_renderFloatValue("Outside temperature", "C", EMS_Boiler.extTemp);
|
||||||
_renderFloatValue("Boiler temperature", "C", EMS_Boiler.boilTemp);
|
_renderFloatValue("Boiler temperature", "C", EMS_Boiler.boilTemp);
|
||||||
@@ -383,9 +403,21 @@ void showInfo() {
|
|||||||
|
|
||||||
myDebug(""); // newline
|
myDebug(""); // newline
|
||||||
|
|
||||||
|
// Dallas
|
||||||
|
if (EMSESP_Status.dallas_sensors != 0) {
|
||||||
|
myDebug("%sExternal temperature sensors:%s", COLOR_BOLD_ON, COLOR_BOLD_OFF);
|
||||||
|
for (uint8_t i = 0; i < EMSESP_Status.dallas_sensors; i++) {
|
||||||
|
char s[80] = {0};
|
||||||
|
snprintf(s, sizeof(s), "Sensor #%d", i + 1);
|
||||||
|
_renderFloatValue(s, "C", ds18.getValue(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
myDebug(""); // newline
|
||||||
|
|
||||||
// show the Shower Info
|
// show the Shower Info
|
||||||
if (EMSESP_Status.shower_timer) {
|
if (EMSESP_Status.shower_timer) {
|
||||||
myDebug("%s Shower stats:%s", COLOR_BOLD_ON, COLOR_BOLD_OFF);
|
myDebug("%sShower stats:%s", COLOR_BOLD_ON, COLOR_BOLD_OFF);
|
||||||
myDebug(" Shower Timer is %s", (EMSESP_Shower.showerOn ? "active" : "off"));
|
myDebug(" Shower Timer is %s", (EMSESP_Shower.showerOn ? "active" : "off"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -597,7 +629,7 @@ bool SettingsCallback(MYESP_FSACTION action, uint8_t wc, const char * setting, c
|
|||||||
// we set the logging here
|
// we set the logging here
|
||||||
void TelnetCallback(uint8_t event) {
|
void TelnetCallback(uint8_t event) {
|
||||||
if (event == TELNET_EVENT_CONNECT) {
|
if (event == TELNET_EVENT_CONNECT) {
|
||||||
ems_setLogging(EMS_SYS_LOGGING_BASIC);
|
ems_setLogging(EMS_SYS_LOGGING_NONE);
|
||||||
} else if (event == TELNET_EVENT_DISCONNECT) {
|
} else if (event == TELNET_EVENT_DISCONNECT) {
|
||||||
ems_setLogging(EMS_SYS_LOGGING_NONE);
|
ems_setLogging(EMS_SYS_LOGGING_NONE);
|
||||||
}
|
}
|
||||||
@@ -838,10 +870,11 @@ void WIFICallback() {
|
|||||||
// Initialize the boiler settings and shower settings
|
// Initialize the boiler settings and shower settings
|
||||||
void initEMSESP() {
|
void initEMSESP() {
|
||||||
// general settings
|
// general settings
|
||||||
EMSESP_Status.shower_timer = BOILER_SHOWER_TIMER;
|
EMSESP_Status.shower_timer = BOILER_SHOWER_TIMER;
|
||||||
EMSESP_Status.shower_alert = BOILER_SHOWER_ALERT;
|
EMSESP_Status.shower_alert = BOILER_SHOWER_ALERT;
|
||||||
EMSESP_Status.led_enabled = false;
|
EMSESP_Status.led_enabled = false;
|
||||||
EMSESP_Status.timestamp = millis();
|
EMSESP_Status.timestamp = millis();
|
||||||
|
EMSESP_Status.dallas_sensors = 0;
|
||||||
|
|
||||||
// shower settings
|
// shower settings
|
||||||
EMSESP_Shower.timerStart = 0;
|
EMSESP_Shower.timerStart = 0;
|
||||||
@@ -888,18 +921,22 @@ void do_systemCheck() {
|
|||||||
// force calls to get data from EMS for the types that aren't sent as broadcasts
|
// force calls to get data from EMS for the types that aren't sent as broadcasts
|
||||||
// only if we have a EMS connection
|
// only if we have a EMS connection
|
||||||
void do_regularUpdates() {
|
void do_regularUpdates() {
|
||||||
myDebugLog("Calling scheduled data refresh from EMS devices..");
|
if (ems_getBusConnected()) {
|
||||||
ems_getThermostatValues();
|
myDebugLog("Calling scheduled data refresh from EMS devices..");
|
||||||
ems_getBoilerValues();
|
ems_getThermostatValues();
|
||||||
|
ems_getBoilerValues();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// turn off hot water to send a shot of cold
|
// turn off hot water to send a shot of cold
|
||||||
void _showerColdShotStart() {
|
void _showerColdShotStart() {
|
||||||
myDebugLog("[Shower] doing a shot of cold water");
|
if (EMSESP_Status.shower_alert) {
|
||||||
ems_setWarmTapWaterActivated(false);
|
myDebugLog("[Shower] doing a shot of cold water");
|
||||||
EMSESP_Shower.doingColdShot = true;
|
ems_setWarmTapWaterActivated(false);
|
||||||
// start the timer for n seconds which will reset the water back to hot
|
EMSESP_Shower.doingColdShot = true;
|
||||||
showerColdShotStopTimer.attach(SHOWER_COLDSHOT_DURATION, _showerColdShotStop);
|
// start the timer for n seconds which will reset the water back to hot
|
||||||
|
showerColdShotStopTimer.attach(SHOWER_COLDSHOT_DURATION, _showerColdShotStop);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// turn back on the hot water for the shower
|
// turn back on the hot water for the shower
|
||||||
@@ -1006,6 +1043,9 @@ void setup() {
|
|||||||
digitalWrite(BOILER_LED, (BOILER_LED == LED_BUILTIN) ? HIGH : LOW); // light off. For onboard high=off
|
digitalWrite(BOILER_LED, (BOILER_LED == LED_BUILTIN) ? HIGH : LOW); // light off. For onboard high=off
|
||||||
ledcheckTimer.attach(LEDCHECK_TIME, do_ledcheck); // blink heartbeat LED
|
ledcheckTimer.attach(LEDCHECK_TIME, do_ledcheck); // blink heartbeat LED
|
||||||
|
|
||||||
|
// check for Dallas sensors
|
||||||
|
EMSESP_Status.dallas_sensors = ds18.setup(TEMPERATURE_SENSOR_PIN);
|
||||||
|
|
||||||
// init the EMS bus
|
// init the EMS bus
|
||||||
// call ems.cpp's init function to set all the internal params
|
// call ems.cpp's init function to set all the internal params
|
||||||
ems_init(MY_THERMOSTAT_MODELID);
|
ems_init(MY_THERMOSTAT_MODELID);
|
||||||
@@ -1020,6 +1060,11 @@ void loop() {
|
|||||||
// the main loop
|
// the main loop
|
||||||
myESP.loop();
|
myESP.loop();
|
||||||
|
|
||||||
|
// check Dallas sensors
|
||||||
|
if (EMSESP_Status.dallas_sensors != 0) {
|
||||||
|
ds18.loop();
|
||||||
|
}
|
||||||
|
|
||||||
// publish the values to MQTT, regardless if the values haven't changed
|
// publish the values to MQTT, regardless if the values haven't changed
|
||||||
// we don't want to publish when doing a deep scan of the thermostat
|
// 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)) {
|
||||||
|
|||||||
34
src/ems.cpp
34
src/ems.cpp
@@ -22,16 +22,20 @@ _EMS_Sys_Status EMS_Sys_Status; // EMS Status
|
|||||||
CircularBuffer<_EMS_TxTelegram, EMS_TX_TELEGRAM_QUEUE_MAX> EMS_TxQueue; // FIFO queue for Tx send buffer
|
CircularBuffer<_EMS_TxTelegram, EMS_TX_TELEGRAM_QUEUE_MAX> EMS_TxQueue; // FIFO queue for Tx send buffer
|
||||||
|
|
||||||
// callbacks per type
|
// callbacks per type
|
||||||
// Boiler and Buderus devices
|
|
||||||
|
// generic
|
||||||
void _process_Version(uint8_t * data, uint8_t length);
|
void _process_Version(uint8_t * data, uint8_t length);
|
||||||
|
|
||||||
|
// Boiler and Buderus devices
|
||||||
void _process_UBAMonitorFast(uint8_t * data, uint8_t length);
|
void _process_UBAMonitorFast(uint8_t * data, uint8_t length);
|
||||||
void _process_UBAMonitorSlow(uint8_t * data, uint8_t length);
|
void _process_UBAMonitorSlow(uint8_t * data, uint8_t length);
|
||||||
void _process_UBAMonitorWWMessage(uint8_t * data, uint8_t length);
|
void _process_UBAMonitorWWMessage(uint8_t * data, uint8_t length);
|
||||||
void _process_UBAParameterWW(uint8_t * data, uint8_t length);
|
void _process_UBAParameterWW(uint8_t * data, uint8_t length);
|
||||||
void _process_UBATotalUptimeMessage(uint8_t * data, uint8_t length);
|
void _process_UBATotalUptimeMessage(uint8_t * data, uint8_t length);
|
||||||
|
void _process_UBAParametersMessage(uint8_t * data, uint8_t length);
|
||||||
|
void _process_SetPoints(uint8_t * data, uint8_t length);
|
||||||
|
|
||||||
// Common for most thermostats
|
// Common for most thermostats
|
||||||
void _process_SetPoints(uint8_t * data, uint8_t length);
|
|
||||||
void _process_RCTime(uint8_t * data, uint8_t length);
|
void _process_RCTime(uint8_t * data, uint8_t length);
|
||||||
void _process_RCOutdoorTempMessage(uint8_t * data, uint8_t length);
|
void _process_RCOutdoorTempMessage(uint8_t * data, uint8_t length);
|
||||||
|
|
||||||
@@ -66,8 +70,7 @@ const _EMS_Type EMS_Types[] = {
|
|||||||
{EMS_MODEL_UBA, EMS_TYPE_UBAParameterWW, "UBAParameterWW", _process_UBAParameterWW},
|
{EMS_MODEL_UBA, EMS_TYPE_UBAParameterWW, "UBAParameterWW", _process_UBAParameterWW},
|
||||||
{EMS_MODEL_UBA, EMS_TYPE_UBATotalUptimeMessage, "UBATotalUptimeMessage", _process_UBATotalUptimeMessage},
|
{EMS_MODEL_UBA, EMS_TYPE_UBATotalUptimeMessage, "UBATotalUptimeMessage", _process_UBATotalUptimeMessage},
|
||||||
{EMS_MODEL_UBA, EMS_TYPE_UBAMaintenanceSettingsMessage, "UBAMaintenanceSettingsMessage", NULL},
|
{EMS_MODEL_UBA, EMS_TYPE_UBAMaintenanceSettingsMessage, "UBAMaintenanceSettingsMessage", NULL},
|
||||||
{EMS_MODEL_UBA, EMS_TYPE_UBAParametersMessage, "UBAParametersMessage", NULL},
|
{EMS_MODEL_UBA, EMS_TYPE_UBAParametersMessage, "UBAParametersMessage", _process_UBAParametersMessage},
|
||||||
{EMS_MODEL_UBA, EMS_TYPE_UBAMaintenanceStatusMessage, "UBAMaintenanceStatusMessage", NULL},
|
|
||||||
{EMS_MODEL_UBA, EMS_TYPE_UBASetPoints, "UBASetPoints", _process_SetPoints},
|
{EMS_MODEL_UBA, EMS_TYPE_UBASetPoints, "UBASetPoints", _process_SetPoints},
|
||||||
|
|
||||||
// RC20 and RC20F
|
// RC20 and RC20F
|
||||||
@@ -212,6 +215,12 @@ void ems_init(uint8_t thermostat_modelid) {
|
|||||||
// UBATotalUptimeMessage
|
// UBATotalUptimeMessage
|
||||||
EMS_Boiler.UBAuptime = EMS_VALUE_LONG_NOTSET; // Total UBA working hours
|
EMS_Boiler.UBAuptime = EMS_VALUE_LONG_NOTSET; // Total UBA working hours
|
||||||
|
|
||||||
|
// UBAParametersMessage
|
||||||
|
EMS_Boiler.heating_temp = EMS_VALUE_INT_NOTSET; // Heating temperature setting on the boiler
|
||||||
|
EMS_Boiler.pump_mod_max = EMS_VALUE_INT_NOTSET; // Boiler circuit pump modulation max. power
|
||||||
|
EMS_Boiler.pump_mod_min = EMS_VALUE_INT_NOTSET; // Boiler circuit pump modulation min. power
|
||||||
|
|
||||||
|
// calculated values
|
||||||
EMS_Boiler.tapwaterActive = EMS_VALUE_INT_NOTSET; // Hot tap water is on/off
|
EMS_Boiler.tapwaterActive = EMS_VALUE_INT_NOTSET; // Hot tap water is on/off
|
||||||
EMS_Boiler.heatingActive = EMS_VALUE_INT_NOTSET; // Central heating is on/off
|
EMS_Boiler.heatingActive = EMS_VALUE_INT_NOTSET; // Central heating is on/off
|
||||||
|
|
||||||
@@ -569,11 +578,6 @@ void ems_parseTelegram(uint8_t * telegram, uint8_t length) {
|
|||||||
if (length == 1) {
|
if (length == 1) {
|
||||||
uint8_t value = telegram[0]; // 1st byte of data package
|
uint8_t value = telegram[0]; // 1st byte of data package
|
||||||
|
|
||||||
// TODO: remove, only for debugging why some people can't do a Tx
|
|
||||||
//if ((value & 0x80) == 0x80) {
|
|
||||||
// myDebug("Poll: %02X", value);
|
|
||||||
//}
|
|
||||||
|
|
||||||
// check first for a Poll for us
|
// check first for a Poll for us
|
||||||
if (value == (EMS_ID_ME | 0x80)) {
|
if (value == (EMS_ID_ME | 0x80)) {
|
||||||
// store when we received a last poll
|
// store when we received a last poll
|
||||||
@@ -886,6 +890,15 @@ void _process_UBATotalUptimeMessage(uint8_t * data, uint8_t length) {
|
|||||||
EMS_Sys_Status.emsRefreshed = true; // when we receieve this, lets force an MQTT publish
|
EMS_Sys_Status.emsRefreshed = true; // when we receieve this, lets force an MQTT publish
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* UBAParametersMessage - type 0x16
|
||||||
|
*/
|
||||||
|
void _process_UBAParametersMessage(uint8_t * data, uint8_t length) {
|
||||||
|
EMS_Boiler.heating_temp = data[1];
|
||||||
|
EMS_Boiler.pump_mod_max = data[9];
|
||||||
|
EMS_Boiler.pump_mod_min = data[10];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* UBAMonitorWWMessage - type 0x34 - warm water monitor. 19 bytes long
|
* UBAMonitorWWMessage - type 0x34 - warm water monitor. 19 bytes long
|
||||||
* received every 10 seconds
|
* received every 10 seconds
|
||||||
@@ -1298,6 +1311,7 @@ void ems_getBoilerValues() {
|
|||||||
ems_doReadCommand(EMS_TYPE_UBAMonitorFast, EMS_Boiler.type_id); // get boiler stats, instead of waiting 10secs for the broadcast
|
ems_doReadCommand(EMS_TYPE_UBAMonitorFast, EMS_Boiler.type_id); // get boiler stats, instead of waiting 10secs for the broadcast
|
||||||
ems_doReadCommand(EMS_TYPE_UBAMonitorSlow, EMS_Boiler.type_id); // get more boiler stats, instead of waiting 60secs for the broadcast
|
ems_doReadCommand(EMS_TYPE_UBAMonitorSlow, EMS_Boiler.type_id); // get more boiler stats, instead of waiting 60secs for the broadcast
|
||||||
ems_doReadCommand(EMS_TYPE_UBAParameterWW, EMS_Boiler.type_id); // get Warm Water values
|
ems_doReadCommand(EMS_TYPE_UBAParameterWW, EMS_Boiler.type_id); // get Warm Water values
|
||||||
|
ems_doReadCommand(EMS_TYPE_UBAParametersMessage, EMS_Boiler.type_id); // get MC10 boiler values
|
||||||
ems_doReadCommand(EMS_TYPE_UBATotalUptimeMessage, EMS_Boiler.type_id); // get Warm Water values
|
ems_doReadCommand(EMS_TYPE_UBATotalUptimeMessage, EMS_Boiler.type_id); // get Warm Water values
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1381,7 +1395,7 @@ char * ems_getBoilerDescription(char * buffer) {
|
|||||||
* Find the versions of our connected devices
|
* Find the versions of our connected devices
|
||||||
*/
|
*/
|
||||||
void ems_scanDevices() {
|
void ems_scanDevices() {
|
||||||
myDebug("Scanning EMS bus for devices. This may take a few seconds...");
|
myDebug("Scanning EMS bus for devices...");
|
||||||
|
|
||||||
// start refresh when scanning and forget anything devices we may have already set
|
// start refresh when scanning and forget anything devices we may have already set
|
||||||
EMS_Thermostat.type_id = EMS_ID_NONE; // forget thermostat
|
EMS_Thermostat.type_id = EMS_ID_NONE; // forget thermostat
|
||||||
|
|||||||
@@ -203,6 +203,11 @@ typedef struct { // UBAParameterWW
|
|||||||
// UBATotalUptimeMessage
|
// UBATotalUptimeMessage
|
||||||
uint32_t UBAuptime; // Total UBA working hours
|
uint32_t UBAuptime; // Total UBA working hours
|
||||||
|
|
||||||
|
// UBAParametersMessage
|
||||||
|
uint8_t heating_temp; // Heating temperature setting on the boiler
|
||||||
|
uint8_t pump_mod_max; // Boiler circuit pump modulation max. power
|
||||||
|
uint8_t pump_mod_min; // Boiler circuit pump modulation min. power
|
||||||
|
|
||||||
// calculated values
|
// calculated values
|
||||||
uint8_t tapwaterActive; // Hot tap water is on/off
|
uint8_t tapwaterActive; // Hot tap water is on/off
|
||||||
uint8_t heatingActive; // Central heating is on/off
|
uint8_t heatingActive; // Central heating is on/off
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ const _Boiler_Type Boiler_Types[] = {
|
|||||||
|
|
||||||
// various boilers and buderus type devices
|
// various boilers and buderus type devices
|
||||||
{EMS_MODEL_UBA, 72, 0x08, "MC10"},
|
{EMS_MODEL_UBA, 72, 0x08, "MC10"},
|
||||||
{EMS_MODEL_UBA, 123, 0x08, "Nefit Trendline"},
|
{EMS_MODEL_UBA, 123, 0x08, "Buderus GB172/Nefit Trendline"},
|
||||||
{EMS_MODEL_UBA, 115, 0x08, "Nefit Topline Compact"},
|
{EMS_MODEL_UBA, 115, 0x08, "Nefit Topline Compact"},
|
||||||
{EMS_MODEL_UBA, 64, 0x08, "Sieger BK15 Boiler"},
|
{EMS_MODEL_UBA, 64, 0x08, "Sieger BK15 Boiler"},
|
||||||
{EMS_MODEL_UBA, 190, 0x09, "BC10 Base Controller"},
|
{EMS_MODEL_UBA, 190, 0x09, "BC10 Base Controller"},
|
||||||
@@ -115,11 +115,11 @@ const _Boiler_Type Boiler_Types[] = {
|
|||||||
const _Thermostat_Type Thermostat_Types[] = {
|
const _Thermostat_Type Thermostat_Types[] = {
|
||||||
|
|
||||||
{EMS_MODEL_ES73, 76, 0x10, "Sieger ES73", EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_YES},
|
{EMS_MODEL_ES73, 76, 0x10, "Sieger ES73", EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_YES},
|
||||||
{EMS_MODEL_RC20, 77, 0x17, "RC20 (e.g. Nefit Moduline 300)", EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_YES},
|
{EMS_MODEL_RC20, 77, 0x17, "RC20/Nefit Moduline 300)", EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_YES},
|
||||||
{EMS_MODEL_RC20F, 93, 0x18, "RC20F", EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_YES},
|
{EMS_MODEL_RC20F, 93, 0x18, "RC20F", EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_YES},
|
||||||
{EMS_MODEL_RC30, 78, 0x10, "RC30 (e.g. Nefit Moduline 400)", EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_YES},
|
{EMS_MODEL_RC30, 78, 0x10, "RC30/Nefit Moduline 400)", EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_YES},
|
||||||
{EMS_MODEL_RC35, 86, 0x10, "RC35", EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_YES},
|
{EMS_MODEL_RC35, 86, 0x10, "RC35", EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_YES},
|
||||||
{EMS_MODEL_EASY, 202, 0x18, "TC100 (e.g. Nefit Easy or CT100)", EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_NO},
|
{EMS_MODEL_EASY, 202, 0x18, "TC100/Nefit Easy", EMS_THERMOSTAT_READ_YES, EMS_THERMOSTAT_WRITE_NO},
|
||||||
{EMS_MODEL_RC310, 158, 0x10, "RC310", EMS_THERMOSTAT_READ_NO, EMS_THERMOSTAT_WRITE_NO},
|
{EMS_MODEL_RC310, 158, 0x10, "RC310", EMS_THERMOSTAT_READ_NO, EMS_THERMOSTAT_WRITE_NO},
|
||||||
{EMS_MODEL_CW100, 255, 0x18, "Bosch CW100", EMS_THERMOSTAT_READ_NO, EMS_THERMOSTAT_WRITE_NO}
|
{EMS_MODEL_CW100, 255, 0x18, "Bosch CW100", EMS_THERMOSTAT_READ_NO, EMS_THERMOSTAT_WRITE_NO}
|
||||||
|
|
||||||
|
|||||||
@@ -6,5 +6,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define APP_NAME "EMS-ESP"
|
#define APP_NAME "EMS-ESP"
|
||||||
#define APP_VERSION "1.3.2"
|
#define APP_VERSION "1.4.0"
|
||||||
#define APP_HOSTNAME "ems-esp"
|
#define APP_HOSTNAME "ems-esp"
|
||||||
|
|||||||
Reference in New Issue
Block a user