diff --git a/CHANGELOG.md b/CHANGELOG.md
index f79a9ab5e..e7ce26930 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [1.9.4 beta]
+There are breaking changes in this release. See `publish_time` below and make sure you set this value to 0.
+
### Added
- Added `publish_always` forcing MQTT topics to be always sent regardless if the data hasn't changed
@@ -28,6 +30,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- fixed version numbers of libraries in `platformio.ini`
- Normalized Heating modes to `off`, `manual`, `auto`, `night` and `day` to keep generic and not Home Assistant specific (like `heat`)
- Keeping Thermostat day/night modes separate from off/auto/manual, and setting this for the Junkers FR50
+- Removed `publish_always` and use `publish_time`. For automatic mode you will need to change `publish_time` to 0 which will send MQTT every time data has changed (every 10 seconds).
+- Changed NTP interval from 1 hour to 12 hours
### Removed
@@ -201,7 +205,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- publish dallas external temp sensors to MQTT (thanks @JewelZB)
- shower timer and shower alert options available via set commands
- added support for warm water modes Hot, Comfort and Intelligent [(issue 67)](https://github.com/proddy/EMS-ESP/issues/67)
-- added `set publish_time` to set how often to publish MQTT
+- added `set publish_time` to set how often to force a publish of MQTT
- support for SM10 Solar Module including MQTT [(issue 77)](https://github.com/proddy/EMS-ESP/issues/77)
- `refresh` command to force a fetch of all known data from the connected EMS devices
diff --git a/src/custom.htm b/src/custom.htm
index 21e871205..0f4d2abdf 100644
--- a/src/custom.htm
+++ b/src/custom.htm
@@ -114,29 +114,14 @@
Publish Time
+ data-content="How often to send MQTT topics with stats. 0 is automatic. (in seconds)">
-
-
- Publish Always
-
-
-
-
-
-
Tx mode", "when set to on all automatic Tx are disabled"},
{true, "shower_timer ", "send MQTT notification on all shower durations"},
{true, "shower_alert ", "stop hot water to send 3 cold burst warnings after max shower time is exceeded"},
- {true, "publish_time ", "set frequency for publishing data to MQTT (0=off)"},
- {true, "publish_always ", "set to on to skip payload comparison since last publish"},
-
+ {true, "publish_time ", "set frequency for publishing data to MQTT (0=automatic)"},
{true, "tx_mode ", "changes Tx logic. 1=EMS generic, 2=EMS+, 3=HT3"},
{false, "info", "show current captured on the devices"},
@@ -507,12 +506,16 @@ void showInfo() {
}
// send all dallas sensor values as a JSON package to MQTT
-void publishSensorValues() {
+void publishSensorValues(bool force) {
// don't send if MQTT is connected
if (!myESP.isMQTTConnected()) {
return;
}
+ if (!EMSESP_Settings.dallas_sensors) {
+ return; // no sensors attached
+ }
+
StaticJsonDocument<200> doc;
JsonObject sensors = doc.to();
@@ -530,11 +533,29 @@ void publishSensorValues() {
}
}
- if (hasdata) {
- char data[200] = {0};
- serializeJson(doc, data, sizeof(data));
- myDebugLog("Publishing external sensor data via MQTT");
- myESP.mqttPublish(TOPIC_EXTERNAL_SENSORS, data);
+ if (!hasdata) {
+ return; // nothing to send
+ }
+
+ CRC32 crc;
+ uint32_t fchecksum;
+
+ char data[200] = {0};
+ serializeJson(doc, data, sizeof(data));
+
+ size_t jsonSize = measureJson(doc);
+ if (hasdata && (jsonSize > 2)) {
+ // calculate hash and send values if something has changed, to save unnecessary wifi traffic
+ for (uint8_t i = 0; i < (jsonSize - 1); i++) {
+ crc.update(data[i]);
+ }
+ fchecksum = crc.finalize();
+ static uint32_t previousSensorPublishCRC; // CRC check for new values
+ if ((previousSensorPublishCRC != fchecksum) || force) {
+ previousSensorPublishCRC = fchecksum;
+ myDebugLog("Publishing external sensor data via MQTT");
+ myESP.mqttPublish(TOPIC_EXTERNAL_SENSORS, data);
+ }
}
}
@@ -542,19 +563,18 @@ void publishSensorValues() {
// a json object is created for the boiler and one for the thermostat
// CRC check is done to see if there are changes in the values since the last send to avoid too much wifi traffic
// a check is done against the previous values and if there are changes only then they are published. Unless force=true
-void publishValues(bool force) {
+void publishEMSValues(bool force) {
// don't send if MQTT is not connected
if (!myESP.isMQTTConnected()) {
return;
}
- // don't publish is publish time is set to 0
- if (EMSESP_Settings.publish_time == 0) {
- return;
+ if (!ems_getBusConnected()) {
+ return; // EMS bus is not connected
}
- // override force
- if (EMSESP_Settings.publish_always) {
+ // override force id not on automatic mode. Always send values is there is a publish_time set
+ if (EMSESP_Settings.publish_time != 0) {
force = true;
}
@@ -900,17 +920,12 @@ void publishValues(bool force) {
// publish external dallas sensor temperature values to MQTT
void do_publishSensorValues() {
- if ((EMSESP_Settings.dallas_sensors) && (EMSESP_Settings.publish_time)) {
- publishSensorValues();
- }
+ publishSensorValues(true); // force publish
}
// call PublishValues without forcing, so using CRC to see if we really need to publish
void do_publishValues() {
- // don't publish if we're not connected to the EMS bus
- if ((ems_getBusConnected()) && myESP.isMQTTConnected() && EMSESP_Settings.publish_time) {
- publishValues(true); // force publish
- }
+ publishEMSValues(true); // force publish
}
// callback to light up the LED, called via Ticker every second
@@ -993,7 +1008,6 @@ bool LoadSaveCallback(MYESP_FSACTION_t action, JsonObject settings) {
EMSESP_Settings.shower_timer = settings["shower_timer"];
EMSESP_Settings.shower_alert = settings["shower_alert"];
EMSESP_Settings.publish_time = settings["publish_time"] | DEFAULT_PUBLISHTIME;
- EMSESP_Settings.publish_always = settings["publish_always"];
EMSESP_Settings.listen_mode = settings["listen_mode"];
ems_setTxDisabled(EMSESP_Settings.listen_mode);
@@ -1013,7 +1027,6 @@ bool LoadSaveCallback(MYESP_FSACTION_t action, JsonObject settings) {
settings["shower_timer"] = EMSESP_Settings.shower_timer;
settings["shower_alert"] = EMSESP_Settings.shower_alert;
settings["publish_time"] = EMSESP_Settings.publish_time;
- settings["publish_always"] = EMSESP_Settings.publish_always;
settings["tx_mode"] = EMSESP_Settings.tx_mode;
return true;
@@ -1148,19 +1161,6 @@ bool SetListCallback(MYESP_FSACTION_t action, uint8_t wc, const char * setting,
ok = true;
}
- // publish_always
- if ((strcmp(setting, "publish_always") == 0) && (wc == 2)) {
- if (strcmp(value, "on") == 0) {
- EMSESP_Settings.publish_always = true;
- ok = true;
- } else if (strcmp(value, "off") == 0) {
- EMSESP_Settings.publish_always = false;
- ok = true;
- } else {
- myDebug_P(PSTR("Error. Usage: set publish_always "));
- }
- }
-
// tx_mode
if ((strcmp(setting, "tx_mode") == 0) && (wc == 2)) {
uint8_t mode = atoi(value);
@@ -1184,7 +1184,6 @@ bool SetListCallback(MYESP_FSACTION_t action, uint8_t wc, const char * setting,
myDebug_P(PSTR(" shower_timer=%s"), EMSESP_Settings.shower_timer ? "on" : "off");
myDebug_P(PSTR(" shower_alert=%s"), EMSESP_Settings.shower_alert ? "on" : "off");
myDebug_P(PSTR(" publish_time=%d"), EMSESP_Settings.publish_time);
- myDebug_P(PSTR(" publish_always=%s"), EMSESP_Settings.publish_always ? "on" : "off");
}
return ok;
@@ -1589,7 +1588,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
if (strcmp(topic, TOPIC_BOILER_CMD_WWTEMP) == 0) {
uint8_t t = atoi((char *)message);
ems_setWarmWaterTemp(t);
- publishValues(true);
+ publishEMSValues(true);
return;
}
@@ -1599,7 +1598,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
if (hc) {
float f = strtof((char *)message, 0);
ems_setThermostatTemp(f, hc);
- publishValues(true); // publish back immediately
+ publishEMSValues(true); // publish back immediately
return;
}
@@ -1632,7 +1631,7 @@ void MQTTCallback(unsigned int type, const char * topic, const char * message) {
if (hc) {
float f = doc["data"];
ems_setThermostatTemp(f, hc);
- publishValues(true); // publish back immediately
+ publishEMSValues(true); // publish back immediately
return;
}
@@ -1862,7 +1861,6 @@ void initEMSESP() {
EMSESP_Settings.led = true; // LED is on by default
EMSESP_Settings.listen_mode = false;
EMSESP_Settings.publish_time = DEFAULT_PUBLISHTIME;
- EMSESP_Settings.publish_always = false;
EMSESP_Settings.dallas_sensors = 0;
EMSESP_Settings.led_gpio = EMSESP_LED_GPIO;
EMSESP_Settings.dallas_gpio = EMSESP_DALLAS_GPIO;
@@ -1985,6 +1983,7 @@ void setup() {
}
// set timers for MQTT publish
+ // only if publish_time is not 0 (automatic mode)
if (EMSESP_Settings.publish_time) {
publishValuesTimer.attach(EMSESP_Settings.publish_time, do_publishValues); // post MQTT EMS values
publishSensorValuesTimer.attach(EMSESP_Settings.publish_time, do_publishSensorValues); // post MQTT dallas sensor values
@@ -2007,8 +2006,7 @@ void setup() {
// Main loop
//
void loop() {
- // the main loop
- myESP.loop();
+ myESP.loop(); // handle telnet, mqtt, wifi etc
// check Dallas sensors, using same schedule as publish_time (default 2 mins)
// these values are published to MQTT separately via the timer publishSensorValuesTimer
@@ -2016,12 +2014,25 @@ void loop() {
ds18.loop();
}
- // publish all the values to MQTT, only if the values have changed
- // although we don't want to publish when doing a deep scan of the thermostat
+ // check if we have data from the EMS bus
if (ems_getEmsRefreshed()) {
- publishValues(false);
- do_publishSensorValues();
- ems_setEmsRefreshed(false); // reset
+ // if we have an EMS connect go and fetch some data and publish it (by force)
+ if (_need_first_publish) {
+ do_regularUpdates();
+ publishEMSValues(true);
+ publishSensorValues(true);
+ _need_first_publish = false; // reset flag
+ }
+
+ // publish all the values to MQTT
+ // but only if the values have changed and publish_time is on automatic mode
+ // always publish when we get the first results, regardless of any publish_time setting
+ if (EMSESP_Settings.publish_time == 0) {
+ publishEMSValues(false);
+ publishSensorValues(false);
+ }
+
+ ems_setEmsRefreshed(false); // reset flag
}
// do shower logic, if enabled
diff --git a/src/ems.cpp b/src/ems.cpp
index 4254a406d..185493cba 100644
--- a/src/ems.cpp
+++ b/src/ems.cpp
@@ -2287,6 +2287,7 @@ void ems_printTxQueue() {
/**
* Generic function to return various settings from the thermostat
+ * This is called manually to fetch values which don't come from broadcast messages
*/
void ems_getThermostatValues() {
if (!ems_getThermostatEnabled()) {
@@ -2994,13 +2995,13 @@ void ems_setThermostatMode(uint8_t mode, uint8_t hc_num) {
if (model_id == EMS_MODEL_RC20) {
EMS_TxTelegram.type = EMS_TYPE_RC20Set;
EMS_TxTelegram.offset = EMS_OFFSET_RC20Set_mode;
- EMS_TxTelegram.type_validate = EMS_TxTelegram.type;
+ EMS_TxTelegram.type_validate = EMS_TYPE_RC20Set;
EMS_TxTelegram.comparisonPostRead = EMS_TYPE_RC20StatusMessage;
} else if (model_id == EMS_MODEL_RC30) {
EMS_TxTelegram.type = EMS_TYPE_RC30Set;
EMS_TxTelegram.offset = EMS_OFFSET_RC30Set_mode;
- EMS_TxTelegram.type_validate = EMS_TxTelegram.type;
+ EMS_TxTelegram.type_validate = EMS_TYPE_RC30Set;
EMS_TxTelegram.comparisonPostRead = EMS_TYPE_RC30StatusMessage;
} else if ((model_id == EMS_MODEL_RC35) || (model_id == EMS_MODEL_ES73)) {
diff --git a/tools/wsemulator/wserver.js b/tools/wsemulator/wserver.js
index d4f9976cb..c96477ab8 100644
--- a/tools/wsemulator/wserver.js
+++ b/tools/wsemulator/wserver.js
@@ -103,8 +103,7 @@ var custom_configfile = {
"listen_mode": false,
"shower_timer": true,
"shower_alert": false,
- "publish_time": 120,
- "publish_always": false,
+ "publish_time": 0,
"tx_mode": 1
}
};