mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 07:49:52 +03:00
added mqtt_nestedjson
This commit is contained in:
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- `boiler wwonetime` command from Telnet
|
- `boiler wwonetime` command from Telnet
|
||||||
- `set bus_id <ID>` to support multiple EMS-ESP circuits. Default is 0x0B to mimic a service key.
|
- `set bus_id <ID>` to support multiple EMS-ESP circuits. Default is 0x0B to mimic a service key.
|
||||||
- MQTT publish messages are queued and gracefully published every second to avoid TCP blocks
|
- MQTT publish messages are queued and gracefully published every second to avoid TCP blocks
|
||||||
|
- Added `mqtt_nestedjson` option to disable multiple data records being nested into a single JSON string
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- set boiler warm water temp on Junkers/Bosch HT3
|
- set boiler warm water temp on Junkers/Bosch HT3
|
||||||
@@ -29,7 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
- `autodetect scan`
|
- `autodetect scan`
|
||||||
- `mqttlog` and showing MQTT log in the web interface - no point showing history of previous mqtt publishes in ESP's precious memory. For debugging recommend using MQTT Explorer or another external tool.
|
- `mqttlog all` and showing MQTT log in the web interface - no point showing history of previous mqtt publishes in ESP's precious memory. For debugging I recommend using MQTT Explorer or another external tool.
|
||||||
|
|
||||||
## [1.9.4] 15-12-2019
|
## [1.9.4] 15-12-2019
|
||||||
|
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ MyESP::MyESP() {
|
|||||||
_mqtt_heartbeat = false;
|
_mqtt_heartbeat = false;
|
||||||
_mqtt_keepalive = MQTT_KEEPALIVE;
|
_mqtt_keepalive = MQTT_KEEPALIVE;
|
||||||
_mqtt_qos = MQTT_QOS;
|
_mqtt_qos = MQTT_QOS;
|
||||||
|
_mqtt_nestedjson = false;
|
||||||
_mqtt_retain = MQTT_RETAIN;
|
_mqtt_retain = MQTT_RETAIN;
|
||||||
_mqtt_will_topic = strdup(MQTT_WILL_TOPIC);
|
_mqtt_will_topic = strdup(MQTT_WILL_TOPIC);
|
||||||
_mqtt_will_online_payload = strdup(MQTT_WILL_ONLINE_PAYLOAD);
|
_mqtt_will_online_payload = strdup(MQTT_WILL_ONLINE_PAYLOAD);
|
||||||
@@ -527,9 +528,8 @@ void MyESP::_mqttPublishQueue() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (packet_id == 0) {
|
if (packet_id == 0) {
|
||||||
// it failed
|
// it failed. if we retried n times, give up. remove from queue
|
||||||
// if we retried 3 times, give up. remove from queue
|
if (element.retry_count == (MQTT_PUBLISH_MAX_RETRY - 1)) {
|
||||||
if (element.retry_count == 2) {
|
|
||||||
myDebug_P(PSTR("[MQTT] Failed to publish to %s with payload %s"), _mqttTopic(element.topic), element.payload);
|
myDebug_P(PSTR("[MQTT] Failed to publish to %s with payload %s"), _mqttTopic(element.topic), element.payload);
|
||||||
_mqtt_publish_fails++; // increment failure counter
|
_mqtt_publish_fails++; // increment failure counter
|
||||||
_mqttRemoveLastPublish();
|
_mqttRemoveLastPublish();
|
||||||
@@ -879,6 +879,7 @@ void MyESP::_printSetCommands() {
|
|||||||
myDebug_P(PSTR(" set mqtt_qos [0-3]"));
|
myDebug_P(PSTR(" set mqtt_qos [0-3]"));
|
||||||
myDebug_P(PSTR(" set mqtt_keepalive [seconds]"));
|
myDebug_P(PSTR(" set mqtt_keepalive [seconds]"));
|
||||||
myDebug_P(PSTR(" set mqtt_retain [on | off]"));
|
myDebug_P(PSTR(" set mqtt_retain [on | off]"));
|
||||||
|
myDebug_P(PSTR(" set mqtt_nestedjson [on | off]"));
|
||||||
myDebug_P(PSTR(" set ntp_enabled <on | off>"));
|
myDebug_P(PSTR(" set ntp_enabled <on | off>"));
|
||||||
myDebug_P(PSTR(" set ntp_interval [minutes]"));
|
myDebug_P(PSTR(" set ntp_interval [minutes]"));
|
||||||
myDebug_P(PSTR(" set ntp_timezone [n]"));
|
myDebug_P(PSTR(" set ntp_timezone [n]"));
|
||||||
@@ -941,6 +942,7 @@ void MyESP::_printSetCommands() {
|
|||||||
myDebug_P(PSTR(" mqtt_retain=%s"), (_mqtt_retain) ? "on" : "off");
|
myDebug_P(PSTR(" mqtt_retain=%s"), (_mqtt_retain) ? "on" : "off");
|
||||||
myDebug_P(PSTR(" mqtt_qos=%d"), _mqtt_qos);
|
myDebug_P(PSTR(" mqtt_qos=%d"), _mqtt_qos);
|
||||||
myDebug_P(PSTR(" mqtt_heartbeat=%s"), (_mqtt_heartbeat) ? "on" : "off");
|
myDebug_P(PSTR(" mqtt_heartbeat=%s"), (_mqtt_heartbeat) ? "on" : "off");
|
||||||
|
myDebug_P(PSTR(" mqtt_nestedjson=%s"), (_mqtt_nestedjson) ? "on" : "off");
|
||||||
|
|
||||||
#ifdef FORCE_SERIAL
|
#ifdef FORCE_SERIAL
|
||||||
myDebug_P(PSTR(" serial=%s (this is always when compiled with -DFORCE_SERIAL)"), (_general_serial) ? "on" : "off");
|
myDebug_P(PSTR(" serial=%s (this is always when compiled with -DFORCE_SERIAL)"), (_general_serial) ? "on" : "off");
|
||||||
@@ -1045,6 +1047,8 @@ bool MyESP::_changeSetting(uint8_t wc, const char * setting, const char * value)
|
|||||||
restart = save_config;
|
restart = save_config;
|
||||||
} else if (strcmp(setting, "mqtt_heartbeat") == 0) {
|
} else if (strcmp(setting, "mqtt_heartbeat") == 0) {
|
||||||
save_config = fs_setSettingValue(&_mqtt_heartbeat, value, false);
|
save_config = fs_setSettingValue(&_mqtt_heartbeat, value, false);
|
||||||
|
} else if (strcmp(setting, "mqtt_nestedjson") == 0) {
|
||||||
|
save_config = fs_setSettingValue(&_mqtt_nestedjson, value, false);
|
||||||
} else if (strcmp(setting, "ntp_enabled") == 0) {
|
} else if (strcmp(setting, "ntp_enabled") == 0) {
|
||||||
save_config = fs_setSettingValue(&_ntp_enabled, value, false);
|
save_config = fs_setSettingValue(&_ntp_enabled, value, false);
|
||||||
} else if (strcmp(setting, "ntp_interval") == 0) {
|
} else if (strcmp(setting, "ntp_interval") == 0) {
|
||||||
@@ -1867,17 +1871,18 @@ bool MyESP::_fs_loadConfig() {
|
|||||||
_general_serial = general["serial"];
|
_general_serial = general["serial"];
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JsonObject mqtt = doc["mqtt"];
|
JsonObject mqtt = doc["mqtt"];
|
||||||
_mqtt_enabled = mqtt["enabled"];
|
_mqtt_enabled = mqtt["enabled"];
|
||||||
_mqtt_heartbeat = mqtt["heartbeat"];
|
_mqtt_heartbeat = mqtt["heartbeat"];
|
||||||
_mqtt_ip = strdup(mqtt["ip"] | "");
|
_mqtt_ip = strdup(mqtt["ip"] | "");
|
||||||
_mqtt_user = strdup(mqtt["user"] | "");
|
_mqtt_user = strdup(mqtt["user"] | "");
|
||||||
_mqtt_port = mqtt["port"] | MQTT_PORT;
|
_mqtt_port = mqtt["port"] | MQTT_PORT;
|
||||||
_mqtt_keepalive = mqtt["keepalive"] | MQTT_KEEPALIVE;
|
_mqtt_keepalive = mqtt["keepalive"] | MQTT_KEEPALIVE;
|
||||||
_mqtt_retain = mqtt["retain"];
|
_mqtt_retain = mqtt["retain"];
|
||||||
_mqtt_qos = mqtt["qos"] | MQTT_QOS;
|
_mqtt_qos = mqtt["qos"] | MQTT_QOS;
|
||||||
_mqtt_password = strdup(mqtt["password"] | "");
|
_mqtt_nestedjson = mqtt["nestedjson"] | true; // default to on
|
||||||
_mqtt_base = strdup(mqtt["base"] | MQTT_BASE_DEFAULT);
|
_mqtt_password = strdup(mqtt["password"] | "");
|
||||||
|
_mqtt_base = strdup(mqtt["base"] | MQTT_BASE_DEFAULT);
|
||||||
|
|
||||||
JsonObject ntp = doc["ntp"];
|
JsonObject ntp = doc["ntp"];
|
||||||
_ntp_server = strdup(ntp["server"] | "");
|
_ntp_server = strdup(ntp["server"] | "");
|
||||||
@@ -2080,17 +2085,18 @@ bool MyESP::_fs_writeConfig() {
|
|||||||
general["log_ip"] = _general_log_ip;
|
general["log_ip"] = _general_log_ip;
|
||||||
general["version"] = _app_version;
|
general["version"] = _app_version;
|
||||||
|
|
||||||
JsonObject mqtt = doc.createNestedObject("mqtt");
|
JsonObject mqtt = doc.createNestedObject("mqtt");
|
||||||
mqtt["enabled"] = _mqtt_enabled;
|
mqtt["enabled"] = _mqtt_enabled;
|
||||||
mqtt["heartbeat"] = _mqtt_heartbeat;
|
mqtt["heartbeat"] = _mqtt_heartbeat;
|
||||||
mqtt["ip"] = _mqtt_ip;
|
mqtt["ip"] = _mqtt_ip;
|
||||||
mqtt["user"] = _mqtt_user;
|
mqtt["user"] = _mqtt_user;
|
||||||
mqtt["port"] = _mqtt_port;
|
mqtt["port"] = _mqtt_port;
|
||||||
mqtt["qos"] = _mqtt_qos;
|
mqtt["qos"] = _mqtt_qos;
|
||||||
mqtt["keepalive"] = _mqtt_keepalive;
|
mqtt["keepalive"] = _mqtt_keepalive;
|
||||||
mqtt["retain"] = _mqtt_retain;
|
mqtt["retain"] = _mqtt_retain;
|
||||||
mqtt["password"] = _mqtt_password;
|
mqtt["password"] = _mqtt_password;
|
||||||
mqtt["base"] = _mqtt_base;
|
mqtt["base"] = _mqtt_base;
|
||||||
|
mqtt["nestedjson"] = _mqtt_nestedjson;
|
||||||
|
|
||||||
JsonObject ntp = doc.createNestedObject("ntp");
|
JsonObject ntp = doc.createNestedObject("ntp");
|
||||||
ntp["server"] = _ntp_server;
|
ntp["server"] = _ntp_server;
|
||||||
@@ -2192,6 +2198,11 @@ void MyESP::_calculateLoad() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns true if nested JSON setting is enabled
|
||||||
|
bool MyESP::mqttUseNestedJson() {
|
||||||
|
return _mqtt_nestedjson;
|
||||||
|
}
|
||||||
|
|
||||||
// returns true is MQTT is alive
|
// returns true is MQTT is alive
|
||||||
bool MyESP::isMQTTConnected() {
|
bool MyESP::isMQTTConnected() {
|
||||||
return mqttClient.connected();
|
return mqttClient.connected();
|
||||||
|
|||||||
65
src/MyESP.h
65
src/MyESP.h
@@ -97,9 +97,11 @@ extern struct rst_info resetInfo;
|
|||||||
#define MQTT_WILL_TOPIC "status" // for last will & testament topic name
|
#define MQTT_WILL_TOPIC "status" // for last will & testament topic name
|
||||||
#define MQTT_MAX_TOPIC_SIZE 50 // max length of MQTT topic
|
#define MQTT_MAX_TOPIC_SIZE 50 // max length of MQTT topic
|
||||||
#define MQTT_MAX_PAYLOAD_SIZE 700 // max size of a JSON object. See https://arduinojson.org/v6/assistant/
|
#define MQTT_MAX_PAYLOAD_SIZE 700 // max size of a JSON object. See https://arduinojson.org/v6/assistant/
|
||||||
#define MQTT_MAX_PAYLOAD_SIZE_LARGE 2000 // max size of a large JSON object, like for sending MQTT log
|
#define MQTT_MAX_PAYLOAD_SIZE_LARGE 2000 // max size of a large JSON object
|
||||||
#define MQTT_QUEUE_MAX_SIZE 20 // Size of the MQTT queue
|
#define MQTT_MAX_PAYLOAD_SIZE_SMALL 200
|
||||||
#define MQTT_PUBLISH_WAIT 1000 // every 2 seconds check MQTT queue
|
#define MQTT_QUEUE_MAX_SIZE 20 // Size of the MQTT queue
|
||||||
|
#define MQTT_PUBLISH_WAIT 1000 // every 1 second check MQTT queue
|
||||||
|
#define MQTT_PUBLISH_MAX_RETRY 4 // max retries for giving up on publishing
|
||||||
|
|
||||||
// Internal MQTT events
|
// Internal MQTT events
|
||||||
#define MQTT_CONNECT_EVENT 0
|
#define MQTT_CONNECT_EVENT 0
|
||||||
@@ -285,6 +287,7 @@ class MyESP {
|
|||||||
void mqttPublish(const char * topic, const char * payload);
|
void mqttPublish(const char * topic, const char * payload);
|
||||||
void mqttPublish(const char * topic, const char * payload, bool retain);
|
void mqttPublish(const char * topic, const char * payload, bool retain);
|
||||||
void setMQTT(mqtt_callback_f callback);
|
void setMQTT(mqtt_callback_f callback);
|
||||||
|
bool mqttUseNestedJson();
|
||||||
|
|
||||||
// OTA
|
// OTA
|
||||||
void setOTA(ota_callback_f OTACallback_pre, ota_callback_f OTACallback_post);
|
void setOTA(ota_callback_f OTACallback_pre, ota_callback_f OTACallback_post);
|
||||||
@@ -329,7 +332,6 @@ class MyESP {
|
|||||||
uint32_t getSystemLoadAverage();
|
uint32_t getSystemLoadAverage();
|
||||||
uint32_t getSystemResetReason();
|
uint32_t getSystemResetReason();
|
||||||
uint8_t getSystemBootStatus();
|
uint8_t getSystemBootStatus();
|
||||||
bool _have_ntp_time;
|
|
||||||
unsigned long getSystemTime();
|
unsigned long getSystemTime();
|
||||||
void heartbeatPrint();
|
void heartbeatPrint();
|
||||||
void heartbeatCheck(bool force = false);
|
void heartbeatCheck(bool force = false);
|
||||||
@@ -365,6 +367,7 @@ class MyESP {
|
|||||||
uint32_t _mqtt_last_connection;
|
uint32_t _mqtt_last_connection;
|
||||||
bool _mqtt_connecting;
|
bool _mqtt_connecting;
|
||||||
bool _mqtt_heartbeat;
|
bool _mqtt_heartbeat;
|
||||||
|
bool _mqtt_nestedjson;
|
||||||
uint16_t _mqtt_publish_fails;
|
uint16_t _mqtt_publish_fails;
|
||||||
|
|
||||||
// wifi
|
// wifi
|
||||||
@@ -408,20 +411,18 @@ class MyESP {
|
|||||||
void _syslog_setup();
|
void _syslog_setup();
|
||||||
|
|
||||||
// fs and settings
|
// fs and settings
|
||||||
void _fs_setup();
|
void _fs_setup();
|
||||||
bool _fs_loadConfig();
|
bool _fs_loadConfig();
|
||||||
bool _fs_loadCustomConfig();
|
bool _fs_loadCustomConfig();
|
||||||
void _fs_eraseConfig();
|
void _fs_eraseConfig();
|
||||||
bool _fs_writeConfig();
|
bool _fs_writeConfig();
|
||||||
bool _fs_createCustomConfig();
|
bool _fs_createCustomConfig();
|
||||||
bool _fs_sendConfig();
|
bool _fs_sendConfig();
|
||||||
size_t _fs_validateConfigFile(const char * filename, size_t maxsize, JsonDocument & doc);
|
size_t _fs_validateConfigFile(const char * filename, size_t maxsize, JsonDocument & doc);
|
||||||
size_t _fs_validateLogFile(const char * filename);
|
size_t _fs_validateLogFile(const char * filename);
|
||||||
|
|
||||||
fs_loadsave_callback_f _fs_loadsave_callback_f;
|
fs_loadsave_callback_f _fs_loadsave_callback_f;
|
||||||
fs_setlist_callback_f _fs_setlist_callback_f;
|
fs_setlist_callback_f _fs_setlist_callback_f;
|
||||||
|
void _printSetCommands();
|
||||||
void _printSetCommands();
|
|
||||||
|
|
||||||
// general
|
// general
|
||||||
char * _general_hostname;
|
char * _general_hostname;
|
||||||
@@ -444,34 +445,27 @@ class MyESP {
|
|||||||
void _kick();
|
void _kick();
|
||||||
|
|
||||||
// reset reason and rtcmem
|
// reset reason and rtcmem
|
||||||
bool _rtcmem_status;
|
bool _rtcmem_status;
|
||||||
bool _rtcmemStatus();
|
bool _rtcmemStatus();
|
||||||
bool _getRtcmemStatus();
|
bool _getRtcmemStatus();
|
||||||
|
void _rtcmemInit();
|
||||||
void _rtcmemInit();
|
void _rtcmemSetup();
|
||||||
void _rtcmemSetup();
|
void _deferredReset(unsigned long delay, uint8_t reason);
|
||||||
|
|
||||||
void _deferredReset(unsigned long delay, uint8_t reason);
|
|
||||||
|
|
||||||
uint8_t _getSystemStabilityCounter();
|
uint8_t _getSystemStabilityCounter();
|
||||||
void _setSystemStabilityCounter(uint8_t counter);
|
void _setSystemStabilityCounter(uint8_t counter);
|
||||||
|
|
||||||
uint8_t _getSystemDropoutCounter();
|
uint8_t _getSystemDropoutCounter();
|
||||||
void _setSystemDropoutCounter(uint8_t counter);
|
void _setSystemDropoutCounter(uint8_t counter);
|
||||||
void _increaseSystemDropoutCounter();
|
void _increaseSystemDropoutCounter();
|
||||||
|
|
||||||
void _setSystemResetReason(uint8_t reason);
|
void _setSystemResetReason(uint8_t reason);
|
||||||
uint8_t _getCustomResetReason();
|
uint8_t _getCustomResetReason();
|
||||||
void _setCustomResetReason(uint8_t reason);
|
void _setCustomResetReason(uint8_t reason);
|
||||||
uint8_t _getSystemResetReason();
|
uint8_t _getSystemResetReason();
|
||||||
|
void _setSystemBootStatus(uint8_t status);
|
||||||
void _setSystemBootStatus(uint8_t status);
|
bool _systemStable;
|
||||||
|
void _bootupSequence();
|
||||||
bool _systemStable;
|
bool _getSystemCheck();
|
||||||
void _bootupSequence();
|
void _systemCheckLoop();
|
||||||
bool _getSystemCheck();
|
void _setSystemCheck(bool stable);
|
||||||
void _systemCheckLoop();
|
|
||||||
void _setSystemCheck(bool stable);
|
|
||||||
|
|
||||||
// load average (0..100) and heap ram
|
// load average (0..100) and heap ram
|
||||||
void _calculateLoad();
|
void _calculateLoad();
|
||||||
@@ -497,6 +491,7 @@ class MyESP {
|
|||||||
uint16_t _ntp_interval;
|
uint16_t _ntp_interval;
|
||||||
bool _ntp_enabled;
|
bool _ntp_enabled;
|
||||||
uint8_t _ntp_timezone;
|
uint8_t _ntp_timezone;
|
||||||
|
bool _have_ntp_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern MyESP myESP;
|
extern MyESP myESP;
|
||||||
|
|||||||
697
src/ems-esp.cpp
697
src/ems-esp.cpp
@@ -582,13 +582,34 @@ void publishSensorValues() {
|
|||||||
bool hasdata = false;
|
bool hasdata = false;
|
||||||
char buffer[128] = {0}; // temp string buffer
|
char buffer[128] = {0}; // temp string buffer
|
||||||
|
|
||||||
|
// if we're not using nested JSON, send each sensor out seperately
|
||||||
|
if (!myESP.mqttUseNestedJson()) {
|
||||||
|
for (uint8_t i = 0; i < EMSESP_Settings.dallas_sensors; i++) {
|
||||||
|
float sensorValue = ds18.getValue(i);
|
||||||
|
if (sensorValue != DS18_DISCONNECTED) {
|
||||||
|
hasdata = true;
|
||||||
|
char topic[30]; // sensors{1-n}
|
||||||
|
strlcpy(topic, TOPIC_EXTERNAL_SENSORS, sizeof(topic)); // create topic
|
||||||
|
strlcat(topic, _int_to_char(buffer, i + 1), sizeof(topic));
|
||||||
|
sensors[PAYLOAD_EXTERNAL_SENSOR_ID] = ds18.getDeviceID(buffer, i); // add ID
|
||||||
|
sensors[PAYLOAD_EXTERNAL_SENSOR_TEMP] = sensorValue; // add temp value
|
||||||
|
char data[100] = {0};
|
||||||
|
serializeJson(doc, data, sizeof(data)); // convert to string
|
||||||
|
myESP.mqttPublish(topic, data); // and publish
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasdata) {
|
||||||
|
myDebugLog("Publishing external sensor data via MQTT");
|
||||||
|
}
|
||||||
|
return; // exit
|
||||||
|
}
|
||||||
|
|
||||||
// see if the sensor values have changed, if so send it on
|
// see if the sensor values have changed, if so send it on
|
||||||
for (uint8_t i = 0; i < EMSESP_Settings.dallas_sensors; i++) {
|
for (uint8_t i = 0; i < EMSESP_Settings.dallas_sensors; i++) {
|
||||||
float sensorValue = ds18.getValue(i);
|
float sensorValue = ds18.getValue(i);
|
||||||
if (sensorValue != DS18_DISCONNECTED) {
|
if (sensorValue != DS18_DISCONNECTED) {
|
||||||
hasdata = true;
|
hasdata = true;
|
||||||
// create a nested object
|
// create a nested object - https://github.com/proddy/EMS-ESP/issues/327
|
||||||
// https://github.com/proddy/EMS-ESP/issues/327
|
|
||||||
char sensorID[10]; // sensor{1-n}
|
char sensorID[10]; // sensor{1-n}
|
||||||
strlcpy(sensorID, PAYLOAD_EXTERNAL_SENSOR_NUM, sizeof(sensorID));
|
strlcpy(sensorID, PAYLOAD_EXTERNAL_SENSOR_NUM, sizeof(sensorID));
|
||||||
strlcat(sensorID, _int_to_char(buffer, i + 1), sizeof(sensorID));
|
strlcat(sensorID, _int_to_char(buffer, i + 1), sizeof(sensorID));
|
||||||
@@ -598,343 +619,313 @@ void publishSensorValues() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* test code - https://github.com/proddy/EMS-ESP/issues/326
|
|
||||||
float sensorValue = 23.43;
|
|
||||||
hasdata = true;
|
|
||||||
char sensorID[10]; // sensor{1-n}
|
|
||||||
for (uint8_t i = 0; i < 10; i++) {
|
|
||||||
strlcpy(sensorID, PAYLOAD_EXTERNAL_SENSOR_NUM, sizeof(sensorID));
|
|
||||||
strlcat(sensorID, _int_to_char(buffer, i + 1), sizeof(sensorID));
|
|
||||||
JsonObject dataSensor = sensors.createNestedObject(sensorID);
|
|
||||||
dataSensor[PAYLOAD_EXTERNAL_SENSOR_ID] = "28D45A79A2190310";
|
|
||||||
dataSensor[PAYLOAD_EXTERNAL_SENSOR_TEMP] = sensorValue;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!hasdata) {
|
|
||||||
return; // nothing to send
|
|
||||||
}
|
|
||||||
|
|
||||||
char data[DS18_MQTT_PAYLOAD_MAXSIZE] = {0};
|
char data[DS18_MQTT_PAYLOAD_MAXSIZE] = {0};
|
||||||
serializeJson(doc, data, sizeof(data));
|
serializeJson(doc, data, sizeof(data));
|
||||||
|
|
||||||
myDebugLog("Publishing external sensor data via MQTT");
|
|
||||||
myESP.mqttPublish(TOPIC_EXTERNAL_SENSORS, data);
|
myESP.mqttPublish(TOPIC_EXTERNAL_SENSORS, data);
|
||||||
|
|
||||||
|
if (hasdata) {
|
||||||
|
myDebugLog("Publishing external sensor data via MQTT");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// send values via MQTT
|
// publish Boiler data via MQTT
|
||||||
// a json object is created for each device type
|
void publishEMSValues_boiler() {
|
||||||
void publishEMSValues(bool force) {
|
|
||||||
// don't send if MQTT is not connected or EMS bus is not connected
|
|
||||||
if (!myESP.isMQTTConnected() || (!ems_getBusConnected()) || (EMSESP_Settings.publish_time == -1)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
char s[20] = {0}; // for formatting strings
|
char s[20] = {0}; // for formatting strings
|
||||||
StaticJsonDocument<MQTT_MAX_PAYLOAD_SIZE> doc;
|
StaticJsonDocument<MQTT_MAX_PAYLOAD_SIZE> doc;
|
||||||
char data[MQTT_MAX_PAYLOAD_SIZE] = {0};
|
char data[MQTT_MAX_PAYLOAD_SIZE] = {0};
|
||||||
|
JsonObject rootBoiler = doc.to<JsonObject>();
|
||||||
|
|
||||||
// do we have boiler changes?
|
if (EMS_Boiler.wWComfort == EMS_VALUE_UBAParameterWW_wwComfort_Hot) {
|
||||||
if (ems_getBoilerEnabled() && (ems_Device_has_flags(EMS_DEVICE_UPDATE_FLAG_BOILER) || force)) {
|
rootBoiler["wWComfort"] = "Hot";
|
||||||
JsonObject rootBoiler = doc.to<JsonObject>();
|
} else if (EMS_Boiler.wWComfort == EMS_VALUE_UBAParameterWW_wwComfort_Eco) {
|
||||||
|
rootBoiler["wWComfort"] = "Eco";
|
||||||
if (EMS_Boiler.wWComfort == EMS_VALUE_UBAParameterWW_wwComfort_Hot) {
|
} else if (EMS_Boiler.wWComfort == EMS_VALUE_UBAParameterWW_wwComfort_Intelligent) {
|
||||||
rootBoiler["wWComfort"] = "Hot";
|
rootBoiler["wWComfort"] = "Intelligent";
|
||||||
} else if (EMS_Boiler.wWComfort == EMS_VALUE_UBAParameterWW_wwComfort_Eco) {
|
|
||||||
rootBoiler["wWComfort"] = "Eco";
|
|
||||||
} else if (EMS_Boiler.wWComfort == EMS_VALUE_UBAParameterWW_wwComfort_Intelligent) {
|
|
||||||
rootBoiler["wWComfort"] = "Intelligent";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EMS_Boiler.wWSelTemp != EMS_VALUE_INT_NOTSET)
|
|
||||||
rootBoiler["wWSelTemp"] = EMS_Boiler.wWSelTemp;
|
|
||||||
if (EMS_Boiler.wWDesinfectTemp != EMS_VALUE_INT_NOTSET)
|
|
||||||
rootBoiler["wWDesinfectionTemp"] = EMS_Boiler.wWDesinfectTemp;
|
|
||||||
if (EMS_Boiler.selFlowTemp != EMS_VALUE_INT_NOTSET)
|
|
||||||
rootBoiler["selFlowTemp"] = EMS_Boiler.selFlowTemp;
|
|
||||||
if (EMS_Boiler.selBurnPow != EMS_VALUE_INT_NOTSET)
|
|
||||||
rootBoiler["selBurnPow"] = EMS_Boiler.selBurnPow;
|
|
||||||
if (EMS_Boiler.curBurnPow != EMS_VALUE_INT_NOTSET)
|
|
||||||
rootBoiler["curBurnPow"] = EMS_Boiler.curBurnPow;
|
|
||||||
if (EMS_Boiler.pumpMod != EMS_VALUE_INT_NOTSET)
|
|
||||||
rootBoiler["pumpMod"] = EMS_Boiler.pumpMod;
|
|
||||||
if (EMS_Boiler.wWCircPump != EMS_VALUE_BOOL_NOTSET)
|
|
||||||
rootBoiler["wWCircPump"] = EMS_Boiler.wWCircPump;
|
|
||||||
|
|
||||||
if (EMS_Boiler.extTemp > EMS_VALUE_SHORT_NOTSET)
|
|
||||||
rootBoiler["outdoorTemp"] = (float)EMS_Boiler.extTemp / 10;
|
|
||||||
if (EMS_Boiler.wWCurTmp < EMS_VALUE_USHORT_NOTSET)
|
|
||||||
rootBoiler["wWCurTmp"] = (float)EMS_Boiler.wWCurTmp / 10;
|
|
||||||
if (EMS_Boiler.wWCurFlow != EMS_VALUE_INT_NOTSET)
|
|
||||||
rootBoiler["wWCurFlow"] = (float)EMS_Boiler.wWCurFlow / 10;
|
|
||||||
if (EMS_Boiler.curFlowTemp < EMS_VALUE_USHORT_NOTSET)
|
|
||||||
rootBoiler["curFlowTemp"] = (float)EMS_Boiler.curFlowTemp / 10;
|
|
||||||
if (EMS_Boiler.retTemp < EMS_VALUE_USHORT_NOTSET)
|
|
||||||
rootBoiler["retTemp"] = (float)EMS_Boiler.retTemp / 10;
|
|
||||||
if (EMS_Boiler.switchTemp < EMS_VALUE_USHORT_NOTSET)
|
|
||||||
rootBoiler["switchTemp"] = (float)EMS_Boiler.switchTemp / 10;
|
|
||||||
if (EMS_Boiler.sysPress != EMS_VALUE_INT_NOTSET)
|
|
||||||
rootBoiler["sysPress"] = (float)EMS_Boiler.sysPress / 10;
|
|
||||||
if (EMS_Boiler.boilTemp < EMS_VALUE_USHORT_NOTSET)
|
|
||||||
rootBoiler["boilTemp"] = (float)EMS_Boiler.boilTemp / 10;
|
|
||||||
if (EMS_Boiler.exhaustTemp < EMS_VALUE_USHORT_NOTSET)
|
|
||||||
rootBoiler["exhaustTemp"] = (float)EMS_Boiler.exhaustTemp / 10;
|
|
||||||
if (EMS_Boiler.wWActivated != EMS_VALUE_BOOL_NOTSET)
|
|
||||||
rootBoiler["wWActivated"] = _bool_to_char(s, EMS_Boiler.wWActivated);
|
|
||||||
|
|
||||||
if (EMS_Boiler.wWActivated != EMS_VALUE_BOOL_NOTSET)
|
|
||||||
rootBoiler["wWOnetime"] = _bool_to_char(s, EMS_Boiler.wWOneTime);
|
|
||||||
|
|
||||||
if (EMS_Boiler.wWCirc != EMS_VALUE_BOOL_NOTSET)
|
|
||||||
rootBoiler["wWCirc"] = _bool_to_char(s, EMS_Boiler.wWCirc);
|
|
||||||
|
|
||||||
if (EMS_Boiler.burnGas != EMS_VALUE_BOOL_NOTSET)
|
|
||||||
rootBoiler["burnGas"] = _bool_to_char(s, EMS_Boiler.burnGas);
|
|
||||||
|
|
||||||
if (EMS_Boiler.flameCurr < EMS_VALUE_USHORT_NOTSET)
|
|
||||||
rootBoiler["flameCurr"] = (float)(int16_t)EMS_Boiler.flameCurr / 10;
|
|
||||||
|
|
||||||
if (EMS_Boiler.heatPmp != EMS_VALUE_BOOL_NOTSET)
|
|
||||||
rootBoiler["heatPmp"] = _bool_to_char(s, EMS_Boiler.heatPmp);
|
|
||||||
|
|
||||||
if (EMS_Boiler.fanWork != EMS_VALUE_BOOL_NOTSET)
|
|
||||||
rootBoiler["fanWork"] = _bool_to_char(s, EMS_Boiler.fanWork);
|
|
||||||
|
|
||||||
if (EMS_Boiler.ignWork != EMS_VALUE_BOOL_NOTSET)
|
|
||||||
rootBoiler["ignWork"] = _bool_to_char(s, EMS_Boiler.ignWork);
|
|
||||||
|
|
||||||
if (EMS_Boiler.heating_temp != EMS_VALUE_INT_NOTSET)
|
|
||||||
rootBoiler["heating_temp"] = EMS_Boiler.heating_temp;
|
|
||||||
if (EMS_Boiler.pump_mod_max != EMS_VALUE_INT_NOTSET)
|
|
||||||
rootBoiler["pump_mod_max"] = EMS_Boiler.pump_mod_max;
|
|
||||||
if (EMS_Boiler.pump_mod_min != EMS_VALUE_INT_NOTSET)
|
|
||||||
rootBoiler["pump_mod_min"] = EMS_Boiler.pump_mod_min;
|
|
||||||
|
|
||||||
if (EMS_Boiler.wWHeat != EMS_VALUE_BOOL_NOTSET)
|
|
||||||
rootBoiler["wWHeat"] = _bool_to_char(s, EMS_Boiler.wWHeat);
|
|
||||||
|
|
||||||
if (abs(EMS_Boiler.wWStarts) != EMS_VALUE_LONG_NOTSET)
|
|
||||||
rootBoiler["wWStarts"] = (float)EMS_Boiler.wWStarts;
|
|
||||||
if (abs(EMS_Boiler.wWWorkM) != EMS_VALUE_LONG_NOTSET)
|
|
||||||
rootBoiler["wWWorkM"] = (float)EMS_Boiler.wWWorkM;
|
|
||||||
if (abs(EMS_Boiler.UBAuptime) != EMS_VALUE_LONG_NOTSET)
|
|
||||||
rootBoiler["UBAuptime"] = (float)EMS_Boiler.UBAuptime;
|
|
||||||
|
|
||||||
if (abs(EMS_Boiler.burnStarts) != EMS_VALUE_LONG_NOTSET)
|
|
||||||
rootBoiler["burnStarts"] = (float)EMS_Boiler.burnStarts;
|
|
||||||
if (abs(EMS_Boiler.burnWorkMin) != EMS_VALUE_LONG_NOTSET)
|
|
||||||
rootBoiler["burnWorkMin"] = (float)EMS_Boiler.burnWorkMin;
|
|
||||||
if (abs(EMS_Boiler.heatWorkMin) != EMS_VALUE_LONG_NOTSET)
|
|
||||||
rootBoiler["heatWorkMin"] = (float)EMS_Boiler.heatWorkMin;
|
|
||||||
|
|
||||||
if (EMS_Boiler.serviceCode != EMS_VALUE_USHORT_NOTSET) {
|
|
||||||
rootBoiler["ServiceCode"] = EMS_Boiler.serviceCodeChar;
|
|
||||||
rootBoiler["ServiceCodeNumber"] = EMS_Boiler.serviceCode;
|
|
||||||
}
|
|
||||||
|
|
||||||
serializeJson(doc, data, sizeof(data));
|
|
||||||
myDebugLog("Publishing boiler data via MQTT");
|
|
||||||
myESP.mqttPublish(TOPIC_BOILER_DATA, data);
|
|
||||||
|
|
||||||
// see if the heating or hot tap water has changed, if so send
|
|
||||||
// last_boilerActive stores heating in bit 1 and tap water in bit 2
|
|
||||||
static uint8_t last_boilerActive = 0xFF; // for remembering last setting of the tap water or heating on/off
|
|
||||||
if ((last_boilerActive != ((EMS_Boiler.tapwaterActive << 1) + EMS_Boiler.heatingActive)) || force) {
|
|
||||||
myDebugLog("Publishing hot water and heating states via MQTT");
|
|
||||||
myESP.mqttPublish(TOPIC_BOILER_TAPWATER_ACTIVE, EMS_Boiler.tapwaterActive == 1 ? "1" : "0");
|
|
||||||
myESP.mqttPublish(TOPIC_BOILER_HEATING_ACTIVE, EMS_Boiler.heatingActive == 1 ? "1" : "0");
|
|
||||||
|
|
||||||
last_boilerActive = ((EMS_Boiler.tapwaterActive << 1) + EMS_Boiler.heatingActive); // remember last state
|
|
||||||
}
|
|
||||||
|
|
||||||
ems_Device_remove_flags(EMS_DEVICE_UPDATE_FLAG_BOILER); // unset flag
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle the thermostat values
|
if (EMS_Boiler.wWSelTemp != EMS_VALUE_INT_NOTSET)
|
||||||
if (ems_getThermostatEnabled() && (ems_Device_has_flags(EMS_DEVICE_UPDATE_FLAG_THERMOSTAT) || force)) {
|
rootBoiler["wWSelTemp"] = EMS_Boiler.wWSelTemp;
|
||||||
doc.clear();
|
if (EMS_Boiler.wWDesinfectTemp != EMS_VALUE_INT_NOTSET)
|
||||||
JsonObject rootThermostat = doc.to<JsonObject>();
|
rootBoiler["wWDesinfectionTemp"] = EMS_Boiler.wWDesinfectTemp;
|
||||||
|
if (EMS_Boiler.selFlowTemp != EMS_VALUE_INT_NOTSET)
|
||||||
|
rootBoiler["selFlowTemp"] = EMS_Boiler.selFlowTemp;
|
||||||
|
if (EMS_Boiler.selBurnPow != EMS_VALUE_INT_NOTSET)
|
||||||
|
rootBoiler["selBurnPow"] = EMS_Boiler.selBurnPow;
|
||||||
|
if (EMS_Boiler.curBurnPow != EMS_VALUE_INT_NOTSET)
|
||||||
|
rootBoiler["curBurnPow"] = EMS_Boiler.curBurnPow;
|
||||||
|
if (EMS_Boiler.pumpMod != EMS_VALUE_INT_NOTSET)
|
||||||
|
rootBoiler["pumpMod"] = EMS_Boiler.pumpMod;
|
||||||
|
if (EMS_Boiler.wWCircPump != EMS_VALUE_BOOL_NOTSET)
|
||||||
|
rootBoiler["wWCircPump"] = EMS_Boiler.wWCircPump;
|
||||||
|
|
||||||
for (uint8_t hc_v = 1; hc_v <= EMS_THERMOSTAT_MAXHC; hc_v++) {
|
if (EMS_Boiler.extTemp > EMS_VALUE_SHORT_NOTSET)
|
||||||
_EMS_Thermostat_HC * thermostat = &EMS_Thermostat.hc[hc_v - 1];
|
rootBoiler["outdoorTemp"] = (float)EMS_Boiler.extTemp / 10;
|
||||||
|
if (EMS_Boiler.wWCurTmp < EMS_VALUE_USHORT_NOTSET)
|
||||||
|
rootBoiler["wWCurTmp"] = (float)EMS_Boiler.wWCurTmp / 10;
|
||||||
|
if (EMS_Boiler.wWCurFlow != EMS_VALUE_INT_NOTSET)
|
||||||
|
rootBoiler["wWCurFlow"] = (float)EMS_Boiler.wWCurFlow / 10;
|
||||||
|
if (EMS_Boiler.curFlowTemp < EMS_VALUE_USHORT_NOTSET)
|
||||||
|
rootBoiler["curFlowTemp"] = (float)EMS_Boiler.curFlowTemp / 10;
|
||||||
|
if (EMS_Boiler.retTemp < EMS_VALUE_USHORT_NOTSET)
|
||||||
|
rootBoiler["retTemp"] = (float)EMS_Boiler.retTemp / 10;
|
||||||
|
if (EMS_Boiler.switchTemp < EMS_VALUE_USHORT_NOTSET)
|
||||||
|
rootBoiler["switchTemp"] = (float)EMS_Boiler.switchTemp / 10;
|
||||||
|
if (EMS_Boiler.sysPress != EMS_VALUE_INT_NOTSET)
|
||||||
|
rootBoiler["sysPress"] = (float)EMS_Boiler.sysPress / 10;
|
||||||
|
if (EMS_Boiler.boilTemp < EMS_VALUE_USHORT_NOTSET)
|
||||||
|
rootBoiler["boilTemp"] = (float)EMS_Boiler.boilTemp / 10;
|
||||||
|
if (EMS_Boiler.exhaustTemp < EMS_VALUE_USHORT_NOTSET)
|
||||||
|
rootBoiler["exhaustTemp"] = (float)EMS_Boiler.exhaustTemp / 10;
|
||||||
|
if (EMS_Boiler.wWActivated != EMS_VALUE_BOOL_NOTSET)
|
||||||
|
rootBoiler["wWActivated"] = _bool_to_char(s, EMS_Boiler.wWActivated);
|
||||||
|
|
||||||
// only send if we have an active Heating Circuit with an actual setpoint temp temperature values
|
if (EMS_Boiler.wWActivated != EMS_VALUE_BOOL_NOTSET)
|
||||||
if ((thermostat->active) && (thermostat->setpoint_roomTemp > EMS_VALUE_SHORT_NOTSET)) {
|
rootBoiler["wWOnetime"] = _bool_to_char(s, EMS_Boiler.wWOneTime);
|
||||||
// build new json object
|
|
||||||
char hc[10]; // hc{1-4}
|
|
||||||
strlcpy(hc, THERMOSTAT_HC, sizeof(hc));
|
|
||||||
strlcat(hc, _int_to_char(s, thermostat->hc), sizeof(hc));
|
|
||||||
JsonObject dataThermostat = rootThermostat.createNestedObject(hc);
|
|
||||||
uint8_t model = ems_getThermostatModel();
|
|
||||||
|
|
||||||
// different logic depending on thermostat types
|
if (EMS_Boiler.wWCirc != EMS_VALUE_BOOL_NOTSET)
|
||||||
if (model == EMS_DEVICE_FLAG_EASY) {
|
rootBoiler["wWCirc"] = _bool_to_char(s, EMS_Boiler.wWCirc);
|
||||||
if (thermostat->setpoint_roomTemp > EMS_VALUE_SHORT_NOTSET)
|
|
||||||
dataThermostat[THERMOSTAT_SELTEMP] = (float)thermostat->setpoint_roomTemp / 100;
|
|
||||||
if (thermostat->curr_roomTemp > EMS_VALUE_SHORT_NOTSET)
|
|
||||||
dataThermostat[THERMOSTAT_CURRTEMP] = (float)thermostat->curr_roomTemp / 100;
|
|
||||||
} else if (model == EMS_DEVICE_FLAG_JUNKERS) {
|
|
||||||
if (thermostat->setpoint_roomTemp > EMS_VALUE_SHORT_NOTSET)
|
|
||||||
dataThermostat[THERMOSTAT_SELTEMP] = (float)thermostat->setpoint_roomTemp / 10;
|
|
||||||
if (thermostat->curr_roomTemp > EMS_VALUE_SHORT_NOTSET)
|
|
||||||
dataThermostat[THERMOSTAT_CURRTEMP] = (float)thermostat->curr_roomTemp / 10;
|
|
||||||
} else {
|
|
||||||
if (thermostat->setpoint_roomTemp > EMS_VALUE_SHORT_NOTSET)
|
|
||||||
dataThermostat[THERMOSTAT_SELTEMP] = (float)thermostat->setpoint_roomTemp / 2;
|
|
||||||
if (thermostat->curr_roomTemp > EMS_VALUE_SHORT_NOTSET)
|
|
||||||
dataThermostat[THERMOSTAT_CURRTEMP] = (float)thermostat->curr_roomTemp / 10;
|
|
||||||
|
|
||||||
if (thermostat->daytemp != EMS_VALUE_INT_NOTSET)
|
if (EMS_Boiler.burnGas != EMS_VALUE_BOOL_NOTSET)
|
||||||
dataThermostat[THERMOSTAT_DAYTEMP] = (float)thermostat->daytemp / 2;
|
rootBoiler["burnGas"] = _bool_to_char(s, EMS_Boiler.burnGas);
|
||||||
if (thermostat->nighttemp != EMS_VALUE_INT_NOTSET)
|
|
||||||
dataThermostat[THERMOSTAT_NIGHTTEMP] = (float)thermostat->nighttemp / 2;
|
|
||||||
if (thermostat->holidaytemp != EMS_VALUE_INT_NOTSET)
|
|
||||||
dataThermostat[THERMOSTAT_HOLIDAYTEMP] = (float)thermostat->holidaytemp / 2;
|
|
||||||
|
|
||||||
if (thermostat->heatingtype != EMS_VALUE_INT_NOTSET)
|
if (EMS_Boiler.flameCurr < EMS_VALUE_USHORT_NOTSET)
|
||||||
dataThermostat[THERMOSTAT_HEATINGTYPE] = thermostat->heatingtype;
|
rootBoiler["flameCurr"] = (float)(int16_t)EMS_Boiler.flameCurr / 10;
|
||||||
|
|
||||||
if (thermostat->circuitcalctemp != EMS_VALUE_INT_NOTSET)
|
if (EMS_Boiler.heatPmp != EMS_VALUE_BOOL_NOTSET)
|
||||||
dataThermostat[THERMOSTAT_CIRCUITCALCTEMP] = thermostat->circuitcalctemp;
|
rootBoiler["heatPmp"] = _bool_to_char(s, EMS_Boiler.heatPmp);
|
||||||
}
|
|
||||||
|
|
||||||
// Thermostat Mode
|
if (EMS_Boiler.fanWork != EMS_VALUE_BOOL_NOTSET)
|
||||||
_EMS_THERMOSTAT_MODE thermoMode = _getThermostatMode(hc_v);
|
rootBoiler["fanWork"] = _bool_to_char(s, EMS_Boiler.fanWork);
|
||||||
if (thermoMode == EMS_THERMOSTAT_MODE_OFF) {
|
|
||||||
dataThermostat[THERMOSTAT_MODE] = "off";
|
if (EMS_Boiler.ignWork != EMS_VALUE_BOOL_NOTSET)
|
||||||
} else if (thermoMode == EMS_THERMOSTAT_MODE_MANUAL) {
|
rootBoiler["ignWork"] = _bool_to_char(s, EMS_Boiler.ignWork);
|
||||||
dataThermostat[THERMOSTAT_MODE] = "manual";
|
|
||||||
} else if (thermoMode == EMS_THERMOSTAT_MODE_AUTO) {
|
if (EMS_Boiler.heating_temp != EMS_VALUE_INT_NOTSET)
|
||||||
dataThermostat[THERMOSTAT_MODE] = "auto";
|
rootBoiler["heating_temp"] = EMS_Boiler.heating_temp;
|
||||||
} else if (thermoMode == EMS_THERMOSTAT_MODE_DAY) {
|
if (EMS_Boiler.pump_mod_max != EMS_VALUE_INT_NOTSET)
|
||||||
dataThermostat[THERMOSTAT_MODE] = "day";
|
rootBoiler["pump_mod_max"] = EMS_Boiler.pump_mod_max;
|
||||||
} else if (thermoMode == EMS_THERMOSTAT_MODE_NIGHT) {
|
if (EMS_Boiler.pump_mod_min != EMS_VALUE_INT_NOTSET)
|
||||||
dataThermostat[THERMOSTAT_MODE] = "night";
|
rootBoiler["pump_mod_min"] = EMS_Boiler.pump_mod_min;
|
||||||
}
|
|
||||||
|
if (EMS_Boiler.wWHeat != EMS_VALUE_BOOL_NOTSET)
|
||||||
|
rootBoiler["wWHeat"] = _bool_to_char(s, EMS_Boiler.wWHeat);
|
||||||
|
|
||||||
|
if (abs(EMS_Boiler.wWStarts) != EMS_VALUE_LONG_NOTSET)
|
||||||
|
rootBoiler["wWStarts"] = (float)EMS_Boiler.wWStarts;
|
||||||
|
if (abs(EMS_Boiler.wWWorkM) != EMS_VALUE_LONG_NOTSET)
|
||||||
|
rootBoiler["wWWorkM"] = (float)EMS_Boiler.wWWorkM;
|
||||||
|
if (abs(EMS_Boiler.UBAuptime) != EMS_VALUE_LONG_NOTSET)
|
||||||
|
rootBoiler["UBAuptime"] = (float)EMS_Boiler.UBAuptime;
|
||||||
|
|
||||||
|
if (abs(EMS_Boiler.burnStarts) != EMS_VALUE_LONG_NOTSET)
|
||||||
|
rootBoiler["burnStarts"] = (float)EMS_Boiler.burnStarts;
|
||||||
|
if (abs(EMS_Boiler.burnWorkMin) != EMS_VALUE_LONG_NOTSET)
|
||||||
|
rootBoiler["burnWorkMin"] = (float)EMS_Boiler.burnWorkMin;
|
||||||
|
if (abs(EMS_Boiler.heatWorkMin) != EMS_VALUE_LONG_NOTSET)
|
||||||
|
rootBoiler["heatWorkMin"] = (float)EMS_Boiler.heatWorkMin;
|
||||||
|
|
||||||
|
if (EMS_Boiler.serviceCode != EMS_VALUE_USHORT_NOTSET) {
|
||||||
|
rootBoiler["ServiceCode"] = EMS_Boiler.serviceCodeChar;
|
||||||
|
rootBoiler["ServiceCodeNumber"] = EMS_Boiler.serviceCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
serializeJson(doc, data, sizeof(data));
|
||||||
|
myDebugLog("Publishing boiler data via MQTT");
|
||||||
|
myESP.mqttPublish(TOPIC_BOILER_DATA, data);
|
||||||
|
|
||||||
|
// see if the heating or hot tap water has changed, if so send
|
||||||
|
// last_boilerActive stores heating in bit 1 and tap water in bit 2
|
||||||
|
static uint8_t last_boilerActive = 0xFF; // for remembering last setting of the tap water or heating on/off
|
||||||
|
if (last_boilerActive != ((EMS_Boiler.tapwaterActive << 1) + EMS_Boiler.heatingActive)) {
|
||||||
|
myDebugLog("Publishing hot water and heating states via MQTT");
|
||||||
|
myESP.mqttPublish(TOPIC_BOILER_TAPWATER_ACTIVE, EMS_Boiler.tapwaterActive == 1 ? "1" : "0");
|
||||||
|
myESP.mqttPublish(TOPIC_BOILER_HEATING_ACTIVE, EMS_Boiler.heatingActive == 1 ? "1" : "0");
|
||||||
|
|
||||||
|
last_boilerActive = ((EMS_Boiler.tapwaterActive << 1) + EMS_Boiler.heatingActive); // remember last state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle the thermostat values
|
||||||
|
void publishEMSValues_thermostat() {
|
||||||
|
char s[20] = {0}; // for formatting strings
|
||||||
|
StaticJsonDocument<MQTT_MAX_PAYLOAD_SIZE> doc;
|
||||||
|
char data[MQTT_MAX_PAYLOAD_SIZE] = {0};
|
||||||
|
JsonObject rootThermostat = doc.to<JsonObject>();
|
||||||
|
|
||||||
|
for (uint8_t hc_v = 1; hc_v <= EMS_THERMOSTAT_MAXHC; hc_v++) {
|
||||||
|
_EMS_Thermostat_HC * thermostat = &EMS_Thermostat.hc[hc_v - 1];
|
||||||
|
|
||||||
|
// only send if we have an active Heating Circuit with an actual setpoint temp temperature values
|
||||||
|
if ((thermostat->active) && (thermostat->setpoint_roomTemp > EMS_VALUE_SHORT_NOTSET)) {
|
||||||
|
// build new json object
|
||||||
|
char hc[10]; // hc{1-4}
|
||||||
|
strlcpy(hc, THERMOSTAT_HC, sizeof(hc));
|
||||||
|
strlcat(hc, _int_to_char(s, thermostat->hc), sizeof(hc));
|
||||||
|
JsonObject dataThermostat = rootThermostat.createNestedObject(hc);
|
||||||
|
uint8_t model = ems_getThermostatModel();
|
||||||
|
|
||||||
|
// different logic depending on thermostat types
|
||||||
|
if (model == EMS_DEVICE_FLAG_EASY) {
|
||||||
|
if (thermostat->setpoint_roomTemp > EMS_VALUE_SHORT_NOTSET)
|
||||||
|
dataThermostat[THERMOSTAT_SELTEMP] = (float)thermostat->setpoint_roomTemp / 100;
|
||||||
|
if (thermostat->curr_roomTemp > EMS_VALUE_SHORT_NOTSET)
|
||||||
|
dataThermostat[THERMOSTAT_CURRTEMP] = (float)thermostat->curr_roomTemp / 100;
|
||||||
|
} else if (model == EMS_DEVICE_FLAG_JUNKERS) {
|
||||||
|
if (thermostat->setpoint_roomTemp > EMS_VALUE_SHORT_NOTSET)
|
||||||
|
dataThermostat[THERMOSTAT_SELTEMP] = (float)thermostat->setpoint_roomTemp / 10;
|
||||||
|
if (thermostat->curr_roomTemp > EMS_VALUE_SHORT_NOTSET)
|
||||||
|
dataThermostat[THERMOSTAT_CURRTEMP] = (float)thermostat->curr_roomTemp / 10;
|
||||||
|
} else {
|
||||||
|
if (thermostat->setpoint_roomTemp > EMS_VALUE_SHORT_NOTSET)
|
||||||
|
dataThermostat[THERMOSTAT_SELTEMP] = (float)thermostat->setpoint_roomTemp / 2;
|
||||||
|
if (thermostat->curr_roomTemp > EMS_VALUE_SHORT_NOTSET)
|
||||||
|
dataThermostat[THERMOSTAT_CURRTEMP] = (float)thermostat->curr_roomTemp / 10;
|
||||||
|
|
||||||
|
if (thermostat->daytemp != EMS_VALUE_INT_NOTSET)
|
||||||
|
dataThermostat[THERMOSTAT_DAYTEMP] = (float)thermostat->daytemp / 2;
|
||||||
|
if (thermostat->nighttemp != EMS_VALUE_INT_NOTSET)
|
||||||
|
dataThermostat[THERMOSTAT_NIGHTTEMP] = (float)thermostat->nighttemp / 2;
|
||||||
|
if (thermostat->holidaytemp != EMS_VALUE_INT_NOTSET)
|
||||||
|
dataThermostat[THERMOSTAT_HOLIDAYTEMP] = (float)thermostat->holidaytemp / 2;
|
||||||
|
|
||||||
|
if (thermostat->heatingtype != EMS_VALUE_INT_NOTSET)
|
||||||
|
dataThermostat[THERMOSTAT_HEATINGTYPE] = thermostat->heatingtype;
|
||||||
|
|
||||||
|
if (thermostat->circuitcalctemp != EMS_VALUE_INT_NOTSET)
|
||||||
|
dataThermostat[THERMOSTAT_CIRCUITCALCTEMP] = thermostat->circuitcalctemp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Thermostat Mode
|
||||||
|
_EMS_THERMOSTAT_MODE thermoMode = _getThermostatMode(hc_v);
|
||||||
|
if (thermoMode == EMS_THERMOSTAT_MODE_OFF) {
|
||||||
|
dataThermostat[THERMOSTAT_MODE] = "off";
|
||||||
|
} else if (thermoMode == EMS_THERMOSTAT_MODE_MANUAL) {
|
||||||
|
dataThermostat[THERMOSTAT_MODE] = "manual";
|
||||||
|
} else if (thermoMode == EMS_THERMOSTAT_MODE_AUTO) {
|
||||||
|
dataThermostat[THERMOSTAT_MODE] = "auto";
|
||||||
|
} else if (thermoMode == EMS_THERMOSTAT_MODE_DAY) {
|
||||||
|
dataThermostat[THERMOSTAT_MODE] = "day";
|
||||||
|
} else if (thermoMode == EMS_THERMOSTAT_MODE_NIGHT) {
|
||||||
|
dataThermostat[THERMOSTAT_MODE] = "night";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data[0] = '\0'; // reset data for next package
|
|
||||||
serializeJson(doc, data, sizeof(data));
|
|
||||||
myDebugLog("Publishing thermostat data via MQTT");
|
|
||||||
myESP.mqttPublish(TOPIC_THERMOSTAT_DATA, data);
|
|
||||||
ems_Device_remove_flags(EMS_DEVICE_UPDATE_FLAG_THERMOSTAT); // unset flag
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle the mixing values
|
serializeJson(doc, data, sizeof(data));
|
||||||
if (ems_getMixingModuleEnabled() && (ems_Device_has_flags(EMS_DEVICE_UPDATE_FLAG_MIXING) || force)) {
|
myDebugLog("Publishing thermostat data via MQTT");
|
||||||
doc.clear();
|
myESP.mqttPublish(TOPIC_THERMOSTAT_DATA, data);
|
||||||
JsonObject rootMixing = doc.to<JsonObject>();
|
}
|
||||||
|
|
||||||
for (uint8_t hc_v = 1; hc_v <= EMS_MIXING_MAXHC; hc_v++) {
|
// publish mixing data
|
||||||
_EMS_MixingModule_HC * mixingHC = &EMS_MixingModule.hc[hc_v - 1];
|
void publishEMSValues_mixing() {
|
||||||
|
char s[20] = {0}; // for formatting strings
|
||||||
|
StaticJsonDocument<MQTT_MAX_PAYLOAD_SIZE> doc;
|
||||||
|
char data[MQTT_MAX_PAYLOAD_SIZE] = {0};
|
||||||
|
JsonObject rootMixing = doc.to<JsonObject>();
|
||||||
|
|
||||||
// only send if we have an active Heating Circuit with real data
|
for (uint8_t hc_v = 1; hc_v <= EMS_MIXING_MAXHC; hc_v++) {
|
||||||
if (mixingHC->active) {
|
_EMS_MixingModule_HC * mixingHC = &EMS_MixingModule.hc[hc_v - 1];
|
||||||
char hc[10]; // hc{1-4}
|
|
||||||
strlcpy(hc, MIXING_HC, sizeof(hc));
|
// only send if we have an active Heating Circuit with real data
|
||||||
strlcat(hc, _int_to_char(s, mixingHC->hc), sizeof(hc));
|
if (mixingHC->active) {
|
||||||
JsonObject dataMixingHC = rootMixing.createNestedObject(hc);
|
char hc[10]; // hc{1-4}
|
||||||
if (mixingHC->flowTemp < EMS_VALUE_USHORT_NOTSET)
|
strlcpy(hc, MIXING_HC, sizeof(hc));
|
||||||
dataMixingHC["flowTemp"] = (float)mixingHC->flowTemp / 10;
|
strlcat(hc, _int_to_char(s, mixingHC->hc), sizeof(hc));
|
||||||
if (mixingHC->flowSetTemp != EMS_VALUE_INT_NOTSET)
|
JsonObject dataMixingHC = rootMixing.createNestedObject(hc);
|
||||||
dataMixingHC["setflowTemp"] = mixingHC->flowSetTemp;
|
if (mixingHC->flowTemp < EMS_VALUE_USHORT_NOTSET)
|
||||||
if (mixingHC->pumpMod != EMS_VALUE_INT_NOTSET)
|
dataMixingHC["flowTemp"] = (float)mixingHC->flowTemp / 10;
|
||||||
dataMixingHC["pumpMod"] = mixingHC->pumpMod;
|
if (mixingHC->flowSetTemp != EMS_VALUE_INT_NOTSET)
|
||||||
if (mixingHC->valveStatus != EMS_VALUE_INT_NOTSET)
|
dataMixingHC["setflowTemp"] = mixingHC->flowSetTemp;
|
||||||
dataMixingHC["valveStatus"] = mixingHC->valveStatus;
|
if (mixingHC->pumpMod != EMS_VALUE_INT_NOTSET)
|
||||||
}
|
dataMixingHC["pumpMod"] = mixingHC->pumpMod;
|
||||||
|
if (mixingHC->valveStatus != EMS_VALUE_INT_NOTSET)
|
||||||
|
dataMixingHC["valveStatus"] = mixingHC->valveStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint8_t wwc_v = 1; wwc_v <= EMS_MIXING_MAXWWC; wwc_v++) {
|
|
||||||
_EMS_MixingModule_WWC * mixingWWC = &EMS_MixingModule.wwc[wwc_v - 1];
|
|
||||||
// only send if we have an active Warm water Circuit with real data
|
|
||||||
if (mixingWWC->active) {
|
|
||||||
char wwc[10]; // wwc{1-2}
|
|
||||||
strlcpy(wwc, MIXING_WWC, sizeof(wwc));
|
|
||||||
strlcat(wwc, _int_to_char(s, mixingWWC->wwc), sizeof(wwc));
|
|
||||||
JsonObject dataMixing = rootMixing.createNestedObject(wwc);
|
|
||||||
if (mixingWWC->flowTemp < EMS_VALUE_USHORT_NOTSET)
|
|
||||||
dataMixing["wwTemp"] = (float)mixingWWC->flowTemp / 10;
|
|
||||||
if (mixingWWC->pumpMod != EMS_VALUE_INT_NOTSET)
|
|
||||||
dataMixing["pumpStatus"] = mixingWWC->pumpMod;
|
|
||||||
if (mixingWWC->tempStatus != EMS_VALUE_INT_NOTSET)
|
|
||||||
dataMixing["tempStatus"] = mixingWWC->tempStatus;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data[0] = '\0'; // reset data for next package
|
|
||||||
serializeJson(doc, data, sizeof(data));
|
|
||||||
myDebugLog("Publishing mixing data via MQTT");
|
|
||||||
myESP.mqttPublish(TOPIC_MIXING_DATA, data);
|
|
||||||
ems_Device_remove_flags(EMS_DEVICE_UPDATE_FLAG_MIXING); // unset flag
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For SM10 and SM100/SM200 Solar Modules
|
for (uint8_t wwc_v = 1; wwc_v <= EMS_MIXING_MAXWWC; wwc_v++) {
|
||||||
if (ems_getSolarModuleEnabled() && (ems_Device_has_flags(EMS_DEVICE_UPDATE_FLAG_SOLAR) || force)) {
|
_EMS_MixingModule_WWC * mixingWWC = &EMS_MixingModule.wwc[wwc_v - 1];
|
||||||
// build new json object
|
// only send if we have an active Warm water Circuit with real data
|
||||||
doc.clear();
|
if (mixingWWC->active) {
|
||||||
JsonObject rootSM = doc.to<JsonObject>();
|
char wwc[10]; // wwc{1-2}
|
||||||
|
strlcpy(wwc, MIXING_WWC, sizeof(wwc));
|
||||||
if (EMS_SolarModule.collectorTemp > EMS_VALUE_SHORT_NOTSET)
|
strlcat(wwc, _int_to_char(s, mixingWWC->wwc), sizeof(wwc));
|
||||||
rootSM[SM_COLLECTORTEMP] = (float)EMS_SolarModule.collectorTemp / 10;
|
JsonObject dataMixing = rootMixing.createNestedObject(wwc);
|
||||||
|
if (mixingWWC->flowTemp < EMS_VALUE_USHORT_NOTSET)
|
||||||
if (EMS_SolarModule.bottomTemp > EMS_VALUE_SHORT_NOTSET)
|
dataMixing["wwTemp"] = (float)mixingWWC->flowTemp / 10;
|
||||||
rootSM[SM_BOTTOMTEMP] = (float)EMS_SolarModule.bottomTemp / 10;
|
if (mixingWWC->pumpMod != EMS_VALUE_INT_NOTSET)
|
||||||
|
dataMixing["pumpStatus"] = mixingWWC->pumpMod;
|
||||||
if (EMS_SolarModule.pumpModulation != EMS_VALUE_INT_NOTSET)
|
if (mixingWWC->tempStatus != EMS_VALUE_INT_NOTSET)
|
||||||
rootSM[SM_PUMPMODULATION] = EMS_SolarModule.pumpModulation;
|
dataMixing["tempStatus"] = mixingWWC->tempStatus;
|
||||||
|
|
||||||
if (EMS_SolarModule.pump != EMS_VALUE_BOOL_NOTSET) {
|
|
||||||
rootSM[SM_PUMP] = _bool_to_char(s, EMS_SolarModule.pump);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EMS_SolarModule.pumpWorkMin != EMS_VALUE_LONG_NOTSET) {
|
|
||||||
rootSM[SM_PUMPWORKMIN] = (float)EMS_SolarModule.pumpWorkMin;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EMS_SolarModule.EnergyLastHour < EMS_VALUE_USHORT_NOTSET)
|
|
||||||
rootSM[SM_ENERGYLASTHOUR] = (float)EMS_SolarModule.EnergyLastHour / 10;
|
|
||||||
|
|
||||||
if (EMS_SolarModule.EnergyToday < EMS_VALUE_USHORT_NOTSET)
|
|
||||||
rootSM[SM_ENERGYTODAY] = EMS_SolarModule.EnergyToday;
|
|
||||||
|
|
||||||
if (EMS_SolarModule.EnergyTotal < EMS_VALUE_USHORT_NOTSET)
|
|
||||||
rootSM[SM_ENERGYTOTAL] = (float)EMS_SolarModule.EnergyTotal / 10;
|
|
||||||
|
|
||||||
data[0] = '\0'; // reset data for next package
|
|
||||||
serializeJson(doc, data, sizeof(data));
|
|
||||||
myDebugLog("Publishing SM data via MQTT");
|
|
||||||
myESP.mqttPublish(TOPIC_SM_DATA, data);
|
|
||||||
ems_Device_remove_flags(EMS_DEVICE_UPDATE_FLAG_SOLAR); // unset flag
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle HeatPump
|
serializeJson(doc, data, sizeof(data));
|
||||||
if (ems_getHeatPumpEnabled() && (ems_Device_has_flags(EMS_DEVICE_UPDATE_FLAG_HEATPUMP) || force)) {
|
myDebugLog("Publishing mixing data via MQTT");
|
||||||
// build new json object
|
myESP.mqttPublish(TOPIC_MIXING_DATA, data);
|
||||||
doc.clear();
|
}
|
||||||
JsonObject rootSM = doc.to<JsonObject>();
|
|
||||||
|
|
||||||
if (EMS_HeatPump.HPModulation != EMS_VALUE_INT_NOTSET)
|
// For SM10 and SM100/SM200 Solar Modules
|
||||||
rootSM[HP_PUMPMODULATION] = EMS_HeatPump.HPModulation;
|
void publishEMSValues_solar() {
|
||||||
|
char s[20] = {0}; // for formatting strings
|
||||||
|
StaticJsonDocument<MQTT_MAX_PAYLOAD_SIZE> doc;
|
||||||
|
char data[MQTT_MAX_PAYLOAD_SIZE] = {0};
|
||||||
|
JsonObject rootSM = doc.to<JsonObject>();
|
||||||
|
|
||||||
if (EMS_HeatPump.HPSpeed != EMS_VALUE_INT_NOTSET)
|
if (EMS_SolarModule.collectorTemp > EMS_VALUE_SHORT_NOTSET)
|
||||||
rootSM[HP_PUMPSPEED] = EMS_HeatPump.HPSpeed;
|
rootSM[SM_COLLECTORTEMP] = (float)EMS_SolarModule.collectorTemp / 10;
|
||||||
|
|
||||||
data[0] = '\0'; // reset data for next package
|
if (EMS_SolarModule.bottomTemp > EMS_VALUE_SHORT_NOTSET)
|
||||||
serializeJson(doc, data, sizeof(data));
|
rootSM[SM_BOTTOMTEMP] = (float)EMS_SolarModule.bottomTemp / 10;
|
||||||
myDebugLog("Publishing HeatPump data via MQTT");
|
|
||||||
myESP.mqttPublish(TOPIC_HP_DATA, data);
|
if (EMS_SolarModule.pumpModulation != EMS_VALUE_INT_NOTSET)
|
||||||
ems_Device_remove_flags(EMS_DEVICE_UPDATE_FLAG_HEATPUMP); // unset flag
|
rootSM[SM_PUMPMODULATION] = EMS_SolarModule.pumpModulation;
|
||||||
|
|
||||||
|
if (EMS_SolarModule.pump != EMS_VALUE_BOOL_NOTSET) {
|
||||||
|
rootSM[SM_PUMP] = _bool_to_char(s, EMS_SolarModule.pump);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (EMS_SolarModule.pumpWorkMin != EMS_VALUE_LONG_NOTSET) {
|
||||||
|
rootSM[SM_PUMPWORKMIN] = (float)EMS_SolarModule.pumpWorkMin;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EMS_SolarModule.EnergyLastHour < EMS_VALUE_USHORT_NOTSET)
|
||||||
|
rootSM[SM_ENERGYLASTHOUR] = (float)EMS_SolarModule.EnergyLastHour / 10;
|
||||||
|
|
||||||
|
if (EMS_SolarModule.EnergyToday < EMS_VALUE_USHORT_NOTSET)
|
||||||
|
rootSM[SM_ENERGYTODAY] = EMS_SolarModule.EnergyToday;
|
||||||
|
|
||||||
|
if (EMS_SolarModule.EnergyTotal < EMS_VALUE_USHORT_NOTSET)
|
||||||
|
rootSM[SM_ENERGYTOTAL] = (float)EMS_SolarModule.EnergyTotal / 10;
|
||||||
|
|
||||||
|
serializeJson(doc, data, sizeof(data));
|
||||||
|
myDebugLog("Publishing SM data via MQTT");
|
||||||
|
myESP.mqttPublish(TOPIC_SM_DATA, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle HeatPump
|
||||||
|
void publishEMSValues_heatpump() {
|
||||||
|
StaticJsonDocument<MQTT_MAX_PAYLOAD_SIZE> doc;
|
||||||
|
char data[MQTT_MAX_PAYLOAD_SIZE] = {0};
|
||||||
|
JsonObject rootHP = doc.to<JsonObject>();
|
||||||
|
|
||||||
|
if (EMS_HeatPump.HPModulation != EMS_VALUE_INT_NOTSET)
|
||||||
|
rootHP[HP_PUMPMODULATION] = EMS_HeatPump.HPModulation;
|
||||||
|
|
||||||
|
if (EMS_HeatPump.HPSpeed != EMS_VALUE_INT_NOTSET)
|
||||||
|
rootHP[HP_PUMPSPEED] = EMS_HeatPump.HPSpeed;
|
||||||
|
|
||||||
|
serializeJson(doc, data, sizeof(data));
|
||||||
|
myDebugLog("Publishing HeatPump data via MQTT");
|
||||||
|
myESP.mqttPublish(TOPIC_HP_DATA, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Publish shower data
|
// Publish shower data
|
||||||
void do_publishShowerData() {
|
void do_publishShowerData() {
|
||||||
StaticJsonDocument<200> doc;
|
StaticJsonDocument<MQTT_MAX_PAYLOAD_SIZE_SMALL> doc;
|
||||||
JsonObject rootShower = doc.to<JsonObject>();
|
JsonObject rootShower = doc.to<JsonObject>();
|
||||||
rootShower[TOPIC_SHOWER_TIMER] = EMSESP_Settings.shower_timer ? "1" : "0";
|
rootShower[TOPIC_SHOWER_TIMER] = EMSESP_Settings.shower_timer ? "1" : "0";
|
||||||
rootShower[TOPIC_SHOWER_ALERT] = EMSESP_Settings.shower_alert ? "1" : "0";
|
rootShower[TOPIC_SHOWER_ALERT] = EMSESP_Settings.shower_alert ? "1" : "0";
|
||||||
|
|
||||||
// only publish shower duration if there is a value
|
// only publish shower duration if there is a value
|
||||||
char s[50] = {0};
|
char s[50] = {0};
|
||||||
@@ -956,17 +947,58 @@ void do_publishShowerData() {
|
|||||||
myESP.mqttPublish(TOPIC_SHOWER_DATA, data, false);
|
myESP.mqttPublish(TOPIC_SHOWER_DATA, data, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// call PublishValues with forcing forcing
|
// send values via MQTT
|
||||||
void do_publishValues() {
|
// a json object is created for each device type
|
||||||
|
void publishEMSValues(bool force) {
|
||||||
|
// don't send if MQTT is not connected or EMS bus is not connected
|
||||||
|
if (!myESP.isMQTTConnected() || (!ems_getBusConnected()) || (EMSESP_Settings.publish_time == -1)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ems_getBoilerEnabled() && (ems_Device_has_flags(EMS_DEVICE_UPDATE_FLAG_BOILER) || force)) {
|
||||||
|
publishEMSValues_boiler();
|
||||||
|
ems_Device_remove_flags(EMS_DEVICE_UPDATE_FLAG_BOILER); // unset flag
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ems_getThermostatEnabled() && (ems_Device_has_flags(EMS_DEVICE_UPDATE_FLAG_THERMOSTAT) || force)) {
|
||||||
|
publishEMSValues_thermostat();
|
||||||
|
ems_Device_remove_flags(EMS_DEVICE_UPDATE_FLAG_THERMOSTAT); // unset flag
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ems_getMixingModuleEnabled() && (ems_Device_has_flags(EMS_DEVICE_UPDATE_FLAG_MIXING) || force)) {
|
||||||
|
publishEMSValues_mixing();
|
||||||
|
ems_Device_remove_flags(EMS_DEVICE_UPDATE_FLAG_MIXING); // unset flag
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ems_getSolarModuleEnabled() && (ems_Device_has_flags(EMS_DEVICE_UPDATE_FLAG_SOLAR) || force)) {
|
||||||
|
publishEMSValues_solar();
|
||||||
|
ems_Device_remove_flags(EMS_DEVICE_UPDATE_FLAG_SOLAR); // unset flag
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ems_getHeatPumpEnabled() && (ems_Device_has_flags(EMS_DEVICE_UPDATE_FLAG_HEATPUMP) || force)) {
|
||||||
|
publishEMSValues_heatpump();
|
||||||
|
ems_Device_remove_flags(EMS_DEVICE_UPDATE_FLAG_HEATPUMP); // unset flag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// publishes value via MQTT
|
||||||
|
void publishValues(bool force, bool send_sensor) {
|
||||||
if (EMSESP_Settings.publish_time == -1) {
|
if (EMSESP_Settings.publish_time == -1) {
|
||||||
myDebugLog("Publishing is disabled.");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
myDebugLog("Starting scheduled MQTT publish...");
|
myDebugLog("Starting scheduled MQTT publish...");
|
||||||
publishEMSValues(false);
|
publishEMSValues(force);
|
||||||
publishSensorValues();
|
if (send_sensor) {
|
||||||
myESP.heartbeatCheck(true);
|
publishSensorValues();
|
||||||
|
}
|
||||||
|
// myESP.heartbeatCheck(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// calls publishValues fron the Ticker loop, also sending sensor data
|
||||||
|
// but not using false for force so only data that has changed will be sent
|
||||||
|
void do_publishValues() {
|
||||||
|
publishValues(false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// callback to light up the LED, called via Ticker every second
|
// callback to light up the LED, called via Ticker every second
|
||||||
@@ -2096,6 +2128,10 @@ void initEMSESP() {
|
|||||||
* Shower Logic
|
* Shower Logic
|
||||||
*/
|
*/
|
||||||
void showerCheck() {
|
void showerCheck() {
|
||||||
|
if (!EMSESP_Settings.shower_timer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t time_now = millis();
|
uint32_t time_now = millis();
|
||||||
// if already in cold mode, ignore all this logic until we're out of the cold blast
|
// if already in cold mode, ignore all this logic until we're out of the cold blast
|
||||||
if (!EMSESP_Shower.doingColdShot) {
|
if (!EMSESP_Shower.doingColdShot) {
|
||||||
@@ -2231,7 +2267,7 @@ void setup() {
|
|||||||
if (EMSESP_Settings.publish_time > 0) {
|
if (EMSESP_Settings.publish_time > 0) {
|
||||||
publishValuesTimer.attach(EMSESP_Settings.publish_time, do_publishValues); // post MQTT EMS values
|
publishValuesTimer.attach(EMSESP_Settings.publish_time, do_publishValues); // post MQTT EMS values
|
||||||
} else if (EMSESP_Settings.publish_time == 0) {
|
} else if (EMSESP_Settings.publish_time == 0) {
|
||||||
// automatic mode. use this Ticker to send out sensor values
|
// automatic mode. use this Ticker to send out sensor values only. the EMS ones are done in the loop.
|
||||||
publishValuesTimer.attach(DEFAULT_SENSOR_PUBLISHTIME, publishSensorValues);
|
publishValuesTimer.attach(DEFAULT_SENSOR_PUBLISHTIME, publishSensorValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2256,33 +2292,30 @@ void setup() {
|
|||||||
void loop() {
|
void loop() {
|
||||||
myESP.loop(); // handle telnet, mqtt, wifi etc
|
myESP.loop(); // handle telnet, mqtt, wifi etc
|
||||||
|
|
||||||
// to prevent load, only run checks every second
|
// get Dallas Sensor readings every 2 seconds
|
||||||
static uint32_t last_check = 0;
|
static uint32_t last_check = 0;
|
||||||
if (millis() - last_check < 1000) {
|
uint32_t time_now = millis();
|
||||||
return;
|
if (time_now - last_check > 2000) {
|
||||||
}
|
last_check = time_now;
|
||||||
last_check = millis();
|
if (EMSESP_Settings.dallas_sensors) {
|
||||||
|
ds18.loop();
|
||||||
// get Dallas Sensor readings
|
|
||||||
if (EMSESP_Settings.dallas_sensors) {
|
|
||||||
ds18.loop();
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we have an EMS bus connection go and fetch some data and MQTT publish it
|
|
||||||
if (_need_first_publish) {
|
|
||||||
publishEMSValues(false);
|
|
||||||
publishSensorValues();
|
|
||||||
_need_first_publish = false; // reset flag
|
|
||||||
} else {
|
|
||||||
// check if we're on auto mode for publishing
|
|
||||||
// then send EMS values, only if its been flagged to update
|
|
||||||
if (EMSESP_Settings.publish_time == 0) {
|
|
||||||
publishEMSValues(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// do shower logic, if enabled
|
// if we just have an EMS bus connection go and fetch the data and MQTT publish it to get started
|
||||||
if (EMSESP_Settings.shower_timer) {
|
if (_need_first_publish) {
|
||||||
showerCheck();
|
publishValues(true, true);
|
||||||
|
_need_first_publish = false;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check if we're on auto mode for publishing
|
||||||
|
// then send EMS values, only if its been flagged to update.
|
||||||
|
// Don't send sensor data as this is done by the Ticker
|
||||||
|
if (EMSESP_Settings.publish_time == 0) {
|
||||||
|
publishValues(false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// do shower logic
|
||||||
|
showerCheck();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define APP_VERSION "1.9.5b38"
|
#define APP_VERSION "1.9.5b39"
|
||||||
|
|||||||
Reference in New Issue
Block a user