Files
UtilitechAS.amsreader-firmware/lib/PriceService/src/EntsoeA44Parser.cpp
Gunnar Skjold c648546b61 Added support for 15 minute price resolution (#1031)
* 15min prices WIP

* WIP more changes for 15min prices

* More work on 15min pricing

* Fixed some errors

* Some changes after testing

* Graphical changes for 15min pricing

* Adjustments on MQTT handlers after switching to 15min prices

* Reverted some MQTT changes

* Adapted HA integration for 15min pricing

* Adapted JSON payload for 15min

* Adjustments during testing

* Set default price interval

* Fixed refresh of price graph when data changes

* Bugfixes

* Fixed some issues with raw payload

* Adjustments for meter timestamp from Kamstrup

* Updated readme

* Added detailed breakdown of payloads coming from Norwegian meters

* Minor changes relating to price

* Fixed byte alignment on price config

* Changes to support RC upgraders
2025-11-13 15:10:54 +01:00

127 lines
3.4 KiB
C++

/**
* @copyright Utilitech AS 2023
* License: Fair Source
*
*/
#include "EntsoeA44Parser.h"
#include "HardwareSerial.h"
EntsoeA44Parser::EntsoeA44Parser(PricesContainer *container) {
this->container = container;
}
EntsoeA44Parser::~EntsoeA44Parser() {
}
int EntsoeA44Parser::available() {
return 0;
}
int EntsoeA44Parser::read() {
return 0;
}
int EntsoeA44Parser::peek() {
return 0;
}
void EntsoeA44Parser::flush() {
}
size_t EntsoeA44Parser::write(const uint8_t *buffer, size_t size) {
for(size_t i = 0; i < size; i++) {
write(buffer[i]);
}
return size;
}
size_t EntsoeA44Parser::write(uint8_t byte) {
if(pos >= 64) pos = 0;
if(docPos == DOCPOS_CURRENCY) {
buf[pos++] = byte;
if(pos == 3) {
buf[pos++] = '\0';
container->setCurrency(buf);
docPos = DOCPOS_SEEK;
pos = 0;
}
} else if(docPos == DOCPOS_MEASUREMENTUNIT) {
buf[pos++] = byte;
if(pos == 3) {
buf[pos++] = '\0';
if(strcmp_P(buf, PSTR("MWH"))) multiplier = 0.001;
docPos = DOCPOS_SEEK;
pos = 0;
}
} else if(docPos == DOCPOS_POSITION) {
if(byte == '<') {
buf[pos] = '\0';
long pn = String(buf).toInt() - 1;
if(pn < container->getNumberOfPoints()) {
pointNum = pn;
}
docPos = DOCPOS_SEEK;
pos = 0;
} else {
buf[pos++] = byte;
}
} else if(docPos == DOCPOS_AMOUNT) {
if(byte == '<') {
buf[pos] = '\0';
float val = String(buf).toFloat();
for(uint8_t i = pointNum; i < container->getNumberOfPoints(); i++) {
container->setPrice(i, val * multiplier, PRICE_DIRECTION_IMPORT);
}
docPos = DOCPOS_SEEK;
pos = 0;
} else {
buf[pos++] = byte;
}
} else if(docPos == DOCPOS_RESOLUTION) {
if(byte == '<') {
buf[pos] = '\0';
// This happens if there are two time series in the XML. We are only interrested in the first one, so we ignore the rest of the document
if(container->hasPrice(0, PRICE_DIRECTION_IMPORT)) return 1;
if(strcmp_P(buf, PSTR("PT15M"))) {
container->setup(15, 100, false);
} else if(strcmp_P(buf, PSTR("PT60M"))) {
container->setup(60, 25, false);
}
docPos = DOCPOS_SEEK;
pos = 0;
} else {
buf[pos++] = byte;
}
} else {
if(pos == 0) {
if(byte == '<') {
buf[pos++] = byte;
}
} else if(byte == '>') {
buf[pos++] = byte;
buf[pos] = '\0';
if(strcmp_P(buf, PSTR("<currency_Unit.name>")) == 0) {
docPos = DOCPOS_CURRENCY;
} else if(strcmp(buf, PSTR("<price_Measure_Unit.name>")) == 0) {
docPos = DOCPOS_MEASUREMENTUNIT;
} else if(strcmp(buf, PSTR("<position>")) == 0) {
docPos = DOCPOS_POSITION;
pointNum = 0xFF;
} else if(strcmp(buf, PSTR("<price.amount>")) == 0) {
docPos = DOCPOS_AMOUNT;
} else if(strcmp(buf, PSTR("<resolution>")) == 0) {
docPos = DOCPOS_RESOLUTION;
}
pos = 0;
} else {
buf[pos++] = byte;
}
}
return 1;
}