diff --git a/lib/HomeAssistantMqttHandler/include/HomeAssistantStatic.h b/lib/HomeAssistantMqttHandler/include/HomeAssistantStatic.h index 5dea64ed..327aa9a9 100644 --- a/lib/HomeAssistantMqttHandler/include/HomeAssistantStatic.h +++ b/lib/HomeAssistantMqttHandler/include/HomeAssistantStatic.h @@ -20,9 +20,10 @@ struct HomeAssistantSensor { }; -const uint8_t List1SensorCount PROGMEM = 1; +const uint8_t List1SensorCount PROGMEM = 2; const HomeAssistantSensor List1Sensors[List1SensorCount] PROGMEM = { - {"Active import", "/power", "P", 30, "W", "power", "measurement"} + {"Active import", "/power", "P", 30, "W", "power", "measurement"}, + {"Data timestamp", "/power", "t", 30, "", "timestamp", ""} }; const uint8_t List2SensorCount PROGMEM = 8; @@ -42,11 +43,12 @@ const HomeAssistantSensor List2ExportSensors[List2ExportSensorCount] PROGMEM = { {"Active export", "/power", "PO", 30, "W", "power", "measurement"} }; -const uint8_t List3SensorCount PROGMEM = 3; +const uint8_t List3SensorCount PROGMEM = 4; const HomeAssistantSensor List3Sensors[List3SensorCount] PROGMEM = { {"Accumulated active import", "/energy", "tPI", 4000, "kWh", "energy", "total_increasing"}, {"Accumulated reactive import","/energy", "tQI", 4000, "kvarh","", "total_increasing"}, - {"Accumulated reactive export","/energy", "tQO", 4000, "kvarh","", "total_increasing"} + {"Accumulated reactive export","/energy", "tQO", 4000, "kvarh","", "total_increasing"}, + {"Meter timestamp", "/energy", "rtc", 4000, "", "timestamp", ""} }; const uint8_t List3ExportSensorCount PROGMEM = 1; diff --git a/lib/HomeAssistantMqttHandler/json/ha1.json b/lib/HomeAssistantMqttHandler/json/ha1.json index bda922a1..d90fe48d 100644 --- a/lib/HomeAssistantMqttHandler/json/ha1.json +++ b/lib/HomeAssistantMqttHandler/json/ha1.json @@ -1,3 +1,4 @@ { - "P" : %lu + "P" : %lu, + "t" : "%s" } diff --git a/lib/HomeAssistantMqttHandler/json/ha2.json b/lib/HomeAssistantMqttHandler/json/ha2.json index 5da62efc..e0c6ba9a 100644 --- a/lib/HomeAssistantMqttHandler/json/ha2.json +++ b/lib/HomeAssistantMqttHandler/json/ha2.json @@ -3,5 +3,6 @@ "tPO" : %.3f, "tQI" : %.3f, "tQO" : %.3f, - "rtc" : %lu + "rtc" : "%s", + "t" : "%s" } diff --git a/lib/HomeAssistantMqttHandler/json/ha3.json b/lib/HomeAssistantMqttHandler/json/ha3.json index e2bc09dc..aa5dc318 100644 --- a/lib/HomeAssistantMqttHandler/json/ha3.json +++ b/lib/HomeAssistantMqttHandler/json/ha3.json @@ -11,5 +11,6 @@ "I3" : %.2f, "U1" : %.2f, "U2" : %.2f, - "U3" : %.2f + "U3" : %.2f, + "t" : "%s" } diff --git a/lib/HomeAssistantMqttHandler/json/ha4.json b/lib/HomeAssistantMqttHandler/json/ha4.json index 8d37a9f6..f68fc60e 100644 --- a/lib/HomeAssistantMqttHandler/json/ha4.json +++ b/lib/HomeAssistantMqttHandler/json/ha4.json @@ -27,5 +27,6 @@ "tPI3" : %.3f, "tPO1" : %.3f, "tPO2" : %.3f, - "tPO3" : %.3f + "tPO3" : %.3f, + "t" : "%s" } diff --git a/lib/HomeAssistantMqttHandler/src/HomeAssistantMqttHandler.cpp b/lib/HomeAssistantMqttHandler/src/HomeAssistantMqttHandler.cpp index d18d34f6..b2b466ab 100644 --- a/lib/HomeAssistantMqttHandler/src/HomeAssistantMqttHandler.cpp +++ b/lib/HomeAssistantMqttHandler/src/HomeAssistantMqttHandler.cpp @@ -63,13 +63,31 @@ bool HomeAssistantMqttHandler::publish(AmsData* update, AmsData* previousState, bool HomeAssistantMqttHandler::publishList1(AmsData* data, EnergyAccounting* ea) { publishList1Sensors(); - snprintf_P(json, BufferSize, HA1_JSON, data->getActiveImportPower()); + + char pt[24]; + memset(pt, 0, 24); + if(data->getPackageTimestamp() > 0) { + tmElements_t tm; + breakTime(data->getPackageTimestamp(), tm); + sprintf_P(pt, PSTR("%04d-%02d-%02dT%02d:%02d:%02dZ"), tm.Year+1970, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second); + } + + snprintf_P(json, BufferSize, HA1_JSON, data->getActiveImportPower(), pt); return mqtt.publish(topic + "/power", json); } bool HomeAssistantMqttHandler::publishList2(AmsData* data, EnergyAccounting* ea) { publishList2Sensors(); if(data->getActiveExportPower() > 0) publishList2ExportSensors(); + + char pt[24]; + memset(pt, 0, 24); + if(data->getPackageTimestamp() > 0) { + tmElements_t tm; + breakTime(data->getPackageTimestamp(), tm); + sprintf_P(pt, PSTR("%04d-%02d-%02dT%02d:%02d:%02dZ"), tm.Year+1970, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second); + } + snprintf_P(json, BufferSize, HA3_JSON, data->getListId().c_str(), data->getMeterId().c_str(), @@ -83,7 +101,8 @@ bool HomeAssistantMqttHandler::publishList2(AmsData* data, EnergyAccounting* ea) data->getL3Current(), data->getL1Voltage(), data->getL2Voltage(), - data->getL3Voltage() + data->getL3Voltage(), + pt ); return mqtt.publish(topic + "/power", json); } @@ -91,12 +110,30 @@ bool HomeAssistantMqttHandler::publishList2(AmsData* data, EnergyAccounting* ea) bool HomeAssistantMqttHandler::publishList3(AmsData* data, EnergyAccounting* ea) { publishList3Sensors(); if(data->getActiveExportCounter() > 0.0) publishList3ExportSensors(); + + char mt[24]; + memset(mt, 0, 24); + if(data->getMeterTimestamp() > 0) { + tmElements_t tm; + breakTime(data->getMeterTimestamp(), tm); + sprintf_P(mt, PSTR("%04d-%02d-%02dT%02d:%02d:%02dZ"), tm.Year+1970, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second); + } + + char pt[24]; + memset(pt, 0, 24); + if(data->getPackageTimestamp() > 0) { + tmElements_t tm; + breakTime(data->getPackageTimestamp(), tm); + sprintf_P(pt, PSTR("%04d-%02d-%02dT%02d:%02d:%02dZ"), tm.Year+1970, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second); + } + snprintf_P(json, BufferSize, HA2_JSON, data->getActiveImportCounter(), data->getActiveExportCounter(), data->getReactiveImportCounter(), data->getReactiveExportCounter(), - data->getMeterTimestamp() + mt, + pt ); return mqtt.publish(topic + "/energy", json); } @@ -104,6 +141,15 @@ bool HomeAssistantMqttHandler::publishList3(AmsData* data, EnergyAccounting* ea) bool HomeAssistantMqttHandler::publishList4(AmsData* data, EnergyAccounting* ea) { publishList4Sensors(); if(data->getL1ActiveExportPower() > 0 || data->getL2ActiveExportPower() > 0 || data->getL3ActiveExportPower() > 0) publishList4ExportSensors(); + + char pt[24]; + memset(pt, 0, 24); + if(data->getPackageTimestamp() > 0) { + tmElements_t tm; + breakTime(data->getPackageTimestamp(), tm); + sprintf_P(pt, PSTR("%04d-%02d-%02dT%02d:%02d:%02dZ"), tm.Year+1970, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second); + } + snprintf_P(json, BufferSize, HA4_JSON, data->getListId().c_str(), data->getMeterId().c_str(), @@ -133,7 +179,8 @@ bool HomeAssistantMqttHandler::publishList4(AmsData* data, EnergyAccounting* ea) data->getL3ActiveImportCounter(), data->getL1ActiveExportCounter(), data->getL2ActiveExportCounter(), - data->getL3ActiveExportCounter() + data->getL3ActiveExportCounter(), + pt ); return mqtt.publish(topic + "/power", json); } @@ -172,8 +219,8 @@ bool HomeAssistantMqttHandler::publishRealtime(AmsData* data, EnergyAccounting* ea->getProducedThisMonth(), ea->getIncomeThisMonth() ); - uint32_t now = millis(); - if(lastThresholdPublish == 0 || now-lastThresholdPublish > 3600000) { + uint32_t ms = millis(); + if(lastThresholdPublish == 0 || ms-lastThresholdPublish > 3600000) { EnergyAccountingConfig* conf = ea->getConfig(); pos += snprintf_P(json+pos, BufferSize-pos, PSTR(",\"thresholds\": [%d,%d,%d,%d,%d,%d,%d,%d,%d]"), conf->thresholds[0], @@ -186,8 +233,18 @@ bool HomeAssistantMqttHandler::publishRealtime(AmsData* data, EnergyAccounting* conf->thresholds[7], conf->thresholds[8] ); - lastThresholdPublish = now; + lastThresholdPublish = ms; } + + time_t now = time(nullptr); + char pt[24]; + memset(pt, 0, 24); + if(now > 0) { + tmElements_t tm; + breakTime(now, tm); + sprintf_P(pt, PSTR("%04d-%02d-%02dT%02d:%02d:%02dZ"), tm.Year+1970, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second); + } + pos += snprintf_P(json+pos, BufferSize-pos, PSTR(",\"t\":\"%s\""), pt); json[pos++] = '}'; json[pos] = '\0'; @@ -199,17 +256,13 @@ bool HomeAssistantMqttHandler::publishTemperatures(AmsConfiguration* config, HwT int count = hw->getTempSensorCount(); if(count < 2) return false; - int size = 32 + (count * 26); - - char buf[size]; - snprintf_P(buf, 24, PSTR("{\"temperatures\":{")); + uint16_t pos = snprintf_P(json, 24, PSTR("{\"temperatures\":{")); for(int i = 0; i < count; i++) { TempSensorData* data = hw->getTempSensorData(i); if(data != NULL) { - char* pos = buf+strlen(buf); String id = toHex(data->address, 8); - snprintf_P(pos, 26, PSTR("\"%s\":%.2f,"), + pos += snprintf_P(json+pos, BufferSize-pos, PSTR("\"%s\":%.2f,"), id.c_str(), data->lastRead ); @@ -217,9 +270,20 @@ bool HomeAssistantMqttHandler::publishTemperatures(AmsConfiguration* config, HwT publishTemperatureSensor(i+1, id); } } - char* pos = buf+strlen(buf); - snprintf_P(count == 0 ? pos : pos-1, 8, PSTR("}}")); - bool ret = mqtt.publish(topic + "/temperatures", buf); + pos += snprintf_P(json+pos, BufferSize-pos, PSTR("}")); + + time_t now = time(nullptr); + char pt[24]; + memset(pt, 0, 24); + if(now > 0) { + tmElements_t tm; + breakTime(now, tm); + sprintf_P(pt, PSTR("%04d-%02d-%02dT%02d:%02d:%02dZ"), tm.Year+1970, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second); + } + pos += snprintf_P(json+pos, BufferSize-pos, PSTR(",\"t\":\"%s\""), pt); + pos += snprintf_P(json+pos, BufferSize-pos, PSTR("}")); + + bool ret = mqtt.publish(topic + "/temperatures", json); loop(); return ret; } @@ -333,6 +397,15 @@ bool HomeAssistantMqttHandler::publishPrices(PriceService* ps) { pos += snprintf_P(json+pos, BufferSize-pos, PSTR(",\"exportprices\":{\"0\":%.4f}"), val); } + char pt[24]; + memset(pt, 0, 24); + if(now > 0) { + tmElements_t tm; + breakTime(now, tm); + sprintf_P(pt, PSTR("%04d-%02d-%02dT%02d:%02d:%02dZ"), tm.Year+1970, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second); + } + pos += snprintf_P(json+pos, BufferSize-pos, PSTR(",\"t\":\"%s\""), pt); + json[pos++] = '}'; json[pos] = '\0'; @@ -348,14 +421,24 @@ bool HomeAssistantMqttHandler::publishSystem(HwTools* hw, PriceService* ps, Ener publishSystemSensors(); if(hw->getTemperature() > -50) publishTemperatureSensor(0, ""); - snprintf_P(json, BufferSize, PSTR("{\"id\":\"%s\",\"name\":\"%s\",\"up\":%d,\"vcc\":%.3f,\"rssi\":%d,\"temp\":%.2f,\"version\":\"%s\"}"), + time_t now = time(nullptr); + char pt[24]; + memset(pt, 0, 24); + if(now > 0) { + tmElements_t tm; + breakTime(now, tm); + sprintf_P(pt, PSTR("%04d-%02d-%02dT%02d:%02d:%02dZ"), tm.Year+1970, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second); + } + + snprintf_P(json, BufferSize, PSTR("{\"id\":\"%s\",\"name\":\"%s\",\"up\":%d,\"vcc\":%.3f,\"rssi\":%d,\"temp\":%.2f,\"version\":\"%s\",\"t\":\"%s\"}"), WiFi.macAddress().c_str(), mqttConfig.clientId, (uint32_t) (millis64()/1000), hw->getVcc(), hw->getWifiRssi(), hw->getTemperature(), - FirmwareVersion::VersionString + FirmwareVersion::VersionString, + pt ); bool ret = mqtt.publish(topic + "/state", json); loop(); @@ -618,9 +701,9 @@ void HomeAssistantMqttHandler::onMessage(String &topic, String &payload) { if(topic.equals(statusTopic)) { if(payload.equals("online")) { #if defined(AMS_REMOTE_DEBUG) -if (debugger->isActive(RemoteDebug::INFO)) -#endif -debugger->printf_P(PSTR("Received online status from HA, resetting sensor status\n")); + if (debugger->isActive(RemoteDebug::INFO)) + #endif + debugger->printf_P(PSTR("Received online status from HA, resetting sensor status\n")); l1Init = l2Init = l2eInit = l3Init = l3eInit = l4Init = l4eInit = rtInit = rteInit = pInit = sInit = rInit = false; for(uint8_t i = 0; i < 32; i++) tInit[i] = false; for(uint8_t i = 0; i < 38; i++) prInit[i] = false;