mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
version 1.4.1
This commit is contained in:
11
CHANGELOG.md
11
CHANGELOG.md
@@ -5,6 +5,17 @@ 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.1] 2019-01-29
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- The led pin, dallas pin and both thermostat and boiler type IDs can be set with the application, and stored.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- some minor improvements to autodetect
|
||||||
|
|
||||||
|
|
||||||
## [1.4.0] 2019-01-27
|
## [1.4.0] 2019-01-27
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|||||||
@@ -402,10 +402,8 @@ void MyESP::_consoleShowHelp() {
|
|||||||
SerialAndTelnet.println(FPSTR("* set"));
|
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 | wifi_password | mqtt_host | mqtt_username | mqtt_password> [value]"));
|
||||||
SerialAndTelnet.println(FPSTR("* set erase"));
|
SerialAndTelnet.println(FPSTR("* set erase"));
|
||||||
SerialAndTelnet.println(FPSTR("* set led <on | off>"));
|
|
||||||
SerialAndTelnet.println(FPSTR("*"));
|
|
||||||
|
|
||||||
// print custom commands if available. Take from progmem
|
// print custom commands if available. Taken from progmem
|
||||||
if (_telnetcommand_callback) {
|
if (_telnetcommand_callback) {
|
||||||
// find the longest key length so we can right align it
|
// find the longest key length so we can right align it
|
||||||
uint8_t max_len = 0;
|
uint8_t max_len = 0;
|
||||||
@@ -513,8 +511,8 @@ void MyESP::_changeSetting(uint8_t wc, const char * setting, const char * value)
|
|||||||
SerialAndTelnet.printf("%s changed to %s\n\r", setting, value);
|
SerialAndTelnet.printf("%s changed to %s\n\r", setting, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_fs_saveConfig()) {
|
if (fs_saveConfig()) {
|
||||||
SerialAndTelnet.println("Note, some changes will only have effect after a device reboot (use ! command)");
|
SerialAndTelnet.println("Note, some changes will only have effect after the ESP is restarted (use ! command)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -811,8 +809,8 @@ bool MyESP::_fs_loadConfig() {
|
|||||||
// use configFile.readString
|
// use configFile.readString
|
||||||
configFile.readBytes(buf.get(), size);
|
configFile.readBytes(buf.get(), size);
|
||||||
|
|
||||||
StaticJsonBuffer<500> jsonBuffer; // https://arduinojson.org/v5/assistant/
|
StaticJsonBuffer<SPIFFS_MAXSIZE> jsonBuffer;
|
||||||
JsonObject & json = jsonBuffer.parseObject(buf.get());
|
JsonObject & json = jsonBuffer.parseObject(buf.get());
|
||||||
|
|
||||||
const char * value;
|
const char * value;
|
||||||
|
|
||||||
@@ -831,18 +829,19 @@ bool MyESP::_fs_loadConfig() {
|
|||||||
value = json["mqtt_password"];
|
value = json["mqtt_password"];
|
||||||
_mqtt_password = (value) ? strdup(value) : NULL;
|
_mqtt_password = (value) ? strdup(value) : NULL;
|
||||||
|
|
||||||
// callback for custom settings
|
// callback for loading custom settings
|
||||||
(_fs_callback)(MYESP_FSACTION_LOAD, json);
|
// ok is false if there's a problem loading a custom setting (e.g. does not exist)
|
||||||
|
bool ok = (_fs_callback)(MYESP_FSACTION_LOAD, json);
|
||||||
|
|
||||||
configFile.close();
|
configFile.close();
|
||||||
|
|
||||||
return true;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
// save settings to spiffs
|
// save settings to spiffs
|
||||||
bool MyESP::_fs_saveConfig() {
|
bool MyESP::fs_saveConfig() {
|
||||||
StaticJsonBuffer<500> jsonBuffer; // https://arduinojson.org/v5/assistant/
|
StaticJsonBuffer<SPIFFS_MAXSIZE> jsonBuffer;
|
||||||
JsonObject & json = jsonBuffer.createObject();
|
JsonObject & json = jsonBuffer.createObject();
|
||||||
|
|
||||||
json["wifi_ssid"] = _wifi_ssid;
|
json["wifi_ssid"] = _wifi_ssid;
|
||||||
json["wifi_password"] = _wifi_password;
|
json["wifi_password"] = _wifi_password;
|
||||||
@@ -850,8 +849,8 @@ bool MyESP::_fs_saveConfig() {
|
|||||||
json["mqtt_username"] = _mqtt_username;
|
json["mqtt_username"] = _mqtt_username;
|
||||||
json["mqtt_password"] = _mqtt_password;
|
json["mqtt_password"] = _mqtt_password;
|
||||||
|
|
||||||
// callback for custom settings
|
// callback for saving custom settings
|
||||||
(_fs_callback)(MYESP_FSACTION_SAVE, json);
|
(void)(_fs_callback)(MYESP_FSACTION_SAVE, json);
|
||||||
|
|
||||||
File configFile = SPIFFS.open("/config.json", "w");
|
File configFile = SPIFFS.open("/config.json", "w");
|
||||||
if (!configFile) {
|
if (!configFile) {
|
||||||
@@ -872,11 +871,12 @@ void MyESP::_fs_setup() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// _fs_printConfig(); // for debugging
|
//_fs_printConfig(); // for debugging
|
||||||
|
|
||||||
// load the config file. if it doesn't exist create it with anything that was specified
|
// load the config file. if it doesn't exist create it
|
||||||
if (!_fs_loadConfig()) {
|
if (!_fs_loadConfig()) {
|
||||||
_fs_saveConfig();
|
myDebug_P(PSTR("[FS] Re-creating config file"));
|
||||||
|
fs_saveConfig();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -939,4 +939,4 @@ void MyESP::loop() {
|
|||||||
yield(); // ...and breath
|
yield(); // ...and breath
|
||||||
}
|
}
|
||||||
|
|
||||||
MyESP myESP;
|
MyESP myESP; // create instance
|
||||||
|
|||||||
@@ -61,8 +61,11 @@
|
|||||||
#define COLOR_CYAN "\x1B[0;36m"
|
#define COLOR_CYAN "\x1B[0;36m"
|
||||||
#define COLOR_WHITE "\x1B[0;37m"
|
#define COLOR_WHITE "\x1B[0;37m"
|
||||||
|
|
||||||
|
// SPIFFS
|
||||||
|
#define SPIFFS_MAXSIZE 500 // https://arduinojson.org/v5/assistant/
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char key[30];
|
char key[40];
|
||||||
char description[100];
|
char description[100];
|
||||||
} command_t;
|
} command_t;
|
||||||
|
|
||||||
@@ -72,7 +75,7 @@ typedef std::function<void(unsigned int, const char *, const char *)>
|
|||||||
typedef std::function<void()> wifi_callback_f;
|
typedef std::function<void()> wifi_callback_f;
|
||||||
typedef std::function<void(uint8_t, const char *)> telnetcommand_callback_f;
|
typedef std::function<void(uint8_t, const char *)> telnetcommand_callback_f;
|
||||||
typedef std::function<void(uint8_t)> telnet_callback_f;
|
typedef std::function<void(uint8_t)> telnet_callback_f;
|
||||||
typedef std::function<void(MYESP_FSACTION, JsonObject & json)> fs_callback_f;
|
typedef std::function<bool(MYESP_FSACTION, JsonObject & json)> fs_callback_f;
|
||||||
typedef std::function<bool(MYESP_FSACTION, uint8_t, const char *, const char *)> fs_settings_callback_f;
|
typedef std::function<bool(MYESP_FSACTION, uint8_t, const char *, const char *)> fs_settings_callback_f;
|
||||||
|
|
||||||
// calculates size of an 2d array at compile time
|
// calculates size of an 2d array at compile time
|
||||||
@@ -113,6 +116,7 @@ class MyESP {
|
|||||||
|
|
||||||
// FS
|
// FS
|
||||||
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);
|
||||||
|
bool fs_saveConfig();
|
||||||
|
|
||||||
// general
|
// general
|
||||||
void end();
|
void end();
|
||||||
@@ -178,7 +182,6 @@ class MyESP {
|
|||||||
|
|
||||||
// fs
|
// fs
|
||||||
void _fs_setup();
|
void _fs_setup();
|
||||||
bool _fs_saveConfig();
|
|
||||||
bool _fs_loadConfig();
|
bool _fs_loadConfig();
|
||||||
void _fs_printConfig();
|
void _fs_printConfig();
|
||||||
void _fs_eraseConfig();
|
void _fs_eraseConfig();
|
||||||
|
|||||||
179
src/ems-esp.ino
179
src/ems-esp.ino
@@ -32,7 +32,7 @@ DS18 ds18;
|
|||||||
#define myDebug_P(...) myESP.myDebug_P(__VA_ARGS__)
|
#define myDebug_P(...) myESP.myDebug_P(__VA_ARGS__)
|
||||||
|
|
||||||
// timers, all values are in seconds
|
// timers, all values are in seconds
|
||||||
#define PUBLISHVALUES_TIME 120 // every 2 minutes post MQTT values
|
#define PUBLISHVALUES_TIME 120 // every 2 minutes publish MQTT values
|
||||||
Ticker publishValuesTimer;
|
Ticker publishValuesTimer;
|
||||||
|
|
||||||
#define SYSTEMCHECK_TIME 20 // every 20 seconds check if Boiler is online
|
#define SYSTEMCHECK_TIME 20 // every 20 seconds check if Boiler is online
|
||||||
@@ -41,7 +41,7 @@ Ticker systemCheckTimer;
|
|||||||
#define REGULARUPDATES_TIME 60 // every minute a call is made to fetch data from EMS devices manually
|
#define REGULARUPDATES_TIME 60 // every minute a call is made to fetch data from EMS devices manually
|
||||||
Ticker regularUpdatesTimer;
|
Ticker regularUpdatesTimer;
|
||||||
|
|
||||||
#define LEDCHECK_TIME 1 // every second blink heartbeat LED
|
#define LEDCHECK_TIME 1 // every second blink the heartbeat LED
|
||||||
Ticker ledcheckTimer;
|
Ticker ledcheckTimer;
|
||||||
|
|
||||||
// thermostat scan - for debugging
|
// thermostat scan - for debugging
|
||||||
@@ -51,26 +51,6 @@ uint8_t scanThermostat_count = 0;
|
|||||||
|
|
||||||
Ticker showerColdShotStopTimer;
|
Ticker showerColdShotStopTimer;
|
||||||
|
|
||||||
// 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 THERMOSTAT_CURRTEMP "thermostat_currtemp" // current temperature
|
|
||||||
#define THERMOSTAT_SELTEMP "thermostat_seltemp" // selected temperature
|
|
||||||
#define THERMOSTAT_MODE "thermostat_mode" // mode
|
|
||||||
|
|
||||||
// boiler
|
|
||||||
#define TOPIC_BOILER_DATA "boiler_data" // for sending boiler values
|
|
||||||
#define TOPIC_BOILER_TAPWATER_ACTIVE "tapwater_active" // if hot tap water is running
|
|
||||||
#define TOPIC_BOILER_HEATING_ACTIVE "heating_active" // if heating is on
|
|
||||||
|
|
||||||
// shower time
|
|
||||||
#define TOPIC_SHOWERTIME "showertime" // for sending shower time results
|
|
||||||
#define TOPIC_SHOWER_TIMER "shower_timer" // toggle switch for enabling the shower logic
|
|
||||||
#define TOPIC_SHOWER_ALERT "shower_alert" // toggle switch for enabling the shower alarm logic
|
|
||||||
#define TOPIC_SHOWER_COLDSHOT "shower_coldshot" // used to trigger a coldshot from an MQTT command
|
|
||||||
#define SHOWER_ALARM "shower_alarm" // for notifying that shower time has reached its limit
|
|
||||||
|
|
||||||
// if using the shower timer, change these settings
|
// if using the shower timer, change these settings
|
||||||
#define SHOWER_PAUSE_TIME 15000 // in ms. 15 seconds, max time if water is switched off & on during a shower
|
#define SHOWER_PAUSE_TIME 15000 // in ms. 15 seconds, max time if water is switched off & on during a shower
|
||||||
#define SHOWER_MIN_DURATION 120000 // in ms. 2 minutes, before recognizing its a shower
|
#define SHOWER_MIN_DURATION 120000 // in ms. 2 minutes, before recognizing its a shower
|
||||||
@@ -83,6 +63,8 @@ typedef struct {
|
|||||||
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
|
uint8_t dallas_sensors; // count of dallas sensors
|
||||||
|
uint8_t led_gpio;
|
||||||
|
uint8_t dallas_gpio;
|
||||||
} _EMSESP_Status;
|
} _EMSESP_Status;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -95,10 +77,16 @@ typedef struct {
|
|||||||
|
|
||||||
command_t PROGMEM project_cmds[] = {
|
command_t PROGMEM project_cmds[] = {
|
||||||
|
|
||||||
|
{"set led <on | off>", "toggle status LED on/off"},
|
||||||
|
{"set led_gpio <pin>", "set the LED pin (onboard=2)"},
|
||||||
|
{"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"},
|
{"info", "show the values"},
|
||||||
{"log <n | b | t | r | v>", "set logging mode to none, basic, thermostat only, raw or verbose"},
|
{"log <n | b | t | r | v>", "set logging mode to none, basic, thermostat only, raw or verbose"},
|
||||||
{"poll", "toggle EMS poll request on/off"},
|
{"poll", "toggle EMS poll request on/off"},
|
||||||
{"tx", "toggle EMX Tx on/off"},
|
{"tx", "toggle EMX Tx line on/off"},
|
||||||
{"publish", "publish values to MQTT"},
|
{"publish", "publish values to MQTT"},
|
||||||
{"types", "list supported EMS telegram type IDs"},
|
{"types", "list supported EMS telegram type IDs"},
|
||||||
{"queue", "print the Tx queue"},
|
{"queue", "print the Tx queue"},
|
||||||
@@ -349,7 +337,9 @@ void showInfo() {
|
|||||||
_renderIntValue("Boiler circuit pump modulation min. power", "%", EMS_Boiler.pump_mod_min);
|
_renderIntValue("Boiler circuit pump modulation min. power", "%", EMS_Boiler.pump_mod_min);
|
||||||
|
|
||||||
// UBAMonitorSlow
|
// UBAMonitorSlow
|
||||||
_renderFloatValue("Outside temperature", "C", EMS_Boiler.extTemp);
|
if (EMS_Boiler.extTemp != EMS_VALUE_FLOAT_NOTSET) {
|
||||||
|
_renderFloatValue("Outside temperature", "C", EMS_Boiler.extTemp);
|
||||||
|
}
|
||||||
_renderFloatValue("Boiler temperature", "C", EMS_Boiler.boilTemp);
|
_renderFloatValue("Boiler temperature", "C", EMS_Boiler.boilTemp);
|
||||||
_renderIntValue("Pump modulation", "%", EMS_Boiler.pumpMod);
|
_renderIntValue("Pump modulation", "%", EMS_Boiler.pumpMod);
|
||||||
_renderLongValue("Burner # restarts", "times", EMS_Boiler.burnStarts);
|
_renderLongValue("Burner # restarts", "times", EMS_Boiler.burnStarts);
|
||||||
@@ -576,7 +566,7 @@ char * _readWord() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// initiate a force scan by sending type read requests from 0 to FF to the thermostat
|
// initiate a force scan by sending type read requests from 0 to FF to the thermostat
|
||||||
// used to analyze repsonses for debugging
|
// used to analyze responses for debugging
|
||||||
void startThermostatScan(uint8_t start) {
|
void startThermostatScan(uint8_t start) {
|
||||||
ems_setLogging(EMS_SYS_LOGGING_THERMOSTAT);
|
ems_setLogging(EMS_SYS_LOGGING_THERMOSTAT);
|
||||||
publishValuesTimer.detach();
|
publishValuesTimer.detach();
|
||||||
@@ -589,22 +579,66 @@ void startThermostatScan(uint8_t start) {
|
|||||||
|
|
||||||
|
|
||||||
// callback for loading/saving settings to the file system (SPIFFS)
|
// callback for loading/saving settings to the file system (SPIFFS)
|
||||||
void FSCallback(MYESP_FSACTION action, JsonObject & json) {
|
bool FSCallback(MYESP_FSACTION action, JsonObject & json) {
|
||||||
|
bool ok = true;
|
||||||
if (action == MYESP_FSACTION_LOAD) {
|
if (action == MYESP_FSACTION_LOAD) {
|
||||||
EMSESP_Status.led_enabled = (bool)json["led"];
|
// led
|
||||||
|
if (json.containsKey("led")) {
|
||||||
|
EMSESP_Status.led_enabled = (bool)json["led"];
|
||||||
|
} else {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// led_gpio
|
||||||
|
if (json.containsKey("led_gpio")) {
|
||||||
|
EMSESP_Status.led_gpio = json["led_gpio"];
|
||||||
|
} else {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dallas_gpio
|
||||||
|
if (json.containsKey("dallas_gpio")) {
|
||||||
|
EMSESP_Status.dallas_gpio = json["dallas_gpio"];
|
||||||
|
} else {
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// thermostat_type
|
||||||
|
if (json.containsKey("thermostat_type")) {
|
||||||
|
EMS_Thermostat.type_id = json["thermostat_type"];
|
||||||
|
} else {
|
||||||
|
EMS_Thermostat.type_id = EMSESP_THERMOSTAT_TYPE; // set default
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// boiler_type
|
||||||
|
if (json.containsKey("boiler_type")) {
|
||||||
|
EMS_Boiler.type_id = json["boiler_type"];
|
||||||
|
} else {
|
||||||
|
EMS_Boiler.type_id = EMSESP_BOILER_TYPE; // set default
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action == MYESP_FSACTION_SAVE) {
|
if (action == MYESP_FSACTION_SAVE) {
|
||||||
json["led"] = EMSESP_Status.led_enabled;
|
json["led"] = EMSESP_Status.led_enabled;
|
||||||
|
json["led_gpio"] = EMSESP_Status.led_gpio;
|
||||||
|
json["dallas_gpio"] = EMSESP_Status.dallas_gpio;
|
||||||
|
json["thermostat_type"] = EMS_Thermostat.type_id;
|
||||||
|
json["boiler_type"] = EMS_Boiler.type_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ok; // all ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// callback for custom settings
|
// callback for custom settings when showing Stored Settings
|
||||||
// wc is number of arguments after the 'set' command
|
// wc is number of arguments after the 'set' command
|
||||||
|
// returns true if successful
|
||||||
bool SettingsCallback(MYESP_FSACTION action, uint8_t wc, const char * setting, const char * value) {
|
bool SettingsCallback(MYESP_FSACTION action, uint8_t wc, const char * setting, const char * value) {
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
|
|
||||||
if (action == MYESP_FSACTION_SET) {
|
if (action == MYESP_FSACTION_SET) {
|
||||||
|
// led
|
||||||
if ((strcmp(setting, "led") == 0) && (wc == 2)) {
|
if ((strcmp(setting, "led") == 0) && (wc == 2)) {
|
||||||
if (strcmp(value, "on") == 0) {
|
if (strcmp(value, "on") == 0) {
|
||||||
EMSESP_Status.led_enabled = true;
|
EMSESP_Status.led_enabled = true;
|
||||||
@@ -613,13 +647,53 @@ bool SettingsCallback(MYESP_FSACTION action, uint8_t wc, const char * setting, c
|
|||||||
EMSESP_Status.led_enabled = false;
|
EMSESP_Status.led_enabled = false;
|
||||||
ok = true;
|
ok = true;
|
||||||
// let's make sure LED is really off
|
// let's make sure LED is really off
|
||||||
digitalWrite(BOILER_LED, (BOILER_LED == LED_BUILTIN) ? HIGH : LOW); // light off. For onboard high=off
|
digitalWrite(EMSESP_Status.led_gpio, (EMSESP_Status.led_gpio == LED_BUILTIN) ? HIGH : LOW); // light off. For onboard high=off
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// led_gpio
|
||||||
|
if ((strcmp(setting, "led_gpio") == 0) && (wc == 2)) {
|
||||||
|
EMSESP_Status.led_gpio = atoi(value);
|
||||||
|
ok = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dallas_gpio
|
||||||
|
if ((strcmp(setting, "dallas_gpio") == 0) && (wc == 2)) {
|
||||||
|
EMSESP_Status.dallas_gpio = atoi(value);
|
||||||
|
ok = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// thermostat_type
|
||||||
|
if (strcmp(setting, "thermostat_type") == 0) {
|
||||||
|
EMS_Thermostat.type_id = ((wc == 2) ? (uint8_t)strtol(value, 0, 16) : EMS_ID_NONE);
|
||||||
|
ok = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// boiler_type
|
||||||
|
if (strcmp(setting, "boiler_type") == 0) {
|
||||||
|
EMS_Boiler.type_id = ((wc == 2) ? (uint8_t)strtol(value, 0, 16) : EMS_ID_NONE);
|
||||||
|
ok = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action == MYESP_FSACTION_LIST) {
|
if (action == MYESP_FSACTION_LIST) {
|
||||||
myDebug(" led=%s", EMSESP_Status.led_enabled ? "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);
|
||||||
|
|
||||||
|
if (EMS_Thermostat.type_id == EMS_ID_NONE) {
|
||||||
|
myDebug(" thermostat_type=<not set>");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
myDebug(" thermostat_type=%02X", EMS_Thermostat.type_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EMS_Boiler.type_id == EMS_ID_NONE) {
|
||||||
|
myDebug(" boiler_type=<not set>");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
myDebug(" boiler_type=%02X", EMS_Boiler.type_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ok;
|
return ok;
|
||||||
@@ -629,7 +703,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_NONE);
|
ems_setLogging(EMS_SYS_LOGGING_DEFAULT);
|
||||||
} else if (event == TELNET_EVENT_DISCONNECT) {
|
} else if (event == TELNET_EVENT_DISCONNECT) {
|
||||||
ems_setLogging(EMS_SYS_LOGGING_NONE);
|
ems_setLogging(EMS_SYS_LOGGING_NONE);
|
||||||
}
|
}
|
||||||
@@ -861,9 +935,7 @@ void WIFICallback() {
|
|||||||
myDebug("[UART] Opened Rx/Tx connection");
|
myDebug("[UART] Opened Rx/Tx connection");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// now that we're connected, set up the boiler and thermostat
|
// now that we're connected, find out what boiler and thermostats we have specified
|
||||||
// the boiler's version will be requested and if there is no thermostat hardcoded it will try
|
|
||||||
// and find the first one
|
|
||||||
ems_discoverModels();
|
ems_discoverModels();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -876,6 +948,9 @@ void initEMSESP() {
|
|||||||
EMSESP_Status.timestamp = millis();
|
EMSESP_Status.timestamp = millis();
|
||||||
EMSESP_Status.dallas_sensors = 0;
|
EMSESP_Status.dallas_sensors = 0;
|
||||||
|
|
||||||
|
EMSESP_Status.led_gpio = EMSESP_LED_GPIO;
|
||||||
|
EMSESP_Status.dallas_gpio = EMSESP_DALLAS_GPIO;
|
||||||
|
|
||||||
// shower settings
|
// shower settings
|
||||||
EMSESP_Shower.timerStart = 0;
|
EMSESP_Shower.timerStart = 0;
|
||||||
EMSESP_Shower.timerPause = 0;
|
EMSESP_Shower.timerPause = 0;
|
||||||
@@ -892,14 +967,14 @@ void do_publishValues() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// callback to light up the LED, called via Ticker every second
|
// callback to light up the LED, called via Ticker every second
|
||||||
// fast way is to use WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + (state ? 4 : 8), (1 << BOILER_LED)); // 4 is on, 8 is off
|
// fast way is to use WRITE_PERI_REG(PERIPHS_GPIO_BASEADDR + (state ? 4 : 8), (1 << EMSESP_Status.led_gpio)); // 4 is on, 8 is off
|
||||||
void do_ledcheck() {
|
void do_ledcheck() {
|
||||||
if (EMSESP_Status.led_enabled) {
|
if (EMSESP_Status.led_enabled) {
|
||||||
if (ems_getBusConnected()) {
|
if (ems_getBusConnected()) {
|
||||||
digitalWrite(BOILER_LED, (BOILER_LED == LED_BUILTIN) ? LOW : HIGH); // light on. For onboard LED high=off
|
digitalWrite(EMSESP_Status.led_gpio, (EMSESP_Status.led_gpio == LED_BUILTIN) ? LOW : HIGH); // light on. For onboard LED high=off
|
||||||
} else {
|
} else {
|
||||||
int state = digitalRead(BOILER_LED);
|
int state = digitalRead(EMSESP_Status.led_gpio);
|
||||||
digitalWrite(BOILER_LED, !state);
|
digitalWrite(EMSESP_Status.led_gpio, !state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1019,6 +1094,12 @@ void showerCheck() {
|
|||||||
// SETUP
|
// SETUP
|
||||||
//
|
//
|
||||||
void setup() {
|
void setup() {
|
||||||
|
// init our own parameters
|
||||||
|
initEMSESP();
|
||||||
|
|
||||||
|
// call ems.cpp's init function to set all the internal params
|
||||||
|
ems_init();
|
||||||
|
|
||||||
#ifndef DEBUG_SUPPORT
|
#ifndef DEBUG_SUPPORT
|
||||||
// Timers using Ticker library
|
// Timers using Ticker library
|
||||||
publishValuesTimer.attach(PUBLISHVALUES_TIME, do_publishValues); // post MQTT values
|
publishValuesTimer.attach(PUBLISHVALUES_TIME, do_publishValues); // post MQTT values
|
||||||
@@ -1031,24 +1112,22 @@ void setup() {
|
|||||||
myESP.setWIFI(WIFI_SSID, WIFI_PASSWORD, WIFICallback);
|
myESP.setWIFI(WIFI_SSID, WIFI_PASSWORD, WIFICallback);
|
||||||
myESP.setMQTT(
|
myESP.setMQTT(
|
||||||
MQTT_HOST, MQTT_USER, MQTT_PASS, MQTT_BASE, MQTT_KEEPALIVE, MQTT_QOS, MQTT_RETAIN, MQTT_WILL_TOPIC, MQTT_WILL_PAYLOAD, MQTTCallback);
|
MQTT_HOST, MQTT_USER, MQTT_PASS, MQTT_BASE, MQTT_KEEPALIVE, MQTT_QOS, MQTT_RETAIN, MQTT_WILL_TOPIC, MQTT_WILL_PAYLOAD, MQTTCallback);
|
||||||
|
|
||||||
|
// custom settings in SPIFFS
|
||||||
myESP.setSettings(FSCallback, SettingsCallback);
|
myESP.setSettings(FSCallback, SettingsCallback);
|
||||||
|
|
||||||
myESP.begin(APP_HOSTNAME, APP_NAME, APP_VERSION); // start it all up
|
// start up all the services
|
||||||
|
myESP.begin(APP_HOSTNAME, APP_NAME, APP_VERSION);
|
||||||
// init our own parameters
|
|
||||||
initEMSESP();
|
|
||||||
|
|
||||||
// set pin for LED
|
// set pin for LED
|
||||||
pinMode(BOILER_LED, OUTPUT);
|
if (EMSESP_Status.led_gpio != EMS_VALUE_INT_NOTSET) {
|
||||||
digitalWrite(BOILER_LED, (BOILER_LED == LED_BUILTIN) ? HIGH : LOW); // light off. For onboard high=off
|
pinMode(EMSESP_Status.led_gpio, OUTPUT);
|
||||||
ledcheckTimer.attach(LEDCHECK_TIME, do_ledcheck); // blink heartbeat LED
|
digitalWrite(EMSESP_Status.led_gpio, (EMSESP_Status.led_gpio == LED_BUILTIN) ? HIGH : LOW); // light off. For onboard high=off
|
||||||
|
ledcheckTimer.attach(LEDCHECK_TIME, do_ledcheck); // blink heartbeat LED
|
||||||
|
}
|
||||||
|
|
||||||
// check for Dallas sensors
|
// check for Dallas sensors
|
||||||
EMSESP_Status.dallas_sensors = ds18.setup(TEMPERATURE_SENSOR_PIN);
|
EMSESP_Status.dallas_sensors = ds18.setup(EMSESP_Status.dallas_gpio); // returns #sensors
|
||||||
|
|
||||||
// init the EMS bus
|
|
||||||
// call ems.cpp's init function to set all the internal params
|
|
||||||
ems_init(MY_THERMOSTAT_MODELID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
109
src/ems.cpp
109
src/ems.cpp
@@ -143,7 +143,7 @@ uint8_t _last_TxTelgramCRC; // CRC of last Tx sent, for checking duplicates
|
|||||||
|
|
||||||
// init stats and counters and buffers
|
// init stats and counters and buffers
|
||||||
// uses -255 or 255 for values that haven't been set yet (EMS_VALUE_INT_NOTSET and EMS_VALUE_FLOAT_NOTSET)
|
// uses -255 or 255 for values that haven't been set yet (EMS_VALUE_INT_NOTSET and EMS_VALUE_FLOAT_NOTSET)
|
||||||
void ems_init(uint8_t thermostat_modelid) {
|
void ems_init() {
|
||||||
// overall status
|
// overall status
|
||||||
EMS_Sys_Status.emsRxPgks = 0;
|
EMS_Sys_Status.emsRxPgks = 0;
|
||||||
EMS_Sys_Status.emsTxPkgs = 0;
|
EMS_Sys_Status.emsTxPkgs = 0;
|
||||||
@@ -224,15 +224,13 @@ void ems_init(uint8_t thermostat_modelid) {
|
|||||||
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
|
||||||
|
|
||||||
// boiler is hardcoded
|
// set boiler type
|
||||||
EMS_Boiler.type_id = EMS_ID_BOILER; // fixed at 0x08
|
|
||||||
EMS_Boiler.product_id = 0;
|
EMS_Boiler.product_id = 0;
|
||||||
strlcpy(EMS_Boiler.version, "not set", sizeof(EMS_Boiler.version));
|
strlcpy(EMS_Boiler.version, "not set", sizeof(EMS_Boiler.version));
|
||||||
|
|
||||||
// set thermostat model
|
// set thermostat model
|
||||||
EMS_Thermostat.type_id = EMS_ID_NONE; // fixed at 0x08
|
EMS_Thermostat.model_id = EMS_MODEL_NONE;
|
||||||
EMS_Thermostat.product_id = 0;
|
EMS_Thermostat.product_id = 0;
|
||||||
_ems_setThermostatModel(thermostat_modelid);
|
|
||||||
strlcpy(EMS_Thermostat.version, "not set", sizeof(EMS_Thermostat.version));
|
strlcpy(EMS_Thermostat.version, "not set", sizeof(EMS_Thermostat.version));
|
||||||
|
|
||||||
// counters
|
// counters
|
||||||
@@ -240,8 +238,8 @@ void ems_init(uint8_t thermostat_modelid) {
|
|||||||
_emsTxRetryCount = 0;
|
_emsTxRetryCount = 0;
|
||||||
_last_TxTelgramCRC = 0;
|
_last_TxTelgramCRC = 0;
|
||||||
|
|
||||||
// default logging is non
|
// default logging is none
|
||||||
ems_setLogging(EMS_SYS_LOGGING_NONE);
|
ems_setLogging(EMS_SYS_LOGGING_DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getters and Setters for parameters
|
// Getters and Setters for parameters
|
||||||
@@ -469,15 +467,15 @@ void _ems_sendTelegram() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if Tx is disabled, don't do anything and ignore the request
|
// if there is no destination, also delete it from the queue
|
||||||
// this could be because the boiler has yet to be found and the type_id is still empty
|
|
||||||
if (EMS_TxTelegram.dest == EMS_ID_NONE) {
|
if (EMS_TxTelegram.dest == EMS_ID_NONE) {
|
||||||
EMS_Sys_Status.emsTxStatus = EMS_TX_IDLE; // finished sending
|
EMS_Sys_Status.emsTxStatus = EMS_TX_IDLE; // finished sending
|
||||||
EMS_TxQueue.shift(); // remove from queue
|
EMS_TxQueue.shift(); // remove from queue
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there is no destination, also delete it from the queue
|
// if Tx is disabled, don't do anything and ignore the request
|
||||||
|
// this could be because the boiler has yet to be found and the type_id is still empty
|
||||||
if (!EMS_Sys_Status.emsTxEnabled) {
|
if (!EMS_Sys_Status.emsTxEnabled) {
|
||||||
myDebug("Tx is disabled. Ignoring %s request to 0x%02X.",
|
myDebug("Tx is disabled. Ignoring %s request to 0x%02X.",
|
||||||
((EMS_TxTelegram.action == EMS_TX_TELEGRAM_WRITE) ? "write" : "read"),
|
((EMS_TxTelegram.action == EMS_TX_TELEGRAM_WRITE) ? "write" : "read"),
|
||||||
@@ -516,6 +514,7 @@ void _ems_sendTelegram() {
|
|||||||
// myDebug("Duplicate message, just sent this one, so removing from queue!");
|
// myDebug("Duplicate message, just sent this one, so removing from queue!");
|
||||||
EMS_Sys_Status.emsTxStatus = EMS_TX_IDLE; // finished sending
|
EMS_Sys_Status.emsTxStatus = EMS_TX_IDLE; // finished sending
|
||||||
EMS_TxQueue.shift(); // remove the last Tx from the queue
|
EMS_TxQueue.shift(); // remove the last Tx from the queue
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
_last_TxTelgramCRC = crc;
|
_last_TxTelgramCRC = crc;
|
||||||
|
|
||||||
@@ -770,8 +769,8 @@ void _ems_processTelegram(uint8_t * telegram, uint8_t length) {
|
|||||||
*/
|
*/
|
||||||
void _processType(uint8_t * telegram, uint8_t length) {
|
void _processType(uint8_t * telegram, uint8_t length) {
|
||||||
// header
|
// header
|
||||||
uint8_t src = telegram[0] & 0x7F; // removing 8th bit as we deal with both reads and writes
|
uint8_t src = telegram[0] & 0x7F; // removing 8th bit as we deal with both reads and writes here
|
||||||
uint8_t dest = telegram[1] & 0x7F; // remove 8th bit to handle both reads and writes
|
uint8_t dest = telegram[1] & 0x7F;
|
||||||
uint8_t type = telegram[2];
|
uint8_t type = telegram[2];
|
||||||
uint8_t * data = telegram + 4; // data block starts at position 5
|
uint8_t * data = telegram + 4; // data block starts at position 5
|
||||||
|
|
||||||
@@ -781,27 +780,33 @@ void _processType(uint8_t * telegram, uint8_t length) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// did we request this telegram? If so it would be either a read or a validate telegram and still on the
|
// did we request this telegram? If so it would be either a read or a validate telegram and still
|
||||||
// Tx queue with the same type
|
// on top of the Tx queue with the same type. because we don't remove a Tx from the queue after a send
|
||||||
// if its a validate check the value, or if its a read, update the Read counter
|
// if its a validate check the value, or if its a read, update the Read counter
|
||||||
// then we can safely removed the read/validate from the queue
|
// then we can safely removed the read/validate from the queue
|
||||||
if ((dest == EMS_ID_ME) && (!EMS_TxQueue.isEmpty())) {
|
if ((dest == EMS_ID_ME) && (!EMS_TxQueue.isEmpty())) {
|
||||||
_EMS_TxTelegram EMS_TxTelegram = EMS_TxQueue.first(); // get current Tx package we last sent
|
_EMS_TxTelegram EMS_TxTelegram = EMS_TxQueue.first(); // get current Tx package we last sent
|
||||||
|
|
||||||
// do the types match? If so we were expecting this response back to us
|
// do the types match? If so we were expecting this telegram response back to us
|
||||||
if (EMS_TxTelegram.type == type) {
|
if (EMS_TxTelegram.type == type) {
|
||||||
emsaurt_tx_poll(); // send Acknowledgement back to free the EMS bus
|
emsaurt_tx_poll(); // send Acknowledgement back to free the EMS bus since we have the telegram
|
||||||
|
|
||||||
// if last action was a read, we are just happy that we actually got a response back
|
// if last action was a read, go ahead and process it
|
||||||
if (EMS_TxTelegram.action == EMS_TX_TELEGRAM_READ) {
|
if (EMS_TxTelegram.action == EMS_TX_TELEGRAM_READ) {
|
||||||
EMS_Sys_Status.emsRxPgks++; // increment rx counter
|
EMS_Sys_Status.emsRxPgks++; // increment rx counter
|
||||||
_emsTxRetryCount = 0; // reset retry count
|
_emsTxRetryCount = 0; // reset retry count
|
||||||
_ems_processTelegram(telegram, length); // and process the telegram
|
//
|
||||||
|
// and process the telegram. This calls the main function to process each type
|
||||||
|
//
|
||||||
|
_ems_processTelegram(telegram, length);
|
||||||
if (EMS_TxTelegram.forceRefresh) {
|
if (EMS_TxTelegram.forceRefresh) {
|
||||||
ems_setEmsRefreshed(true); // set the MQTT refresh flag to force sending to MQTT
|
ems_setEmsRefreshed(true); // set the MQTT refresh flag to force sending to MQTT
|
||||||
}
|
}
|
||||||
EMS_TxQueue.shift(); // remove read from queue, all done now
|
EMS_TxQueue.shift(); // remove read from queue, all done now
|
||||||
} else if (EMS_TxTelegram.action == EMS_TX_TELEGRAM_VALIDATE) {
|
return; // quit
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EMS_TxTelegram.action == EMS_TX_TELEGRAM_VALIDATE) {
|
||||||
// this read was for a validate. Do a compare on the 1 byte result from the last write
|
// this read was for a validate. Do a compare on the 1 byte result from the last write
|
||||||
uint8_t dataReceived = data[0]; // only a single byte is returned after a read
|
uint8_t dataReceived = data[0]; // only a single byte is returned after a read
|
||||||
if (EMS_TxTelegram.comparisonValue == dataReceived) {
|
if (EMS_TxTelegram.comparisonValue == dataReceived) {
|
||||||
@@ -816,7 +821,7 @@ void _processType(uint8_t * telegram, uint8_t length) {
|
|||||||
} else {
|
} else {
|
||||||
// write failed.
|
// write failed.
|
||||||
if (EMS_Sys_Status.emsLogging >= EMS_SYS_LOGGING_BASIC) {
|
if (EMS_Sys_Status.emsLogging >= EMS_SYS_LOGGING_BASIC) {
|
||||||
myDebug("Last write failed. Compared set value 0x%02X with received value 0x%02X.",
|
myDebug("Last write failed. Compared set value 0x%02X with received value 0x%02X",
|
||||||
EMS_TxTelegram.comparisonValue,
|
EMS_TxTelegram.comparisonValue,
|
||||||
dataReceived);
|
dataReceived);
|
||||||
}
|
}
|
||||||
@@ -838,9 +843,18 @@ void _processType(uint8_t * telegram, uint8_t length) {
|
|||||||
EMS_TxQueue.unshift(EMS_TxTelegram); // add back to queue making it next in line
|
EMS_TxQueue.unshift(EMS_TxTelegram); // add back to queue making it next in line
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// telegram was for us, but seems we didn't ask for it
|
// telegram was for us, but seems we didn't ask for it
|
||||||
|
// so kinda invalidates the last action on the queue remove from queue
|
||||||
|
myDebug("Telegram sent to us but we didn't ask for it! (src=0x%02X dest=0x%02X type=0x%02X)",
|
||||||
|
telegram[0] & 0x7F,
|
||||||
|
telegram[1] & 0x7F,
|
||||||
|
telegram[2]);
|
||||||
|
// ems_printTxQueue();
|
||||||
|
// EMS_TxQueue.shift(); // remove validate from queue
|
||||||
} else {
|
} else {
|
||||||
// we didn't request it, was for somebody else or a broadcast, process it anyway
|
// we didn't request it, was for somebody else or a broadcast, process it anyway
|
||||||
_ems_processTelegram(telegram, length);
|
_ems_processTelegram(telegram, length);
|
||||||
@@ -1055,6 +1069,7 @@ void _process_Version(uint8_t * data, uint8_t length) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool do_save = false;
|
||||||
uint8_t product_id = data[0];
|
uint8_t product_id = data[0];
|
||||||
char version[10] = {0};
|
char version[10] = {0};
|
||||||
snprintf(version, sizeof(version), "%02d.%02d", data[1], data[2]);
|
snprintf(version, sizeof(version), "%02d.%02d", data[1], data[2]);
|
||||||
@@ -1072,29 +1087,33 @@ void _process_Version(uint8_t * data, uint8_t length) {
|
|||||||
|
|
||||||
if (typeFound) {
|
if (typeFound) {
|
||||||
// its a boiler
|
// its a boiler
|
||||||
if (EMS_Sys_Status.emsLogging >= EMS_SYS_LOGGING_BASIC) {
|
myDebug("Boiler type device found. Model %s with TypeID 0x%02X, Product ID %d, Version %s",
|
||||||
myDebug("Boiler found. Model %s with TypeID 0x%02X, Product ID %d, Version %s",
|
Boiler_Types[i].model_string,
|
||||||
|
Boiler_Types[i].type_id,
|
||||||
|
product_id,
|
||||||
|
version);
|
||||||
|
|
||||||
|
// if its a boiler set it
|
||||||
|
// it will take the first one found in the list
|
||||||
|
if ((EMS_Boiler.type_id == EMS_ID_NONE) || (EMS_Boiler.type_id == Boiler_Types[i].type_id)) {
|
||||||
|
myDebug("* Setting Boiler type to Model %s, TypeID 0x%02X, Product ID %d, Version %s",
|
||||||
Boiler_Types[i].model_string,
|
Boiler_Types[i].model_string,
|
||||||
Boiler_Types[i].type_id,
|
Boiler_Types[i].type_id,
|
||||||
product_id,
|
product_id,
|
||||||
version);
|
version);
|
||||||
}
|
|
||||||
|
|
||||||
// if its a boiler set it (even if it was already set)
|
|
||||||
if (Boiler_Types[i].type_id == EMS_ID_BOILER) {
|
|
||||||
if (EMS_Sys_Status.emsLogging >= EMS_SYS_LOGGING_BASIC) {
|
|
||||||
myDebug("* Setting boiler to this new type");
|
|
||||||
}
|
|
||||||
EMS_Boiler.type_id = Boiler_Types[i].type_id;
|
EMS_Boiler.type_id = Boiler_Types[i].type_id;
|
||||||
EMS_Boiler.product_id = Boiler_Types[i].product_id;
|
EMS_Boiler.product_id = Boiler_Types[i].product_id;
|
||||||
strlcpy(EMS_Boiler.version, version, sizeof(EMS_Boiler.version));
|
strlcpy(EMS_Boiler.version, version, sizeof(EMS_Boiler.version));
|
||||||
|
|
||||||
|
do_save = true;
|
||||||
|
|
||||||
ems_getBoilerValues(); // get Boiler values that we would usually have to wait for
|
ems_getBoilerValues(); // get Boiler values that we would usually have to wait for
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// its not a boiler, maybe its a known thermostat
|
// its not a boiler, maybe its a known thermostat?
|
||||||
i = 0;
|
i = 0;
|
||||||
while (i < _Thermostat_Types_max) {
|
while (i < _Thermostat_Types_max) {
|
||||||
if (Thermostat_Types[i].product_id == product_id) {
|
if (Thermostat_Types[i].product_id == product_id) {
|
||||||
@@ -1115,11 +1134,14 @@ void _process_Version(uint8_t * data, uint8_t length) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if we don't have a thermostat set, use this one
|
// if we don't have a thermostat set, use this one
|
||||||
// if its the one we hard coded, refresh the data anyway
|
if ((EMS_Thermostat.type_id == EMS_ID_NONE) || (EMS_Thermostat.model_id == EMS_MODEL_NONE)
|
||||||
if ((EMS_Thermostat.model_id == EMS_MODEL_NONE) || (EMS_Thermostat.model_id == Thermostat_Types[i].model_id)) {
|
|| (EMS_Thermostat.type_id == Thermostat_Types[i].type_id)) {
|
||||||
if (EMS_Sys_Status.emsLogging >= EMS_SYS_LOGGING_BASIC) {
|
myDebug("* Setting Thermostat type to Model %s, TypeID 0x%02X, Product ID %d, Version %s",
|
||||||
myDebug("* Setting thermostat to this new type");
|
Thermostat_Types[i].model_string,
|
||||||
}
|
Thermostat_Types[i].type_id,
|
||||||
|
product_id,
|
||||||
|
version);
|
||||||
|
|
||||||
EMS_Thermostat.model_id = Thermostat_Types[i].model_id;
|
EMS_Thermostat.model_id = Thermostat_Types[i].model_id;
|
||||||
EMS_Thermostat.type_id = Thermostat_Types[i].type_id;
|
EMS_Thermostat.type_id = Thermostat_Types[i].type_id;
|
||||||
EMS_Thermostat.read_supported = Thermostat_Types[i].read_supported;
|
EMS_Thermostat.read_supported = Thermostat_Types[i].read_supported;
|
||||||
@@ -1127,12 +1149,19 @@ void _process_Version(uint8_t * data, uint8_t length) {
|
|||||||
EMS_Thermostat.product_id = product_id;
|
EMS_Thermostat.product_id = product_id;
|
||||||
strlcpy(EMS_Thermostat.version, version, sizeof(EMS_Thermostat.version));
|
strlcpy(EMS_Thermostat.version, version, sizeof(EMS_Thermostat.version));
|
||||||
|
|
||||||
|
do_save = true;
|
||||||
|
|
||||||
// get Thermostat values (if supported)
|
// get Thermostat values (if supported)
|
||||||
ems_getThermostatValues();
|
ems_getThermostatValues();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
myDebug("Unrecognized device found. Product ID %d, Version %s", product_id, version);
|
myDebug("Unrecognized device found. Product ID %d, Version %s", product_id, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the boiler or thermostat values have changed, save them to SPIFFS
|
||||||
|
if (do_save) {
|
||||||
|
myESP.fs_saveConfig();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1140,15 +1169,15 @@ void _process_Version(uint8_t * data, uint8_t length) {
|
|||||||
*/
|
*/
|
||||||
void ems_discoverModels() {
|
void ems_discoverModels() {
|
||||||
// boiler
|
// boiler
|
||||||
ems_doReadCommand(EMS_TYPE_Version, EMS_ID_BOILER); // get version details of boiler
|
ems_doReadCommand(EMS_TYPE_Version, EMS_Boiler.type_id); // get version details of boiler
|
||||||
ems_getBoilerValues(); // fetch values from boiler, instead of waiting for broadcasts
|
ems_getBoilerValues(); // fetch values from boiler, instead of waiting for broadcasts
|
||||||
|
|
||||||
// thermostat
|
// thermostat
|
||||||
if (EMS_Thermostat.model_id == EMS_MODEL_NONE) {
|
// if it hasn't been set, auto discover it
|
||||||
|
if (EMS_Thermostat.type_id == EMS_ID_NONE) {
|
||||||
ems_scanDevices(); // auto-discover it
|
ems_scanDevices(); // auto-discover it
|
||||||
} else {
|
} else {
|
||||||
// set the model as hardcoded (see my_devices.h) and fetch the version and product id
|
// set the model as hardcoded (see my_devices.h) and fetch the version and product id
|
||||||
_ems_setThermostatModel(EMS_Thermostat.model_id);
|
|
||||||
ems_doReadCommand(EMS_TYPE_Version, EMS_Thermostat.type_id);
|
ems_doReadCommand(EMS_TYPE_Version, EMS_Thermostat.type_id);
|
||||||
ems_getThermostatValues();
|
ems_getThermostatValues();
|
||||||
}
|
}
|
||||||
|
|||||||
14
src/ems.h
14
src/ems.h
@@ -13,19 +13,15 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
// EMS IDs
|
// EMS IDs
|
||||||
#define EMS_ID_NONE 0x00 // Fixed - used as a dest in broadcast messages and empty type IDs
|
#define EMS_ID_NONE 0x00 // Fixed - used as a dest in broadcast messages and empty type IDs
|
||||||
#define EMS_ID_ME 0x0B // Fixed - our device, hardcoded as the "Service Key"
|
#define EMS_ID_ME 0x0B // Fixed - our device, hardcoded as the "Service Key"
|
||||||
#define EMS_ID_BOILER 0x08 // Fixed - boilers are always 0x08. I think.
|
#define EMS_ID_DEFAULT_BOILER 0x08
|
||||||
|
|
||||||
#define EMS_MIN_TELEGRAM_LENGTH 6 // minimal length for a validation telegram, including CRC
|
#define EMS_MIN_TELEGRAM_LENGTH 6 // minimal length for a validation telegram, including CRC
|
||||||
|
|
||||||
// max length of a telegram, including CRC, for Rx and Tx.
|
// max length of a telegram, including CRC, for Rx and Tx.
|
||||||
// This can differs per firmware version and typically 32 is the max
|
|
||||||
#define EMS_MAX_TELEGRAM_LENGTH 99
|
#define EMS_MAX_TELEGRAM_LENGTH 99
|
||||||
|
|
||||||
// Common for all EMS devices
|
|
||||||
#define EMS_TYPE_Version 0x02 // version of the UBA controller (boiler)
|
|
||||||
|
|
||||||
// default values
|
// default values
|
||||||
#define EMS_VALUE_INT_ON 1 // boolean true
|
#define EMS_VALUE_INT_ON 1 // boolean true
|
||||||
#define EMS_VALUE_INT_OFF 0 // boolean false
|
#define EMS_VALUE_INT_OFF 0 // boolean false
|
||||||
@@ -60,6 +56,8 @@
|
|||||||
|
|
||||||
#define EMS_TX_TELEGRAM_QUEUE_MAX 50 // max size of Tx FIFO queue
|
#define EMS_TX_TELEGRAM_QUEUE_MAX 50 // max size of Tx FIFO queue
|
||||||
|
|
||||||
|
//#define EMS_SYS_LOGGING_DEFAULT EMS_SYS_LOGGING_VERBOSE
|
||||||
|
#define EMS_SYS_LOGGING_DEFAULT EMS_SYS_LOGGING_NONE
|
||||||
|
|
||||||
/* EMS UART transfer status */
|
/* EMS UART transfer status */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -251,7 +249,7 @@ typedef struct {
|
|||||||
|
|
||||||
// function definitions
|
// function definitions
|
||||||
extern void ems_parseTelegram(uint8_t * telegram, uint8_t len);
|
extern void ems_parseTelegram(uint8_t * telegram, uint8_t len);
|
||||||
void ems_init(uint8_t thermostat_modelid);
|
void ems_init();
|
||||||
void ems_doReadCommand(uint8_t type, uint8_t dest, bool forceRefresh = false);
|
void ems_doReadCommand(uint8_t type, uint8_t dest, bool forceRefresh = false);
|
||||||
void ems_sendRawTelegram(char * telegram);
|
void ems_sendRawTelegram(char * telegram);
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Paul Derbyshire - https://github.com/proddy/EMS-ESP
|
* Paul Derbyshire - https://github.com/proddy/EMS-ESP
|
||||||
*
|
*
|
||||||
* See ChangeLog.md for history
|
* See ChangeLog.md for History
|
||||||
* See README.md for Acknowledgments
|
* See README.md for Acknowledgments
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -12,6 +12,12 @@
|
|||||||
|
|
||||||
#include "ems.h"
|
#include "ems.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Common
|
||||||
|
*/
|
||||||
|
#define EMS_TYPE_Version 0x02
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Boiler...
|
* Boiler...
|
||||||
*/
|
*/
|
||||||
@@ -91,11 +97,10 @@ typedef enum {
|
|||||||
|
|
||||||
} _EMS_MODEL_ID;
|
} _EMS_MODEL_ID;
|
||||||
|
|
||||||
// EMS types for known Buderus devices. This list will be extended when new devices are recognized.
|
// EMS types for known Buderus/Bosch devices. This list will be extended when new devices are recognized.
|
||||||
// format is MODEL_ID, PRODUCT ID, TYPE_ID, DESCRIPTION
|
// format is MODEL_ID, PRODUCT ID, TYPE_ID, DESCRIPTION
|
||||||
const _Boiler_Type Boiler_Types[] = {
|
const _Boiler_Type Boiler_Types[] = {
|
||||||
|
|
||||||
// various boilers and buderus type devices
|
|
||||||
{EMS_MODEL_UBA, 72, 0x08, "MC10"},
|
{EMS_MODEL_UBA, 72, 0x08, "MC10"},
|
||||||
{EMS_MODEL_UBA, 123, 0x08, "Buderus GB172/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"},
|
||||||
|
|||||||
@@ -10,15 +10,6 @@
|
|||||||
|
|
||||||
#include "ems.h"
|
#include "ems.h"
|
||||||
|
|
||||||
// Set your wifi and mqtt params
|
|
||||||
// If set to NULL (default) you'll need to set them in AP mode using the 'set' command
|
|
||||||
// as these values are stored in SPIFFs for persisted
|
|
||||||
#define WIFI_SSID NULL
|
|
||||||
#define WIFI_PASSWORD NULL
|
|
||||||
#define MQTT_HOST NULL
|
|
||||||
#define MQTT_USER NULL
|
|
||||||
#define MQTT_PASS NULL
|
|
||||||
|
|
||||||
// All MQTT topics are prefixed with the following string
|
// All MQTT topics are prefixed with the following string
|
||||||
#define MQTT_BASE "home"
|
#define MQTT_BASE "home"
|
||||||
#define MQTT_TOPIC_START "start"
|
#define MQTT_TOPIC_START "start"
|
||||||
@@ -29,21 +20,53 @@
|
|||||||
#define MQTT_KEEPALIVE 300
|
#define MQTT_KEEPALIVE 300
|
||||||
#define MQTT_QOS 1
|
#define MQTT_QOS 1
|
||||||
|
|
||||||
|
// 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 THERMOSTAT_CURRTEMP "thermostat_currtemp" // current temperature
|
||||||
|
#define THERMOSTAT_SELTEMP "thermostat_seltemp" // selected temperature
|
||||||
|
#define THERMOSTAT_MODE "thermostat_mode" // mode
|
||||||
|
|
||||||
|
// boiler
|
||||||
|
#define TOPIC_BOILER_DATA "boiler_data" // for sending boiler values
|
||||||
|
#define TOPIC_BOILER_TAPWATER_ACTIVE "tapwater_active" // if hot tap water is running
|
||||||
|
#define TOPIC_BOILER_HEATING_ACTIVE "heating_active" // if heating is on
|
||||||
|
|
||||||
|
// shower time
|
||||||
|
#define TOPIC_SHOWERTIME "showertime" // for sending shower time results
|
||||||
|
#define TOPIC_SHOWER_TIMER "shower_timer" // toggle switch for enabling the shower logic
|
||||||
|
#define TOPIC_SHOWER_ALERT "shower_alert" // toggle switch for enabling the shower alarm logic
|
||||||
|
#define TOPIC_SHOWER_COLDSHOT "shower_coldshot" // used to trigger a coldshot from an MQTT command
|
||||||
|
|
||||||
// default values for shower logic on/off
|
// default values for shower logic on/off
|
||||||
#define BOILER_SHOWER_TIMER 1 // enable (1) to monitor shower time
|
#define BOILER_SHOWER_TIMER 1 // enable (1) to monitor shower time
|
||||||
#define BOILER_SHOWER_ALERT 0 // enable (1) to send alert of cold water when shower time limit has exceeded
|
#define BOILER_SHOWER_ALERT 0 // enable (1) to send alert of cold water when shower time limit has exceeded
|
||||||
#define SHOWER_MAX_DURATION 420000 // in ms. 7 minutes, before trigger a shot of cold water
|
#define SHOWER_MAX_DURATION 420000 // in ms. 7 minutes, before trigger a shot of cold water
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// THESE DEFAULT VALUES CAN ALSO BE SET AND STORED WITHTIN THE APPLICATION (see 'set' command) //
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Set your wifi and mqtt params
|
||||||
|
// If set to NULL (default) you'll need to set them in AP mode using the 'set' command
|
||||||
|
#define WIFI_SSID NULL
|
||||||
|
#define WIFI_PASSWORD NULL
|
||||||
|
#define MQTT_HOST NULL
|
||||||
|
#define MQTT_USER NULL
|
||||||
|
#define MQTT_PASS NULL
|
||||||
|
|
||||||
// Set LED pin used for showing ems bus connection status. Solid is connected, Flashing is error
|
// Set LED pin used for showing ems bus connection status. Solid is connected, Flashing is error
|
||||||
// can be either the onboard LED on the ESP8266 or external via an external pull-up LED (e.g. D1 on bbqkees' board)
|
// can be either the onboard LED on the ESP8266 (LED_BULLETIN) or external via an external pull-up LED (e.g. D1 on bbqkees' board)
|
||||||
// can be enabled and disabled via the 'set led' command
|
// can be enabled and disabled via the 'set led' command
|
||||||
#define BOILER_LED LED_BUILTIN // LED_BULLETIN for onboard LED
|
// pin can be set by 'set led_gpio'
|
||||||
|
#define EMSESP_LED_GPIO LED_BUILTIN
|
||||||
|
|
||||||
// set this if using an external temperature sensor like a DS18B20
|
// set this if using an external temperature sensor like a DS18B20
|
||||||
// D5 is the default on bbqkees' board
|
// D5 is the default on bbqkees' board
|
||||||
#define TEMPERATURE_SENSOR_PIN D5
|
#define EMSESP_DALLAS_GPIO D5
|
||||||
|
|
||||||
// By default the EMS bus will be scanned for known devices based on product ids in ems_devices.h
|
// By default the EMS bus will be scanned for known devices based on product ids in ems_devices.h
|
||||||
// You can override the Thermostat model by hardcoding the model type
|
// You can override the Thermostat and Boiler types here
|
||||||
#define MY_THERMOSTAT_MODELID EMS_MODEL_NONE
|
#define EMSESP_BOILER_TYPE EMS_ID_NONE
|
||||||
//#define MY_THERMOSTAT_MODELID EMS_MODEL_RC35
|
#define EMSESP_THERMOSTAT_TYPE EMS_ID_NONE
|
||||||
|
|||||||
@@ -6,5 +6,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define APP_NAME "EMS-ESP"
|
#define APP_NAME "EMS-ESP"
|
||||||
#define APP_VERSION "1.4.0"
|
#define APP_VERSION "1.4.1"
|
||||||
#define APP_HOSTNAME "ems-esp"
|
#define APP_HOSTNAME "ems-esp"
|
||||||
|
|||||||
Reference in New Issue
Block a user