mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2025-12-06 15:59:52 +03:00
optimized MQTT json
This commit is contained in:
107
src/MyESP.cpp
107
src/MyESP.cpp
@@ -433,22 +433,23 @@ void MyESP::_printMQTTLog() {
|
|||||||
|
|
||||||
// Publish using the user's custom retain flag
|
// Publish using the user's custom retain flag
|
||||||
void MyESP::mqttPublish(const char * topic, const char * payload) {
|
void MyESP::mqttPublish(const char * topic, const char * payload) {
|
||||||
mqttPublish(topic, payload, _mqtt_retain);
|
_mqttQueue(topic, payload, _mqtt_retain);
|
||||||
|
}
|
||||||
|
void MyESP::mqttPublish(const char * topic, JsonDocument payload) {
|
||||||
|
_mqttQueue(topic, payload, _mqtt_retain);
|
||||||
}
|
}
|
||||||
|
|
||||||
// MQTT Publish
|
// MQTT Publish
|
||||||
void MyESP::mqttPublish(const char * topic, const char * payload, bool retain) {
|
void MyESP::mqttPublish(const char * topic, const char * payload, bool retain) {
|
||||||
if (!_hasValue(topic)) {
|
_mqttQueue(topic, payload, retain);
|
||||||
return;
|
}
|
||||||
}
|
void MyESP::mqttPublish(const char * topic, JsonDocument payload, bool retain) {
|
||||||
|
_mqttQueue(topic, payload, retain);
|
||||||
_mqttQueue(topic, payload, retain); // queue the message
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// put a payload string into the queue
|
||||||
bool MyESP::_mqttQueue(const char * topic, const char * payload, bool retain) {
|
bool MyESP::_mqttQueue(const char * topic, const char * payload, bool retain) {
|
||||||
// Queue is not meant to send message "offline"
|
if (!mqttClient.connected() || _mqtt_queue.size() >= MQTT_QUEUE_MAX_SIZE || !_hasValue(topic)) {
|
||||||
// We must prevent the queue does not get full while offline
|
|
||||||
if (!mqttClient.connected() || (_mqtt_queue.size() >= MQTT_QUEUE_MAX_SIZE)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,7 +459,7 @@ bool MyESP::_mqttQueue(const char * topic, const char * payload, bool retain) {
|
|||||||
element.retain = retain;
|
element.retain = retain;
|
||||||
element.packetId = 0;
|
element.packetId = 0;
|
||||||
element.retry_count = 0;
|
element.retry_count = 0;
|
||||||
if (NULL != payload) {
|
if (payload != NULL) {
|
||||||
element.payload = strdup(payload);
|
element.payload = strdup(payload);
|
||||||
}
|
}
|
||||||
#ifdef MYESP_DEBUG
|
#ifdef MYESP_DEBUG
|
||||||
@@ -469,6 +470,34 @@ bool MyESP::_mqttQueue(const char * topic, const char * payload, bool retain) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// convert json doc to a string buffer and place on queue
|
||||||
|
bool MyESP::_mqttQueue(const char * topic, JsonDocument payload, bool retain) {
|
||||||
|
if (!mqttClient.connected() || _mqtt_queue.size() >= MQTT_QUEUE_MAX_SIZE || !_hasValue(topic)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a new message
|
||||||
|
mqtt_message_t element;
|
||||||
|
element.topic = strdup(topic);
|
||||||
|
element.retain = retain;
|
||||||
|
element.packetId = 0;
|
||||||
|
element.retry_count = 0;
|
||||||
|
|
||||||
|
// reserve space for buffer and serialize json into it
|
||||||
|
const size_t capacity = measureJson(payload) + 1;
|
||||||
|
if (capacity) {
|
||||||
|
element.payload = (char *)malloc(capacity);
|
||||||
|
serializeJson(payload, (char *)element.payload, capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MYESP_DEBUG
|
||||||
|
myDebug_P(PSTR("[MQTT] Adding to queue: #%d [%s] %s"), _mqtt_queue.size(), element.topic, element.payload);
|
||||||
|
#endif
|
||||||
|
_mqtt_queue.push_back(element);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// called when an MQTT Publish ACK is received
|
// called when an MQTT Publish ACK is received
|
||||||
// check if ACK matches the last Publish we sent, if not report an error
|
// check if ACK matches the last Publish we sent, if not report an error
|
||||||
// and always remove from queue
|
// and always remove from queue
|
||||||
@@ -1604,11 +1633,10 @@ void MyESP::heartbeatCheck(bool force) {
|
|||||||
uint32_t free_memory = ESP.getFreeHeap();
|
uint32_t free_memory = ESP.getFreeHeap();
|
||||||
uint8_t mem_available = 100 * free_memory / total_memory; // as a %
|
uint8_t mem_available = 100 * free_memory / total_memory; // as a %
|
||||||
|
|
||||||
StaticJsonDocument<MYESP_JSON_MAXSIZE_SMALL> doc;
|
const size_t capacity = JSON_OBJECT_SIZE(6);
|
||||||
JsonObject rootHeartbeat = doc.to<JsonObject>();
|
StaticJsonDocument<capacity> doc;
|
||||||
|
JsonObject rootHeartbeat = doc.to<JsonObject>();
|
||||||
|
|
||||||
//rootHeartbeat["version"] = _app_version;
|
|
||||||
//rootHeartbeat["IP"] = WiFi.localIP().toString();
|
|
||||||
rootHeartbeat["rssid"] = getWifiQuality();
|
rootHeartbeat["rssid"] = getWifiQuality();
|
||||||
rootHeartbeat["load"] = getSystemLoadAverage();
|
rootHeartbeat["load"] = getSystemLoadAverage();
|
||||||
rootHeartbeat["uptime"] = _getUptime();
|
rootHeartbeat["uptime"] = _getUptime();
|
||||||
@@ -1616,10 +1644,7 @@ void MyESP::heartbeatCheck(bool force) {
|
|||||||
rootHeartbeat["tcpdrops"] = _getSystemDropoutCounter();
|
rootHeartbeat["tcpdrops"] = _getSystemDropoutCounter();
|
||||||
rootHeartbeat["mqttpublishfails"] = _mqtt_publish_fails;
|
rootHeartbeat["mqttpublishfails"] = _mqtt_publish_fails;
|
||||||
|
|
||||||
char data[300] = {0};
|
mqttPublish(MQTT_TOPIC_HEARTBEAT, doc, false); // send to MQTT with retain off
|
||||||
serializeJson(doc, data, sizeof(data));
|
|
||||||
|
|
||||||
(void)mqttPublish(MQTT_TOPIC_HEARTBEAT, data, false); // send to MQTT with retain off
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1632,13 +1657,13 @@ void MyESP::heartbeatPrint() {
|
|||||||
uint32_t total_memory = _getInitialFreeHeap();
|
uint32_t total_memory = _getInitialFreeHeap();
|
||||||
uint32_t free_memory = ESP.getFreeHeap();
|
uint32_t free_memory = ESP.getFreeHeap();
|
||||||
|
|
||||||
myDebug("[%d] uptime:%d bytesfree:%d (%2u%%), load:%d, dropouts:%d",
|
myDebug_P(PSTR("[%d] uptime:%d bytesfree:%d (%2u%%), load:%d, dropouts:%d"),
|
||||||
i++,
|
i++,
|
||||||
_getUptime(),
|
_getUptime(),
|
||||||
free_memory,
|
free_memory,
|
||||||
100 * free_memory / total_memory,
|
100 * free_memory / total_memory,
|
||||||
getSystemLoadAverage(),
|
getSystemLoadAverage(),
|
||||||
_getSystemDropoutCounter()
|
_getSystemDropoutCounter()
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -2418,7 +2443,7 @@ void MyESP::writeLogEvent(const uint8_t type, const char * msg) {
|
|||||||
// Handles WebSocket Events
|
// Handles WebSocket Events
|
||||||
void MyESP::_onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t * data, size_t len) {
|
void MyESP::_onWsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventType type, void * arg, uint8_t * data, size_t len) {
|
||||||
if (type == WS_EVT_ERROR) {
|
if (type == WS_EVT_ERROR) {
|
||||||
myDebug("[WEB] WebSocket[%s][%u] error(%u): %s\r\n", server->url(), client->id(), *((uint16_t *)arg), (char *)data);
|
myDebug_P(PSTR("[WEB] WebSocket[%s][%u] error(%u): %s\r\n"), server->url(), client->id(), *((uint16_t *)arg), (char *)data);
|
||||||
} else if (type == WS_EVT_DATA) {
|
} else if (type == WS_EVT_DATA) {
|
||||||
AwsFrameInfo * info = (AwsFrameInfo *)arg;
|
AwsFrameInfo * info = (AwsFrameInfo *)arg;
|
||||||
uint64_t index = info->index;
|
uint64_t index = info->index;
|
||||||
@@ -2550,7 +2575,7 @@ bool MyESP::_fs_sendConfig() {
|
|||||||
|
|
||||||
// send custom status via ws
|
// send custom status via ws
|
||||||
void MyESP::_sendCustomStatus() {
|
void MyESP::_sendCustomStatus() {
|
||||||
DynamicJsonDocument doc(MYESP_JSON_MAXSIZE_LARGE);
|
DynamicJsonDocument doc(MYESP_JSON_MAXSIZE_MEDIUM);
|
||||||
|
|
||||||
JsonObject root = doc.to<JsonObject>();
|
JsonObject root = doc.to<JsonObject>();
|
||||||
|
|
||||||
@@ -2566,7 +2591,7 @@ void MyESP::_sendCustomStatus() {
|
|||||||
(_web_callback_f)(root);
|
(_web_callback_f)(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
char buffer[MYESP_JSON_MAXSIZE_LARGE];
|
char buffer[MYESP_JSON_MAXSIZE_MEDIUM];
|
||||||
size_t len = serializeJson(root, buffer);
|
size_t len = serializeJson(root, buffer);
|
||||||
|
|
||||||
#ifdef MYESP_DEBUG
|
#ifdef MYESP_DEBUG
|
||||||
@@ -2582,13 +2607,13 @@ void MyESP::_sendStatus() {
|
|||||||
uint32_t total_memory = _getInitialFreeHeap();
|
uint32_t total_memory = _getInitialFreeHeap();
|
||||||
uint32_t free_memory = ESP.getFreeHeap();
|
uint32_t free_memory = ESP.getFreeHeap();
|
||||||
|
|
||||||
DynamicJsonDocument doc(MQTT_MAX_PAYLOAD_SIZE_LARGE);
|
DynamicJsonDocument doc(MYESP_JSON_MAXSIZE_MEDIUM);
|
||||||
JsonObject root = doc.to<JsonObject>();
|
JsonObject root = doc.to<JsonObject>();
|
||||||
root["command"] = "status";
|
root["command"] = "status";
|
||||||
|
|
||||||
FSInfo fsinfo;
|
FSInfo fsinfo;
|
||||||
if (!SPIFFS.info(fsinfo)) {
|
if (!SPIFFS.info(fsinfo)) {
|
||||||
myDebug("[SYSTEM] Error getting info on SPIFFS");
|
myDebug_P(PSTR("[SYSTEM] Error getting info on SPIFFS"));
|
||||||
} else {
|
} else {
|
||||||
root["availspiffs"] = (fsinfo.totalBytes - fsinfo.usedBytes) / 1000;
|
root["availspiffs"] = (fsinfo.totalBytes - fsinfo.usedBytes) / 1000;
|
||||||
root["spiffssize"] = (fsinfo.totalBytes / 1000);
|
root["spiffssize"] = (fsinfo.totalBytes / 1000);
|
||||||
@@ -2626,7 +2651,7 @@ void MyESP::_sendStatus() {
|
|||||||
sprintf(uptime, "%d day%s %d hour%s %d minute%s %d second%s", d, (d == 1) ? "" : "s", h, (h == 1) ? "" : "s", m, (m == 1) ? "" : "s", sec, (sec == 1) ? "" : "s");
|
sprintf(uptime, "%d day%s %d hour%s %d minute%s %d second%s", d, (d == 1) ? "" : "s", h, (h == 1) ? "" : "s", m, (m == 1) ? "" : "s", sec, (sec == 1) ? "" : "s");
|
||||||
root["uptime"] = uptime;
|
root["uptime"] = uptime;
|
||||||
|
|
||||||
char buffer[MQTT_MAX_PAYLOAD_SIZE_LARGE];
|
char buffer[MYESP_JSON_MAXSIZE_MEDIUM];
|
||||||
size_t len = serializeJson(root, buffer);
|
size_t len = serializeJson(root, buffer);
|
||||||
|
|
||||||
_ws->textAll(buffer, len);
|
_ws->textAll(buffer, len);
|
||||||
@@ -2783,13 +2808,13 @@ void MyESP::_printHeap(const char * prefix) {
|
|||||||
uint32_t total_memory = _getInitialFreeHeap();
|
uint32_t total_memory = _getInitialFreeHeap();
|
||||||
uint32_t free_memory = ESP.getFreeHeap();
|
uint32_t free_memory = ESP.getFreeHeap();
|
||||||
|
|
||||||
myDebug("%s Free Heap: %d bytes initially | %d bytes used (%2u%%) | %d bytes free (%2u%%)",
|
myDebug_P(PSTR("%s Free Heap: %d bytes initially | %d bytes used (%2u%%) | %d bytes free (%2u%%)"),
|
||||||
prefix,
|
prefix,
|
||||||
total_memory,
|
total_memory,
|
||||||
total_memory - free_memory,
|
total_memory - free_memory,
|
||||||
100 * (total_memory - free_memory) / total_memory,
|
100 * (total_memory - free_memory) / total_memory,
|
||||||
free_memory,
|
free_memory,
|
||||||
100 * free_memory / total_memory);
|
100 * free_memory / total_memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
// send UTC time via ws
|
// send UTC time via ws
|
||||||
@@ -2959,7 +2984,7 @@ void MyESP::loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_formatreq) {
|
if (_formatreq) {
|
||||||
myDebug("[SYSTEM] Factory reset initiated. Please wait. System will automatically restart when complete...");
|
myDebug_P(PSTR("[SYSTEM] Factory reset initiated. Please wait. System will automatically restart when complete..."));
|
||||||
SPIFFS.end();
|
SPIFFS.end();
|
||||||
_ws->enable(false);
|
_ws->enable(false);
|
||||||
SPIFFS.format();
|
SPIFFS.format();
|
||||||
@@ -2969,7 +2994,7 @@ void MyESP::loop() {
|
|||||||
|
|
||||||
if (_shouldRestart) {
|
if (_shouldRestart) {
|
||||||
writeLogEvent(MYESP_SYSLOG_INFO, "System is restarting");
|
writeLogEvent(MYESP_SYSLOG_INFO, "System is restarting");
|
||||||
myDebug("[SYSTEM] Restarting...");
|
myDebug_P(PSTR("[SYSTEM] Restarting..."));
|
||||||
_deferredReset(500, CUSTOM_RESET_TERMINAL);
|
_deferredReset(500, CUSTOM_RESET_TERMINAL);
|
||||||
ESP.restart();
|
ESP.restart();
|
||||||
}
|
}
|
||||||
@@ -2977,6 +3002,4 @@ void MyESP::loop() {
|
|||||||
delay(MYESP_DELAY); // some time to WiFi and everything else to catch up, calls yield, and also prevent overheating
|
delay(MYESP_DELAY); // some time to WiFi and everything else to catch up, calls yield, and also prevent overheating
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
MyESP myESP;
|
MyESP myESP;
|
||||||
|
|||||||
25
src/MyESP.h
25
src/MyESP.h
@@ -96,22 +96,18 @@ extern struct rst_info resetInfo;
|
|||||||
#define MQTT_QOS 0 // default qos 0
|
#define MQTT_QOS 0 // default qos 0
|
||||||
#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_QUEUE_MAX_SIZE 50 // Size of the MQTT queue
|
||||||
#define MQTT_MAX_PAYLOAD_SIZE_LARGE 2000 // max size of a large JSON object
|
#define MQTT_PUBLISH_WAIT 750 // time in ms before sending MQTT messages
|
||||||
#define MQTT_MAX_PAYLOAD_SIZE_SMALL 200
|
#define MQTT_PUBLISH_MAX_RETRY 4 // max retries for giving up on publishing
|
||||||
#define MQTT_QUEUE_MAX_SIZE 20 // Size of the MQTT queue
|
#define MYESP_JSON_MAXSIZE_LARGE 2000 // for large Dynamic json files - https://arduinojson.org/v6/assistant/
|
||||||
#define MQTT_PUBLISH_WAIT 1000 // every 1 second check MQTT queue
|
#define MYESP_JSON_MAXSIZE_MEDIUM 800 // for medium Dynamic json files - https://arduinojson.org/v6/assistant/
|
||||||
#define MQTT_PUBLISH_MAX_RETRY 4 // max retries for giving up on publishing
|
#define MYESP_JSON_MAXSIZE_SMALL 200 // for smaller Static json documents - https://arduinojson.org/v6/assistant/
|
||||||
|
|
||||||
// Internal MQTT events
|
// Internal MQTT events
|
||||||
#define MQTT_CONNECT_EVENT 0
|
#define MQTT_CONNECT_EVENT 0
|
||||||
#define MQTT_DISCONNECT_EVENT 1
|
#define MQTT_DISCONNECT_EVENT 1
|
||||||
#define MQTT_MESSAGE_EVENT 2
|
#define MQTT_MESSAGE_EVENT 2
|
||||||
|
|
||||||
#define MYESP_JSON_MAXSIZE_LARGE 2000 // for large Dynamic json files
|
|
||||||
#define MYESP_JSON_MAXSIZE_MEDIUM 800 // for medium Dynamic json files
|
|
||||||
#define MYESP_JSON_MAXSIZE_SMALL 200 // for smaller Static json documents
|
|
||||||
|
|
||||||
#define MYESP_MQTT_PAYLOAD_ON '1' // for MQTT switch on
|
#define MYESP_MQTT_PAYLOAD_ON '1' // for MQTT switch on
|
||||||
#define MYESP_MQTT_PAYLOAD_OFF '0' // for MQTT switch off
|
#define MYESP_MQTT_PAYLOAD_OFF '0' // for MQTT switch off
|
||||||
|
|
||||||
@@ -213,9 +209,9 @@ struct RtcmemData {
|
|||||||
|
|
||||||
static_assert(sizeof(RtcmemData) <= (RTCMEM_BLOCKS * 4u), "RTCMEM struct is too big");
|
static_assert(sizeof(RtcmemData) <= (RTCMEM_BLOCKS * 4u), "RTCMEM struct is too big");
|
||||||
|
|
||||||
#define MYESP_SYSTEM_CHECK_TIME 60000 // The system is considered stable after these many millis (1 minute)
|
#define MYESP_SYSTEM_CHECK_TIME 60000 // The system is considered stable after these many millis (1 min)
|
||||||
#define MYESP_SYSTEM_CHECK_MAX 10 // After this many crashes on boot
|
#define MYESP_SYSTEM_CHECK_MAX 10 // After this many crashes on boot
|
||||||
#define MYESP_HEARTBEAT_INTERVAL 120000 // in milliseconds, how often the MQTT heartbeat is sent (2 mins)
|
#define MYESP_HEARTBEAT_INTERVAL 60000 // in milliseconds, how often the MQTT heartbeat is sent (1 min)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool set; // is it a set command?
|
bool set; // is it a set command?
|
||||||
@@ -286,6 +282,8 @@ class MyESP {
|
|||||||
void mqttUnsubscribe(const char * topic);
|
void mqttUnsubscribe(const char * topic);
|
||||||
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 mqttPublish(const char * topic, JsonDocument payload);
|
||||||
|
void mqttPublish(const char * topic, JsonDocument payload, bool retain);
|
||||||
void setMQTT(mqtt_callback_f callback);
|
void setMQTT(mqtt_callback_f callback);
|
||||||
bool mqttUseNestedJson();
|
bool mqttUseNestedJson();
|
||||||
|
|
||||||
@@ -346,6 +344,7 @@ class MyESP {
|
|||||||
void _sendStart();
|
void _sendStart();
|
||||||
char * _mqttTopic(const char * topic);
|
char * _mqttTopic(const char * topic);
|
||||||
bool _mqttQueue(const char * topic, const char * payload, bool retain);
|
bool _mqttQueue(const char * topic, const char * payload, bool retain);
|
||||||
|
bool _mqttQueue(const char * topic, JsonDocument payload, bool retain);
|
||||||
void _printMQTTLog();
|
void _printMQTTLog();
|
||||||
void _mqttPublishQueue();
|
void _mqttPublishQueue();
|
||||||
void _mqttRemoveLastPublish();
|
void _mqttRemoveLastPublish();
|
||||||
|
|||||||
308
src/ems-esp.cpp
308
src/ems-esp.cpp
@@ -573,14 +573,14 @@ void publishSensorValues() {
|
|||||||
|
|
||||||
// each payload per sensor is 30 bytes so calculate if we have enough space
|
// each payload per sensor is 30 bytes so calculate if we have enough space
|
||||||
if ((EMSESP_Settings.dallas_sensors * 50) > DS18_MQTT_PAYLOAD_MAXSIZE) {
|
if ((EMSESP_Settings.dallas_sensors * 50) > DS18_MQTT_PAYLOAD_MAXSIZE) {
|
||||||
myDebug("Error: too many Dallas sensors for MQTT payload");
|
myDebug_P(PSTR("Error: too many Dallas sensors for MQTT payload"));
|
||||||
}
|
}
|
||||||
|
|
||||||
StaticJsonDocument<DS18_MQTT_PAYLOAD_MAXSIZE> doc;
|
StaticJsonDocument<DS18_MQTT_PAYLOAD_MAXSIZE> doc;
|
||||||
JsonObject sensors = doc.to<JsonObject>();
|
JsonObject sensors = doc.to<JsonObject>();
|
||||||
|
|
||||||
bool hasdata = false;
|
bool hasdata = false;
|
||||||
char buffer[128] = {0}; // temp string buffer
|
char buffer[128]; // temp string buffer
|
||||||
|
|
||||||
// if we're not using nested JSON, send each sensor out seperately
|
// if we're not using nested JSON, send each sensor out seperately
|
||||||
if (!myESP.mqttUseNestedJson()) {
|
if (!myESP.mqttUseNestedJson()) {
|
||||||
@@ -593,9 +593,7 @@ void publishSensorValues() {
|
|||||||
strlcat(topic, _int_to_char(buffer, i + 1), sizeof(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_ID] = ds18.getDeviceID(buffer, i); // add ID
|
||||||
sensors[PAYLOAD_EXTERNAL_SENSOR_TEMP] = sensorValue; // add temp value
|
sensors[PAYLOAD_EXTERNAL_SENSOR_TEMP] = sensorValue; // add temp value
|
||||||
char data[100] = {0};
|
myESP.mqttPublish(topic, doc); // and publish
|
||||||
serializeJson(doc, data, sizeof(data)); // convert to string
|
|
||||||
myESP.mqttPublish(topic, data); // and publish
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hasdata) {
|
if (hasdata) {
|
||||||
@@ -604,24 +602,25 @@ void publishSensorValues() {
|
|||||||
return; // exit
|
return; // exit
|
||||||
}
|
}
|
||||||
|
|
||||||
// see if the sensor values have changed, if so send it on
|
// group all sensors together - https://github.com/proddy/EMS-ESP/issues/327
|
||||||
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 - https://github.com/proddy/EMS-ESP/issues/327
|
#ifdef SENSOR_MQTT_USEID
|
||||||
|
sensors[ds18.getDeviceID(buffer, i)] = sensorValue;
|
||||||
|
#else
|
||||||
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));
|
||||||
JsonObject dataSensor = sensors.createNestedObject(sensorID);
|
JsonObject dataSensor = sensors.createNestedObject(sensorID);
|
||||||
dataSensor[PAYLOAD_EXTERNAL_SENSOR_ID] = ds18.getDeviceID(buffer, i);
|
dataSensor[PAYLOAD_EXTERNAL_SENSOR_ID] = ds18.getDeviceID(buffer, i);
|
||||||
dataSensor[PAYLOAD_EXTERNAL_SENSOR_TEMP] = sensorValue;
|
dataSensor[PAYLOAD_EXTERNAL_SENSOR_TEMP] = sensorValue;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char data[DS18_MQTT_PAYLOAD_MAXSIZE] = {0};
|
myESP.mqttPublish(TOPIC_EXTERNAL_SENSORS, doc);
|
||||||
serializeJson(doc, data, sizeof(data));
|
|
||||||
myESP.mqttPublish(TOPIC_EXTERNAL_SENSORS, data);
|
|
||||||
|
|
||||||
if (hasdata) {
|
if (hasdata) {
|
||||||
myDebugLog("Publishing external sensor data via MQTT");
|
myDebugLog("Publishing external sensor data via MQTT");
|
||||||
@@ -630,10 +629,11 @@ void publishSensorValues() {
|
|||||||
|
|
||||||
// publish Boiler data via MQTT
|
// publish Boiler data via MQTT
|
||||||
void publishEMSValues_boiler() {
|
void publishEMSValues_boiler() {
|
||||||
char s[20] = {0}; // for formatting strings
|
const size_t capacity = JSON_OBJECT_SIZE(34); // must recalculate if more objects addded https://arduinojson.org/v6/assistant/
|
||||||
StaticJsonDocument<MQTT_MAX_PAYLOAD_SIZE> doc;
|
DynamicJsonDocument doc(capacity);
|
||||||
char data[MQTT_MAX_PAYLOAD_SIZE] = {0};
|
JsonObject rootBoiler = doc.to<JsonObject>();
|
||||||
JsonObject rootBoiler = doc.to<JsonObject>();
|
|
||||||
|
char s[20]; // for formatting strings
|
||||||
|
|
||||||
if (EMS_Boiler.wWComfort == EMS_VALUE_UBAParameterWW_wwComfort_Hot) {
|
if (EMS_Boiler.wWComfort == EMS_VALUE_UBAParameterWW_wwComfort_Hot) {
|
||||||
rootBoiler["wWComfort"] = "Hot";
|
rootBoiler["wWComfort"] = "Hot";
|
||||||
@@ -643,126 +643,153 @@ void publishEMSValues_boiler() {
|
|||||||
rootBoiler["wWComfort"] = "Intelligent";
|
rootBoiler["wWComfort"] = "Intelligent";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EMS_Boiler.wWSelTemp != EMS_VALUE_INT_NOTSET)
|
if (EMS_Boiler.wWSelTemp != EMS_VALUE_INT_NOTSET) {
|
||||||
rootBoiler["wWSelTemp"] = EMS_Boiler.wWSelTemp;
|
rootBoiler["wWSelTemp"] = EMS_Boiler.wWSelTemp;
|
||||||
if (EMS_Boiler.wWDesinfectTemp != EMS_VALUE_INT_NOTSET)
|
}
|
||||||
|
if (EMS_Boiler.wWDesinfectTemp != EMS_VALUE_INT_NOTSET) {
|
||||||
rootBoiler["wWDesinfectionTemp"] = EMS_Boiler.wWDesinfectTemp;
|
rootBoiler["wWDesinfectionTemp"] = EMS_Boiler.wWDesinfectTemp;
|
||||||
if (EMS_Boiler.selFlowTemp != EMS_VALUE_INT_NOTSET)
|
}
|
||||||
|
if (EMS_Boiler.selFlowTemp != EMS_VALUE_INT_NOTSET) {
|
||||||
rootBoiler["selFlowTemp"] = EMS_Boiler.selFlowTemp;
|
rootBoiler["selFlowTemp"] = EMS_Boiler.selFlowTemp;
|
||||||
if (EMS_Boiler.selBurnPow != EMS_VALUE_INT_NOTSET)
|
}
|
||||||
|
if (EMS_Boiler.selBurnPow != EMS_VALUE_INT_NOTSET) {
|
||||||
rootBoiler["selBurnPow"] = EMS_Boiler.selBurnPow;
|
rootBoiler["selBurnPow"] = EMS_Boiler.selBurnPow;
|
||||||
if (EMS_Boiler.curBurnPow != EMS_VALUE_INT_NOTSET)
|
}
|
||||||
|
if (EMS_Boiler.curBurnPow != EMS_VALUE_INT_NOTSET) {
|
||||||
rootBoiler["curBurnPow"] = EMS_Boiler.curBurnPow;
|
rootBoiler["curBurnPow"] = EMS_Boiler.curBurnPow;
|
||||||
if (EMS_Boiler.pumpMod != EMS_VALUE_INT_NOTSET)
|
}
|
||||||
|
if (EMS_Boiler.pumpMod != EMS_VALUE_INT_NOTSET) {
|
||||||
rootBoiler["pumpMod"] = EMS_Boiler.pumpMod;
|
rootBoiler["pumpMod"] = EMS_Boiler.pumpMod;
|
||||||
if (EMS_Boiler.wWCircPump != EMS_VALUE_BOOL_NOTSET)
|
}
|
||||||
|
if (EMS_Boiler.wWCircPump != EMS_VALUE_BOOL_NOTSET) {
|
||||||
rootBoiler["wWCircPump"] = EMS_Boiler.wWCircPump;
|
rootBoiler["wWCircPump"] = EMS_Boiler.wWCircPump;
|
||||||
|
}
|
||||||
if (EMS_Boiler.extTemp > EMS_VALUE_SHORT_NOTSET)
|
if (EMS_Boiler.extTemp > EMS_VALUE_SHORT_NOTSET) {
|
||||||
rootBoiler["outdoorTemp"] = (float)EMS_Boiler.extTemp / 10;
|
rootBoiler["outdoorTemp"] = (float)EMS_Boiler.extTemp / 10;
|
||||||
if (EMS_Boiler.wWCurTmp < EMS_VALUE_USHORT_NOTSET)
|
}
|
||||||
|
if (EMS_Boiler.wWCurTmp < EMS_VALUE_USHORT_NOTSET) {
|
||||||
rootBoiler["wWCurTmp"] = (float)EMS_Boiler.wWCurTmp / 10;
|
rootBoiler["wWCurTmp"] = (float)EMS_Boiler.wWCurTmp / 10;
|
||||||
if (EMS_Boiler.wWCurFlow != EMS_VALUE_INT_NOTSET)
|
}
|
||||||
|
if (EMS_Boiler.wWCurFlow != EMS_VALUE_INT_NOTSET) {
|
||||||
rootBoiler["wWCurFlow"] = (float)EMS_Boiler.wWCurFlow / 10;
|
rootBoiler["wWCurFlow"] = (float)EMS_Boiler.wWCurFlow / 10;
|
||||||
if (EMS_Boiler.curFlowTemp < EMS_VALUE_USHORT_NOTSET)
|
}
|
||||||
|
if (EMS_Boiler.curFlowTemp < EMS_VALUE_USHORT_NOTSET) {
|
||||||
rootBoiler["curFlowTemp"] = (float)EMS_Boiler.curFlowTemp / 10;
|
rootBoiler["curFlowTemp"] = (float)EMS_Boiler.curFlowTemp / 10;
|
||||||
if (EMS_Boiler.retTemp < EMS_VALUE_USHORT_NOTSET)
|
}
|
||||||
|
if (EMS_Boiler.retTemp < EMS_VALUE_USHORT_NOTSET) {
|
||||||
rootBoiler["retTemp"] = (float)EMS_Boiler.retTemp / 10;
|
rootBoiler["retTemp"] = (float)EMS_Boiler.retTemp / 10;
|
||||||
if (EMS_Boiler.switchTemp < EMS_VALUE_USHORT_NOTSET)
|
}
|
||||||
|
if (EMS_Boiler.switchTemp < EMS_VALUE_USHORT_NOTSET) {
|
||||||
rootBoiler["switchTemp"] = (float)EMS_Boiler.switchTemp / 10;
|
rootBoiler["switchTemp"] = (float)EMS_Boiler.switchTemp / 10;
|
||||||
if (EMS_Boiler.sysPress != EMS_VALUE_INT_NOTSET)
|
}
|
||||||
|
if (EMS_Boiler.sysPress != EMS_VALUE_INT_NOTSET) {
|
||||||
rootBoiler["sysPress"] = (float)EMS_Boiler.sysPress / 10;
|
rootBoiler["sysPress"] = (float)EMS_Boiler.sysPress / 10;
|
||||||
if (EMS_Boiler.boilTemp < EMS_VALUE_USHORT_NOTSET)
|
}
|
||||||
|
if (EMS_Boiler.boilTemp < EMS_VALUE_USHORT_NOTSET) {
|
||||||
rootBoiler["boilTemp"] = (float)EMS_Boiler.boilTemp / 10;
|
rootBoiler["boilTemp"] = (float)EMS_Boiler.boilTemp / 10;
|
||||||
if (EMS_Boiler.exhaustTemp < EMS_VALUE_USHORT_NOTSET)
|
}
|
||||||
|
if (EMS_Boiler.exhaustTemp < EMS_VALUE_USHORT_NOTSET) {
|
||||||
rootBoiler["exhaustTemp"] = (float)EMS_Boiler.exhaustTemp / 10;
|
rootBoiler["exhaustTemp"] = (float)EMS_Boiler.exhaustTemp / 10;
|
||||||
if (EMS_Boiler.wWActivated != EMS_VALUE_BOOL_NOTSET)
|
}
|
||||||
|
if (EMS_Boiler.wWActivated != EMS_VALUE_BOOL_NOTSET) {
|
||||||
rootBoiler["wWActivated"] = _bool_to_char(s, EMS_Boiler.wWActivated);
|
rootBoiler["wWActivated"] = _bool_to_char(s, EMS_Boiler.wWActivated);
|
||||||
|
}
|
||||||
if (EMS_Boiler.wWActivated != EMS_VALUE_BOOL_NOTSET)
|
if (EMS_Boiler.wWActivated != EMS_VALUE_BOOL_NOTSET) {
|
||||||
rootBoiler["wWOnetime"] = _bool_to_char(s, EMS_Boiler.wWOneTime);
|
rootBoiler["wWOnetime"] = _bool_to_char(s, EMS_Boiler.wWOneTime);
|
||||||
|
}
|
||||||
if (EMS_Boiler.wWCirc != EMS_VALUE_BOOL_NOTSET)
|
if (EMS_Boiler.wWCirc != EMS_VALUE_BOOL_NOTSET) {
|
||||||
rootBoiler["wWCirc"] = _bool_to_char(s, EMS_Boiler.wWCirc);
|
rootBoiler["wWCirc"] = _bool_to_char(s, EMS_Boiler.wWCirc);
|
||||||
|
}
|
||||||
if (EMS_Boiler.burnGas != EMS_VALUE_BOOL_NOTSET)
|
if (EMS_Boiler.burnGas != EMS_VALUE_BOOL_NOTSET) {
|
||||||
rootBoiler["burnGas"] = _bool_to_char(s, EMS_Boiler.burnGas);
|
rootBoiler["burnGas"] = _bool_to_char(s, EMS_Boiler.burnGas);
|
||||||
|
}
|
||||||
if (EMS_Boiler.flameCurr < EMS_VALUE_USHORT_NOTSET)
|
if (EMS_Boiler.flameCurr < EMS_VALUE_USHORT_NOTSET) {
|
||||||
rootBoiler["flameCurr"] = (float)(int16_t)EMS_Boiler.flameCurr / 10;
|
rootBoiler["flameCurr"] = (float)(int16_t)EMS_Boiler.flameCurr / 10;
|
||||||
|
}
|
||||||
if (EMS_Boiler.heatPmp != EMS_VALUE_BOOL_NOTSET)
|
if (EMS_Boiler.heatPmp != EMS_VALUE_BOOL_NOTSET) {
|
||||||
rootBoiler["heatPmp"] = _bool_to_char(s, EMS_Boiler.heatPmp);
|
rootBoiler["heatPmp"] = _bool_to_char(s, EMS_Boiler.heatPmp);
|
||||||
|
}
|
||||||
if (EMS_Boiler.fanWork != EMS_VALUE_BOOL_NOTSET)
|
if (EMS_Boiler.fanWork != EMS_VALUE_BOOL_NOTSET) {
|
||||||
rootBoiler["fanWork"] = _bool_to_char(s, EMS_Boiler.fanWork);
|
rootBoiler["fanWork"] = _bool_to_char(s, EMS_Boiler.fanWork);
|
||||||
|
}
|
||||||
if (EMS_Boiler.ignWork != EMS_VALUE_BOOL_NOTSET)
|
if (EMS_Boiler.ignWork != EMS_VALUE_BOOL_NOTSET) {
|
||||||
rootBoiler["ignWork"] = _bool_to_char(s, EMS_Boiler.ignWork);
|
rootBoiler["ignWork"] = _bool_to_char(s, EMS_Boiler.ignWork);
|
||||||
|
}
|
||||||
if (EMS_Boiler.heating_temp != EMS_VALUE_INT_NOTSET)
|
if (EMS_Boiler.heating_temp != EMS_VALUE_INT_NOTSET) {
|
||||||
rootBoiler["heating_temp"] = EMS_Boiler.heating_temp;
|
rootBoiler["heating_temp"] = EMS_Boiler.heating_temp;
|
||||||
if (EMS_Boiler.pump_mod_max != EMS_VALUE_INT_NOTSET)
|
}
|
||||||
|
if (EMS_Boiler.pump_mod_max != EMS_VALUE_INT_NOTSET) {
|
||||||
rootBoiler["pump_mod_max"] = EMS_Boiler.pump_mod_max;
|
rootBoiler["pump_mod_max"] = EMS_Boiler.pump_mod_max;
|
||||||
if (EMS_Boiler.pump_mod_min != EMS_VALUE_INT_NOTSET)
|
}
|
||||||
|
if (EMS_Boiler.pump_mod_min != EMS_VALUE_INT_NOTSET) {
|
||||||
rootBoiler["pump_mod_min"] = EMS_Boiler.pump_mod_min;
|
rootBoiler["pump_mod_min"] = EMS_Boiler.pump_mod_min;
|
||||||
|
}
|
||||||
if (EMS_Boiler.wWHeat != EMS_VALUE_BOOL_NOTSET)
|
if (EMS_Boiler.wWHeat != EMS_VALUE_BOOL_NOTSET) {
|
||||||
rootBoiler["wWHeat"] = _bool_to_char(s, EMS_Boiler.wWHeat);
|
rootBoiler["wWHeat"] = _bool_to_char(s, EMS_Boiler.wWHeat);
|
||||||
|
}
|
||||||
if (abs(EMS_Boiler.wWStarts) != EMS_VALUE_LONG_NOTSET)
|
if (abs(EMS_Boiler.wWStarts) != EMS_VALUE_LONG_NOTSET) {
|
||||||
rootBoiler["wWStarts"] = (float)EMS_Boiler.wWStarts;
|
rootBoiler["wWStarts"] = (float)EMS_Boiler.wWStarts;
|
||||||
if (abs(EMS_Boiler.wWWorkM) != EMS_VALUE_LONG_NOTSET)
|
}
|
||||||
|
if (abs(EMS_Boiler.wWWorkM) != EMS_VALUE_LONG_NOTSET) {
|
||||||
rootBoiler["wWWorkM"] = (float)EMS_Boiler.wWWorkM;
|
rootBoiler["wWWorkM"] = (float)EMS_Boiler.wWWorkM;
|
||||||
if (abs(EMS_Boiler.UBAuptime) != EMS_VALUE_LONG_NOTSET)
|
}
|
||||||
|
if (abs(EMS_Boiler.UBAuptime) != EMS_VALUE_LONG_NOTSET) {
|
||||||
rootBoiler["UBAuptime"] = (float)EMS_Boiler.UBAuptime;
|
rootBoiler["UBAuptime"] = (float)EMS_Boiler.UBAuptime;
|
||||||
|
}
|
||||||
if (abs(EMS_Boiler.burnStarts) != EMS_VALUE_LONG_NOTSET)
|
if (abs(EMS_Boiler.burnStarts) != EMS_VALUE_LONG_NOTSET) {
|
||||||
rootBoiler["burnStarts"] = (float)EMS_Boiler.burnStarts;
|
rootBoiler["burnStarts"] = (float)EMS_Boiler.burnStarts;
|
||||||
if (abs(EMS_Boiler.burnWorkMin) != EMS_VALUE_LONG_NOTSET)
|
}
|
||||||
|
if (abs(EMS_Boiler.burnWorkMin) != EMS_VALUE_LONG_NOTSET) {
|
||||||
rootBoiler["burnWorkMin"] = (float)EMS_Boiler.burnWorkMin;
|
rootBoiler["burnWorkMin"] = (float)EMS_Boiler.burnWorkMin;
|
||||||
if (abs(EMS_Boiler.heatWorkMin) != EMS_VALUE_LONG_NOTSET)
|
}
|
||||||
|
if (abs(EMS_Boiler.heatWorkMin) != EMS_VALUE_LONG_NOTSET) {
|
||||||
rootBoiler["heatWorkMin"] = (float)EMS_Boiler.heatWorkMin;
|
rootBoiler["heatWorkMin"] = (float)EMS_Boiler.heatWorkMin;
|
||||||
|
}
|
||||||
|
|
||||||
if (EMS_Boiler.serviceCode != EMS_VALUE_USHORT_NOTSET) {
|
if (EMS_Boiler.serviceCode != EMS_VALUE_USHORT_NOTSET) {
|
||||||
rootBoiler["ServiceCode"] = EMS_Boiler.serviceCodeChar;
|
rootBoiler["ServiceCode"] = EMS_Boiler.serviceCodeChar;
|
||||||
rootBoiler["ServiceCodeNumber"] = EMS_Boiler.serviceCode;
|
rootBoiler["ServiceCodeNumber"] = EMS_Boiler.serviceCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
serializeJson(doc, data, sizeof(data));
|
|
||||||
myDebugLog("Publishing boiler data via MQTT");
|
myDebugLog("Publishing boiler data via MQTT");
|
||||||
myESP.mqttPublish(TOPIC_BOILER_DATA, data);
|
myESP.mqttPublish(TOPIC_BOILER_DATA, doc);
|
||||||
|
|
||||||
// see if the heating or hot tap water has changed, if so send
|
// 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
|
// 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
|
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)) {
|
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_TAPWATER_ACTIVE, EMS_Boiler.tapwaterActive == 1 ? "1" : "0");
|
||||||
myESP.mqttPublish(TOPIC_BOILER_HEATING_ACTIVE, EMS_Boiler.heatingActive == 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
|
last_boilerActive = ((EMS_Boiler.tapwaterActive << 1) + EMS_Boiler.heatingActive); // remember last state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle the thermostat values
|
// handle the thermostat values
|
||||||
void publishEMSValues_thermostat() {
|
void publishEMSValues_thermostat() {
|
||||||
char s[20] = {0}; // for formatting strings
|
StaticJsonDocument<MYESP_JSON_MAXSIZE_MEDIUM> doc;
|
||||||
StaticJsonDocument<MQTT_MAX_PAYLOAD_SIZE> doc;
|
JsonObject rootThermostat = doc.to<JsonObject>();
|
||||||
char data[MQTT_MAX_PAYLOAD_SIZE] = {0};
|
JsonObject dataThermostat;
|
||||||
JsonObject rootThermostat = doc.to<JsonObject>();
|
|
||||||
|
bool has_data = false;
|
||||||
|
|
||||||
for (uint8_t hc_v = 1; hc_v <= EMS_THERMOSTAT_MAXHC; hc_v++) {
|
for (uint8_t hc_v = 1; hc_v <= EMS_THERMOSTAT_MAXHC; hc_v++) {
|
||||||
_EMS_Thermostat_HC * thermostat = &EMS_Thermostat.hc[hc_v - 1];
|
_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
|
// 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)) {
|
if ((thermostat->active) && (thermostat->setpoint_roomTemp > EMS_VALUE_SHORT_NOTSET)) {
|
||||||
// build new json object
|
uint8_t model = ems_getThermostatModel(); // fetch model flags
|
||||||
char hc[10]; // hc{1-4}
|
has_data = true;
|
||||||
strlcpy(hc, THERMOSTAT_HC, sizeof(hc));
|
|
||||||
strlcat(hc, _int_to_char(s, thermostat->hc), sizeof(hc));
|
if (myESP.mqttUseNestedJson()) {
|
||||||
JsonObject dataThermostat = rootThermostat.createNestedObject(hc);
|
// create nested json for each HC
|
||||||
uint8_t model = ems_getThermostatModel();
|
char hc[10]; // hc{1-4}
|
||||||
|
strlcpy(hc, THERMOSTAT_HC, sizeof(hc));
|
||||||
|
char s[20]; // for formatting strings
|
||||||
|
strlcat(hc, _int_to_char(s, thermostat->hc), sizeof(hc));
|
||||||
|
dataThermostat = rootThermostat.createNestedObject(hc);
|
||||||
|
} else {
|
||||||
|
dataThermostat = rootThermostat;
|
||||||
|
}
|
||||||
|
|
||||||
// different logic depending on thermostat types
|
// different logic depending on thermostat types
|
||||||
if (model == EMS_DEVICE_FLAG_EASY) {
|
if (model == EMS_DEVICE_FLAG_EASY) {
|
||||||
@@ -808,26 +835,46 @@ void publishEMSValues_thermostat() {
|
|||||||
} else if (thermoMode == EMS_THERMOSTAT_MODE_NIGHT) {
|
} else if (thermoMode == EMS_THERMOSTAT_MODE_NIGHT) {
|
||||||
dataThermostat[THERMOSTAT_MODE] = "night";
|
dataThermostat[THERMOSTAT_MODE] = "night";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// if its not nested, send immediately
|
||||||
|
if (!myESP.mqttUseNestedJson()) {
|
||||||
|
char topic[30];
|
||||||
|
char s[20]; // for formatting strings
|
||||||
|
strlcpy(topic, TOPIC_THERMOSTAT_DATA, sizeof(topic));
|
||||||
|
strlcat(topic, _int_to_char(s, thermostat->hc), sizeof(topic)); // append hc to topic
|
||||||
|
char data[MYESP_JSON_MAXSIZE_MEDIUM];
|
||||||
|
serializeJson(doc, data);
|
||||||
|
myESP.mqttPublish(topic, data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
serializeJson(doc, data, sizeof(data));
|
// if we're using nested json, send all in one go
|
||||||
myDebugLog("Publishing thermostat data via MQTT");
|
if (myESP.mqttUseNestedJson() && has_data) {
|
||||||
myESP.mqttPublish(TOPIC_THERMOSTAT_DATA, data);
|
char data[MYESP_JSON_MAXSIZE_MEDIUM];
|
||||||
|
serializeJson(doc, data);
|
||||||
|
myESP.mqttPublish(TOPIC_THERMOSTAT_DATA, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_data) {
|
||||||
|
myDebugLog("Publishing thermostat data via MQTT");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// publish mixing data
|
// publish mixing data
|
||||||
|
// only sending if we have an active hc
|
||||||
void publishEMSValues_mixing() {
|
void publishEMSValues_mixing() {
|
||||||
char s[20] = {0}; // for formatting strings
|
char s[20]; // for formatting strings
|
||||||
StaticJsonDocument<MQTT_MAX_PAYLOAD_SIZE> doc;
|
StaticJsonDocument<MYESP_JSON_MAXSIZE_MEDIUM> doc;
|
||||||
char data[MQTT_MAX_PAYLOAD_SIZE] = {0};
|
JsonObject rootMixing = doc.to<JsonObject>();
|
||||||
JsonObject rootMixing = doc.to<JsonObject>();
|
bool has_data = false;
|
||||||
|
|
||||||
for (uint8_t hc_v = 1; hc_v <= EMS_MIXING_MAXHC; hc_v++) {
|
for (uint8_t hc_v = 1; hc_v <= EMS_MIXING_MAXHC; hc_v++) {
|
||||||
_EMS_MixingModule_HC * mixingHC = &EMS_MixingModule.hc[hc_v - 1];
|
_EMS_MixingModule_HC * mixingHC = &EMS_MixingModule.hc[hc_v - 1];
|
||||||
|
|
||||||
// only send if we have an active Heating Circuit with real data
|
|
||||||
if (mixingHC->active) {
|
if (mixingHC->active) {
|
||||||
|
has_data = true;
|
||||||
char hc[10]; // hc{1-4}
|
char hc[10]; // hc{1-4}
|
||||||
strlcpy(hc, MIXING_HC, sizeof(hc));
|
strlcpy(hc, MIXING_HC, sizeof(hc));
|
||||||
strlcat(hc, _int_to_char(s, mixingHC->hc), sizeof(hc));
|
strlcat(hc, _int_to_char(s, mixingHC->hc), sizeof(hc));
|
||||||
@@ -845,8 +892,9 @@ void publishEMSValues_mixing() {
|
|||||||
|
|
||||||
for (uint8_t wwc_v = 1; wwc_v <= EMS_MIXING_MAXWWC; wwc_v++) {
|
for (uint8_t wwc_v = 1; wwc_v <= EMS_MIXING_MAXWWC; wwc_v++) {
|
||||||
_EMS_MixingModule_WWC * mixingWWC = &EMS_MixingModule.wwc[wwc_v - 1];
|
_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) {
|
if (mixingWWC->active) {
|
||||||
|
has_data = true;
|
||||||
char wwc[10]; // wwc{1-2}
|
char wwc[10]; // wwc{1-2}
|
||||||
strlcpy(wwc, MIXING_WWC, sizeof(wwc));
|
strlcpy(wwc, MIXING_WWC, sizeof(wwc));
|
||||||
strlcat(wwc, _int_to_char(s, mixingWWC->wwc), sizeof(wwc));
|
strlcat(wwc, _int_to_char(s, mixingWWC->wwc), sizeof(wwc));
|
||||||
@@ -860,72 +908,69 @@ void publishEMSValues_mixing() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
serializeJson(doc, data, sizeof(data));
|
if (has_data) {
|
||||||
myDebugLog("Publishing mixing data via MQTT");
|
myDebugLog("Publishing mixing data via MQTT");
|
||||||
myESP.mqttPublish(TOPIC_MIXING_DATA, data);
|
myESP.mqttPublish(TOPIC_MIXING_DATA, doc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For SM10 and SM100/SM200 Solar Modules
|
// For SM10 and SM100/SM200 Solar Modules
|
||||||
void publishEMSValues_solar() {
|
void publishEMSValues_solar() {
|
||||||
StaticJsonDocument<MQTT_MAX_PAYLOAD_SIZE> doc;
|
StaticJsonDocument<MYESP_JSON_MAXSIZE_SMALL> doc;
|
||||||
char data[MQTT_MAX_PAYLOAD_SIZE] = {0};
|
JsonObject rootSM = doc.to<JsonObject>();
|
||||||
JsonObject rootSM = doc.to<JsonObject>();
|
|
||||||
|
|
||||||
if (EMS_SolarModule.collectorTemp > EMS_VALUE_SHORT_NOTSET)
|
if (EMS_SolarModule.collectorTemp > EMS_VALUE_SHORT_NOTSET) {
|
||||||
rootSM[SM_COLLECTORTEMP] = (float)EMS_SolarModule.collectorTemp / 10;
|
rootSM[SM_COLLECTORTEMP] = (float)EMS_SolarModule.collectorTemp / 10;
|
||||||
|
}
|
||||||
if (EMS_SolarModule.bottomTemp > EMS_VALUE_SHORT_NOTSET)
|
if (EMS_SolarModule.bottomTemp > EMS_VALUE_SHORT_NOTSET) {
|
||||||
rootSM[SM_BOTTOMTEMP] = (float)EMS_SolarModule.bottomTemp / 10;
|
rootSM[SM_BOTTOMTEMP] = (float)EMS_SolarModule.bottomTemp / 10;
|
||||||
|
}
|
||||||
if (EMS_SolarModule.pumpModulation != EMS_VALUE_INT_NOTSET)
|
if (EMS_SolarModule.pumpModulation != EMS_VALUE_INT_NOTSET) {
|
||||||
rootSM[SM_PUMPMODULATION] = EMS_SolarModule.pumpModulation;
|
rootSM[SM_PUMPMODULATION] = EMS_SolarModule.pumpModulation;
|
||||||
|
}
|
||||||
if (EMS_SolarModule.pump != EMS_VALUE_BOOL_NOTSET) {
|
if (EMS_SolarModule.pump != EMS_VALUE_BOOL_NOTSET) {
|
||||||
char s[20] = {0}; // for formatting strings
|
char s[20];
|
||||||
rootSM[SM_PUMP] = _bool_to_char(s, EMS_SolarModule.pump);
|
rootSM[SM_PUMP] = _bool_to_char(s, EMS_SolarModule.pump);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EMS_SolarModule.pumpWorkMin != EMS_VALUE_LONG_NOTSET) {
|
if (EMS_SolarModule.pumpWorkMin != EMS_VALUE_LONG_NOTSET) {
|
||||||
rootSM[SM_PUMPWORKMIN] = (float)EMS_SolarModule.pumpWorkMin;
|
rootSM[SM_PUMPWORKMIN] = (float)EMS_SolarModule.pumpWorkMin;
|
||||||
}
|
}
|
||||||
|
if (EMS_SolarModule.EnergyLastHour < EMS_VALUE_USHORT_NOTSET) {
|
||||||
if (EMS_SolarModule.EnergyLastHour < EMS_VALUE_USHORT_NOTSET)
|
|
||||||
rootSM[SM_ENERGYLASTHOUR] = (float)EMS_SolarModule.EnergyLastHour / 10;
|
rootSM[SM_ENERGYLASTHOUR] = (float)EMS_SolarModule.EnergyLastHour / 10;
|
||||||
|
}
|
||||||
if (EMS_SolarModule.EnergyToday < EMS_VALUE_USHORT_NOTSET)
|
if (EMS_SolarModule.EnergyToday < EMS_VALUE_USHORT_NOTSET) {
|
||||||
rootSM[SM_ENERGYTODAY] = EMS_SolarModule.EnergyToday;
|
rootSM[SM_ENERGYTODAY] = EMS_SolarModule.EnergyToday;
|
||||||
|
}
|
||||||
if (EMS_SolarModule.EnergyTotal < EMS_VALUE_USHORT_NOTSET)
|
if (EMS_SolarModule.EnergyTotal < EMS_VALUE_USHORT_NOTSET) {
|
||||||
rootSM[SM_ENERGYTOTAL] = (float)EMS_SolarModule.EnergyTotal / 10;
|
rootSM[SM_ENERGYTOTAL] = (float)EMS_SolarModule.EnergyTotal / 10;
|
||||||
|
}
|
||||||
|
|
||||||
serializeJson(doc, data, sizeof(data));
|
myDebugLog("Publishing solar module data via MQTT");
|
||||||
myDebugLog("Publishing SM data via MQTT");
|
myESP.mqttPublish(TOPIC_SM_DATA, doc);
|
||||||
myESP.mqttPublish(TOPIC_SM_DATA, data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle HeatPump
|
// handle HeatPump
|
||||||
void publishEMSValues_heatpump() {
|
void publishEMSValues_heatpump() {
|
||||||
StaticJsonDocument<MQTT_MAX_PAYLOAD_SIZE> doc;
|
StaticJsonDocument<MYESP_JSON_MAXSIZE_SMALL> doc;
|
||||||
char data[MQTT_MAX_PAYLOAD_SIZE] = {0};
|
JsonObject rootHP = doc.to<JsonObject>();
|
||||||
JsonObject rootHP = doc.to<JsonObject>();
|
|
||||||
|
|
||||||
if (EMS_HeatPump.HPModulation != EMS_VALUE_INT_NOTSET)
|
if (EMS_HeatPump.HPModulation != EMS_VALUE_INT_NOTSET) {
|
||||||
rootHP[HP_PUMPMODULATION] = EMS_HeatPump.HPModulation;
|
rootHP[HP_PUMPMODULATION] = EMS_HeatPump.HPModulation;
|
||||||
|
}
|
||||||
if (EMS_HeatPump.HPSpeed != EMS_VALUE_INT_NOTSET)
|
if (EMS_HeatPump.HPSpeed != EMS_VALUE_INT_NOTSET) {
|
||||||
rootHP[HP_PUMPSPEED] = EMS_HeatPump.HPSpeed;
|
rootHP[HP_PUMPSPEED] = EMS_HeatPump.HPSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
serializeJson(doc, data, sizeof(data));
|
myDebugLog("Publishing peat pump data via MQTT");
|
||||||
myDebugLog("Publishing HeatPump data via MQTT");
|
myESP.mqttPublish(TOPIC_HP_DATA, doc);
|
||||||
myESP.mqttPublish(TOPIC_HP_DATA, data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Publish shower data
|
// Publish shower data
|
||||||
void do_publishShowerData() {
|
void do_publishShowerData() {
|
||||||
StaticJsonDocument<MQTT_MAX_PAYLOAD_SIZE_SMALL> doc;
|
StaticJsonDocument<MYESP_JSON_MAXSIZE_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};
|
||||||
@@ -938,13 +983,8 @@ void do_publishShowerData() {
|
|||||||
rootShower[TOPIC_SHOWER_DURATION] = s;
|
rootShower[TOPIC_SHOWER_DURATION] = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
char data[300] = {0};
|
|
||||||
serializeJson(doc, data, sizeof(data));
|
|
||||||
|
|
||||||
myDebugLog("Publishing shower data via MQTT");
|
myDebugLog("Publishing shower data via MQTT");
|
||||||
|
myESP.mqttPublish(TOPIC_SHOWER_DATA, doc, false); // Publish MQTT forcing retain to be off
|
||||||
// Publish MQTT forcing retain to be off
|
|
||||||
myESP.mqttPublish(TOPIC_SHOWER_DATA, data, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// send values via MQTT
|
// send values via MQTT
|
||||||
@@ -955,16 +995,18 @@ void publishEMSValues(bool force) {
|
|||||||
return;
|
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)) {
|
if (ems_getThermostatEnabled() && (ems_Device_has_flags(EMS_DEVICE_UPDATE_FLAG_THERMOSTAT) || force)) {
|
||||||
publishEMSValues_thermostat();
|
publishEMSValues_thermostat();
|
||||||
ems_Device_remove_flags(EMS_DEVICE_UPDATE_FLAG_THERMOSTAT); // unset flag
|
ems_Device_remove_flags(EMS_DEVICE_UPDATE_FLAG_THERMOSTAT); // unset flag
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return; // XXX
|
||||||
|
|
||||||
|
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_getMixingModuleEnabled() && (ems_Device_has_flags(EMS_DEVICE_UPDATE_FLAG_MIXING) || force)) {
|
if (ems_getMixingModuleEnabled() && (ems_Device_has_flags(EMS_DEVICE_UPDATE_FLAG_MIXING) || force)) {
|
||||||
publishEMSValues_mixing();
|
publishEMSValues_mixing();
|
||||||
ems_Device_remove_flags(EMS_DEVICE_UPDATE_FLAG_MIXING); // unset flag
|
ems_Device_remove_flags(EMS_DEVICE_UPDATE_FLAG_MIXING); // unset flag
|
||||||
@@ -1073,8 +1115,6 @@ bool LoadSaveCallback(MYESP_FSACTION_t action, JsonObject settings) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// serializeJsonPretty(settings, Serial); // for debugging
|
|
||||||
|
|
||||||
EMSESP_Settings.led = settings["led"];
|
EMSESP_Settings.led = settings["led"];
|
||||||
EMSESP_Settings.led_gpio = settings["led_gpio"] | EMSESP_LED_GPIO;
|
EMSESP_Settings.led_gpio = settings["led_gpio"] | EMSESP_LED_GPIO;
|
||||||
EMSESP_Settings.dallas_gpio = settings["dallas_gpio"] | EMSESP_DALLAS_GPIO;
|
EMSESP_Settings.dallas_gpio = settings["dallas_gpio"] | EMSESP_DALLAS_GPIO;
|
||||||
@@ -1372,7 +1412,7 @@ void saveEMSDevices() {
|
|||||||
|
|
||||||
strlcpy(EMSESP_Settings.known_devices, s, sizeof(s));
|
strlcpy(EMSESP_Settings.known_devices, s, sizeof(s));
|
||||||
|
|
||||||
myDebug("The device IDs %s%s%swill be automatically scanned when EMS-ESP boots up.", COLOR_BOLD_ON, EMSESP_Settings.known_devices, COLOR_BOLD_OFF);
|
myDebug_P(PSTR("The device IDs %s%s%swill be automatically scanned when EMS-ESP boots up."), COLOR_BOLD_ON, EMSESP_Settings.known_devices, COLOR_BOLD_OFF);
|
||||||
myESP.saveSettings();
|
myESP.saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
#define APP_VERSION "1.9.5b39"
|
#define APP_VERSION "1.9.5b40"
|
||||||
|
|||||||
Reference in New Issue
Block a user