mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-02-26 17:04:20 +00:00
Added last month in realtime data. Also increased precision on realtime data
This commit is contained in:
@@ -65,7 +65,6 @@ bool AmsDataStorage::update(AmsData* data) {
|
||||
day.activeImport = importCounter;
|
||||
day.activeExport = exportCounter;
|
||||
day.lastMeterReadTime = now;
|
||||
return true;
|
||||
} else if(day.activeImport == 0 || now - day.lastMeterReadTime > 86400) {
|
||||
day.activeImport = importCounter;
|
||||
day.activeExport = exportCounter;
|
||||
|
||||
@@ -12,6 +12,21 @@ struct EnergyAccountingPeak {
|
||||
};
|
||||
|
||||
struct EnergyAccountingData {
|
||||
uint8_t version;
|
||||
uint8_t month;
|
||||
uint32_t costYesterday;
|
||||
uint32_t costThisMonth;
|
||||
uint32_t costLastMonth;
|
||||
uint32_t incomeYesterday;
|
||||
uint32_t incomeThisMonth;
|
||||
uint32_t incomeLastMonth;
|
||||
uint32_t lastMonthImport;
|
||||
uint32_t lastMonthExport;
|
||||
uint8_t lastMonthAccuracy;
|
||||
EnergyAccountingPeak peaks[5];
|
||||
};
|
||||
|
||||
struct EnergyAccountingData5 {
|
||||
uint8_t version;
|
||||
uint8_t month;
|
||||
uint16_t costYesterday;
|
||||
@@ -32,7 +47,7 @@ struct EnergyAccountingData4 {
|
||||
EnergyAccountingPeak peaks[5];
|
||||
};
|
||||
|
||||
struct EnergyAccountingData1 {
|
||||
struct EnergyAccountingData2 {
|
||||
uint8_t version;
|
||||
uint8_t month;
|
||||
uint16_t maxHour;
|
||||
@@ -57,22 +72,24 @@ public:
|
||||
float getUseThisHour();
|
||||
float getUseToday();
|
||||
float getUseThisMonth();
|
||||
float getUseLastMonth();
|
||||
|
||||
float getProducedThisHour();
|
||||
float getProducedToday();
|
||||
float getProducedThisMonth();
|
||||
float getProducedLastMonth();
|
||||
|
||||
float getCostThisHour();
|
||||
float getCostToday();
|
||||
float getCostYesterday();
|
||||
float getCostThisMonth();
|
||||
uint16_t getCostLastMonth();
|
||||
float getCostLastMonth();
|
||||
|
||||
float getIncomeThisHour();
|
||||
float getIncomeToday();
|
||||
float getIncomeYesterday();
|
||||
float getIncomeThisMonth();
|
||||
uint16_t getIncomeLastMonth();
|
||||
float getIncomeLastMonth();
|
||||
|
||||
float getMonthMax();
|
||||
uint8_t getCurrentThreshold();
|
||||
@@ -95,7 +112,7 @@ private:
|
||||
uint8_t currentHour = 0, currentDay = 0, currentThresholdIdx = 0;
|
||||
float use = 0, costHour = 0, costDay = 0;
|
||||
float produce = 0, incomeHour = 0, incomeDay = 0;
|
||||
EnergyAccountingData data = { 0, 0, 0, 0, 0, 0 };
|
||||
EnergyAccountingData data = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
float fixedPrice = 0;
|
||||
String currency = "";
|
||||
|
||||
|
||||
@@ -49,9 +49,10 @@ bool EnergyAccounting::update(AmsData* amsData) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("(EnergyAccounting) Initializing data at %lu\n"), (int32_t) now);
|
||||
if(!load()) {
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("(EnergyAccounting) Unable to load existing data\n"));
|
||||
data = { 5, local.Month,
|
||||
data = { 6, 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
|
||||
@@ -62,8 +63,8 @@ bool EnergyAccounting::update(AmsData* amsData) {
|
||||
for(uint8_t i = 0; i < 5; i++) {
|
||||
debugger->printf_P(PSTR("(EnergyAccounting) Peak hour from day %d: %d\n"), data.peaks[i].day, data.peaks[i].value*10);
|
||||
}
|
||||
debugger->printf_P(PSTR("(EnergyAccounting) Loaded cost yesterday: %.2f, this month: %d, last month: %d\n"), data.costYesterday / 10.0, data.costThisMonth, data.costLastMonth);
|
||||
debugger->printf_P(PSTR("(EnergyAccounting) Loaded income yesterday: %.2f, this month: %d, last month: %d\n"), data.incomeYesterday / 10.0, data.incomeThisMonth, data.incomeLastMonth);
|
||||
debugger->printf_P(PSTR("(EnergyAccounting) Loaded cost yesterday: %.2f, this month: %d, last month: %d\n"), data.costYesterday / 100.0, data.costThisMonth / 100.0, data.costLastMonth / 100.0);
|
||||
debugger->printf_P(PSTR("(EnergyAccounting) Loaded income yesterday: %.2f, this month: %d, last month: %d\n"), data.incomeYesterday / 100.0, data.incomeThisMonth / 100.0, data.incomeLastMonth / 100.0);
|
||||
}
|
||||
init = true;
|
||||
}
|
||||
@@ -94,14 +95,15 @@ bool EnergyAccounting::update(AmsData* amsData) {
|
||||
costHour = 0;
|
||||
incomeHour = 0;
|
||||
|
||||
uint8_t prevDay = currentDay;
|
||||
if(local.Day != currentDay) {
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("(EnergyAccounting) New day %d\n"), local.Day);
|
||||
data.costYesterday = costDay * 10;
|
||||
data.costThisMonth += costDay;
|
||||
data.costYesterday = costDay * 100;
|
||||
data.costThisMonth += costDay * 100;
|
||||
costDay = 0;
|
||||
|
||||
data.incomeYesterday = incomeDay * 10;
|
||||
data.incomeThisMonth += incomeDay;
|
||||
data.incomeYesterday = incomeDay * 100;
|
||||
data.incomeThisMonth += incomeDay * 100;
|
||||
incomeDay = 0;
|
||||
|
||||
currentDay = local.Day;
|
||||
@@ -117,6 +119,21 @@ bool EnergyAccounting::update(AmsData* amsData) {
|
||||
for(uint8_t i = 0; i < 5; i++) {
|
||||
data.peaks[i] = { 0, 0 };
|
||||
}
|
||||
|
||||
uint64_t totalImport = 0, totalExport = 0;
|
||||
for(uint8_t i = 1; i <= prevDay; i++) {
|
||||
totalImport += ds->getDayImport(i);
|
||||
totalExport += ds->getDayExport(i);
|
||||
}
|
||||
uint8_t accuracy;
|
||||
uint64_t importUpdate = totalImport, exportUpdate = totalExport;
|
||||
while(totalImport > UINT32_MAX || totalExport > UINT32_MAX) {
|
||||
accuracy++;
|
||||
importUpdate = totalImport / pow(10, accuracy);
|
||||
exportUpdate = totalExport / pow(10, accuracy);
|
||||
}
|
||||
data.lastMonthAccuracy = accuracy;
|
||||
|
||||
data.month = local.Month;
|
||||
currentThresholdIdx = 0;
|
||||
ret = true;
|
||||
@@ -203,12 +220,16 @@ float EnergyAccounting::getUseThisMonth() {
|
||||
time_t now = time(nullptr);
|
||||
if(now < FirmwareVersion::BuildEpoch) return 0.0;
|
||||
float ret = 0;
|
||||
for(uint8_t i = 0; i < currentDay; i++) {
|
||||
for(uint8_t i = 1; i < currentDay; i++) {
|
||||
ret += ds->getDayImport(i) / 1000.0;
|
||||
}
|
||||
return ret + getUseToday();
|
||||
}
|
||||
|
||||
float EnergyAccounting::getUseLastMonth() {
|
||||
return (data.lastMonthImport * pow(10, data.lastMonthAccuracy)) / 1000;
|
||||
}
|
||||
|
||||
float EnergyAccounting::getProducedThisHour() {
|
||||
return produce;
|
||||
}
|
||||
@@ -230,12 +251,15 @@ float EnergyAccounting::getProducedThisMonth() {
|
||||
time_t now = time(nullptr);
|
||||
if(now < FirmwareVersion::BuildEpoch) return 0.0;
|
||||
float ret = 0;
|
||||
for(uint8_t i = 0; i < currentDay; i++) {
|
||||
for(uint8_t i = 1; i < currentDay; i++) {
|
||||
ret += ds->getDayExport(i) / 1000.0;
|
||||
}
|
||||
return ret + getProducedToday();
|
||||
}
|
||||
|
||||
float EnergyAccounting::getProducedLastMonth() {
|
||||
return (data.lastMonthExport * pow(10, data.lastMonthAccuracy)) / 1000;
|
||||
}
|
||||
|
||||
float EnergyAccounting::getCostThisHour() {
|
||||
return costHour;
|
||||
@@ -246,15 +270,15 @@ float EnergyAccounting::getCostToday() {
|
||||
}
|
||||
|
||||
float EnergyAccounting::getCostYesterday() {
|
||||
return data.costYesterday / 10.0;
|
||||
return data.costYesterday / 100.0;
|
||||
}
|
||||
|
||||
float EnergyAccounting::getCostThisMonth() {
|
||||
return data.costThisMonth + getCostToday();
|
||||
return (data.costThisMonth / 100.0) + getCostToday();
|
||||
}
|
||||
|
||||
uint16_t EnergyAccounting::getCostLastMonth() {
|
||||
return data.costLastMonth;
|
||||
float EnergyAccounting::getCostLastMonth() {
|
||||
return data.costLastMonth / 100.0;
|
||||
}
|
||||
|
||||
float EnergyAccounting::getIncomeThisHour() {
|
||||
@@ -266,15 +290,15 @@ float EnergyAccounting::getIncomeToday() {
|
||||
}
|
||||
|
||||
float EnergyAccounting::getIncomeYesterday() {
|
||||
return data.incomeYesterday / 10.0;
|
||||
return data.incomeYesterday / 100.0;
|
||||
}
|
||||
|
||||
float EnergyAccounting::getIncomeThisMonth() {
|
||||
return data.incomeThisMonth + getIncomeToday();
|
||||
return (data.incomeThisMonth / 100.0) + getIncomeToday();
|
||||
}
|
||||
|
||||
uint16_t EnergyAccounting::getIncomeLastMonth() {
|
||||
return data.incomeLastMonth;
|
||||
float EnergyAccounting::getIncomeLastMonth() {
|
||||
return data.incomeLastMonth / 100.0;
|
||||
}
|
||||
|
||||
uint8_t EnergyAccounting::getCurrentThreshold() {
|
||||
@@ -364,17 +388,35 @@ bool EnergyAccounting::load() {
|
||||
file.readBytes(buf, file.size());
|
||||
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("(EnergyAccounting) Data version %d\n"), buf[0]);
|
||||
if(buf[0] == 5) {
|
||||
if(buf[0] == 6) {
|
||||
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,
|
||||
data->costYesterday,
|
||||
data->costThisMonth,
|
||||
data->costLastMonth,
|
||||
((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,
|
||||
@@ -385,8 +427,11 @@ bool EnergyAccounting::load() {
|
||||
} else if(buf[0] == 3) {
|
||||
EnergyAccountingData* data = (EnergyAccountingData*) buf;
|
||||
this->data = { 5, data->month,
|
||||
(uint16_t) (data->costYesterday / 10), (uint16_t) (data->costThisMonth / 100), (uint16_t) (data->costLastMonth / 100),
|
||||
data->costYesterday * 10,
|
||||
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,
|
||||
@@ -398,6 +443,7 @@ bool EnergyAccounting::load() {
|
||||
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
|
||||
@@ -405,11 +451,11 @@ bool EnergyAccounting::load() {
|
||||
0, 0 // Peak 5
|
||||
};
|
||||
if(buf[0] == 2) {
|
||||
EnergyAccountingData1* data = (EnergyAccountingData1*) buf;
|
||||
EnergyAccountingData2* data = (EnergyAccountingData2*) buf;
|
||||
this->data.month = data->month;
|
||||
this->data.costYesterday = (uint16_t) (data->costYesterday / 10);
|
||||
this->data.costThisMonth = (uint16_t) (data->costThisMonth / 100);
|
||||
this->data.costLastMonth = (uint16_t) (data->costLastMonth / 100);
|
||||
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;
|
||||
@@ -418,15 +464,6 @@ bool EnergyAccounting::load() {
|
||||
if(b >= config->hours || b >= 5) break;
|
||||
}
|
||||
ret = true;
|
||||
} else if(buf[0] == 1) {
|
||||
EnergyAccountingData1* data = (EnergyAccountingData1*) buf;
|
||||
this->data.month = data->month;
|
||||
this->data.costYesterday = (uint16_t) (data->costYesterday / 10);
|
||||
this->data.costThisMonth = (uint16_t) (data->costThisMonth / 100);
|
||||
this->data.costLastMonth = (uint16_t) (data->costLastMonth / 100);
|
||||
this->data.peaks[0].day = 1;
|
||||
this->data.peaks[0].value = data->maxHour;
|
||||
ret = true;
|
||||
} else {
|
||||
if(debugger->isActive(RemoteDebug::WARNING)) debugger->printf_P(PSTR("(EnergyAccounting) Unknown version\n"));
|
||||
ret = false;
|
||||
|
||||
22
lib/SvelteUi/app/dist/index.js
vendored
22
lib/SvelteUi/app/dist/index.js
vendored
File diff suppressed because one or more lines are too long
@@ -1,7 +1,7 @@
|
||||
<script>
|
||||
import { fmtnum } from "./Helpers";
|
||||
|
||||
|
||||
export let sysinfo;
|
||||
export let data;
|
||||
export let currency;
|
||||
export let hasExport;
|
||||
@@ -9,7 +9,7 @@
|
||||
let hasCost = false;
|
||||
let cols = 3
|
||||
$: {
|
||||
hasCost = data && data.h && (data.h.c || data.d.c || data.m.c || data.h.i || data.d.i || data.m.i);
|
||||
hasCost = data && data.h && (data.h.c > 0.01 || data.d.c > 0.01 || data.m.c > 0.01 || data.h.i > 0.01 || data.d.i > 0.01 || data.m.i > 0.01);
|
||||
cols = hasCost ? 3 : 2;
|
||||
}
|
||||
</script>
|
||||
@@ -31,6 +31,9 @@
|
||||
<div>Month</div>
|
||||
<div class="text-right">{fmtnum(data.m.u)} kWh</div>
|
||||
{#if hasCost}<div class="text-right">{fmtnum(data.m.c)} {currency}</div>{/if}
|
||||
<div>Last month</div>
|
||||
<div class="text-right">{fmtnum(sysinfo.last_month.u)} kWh</div>
|
||||
{#if hasCost}<div class="text-right">{fmtnum(sysinfo.last_month.c)} {currency}</div>{/if}
|
||||
</div>
|
||||
<strong>Export</strong>
|
||||
<div class="grid grid-cols-{cols}">
|
||||
@@ -43,6 +46,9 @@
|
||||
<div>Month</div>
|
||||
<div class="text-right">{fmtnum(data.m.p)} kWh</div>
|
||||
{#if hasCost}<div class="text-right">{fmtnum(data.m.i)} {currency}</div>{/if}
|
||||
<div>Last month</div>
|
||||
<div class="text-right">{fmtnum(sysinfo.last_month.p)} kWh</div>
|
||||
{#if hasCost}<div class="text-right">{fmtnum(sysinfo.last_month.i)} {currency}</div>{/if}
|
||||
</div>
|
||||
{:else}
|
||||
<strong>Consumption</strong>
|
||||
@@ -53,6 +59,8 @@
|
||||
<div class="text-right">{fmtnum(data.d.u,1)} kWh</div>
|
||||
<div>Month</div>
|
||||
<div class="text-right">{fmtnum(data.m.u)} kWh</div>
|
||||
<div>Last month</div>
|
||||
<div class="text-right">{fmtnum(sysinfo.last_month.u)} kWh</div>
|
||||
</div>
|
||||
{#if hasCost}
|
||||
<strong>Cost</strong>
|
||||
@@ -63,6 +71,8 @@
|
||||
<div class="text-right">{fmtnum(data.d.c,1)} {currency}</div>
|
||||
<div>Month</div>
|
||||
<div class="text-right">{fmtnum(data.m.c)} {currency}</div>
|
||||
<div>Last month</div>
|
||||
<div class="text-right">{fmtnum(sysinfo.last_month.c)} {currency}</div>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
{/if}
|
||||
{#if uiVisibility(sysinfo.ui.c, data.ea)}
|
||||
<div class="cnt">
|
||||
<AccountingData data={data.ea} currency={data.pc} hasExport={data.om > 0 || data.e > 0}/>
|
||||
<AccountingData sysinfo={sysinfo} data={data.ea} currency={data.pc} hasExport={data.om > 0 || data.e > 0}/>
|
||||
</div>
|
||||
{/if}
|
||||
{#if uiVisibility(sysinfo.ui.t, data.pr && (data.pr.startsWith("10YNO") || data.pr == '10Y1001A1001A48H'))}
|
||||
|
||||
@@ -44,5 +44,11 @@
|
||||
"e": %d,
|
||||
"f": "%s",
|
||||
"t": "%s"
|
||||
},
|
||||
"last_month": {
|
||||
"u" : %.2f,
|
||||
"c" : %.2f,
|
||||
"p" : %.2f,
|
||||
"i" : %.2f
|
||||
}
|
||||
}
|
||||
@@ -322,7 +322,11 @@ void AmsWebServer::sysinfoJson() {
|
||||
upinfo.exitCode,
|
||||
upinfo.errorCode,
|
||||
upinfo.fromVersion,
|
||||
upinfo.toVersion
|
||||
upinfo.toVersion,
|
||||
ea->getUseLastMonth(),
|
||||
ea->getCostLastMonth(),
|
||||
ea->getProducedLastMonth(),
|
||||
ea->getIncomeLastMonth()
|
||||
);
|
||||
|
||||
stripNonAscii((uint8_t*) buf, size+1);
|
||||
|
||||
@@ -1182,11 +1182,11 @@ void handleDataSuccess(AmsData* data) {
|
||||
meterState.apply(*data);
|
||||
|
||||
bool saveData = false;
|
||||
if(!ds.isDayHappy() && now > FirmwareVersion::BuildEpoch) {
|
||||
if(!ds.isHappy() && now > FirmwareVersion::BuildEpoch) { // Must use "isHappy()" in case day state gets reset and lastTimestamp is "now"
|
||||
debugD_P(PSTR("Its time to update data storage"));
|
||||
tmElements_t tm;
|
||||
breakTime(now, tm);
|
||||
if(tm.Minute == 0) {
|
||||
if(tm.Minute == 0 && data->getListType() >= 3) {
|
||||
debugV_P(PSTR(" using actual data"));
|
||||
saveData = ds.update(data);
|
||||
} else if(tm.Minute == 1 && meterState.getListType() >= 3) {
|
||||
|
||||
Reference in New Issue
Block a user