mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-01-29 05:20:58 +00:00
New meter config
This commit is contained in:
@@ -182,7 +182,12 @@ bool AmsConfiguration::getMeterConfig(MeterConfig& config) {
|
||||
bool AmsConfiguration::setMeterConfig(MeterConfig& config) {
|
||||
MeterConfig existing;
|
||||
if(getMeterConfig(existing)) {
|
||||
meterChanged |= config.type != existing.type;
|
||||
meterChanged |= config.baud != existing.baud;
|
||||
meterChanged |= config.parity != existing.parity;
|
||||
meterChanged |= config.invert != existing.invert;
|
||||
meterChanged |= config.distributionSystem != existing.distributionSystem;
|
||||
meterChanged |= config.mainFuse != existing.mainFuse;
|
||||
meterChanged |= config.productionCapacity != existing.productionCapacity;
|
||||
meterChanged |= strcmp((char*) config.encryptionKey, (char*) existing.encryptionKey);
|
||||
meterChanged |= strcmp((char*) config.authenticationKey, (char*) existing.authenticationKey);
|
||||
} else {
|
||||
@@ -196,13 +201,14 @@ bool AmsConfiguration::setMeterConfig(MeterConfig& config) {
|
||||
}
|
||||
|
||||
void AmsConfiguration::clearMeter(MeterConfig& config) {
|
||||
config.type = 0;
|
||||
config.baud = 2400;
|
||||
config.parity = 11; // 8E1
|
||||
config.invert = false;
|
||||
config.distributionSystem = 0;
|
||||
config.mainFuse = 0;
|
||||
config.productionCapacity = 0;
|
||||
memset(config.encryptionKey, 0, 16);
|
||||
memset(config.authenticationKey, 0, 16);
|
||||
config.substituteMissing = false;
|
||||
}
|
||||
|
||||
bool AmsConfiguration::isMeterChanged() {
|
||||
@@ -521,16 +527,6 @@ bool AmsConfiguration::hasConfig() {
|
||||
EEPROM.end();
|
||||
}
|
||||
switch(configVersion) {
|
||||
case 82:
|
||||
configVersion = -1; // Prevent loop
|
||||
if(loadConfig82(EEPROM_CONFIG_ADDRESS+1)) {
|
||||
configVersion = EEPROM_CHECK_SUM;
|
||||
return true;
|
||||
} else {
|
||||
configVersion = 0;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 83:
|
||||
configVersion = -1; // Prevent loop
|
||||
if(loadConfig83(EEPROM_CONFIG_ADDRESS+1)) {
|
||||
@@ -544,20 +540,26 @@ bool AmsConfiguration::hasConfig() {
|
||||
case 86:
|
||||
configVersion = -1; // Prevent loop
|
||||
if(relocateConfig86()) {
|
||||
configVersion = EEPROM_CHECK_SUM;
|
||||
return true;
|
||||
configVersion = 87;
|
||||
} else {
|
||||
configVersion = 0;
|
||||
return false;
|
||||
}
|
||||
case 87:
|
||||
configVersion = -1; // Prevent loop
|
||||
if(relocateConfig87()) {
|
||||
configVersion = 88;
|
||||
} else {
|
||||
configVersion = 0;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case EEPROM_CHECK_SUM:
|
||||
return true;
|
||||
default:
|
||||
configVersion = 0;
|
||||
return false;
|
||||
}
|
||||
return configVersion == EEPROM_CHECK_SUM;
|
||||
}
|
||||
|
||||
int AmsConfiguration::getConfigVersion() {
|
||||
@@ -602,107 +604,6 @@ void AmsConfiguration::saveTempSensors() {
|
||||
}
|
||||
}
|
||||
|
||||
bool AmsConfiguration::loadConfig82(int address) {
|
||||
ConfigObject82 c;
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
EEPROM.get(address, c);
|
||||
|
||||
EntsoeConfig entsoe;
|
||||
clearEntsoe(entsoe);
|
||||
EEPROM.put(CONFIG_ENTSOE_START, entsoe);
|
||||
|
||||
NtpConfig ntp;
|
||||
clearNtp(ntp);
|
||||
EEPROM.put(CONFIG_NTP_START, ntp);
|
||||
|
||||
DomoticzConfig domo {
|
||||
c.domoELIDX,
|
||||
c.domoVL1IDX,
|
||||
c.domoVL2IDX,
|
||||
c.domoVL3IDX,
|
||||
c.domoCL1IDX
|
||||
};
|
||||
EEPROM.put(CONFIG_DOMOTICZ_START, domo);
|
||||
|
||||
GpioConfig gpio {
|
||||
c.hanPin,
|
||||
c.apPin,
|
||||
c.ledPin,
|
||||
c.ledInverted,
|
||||
c.ledPinRed,
|
||||
c.ledPinGreen,
|
||||
c.ledPinBlue,
|
||||
c.ledRgbInverted,
|
||||
c.tempSensorPin,
|
||||
0xFF,
|
||||
c.vccPin,
|
||||
0,
|
||||
c.vccMultiplier,
|
||||
c.vccBootLimit
|
||||
};
|
||||
EEPROM.put(CONFIG_GPIO_START, gpio);
|
||||
|
||||
DebugConfig debug {
|
||||
c.debugTelnet,
|
||||
c.debugSerial,
|
||||
c.debugLevel
|
||||
};
|
||||
EEPROM.put(CONFIG_DEBUG_START, debug);
|
||||
|
||||
MeterConfig meter {
|
||||
c.meterType,
|
||||
c.distributionSystem,
|
||||
c.mainFuse,
|
||||
c.productionCapacity,
|
||||
{0},
|
||||
{0},
|
||||
c.substituteMissing
|
||||
};
|
||||
EEPROM.put(CONFIG_METER_START, meter);
|
||||
|
||||
WebConfig web {
|
||||
c.authSecurity
|
||||
};
|
||||
strcpy(web.username, c.authUser);
|
||||
strcpy(web.password, c.authPassword);
|
||||
EEPROM.put(CONFIG_WEB_START, web);
|
||||
|
||||
MqttConfig mqtt;
|
||||
strcpy(mqtt.host, c.mqttHost);
|
||||
mqtt.port = c.mqttPort;
|
||||
strcpy(mqtt.clientId, c.mqttClientId);
|
||||
strcpy(mqtt.publishTopic, c.mqttPublishTopic);
|
||||
strcpy(mqtt.subscribeTopic, c.mqttSubscribeTopic);
|
||||
strcpy(mqtt.username, c.mqttUser);
|
||||
strcpy(mqtt.password, c.mqttPassword);
|
||||
mqtt.payloadFormat = c.mqttPayloadFormat;
|
||||
mqtt.ssl = c.mqttSsl;
|
||||
EEPROM.put(CONFIG_MQTT_START, mqtt);
|
||||
|
||||
WiFiConfig wifi;
|
||||
strcpy(wifi.ssid, c.wifiSsid);
|
||||
strcpy(wifi.psk, c.wifiPassword);
|
||||
strcpy(wifi.ip, c.wifiIp);
|
||||
strcpy(wifi.gateway, c.wifiGw);
|
||||
strcpy(wifi.subnet, c.wifiSubnet);
|
||||
strcpy(wifi.dns1, c.wifiDns1);
|
||||
strcpy(wifi.dns2, c.wifiDns2);
|
||||
strcpy(wifi.hostname, c.wifiHostname);
|
||||
wifi.mdns = true;
|
||||
EEPROM.put(CONFIG_WIFI_START, wifi);
|
||||
|
||||
SystemConfig sys {
|
||||
c.boardType
|
||||
};
|
||||
EEPROM.put(CONFIG_SYSTEM_START, sys);
|
||||
|
||||
EEPROM.put(EEPROM_CONFIG_ADDRESS, EEPROM_CHECK_SUM);
|
||||
bool ret = EEPROM.commit();
|
||||
EEPROM.end();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool AmsConfiguration::loadConfig83(int address) {
|
||||
ConfigObject83 c;
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
@@ -755,13 +656,14 @@ bool AmsConfiguration::loadConfig83(int address) {
|
||||
EEPROM.put(CONFIG_DEBUG_START, debug);
|
||||
|
||||
MeterConfig meter {
|
||||
c.meterType,
|
||||
2400,
|
||||
c.meterType == 3 || c.meterType == 4 ? 3 : 11,
|
||||
false,
|
||||
c.distributionSystem,
|
||||
c.mainFuse,
|
||||
c.productionCapacity,
|
||||
{0},
|
||||
{0},
|
||||
c.substituteMissing
|
||||
{0}
|
||||
};
|
||||
memcpy(meter.encryptionKey, c.meterEncryptionKey, 16);
|
||||
memcpy(meter.authenticationKey, c.meterAuthenticationKey, 16);
|
||||
@@ -825,6 +727,25 @@ bool AmsConfiguration::relocateConfig86() {
|
||||
mqtt.payloadFormat = mqtt86.payloadFormat;
|
||||
mqtt.ssl = mqtt86.ssl;
|
||||
EEPROM.put(CONFIG_MQTT_START, mqtt);
|
||||
EEPROM.put(EEPROM_CONFIG_ADDRESS, 87);
|
||||
bool ret = EEPROM.commit();
|
||||
EEPROM.end();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool AmsConfiguration::relocateConfig87() {
|
||||
MeterConfig87 meter87;
|
||||
MeterConfig meter;
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
EEPROM.get(CONFIG_METER_START_87, meter87);
|
||||
meter.baud = 2400;
|
||||
meter.parity = meter87.type == 3 || meter87.type == 4 ? 3 : 11;
|
||||
meter.invert = false;
|
||||
meter.distributionSystem = meter87.distributionSystem;
|
||||
meter.mainFuse = meter87.mainFuse;
|
||||
meter.productionCapacity = meter87.productionCapacity;
|
||||
EEPROM.put(CONFIG_METER_START, meter);
|
||||
EEPROM.put(EEPROM_CONFIG_ADDRESS, 88);
|
||||
bool ret = EEPROM.commit();
|
||||
EEPROM.end();
|
||||
return ret;
|
||||
@@ -986,11 +907,12 @@ void AmsConfiguration::print(Print* debugger)
|
||||
MeterConfig meter;
|
||||
if(getMeterConfig(meter)) {
|
||||
debugger->println("--Meter configuration--");
|
||||
debugger->printf("Type: %i\r\n", meter.type);
|
||||
debugger->printf("Baud: %i\r\n", meter.baud);
|
||||
debugger->printf("Parity: %i\r\n", meter.parity);
|
||||
debugger->printf("Invert serial: %s\r\n", meter.invert ? "Yes" : "No");
|
||||
debugger->printf("Distribution system: %i\r\n", meter.distributionSystem);
|
||||
debugger->printf("Main fuse: %i\r\n", meter.mainFuse);
|
||||
debugger->printf("Production Capacity: %i\r\n", meter.productionCapacity);
|
||||
debugger->printf("Substitute missing: %s\r\n", meter.substituteMissing ? "Yes" : "No");
|
||||
debugger->println("");
|
||||
delay(10);
|
||||
Serial.flush();
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
#include "Arduino.h"
|
||||
|
||||
#define EEPROM_SIZE 1024 * 3
|
||||
#define EEPROM_CHECK_SUM 87 // Used to check if config is stored. Change if structure changes
|
||||
#define EEPROM_CHECK_SUM 88 // Used to check if config is stored. Change if structure changes
|
||||
#define EEPROM_CONFIG_ADDRESS 0
|
||||
#define EEPROM_TEMP_CONFIG_ADDRESS 2048
|
||||
|
||||
#define CONFIG_SYSTEM_START 8
|
||||
#define CONFIG_WIFI_START 16
|
||||
#define CONFIG_METER_START 224
|
||||
#define CONFIG_WEB_START 648
|
||||
#define CONFIG_METER_START 784
|
||||
#define CONFIG_DEBUG_START 824
|
||||
#define CONFIG_GPIO_START 832
|
||||
#define CONFIG_DOMOTICZ_START 856
|
||||
@@ -20,6 +20,7 @@
|
||||
#define CONFIG_MQTT_START 1004
|
||||
|
||||
#define CONFIG_MQTT_START_86 224
|
||||
#define CONFIG_METER_START_87 784
|
||||
|
||||
|
||||
struct SystemConfig {
|
||||
@@ -69,6 +70,17 @@ struct WebConfig {
|
||||
}; // 129
|
||||
|
||||
struct MeterConfig {
|
||||
uint32_t baud;
|
||||
uint8_t parity;
|
||||
bool invert;
|
||||
uint8_t distributionSystem;
|
||||
uint8_t mainFuse;
|
||||
uint8_t productionCapacity;
|
||||
uint8_t encryptionKey[16];
|
||||
uint8_t authenticationKey[16];
|
||||
}; // 41
|
||||
|
||||
struct MeterConfig87 {
|
||||
uint8_t type;
|
||||
uint8_t distributionSystem;
|
||||
uint8_t mainFuse;
|
||||
@@ -190,60 +202,6 @@ struct ConfigObject83 {
|
||||
uint8_t tempAnalogSensorPin;
|
||||
};
|
||||
|
||||
struct ConfigObject82 {
|
||||
uint8_t boardType;
|
||||
char wifiSsid[32];
|
||||
char wifiPassword[64];
|
||||
char wifiIp[15];
|
||||
char wifiGw[15];
|
||||
char wifiSubnet[15];
|
||||
char wifiDns1[15];
|
||||
char wifiDns2[15];
|
||||
char wifiHostname[32];
|
||||
char mqttHost[128];
|
||||
uint16_t mqttPort;
|
||||
char mqttClientId[32];
|
||||
char mqttPublishTopic[64];
|
||||
char mqttSubscribeTopic[64];
|
||||
char mqttUser[64];
|
||||
char mqttPassword[64];
|
||||
uint8_t mqttPayloadFormat;
|
||||
bool mqttSsl;
|
||||
uint8_t authSecurity;
|
||||
char authUser[64];
|
||||
char authPassword[64];
|
||||
|
||||
uint8_t meterType;
|
||||
uint8_t distributionSystem;
|
||||
uint8_t mainFuse;
|
||||
uint8_t productionCapacity;
|
||||
bool substituteMissing;
|
||||
bool sendUnknown;
|
||||
|
||||
bool debugTelnet;
|
||||
bool debugSerial;
|
||||
uint8_t debugLevel;
|
||||
|
||||
uint8_t hanPin;
|
||||
uint8_t apPin;
|
||||
uint8_t ledPin;
|
||||
bool ledInverted;
|
||||
uint8_t ledPinRed;
|
||||
uint8_t ledPinGreen;
|
||||
uint8_t ledPinBlue;
|
||||
bool ledRgbInverted;
|
||||
uint8_t tempSensorPin;
|
||||
uint8_t vccPin;
|
||||
uint16_t vccMultiplier;
|
||||
uint8_t vccBootLimit;
|
||||
|
||||
uint16_t domoELIDX;
|
||||
uint16_t domoVL1IDX;
|
||||
uint16_t domoVL2IDX;
|
||||
uint16_t domoVL3IDX;
|
||||
uint16_t domoCL1IDX;
|
||||
};
|
||||
|
||||
struct TempSensorConfig {
|
||||
uint8_t address[8];
|
||||
char name[16];
|
||||
@@ -334,9 +292,9 @@ private:
|
||||
uint8_t tempSensorCount = 0;
|
||||
TempSensorConfig** tempSensors;
|
||||
|
||||
bool loadConfig82(int address);
|
||||
bool loadConfig83(int address);
|
||||
bool relocateConfig86();
|
||||
bool relocateConfig87();
|
||||
|
||||
int readString(int pAddress, char* pString[]);
|
||||
int readInt(int pAddress, int *pValue);
|
||||
|
||||
@@ -109,25 +109,28 @@ AmsData::AmsData(const char* d, bool substituteMissing) {
|
||||
l3current = s32;
|
||||
}
|
||||
|
||||
int vdiv = 1;
|
||||
int voltage = l1voltage == 0 ? l2voltage == 0 ? l3voltage == 0 ? 0 : l3voltage : l2voltage : l1voltage;
|
||||
while(voltage > 1000) {
|
||||
vdiv *= 10;
|
||||
voltage /= 10;
|
||||
}
|
||||
if(listType == 2) {
|
||||
int vdiv = 1;
|
||||
int voltage = l1voltage == 0 ? l2voltage == 0 ? l3voltage == 0 ? 0 : l3voltage : l2voltage : l1voltage;
|
||||
while(voltage > 1000) {
|
||||
vdiv *= 10;
|
||||
voltage /= 10;
|
||||
}
|
||||
|
||||
l1voltage = l1voltage != 0 ? l1voltage / vdiv : 0;
|
||||
l2voltage = l2voltage != 0 ? l2voltage / vdiv : 0;
|
||||
l3voltage = l3voltage != 0 ? l3voltage / vdiv : 0;
|
||||
l1voltage = l1voltage != 0 ? l1voltage / vdiv : 0;
|
||||
l2voltage = l2voltage != 0 ? l2voltage / vdiv : 0;
|
||||
l3voltage = l3voltage != 0 ? l3voltage / vdiv : 0;
|
||||
|
||||
if(meterType == AmsTypeAidon) {
|
||||
l1current = l1current != 0 ? l1current / 10.0 : 0;
|
||||
l2current = l2current != 0 ? l2current / 10.0 : 0;
|
||||
l3current = l3current != 0 ? l3current / 10.0 : 0;
|
||||
} else if(meterType == AmsTypeKamstrup) {
|
||||
l1current = l1current != 0 ? l1current / 100.0 : 0;
|
||||
l2current = l2current != 0 ? l2current / 100.0 : 0;
|
||||
l3current = l3current != 0 ? l3current / 100.0 : 0;
|
||||
int adiv = 1;
|
||||
int watt = (l1voltage * l1current) + (l2voltage * l2current) + (l3voltage * l3current);
|
||||
while(watt / activeImportPower > 2) {
|
||||
adiv *= 10;
|
||||
watt /= 10;
|
||||
}
|
||||
|
||||
l1current = l1current != 0 ? l1current / adiv : 0;
|
||||
l2current = l2current != 0 ? l2current / adiv : 0;
|
||||
l3current = l3current != 0 ? l3current / adiv : 0;
|
||||
}
|
||||
|
||||
u32 = AMS_getUnsignedNumber(AMS_OBIS_ACTIVE_IMPORT_COUNT, ((char *) (d)));
|
||||
@@ -170,8 +173,8 @@ AmsData::AmsData(const char* d, bool substituteMissing) {
|
||||
twoPhase = (l1voltage > 0 && l2voltage > 0) || (l2voltage > 0 && l3voltage > 0) || (l3voltage > 0 && l1voltage > 0);
|
||||
|
||||
if(threePhase) {
|
||||
if(substituteMissing) {
|
||||
l2current = (((activeImportPower - activeExportPower) * sqrt(3)) - (l1voltage * l1current) - (l3voltage * l3current)) / l2voltage;
|
||||
if(substituteMissing && l2current == 0) {
|
||||
l2current = (((activeImportPower - activeExportPower) * sqrt(3)) - (l1voltage * l1current) - (l3voltage * l3current)) / l2voltage;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <Timezone.h>
|
||||
#include "HanReader.h"
|
||||
|
||||
#define METER_TYPE_KAIFA 1
|
||||
#define METER_TYPE_AIDON 2
|
||||
@@ -14,7 +13,6 @@ class AmsData {
|
||||
public:
|
||||
AmsData();
|
||||
AmsData(const char* d, bool substituteMissing);
|
||||
AmsData(uint8_t meterType, bool substituteMissing, HanReader& hanReader);
|
||||
|
||||
void apply(AmsData& other);
|
||||
|
||||
@@ -61,11 +59,6 @@ private:
|
||||
float l1voltage = 0, l2voltage = 0, l3voltage = 0, l1current = 0, l2current = 0, l3current = 0;
|
||||
float activeImportCounter = 0, reactiveImportCounter = 0, activeExportCounter = 0, reactiveExportCounter = 0;
|
||||
bool threePhase = false, twoPhase = false, counterEstimated = false;
|
||||
|
||||
void extractFromKaifa(HanReader& hanReader, uint8_t listSize);
|
||||
void extractFromAidon(HanReader& hanReader, uint8_t listSize);
|
||||
void extractFromKamstrup(HanReader& hanReader, uint8_t listSize);
|
||||
void extractFromOmnipower(HanReader& hanReader, uint8_t listSize);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -31,18 +31,12 @@ ADC_MODE(ADC_VCC);
|
||||
|
||||
#include "web/AmsWebServer.h"
|
||||
#include "AmsConfiguration.h"
|
||||
#include "HanReader.h"
|
||||
|
||||
#include "mqtt/AmsMqttHandler.h"
|
||||
#include "mqtt/JsonMqttHandler.h"
|
||||
#include "mqtt/RawMqttHandler.h"
|
||||
#include "mqtt/DomoticzMqttHandler.h"
|
||||
|
||||
#include "Aidon.h"
|
||||
#include "Kaifa.h"
|
||||
#include "Kamstrup.h"
|
||||
#include "Omnipower.h"
|
||||
|
||||
#include "Uptime.h"
|
||||
|
||||
#include "RemoteDebug.h"
|
||||
@@ -67,8 +61,6 @@ AmsWebServer ws(&Debug, &hw);
|
||||
MQTTClient mqtt(512);
|
||||
AmsMqttHandler* mqttHandler = NULL;
|
||||
|
||||
HanReader hanReader;
|
||||
|
||||
Stream *hanSerial;
|
||||
|
||||
GpioConfig gpioConfig;
|
||||
@@ -144,15 +136,16 @@ void setup() {
|
||||
config.getMeterConfig(meterConfig);
|
||||
if(gpioConfig.hanPin == 3) {
|
||||
shared = true;
|
||||
switch(meterConfig.type) {
|
||||
case METER_TYPE_KAMSTRUP:
|
||||
case METER_TYPE_OMNIPOWER:
|
||||
Serial.begin(2400, SERIAL_8N1);
|
||||
SerialConfig serialConfig;
|
||||
switch(meterConfig.parity) {
|
||||
case 3:
|
||||
serialConfig = SERIAL_8N1;
|
||||
break;
|
||||
default:
|
||||
Serial.begin(2400, SERIAL_8E1);
|
||||
serialConfig = SERIAL_8E1;
|
||||
break;
|
||||
}
|
||||
Serial.begin(meterConfig.baud, serialConfig);
|
||||
}
|
||||
|
||||
if(!shared) {
|
||||
@@ -449,7 +442,7 @@ void loop() {
|
||||
|
||||
if(config.isMeterChanged()) {
|
||||
config.getMeterConfig(meterConfig);
|
||||
setupHanPort(gpioConfig.hanPin, meterConfig.type);
|
||||
setupHanPort(gpioConfig.hanPin, meterConfig.baud, meterConfig.parity, meterConfig.invert);
|
||||
config.ackMeterChanged();
|
||||
}
|
||||
delay(1);
|
||||
@@ -458,8 +451,8 @@ void loop() {
|
||||
delay(1); // Needed for auto modem sleep
|
||||
}
|
||||
|
||||
void setupHanPort(int pin, int newMeterType) {
|
||||
debugI("Setting up HAN on pin %d for meter type %d", pin, newMeterType);
|
||||
void setupHanPort(uint8_t pin, uint32_t baud, uint8_t parityOrdinal, bool invert) {
|
||||
debugI("Setting up HAN on pin %d with baud %d and parity %d", pin, baud, parityOrdinal);
|
||||
|
||||
HardwareSerial *hwSerial = NULL;
|
||||
if(pin == 3) {
|
||||
@@ -482,42 +475,40 @@ void setupHanPort(int pin, int newMeterType) {
|
||||
if(hwSerial != NULL) {
|
||||
debugD("Hardware serial");
|
||||
Serial.flush();
|
||||
switch(newMeterType) {
|
||||
case METER_TYPE_KAMSTRUP:
|
||||
case METER_TYPE_OMNIPOWER:
|
||||
hwSerial->begin(2400, SERIAL_8N1);
|
||||
|
||||
SerialConfig serialConfig;
|
||||
switch(parityOrdinal) {
|
||||
case 3:
|
||||
serialConfig = SERIAL_8N1;
|
||||
break;
|
||||
default:
|
||||
hwSerial->begin(2400, SERIAL_8E1);
|
||||
serialConfig = SERIAL_8E1;
|
||||
break;
|
||||
}
|
||||
|
||||
hwSerial->begin(baud, serialConfig, SERIAL_FULL, -1, invert);
|
||||
hanSerial = hwSerial;
|
||||
} else {
|
||||
debugD("Software serial");
|
||||
Serial.flush();
|
||||
SoftwareSerial *swSerial = new SoftwareSerial(pin);
|
||||
|
||||
switch(newMeterType) {
|
||||
case METER_TYPE_KAMSTRUP:
|
||||
case METER_TYPE_OMNIPOWER:
|
||||
swSerial->begin(2400, SWSERIAL_8N1);
|
||||
SoftwareSerialConfig serialConfig;
|
||||
switch(parityOrdinal) {
|
||||
case 3:
|
||||
serialConfig = SWSERIAL_8N1;
|
||||
break;
|
||||
default:
|
||||
swSerial->begin(2400, SWSERIAL_8E1);
|
||||
serialConfig = SWSERIAL_8E1;
|
||||
break;
|
||||
}
|
||||
|
||||
SoftwareSerial *swSerial = new SoftwareSerial(pin, -1, invert);
|
||||
swSerial->begin(baud, serialConfig);
|
||||
hanSerial = swSerial;
|
||||
|
||||
Serial.begin(115200);
|
||||
}
|
||||
|
||||
hanReader.setup(hanSerial, &Debug);
|
||||
hanReader.setEncryptionKey(meterConfig.encryptionKey);
|
||||
hanReader.setAuthenticationKey(meterConfig.authenticationKey);
|
||||
|
||||
// Compensate for the known Kaifa bug
|
||||
hanReader.compensateFor09HeaderBug = (newMeterType == 1);
|
||||
|
||||
// Empty buffer before starting
|
||||
while (hanSerial->available() > 0) {
|
||||
hanSerial->read();
|
||||
@@ -604,15 +595,16 @@ HDLCConfig* hc = NULL;
|
||||
int currentMeterType = 0;
|
||||
void readHanPort() {
|
||||
uint8_t buf[BUF_SIZE];
|
||||
if(!hanSerial->available()) return;
|
||||
size_t len = hanSerial->readBytes(buf, BUF_SIZE); // TODO: read one byte at the time. This blocks up the GUI
|
||||
if(len > 0) {
|
||||
if(meterConfig.type == 4 && hc == NULL) {
|
||||
int pos = HDLC_validate((uint8_t *) buf, len, hc);
|
||||
if(pos == HDLC_ENCRYPTION_CONFIG_MISSING) {
|
||||
hc = new HDLCConfig();
|
||||
memcpy(hc->encryption_key, meterConfig.encryptionKey, 16);
|
||||
memcpy(hc->authentication_key, meterConfig.authenticationKey, 16);
|
||||
}
|
||||
int pos = HDLC_validate((uint8_t *) buf, len, hc);
|
||||
if(Debug.isActive(RemoteDebug::INFO)) {
|
||||
if(Debug.isActive(RemoteDebug::DEBUG)) {
|
||||
debugD("Frame dump:");
|
||||
debugPrint(buf, 0, len);
|
||||
if(hc != NULL) {
|
||||
@@ -630,7 +622,7 @@ void readHanPort() {
|
||||
debugI("Valid HDLC, start at %d", pos);
|
||||
if(!hw.ledBlink(LED_GREEN, 1))
|
||||
hw.ledBlink(LED_INTERNAL, 1);
|
||||
AmsData data = AmsData(((char *) (buf)) + pos, meterConfig.substituteMissing);
|
||||
AmsData data = AmsData(((char *) (buf)) + pos, true);
|
||||
if(data.getListType() > 0) {
|
||||
if(mqttEnabled && mqttHandler != NULL) {
|
||||
if(mqttHandler->publish(&data, &meterState)) {
|
||||
@@ -682,95 +674,6 @@ void debugPrint(byte *buffer, int start, int length) {
|
||||
Debug.println("");
|
||||
}
|
||||
|
||||
void oldReadHanPort() {
|
||||
if (hanReader.read()) {
|
||||
lastSuccessfulRead = millis();
|
||||
delay(1);
|
||||
|
||||
if(meterConfig.type > 0) {
|
||||
if(!hw.ledBlink(LED_GREEN, 1))
|
||||
hw.ledBlink(LED_INTERNAL, 1);
|
||||
|
||||
AmsData data(meterConfig.type, meterConfig.substituteMissing, hanReader);
|
||||
if(data.getListType() > 0) {
|
||||
if(mqttEnabled && mqttHandler != NULL) {
|
||||
if(mqttHandler->publish(&data, &meterState)) {
|
||||
if(data.getListType() == 3 && eapi != NULL) {
|
||||
mqttHandler->publishPrices(eapi);
|
||||
}
|
||||
if(data.getListType() >= 2) {
|
||||
mqttHandler->publishSystem(&hw);
|
||||
}
|
||||
time_t now = time(nullptr);
|
||||
if(now < EPOCH_2021_01_01 || data.getListType() == 3) {
|
||||
if(data.getMeterTimestamp() > EPOCH_2021_01_01 || !ntpEnabled) {
|
||||
debugI("Using timestamp from meter");
|
||||
now = data.getMeterTimestamp();
|
||||
} else if(data.getPackageTimestamp() > EPOCH_2021_01_01) {
|
||||
debugI("Using timestamp from meter (DLMS)");
|
||||
now = data.getPackageTimestamp();
|
||||
}
|
||||
if(now > EPOCH_2021_01_01) {
|
||||
timeval tv { now, 0};
|
||||
settimeofday(&tv, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
mqtt.loop();
|
||||
delay(10);
|
||||
}
|
||||
meterState.apply(data);
|
||||
}
|
||||
} else {
|
||||
// Auto detect meter if not set
|
||||
for(int i = 1; i <= 3; i++) {
|
||||
String list;
|
||||
switch(i) {
|
||||
case 1:
|
||||
list = hanReader.getString((int) Kaifa_List1Phase::ListVersionIdentifier);
|
||||
break;
|
||||
case 2:
|
||||
list = hanReader.getString((int) Aidon_List1Phase::ListVersionIdentifier);
|
||||
break;
|
||||
case 3:
|
||||
list = hanReader.getString((int) Kamstrup_List1Phase::ListVersionIdentifier);
|
||||
break;
|
||||
}
|
||||
if(!list.isEmpty()) {
|
||||
list.toLowerCase();
|
||||
if(list.startsWith("kfm")) {
|
||||
meterConfig.type = 1;
|
||||
config.setMeterConfig(meterConfig);
|
||||
if(Debug.isActive(RemoteDebug::INFO)) debugI("Detected Kaifa meter");
|
||||
break;
|
||||
} else if(list.startsWith("aidon")) {
|
||||
meterConfig.type = 2;
|
||||
config.setMeterConfig(meterConfig);
|
||||
if(Debug.isActive(RemoteDebug::INFO)) debugI("Detected Aidon meter");
|
||||
break;
|
||||
} else if(list.startsWith("kamstrup")) {
|
||||
meterConfig.type = 3;
|
||||
config.setMeterConfig(meterConfig);
|
||||
if(Debug.isActive(RemoteDebug::INFO)) debugI("Detected Kamstrup meter");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
hanReader.compensateFor09HeaderBug = (meterConfig.type == 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Switch parity if meter is still not detected
|
||||
if(meterConfig.type == 0 && millis() - lastSuccessfulRead > 10000) {
|
||||
lastSuccessfulRead = millis();
|
||||
debugD("No data for current setting, switching parity");
|
||||
Serial.flush();
|
||||
if(++currentMeterType == 4) currentMeterType = 1;
|
||||
setupHanPort(gpioConfig.hanPin, currentMeterType);
|
||||
}
|
||||
delay(1);
|
||||
}
|
||||
|
||||
unsigned long wifiTimeout = WIFI_CONNECTION_TIMEOUT;
|
||||
unsigned long lastWifiRetry = -WIFI_CONNECTION_TIMEOUT;
|
||||
void WiFi_connect() {
|
||||
|
||||
@@ -90,7 +90,7 @@ int HDLC_validate(const uint8_t* d, int len, HDLCConfig* config) {
|
||||
// Encrypted APDU
|
||||
// http://www.weigu.lu/tutorials/sensors2bus/04_encryption/index.html
|
||||
if(config == NULL)
|
||||
return -90;
|
||||
return HDLC_ENCRYPTION_CONFIG_MISSING;
|
||||
|
||||
memcpy(config->system_title, d + headersize + 2, 8);
|
||||
memcpy(config->initialization_vector, config->system_title, 8);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#define HDLC_FLAG 0x7E
|
||||
#define HDLC_ENCRYPTION_CONFIG_MISSING -90
|
||||
|
||||
struct HDLCConfig {
|
||||
uint8_t encryption_key[32];
|
||||
|
||||
@@ -391,10 +391,13 @@ void AmsWebServer::configMeterHtml() {
|
||||
server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
server.sendHeader("Pragma", "no-cache");
|
||||
|
||||
html.replace("{m}", String(meterConfig->mainFuse));
|
||||
for(int i = 0; i<5; i++) {
|
||||
html.replace("{m" + String(i) + "}", meterConfig->type == i ? "selected" : "");
|
||||
}
|
||||
html.replace("{b}", String(meterConfig->baud));
|
||||
html.replace("{b2400}", meterConfig->baud == 2400 ? "selected" : "");
|
||||
html.replace("{b115200}", meterConfig->baud == 115200 ? "selected" : "");
|
||||
html.replace("{c}", String(meterConfig->baud));
|
||||
html.replace("{c3}", meterConfig->parity == 3 ? "selected" : "");
|
||||
html.replace("{c11}", meterConfig->parity == 11 ? "selected" : "");
|
||||
html.replace("{i}", meterConfig->invert ? "checked" : "");
|
||||
html.replace("{d}", String(meterConfig->distributionSystem));
|
||||
for(int i = 0; i<3; i++) {
|
||||
html.replace("{d" + String(i) + "}", meterConfig->distributionSystem == i ? "selected" : "");
|
||||
@@ -405,7 +408,7 @@ void AmsWebServer::configMeterHtml() {
|
||||
}
|
||||
html.replace("{p}", String(meterConfig->productionCapacity));
|
||||
|
||||
if(meterConfig->type == METER_TYPE_OMNIPOWER) {
|
||||
if(meterConfig->encryptionKey[0] != 0x00) {
|
||||
String encryptionKeyHex = "0x";
|
||||
encryptionKeyHex += toHex(meterConfig->encryptionKey, 16);
|
||||
html.replace("{e}", encryptionKeyHex);
|
||||
@@ -418,8 +421,6 @@ void AmsWebServer::configMeterHtml() {
|
||||
html.replace("{a}", "");
|
||||
}
|
||||
|
||||
html.replace("{s}", meterConfig->substituteMissing ? "checked" : "");
|
||||
|
||||
server.setContentLength(html.length() + HEAD_HTML_LEN + FOOT_HTML_LEN);
|
||||
server.send_P(200, "text/html", HEAD_HTML);
|
||||
server.sendContent(html);
|
||||
@@ -665,7 +666,7 @@ void AmsWebServer::dataJson() {
|
||||
|
||||
|
||||
uint8_t hanStatus;
|
||||
if(meterConfig->type == 0) {
|
||||
if(meterConfig->baud == 0) {
|
||||
hanStatus = 0;
|
||||
} else if(now - meterState->getLastUpdateMillis() < 15000) {
|
||||
hanStatus = 1;
|
||||
@@ -910,7 +911,9 @@ void AmsWebServer::handleSave() {
|
||||
|
||||
if(server.hasArg("mc") && server.arg("mc") == "true") {
|
||||
printD("Received meter config");
|
||||
meterConfig->type = server.arg("m").toInt();
|
||||
meterConfig->baud = server.arg("b").toInt();
|
||||
meterConfig->parity = server.arg("c").toInt();
|
||||
meterConfig->invert = server.hasArg("i") && server.arg("i") == "true";
|
||||
meterConfig->distributionSystem = server.arg("d").toInt();
|
||||
meterConfig->mainFuse = server.arg("f").toInt();
|
||||
meterConfig->productionCapacity = server.arg("p").toInt();
|
||||
@@ -926,7 +929,6 @@ void AmsWebServer::handleSave() {
|
||||
authenticationKeyHex.replace("0x", "");
|
||||
fromHex(meterConfig->authenticationKey, authenticationKeyHex, 16);
|
||||
}
|
||||
meterConfig->substituteMissing = server.hasArg("s") && server.arg("s") == "true";
|
||||
config->setMeterConfig(*meterConfig);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user