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
This commit is contained in:
Gunnar Skjold
2025-11-13 15:10:54 +01:00
committed by GitHub
parent ffd8d46f2e
commit c648546b61
44 changed files with 1073 additions and 637 deletions

View File

@@ -15,28 +15,23 @@
#define DOCPOS_MEASUREMENTUNIT 2
#define DOCPOS_POSITION 3
#define DOCPOS_AMOUNT 4
#define DOCPOS_RESOLUTION 5
class EntsoeA44Parser: public Stream {
public:
EntsoeA44Parser();
EntsoeA44Parser(PricesContainer *container);
virtual ~EntsoeA44Parser();
char* getCurrency();
char* getMeasurementUnit();
float getPoint(uint8_t position);
int available();
int read();
int peek();
void flush();
size_t write(const uint8_t *buffer, size_t size);
size_t write(uint8_t);
void get(PricesContainer*);
private:
char currency[4];
char measurementUnit[4];
float points[25];
PricesContainer *container;
float multiplier = 1.0;
char buf[64];
uint8_t pos = 0;

View File

@@ -27,10 +27,6 @@
#define SSL_BUF_SIZE 512
#define PRICE_DIRECTION_IMPORT 0x01
#define PRICE_DIRECTION_EXPORT 0x02
#define PRICE_DIRECTION_BOTH 0x03
#define PRICE_DAY_MO 0x01
#define PRICE_DAY_TU 0x02
#define PRICE_DAY_WE 0x04
@@ -57,10 +53,13 @@ struct PriceConfig {
uint8_t end_dayofmonth;
};
struct PricePart {
char name[32];
char description[32];
uint32_t value;
struct AmsPriceV2Header {
char currency[4];
char measurementUnit[4];
char source[4];
uint8_t resolutionInMinutes;
bool differentExportPrices;
uint8_t numberOfPoints;
};
class PriceService {
@@ -78,17 +77,25 @@ public:
char* getCurrency();
char* getArea();
char* getSource();
float getValueForHour(uint8_t direction, int8_t hour);
float getValueForHour(uint8_t direction, time_t ts, int8_t hour);
float getEnergyPriceForHour(uint8_t direction, time_t ts, int8_t hour);
uint8_t getResolutionInMinutes();
uint8_t getNumberOfPointsAvailable();
uint8_t getCurrentPricePointIndex();
bool isExportPricesDifferentFromImport();
bool hasPrice() { return hasPrice(PRICE_DIRECTION_IMPORT); }
bool hasPrice(uint8_t direction) { return getCurrentPrice(direction) != PRICE_NO_VALUE; }
bool hasPricePoint(uint8_t direction, int8_t point) { return getPricePoint(direction, point) != PRICE_NO_VALUE; }
float getCurrentPrice(uint8_t direction);
float getPricePoint(uint8_t direction, uint8_t point);
float getPriceForRelativeHour(uint8_t direction, int8_t hour); // If not 60min interval, average
std::vector<PriceConfig>& getPriceConfig();
void setPriceConfig(uint8_t index, PriceConfig &priceConfig);
void cropPriceConfig(uint8_t size);
PricePart getPricePart(uint8_t index);
int16_t getLastError();
bool load();
@@ -103,7 +110,7 @@ private:
PriceServiceConfig* config = NULL;
HTTPClient* http = NULL;
uint8_t currentDay = 0, currentHour = 0;
uint8_t currentDay = 0, currentPricePoint = 0;
uint8_t tomorrowFetchMinute = 15; // How many minutes over 13:00 should it fetch prices
uint8_t nextFetchDelayMinutes = 15;
uint64_t lastTodayFetch = 0;
@@ -132,5 +139,7 @@ private:
bool retrieve(const char* url, Stream* doc);
float getCurrencyMultiplier(const char* from, const char* to, time_t t);
bool timeIsInPeriod(tmElements_t tm, PriceConfig pc);
float getFixedPrice(uint8_t direction, int8_t hour);
float getEnergyPricePoint(uint8_t direction, uint8_t point);
};
#endif

View File

@@ -4,15 +4,43 @@
*
*/
#include <stdint.h>
#ifndef _PRICESCONTAINER_H
#define _PRICESCONTAINER_H
#define PRICE_NO_VALUE -127
#define PRICE_DIRECTION_IMPORT 0x01
#define PRICE_DIRECTION_EXPORT 0x02
#define PRICE_DIRECTION_BOTH 0x03
struct PricesContainer {
char currency[4];
char measurementUnit[4];
int32_t points[25];
class PricesContainer {
public:
PricesContainer(char* source);
void setup(uint8_t resolutionInMinutes, uint8_t numberOfPoints, bool differentExportPrices);
char* getSource();
void setCurrency(char* currency);
char* getCurrency();
bool isExportPricesDifferentFromImport() {
return differentExportPrices;
}
uint8_t getResolutionInMinutes();
uint8_t getNumberOfPoints();
void setPrice(uint8_t point, float value, uint8_t direction);
bool hasPrice(uint8_t point, uint8_t direction);
float getPrice(uint8_t point, uint8_t direction); // int32_t / 10_000
private:
char source[4];
char currency[4];
uint8_t resolutionInMinutes;
bool differentExportPrices;
uint8_t numberOfPoints;
int32_t *points;
};
#endif