Added hour to tariff peaks (#1028)

* Added hour to tariff peaks

* Some adjustments
This commit is contained in:
Gunnar Skjold 2025-10-02 13:51:58 +02:00 committed by GitHub
parent c307103605
commit 46cd8c6e68
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 159 additions and 151 deletions

View File

@ -13,6 +13,12 @@
#include "PriceService.h"
struct EnergyAccountingPeak {
uint8_t day;
uint8_t hour;
uint16_t value;
};
struct EnergyAccountingPeak6 {
uint8_t day;
uint16_t value;
};
@ -32,34 +38,19 @@ struct EnergyAccountingData {
EnergyAccountingPeak peaks[5];
};
struct EnergyAccountingData5 {
struct EnergyAccountingData6 {
uint8_t version;
uint8_t month;
uint16_t costYesterday;
uint16_t costThisMonth;
uint16_t costLastMonth;
uint16_t incomeYesterday;
uint16_t incomeThisMonth;
uint16_t incomeLastMonth;
EnergyAccountingPeak peaks[5];
};
struct EnergyAccountingData4 {
uint8_t version;
uint8_t month;
uint16_t costYesterday;
uint16_t costThisMonth;
uint16_t costLastMonth;
EnergyAccountingPeak peaks[5];
};
struct EnergyAccountingData2 {
uint8_t version;
uint8_t month;
uint16_t maxHour;
uint16_t costYesterday;
uint16_t costThisMonth;
uint16_t costLastMonth;
int32_t costYesterday;
int32_t costThisMonth;
int32_t costLastMonth;
int32_t incomeYesterday;
int32_t incomeThisMonth;
int32_t incomeLastMonth;
uint32_t lastMonthImport;
uint32_t lastMonthExport;
uint8_t lastMonthAccuracy;
EnergyAccountingPeak6 peaks[5];
};
struct EnergyAccountingRealtimeData {
@ -142,7 +133,7 @@ private:
String currency = "";
void calcDayCost();
bool updateMax(uint16_t val, uint8_t day);
bool updateMax(uint16_t val, uint8_t day, uint8_t hour);
};
#endif

View File

@ -72,15 +72,15 @@ bool EnergyAccounting::update(AmsData* amsData) {
this->realtimeData->currentHour = local.Hour;
this->realtimeData->currentDay = local.Day;
if(!load()) {
data = { 6, local.Month,
data = { 7, local.Month,
0, 0, 0, // Cost
0, 0, 0, // Income
0, 0, 0, // Last month import, export and accuracy
0, 0, // Peak 1
0, 0, // Peak 2
0, 0, // Peak 3
0, 0, // Peak 4
0, 0 // Peak 5
0, 0, 0, // Peak 1
0, 0, 0, // Peak 2
0, 0, 0, // Peak 3
0, 0, 0, // Peak 4
0, 0, 0 // Peak 5
};
}
init = true;
@ -97,7 +97,7 @@ bool EnergyAccounting::update(AmsData* amsData) {
uint16_t val = round(ds->getHourImport(oneHrAgo.Hour) / 10.0);
breakTime(tz->toLocal(now-3600), oneHrAgoLocal);
ret |= updateMax(val, oneHrAgoLocal.Day);
ret |= updateMax(val, oneHrAgoLocal.Day, oneHrAgoLocal.Hour);
this->realtimeData->currentHour = local.Hour; // Need to be defined here so that day cost is correctly calculated
if(local.Hour > 0) {
@ -407,85 +407,29 @@ bool EnergyAccounting::load() {
char buf[file.size()];
file.readBytes(buf, file.size());
if(buf[0] == 6) {
if(buf[0] == 7) {
EnergyAccountingData* data = (EnergyAccountingData*) buf;
memcpy(&this->data, data, sizeof(this->data));
ret = true;
} else if(buf[0] == 5) {
EnergyAccountingData5* data = (EnergyAccountingData5*) buf;
this->data = { 6, data->month,
((uint32_t) data->costYesterday) * 10,
((uint32_t) data->costThisMonth) * 100,
((uint32_t) data->costLastMonth) * 100,
((uint32_t) data->incomeYesterday) * 10,
((uint32_t) data->incomeThisMonth) * 100,
((uint32_t) data->incomeLastMonth) * 100,
0,0,0, // Last month import, export and accuracy
data->peaks[0].day, data->peaks[0].value,
data->peaks[1].day, data->peaks[1].value,
data->peaks[2].day, data->peaks[2].value,
data->peaks[3].day, data->peaks[3].value,
data->peaks[4].day, data->peaks[4].value
};
ret = true;
} else if(buf[0] == 4) {
EnergyAccountingData4* data = (EnergyAccountingData4*) buf;
this->data = { 5, data->month,
((uint32_t) data->costYesterday) * 10,
((uint32_t) data->costThisMonth) * 100,
((uint32_t) data->costLastMonth) * 100,
0,0,0, // Income from production
0,0,0, // Last month import, export and accuracy
data->peaks[0].day, data->peaks[0].value,
data->peaks[1].day, data->peaks[1].value,
data->peaks[2].day, data->peaks[2].value,
data->peaks[3].day, data->peaks[3].value,
data->peaks[4].day, data->peaks[4].value
};
ret = true;
} else if(buf[0] == 3) {
EnergyAccountingData* data = (EnergyAccountingData*) buf;
this->data = { 5, data->month,
data->costYesterday * 10,
} else if(buf[0] == 6) {
EnergyAccountingData6* data = (EnergyAccountingData6*) buf;
this->data = { 7, data->month,
data->costYesterday,
data->costThisMonth,
data->costLastMonth,
0,0,0, // Income from production
0,0,0, // Last month import, export and accuracy
data->peaks[0].day, data->peaks[0].value,
data->peaks[1].day, data->peaks[1].value,
data->peaks[2].day, data->peaks[2].value,
data->peaks[3].day, data->peaks[3].value,
data->peaks[4].day, data->peaks[4].value
data->incomeYesterday,
data->incomeThisMonth,
data->incomeLastMonth,
data->lastMonthImport,
data->lastMonthExport,
data->lastMonthAccuracy,
data->peaks[0].day, 0, data->peaks[0].value,
data->peaks[1].day, 0, data->peaks[1].value,
data->peaks[2].day, 0, data->peaks[2].value,
data->peaks[3].day, 0, data->peaks[3].value,
data->peaks[4].day, 0, data->peaks[4].value
};
ret = true;
} else {
data = { 5, 0,
0, 0, 0, // Cost
0,0,0, // Income from production
0,0,0, // Last month import, export and accuracy
0, 0, // Peak 1
0, 0, // Peak 2
0, 0, // Peak 3
0, 0, // Peak 4
0, 0 // Peak 5
};
if(buf[0] == 2) {
EnergyAccountingData2* data = (EnergyAccountingData2*) buf;
this->data.month = data->month;
this->data.costYesterday = data->costYesterday * 10;
this->data.costThisMonth = data->costThisMonth;
this->data.costLastMonth = data->costLastMonth;
uint8_t b = 0;
for(uint8_t i = sizeof(this->data); i < file.size(); i+=2) {
this->data.peaks[b].day = b;
memcpy(&this->data.peaks[b].value, buf+i, 2);
b++;
if(b >= config->hours || b >= 5) break;
}
ret = true;
} else {
ret = false;
}
}
file.close();
@ -518,11 +462,12 @@ void EnergyAccounting::setData(EnergyAccountingData& data) {
this->data = data;
}
bool EnergyAccounting::updateMax(uint16_t val, uint8_t day) {
bool EnergyAccounting::updateMax(uint16_t val, uint8_t day, uint8_t hour) {
for(uint8_t i = 0; i < 5; i++) {
if(data.peaks[i].day == day || data.peaks[i].day == 0) {
if(val > data.peaks[i].value) {
data.peaks[i].day = day;
data.peaks[i].hour = hour;
data.peaks[i].value = val;
return true;
}

File diff suppressed because one or more lines are too long

View File

@ -61,7 +61,7 @@
{#if !isNaN(yScale(tick.value))}
<g class="tick tick-{tick.value} tick-{tick.color}" transform="translate(0, {yScale(tick.value)})">
<line x2="100%"></line>
<text y="-4" x={tick.align == 'right' ? '85%' : ''}>{tick.label}</text>
<text y="-4" x={tick.align == 'right' ? '90%' : ''}>{tick.label}</text>
</g>
{/if}
{/each}

View File

@ -128,7 +128,7 @@
{/if}
{#if uiVisibility(sysinfo.ui.t, data.pr && (data.pr.startsWith("NO") || data.pr.startsWith("10YNO") || data.pr.startsWith('10Y1001A1001A4')))}
<div class="cnt h-64">
<TariffPeakChart title={translations.dashboard?.tariffpeak ?? "Tariff peaks"} tariffData={tariffData} translations={translations}/>
<TariffPeakChart title={translations.dashboard?.tariffpeak ?? "Tariff peaks"} tariffData={tariffData} realtime={data.ea} translations={translations}/>
</div>
{/if}
{#if uiVisibility(sysinfo.ui.l, data.hm == 1)}

View File

@ -1,5 +1,5 @@
<script>
import { zeropad } from './Helpers.js';
import { ampcol, zeropad } from './Helpers.js';
import BarChart from './BarChart.svelte';
export let title;
@ -12,6 +12,7 @@
let min = 0;
export let tariffData;
export let realtime;
$: {
let i = 0;
@ -24,16 +25,36 @@
label: 0
});
console.log(realtime);
if(tariffData && !isNaN(realtime?.h?.u)) {
points.push({
label: realtime.h.u.toFixed(2),
value: realtime.h.u,
title: realtime.h.u.toFixed(2) + ' kWh',
color: ampcol(realtime.h.u/tariffData.c*100.0)
});
xTicks.push({
label: translations.common?.now ?? "Now"
});
}
if(tariffData && tariffData.p) {
for(i = 0; i < tariffData.p.length; i++) {
let peak = tariffData.p[i];
let daylabel = peak.d > 0 ? zeropad(peak.d) + "." + (translations.months ? translations.months?.[new Date().getMonth()] : zeropad(new Date().getMonth()+1)) : "-";
let title = daylabel;
if(!isNaN(peak.h))
title = title + ' ' + zeropad(peak.h) + ':00';
title = title + ': ' + peak.v.toFixed(2) + ' kWh';
points.push({
label: peak.v.toFixed(2),
value: peak.v,
title: title,
color: dark ? '#5c2da5' : '#7c3aed'
});
xTicks.push({
label: peak.d > 0 ? zeropad(peak.d) + "." + (translations.months ? translations.months?.[new Date().getMonth()] : zeropad(new Date().getMonth()+1)) : "-"
label: daylabel
})
max = Math.max(max, peak.v);
}
@ -71,7 +92,7 @@
config = {
title: title,
dark: document.documentElement.classList.contains('dark'),
padding: { top: 20, right: 35, bottom: 20, left: 35 },
padding: { top: 20, right: 20, bottom: 20, left: 20 },
y: {
min: min,
max: max,

View File

@ -17,27 +17,27 @@ export default defineConfig({
plugins: [svelte()],
server: {
proxy: {
"/data.json": "http://192.168.21.192",
"/energyprice.json": "http://192.168.21.192",
"/dayplot.json": "http://192.168.21.192",
"/monthplot.json": "http://192.168.21.192",
"/temperature.json": "http://192.168.21.192",
"/sysinfo.json": "http://192.168.21.192",
"/configuration.json": "http://192.168.21.192",
"/tariff.json": "http://192.168.21.192",
"/realtime.json": "http://192.168.21.192",
"/priceconfig.json": "http://192.168.21.192",
"/translations.json": "http://192.168.21.192",
"/cloudkey.json": "http://192.168.21.192",
"/wifiscan.json": "http://192.168.21.192",
"/save": "http://192.168.21.192",
"/reboot": "http://192.168.21.192",
"/configfile": "http://192.168.21.192",
"/upgrade": "http://192.168.21.192",
"/mqtt-ca": "http://192.168.21.192",
"/mqtt-cert": "http://192.168.21.192",
"/mqtt-key": "http://192.168.21.192",
"/logo.svg": "http://192.168.21.192",
"/data.json": "http://192.168.21.122",
"/energyprice.json": "http://192.168.21.122",
"/dayplot.json": "http://192.168.21.122",
"/monthplot.json": "http://192.168.21.122",
"/temperature.json": "http://192.168.21.122",
"/sysinfo.json": "http://192.168.21.122",
"/configuration.json": "http://192.168.21.122",
"/tariff.json": "http://192.168.21.122",
"/realtime.json": "http://192.168.21.122",
"/priceconfig.json": "http://192.168.21.122",
"/translations.json": "http://192.168.21.122",
"/cloudkey.json": "http://192.168.21.122",
"/wifiscan.json": "http://192.168.21.122",
"/save": "http://192.168.21.122",
"/reboot": "http://192.168.21.122",
"/configfile": "http://192.168.21.122",
"/upgrade": "http://192.168.21.122",
"/mqtt-ca": "http://192.168.21.122",
"/mqtt-cert": "http://192.168.21.122",
"/mqtt-key": "http://192.168.21.122",
"/logo.svg": "http://192.168.21.122",
}
}
})

View File

@ -2097,8 +2097,9 @@ void AmsWebServer::tariffJson() {
String peaks;
for(uint8_t x = 0;x < min((uint8_t) 5, eac->hours); x++) {
EnergyAccountingPeak peak = ea->getPeak(x+1);
int len = snprintf_P(buf, BufferSize, PSTR("{\"d\":%d,\"v\":%.2f}"),
int len = snprintf_P(buf, BufferSize, PSTR("{\"d\":%d,\"h\":%d,\"v\":%.2f}"),
peak.day,
peak.hour,
peak.value / 100.0
);
buf[len] = '\0';
@ -2592,7 +2593,7 @@ void AmsWebServer::configFileDownload() {
EnergyAccountingConfig eac;
config->getEnergyAccountingConfig(eac);
EnergyAccountingData ead = ea->getData();
server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("energyaccounting %d %d %.2f %.2f %.2f %.2f %.2f %.2f %d %.2f %d %.2f %d %.2f %d %.2f %d %.2f %.2f %.2f"),
server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("energyaccounting %d %d %.2f %.2f %.2f %.2f %.2f %.2f %d %d %.2f %d %d %.2f %d %d %.2f %d %d %.2f %d %d %.2f %.2f %.2f"),
ead.version,
ead.month,
ea->getCostYesterday(),
@ -2602,14 +2603,19 @@ void AmsWebServer::configFileDownload() {
ea->getIncomeThisMonth(),
ea->getIncomeLastMonth(),
ead.peaks[0].day,
ead.peaks[0].hour,
ead.peaks[0].value / 100.0,
ead.peaks[1].day,
ead.peaks[1].hour,
ead.peaks[1].value / 100.0,
ead.peaks[2].day,
ead.peaks[2].hour,
ead.peaks[2].value / 100.0,
ead.peaks[3].day,
ead.peaks[3].hour,
ead.peaks[3].value / 100.0,
ead.peaks[4].day,
ead.peaks[4].hour,
ead.peaks[4].value / 100.0,
ea->getUseLastMonth(),
ea->getProducedLastMonth()

View File

@ -2164,11 +2164,11 @@ void configFileParse() {
0, 0, 0, // Cost
0, 0, 0, // Income
0, 0, 0, // Last month import, export and accuracy
0, 0, // Peak 1
0, 0, // Peak 2
0, 0, // Peak 3
0, 0, // Peak 4
0, 0 // Peak 5
0, 0, 0, // Peak 1
0, 0, 0, // Peak 2
0, 0, 0, // Peak 3
0, 0, 0, // Peak 4
0, 0, 0 // Peak 5
};
uint8_t peak = 0;
uint64_t totalImport = 0, totalExport = 0;
@ -2184,7 +2184,7 @@ void configFileParse() {
} else if(i == 2) {
float val = String(pch).toFloat();
if(val > 0.0) {
ead.peaks[0] = { 1, (uint16_t) (val*100) };
ead.peaks[0] = { 1, 0, (uint16_t) (val*100) };
}
} else if(i == 3) {
float val = String(pch).toFloat();
@ -2196,7 +2196,6 @@ void configFileParse() {
float val = String(pch).toFloat();
ead.costLastMonth = val * 100;
} else if(i >= 6 && i < 18) {
uint8_t hour = i-6;
{
long val = String(pch).toInt();
ead.peaks[peak].day = val;
@ -2209,6 +2208,47 @@ void configFileParse() {
}
peak++;
}
} else if(ead.version < 7) {
if(i == 1) {
long val = String(pch).toInt();
ead.month = val;
} else if(i == 2) {
float val = String(pch).toFloat();
ead.costYesterday = val * 100;
} else if(i == 3) {
float val = String(pch).toFloat();
ead.costThisMonth = val * 100;
} else if(i == 4) {
float val = String(pch).toFloat();
ead.costLastMonth = val * 100;
} else if(i == 5) {
float val = String(pch).toFloat();
ead.incomeYesterday= val * 100;
} else if(i == 6) {
float val = String(pch).toFloat();
ead.incomeThisMonth = val * 100;
} else if(i == 7) {
float val = String(pch).toFloat();
ead.incomeLastMonth = val * 100;
} else if(i >= 8 && i < 18) {
{
long val = String(pch).toInt();
ead.peaks[peak].day = val;
}
pch = strtok (NULL, " ");
i++;
{
float val = String(pch).toFloat();
ead.peaks[peak].value = val * 100;
}
peak++;
} else if(i == 18) {
float val = String(pch).toFloat();
totalImport = val * 1000;
} else if(i == 19) {
float val = String(pch).toFloat();
totalExport = val * 1000;
}
} else {
if(i == 1) {
long val = String(pch).toInt();
@ -2231,14 +2271,19 @@ void configFileParse() {
} else if(i == 7) {
float val = String(pch).toFloat();
ead.incomeLastMonth = val * 100;
} else if(i >= 8 && i < 18) {
uint8_t hour = i-8;
} else if(i >= 8 && i < 23) {
{
long val = String(pch).toInt();
ead.peaks[peak].day = val;
}
pch = strtok (NULL, " ");
i++;
{
long val = String(pch).toInt();
ead.peaks[peak].hour = val;
}
pch = strtok (NULL, " ");
i++;
{
float val = String(pch).toFloat();
ead.peaks[peak].value = val * 100;
@ -2265,7 +2310,7 @@ void configFileParse() {
ead.lastMonthImport = importUpdate;
ead.lastMonthExport = exportUpdate;
ead.version = 6;
ead.version = 7;
ea.setData(ead);
sEa = true;
}