added mqtt log

This commit is contained in:
Paul
2019-08-16 21:49:52 +02:00
parent e12fa66462
commit ae766b09e1
11 changed files with 398 additions and 144 deletions

View File

@@ -22,7 +22,6 @@ union system_rtcmem_t {
uint32_t value; uint32_t value;
}; };
// nasty global variables that are called from internal ws functions // nasty global variables that are called from internal ws functions
static char * _general_password = nullptr; static char * _general_password = nullptr;
static bool _shouldRestart = false; static bool _shouldRestart = false;
@@ -103,6 +102,13 @@ MyESP::MyESP() {
// get the build time // get the build time
_buildTime = _getBuildTime(); _buildTime = _getBuildTime();
// MQTT log
for (uint8_t i = 0; i < MYESP_MQTTLOG_MAX; i++) {
MQTT_log[i].timestamp = 0;
MQTT_log[i].topic = nullptr;
MQTT_log[i].payload = nullptr;
}
} }
MyESP::~MyESP() { MyESP::~MyESP() {
@@ -190,12 +196,6 @@ uint32_t MyESP::_getInitialFreeHeap() {
return _heap; return _heap;
} }
// used heap mem
// note calls to getFreeHeap sometimes causes some ESPs to crash
uint32_t MyESP::_getUsedHeap() {
return _getInitialFreeHeap() - ESP.getFreeHeap();
}
// called when WiFi is connected, and used to start OTA, MQTT // called when WiFi is connected, and used to start OTA, MQTT
void MyESP::_wifiCallback(justwifi_messages_t code, char * parameter) { void MyESP::_wifiCallback(justwifi_messages_t code, char * parameter) {
if ((code == MESSAGE_CONNECTED)) { if ((code == MESSAGE_CONNECTED)) {
@@ -370,6 +370,8 @@ void MyESP::mqttUnsubscribe(const char * topic) {
void MyESP::mqttPublish(const char * topic, const char * payload) { void MyESP::mqttPublish(const char * topic, const char * payload) {
// myDebug_P(PSTR("[MQTT] Sending pubish to %s with payload %s"), _mqttTopic(topic), payload); // for debugging // myDebug_P(PSTR("[MQTT] Sending pubish to %s with payload %s"), _mqttTopic(topic), payload); // for debugging
mqttClient.publish(_mqttTopic(topic), _mqtt_qos, _mqtt_retain, payload); mqttClient.publish(_mqttTopic(topic), _mqtt_qos, _mqtt_retain, payload);
_addMQTTLog(topic, payload); // add to the log
} }
// MQTT onConnect - when a connect is established // MQTT onConnect - when a connect is established
@@ -380,7 +382,7 @@ void MyESP::_mqttOnConnect() {
_mqtt_last_connection = millis(); _mqtt_last_connection = millis();
// say we're alive to the Last Will topic // say we're alive to the Last Will topic
mqttClient.publish(_mqttTopic(_mqtt_will_topic), 1, true, _mqtt_will_online_payload); mqttClient.publish(_mqttTopic(_mqtt_will_topic), 1, true, _mqtt_will_online_payload); // qos=1, retain=true
// subscribe to general subs // subscribe to general subs
mqttSubscribe(MQTT_TOPIC_RESTART); mqttSubscribe(MQTT_TOPIC_RESTART);
@@ -389,6 +391,9 @@ void MyESP::_mqttOnConnect() {
mqttSubscribe(MQTT_TOPIC_START); mqttSubscribe(MQTT_TOPIC_START);
mqttPublish(MQTT_TOPIC_START, MQTT_TOPIC_START_PAYLOAD); mqttPublish(MQTT_TOPIC_START, MQTT_TOPIC_START_PAYLOAD);
// send heartbeat if enabled
_heartbeatCheck(true);
// call custom function to handle mqtt receives // call custom function to handle mqtt receives
(_mqtt_callback_f)(MQTT_CONNECT_EVENT, nullptr, nullptr); (_mqtt_callback_f)(MQTT_CONNECT_EVENT, nullptr, nullptr);
} }
@@ -604,7 +609,7 @@ void MyESP::_consoleShowHelp() {
myDebug_P(PSTR("*")); myDebug_P(PSTR("*"));
myDebug_P(PSTR("* Commands:")); myDebug_P(PSTR("* Commands:"));
myDebug_P(PSTR("* ?=help, CTRL-D/quit=exit telnet session")); myDebug_P(PSTR("* ?=help, CTRL-D/quit=exit telnet session"));
myDebug_P(PSTR("* set, system, restart")); myDebug_P(PSTR("* set, system, restart, mqttlog"));
#ifdef CRASH #ifdef CRASH
myDebug_P(PSTR("* crash <dump | clear | test [n]>")); myDebug_P(PSTR("* crash <dump | clear | test [n]>"));
#endif #endif
@@ -944,6 +949,13 @@ void MyESP::_telnetCommand(char * commandLine) {
// restart command // restart command
if ((strcmp(ptrToCommandName, "restart") == 0) && (wc == 1)) { if ((strcmp(ptrToCommandName, "restart") == 0) && (wc == 1)) {
resetESP(); resetESP();
return;
}
// print mqtt log command
if ((strcmp(ptrToCommandName, "mqttlog") == 0) && (wc == 1)) {
_printMQTTLog();
return;
} }
// show system stats // show system stats
@@ -1108,7 +1120,7 @@ bool MyESP::_rtcmemStatus() {
if (reason == REASON_EXT_SYS_RST) { // external system reset if (reason == REASON_EXT_SYS_RST) { // external system reset
if (getSystemBootStatus() == MYESP_BOOTSTATUS_BOOTING) { if (getSystemBootStatus() == MYESP_BOOTSTATUS_BOOTING) {
_setSystemBootStatus(MYESP_BOOTSTATUS_RESETNEEDED); _setSystemBootStatus(MYESP_BOOTSTATUS_RESETNEEDED);
// _formatreq = true; // do a wipe next in the loop() TODO commented out for now // _formatreq = true; // do a wipe next in the loop() - commented out for now because we use the web
} else { } else {
_setSystemBootStatus(MYESP_BOOTSTATUS_POWERON); _setSystemBootStatus(MYESP_BOOTSTATUS_POWERON);
} }
@@ -1199,7 +1211,6 @@ void MyESP::_systemCheckLoop() {
} }
} }
// print out ESP system stats // print out ESP system stats
// for battery power is ESP.getVcc() // for battery power is ESP.getVcc()
void MyESP::showSystemStats() { void MyESP::showSystemStats() {
@@ -1340,6 +1351,8 @@ void MyESP::_heartbeatCheck(bool force = false) {
if ((millis() - last_heartbeat > MYESP_HEARTBEAT_INTERVAL) || force) { if ((millis() - last_heartbeat > MYESP_HEARTBEAT_INTERVAL) || force) {
last_heartbeat = millis(); last_heartbeat = millis();
// _printHeap("Heartbeat"); // for heartbeat debugging
if (!isMQTTConnected() || !(_mqtt_heartbeat)) { if (!isMQTTConnected() || !(_mqtt_heartbeat)) {
return; return;
} }
@@ -1819,7 +1832,7 @@ bool MyESP::_fs_createCustomConfig() {
// if it doesn't exist try and create it // if it doesn't exist try and create it
void MyESP::_fs_setup() { void MyESP::_fs_setup() {
if (!SPIFFS.begin()) { if (!SPIFFS.begin()) {
Serial.print(F("[WARN] Formatting filesystem...")); myDebug_P(PSTR("[FS] Formatting filesystem..."));
if (SPIFFS.format()) { if (SPIFFS.format()) {
_writeEvent("WARN", "sys", "File system formatted", ""); _writeEvent("WARN", "sys", "File system formatted", "");
} else { } else {
@@ -2108,7 +2121,7 @@ void MyESP::_writeEvent(const char * type, const char * src, const char * desc,
return; return;
} }
StaticJsonDocument<300> root; StaticJsonDocument<MYESP_JSON_LOG_MAXSIZE> root;
root["type"] = type; root["type"] = type;
root["src"] = src; root["src"] = src;
root["desc"] = desc; root["desc"] = desc;
@@ -2132,9 +2145,16 @@ void MyESP::_sendEventLog(uint8_t page) {
if (!eventlog) { if (!eventlog) {
eventlog.close(); eventlog.close();
myDebug_P(PSTR("[WEB] Event log is missing")); myDebug_P(PSTR("[WEB] Event log is missing"));
if (_ota_post_callback_f) {
(_ota_post_callback_f)(); // call custom function
}
return; // file can't be opened return; // file can't be opened
} }
if (_ota_pre_callback_f) {
(_ota_pre_callback_f)(); // call custom function
}
// the size of the json will be quite big so best not to use stack (StaticJsonDocument) // the size of the json will be quite big so best not to use stack (StaticJsonDocument)
DynamicJsonDocument doc(MYESP_JSON_MAXSIZE); DynamicJsonDocument doc(MYESP_JSON_MAXSIZE);
JsonObject root = doc.to<JsonObject>(); JsonObject root = doc.to<JsonObject>();
@@ -2143,31 +2163,67 @@ void MyESP::_sendEventLog(uint8_t page) {
JsonArray list = doc.createNestedArray("list"); JsonArray list = doc.createNestedArray("list");
uint8_t first = (page - 1) * 10; uint8_t first = ((page - 1) * 10) + 1;
uint8_t last = page * 10; uint8_t last = page * 10;
uint8_t i = 0; uint8_t char_count = 0;
uint8_t line_count = 0;
uint16_t read_count = 0;
bool abort = false;
char char_buffer[MYESP_JSON_LOG_MAXSIZE];
while (eventlog.available()) { // if at start, start immediately recording
String item = String(); bool record = (first == 1) ? true : false;
item = eventlog.readStringUntil('\n');
if (i >= first && i < last) { // start at top and read until we find the page we want (sets of 10)
list.add(item); while (eventlog.available() && !abort) {
char c = eventlog.read();
// see if we've overrun, which means corrupt so ignore rest
if (read_count++ > MYESP_JSON_LOG_MAXSIZE - 1) {
abort = true;
} }
i++;
}
eventlog.close();
float pages = i / 10.0; // see if we have reached the end of the string
if (c == '\0' || c == '\n') {
line_count++;
// save line
if (record) {
char_buffer[char_count] = '\0';
list.add(char_buffer);
}
char_count = 0;
read_count = 0;
if (line_count == first - 1) { // have we come to the start position, start recording
record = true;
} else if (line_count == last) { // finish recording and exit loop
record = false;
}
} else {
// add the char to the buffer if recording
if (record && (char_count < MYESP_JSON_LOG_MAXSIZE)) {
char_buffer[char_count++] = c;
}
}
}
eventlog.close(); // close SPIFFS
float pages = line_count / 10.0;
root["haspages"] = ceil(pages); root["haspages"] = ceil(pages);
char buffer[MYESP_JSON_MAXSIZE]; char buffer[MYESP_JSON_MAXSIZE];
size_t len = serializeJson(root, buffer); size_t len = serializeJson(root, buffer);
//Serial.printf("\nEVENTLOG: page %d\n", page); // turn on for debugging //Serial.printf("\nEVENTLOG: page %d\n", page); // turn on for debugging XXX
//serializeJson(root, Serial); // turn on for debugging //serializeJson(root, Serial); // turn on for debugging
_ws->textAll(buffer, len); _ws->textAll(buffer, len);
_ws->textAll("{\"command\":\"result\",\"resultof\":\"eventlist\",\"result\": true}"); _ws->textAll("{\"command\":\"result\",\"resultof\":\"eventlist\",\"result\": true}");
if (_ota_post_callback_f) {
(_ota_post_callback_f)(); // call custom function
}
} }
// Handles WebSocket Events // Handles WebSocket Events
@@ -2334,22 +2390,27 @@ void MyESP::_sendCustomStatus() {
// send system status via ws // send system status via ws
void MyESP::_sendStatus() { void MyESP::_sendStatus() {
StaticJsonDocument<400> doc; // capture memory before we stick in a huge json buffer on the heap!
JsonObject root = doc.to<JsonObject>(); uint32_t total_memory = _getInitialFreeHeap();
uint32_t free_memory = ESP.getFreeHeap();
DynamicJsonDocument doc(MQTT_MAX_PAYLOAD_SIZE_LARGE);
JsonObject root = doc.to<JsonObject>();
root["command"] = "status";
FSInfo fsinfo; FSInfo fsinfo;
if (!SPIFFS.info(fsinfo)) { if (!SPIFFS.info(fsinfo)) {
myDebug("[SYSTEM] Error getting info on SPIFFS"); myDebug("[SYSTEM] Error getting info on SPIFFS");
} else {
root["availspiffs"] = (fsinfo.totalBytes - fsinfo.usedBytes) / 1000;
root["spiffssize"] = (fsinfo.totalBytes / 1000);
} }
root["command"] = "status";
// all sizes in bytes converted to KB // all sizes in bytes converted to KB
root["heap"] = ESP.getFreeHeap() / 1000; root["initheap"] = total_memory;
root["sketchsize"] = ESP.getSketchSize() / 1000; root["heap"] = free_memory;
root["availsize"] = ESP.getFreeSketchSpace() / 1000; root["sketchsize"] = ESP.getSketchSize() / 1000;
root["availspiffs"] = (fsinfo.totalBytes - fsinfo.usedBytes) / 1000; root["availsize"] = ESP.getFreeSketchSpace() / 1000;
root["spiffssize"] = (fsinfo.totalBytes / 1000);
if (isAPmode()) { if (isAPmode()) {
root["ip"] = WiFi.softAPIP().toString(); root["ip"] = WiFi.softAPIP().toString();
@@ -2377,8 +2438,32 @@ 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[400]; char topic_s[MQTT_MAX_TOPIC_SIZE] = {0};
if (_hasValue(_mqtt_base)) {
strlcpy(topic_s, _mqtt_base, sizeof(topic_s));
strlcat(topic_s, "/", sizeof(topic_s));
strlcat(topic_s, _general_hostname, sizeof(topic_s));
} else {
strlcpy(topic_s, _general_hostname, sizeof(topic_s));
}
strlcat(topic_s, "/", sizeof(topic_s));
root["mqttloghdr"] = topic_s;
// create MQTT log
JsonArray list = root.createNestedArray("mqttlog");
for (uint8_t i = 0; i < MYESP_MQTTLOG_MAX; i++) {
if (MQTT_log[i].topic != nullptr) {
JsonObject item = list.createNestedObject();
item["topic"] = MQTT_log[i].topic;
item["payload"] = MQTT_log[i].payload;
item["time"] = MQTT_log[i].timestamp;
}
}
char buffer[MQTT_MAX_PAYLOAD_SIZE_LARGE];
size_t len = serializeJson(root, buffer); size_t len = serializeJson(root, buffer);
_ws->textAll(buffer, len); _ws->textAll(buffer, len);
} }
@@ -2525,6 +2610,72 @@ void MyESP::_webserver_setup() {
myDebug_P(PSTR("[WEB] Web server started")); myDebug_P(PSTR("[WEB] Web server started"));
} }
// print memory
void MyESP::_printHeap(const char * s) {
uint32_t total_memory = _getInitialFreeHeap();
uint32_t free_memory = ESP.getFreeHeap();
myDebug(" [%s] Free Heap: %d bytes initially | %d bytes used (%2u%%) | %d bytes free (%2u%%)",
s,
total_memory,
total_memory - free_memory,
100 * (total_memory - free_memory) / total_memory,
free_memory,
100 * free_memory / total_memory);
}
// print MQTT log - everything that was published last per topic
void MyESP::_printMQTTLog() {
myDebug_P(PSTR("MQTT publish log:"));
for (uint8_t i = 0; i < MYESP_MQTTLOG_MAX; i++) {
if (MQTT_log[i].topic != nullptr) {
myDebug_P(PSTR("(%d) [%lu] Topic:%s Payload:%s"), i, MQTT_log[i].timestamp, MQTT_log[i].topic, MQTT_log[i].payload);
}
}
myDebug_P(PSTR("")); // newline
}
// add an MQTT log entry
void MyESP::_addMQTTLog(const char * topic, const char * payload) {
static uint8_t logCount = 0;
uint8_t logPointer = 0;
bool found = false;
// myDebug("Publish [#%d] %s (%d) %s (%d)", logCount, topic, strlen(topic), payload, strlen(payload)); // for debugging
// find the topic
while ((_hasValue(MQTT_log[logPointer].topic) && logPointer < MYESP_MQTTLOG_MAX)) {
if (strcmp(MQTT_log[logPointer].topic, topic) == 0) {
found = true;
break;
}
logPointer++;
}
// if not found add it and increment next free space pointer
if (!found) {
logPointer = logCount;
if (++logCount == MYESP_MQTTLOG_MAX) {
logCount = 0; // rotate
}
}
// delete old record
if (MQTT_log[logPointer].topic) {
free(MQTT_log[logPointer].topic);
}
if (MQTT_log[logPointer].payload) {
free(MQTT_log[logPointer].payload);
}
// add new record
MQTT_log[logPointer].topic = strdup(topic);
MQTT_log[logPointer].payload = strdup(payload);
MQTT_log[logPointer].timestamp = now();
}
// send UTC time via ws // send UTC time via ws
void MyESP::_sendTime() { void MyESP::_sendTime() {
@@ -2594,6 +2745,10 @@ void MyESP::begin(const char * app_hostname, const char * app_name, const char *
_telnet_setup(); // Telnet setup, called first to set Serial _telnet_setup(); // Telnet setup, called first to set Serial
// _fs_printFile(MYESP_CONFIG_FILE); // for debugging
//_fs_printFile(MYESP_CUSTOMCONFIG_FILE); // for debugging
//_fs_printFile(MYESP_EVENTLOG_FILE); // for debugging
// print a welcome message // print a welcome message
myDebug_P(PSTR("\n\n* %s version %s"), _app_name, _app_version); myDebug_P(PSTR("\n\n* %s version %s"), _app_name, _app_version);
@@ -2613,10 +2768,6 @@ void MyESP::begin(const char * app_hostname, const char * app_name, const char *
_heartbeatCheck(true); // force heartbeat _heartbeatCheck(true); // force heartbeat
SerialAndTelnet.flush(); SerialAndTelnet.flush();
//_fs_printFile(MYESP_CONFIG_FILE); // for debugging
//_fs_printFile(MYESP_CUSTOMCONFIG_FILE); // for debugging
//_fs_printFile(MYESP_EVENTLOG_FILE); // for debugging
} }
/* /*
@@ -2643,7 +2794,7 @@ void MyESP::loop() {
} }
if (_formatreq) { if (_formatreq) {
myDebug("[SYSTEM] Factory reset initiated"); myDebug("[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();

View File

@@ -72,7 +72,6 @@ extern struct rst_info resetInfo;
#define MQTT_RECONNECT_DELAY_MIN 2000 // Try to reconnect in 3 seconds upon disconnection #define MQTT_RECONNECT_DELAY_MIN 2000 // Try to reconnect in 3 seconds upon disconnection
#define MQTT_RECONNECT_DELAY_STEP 3000 // Increase the reconnect delay in 3 seconds after each failed attempt #define MQTT_RECONNECT_DELAY_STEP 3000 // Increase the reconnect delay in 3 seconds after each failed attempt
#define MQTT_RECONNECT_DELAY_MAX 120000 // Set reconnect time to 2 minutes at most #define MQTT_RECONNECT_DELAY_MAX 120000 // Set reconnect time to 2 minutes at most
#define MQTT_MAX_TOPIC_SIZE 50 // max length of MQTT topic
#define MQTT_TOPIC_START "start" #define MQTT_TOPIC_START "start"
#define MQTT_TOPIC_HEARTBEAT "heartbeat" #define MQTT_TOPIC_HEARTBEAT "heartbeat"
#define MQTT_TOPIC_START_PAYLOAD "start" #define MQTT_TOPIC_START_PAYLOAD "start"
@@ -82,7 +81,13 @@ extern struct rst_info resetInfo;
#define MQTT_RETAIN false #define MQTT_RETAIN false
#define MQTT_KEEPALIVE 60 // 1 minute #define MQTT_KEEPALIVE 60 // 1 minute
#define MQTT_QOS 1 #define MQTT_QOS 1
#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_PAYLOAD_SIZE 500 // 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 MYESP_JSON_MAXSIZE 2000 // for large Dynamic json files
#define MYESP_MQTTLOG_MAX 20 // max number of log entries for MQTT publishes
#define MYESP_JSON_LOG_MAXSIZE 300 // max size of an JSON log entry
// Internal MQTT events // Internal MQTT events
#define MQTT_CONNECT_EVENT 0 #define MQTT_CONNECT_EVENT 0
@@ -134,7 +139,6 @@ PROGMEM const char * const custom_reset_string[] = {custom_reset_hardware, cus
// SPIFFS // SPIFFS
#define MYESP_SPIFFS_MAXSIZE 800 // https://arduinojson.org/v6/assistant/ #define MYESP_SPIFFS_MAXSIZE 800 // https://arduinojson.org/v6/assistant/
#define MYESP_JSON_MAXSIZE 2000 // for large Dynamic json files
// CRASH // CRASH
/** /**
@@ -186,8 +190,8 @@ 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 minute)
#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 120000 // in milliseconds, how often the MQTT heartbeat is sent (2 mins)
typedef struct { typedef struct {
@@ -205,6 +209,13 @@ typedef enum {
MYESP_BOOTSTATUS_RESETNEEDED = 3 MYESP_BOOTSTATUS_RESETNEEDED = 3
} MYESP_BOOTSTATUS; // boot messages } MYESP_BOOTSTATUS; // boot messages
// for storing all MQTT publish messages
typedef struct {
char * topic;
char * payload;
time_t timestamp;
} _MQTT_Log;
typedef std::function<void(unsigned int, const char *, const char *)> mqtt_callback_f; typedef std::function<void(unsigned int, const char *, const char *)> mqtt_callback_f;
typedef std::function<void()> wifi_callback_f; typedef std::function<void()> wifi_callback_f;
typedef std::function<void()> ota_callback_f; typedef std::function<void()> ota_callback_f;
@@ -297,28 +308,34 @@ class MyESP {
private: private:
// mqtt // mqtt
AsyncMqttClient mqttClient; void _mqttOnMessage(char * topic, char * payload, size_t len);
unsigned long _mqtt_reconnect_delay; void _mqttConnect();
void _mqttOnMessage(char * topic, char * payload, size_t len); void _mqtt_setup();
void _mqttConnect(); void _mqttOnConnect();
void _mqtt_setup(); void _sendStart();
char * _mqttTopic(const char * topic);
// mqtt log
_MQTT_Log MQTT_log[MYESP_MQTTLOG_MAX]; // log for publish messages
void _printMQTTLog();
void _addMQTTLog(const char * topic, const char * payload);
AsyncMqttClient mqttClient; // the MQTT class
uint32_t _mqtt_reconnect_delay;
mqtt_callback_f _mqtt_callback_f; mqtt_callback_f _mqtt_callback_f;
void _mqttOnConnect();
void _sendStart();
char * _mqttTopic(const char * topic);
char * _mqtt_ip; char * _mqtt_ip;
char * _mqtt_user; char * _mqtt_user;
char * _mqtt_password; char * _mqtt_password;
int _mqtt_port; int _mqtt_port;
char * _mqtt_base; char * _mqtt_base;
bool _mqtt_enabled; bool _mqtt_enabled;
unsigned long _mqtt_keepalive; uint32_t _mqtt_keepalive;
unsigned char _mqtt_qos; uint8_t _mqtt_qos;
bool _mqtt_retain; bool _mqtt_retain;
char * _mqtt_will_topic; char * _mqtt_will_topic;
char * _mqtt_will_online_payload; char * _mqtt_will_online_payload;
char * _mqtt_will_offline_payload; char * _mqtt_will_offline_payload;
unsigned long _mqtt_last_connection; uint32_t _mqtt_last_connection;
bool _mqtt_connecting; bool _mqtt_connecting;
bool _mqtt_heartbeat; bool _mqtt_heartbeat;
@@ -383,6 +400,7 @@ class MyESP {
bool _timerequest; bool _timerequest;
bool _formatreq; bool _formatreq;
bool _hasValue(char * s); bool _hasValue(char * s);
void _printHeap(const char * s);
// reset reason and rtcmem // reset reason and rtcmem
bool _rtcmem_status; bool _rtcmem_status;

View File

@@ -9,7 +9,7 @@
<label class="col-xs-3">LED<i style="margin-left: 10px;" <label class="col-xs-3">LED<i style="margin-left: 10px;"
class="glyphicon glyphicon-exclamation-sign text-danger" aria-hidden="true" data-toggle="popover" class="glyphicon glyphicon-exclamation-sign text-danger" aria-hidden="true" data-toggle="popover"
data-trigger="hover" data-placement="right" data-trigger="hover" data-placement="right"
data-content="Please choose if you want to enable the LED"></i></label> data-content="Please choose if you want to enable an LED to show status"></i></label>
<div class="col-xs-9"> <div class="col-xs-9">
<form> <form>
<label class="radio-inline"> <label class="radio-inline">
@@ -148,19 +148,15 @@
<div id="custom_statuscontent"> <div id="custom_statuscontent">
<br> <br>
<div class="row text-center"> <div class="row text-left">
<div class="col-md-8 col-md-offset-2"> <div class="col-md-8 col-md-offset-2">
<h1>Dashboard</h1> <h2>EMS Dashboard</h2>
<p>Real-time values from the EMS-ESP device are shown here. <p>Real-time values from the EMS-ESP device are shown here.</p>
<div class="row form-group">
<button onclick="refreshEMS()" class="btn btn-primary">Refresh Data</button>
</div>
</p>
</div> </div>
<div class="col-md-8 col-md-offset-2"> <div class="col-md-8 col-md-offset-2">
<div class="panel panel-default table-responsive"> <div class="panel panel-default table-responsive">
<table class="table table-hover table-striped table-condensed"> <table class="table table-hover table-striped table-condensed">
<caption>EMS Bus stats</caption> <caption>EMS Bus Status</caption>
<tr> <tr>
<td colspan="2"> <td colspan="2">
<b> <b>
@@ -169,7 +165,7 @@
</td> </td>
</tr> </tr>
<tr> <tr>
<th>Detected Devices:</th> <th id="devicesshow">Discovered Devices:</th>
<td> <td>
<ul class="list-group"> <ul class="list-group">
<div id="devices"></div> <div id="devices"></div>
@@ -228,4 +224,7 @@
</div> </div>
</div> </div>
<div class="row form-group" style="text-align: center;">
<button onclick="refreshEMS()" class="btn btn-primary">Refresh Data</button>
</div>
</div> </div>

View File

@@ -82,6 +82,7 @@ function listCustomStats() {
document.getElementById("msg").className = "alert alert-success"; document.getElementById("msg").className = "alert alert-success";
} else { } else {
document.getElementById("msg").className = "alert alert-danger"; document.getElementById("msg").className = "alert alert-danger";
document.getElementById("devicesshow").style.display = "none";
document.getElementById("thermostat_show").style.display = "none"; document.getElementById("thermostat_show").style.display = "none";
document.getElementById("boiler_show").style.display = "none"; document.getElementById("boiler_show").style.display = "none";
return; return;
@@ -89,6 +90,9 @@ function listCustomStats() {
var list = document.getElementById("devices"); var list = document.getElementById("devices");
var obj = ajaxobj.emsbus.devices; var obj = ajaxobj.emsbus.devices;
document.getElementById("devicesshow").style.display = "block";
for (var i = 0; i < obj.length; i++) { for (var i = 0; i < obj.length; i++) {
var l = document.createElement("li"); var l = document.createElement("li");
var type = obj[i].type; var type = obj[i].type;

View File

@@ -67,8 +67,6 @@ Ticker showerColdShotStopTimer;
#define SHOWER_COLDSHOT_DURATION 10 // in seconds. 10 seconds for cold water before turning back hot water #define SHOWER_COLDSHOT_DURATION 10 // in seconds. 10 seconds for cold water before turning back hot water
#define SHOWER_MAX_DURATION 420000 // in ms. 7 minutes, before trigger a shot of cold water #define SHOWER_MAX_DURATION 420000 // in ms. 7 minutes, before trigger a shot of cold water
#define MQTT_MAX_SIZE 700 // max size of a JSON object. See https://arduinojson.org/v6/assistant/
typedef struct { typedef struct {
uint32_t timestamp; // for internal timings, via millis() uint32_t timestamp; // for internal timings, via millis()
uint8_t dallas_sensors; // count of dallas sensors uint8_t dallas_sensors; // count of dallas sensors
@@ -508,7 +506,7 @@ void showInfo() {
_renderIntValue("Burner current power", "%", EMS_Boiler.curBurnPow); _renderIntValue("Burner current power", "%", EMS_Boiler.curBurnPow);
_renderShortValue("Flame current", "uA", EMS_Boiler.flameCurr); _renderShortValue("Flame current", "uA", EMS_Boiler.flameCurr);
_renderIntValue("System pressure", "bar", EMS_Boiler.sysPress, 10); _renderIntValue("System pressure", "bar", EMS_Boiler.sysPress, 10);
if (EMS_Boiler.serviceCode == EMS_VALUE_SHORT_NOTSET) { if (EMS_Boiler.serviceCode == EMS_VALUE_USHORT_NOTSET) {
myDebug_P(PSTR(" System service code: %s"), EMS_Boiler.serviceCodeChar); myDebug_P(PSTR(" System service code: %s"), EMS_Boiler.serviceCodeChar);
} else { } else {
myDebug_P(PSTR(" System service code: %s (%d)"), EMS_Boiler.serviceCodeChar, EMS_Boiler.serviceCode); myDebug_P(PSTR(" System service code: %s (%d)"), EMS_Boiler.serviceCodeChar, EMS_Boiler.serviceCode);
@@ -688,16 +686,17 @@ void publishSensorValues() {
// CRC check is done to see if there are changes in the values since the last send to avoid too much wifi traffic // CRC check is done to see if there are changes in the values since the last send to avoid too much wifi traffic
// a check is done against the previous values and if there are changes only then they are published. Unless force=true // a check is done against the previous values and if there are changes only then they are published. Unless force=true
void publishValues(bool force) { void publishValues(bool force) {
// don't send if MQTT is connected // don't send if MQTT is not connected
if (!myESP.isMQTTConnected()) { if (!myESP.isMQTTConnected()) {
return; return;
} }
char s[20] = {0}; // for formatting strings char s[20] = {0}; // for formatting strings
StaticJsonDocument<MQTT_MAX_SIZE> doc; StaticJsonDocument<MQTT_MAX_PAYLOAD_SIZE> doc;
char data[MQTT_MAX_SIZE] = {0}; char data[MQTT_MAX_PAYLOAD_SIZE] = {0};
CRC32 crc; CRC32 crc;
uint32_t fchecksum; uint32_t fchecksum;
uint8_t jsonSize;
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
static uint32_t previousBoilerPublishCRC = 0; // CRC check for boiler values static uint32_t previousBoilerPublishCRC = 0; // CRC check for boiler values
@@ -769,22 +768,28 @@ void publishValues(bool force) {
if (abs(EMS_Boiler.heatWorkMin) != EMS_VALUE_LONG_NOTSET) if (abs(EMS_Boiler.heatWorkMin) != EMS_VALUE_LONG_NOTSET)
rootBoiler["heatWorkMin"] = (double)EMS_Boiler.heatWorkMin; rootBoiler["heatWorkMin"] = (double)EMS_Boiler.heatWorkMin;
rootBoiler["ServiceCode"] = EMS_Boiler.serviceCodeChar; if (EMS_Boiler.serviceCode != EMS_VALUE_USHORT_NOTSET) {
rootBoiler["ServiceCodeNumber"] = EMS_Boiler.serviceCode; rootBoiler["ServiceCode"] = EMS_Boiler.serviceCodeChar;
rootBoiler["ServiceCodeNumber"] = EMS_Boiler.serviceCode;
}
serializeJson(doc, data, sizeof(data)); serializeJson(doc, data, sizeof(data));
// calculate hash and send values if something has changed, to save unnecessary wifi traffic // check for empty json
for (size_t i = 0; i < measureJson(doc) - 1; i++) { jsonSize = measureJson(doc);
crc.update(data[i]); if (jsonSize > 2) {
} // calculate hash and send values if something has changed, to save unnecessary wifi traffic
fchecksum = crc.finalize(); for (uint8_t i = 0; i < (jsonSize - 1); i++) {
if ((previousBoilerPublishCRC != fchecksum) || force) { crc.update(data[i]);
previousBoilerPublishCRC = fchecksum; }
myDebugLog("Publishing boiler data via MQTT"); fchecksum = crc.finalize();
if ((previousBoilerPublishCRC != fchecksum) || force) {
previousBoilerPublishCRC = fchecksum;
myDebugLog("Publishing boiler data via MQTT");
// send values via MQTT // send values via MQTT
myESP.mqttPublish(TOPIC_BOILER_DATA, data); myESP.mqttPublish(TOPIC_BOILER_DATA, data);
}
} }
// 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
@@ -856,18 +861,22 @@ void publishValues(bool force) {
data[0] = '\0'; // reset data for next package data[0] = '\0'; // reset data for next package
serializeJson(doc, data, sizeof(data)); serializeJson(doc, data, sizeof(data));
// calculate new CRC // check for empty json
crc.reset(); jsonSize = measureJson(doc);
for (size_t i = 0; i < measureJson(doc) - 1; i++) { if (jsonSize > 2) {
crc.update(data[i]); // calculate new CRC
} crc.reset();
fchecksum = crc.finalize(); for (uint8_t i = 0; i < (jsonSize - 1); i++) {
if ((previousThermostatPublishCRC != fchecksum) || force) { crc.update(data[i]);
previousThermostatPublishCRC = fchecksum; }
myDebugLog("Publishing thermostat data via MQTT"); fchecksum = crc.finalize();
if ((previousThermostatPublishCRC != fchecksum) || force) {
previousThermostatPublishCRC = fchecksum;
myDebugLog("Publishing thermostat data via MQTT");
// send values via MQTT // send values via MQTT
myESP.mqttPublish(TOPIC_THERMOSTAT_DATA, data); myESP.mqttPublish(TOPIC_THERMOSTAT_DATA, data);
}
} }
} }
@@ -906,18 +915,22 @@ void publishValues(bool force) {
data[0] = '\0'; // reset data for next package data[0] = '\0'; // reset data for next package
serializeJson(doc, data, sizeof(data)); serializeJson(doc, data, sizeof(data));
// calculate new CRC // check for empty json
crc.reset(); jsonSize = measureJson(doc);
for (size_t i = 0; i < measureJson(doc) - 1; i++) { if (jsonSize > 2) {
crc.update(data[i]); // calculate new CRC
} crc.reset();
fchecksum = crc.finalize(); for (uint8_t i = 0; i < (jsonSize - 1); i++) {
if ((previousSMPublishCRC != fchecksum) || force) { crc.update(data[i]);
previousSMPublishCRC = fchecksum; }
myDebugLog("Publishing SM data via MQTT"); fchecksum = crc.finalize();
if ((previousSMPublishCRC != fchecksum) || force) {
previousSMPublishCRC = fchecksum;
myDebugLog("Publishing SM data via MQTT");
// send values via MQTT // send values via MQTT
myESP.mqttPublish(TOPIC_SM_DATA, data); myESP.mqttPublish(TOPIC_SM_DATA, data);
}
} }
} }
@@ -1675,7 +1688,7 @@ void WebCallback(JsonObject root) {
if (myESP.getUseSerial()) { if (myESP.getUseSerial()) {
emsbus["ok"] = false; emsbus["ok"] = false;
emsbus["msg"] = "EMS Bus is disabled when in Serial mode. Check Settings->General Settings"; emsbus["msg"] = "EMS Bus is disabled when in Serial mode. Check Settings->General Settings->Serial Port";
} else { } else {
if (ems_getBusConnected()) { if (ems_getBusConnected()) {
if (ems_getTxDisabled()) { if (ems_getTxDisabled()) {

View File

@@ -273,10 +273,10 @@ void ems_init() {
EMS_Boiler.wWCirc = EMS_VALUE_INT_NOTSET; // Circulation on/off EMS_Boiler.wWCirc = EMS_VALUE_INT_NOTSET; // Circulation on/off
EMS_Boiler.selBurnPow = EMS_VALUE_INT_NOTSET; // Burner max power EMS_Boiler.selBurnPow = EMS_VALUE_INT_NOTSET; // Burner max power
EMS_Boiler.curBurnPow = EMS_VALUE_INT_NOTSET; // Burner current power EMS_Boiler.curBurnPow = EMS_VALUE_INT_NOTSET; // Burner current power
EMS_Boiler.flameCurr = EMS_VALUE_SHORT_NOTSET; // Flame current in micro amps EMS_Boiler.flameCurr = EMS_VALUE_USHORT_NOTSET; // Flame current in micro amps
EMS_Boiler.sysPress = EMS_VALUE_INT_NOTSET; // System pressure EMS_Boiler.sysPress = EMS_VALUE_INT_NOTSET; // System pressure
strlcpy(EMS_Boiler.serviceCodeChar, "??", sizeof(EMS_Boiler.serviceCodeChar)); strlcpy(EMS_Boiler.serviceCodeChar, "??", sizeof(EMS_Boiler.serviceCodeChar));
EMS_Boiler.serviceCode = EMS_VALUE_SHORT_NOTSET; EMS_Boiler.serviceCode = EMS_VALUE_USHORT_NOTSET;
// UBAMonitorSlow // UBAMonitorSlow
EMS_Boiler.extTemp = EMS_VALUE_SHORT_NOTSET; // Outside temperature EMS_Boiler.extTemp = EMS_VALUE_SHORT_NOTSET; // Outside temperature
@@ -335,7 +335,6 @@ void ems_init() {
EMS_Thermostat.product_id = EMS_ID_NONE; EMS_Thermostat.product_id = EMS_ID_NONE;
strlcpy(EMS_Thermostat.version, "?", sizeof(EMS_Thermostat.version)); strlcpy(EMS_Thermostat.version, "?", sizeof(EMS_Thermostat.version));
// default logging is none // default logging is none
ems_setLogging(EMS_SYS_LOGGING_DEFAULT); ems_setLogging(EMS_SYS_LOGGING_DEFAULT);
} }
@@ -605,7 +604,9 @@ void _ems_sendTelegram() {
_EMS_TX_STATUS _txStatus = emsuart_tx_buffer(EMS_TxTelegram.data, EMS_TxTelegram.length); // send the telegram to the UART Tx _EMS_TX_STATUS _txStatus = emsuart_tx_buffer(EMS_TxTelegram.data, EMS_TxTelegram.length); // send the telegram to the UART Tx
if (EMS_TX_BRK_DETECT == _txStatus || EMS_TX_WTD_TIMEOUT == _txStatus) { if (EMS_TX_BRK_DETECT == _txStatus || EMS_TX_WTD_TIMEOUT == _txStatus) {
// Tx Error! // Tx Error!
myDebug_P(PSTR("** error sending buffer: %s"), _txStatus == EMS_TX_BRK_DETECT ? "BRK" : "WDTO"); if (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_VERBOSE) {
myDebug_P(PSTR("** error sending buffer: %s"), _txStatus == EMS_TX_BRK_DETECT ? "BRK" : "WDTO");
}
// EMS_Sys_Status.emsTxStatus = EMS_TX_STATUS_IDLE; // EMS_Sys_Status.emsTxStatus = EMS_TX_STATUS_IDLE;
} }
EMS_TxQueue.shift(); // and remove from queue EMS_TxQueue.shift(); // and remove from queue
@@ -668,8 +669,9 @@ void _ems_sendTelegram() {
EMS_Sys_Status.emsTxStatus = EMS_TX_STATUS_WAIT; EMS_Sys_Status.emsTxStatus = EMS_TX_STATUS_WAIT;
else { else {
// Tx Error! // Tx Error!
// Tx Error! if (EMS_Sys_Status.emsLogging == EMS_SYS_LOGGING_VERBOSE) {
myDebug_P(PSTR("** error sending buffer: %s"), _txStatus == EMS_TX_BRK_DETECT ? "BRK" : "WDTO"); myDebug_P(PSTR("** error sending buffer: %s"), _txStatus == EMS_TX_BRK_DETECT ? "BRK" : "WDTO");
}
EMS_Sys_Status.emsTxStatus = EMS_TX_STATUS_IDLE; EMS_Sys_Status.emsTxStatus = EMS_TX_STATUS_IDLE;
} }
} }
@@ -2509,10 +2511,6 @@ void ems_setThermostatTemp(float temperature, uint8_t temptype) {
} }
} }
// TODO XXX hack, please remove
EMS_TxTelegram.type = EMS_TYPE_RCPLUSSet; // for 3000 and 1010, e.g. 0B 10 FF (0A | 08) 01 89 2B
EMS_TxTelegram.offset = 0x08; // auto offset
EMS_TxTelegram.length = EMS_MIN_TELEGRAM_LENGTH; EMS_TxTelegram.length = EMS_MIN_TELEGRAM_LENGTH;
EMS_TxTelegram.dataValue = (uint8_t)((float)temperature * (float)2); // value * 2 EMS_TxTelegram.dataValue = (uint8_t)((float)temperature * (float)2); // value * 2
EMS_TxTelegram.type_validate = EMS_TxTelegram.type; EMS_TxTelegram.type_validate = EMS_TxTelegram.type;

View File

@@ -1,6 +1,6 @@
#define APP_NAME "EMS-ESP" #define APP_NAME "EMS-ESP"
#define APP_VERSION "1.9.0b2_web" #define APP_VERSION "1.9.0b3_web"
#define APP_HOSTNAME "ems-esp" #define APP_HOSTNAME "ems-esp"
#define APP_URL "https://github.com/proddy/EMS-ESP" #define APP_URL "https://github.com/proddy/EMS-ESP"
#define APP_UPDATEURL "https://api.github.com/repos/proddy/EMS-ESP/releases/latest" #define APP_UPDATEURL "https://api.github.com/repos/proddy/EMS-ESP/releases/latest"

View File

@@ -158,7 +158,8 @@
<div class="alert alert-warning"> <div class="alert alert-warning">
<h5><b>Warning!</b> This action <strong>cannot</strong> be undone. This will permanently <h5><b>Warning!</b> This action <strong>cannot</strong> be undone. This will permanently
delete <strong>all delete <strong>all
the settings and logs.</strong> Please make sure you've made a backup before resetting!</h5> the settings and logs.</strong> Please make sure you've made a backup before
resetting!</h5>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<h5>Please type in the hostname of the device to confirm.</h5> <h5>Please type in the hostname of the device to confirm.</h5>

View File

@@ -107,7 +107,7 @@
<div class="row form-group"> <div class="row form-group">
<label class="col-xs-3">Serial Port<i style="margin-left: 10px;" class="glyphicon glyphicon-info-sign" <label class="col-xs-3">Serial Port<i style="margin-left: 10px;" class="glyphicon glyphicon-info-sign"
aria-hidden="true" data-toggle="popover" data-trigger="hover" data-placement="right" aria-hidden="true" data-toggle="popover" data-trigger="hover" data-placement="right"
data-content="Please choose if you want to enable Serial port for debugging"></i></label> data-content="Serial port for console output directly via USB as well as Telnet"></i></label>
<div class="col-xs-9"> <div class="col-xs-9">
<form> <form>
<label class="radio-inline"> <label class="radio-inline">
@@ -224,7 +224,7 @@
<div class="row form-group"> <div class="row form-group">
<label class="col-xs-3">Heartbeat<i style="margin-left: 10px;" class="glyphicon glyphicon-info-sign" <label class="col-xs-3">Heartbeat<i style="margin-left: 10px;" class="glyphicon glyphicon-info-sign"
aria-hidden="true" data-toggle="popover" data-trigger="hover" data-placement="right" aria-hidden="true" data-toggle="popover" data-trigger="hover" data-placement="right"
data-content="Please choose if you want to enable the MQTT heartbeat"></i></label> data-content="enable/disable an automatic MQTT publish with system stats"></i></label>
<div class="col-xs-9"> <div class="col-xs-9">
<form> <form>
<label class="radio-inline"> <label class="radio-inline">
@@ -391,7 +391,7 @@
<br><br> <br><br>
<legend>System Status</legend> <legend>System Status</legend>
<br> <br>
<div class="row text-center"> <div class="row text-left">
<div class="col-md-8 col-md-offset-2"> <div class="col-md-8 col-md-offset-2">
<div class="panel panel-default table-responsive"> <div class="panel panel-default table-responsive">
<table class="table table-hover table-striped table-condensed"> <table class="table table-hover table-striped table-condensed">
@@ -476,9 +476,15 @@
</td> </td>
</tr> </tr>
</table> </table>
<div class="panel-heading">
<div class="panel-title" id="mqttloghdr"></div>
</div>
<div>
<table id="mqttlogtable" class="table" data-paging="false" data-filtering="false"
data-sorting="false" data-editing="false" data-state="true"></table>
</div>
</div> </div>
</div> </div>
<br>
<br>
</div> </div>
</div> </div>

View File

@@ -346,8 +346,8 @@ function listStats() {
document.getElementById("uptime").innerHTML = ajaxobj.uptime; document.getElementById("uptime").innerHTML = ajaxobj.uptime;
document.getElementById("heap").innerHTML = ajaxobj.heap + " KB"; document.getElementById("heap").innerHTML = ajaxobj.heap + " bytes";
document.getElementById("heap").style.width = (ajaxobj.heap * 100) / 41 + "%"; document.getElementById("heap").style.width = (ajaxobj.heap * 100) / ajaxobj.initheap + "%";
colorStatusbar(document.getElementById("heap")); colorStatusbar(document.getElementById("heap"));
document.getElementById("flash").innerHTML = ajaxobj.availsize + " KB"; document.getElementById("flash").innerHTML = ajaxobj.availsize + " KB";
@@ -380,6 +380,8 @@ function listStats() {
document.getElementById("mqttheartbeat").className = "label label-primary"; document.getElementById("mqttheartbeat").className = "label label-primary";
} }
document.getElementById("mqttloghdr").innerHTML = "MQTT Publish Log: (topics are prefixed with <b>" + ajaxobj.mqttloghdr + "</b>)";
} }
function getContent(contentname) { function getContent(contentname) {
@@ -605,6 +607,55 @@ function initEventTable() {
}); });
} }
function initMQTTLogTable() {
var newlist = [];
for (var i = 0; i < ajaxobj.mqttlog.length; i++) {
var data = JSON.stringify(ajaxobj.mqttlog[i]);
newlist[i] = {};
newlist[i].options = {};
newlist[i].value = {};
newlist[i].value = JSON.parse(data);
newlist[i].options.classes = "warning";
newlist[i].options.style = "color: blue";
}
jQuery(function ($) {
window.FooTable.init("#mqttlogtable", {
columns: [{
"name": "time",
"title": "Last Published",
"style": { "min-width": "160px" },
"parser": function (value) {
if (value < 1563300000) {
return "(" + value + ")";
} else {
var comp = new Date();
value = Math.floor(value + ((comp.getTimezoneOffset() * 60) * -1));
var vuepoch = new Date(value * 1000);
var formatted = vuepoch.getUTCFullYear() +
"-" + twoDigits(vuepoch.getUTCMonth() + 1) +
"-" + twoDigits(vuepoch.getUTCDate()) +
" " + twoDigits(vuepoch.getUTCHours()) +
":" + twoDigits(vuepoch.getUTCMinutes()) +
":" + twoDigits(vuepoch.getUTCSeconds());
return formatted;
}
},
"breakpoints": "xs sm"
},
{
"name": "topic",
"title": "Topic",
},
{
"name": "payload",
"title": "Payload",
},
],
rows: newlist
});
});
}
function restartESP() { function restartESP() {
inProgress("restart"); inProgress("restart");
} }
@@ -617,6 +668,7 @@ function socketMessageListener(evt) {
switch (obj.command) { switch (obj.command) {
case "status": case "status":
ajaxobj = obj; ajaxobj = obj;
initMQTTLogTable();
getContent("#statuscontent"); getContent("#statuscontent");
break; break;
case "custom_settings": case "custom_settings":

View File

@@ -123,20 +123,32 @@ function sendEventLog() {
function sendStatus() { function sendStatus() {
var stats = { var stats = {
"command": "status", "command": "status",
"heap": 30, "availspiffs": 948,
"availsize": 555, "spiffssize": 957,
"availspiffs": 445, "initheap": 25392,
"spiffssize": 888, "heap": 13944,
"sketchsize": 222, "sketchsize": 673,
"uptime": "1 Day 6 Hours", "availsize": 2469,
"ssid": "SSID", "ip": "10.10.10.198",
"mac": "EM:44:11:33:22", "ssid": "derbyshire",
"ip": "192.168.2.2", "mac": "DC:4F:11:22:93:06",
"signalstr": 66, "signalstr": 62,
"systemload": 10, "systemload": 0,
"mqttconnected": true, "mqttconnected": true,
"mqttheartbeat": false "mqttheartbeat": false,
"uptime": "0 days 0 hours 1 minute 45 seconds",
"mqttloghdr": "home/ems-esp/",
"mqttlog": [
{ "topic": "start", "payload": "start", "time": 1565956388 },
{ "topic": "shower_timer", "payload": "1", "time": 1565956388 },
{ "topic": "shower_alert", "payload": "0", "time": 1565956388 },
{ "topic": "boiler_data", "payload": "{\"wWComfort\":\"Hot\",\"wWSelTemp\":60,\"selFlowTemp\":5,\"selBurnPow\":0,\"curBurnPow\":0,\"pumpMod\":0,\"wWCurTmp\":48.4,\"wWCurFlow\":0,\"curFlowTemp\":49.3,\"retTemp\":49.3,\"sysPress\":1.8,\"boilTemp\":50.5,\"wWActivated\":\"on\",\"burnGas\":\"off\",\"heatPmp\":\"off\",\"fanWork\":\"off\",\"ignWork\":\"off\",\"wWCirc\":\"off\",\"wWHeat\":\"on\",\"burnStarts\":223397,\"burnWorkMin\":366019,\"heatWorkMin\":294036,\"ServiceCode\":\"0H\",\"ServiceCodeNumber\":203}", "time": 1565956463 },
{ "topic": "tapwater_active", "payload": "0", "time": 1565956408 },
{ "topic": "heating_active", "payload": "0", "time": 1565956408 },
{ "topic": "thermostat_data", "payload": "{\"thermostat_hc\":\"1\",\"thermostat_seltemp\":15,\"thermostat_currtemp\":23,\"thermostat_mode\":\"auto\"}", "time": 1565956444 }
]
}; };
wss.broadcast(stats); wss.broadcast(stats);
} }
@@ -157,7 +169,6 @@ function sendCustomStatus() {
{ "type": 3, "model": "model 3", "deviceid": "device id3", "version": "version id3", "productid": "product id3" }, { "type": 3, "model": "model 3", "deviceid": "device id3", "version": "version id3", "productid": "product id3" },
{ "type": 4, "model": "model 4", "deviceid": "device id3", "version": "version id3", "productid": "product id3" }, { "type": 4, "model": "model 4", "deviceid": "device id3", "version": "version id3", "productid": "product id3" },
{ "type": 5, "model": "model 5", "deviceid": "device id3", "version": "version id3", "productid": "product id3" } { "type": 5, "model": "model 5", "deviceid": "device id3", "version": "version id3", "productid": "product id3" }
] ]
}, },
@@ -181,6 +192,7 @@ function sendCustomStatus() {
} }
}; };
wss.broadcast(stats); wss.broadcast(stats);
} }