From f7eb54fa411f8844ae7f9da167ed22e47228476f Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Wed, 6 Jul 2022 22:17:26 +0200 Subject: [PATCH] First version of webapi for event log --- include/WebApi.h | 2 + include/WebApi_eventlog.h | 14 ++++++ lib/Hoymiles/src/parser/AlarmLogParser.cpp | 23 +++++++++- lib/Hoymiles/src/parser/AlarmLogParser.h | 6 ++- src/WebApi.cpp | 2 + src/WebApi_eventlog.cpp | 50 ++++++++++++++++++++++ 6 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 include/WebApi_eventlog.h create mode 100644 src/WebApi_eventlog.cpp diff --git a/include/WebApi.h b/include/WebApi.h index 69757dc..a219208 100644 --- a/include/WebApi.h +++ b/include/WebApi.h @@ -1,6 +1,7 @@ #pragma once #include "WebApi_dtu.h" +#include "WebApi_eventlog.h" #include "WebApi_firmware.h" #include "WebApi_inverter.h" #include "WebApi_mqtt.h" @@ -23,6 +24,7 @@ private: AsyncEventSource _events; WebApiDtuClass _webApiDtu; + WebApiEventlogClass _webApiEventlog; WebApiFirmwareClass _webApiFirmware; WebApiInverterClass _webApiInverter; WebApiMqttClass _webApiMqtt; diff --git a/include/WebApi_eventlog.h b/include/WebApi_eventlog.h new file mode 100644 index 0000000..4b50411 --- /dev/null +++ b/include/WebApi_eventlog.h @@ -0,0 +1,14 @@ +#pragma once + +#include + +class WebApiEventlogClass { +public: + void init(AsyncWebServer* server); + void loop(); + +private: + void onEventlogStatus(AsyncWebServerRequest* request); + + AsyncWebServer* _server; +}; \ No newline at end of file diff --git a/lib/Hoymiles/src/parser/AlarmLogParser.cpp b/lib/Hoymiles/src/parser/AlarmLogParser.cpp index 3408f1b..aeab8e7 100644 --- a/lib/Hoymiles/src/parser/AlarmLogParser.cpp +++ b/lib/Hoymiles/src/parser/AlarmLogParser.cpp @@ -18,11 +18,15 @@ uint8_t AlarmLogParser::getEntryCount() return (_alarmLogLength - 2) / ALARM_LOG_ENTRY_SIZE; } -void AlarmLogParser::getLogEntry(uint8_t entryId, AlarmLogEntry* entry) +void AlarmLogParser::getLogEntry(uint8_t entryId, AlarmLogEntry_t* entry) { uint8_t entryStartOffset = 2 + entryId * ALARM_LOG_ENTRY_SIZE; + int timezoneOffset = getTimezoneOffset(); + entry->MessageId = _payloadAlarmLog[entryStartOffset + 1]; + entry->StartTime = ((uint16_t)_payloadAlarmLog[entryStartOffset + 4] << 8) | ((uint16_t)_payloadAlarmLog[entryStartOffset + 5]) + timezoneOffset; + entry->EndTime = ((uint16_t)_payloadAlarmLog[entryStartOffset + 6] << 8) | ((uint16_t)_payloadAlarmLog[entryStartOffset + 7]) + timezoneOffset; switch (entry->MessageId) { case 1: @@ -233,4 +237,21 @@ void AlarmLogParser::getLogEntry(uint8_t entryId, AlarmLogEntry* entry) entry->Message = String(F("Unknown")); break; } +} + +int AlarmLogParser::getTimezoneOffset() +{ + // see: https://stackoverflow.com/questions/13804095/get-the-time-zone-gmt-offset-in-c/44063597#44063597 + + time_t gmt, rawtime = time(NULL); + struct tm *ptm; + + struct tm gbuf; + ptm = gmtime_r(&rawtime, &gbuf); + + // Request that mktime() looksup dst in timezone database + ptm->tm_isdst = -1; + gmt = mktime(ptm); + + return (int)difftime(rawtime, gmt); } \ No newline at end of file diff --git a/lib/Hoymiles/src/parser/AlarmLogParser.h b/lib/Hoymiles/src/parser/AlarmLogParser.h index b89ec48..c5c7624 100644 --- a/lib/Hoymiles/src/parser/AlarmLogParser.h +++ b/lib/Hoymiles/src/parser/AlarmLogParser.h @@ -5,7 +5,7 @@ #define ALARM_LOG_ENTRY_COUNT 15 #define ALARM_LOG_ENTRY_SIZE 12 -struct AlarmLogEntry { +struct AlarmLogEntry_t { uint16_t MessageId; String Message; time_t StartTime; @@ -18,9 +18,11 @@ public: void appendFragment(uint8_t offset, uint8_t* payload, uint8_t len); uint8_t getEntryCount(); - void getLogEntry(uint8_t entryId, AlarmLogEntry* entry); + void getLogEntry(uint8_t entryId, AlarmLogEntry_t* entry); private: + static int getTimezoneOffset(); + uint8_t _payloadAlarmLog[ALARM_LOG_ENTRY_SIZE * ALARM_LOG_ENTRY_COUNT]; uint8_t _alarmLogLength; }; \ No newline at end of file diff --git a/src/WebApi.cpp b/src/WebApi.cpp index 51e599f..cb86141 100644 --- a/src/WebApi.cpp +++ b/src/WebApi.cpp @@ -20,6 +20,7 @@ void WebApiClass::init() _ws.onEvent(std::bind(&WebApiClass::onWebsocketEvent, this, _1, _2, _3, _4, _5, _6)); _webApiDtu.init(&_server); + _webApiEventlog.init(&_server); _webApiFirmware.init(&_server); _webApiInverter.init(&_server); _webApiMqtt.init(&_server); @@ -36,6 +37,7 @@ void WebApiClass::init() void WebApiClass::loop() { _webApiDtu.loop(); + _webApiEventlog.loop(); _webApiFirmware.loop(); _webApiInverter.loop(); _webApiMqtt.loop(); diff --git a/src/WebApi_eventlog.cpp b/src/WebApi_eventlog.cpp new file mode 100644 index 0000000..5321121 --- /dev/null +++ b/src/WebApi_eventlog.cpp @@ -0,0 +1,50 @@ +#include "WebApi_eventlog.h" +#include "ArduinoJson.h" +#include "AsyncJson.h" +#include "Hoymiles.h" + +void WebApiEventlogClass::init(AsyncWebServer* server) +{ + using namespace std::placeholders; + + _server = server; + + _server->on("/api/eventlog/status", HTTP_GET, std::bind(&WebApiEventlogClass::onEventlogStatus, this, _1)); +} + +void WebApiEventlogClass::loop() +{ +} + +void WebApiEventlogClass::onEventlogStatus(AsyncWebServerRequest* request) +{ + AsyncJsonResponse* response = new AsyncJsonResponse(); + JsonObject root = response->getRoot(); + + for (uint8_t i = 0; i < Hoymiles.getNumInverters(); i++) { + auto inv = Hoymiles.getInverterByPos(i); + + // Inverter Serial is read as HEX + char buffer[sizeof(uint64_t) * 8 + 1]; + sprintf(buffer, "%0lx%08lx", + ((uint32_t)((inv->serial() >> 32) & 0xFFFFFFFF)), + ((uint32_t)(inv->serial() & 0xFFFFFFFF))); + + uint8_t logEntryCount = inv->EventLog()->getEntryCount(); + + root[buffer]["count"] = logEntryCount; + + for (uint8_t logEntry = 0; logEntry < logEntryCount; logEntry++) { + AlarmLogEntry_t entry; + inv->EventLog()->getLogEntry(logEntry, &entry); + + root[buffer][String(logEntry)][F("message_id")] = entry.MessageId; + root[buffer][String(logEntry)][F("message")] = entry.Message; + root[buffer][String(logEntry)][F("start_time")] = entry.StartTime; + root[buffer][String(logEntry)][F("end_time")] = entry.EndTime; + } + } + + response->setLength(); + request->send(response); +} \ No newline at end of file