Command to request day or month plot data via MQTT (#1023)

This commit is contained in:
Gunnar Skjold
2025-10-02 12:56:25 +02:00
committed by GitHub
parent e11fac3d11
commit 6a75b0fe71
8 changed files with 84 additions and 34 deletions

View File

@@ -0,0 +1,9 @@
#pragma once
#include "AmsDataStorage.h"
class AmsJsonGenerator {
public:
static void generateDayPlotJson(AmsDataStorage* ds, char* buf, size_t bufSize);
static void generateMonthPlotJson(AmsDataStorage* ds, char* buf, size_t bufSize);
};

View File

@@ -0,0 +1,17 @@
#include "AmsJsonGenerator.h"
void AmsJsonGenerator::generateDayPlotJson(AmsDataStorage* ds, char* buf, size_t bufSize) {
uint16_t pos = snprintf_P(buf, bufSize, PSTR("{\"unit\":\"kwh\""));
for(uint8_t i = 0; i < 24; i++) {
pos += snprintf_P(buf+pos, bufSize-pos, PSTR(",\"i%02d\":%.3f,\"e%02d\":%.3f"), i, ds->getHourImport(i) / 1000.0, i, ds->getHourExport(i) / 1000.0);
}
snprintf_P(buf+pos, bufSize-pos, PSTR("}"));
}
void AmsJsonGenerator::generateMonthPlotJson(AmsDataStorage* ds, char* buf, size_t bufSize) {
uint16_t pos = snprintf_P(buf, bufSize, PSTR("{\"unit\":\"kwh\""));
for(uint8_t i = 1; i < 32; i++) {
pos += snprintf_P(buf+pos, bufSize-pos, PSTR(",\"i%02d\":%.3f,\"e%02d\":%.3f"), i, ds->getDayImport(i) / 1000.0, i, ds->getDayExport(i) / 1000.0);
}
snprintf_P(buf+pos, bufSize-pos, PSTR("}"));
}

View File

@@ -124,18 +124,6 @@ bool AmsMqttHandler::connect() {
#endif
debugger->printf_P(PSTR("Successfully connected to MQTT\n"));
mqtt.onMessage(std::bind(&AmsMqttHandler::onMessage, this, std::placeholders::_1, std::placeholders::_2));
if(strlen(mqttConfig.subscribeTopic) > 0) {
#if defined(AMS_REMOTE_DEBUG)
if (debugger->isActive(RemoteDebug::INFO))
#endif
debugger->printf_P(PSTR(" Subscribing to [%s]\n"), mqttConfig.subscribeTopic);
if(!mqtt.subscribe(mqttConfig.subscribeTopic)) {
#if defined(AMS_REMOTE_DEBUG)
if (debugger->isActive(RemoteDebug::ERROR))
#endif
debugger->printf_P(PSTR(" Unable to subscribe to to [%s]\n"), mqttConfig.subscribeTopic);
}
}
mqtt.publish(statusTopic, "online", true, 0);
mqtt.loop();
postConnect();

View File

@@ -12,14 +12,18 @@
class JsonMqttHandler : public AmsMqttHandler {
public:
#if defined(AMS_REMOTE_DEBUG)
JsonMqttHandler(MqttConfig& mqttConfig, RemoteDebug* debugger, char* buf, HwTools* hw, AmsFirmwareUpdater* updater) : AmsMqttHandler(mqttConfig, debugger, buf, updater) {
this->hw = hw;
};
JsonMqttHandler(MqttConfig& mqttConfig, RemoteDebug* debugger, char* buf, HwTools* hw, AmsDataStorage* ds, AmsFirmwareUpdater* updater) : AmsMqttHandler(mqttConfig, debugger, buf, updater) {
#else
JsonMqttHandler(MqttConfig& mqttConfig, Stream* debugger, char* buf, HwTools* hw) : AmsMqttHandler(mqttConfig, debugger, buf) {
this->hw = hw;
};
JsonMqttHandler(MqttConfig& mqttConfig, Stream* debugger, char* buf, HwTools* hw, AmsDataStorage* ds, AmsFirmwareUpdater* updater) : AmsMqttHandler(mqttConfig, debugger, buf, updater) {
#endif
subTopic = String(mqttConfig.subscribeTopic);
if(subTopic.isEmpty()) {
String pubTopic = String(mqttConfig.publishTopic);
subTopic = pubTopic+"/command";
}
this->hw = hw;
this->ds = ds;
};
bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea, PriceService* ps);
bool publishTemperatures(AmsConfiguration*, HwTools*);
bool publishPrices(PriceService*);
@@ -27,12 +31,17 @@ public:
bool publishRaw(String data);
bool publishFirmware();
bool postConnect();
void onMessage(String &topic, String &payload);
uint8_t getFormat();
private:
String subTopic;
HwTools* hw;
AmsDataStorage* ds;
uint16_t appendJsonHeader(AmsData* data);
uint16_t appendJsonFooter(EnergyAccounting* ea, uint16_t pos);
bool publishList1(AmsData* data, EnergyAccounting* ea);

View File

@@ -8,6 +8,18 @@
#include "FirmwareVersion.h"
#include "hexutils.h"
#include "Uptime.h"
#include "AmsJsonGenerator.h"
bool JsonMqttHandler::postConnect() {
if(!subTopic.isEmpty() && !mqtt.subscribe(subTopic)) {
#if defined(AMS_REMOTE_DEBUG)
if (debugger->isActive(RemoteDebug::ERROR))
#endif
debugger->printf_P(PSTR(" Unable to subscribe to to [%s]\n"), subTopic.c_str());
return false;
}
return true;
}
bool JsonMqttHandler::publish(AmsData* update, AmsData* previousState, EnergyAccounting* ea, PriceService* ps) {
if(strlen(mqttConfig.publishTopic) == 0) {
@@ -447,11 +459,35 @@ bool JsonMqttHandler::publishFirmware() {
}
void JsonMqttHandler::onMessage(String &topic, String &payload) {
if(strncmp(topic.c_str(), mqttConfig.subscribeTopic, 12) == 0) {
if(strlen(mqttConfig.publishTopic) == 0 || !mqtt.connected())
return;
#if defined(AMS_REMOTE_DEBUG)
if (debugger->isActive(RemoteDebug::INFO))
#endif
debugger->printf_P(PSTR("Received command [%s] to [%s]\n"), payload.c_str(), topic.c_str());
if(topic.equals(subTopic)) {
#if defined(AMS_REMOTE_DEBUG)
if (debugger->isActive(RemoteDebug::DEBUG))
#endif
debugger->printf_P(PSTR(" - this is our subscribed topic\n"));
if(payload.equals("fwupgrade")) {
if(strcmp(updater->getNextVersion(), FirmwareVersion::VersionString) != 0) {
updater->setTargetVersion(updater->getNextVersion());
}
} else if(payload.equals("dayplot")) {
char pubTopic[192];
snprintf_P(pubTopic, 192, PSTR("%s/dayplot"), mqttConfig.publishTopic);
AmsJsonGenerator::generateDayPlotJson(ds, json, BufferSize);
bool ret = mqtt.publish(pubTopic, json);
loop();
} else if(payload.equals("monthplot")) {
char pubTopic[192];
snprintf_P(pubTopic, 192, PSTR("%s/monthplot"), mqttConfig.publishTopic);
AmsJsonGenerator::generateMonthPlotJson(ds, json, BufferSize);
bool ret = mqtt.publish(pubTopic, json);
loop();
}
}
}

View File

@@ -9,6 +9,7 @@
#include "FirmwareVersion.h"
#include "base64.h"
#include "hexutils.h"
#include "AmsJsonGenerator.h"
#include "html/index_html.h"
#include "html/index_css.h"
@@ -682,12 +683,7 @@ void AmsWebServer::dayplotJson() {
if(ds == NULL) {
notFound();
} else {
uint16_t pos = snprintf_P(buf, BufferSize, PSTR("{\"unit\":\"kwh\""));
for(uint8_t i = 0; i < 24; i++) {
pos += snprintf_P(buf+pos, BufferSize-pos, PSTR(",\"i%02d\":%.3f,\"e%02d\":%.3f"), i, ds->getHourImport(i) / 1000.0, i, ds->getHourExport(i) / 1000.0);
}
snprintf_P(buf+pos, BufferSize-pos, PSTR("}"));
AmsJsonGenerator::generateDayPlotJson(ds, buf, BufferSize);
addConditionalCloudHeaders();
server.sendHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE);
server.sendHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE);
@@ -705,12 +701,7 @@ void AmsWebServer::monthplotJson() {
if(ds == NULL) {
notFound();
} else {
uint16_t pos = snprintf_P(buf, BufferSize, PSTR("{\"unit\":\"kwh\""));
for(uint8_t i = 1; i < 32; i++) {
pos += snprintf_P(buf+pos, BufferSize-pos, PSTR(",\"i%02d\":%.3f,\"e%02d\":%.3f"), i, ds->getDayImport(i) / 1000.0, i, ds->getDayExport(i) / 1000.0);
}
snprintf_P(buf+pos, BufferSize-pos, PSTR("}"));
AmsJsonGenerator::generateMonthPlotJson(ds, buf, BufferSize);
addConditionalCloudHeaders();
server.sendHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE);
server.sendHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE);