mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-01-19 01:36:49 +00:00
447 lines
14 KiB
C++
447 lines
14 KiB
C++
/**
|
|
* @copyright Utilitech AS 2023
|
|
* License: Fair Source
|
|
*
|
|
*/
|
|
|
|
#include "AmsData.h"
|
|
|
|
AmsData::AmsData() {}
|
|
|
|
void AmsData::apply(AmsData& other) {
|
|
if(other.getListType() < 3) {
|
|
unsigned long ms = this->lastUpdateMillis > other.getLastUpdateMillis() ? 0 : other.getLastUpdateMillis() - this->lastUpdateMillis;
|
|
|
|
if(ms > 0) {
|
|
if(other.getActiveImportPower() > 0) {
|
|
uint32_t power = (activeImportPower + other.getActiveImportPower()) / 2;
|
|
float add = power * (((float) ms) / 3600000.0);
|
|
activeImportCounter += add / 1000.0;
|
|
//Serial.printf("%dW, %dms, %.6fkWh added\n", other.getActiveImportPower(), ms, add);
|
|
}
|
|
|
|
if(other.getListType() > 1) {
|
|
ms = this->lastList2 > other.getLastUpdateMillis() ? 0 : other.getLastUpdateMillis() - this->lastList2;
|
|
if(other.getActiveExportPower() > 0) {
|
|
uint32_t power = (activeExportPower + other.getActiveExportPower()) / 2;
|
|
float add = power * (((float) ms) / 3600000.0);
|
|
activeExportCounter += add / 1000.0;
|
|
}
|
|
if(other.getReactiveImportPower() > 0) {
|
|
uint32_t power = (reactiveImportPower + other.getReactiveImportPower()) / 2;
|
|
float add = power * (((float) ms) / 3600000.0);
|
|
reactiveImportCounter += add / 1000.0;
|
|
}
|
|
if(other.getReactiveExportPower() > 0) {
|
|
uint32_t power = (reactiveExportPower + other.getReactiveExportPower()) / 2;
|
|
float add = power * (((float) ms) / 3600000.0);
|
|
reactiveExportCounter += add / 1000.0;
|
|
}
|
|
}
|
|
counterEstimated = true;
|
|
}
|
|
}
|
|
|
|
this->lastUpdateMillis = other.getLastUpdateMillis();
|
|
if(other.getListType() > 1) {
|
|
this->lastList2 = this->lastUpdateMillis;
|
|
}
|
|
this->packageTimestamp = other.getPackageTimestamp();
|
|
if(other.getListType() > this->listType)
|
|
this->listType = other.getListType();
|
|
switch(other.getListType()) {
|
|
case 4:
|
|
this->powerFactor = other.getPowerFactor();
|
|
this->l1PowerFactor = other.getL1PowerFactor();
|
|
this->l2PowerFactor = other.getL2PowerFactor();
|
|
this->l3PowerFactor = other.getL3PowerFactor();
|
|
this->l1activeImportPower = other.getL1ActiveImportPower();
|
|
this->l2activeImportPower = other.getL2ActiveImportPower();
|
|
this->l3activeImportPower = other.getL3ActiveImportPower();
|
|
this->l1activeExportPower = other.getL1ActiveExportPower();
|
|
this->l2activeExportPower = other.getL2ActiveExportPower();
|
|
this->l3activeExportPower = other.getL3ActiveExportPower();
|
|
this->l1activeImportCounter = other.getL1ActiveImportCounter();
|
|
this->l2activeImportCounter = other.getL2ActiveImportCounter();
|
|
this->l3activeImportCounter = other.getL3ActiveImportCounter();
|
|
this->l1activeExportCounter = other.getL1ActiveExportCounter();
|
|
this->l2activeExportCounter = other.getL2ActiveExportCounter();
|
|
this->l3activeExportCounter = other.getL3ActiveExportCounter();
|
|
case 3:
|
|
this->meterTimestamp = other.getMeterTimestamp();
|
|
// Aidon tends to sometime send the same counter as last hour by accident
|
|
if(meterType == AmsTypeAidon && counterEstimated && lastKnownCounter == other.getActiveImportCounter()-other.getActiveExportCounter()) {
|
|
double diff = activeImportCounter - activeExportCounter - lastKnownCounter;
|
|
if(diff < 1.0) { // In case a very low value have been calculated, use the new values
|
|
this->activeImportCounter = other.getActiveImportCounter();
|
|
this->activeExportCounter = other.getActiveExportCounter();
|
|
this->reactiveImportCounter = other.getReactiveImportCounter();
|
|
this->reactiveExportCounter = other.getReactiveExportCounter();
|
|
this->lastKnownCounter = activeImportCounter - activeExportCounter;
|
|
}
|
|
} else {
|
|
this->activeImportCounter = other.getActiveImportCounter();
|
|
this->activeExportCounter = other.getActiveExportCounter();
|
|
this->reactiveImportCounter = other.getReactiveImportCounter();
|
|
this->reactiveExportCounter = other.getReactiveExportCounter();
|
|
this->lastKnownCounter = activeImportCounter - activeExportCounter;
|
|
}
|
|
this->counterEstimated = false;
|
|
case 2:
|
|
this->listId = other.getListId();
|
|
this->meterId = other.getMeterId();
|
|
this->meterType = other.getMeterType();
|
|
this->meterModel = other.getMeterModel();
|
|
this->reactiveImportPower = other.getReactiveImportPower();
|
|
this->reactiveExportPower = other.getReactiveExportPower();
|
|
this->l1current = other.getL1Current();
|
|
this->l2current = other.getL2Current();
|
|
this->l2currentMissing = other.isL2currentMissing();
|
|
this->l3current = other.getL3Current();
|
|
this->l1voltage = other.getL1Voltage();
|
|
this->l2voltage = other.getL2Voltage();
|
|
this->l3voltage = other.getL3Voltage();
|
|
this->threePhase = other.isThreePhase();
|
|
this->twoPhase = other.isTwoPhase();
|
|
}
|
|
|
|
// Moved outside switch to handle meters alternating between sending active and accumulated values
|
|
if(other.getListType() == 1 || (other.getActiveImportPower() > 0 || other.getActiveExportPower() > 0))
|
|
this->activeImportPower = other.getActiveImportPower();
|
|
if(other.getListType() == 2 || (other.getActiveImportPower() > 0 || other.getActiveExportPower() > 0))
|
|
this->activeExportPower = other.getActiveExportPower();
|
|
}
|
|
|
|
void AmsData::apply(OBIS_code_t obis, double value) {
|
|
if(obis.sensor == 0 && obis.gr == 0 && obis.tariff == 0) {
|
|
meterType = value;
|
|
}
|
|
if(obis.gr == 1) {
|
|
if(obis.sensor == 96) {
|
|
if(obis.tariff == 0) {
|
|
meterId = String((long) value, 10);
|
|
return;
|
|
} else if(obis.tariff == 1) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
if(obis.tariff != 0) {
|
|
Serial.println("Tariff not implemented");
|
|
return;
|
|
}
|
|
if(obis.gr == 7) { // Instant values
|
|
switch(obis.sensor) {
|
|
case 1:
|
|
activeImportPower = value;
|
|
listType = max(listType, (uint8_t) 2);
|
|
break;
|
|
case 2:
|
|
activeExportPower = value;
|
|
listType = max(listType, (uint8_t) 2);
|
|
break;
|
|
case 3:
|
|
reactiveImportPower = value;
|
|
listType = max(listType, (uint8_t) 2);
|
|
break;
|
|
case 4:
|
|
reactiveExportPower = value;
|
|
listType = max(listType, (uint8_t) 2);
|
|
break;
|
|
case 13:
|
|
powerFactor = value;
|
|
listType = max(listType, (uint8_t) 4);
|
|
break;
|
|
case 21:
|
|
l1activeImportPower = value;
|
|
listType = max(listType, (uint8_t) 4);
|
|
break;
|
|
case 22:
|
|
l1activeExportPower = value;
|
|
listType = max(listType, (uint8_t) 4);
|
|
break;
|
|
case 31:
|
|
l1current = value;
|
|
listType = max(listType, (uint8_t) 2);
|
|
break;
|
|
case 32:
|
|
l1voltage = value;
|
|
listType = max(listType, (uint8_t) 2);
|
|
break;
|
|
case 33:
|
|
l1PowerFactor = value;
|
|
listType = max(listType, (uint8_t) 4);
|
|
break;
|
|
case 41:
|
|
l2activeImportPower = value;
|
|
listType = max(listType, (uint8_t) 4);
|
|
break;
|
|
case 42:
|
|
l2activeExportPower = value;
|
|
listType = max(listType, (uint8_t) 4);
|
|
break;
|
|
case 51:
|
|
l2current = value;
|
|
listType = max(listType, (uint8_t) 2);
|
|
break;
|
|
case 52:
|
|
l2voltage = value;
|
|
listType = max(listType, (uint8_t) 2);
|
|
break;
|
|
case 53:
|
|
l2PowerFactor = value;
|
|
listType = max(listType, (uint8_t) 4);
|
|
break;
|
|
case 61:
|
|
l3activeImportPower = value;
|
|
listType = max(listType, (uint8_t) 4);
|
|
break;
|
|
case 62:
|
|
l3activeExportPower = value;
|
|
listType = max(listType, (uint8_t) 4);
|
|
break;
|
|
case 71:
|
|
l3current = value;
|
|
listType = max(listType, (uint8_t) 2);
|
|
break;
|
|
case 72:
|
|
l3voltage = value;
|
|
listType = max(listType, (uint8_t) 2);
|
|
break;
|
|
case 73:
|
|
l3PowerFactor = value;
|
|
listType = max(listType, (uint8_t) 4);
|
|
break;
|
|
}
|
|
} else if(obis.gr == 8) { // Accumulated values
|
|
switch(obis.sensor) {
|
|
case 1:
|
|
activeImportCounter = value;
|
|
listType = max(listType, (uint8_t) 3);
|
|
break;
|
|
case 2:
|
|
activeExportCounter = value;
|
|
listType = max(listType, (uint8_t) 3);
|
|
break;
|
|
case 3:
|
|
reactiveImportCounter = value;
|
|
listType = max(listType, (uint8_t) 3);
|
|
break;
|
|
case 4:
|
|
reactiveExportCounter = value;
|
|
listType = max(listType, (uint8_t) 3);
|
|
break;
|
|
case 21:
|
|
l1activeImportCounter = value;
|
|
listType = max(listType, (uint8_t) 4);
|
|
break;
|
|
case 22:
|
|
l1activeExportCounter = value;
|
|
listType = max(listType, (uint8_t) 4);
|
|
break;
|
|
case 41:
|
|
l2activeImportCounter = value;
|
|
listType = max(listType, (uint8_t) 4);
|
|
break;
|
|
case 42:
|
|
l2activeExportCounter = value;
|
|
listType = max(listType, (uint8_t) 4);
|
|
break;
|
|
case 61:
|
|
l3activeImportCounter = value;
|
|
listType = max(listType, (uint8_t) 4);
|
|
break;
|
|
case 62:
|
|
l3activeExportCounter = value;
|
|
listType = max(listType, (uint8_t) 4);
|
|
break;
|
|
}
|
|
}
|
|
if(listType > 0)
|
|
lastUpdateMillis = millis();
|
|
|
|
threePhase = l1voltage > 0 && l2voltage > 0 && l3voltage > 0;
|
|
if(!threePhase)
|
|
twoPhase = (l1voltage > 0 && l2voltage > 0) || (l2voltage > 0 && l3voltage > 0) || (l3voltage > 0 && l1voltage > 0);
|
|
}
|
|
|
|
uint64_t AmsData::getLastUpdateMillis() {
|
|
return this->lastUpdateMillis;
|
|
}
|
|
|
|
time_t AmsData::getPackageTimestamp() {
|
|
return this->packageTimestamp;
|
|
}
|
|
|
|
uint8_t AmsData::getListType() {
|
|
return this->listType;
|
|
}
|
|
|
|
String AmsData::getListId() {
|
|
return this->listId;
|
|
}
|
|
|
|
String AmsData::getMeterId() {
|
|
return this->meterId;
|
|
}
|
|
|
|
uint8_t AmsData::getMeterType() {
|
|
return this->meterType;
|
|
}
|
|
|
|
String AmsData::getMeterModel() {
|
|
return this->meterModel;
|
|
}
|
|
|
|
time_t AmsData::getMeterTimestamp() {
|
|
return this->meterTimestamp;
|
|
}
|
|
|
|
uint32_t AmsData::getActiveImportPower() {
|
|
return this->activeImportPower;
|
|
}
|
|
|
|
uint32_t AmsData::getReactiveImportPower() {
|
|
return this->reactiveImportPower;
|
|
}
|
|
|
|
uint32_t AmsData::getActiveExportPower() {
|
|
return this->activeExportPower;
|
|
}
|
|
|
|
uint32_t AmsData::getReactiveExportPower() {
|
|
return this->reactiveExportPower;
|
|
}
|
|
|
|
float AmsData::getL1Voltage() {
|
|
return this->l1voltage;
|
|
}
|
|
|
|
float AmsData::getL2Voltage() {
|
|
return this->l2voltage;
|
|
}
|
|
|
|
float AmsData::getL3Voltage() {
|
|
return this->l3voltage;
|
|
}
|
|
|
|
float AmsData::getL1Current() {
|
|
return this->l1current;
|
|
}
|
|
|
|
float AmsData::getL2Current() {
|
|
return this->l2current;
|
|
}
|
|
|
|
float AmsData::getL3Current() {
|
|
return this->l3current;
|
|
}
|
|
|
|
float AmsData::getPowerFactor() {
|
|
return this->powerFactor;
|
|
}
|
|
|
|
float AmsData::getL1PowerFactor() {
|
|
return this->l1PowerFactor;
|
|
}
|
|
|
|
float AmsData::getL2PowerFactor() {
|
|
return this->l2PowerFactor;
|
|
}
|
|
|
|
float AmsData::getL3PowerFactor() {
|
|
return this->l3PowerFactor;
|
|
}
|
|
|
|
uint32_t AmsData::getL1ActiveImportPower() {
|
|
return this->l1activeImportPower;
|
|
}
|
|
|
|
uint32_t AmsData::getL2ActiveImportPower() {
|
|
return this->l2activeImportPower;
|
|
}
|
|
|
|
uint32_t AmsData::getL3ActiveImportPower() {
|
|
return this->l3activeImportPower;
|
|
}
|
|
|
|
uint32_t AmsData::getL1ActiveExportPower() {
|
|
return this->l1activeExportPower;
|
|
}
|
|
|
|
uint32_t AmsData::getL2ActiveExportPower() {
|
|
return this->l2activeExportPower;
|
|
}
|
|
|
|
uint32_t AmsData::getL3ActiveExportPower() {
|
|
return this->l3activeExportPower;
|
|
}
|
|
|
|
double AmsData::getL1ActiveImportCounter() {
|
|
return this->l1activeImportCounter;
|
|
}
|
|
|
|
double AmsData::getL2ActiveImportCounter() {
|
|
return this->l2activeImportCounter;
|
|
}
|
|
|
|
double AmsData::getL3ActiveImportCounter() {
|
|
return this->l3activeImportCounter;
|
|
}
|
|
|
|
double AmsData::getL1ActiveExportCounter() {
|
|
return this->l1activeExportCounter;
|
|
}
|
|
|
|
double AmsData::getL2ActiveExportCounter() {
|
|
return this->l2activeExportCounter;
|
|
}
|
|
|
|
double AmsData::getL3ActiveExportCounter() {
|
|
return this->l3activeExportCounter;
|
|
}
|
|
|
|
double AmsData::getActiveImportCounter() {
|
|
return this->activeImportCounter;
|
|
}
|
|
|
|
double AmsData::getReactiveImportCounter() {
|
|
return this->reactiveImportCounter;
|
|
}
|
|
|
|
double AmsData::getActiveExportCounter() {
|
|
return this->activeExportCounter;
|
|
}
|
|
|
|
double AmsData::getReactiveExportCounter() {
|
|
return this->reactiveExportCounter;
|
|
}
|
|
|
|
bool AmsData::isThreePhase() {
|
|
return this->threePhase;
|
|
}
|
|
|
|
bool AmsData::isTwoPhase() {
|
|
return this->twoPhase;
|
|
}
|
|
|
|
bool AmsData::isCounterEstimated() {
|
|
return this->counterEstimated;
|
|
}
|
|
|
|
bool AmsData::isL2currentMissing() {
|
|
return this->l2currentMissing;
|
|
}
|
|
|
|
int8_t AmsData::getLastError() {
|
|
return lastErrorCount > 2 ? lastError : 0;
|
|
}
|
|
|
|
void AmsData::setLastError(int8_t lastError) {
|
|
this->lastError = lastError;
|
|
if(lastError == 0) {
|
|
lastErrorCount = 0;
|
|
} else {
|
|
lastErrorCount++;
|
|
}
|
|
} |