From af8f5a7c24d2378af30958581d382045f6f40118 Mon Sep 17 00:00:00 2001 From: Gunnar Skjold Date: Sat, 16 Jan 2021 16:02:39 +0100 Subject: [PATCH] Memory optimization and bugfix --- lib/HanReader/src/DlmsReader.cpp | 8 + lib/HanReader/src/DlmsReader.h | 2 + lib/HanReader/src/HanReader.cpp | 34 +- lib/HanReader/src/HanReader.h | 34 +- lib/mbedtls/include/mbedtls/config.h | 11 +- src/AmsConfiguration.cpp | 1493 ++++++++++++-------------- src/AmsConfiguration.h | 370 ++----- src/AmsData.cpp | 401 ++++--- src/AmsData.h | 57 +- src/AmsToMqttBridge.ino | 711 ++++++------ src/HwTools.cpp | 217 ++-- src/HwTools.h | 29 +- src/entsoe/DnbCurrParser.cpp | 4 +- src/entsoe/DnbCurrParser.h | 6 +- src/entsoe/EntsoeA44Parser.cpp | 4 +- src/entsoe/EntsoeA44Parser.h | 6 +- src/entsoe/EntsoeApi.cpp | 86 +- src/entsoe/EntsoeApi.h | 25 +- src/web/AmsWebServer.cpp | 797 +++++++------- src/web/AmsWebServer.h | 21 +- web/application.js | 9 +- web/entsoe.html | 2 +- web/index.html | 26 +- 23 files changed, 2041 insertions(+), 2312 deletions(-) diff --git a/lib/HanReader/src/DlmsReader.cpp b/lib/HanReader/src/DlmsReader.cpp index aaa44557..5c1688bb 100644 --- a/lib/HanReader/src/DlmsReader.cpp +++ b/lib/HanReader/src/DlmsReader.cpp @@ -167,6 +167,14 @@ int DlmsReader::GetRawData(byte *dataBuffer, int start, int length) return 0; } +int DlmsReader::getBytesRead() { + return dataLength - (3 + destinationAddressLength + sourceAddressLength + 2 + 1); +} + +byte* DlmsReader::getBuffer() { + return buffer + (3 + destinationAddressLength + sourceAddressLength + 2 + 1); +} + int DlmsReader::GetAddress(int addressPosition, byte* addressBuffer, int start, int length) { int addressBufferPos = start; diff --git a/lib/HanReader/src/DlmsReader.h b/lib/HanReader/src/DlmsReader.h index d82eb4a1..17ad0d3d 100644 --- a/lib/HanReader/src/DlmsReader.h +++ b/lib/HanReader/src/DlmsReader.h @@ -18,6 +18,8 @@ class DlmsReader DlmsReader(); bool Read(byte data, Print* Debug); int GetRawData(byte *buffer, int start, int length); + int getBytesRead(); + byte* getBuffer(); protected: Crc16Class Crc16; diff --git a/lib/HanReader/src/HanReader.cpp b/lib/HanReader/src/HanReader.cpp index 170f16e4..c3079ba5 100644 --- a/lib/HanReader/src/HanReader.cpp +++ b/lib/HanReader/src/HanReader.cpp @@ -22,17 +22,18 @@ void HanReader::setup(Stream *hanPort){ } void HanReader::setEncryptionKey(uint8_t* encryption_key) { - memcpy(this->encryption_key, encryption_key, 16); + this->encryption_key = encryption_key; } void HanReader::setAuthenticationKey(uint8_t* authentication_key) { - memcpy(this->authentication_key, authentication_key, 16); + this->authentication_key = authentication_key; } bool HanReader::read(byte data) { if (reader.Read(data, debugger->isActive(RemoteDebug::DEBUG) ? debugger : NULL)) { - bytesRead = reader.GetRawData(buffer, 0, 512); + bytesRead = reader.getBytesRead(); + buffer = reader.getBuffer(); if (debugger->isActive(RemoteDebug::INFO)) { printI("Got valid DLMS data (%d bytes)", bytesRead); if (debugger->isActive(RemoteDebug::DEBUG)) { @@ -52,7 +53,6 @@ bool HanReader::read(byte data) { buffer[0] != 0xE6 || buffer[1] != 0xE7 || buffer[2] != 0x00 - //|| buffer[3] != 0x0F ) { printW("Invalid HAN data: Start should be E6 E7 00"); @@ -176,19 +176,19 @@ time_t HanReader::getPackageTime(bool respectTimezone, bool respectDsc) { return getTime(buffer, packageTimePosition, bytesRead, respectTimezone, respectDsc); } -time_t HanReader::getTime(int objectId, bool respectTimezone, bool respectDsc) { +time_t HanReader::getTime(uint8_t objectId, bool respectTimezone, bool respectDsc) { return getTime(objectId, respectTimezone, respectDsc, buffer, 0, bytesRead); } -int32_t HanReader::getInt(int objectId) { +int32_t HanReader::getInt(uint8_t objectId) { return getInt(objectId, buffer, 0, bytesRead); } -uint32_t HanReader::getUint(int objectId) { +uint32_t HanReader::getUint(uint8_t objectId) { return getUint32(objectId, buffer, 0, bytesRead); } -String HanReader::getString(int objectId) { +String HanReader::getString(uint8_t objectId) { return getString(objectId, buffer, 0, bytesRead); } @@ -199,7 +199,7 @@ int HanReader::getBuffer(byte* buf) { return bytesRead; } -int HanReader::findValuePosition(int dataPosition, byte *buffer, int start, int length) { +int HanReader::findValuePosition(uint8_t dataPosition, byte *buffer, int start, int length) { // The first byte after the header gives the length // of the extended header information (variable) int headerSize = dataHeader + (compensateFor09HeaderBug ? 1 : 0); @@ -240,7 +240,7 @@ int HanReader::findValuePosition(int dataPosition, byte *buffer, int start, int } -time_t HanReader::getTime(int dataPosition, bool respectTimezone, bool respectDsc, byte *buffer, int start, int length) { +time_t HanReader::getTime(uint8_t dataPosition, bool respectTimezone, bool respectDsc, byte *buffer, int start, int length) { // TODO: check if the time is represented always as a 12 byte string (0x09 0x0C) int timeStart = findValuePosition(dataPosition, buffer, start, length); timeStart += 1; @@ -285,7 +285,7 @@ time_t HanReader::getTime(byte *buffer, int start, int length, bool respectTimez } } -int HanReader::getInt(int dataPosition, byte *buffer, int start, int length) { +int HanReader::getInt(uint8_t dataPosition, byte *buffer, int start, int length) { int valuePosition = findValuePosition(dataPosition, buffer, start, length); if (valuePosition > 0) { @@ -307,7 +307,7 @@ int HanReader::getInt(int dataPosition, byte *buffer, int start, int length) { return 0; } -int8_t HanReader::getInt8(int dataPosition, byte *buffer, int start, int length) { +int8_t HanReader::getInt8(uint8_t dataPosition, byte *buffer, int start, int length) { int valuePosition = findValuePosition(dataPosition, buffer, start, length); if (valuePosition > 0 && buffer[valuePosition++] == 0x0F) { return buffer[valuePosition]; @@ -315,7 +315,7 @@ int8_t HanReader::getInt8(int dataPosition, byte *buffer, int start, int length) return 0; } -int16_t HanReader::getInt16(int dataPosition, byte *buffer, int start, int length) { +int16_t HanReader::getInt16(uint8_t dataPosition, byte *buffer, int start, int length) { int valuePosition = findValuePosition(dataPosition, buffer, start, length); if (valuePosition > 0 && buffer[valuePosition++] == 0x10) { return buffer[valuePosition] << 8 | buffer[valuePosition+1]; @@ -323,7 +323,7 @@ int16_t HanReader::getInt16(int dataPosition, byte *buffer, int start, int lengt return 0; } -uint8_t HanReader::getUint8(int dataPosition, byte *buffer, int start, int length) { +uint8_t HanReader::getUint8(uint8_t dataPosition, byte *buffer, int start, int length) { int valuePosition = findValuePosition(dataPosition, buffer, start, length); if (valuePosition > 0) { switch(buffer[valuePosition++]) { @@ -336,7 +336,7 @@ uint8_t HanReader::getUint8(int dataPosition, byte *buffer, int start, int lengt return 0; } -uint16_t HanReader::getUint16(int dataPosition, byte *buffer, int start, int length) { +uint16_t HanReader::getUint16(uint8_t dataPosition, byte *buffer, int start, int length) { int valuePosition = findValuePosition(dataPosition, buffer, start, length); if (valuePosition > 0 && buffer[valuePosition++] == 0x12) { return buffer[valuePosition] << 8 | buffer[valuePosition+1]; @@ -344,7 +344,7 @@ uint16_t HanReader::getUint16(int dataPosition, byte *buffer, int start, int len return 0; } -uint32_t HanReader::getUint32(int dataPosition, byte *buffer, int start, int length) { +uint32_t HanReader::getUint32(uint8_t dataPosition, byte *buffer, int start, int length) { int valuePosition = findValuePosition(dataPosition, buffer, start, length); if (valuePosition > 0) { if(buffer[valuePosition++] != 0x06) @@ -358,7 +358,7 @@ uint32_t HanReader::getUint32(int dataPosition, byte *buffer, int start, int len return 0; } -String HanReader::getString(int dataPosition, byte *buffer, int start, int length) { +String HanReader::getString(uint8_t dataPosition, byte *buffer, int start, int length) { int valuePosition = findValuePosition(dataPosition, buffer, start, length); if (valuePosition > 0) { String value = String(""); diff --git a/lib/HanReader/src/HanReader.h b/lib/HanReader/src/HanReader.h index f4a4906d..d85f018c 100644 --- a/lib/HanReader/src/HanReader.h +++ b/lib/HanReader/src/HanReader.h @@ -25,10 +25,10 @@ public: bool read(byte data); int getListSize(); time_t getPackageTime(bool respectTimezone, bool respectDsc); - int32_t getInt(int objectId); // Use this for uint8, int8, uint16, int16 - uint32_t getUint(int objectId); // Only for uint32 - String getString(int objectId); - time_t getTime(int objectId, bool respectTimezone, bool respectDsc); + int32_t getInt(uint8_t objectId); // Use this for uint8, int8, uint16, int16 + uint32_t getUint(uint8_t objectId); // Only for uint32 + String getString(uint8_t objectId); + time_t getTime(uint8_t objectId, bool respectTimezone, bool respectDsc); int getBuffer(byte* buf); void setEncryptionKey(uint8_t* encryption_key); @@ -37,27 +37,27 @@ public: private: RemoteDebug* debugger; Stream *han; - byte buffer[512]; + byte* buffer; int bytesRead; DlmsReader reader; int listSize; Timezone *localZone; - uint8_t encryption_key[16]; - uint8_t authentication_key[16]; + uint8_t* encryption_key; + uint8_t* authentication_key; - int findValuePosition(int dataPosition, byte *buffer, int start, int length); + int findValuePosition(uint8_t dataPosition, byte *buffer, int start, int length); - time_t getTime(int dataPosition, bool respectTimezone, bool respectDsc, byte *buffer, int start, int length); + time_t getTime(uint8_t dataPosition, bool respectTimezone, bool respectDsc, byte *buffer, int start, int length); time_t getTime(byte *buffer, int start, int length, bool respectTimezone, bool respectDsc); - int getInt(int dataPosition, byte *buffer, int start, int length); - int8_t getInt8(int dataPosition, byte *buffer, int start, int length); - uint8_t getUint8(int dataPosition, byte *buffer, int start, int length); - int16_t getInt16(int dataPosition, byte *buffer, int start, int length); - uint16_t getUint16(int dataPosition, byte *buffer, int start, int length); - uint32_t getUint32(int dataPosition, byte *buffer, int start, int length); - String getString(int dataPosition, byte *buffer, int start, int length); + int getInt(uint8_t dataPosition, byte *buffer, int start, int length); + int8_t getInt8(uint8_t dataPosition, byte *buffer, int start, int length); + uint8_t getUint8(uint8_t dataPosition, byte *buffer, int start, int length); + int16_t getInt16(uint8_t dataPosition, byte *buffer, int start, int length); + uint16_t getUint16(uint8_t dataPosition, byte *buffer, int start, int length); + uint32_t getUint32(uint8_t dataPosition, byte *buffer, int start, int length); + String getString(uint8_t dataPosition, byte *buffer, int start, int length); - time_t toUnixTime(int year, int month, int day, int hour, int minute, int second); + time_t toUnixTime(uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second); bool decryptFrame(); diff --git a/lib/mbedtls/include/mbedtls/config.h b/lib/mbedtls/include/mbedtls/config.h index d8cc1ab4..cc576ebe 100755 --- a/lib/mbedtls/include/mbedtls/config.h +++ b/lib/mbedtls/include/mbedtls/config.h @@ -34,6 +34,14 @@ #ifndef MBEDTLS_CONFIG_H #define MBEDTLS_CONFIG_H +#define MBEDTLS_SSL_MAX_CONTENT_LEN 8192 +#define MBEDTLS_MPI_MAX_SIZE 128 +#define MBEDTLS_MPI_WINDOW_SIZE 1 +#define MBEDTLS_ECP_MAX_BITS 128 +#define MBEDTLS_ECP_WINDOW_SIZE 2 +#define MBEDTLS_ECP_FIXED_POINT_OPTIM 0 +#define MBEDTLS_AES_ROM_TABLES 1 + /* System support */ #define MBEDTLS_HAVE_ASM #define MBEDTLS_HAVE_TIME @@ -84,9 +92,6 @@ #define MBEDTLS_X509_CRL_PARSE_C //#define MBEDTLS_CMAC_C -/* Miscellaneous options */ -#define MBEDTLS_AES_ROM_TABLES - #include "mbedtls/check_config.h" #endif /* MBEDTLS_CONFIG_H */ diff --git a/src/AmsConfiguration.cpp b/src/AmsConfiguration.cpp index 05ed34c0..be64bc4b 100644 --- a/src/AmsConfiguration.cpp +++ b/src/AmsConfiguration.cpp @@ -1,99 +1,78 @@ #include "AmsConfiguration.h" -uint8_t AmsConfiguration::getBoardType() { - return config.boardType; +bool AmsConfiguration::getSystemConfig(SystemConfig& config) { + if(hasConfig()) { + EEPROM.begin(EEPROM_SIZE); + EEPROM.get(CONFIG_SYSTEM_START, config); + EEPROM.end(); + return true; + } else { + return false; + } } -void AmsConfiguration::setBoardType(uint8_t boardType) { - config.boardType = boardType; +bool AmsConfiguration::setSystemConfig(SystemConfig& config) { + EEPROM.begin(EEPROM_SIZE); + EEPROM.put(CONFIG_SYSTEM_START, config); + bool ret = EEPROM.commit(); + EEPROM.end(); + return ret; } -char* AmsConfiguration::getWifiSsid() { - return config.wifiSsid; +bool AmsConfiguration::getWiFiConfig(WiFiConfig& config) { + if(hasConfig()) { + EEPROM.begin(EEPROM_SIZE); + EEPROM.get(CONFIG_WIFI_START, config); + EEPROM.end(); + return true; + } else { + clearWifi(config); + return false; + } } -void AmsConfiguration::setWifiSsid(const char* wifiSsid) { - wifiChanged |= strcmp(config.wifiSsid, wifiSsid) != 0; - strcpy(config.wifiSsid, wifiSsid); +bool AmsConfiguration::setWiFiConfig(WiFiConfig& config) { + WiFiConfig existing; + if(getWiFiConfig(existing)) { + wifiChanged |= strcmp(config.ssid, existing.ssid) != 0; + wifiChanged |= strcmp(config.psk, existing.psk) != 0; + wifiChanged |= strcmp(config.ip, existing.ip) != 0; + wifiChanged |= strcmp(config.gateway, existing.gateway) != 0; + wifiChanged |= strcmp(config.subnet, existing.subnet) != 0; + wifiChanged |= strcmp(config.dns1, existing.dns1) != 0; + wifiChanged |= strcmp(config.dns2, existing.dns2) != 0; + wifiChanged |= strcmp(config.hostname, existing.hostname) != 0; + } else { + wifiChanged = true; + } + EEPROM.begin(EEPROM_SIZE); + EEPROM.put(CONFIG_WIFI_START, config); + bool ret = EEPROM.commit(); + EEPROM.end(); + return ret; } -char* AmsConfiguration::getWifiPassword() { - return config.wifiPassword; +void AmsConfiguration::clearWifi(WiFiConfig& config) { + strcpy(config.ssid, ""); + strcpy(config.psk, ""); + clearWifiIp(config); + + uint16_t chipId; + #if defined(ESP32) + chipId = ESP.getEfuseMac(); + #else + chipId = ESP.getChipId(); + #endif + strcpy(config.hostname, (String("ams-") + String(chipId, HEX)).c_str()); + config.mdns = true; } -void AmsConfiguration::setWifiPassword(const char* wifiPassword) { - wifiChanged |= strcmp(config.wifiPassword, wifiPassword) != 0; - strcpy(config.wifiPassword, wifiPassword); -} - -char* AmsConfiguration::getWifiIp() { - return config.wifiIp; -} - -void AmsConfiguration::setWifiIp(const char* wifiIp) { - wifiChanged |= strcmp(config.wifiIp, wifiIp) != 0; - strcpy(config.wifiIp, wifiIp); -} - -char* AmsConfiguration::getWifiGw() { - return config.wifiGw; -} - -void AmsConfiguration::setWifiGw(const char* wifiGw) { - wifiChanged |= strcmp(config.wifiGw, wifiGw) != 0; - strcpy(config.wifiGw, wifiGw); -} - -char* AmsConfiguration::getWifiSubnet() { - return config.wifiSubnet; -} - -void AmsConfiguration::setWifiSubnet(const char* wifiSubnet) { - wifiChanged |= strcmp(config.wifiSubnet, wifiSubnet) != 0; - strcpy(config.wifiSubnet, wifiSubnet); -} - -char* AmsConfiguration::getWifiDns1() { - return config.wifiDns1; -} - -void AmsConfiguration::setWifiDns1(const char* wifiDns1) { - wifiChanged |= strcmp(config.wifiDns1, wifiDns1) != 0; - strcpy(config.wifiDns1, wifiDns1); -} - -char* AmsConfiguration::getWifiDns2() { - return config.wifiDns2; -} - -void AmsConfiguration::setWifiDns2(const char* wifiDns2) { - wifiChanged |= strcmp(config.wifiDns2, wifiDns2) != 0; - strcpy(config.wifiDns2, wifiDns2); -} - -char* AmsConfiguration::getWifiHostname() { - return config.wifiHostname; -} - -void AmsConfiguration::setWifiHostname(const char* wifiHostname) { - wifiChanged |= strcmp(config.wifiHostname, wifiHostname) != 0; - strcpy(config.wifiHostname, wifiHostname); -} - -void AmsConfiguration::clearWifi() { - setWifiSsid(""); - setWifiPassword(""); - setWifiHostname(""); - setMdnsEnable(true); - clearWifiIp(); -} - -void AmsConfiguration::clearWifiIp() { - setWifiIp(""); - setWifiGw(""); - setWifiSubnet(""); - setWifiDns1(""); - setWifiDns2(""); +void AmsConfiguration::clearWifiIp(WiFiConfig& config) { + strcpy(config.ip, ""); + strcpy(config.gateway, ""); + strcpy(config.subnet, ""); + strcpy(config.dns1, ""); + strcpy(config.dns2, ""); } bool AmsConfiguration::isWifiChanged() { @@ -104,96 +83,49 @@ void AmsConfiguration::ackWifiChange() { wifiChanged = false; } - -char* AmsConfiguration::getMqttHost() { - return config.mqttHost; +bool AmsConfiguration::getMqttConfig(MqttConfig& config) { + if(hasConfig()) { + EEPROM.begin(EEPROM_SIZE); + EEPROM.get(CONFIG_MQTT_START, config); + EEPROM.end(); + return true; + } else { + clearMqtt(config); + return false; + } } -void AmsConfiguration::setMqttHost(const char* mqttHost) { - mqttChanged |= strcmp(config.mqttHost, mqttHost) != 0; - strcpy(config.mqttHost, mqttHost); +bool AmsConfiguration::setMqttConfig(MqttConfig& config) { + MqttConfig existing; + if(getMqttConfig(existing)) { + mqttChanged |= strcmp(config.host, existing.host) != 0; + mqttChanged |= config.port != existing.port; + mqttChanged |= strcmp(config.clientId, existing.clientId) != 0; + mqttChanged |= strcmp(config.publishTopic, existing.publishTopic) != 0; + mqttChanged |= strcmp(config.subscribeTopic, existing.subscribeTopic) != 0; + mqttChanged |= strcmp(config.username, existing.username) != 0; + mqttChanged |= strcmp(config.password, existing.password) != 0; + mqttChanged |= config.ssl != existing.ssl; + } else { + mqttChanged = true; + } + EEPROM.begin(EEPROM_SIZE); + EEPROM.put(CONFIG_MQTT_START, config); + bool ret = EEPROM.commit(); + EEPROM.end(); + return ret; } -uint16_t AmsConfiguration::getMqttPort() { - return config.mqttPort; -} - -void AmsConfiguration::setMqttPort(uint16_t mqttPort) { - mqttChanged |= config.mqttPort != mqttPort; - config.mqttPort = mqttPort; -} - -char* AmsConfiguration::getMqttClientId() { - return config.mqttClientId; -} - -void AmsConfiguration::setMqttClientId(const char* mqttClientId) { - mqttChanged |= strcmp(config.mqttClientId, mqttClientId) != 0; - strcpy(config.mqttClientId, mqttClientId); -} - -char* AmsConfiguration::getMqttPublishTopic() { - return config.mqttPublishTopic; -} - -void AmsConfiguration::setMqttPublishTopic(const char* mqttPublishTopic) { - mqttChanged |= strcmp(config.mqttPublishTopic, mqttPublishTopic) != 0; - strcpy(config.mqttPublishTopic, mqttPublishTopic); -} - -char* AmsConfiguration::getMqttSubscribeTopic() { - return config.mqttSubscribeTopic; -} - -void AmsConfiguration::setMqttSubscribeTopic(const char* mqttSubscribeTopic) { - mqttChanged |= strcmp(config.mqttSubscribeTopic, mqttSubscribeTopic) != 0; - strcpy(config.mqttSubscribeTopic, mqttSubscribeTopic); -} - -char* AmsConfiguration::getMqttUser() { - return config.mqttUser; -} - -void AmsConfiguration::setMqttUser(const char* mqttUser) { - mqttChanged |= strcmp(config.mqttUser, mqttUser) != 0; - strcpy(config.mqttUser, mqttUser); -} - -char* AmsConfiguration::getMqttPassword() { - return config.mqttPassword; -} - -void AmsConfiguration::setMqttPassword(const char* mqttPassword) { - mqttChanged |= strcmp(config.mqttPassword, mqttPassword) != 0; - strcpy(config.mqttPassword, mqttPassword); -} - -uint8_t AmsConfiguration::getMqttPayloadFormat() { - return config.mqttPayloadFormat; -} - -void AmsConfiguration::setMqttPayloadFormat(uint8_t mqttPayloadFormat) { - config.mqttPayloadFormat = mqttPayloadFormat; -} - -bool AmsConfiguration::isMqttSsl() { - return config.mqttSsl; -} - -void AmsConfiguration::setMqttSsl(bool mqttSsl) { - mqttChanged |= config.mqttSsl != mqttSsl; - config.mqttSsl = mqttSsl; -} - -void AmsConfiguration::clearMqtt() { - setMqttHost(""); - setMqttPort(1883); - setMqttClientId(""); - setMqttPublishTopic(""); - setMqttSubscribeTopic(""); - setMqttUser(""); - setMqttPassword(""); - setMqttSsl(false); +void AmsConfiguration::clearMqtt(MqttConfig& config) { + strcpy(config.host, ""); + config.port = 1883; + strcpy(config.clientId, ""); + strcpy(config.publishTopic, ""); + strcpy(config.subscribeTopic, ""); + strcpy(config.username, ""); + strcpy(config.password, ""); + config.payloadFormat = 0; + config.ssl = false; } void AmsConfiguration::setMqttChanged() { @@ -208,114 +140,69 @@ void AmsConfiguration::ackMqttChange() { mqttChanged = false; } -byte AmsConfiguration::getAuthSecurity() { - return config.authSecurity; +bool AmsConfiguration::getWebConfig(WebConfig& config) { + if(hasConfig()) { + EEPROM.begin(EEPROM_SIZE); + EEPROM.get(CONFIG_WEB_START, config); + EEPROM.end(); + return true; + } else { + clearAuth(config); + return false; + } } -void AmsConfiguration::setAuthSecurity(byte authSecurity) { - config.authSecurity = authSecurity; +bool AmsConfiguration::setWebConfig(WebConfig& config) { + EEPROM.begin(EEPROM_SIZE); + EEPROM.put(CONFIG_WEB_START, config); + bool ret = EEPROM.commit(); + EEPROM.end(); + return ret; } -char* AmsConfiguration::getAuthUser() { - return config.authUser; +void AmsConfiguration::clearAuth(WebConfig& config) { + config.security = 0; + strcpy(config.username, ""); + strcpy(config.password, ""); } -void AmsConfiguration::setAuthUser(const char* authUser) { - strcpy(config.authUser, authUser); +bool AmsConfiguration::getMeterConfig(MeterConfig& config) { + if(hasConfig()) { + EEPROM.begin(EEPROM_SIZE); + EEPROM.get(CONFIG_METER_START, config); + EEPROM.end(); + return true; + } else { + clearMeter(config); + return false; + } } -char* AmsConfiguration::getAuthPassword() { - return config.authPassword; +bool AmsConfiguration::setMeterConfig(MeterConfig& config) { + MeterConfig existing; + if(getMeterConfig(existing)) { + meterChanged |= config.type != existing.type; + meterChanged |= strcmp((char*) config.encryptionKey, (char*) existing.encryptionKey); + meterChanged |= strcmp((char*) config.authenticationKey, (char*) existing.authenticationKey); + } else { + meterChanged = true; + } + EEPROM.begin(EEPROM_SIZE); + EEPROM.put(CONFIG_METER_START, config); + bool ret = EEPROM.commit(); + EEPROM.end(); + return ret; } -void AmsConfiguration::setAuthPassword(const char* authPassword) { - strcpy(config.authPassword, authPassword); -} - -void AmsConfiguration::clearAuth() { - setAuthSecurity(0); - setAuthUser(""); - setAuthPassword(""); -} - -uint8_t AmsConfiguration::getMeterType() { - return config.meterType; -} - -void AmsConfiguration::setMeterType(uint8_t meterType) { - meterChanged |= config.meterType != meterType; - config.meterType = meterType; -} - -uint8_t AmsConfiguration::getDistributionSystem() { - return config.distributionSystem; -} - -void AmsConfiguration::setDistributionSystem(uint8_t distributionSystem) { - config.distributionSystem = distributionSystem; -} - -uint8_t AmsConfiguration::getMainFuse() { - return config.mainFuse; -} - -void AmsConfiguration::setMainFuse(uint8_t mainFuse) { - config.mainFuse = mainFuse; -} - -uint8_t AmsConfiguration::getProductionCapacity() { - return config.productionCapacity; -} - -void AmsConfiguration::setProductionCapacity(uint8_t productionCapacity) { - config.productionCapacity = productionCapacity; -} - -uint8_t* AmsConfiguration::getMeterEncryptionKey() { - return config.meterEncryptionKey; -} - -void AmsConfiguration::setMeterEncryptionKey(uint8_t* meterEncryptionKey) { - meterChanged |= strcmp((char*) config.meterEncryptionKey, (char*) meterEncryptionKey); - memcpy(config.meterEncryptionKey, meterEncryptionKey, 16); -} - -uint8_t* AmsConfiguration::getMeterAuthenticationKey() { - return config.meterAuthenticationKey; -} - -void AmsConfiguration::setMeterAuthenticationKey(uint8_t* meterAuthenticationKey) { - meterChanged |= strcmp((char*) config.meterAuthenticationKey, (char*) meterAuthenticationKey); - memcpy(config.meterAuthenticationKey, meterAuthenticationKey, 16); -} - -bool AmsConfiguration::isSubstituteMissing() { - return config.substituteMissing; -} - -void AmsConfiguration::setSubstituteMissing(bool substituteMissing) { - config.substituteMissing = substituteMissing; -} - -bool AmsConfiguration::isSendUnknown() { - return config.sendUnknown; -} - -void AmsConfiguration::setSendUnknown(bool sendUnknown) { - config.sendUnknown = sendUnknown; -} - -void AmsConfiguration::clearMeter() { - uint8_t blankKey[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - setMeterType(0); - setDistributionSystem(0); - setMainFuse(0); - setProductionCapacity(0); - setMeterEncryptionKey(blankKey); - setMeterAuthenticationKey(blankKey); - setSubstituteMissing(false); - setSendUnknown(false); +void AmsConfiguration::clearMeter(MeterConfig& config) { + config.type = 0; + config.distributionSystem = 0; + config.mainFuse = 0; + config.productionCapacity = 0; + memset(config.encryptionKey, 0, 16); + memset(config.authenticationKey, 0, 16); + config.substituteMissing = false; + config.sendUnknown = false; } bool AmsConfiguration::isMeterChanged() { @@ -326,231 +213,63 @@ void AmsConfiguration::ackMeterChanged() { meterChanged = false; } - -bool AmsConfiguration::isDebugTelnet() { - return config.debugTelnet; -} - -void AmsConfiguration::setDebugTelnet(bool debugTelnet) { - config.debugTelnet = debugTelnet; -} - -bool AmsConfiguration::isDebugSerial() { - return config.debugSerial; -} - -void AmsConfiguration::setDebugSerial(bool debugSerial) { - config.debugSerial = debugSerial; -} - -uint8_t AmsConfiguration::getDebugLevel() { - return config.debugLevel; -} - -void AmsConfiguration::setDebugLevel(uint8_t debugLevel) { - config.debugLevel = debugLevel; -} - -uint16_t AmsConfiguration::getDomoELIDX() { - return config.domoELIDX; -} -uint16_t AmsConfiguration::getDomoVL1IDX() { - return config.domoVL1IDX; -} -uint16_t AmsConfiguration::getDomoVL2IDX() { - return config.domoVL2IDX; -} -uint16_t AmsConfiguration::getDomoVL3IDX() { - return config.domoVL3IDX; -} -uint16_t AmsConfiguration::getDomoCL1IDX() { - return config.domoCL1IDX; -} - -void AmsConfiguration::setDomoELIDX(uint16_t domoELIDX) { - domoChanged |= config.domoELIDX != domoELIDX; - config.domoELIDX = domoELIDX; -} - -void AmsConfiguration::setDomoVL1IDX(uint16_t domoVL1IDX) { - domoChanged |= config.domoVL1IDX != domoVL1IDX; - config.domoVL1IDX = domoVL1IDX; -} - -void AmsConfiguration::setDomoVL2IDX(uint16_t domoVL2IDX) { - domoChanged |= config.domoVL2IDX != domoVL2IDX; - config.domoVL2IDX = domoVL2IDX; -} - -void AmsConfiguration::setDomoVL3IDX(uint16_t domoVL3IDX) { - domoChanged |= config.domoVL3IDX != domoVL3IDX; - config.domoVL3IDX = domoVL3IDX; -} - -void AmsConfiguration::setDomoCL1IDX(uint16_t domoCL1IDX) { - domoChanged |= config.domoCL1IDX != domoCL1IDX; - config.domoCL1IDX = domoCL1IDX; -} - -void AmsConfiguration::clearDomo() { - setDomoELIDX(0); - setDomoVL1IDX(0); - setDomoVL2IDX(0); - setDomoVL3IDX(0); - setDomoCL1IDX(0); -} - -bool AmsConfiguration::pinUsed(uint8_t pin) { - if(pin == 0xFF) +bool AmsConfiguration::getDebugConfig(DebugConfig& config) { + if(hasConfig()) { + EEPROM.begin(EEPROM_SIZE); + EEPROM.get(CONFIG_DEBUG_START, config); + EEPROM.end(); + return true; + } else { return false; - return - pin == config.hanPin || - pin == config.apPin || - pin == config.ledPinRed || - pin == config.ledPinGreen || - pin == config.ledPinBlue || - pin == config.tempSensorPin || - pin == config.vccPin - ; -} - -uint8_t AmsConfiguration::getHanPin() { - return config.hanPin; -} - -void AmsConfiguration::setHanPin(uint8_t hanPin) { - if(!pinUsed(hanPin)) { - meterChanged |= config.hanPin != hanPin; - config.hanPin = hanPin; } } -uint8_t AmsConfiguration::getApPin() { - return config.apPin; +bool AmsConfiguration::setDebugConfig(DebugConfig& config) { + EEPROM.begin(EEPROM_SIZE); + EEPROM.put(CONFIG_DEBUG_START, config); + bool ret = EEPROM.commit(); + EEPROM.end(); + return ret; } -void AmsConfiguration::setApPin(uint8_t apPin) { - if(!pinUsed(apPin)) { - config.apPin = apPin; - if(apPin >= 0) - pinMode(apPin, INPUT_PULLUP); +bool AmsConfiguration::getDomoticzConfig(DomoticzConfig& config) { + if(hasConfig()) { + EEPROM.begin(EEPROM_SIZE); + EEPROM.get(CONFIG_DOMOTICZ_START, config); + EEPROM.end(); + return true; + } else { + clearDomo(config); + return false; } } -uint8_t AmsConfiguration::getLedPin() { - return config.ledPin; -} - -void AmsConfiguration::setLedPin(uint8_t ledPin) { - if(!pinUsed(ledPin)) { - config.ledPin = ledPin; +bool AmsConfiguration::setDomoticzConfig(DomoticzConfig& config) { + DomoticzConfig existing; + if(getDomoticzConfig(existing)) { + domoChanged |= config.elidx != existing.elidx; + domoChanged |= config.vl1idx != existing.vl1idx; + domoChanged |= config.vl2idx != existing.vl2idx; + domoChanged |= config.vl3idx != existing.vl3idx; + domoChanged |= config.cl1idx != existing.cl1idx; + } else { + domoChanged = true; } + EEPROM.begin(EEPROM_SIZE); + EEPROM.put(CONFIG_DOMOTICZ_START, config); + bool ret = EEPROM.commit(); + EEPROM.end(); + return ret; } -bool AmsConfiguration::isLedInverted() { - return config.ledInverted; +void AmsConfiguration::clearDomo(DomoticzConfig& config) { + config.elidx = 0; + config.vl1idx = 0; + config.vl2idx = 0; + config.vl3idx = 0; + config.cl1idx = 0; } -void AmsConfiguration::setLedInverted(bool ledInverted) { - config.ledInverted = ledInverted; -} - - -uint8_t AmsConfiguration::getLedPinRed() { - return config.ledPinRed; -} - -void AmsConfiguration::setLedPinRed(uint8_t ledPinRed) { - if(!pinUsed(ledPinRed)) { - config.ledPinRed = ledPinRed; - } -} - -uint8_t AmsConfiguration::getLedPinGreen() { - return config.ledPinGreen; -} - -void AmsConfiguration::setLedPinGreen(uint8_t ledPinGreen) { - if(!pinUsed(ledPinGreen)) { - config.ledPinGreen = ledPinGreen; - } -} - -uint8_t AmsConfiguration::getLedPinBlue() { - return config.ledPinBlue; -} - -void AmsConfiguration::setLedPinBlue(uint8_t ledPinBlue) { - if(!pinUsed(ledPinBlue)) { - config.ledPinBlue = ledPinBlue; - } -} - -bool AmsConfiguration::isLedRgbInverted() { - return config.ledRgbInverted; -} - -void AmsConfiguration::setLedRgbInverted(bool ledRgbInverted) { - config.ledRgbInverted = ledRgbInverted; -} - - -uint8_t AmsConfiguration::getTempSensorPin() { - return config.tempSensorPin; -} - -void AmsConfiguration::setTempSensorPin(uint8_t tempSensorPin) { - if(!pinUsed(tempSensorPin)) { - config.tempSensorPin = tempSensorPin; - } -} - -uint8_t AmsConfiguration::getTempAnalogSensorPin() { - return config.tempAnalogSensorPin; -} - -void AmsConfiguration::setTempAnalogSensorPin(uint8_t tempAnalogSensorPin) { - if(!pinUsed(tempAnalogSensorPin)) { - config.tempAnalogSensorPin = tempAnalogSensorPin; - } -} - -uint8_t AmsConfiguration::getVccPin() { - return config.vccPin; -} - -void AmsConfiguration::setVccPin(uint8_t vccPin) { - if(!pinUsed(vccPin)) { - config.vccPin = vccPin; - } -} - -double AmsConfiguration::getVccOffset() { - return config.vccOffset > 0 ? config.vccOffset / 100.0 : 0; -} - -void AmsConfiguration::setVccOffset(double vccOffset) { - config.vccOffset = vccOffset == 0 ? 0 : max(-350, min((int)(vccOffset * 100.0), 350)); -} - -double AmsConfiguration::getVccMultiplier() { - return config.vccMultiplier > 0 ? config.vccMultiplier / 1000.0 : 0; -} - -void AmsConfiguration::setVccMultiplier(double vccMultiplier) { - config.vccMultiplier = max(1, min((int) (vccMultiplier * 1000), 65535)); -} - -double AmsConfiguration::getVccBootLimit() { - return config.vccBootLimit > 0 ? config.vccBootLimit / 10.0 : 0; -} - -void AmsConfiguration::setVccBootLimit(double vccBootLimit) { - if(vccBootLimit == 0.0) - config.vccBootLimit = 0; - else - config.vccBootLimit = max(25, min((int)(vccBootLimit * 10), 35)); -} bool AmsConfiguration::isDomoChanged() { return domoChanged; } @@ -559,62 +278,138 @@ void AmsConfiguration::ackDomoChange() { domoChanged = false; } -bool AmsConfiguration::isMdnsEnable() { - return config.mDnsEnable; +bool AmsConfiguration::pinUsed(uint8_t pin, GpioConfig& config) { + if(pin == 0xFF) + return false; + return + pin == config.hanPin || + pin == config.apPin || + pin == config.ledPin || + pin == config.ledPinRed || + pin == config.ledPinGreen || + pin == config.ledPinBlue || + pin == config.tempSensorPin || + pin == config.tempAnalogSensorPin || + pin == config.vccPin + ; } -void AmsConfiguration::setMdnsEnable(bool mdnsEnable) { - config.mDnsEnable = mdnsEnable; -} - -bool AmsConfiguration::isNtpEnable() { - return config.ntpEnable; -} - -void AmsConfiguration::setNtpEnable(bool ntpEnable) { - if(config.ntpEnable != ntpEnable) { - if(!ntpEnable) { - wifiChanged = true; - } else { - ntpChanged = true; - } - config.ntpEnable = ntpEnable; +bool AmsConfiguration::getGpioConfig(GpioConfig& config) { + if(hasConfig()) { + EEPROM.begin(EEPROM_SIZE); + EEPROM.get(CONFIG_GPIO_START, config); + EEPROM.end(); + return true; + } else { + clearGpio(config); + return false; } } -bool AmsConfiguration::isNtpDhcp() { - return config.ntpDhcp; +bool AmsConfiguration::setGpioConfig(GpioConfig& config) { + GpioConfig existing; + if(getGpioConfig(existing)) { + meterChanged |= config.hanPin != existing.hanPin; + } + /* This currently does not work, as it checks its own pin + if(pinUsed(config.hanPin, config)) { + Serial.println("HAN pin already used"); + return false; + } + if(pinUsed(config.apPin, config)) { + Serial.println("AP pin already used"); + return false; + } + if(pinUsed(config.ledPin, config)) { + Serial.println("LED pin already used"); + return false; + } + if(pinUsed(config.ledPinRed, config)) { + Serial.println("LED RED pin already used"); + return false; + } + if(pinUsed(config.ledPinGreen, config)) { + Serial.println("LED GREEN pin already used"); + return false; + } + if(pinUsed(config.ledPinBlue, config)) { + Serial.println("LED BLUE pin already used"); + return false; + } + if(pinUsed(config.tempSensorPin, config)) { + Serial.println("Temp sensor pin already used"); + return false; + } + if(pinUsed(config.tempAnalogSensorPin, config)) { + Serial.println("Analog temp sensor pin already used"); + return false; + } + if(pinUsed(config.vccPin, config)) { + Serial.println("Vcc pin already used"); + return false; + } + */ + if(config.apPin >= 0) + pinMode(config.apPin, INPUT_PULLUP); + + EEPROM.begin(EEPROM_SIZE); + EEPROM.put(CONFIG_GPIO_START, config); + bool ret = EEPROM.commit(); + EEPROM.end(); + return ret; } -void AmsConfiguration::setNtpDhcp(bool ntpDhcp) { - ntpChanged |= config.ntpDhcp != ntpDhcp; - config.ntpDhcp = ntpDhcp; +void AmsConfiguration::clearGpio(GpioConfig& config) { + config.hanPin = 3; + config.apPin = 0xFF; + config.ledPin = 0xFF; + config.ledInverted = true; + config.ledPinRed = 0xFF; + config.ledPinGreen = 0xFF; + config.ledPinBlue = 0xFF; + config.ledRgbInverted = true; + config.tempSensorPin = 0xFF; + config.tempAnalogSensorPin = 0xFF; + config.vccPin = 0xFF; + config.vccOffset = 0; + config.vccMultiplier = 1000; + config.vccBootLimit = 0; } -int32_t AmsConfiguration::getNtpOffset() { - return config.ntpOffset * 10; +bool AmsConfiguration::getNtpConfig(NtpConfig& config) { + if(hasConfig()) { + EEPROM.begin(EEPROM_SIZE); + EEPROM.get(CONFIG_NTP_START, config); + EEPROM.end(); + return true; + } else { + clearNtp(config); + return false; + } } -void AmsConfiguration::setNtpOffset(uint32_t ntpOffset) { - ntpChanged |= config.ntpOffset != ntpOffset/10; - config.ntpOffset = ntpOffset == 0 ? 0 : ntpOffset / 10; -} - -int32_t AmsConfiguration::getNtpSummerOffset() { - return config.ntpSummerOffset * 10; -} - -void AmsConfiguration::setNtpSummerOffset(uint32_t ntpSummerOffset) { - ntpChanged |= config.ntpSummerOffset != ntpSummerOffset/10; - config.ntpSummerOffset = ntpSummerOffset == 0 ? 0 : ntpSummerOffset / 10; -} - -char* AmsConfiguration::getNtpServer() { - return config.ntpServer; -} - -void AmsConfiguration::setNtpServer(const char* ntpServer) { - strcpy(config.ntpServer, ntpServer); +bool AmsConfiguration::setNtpConfig(NtpConfig& config) { + NtpConfig existing; + if(getNtpConfig(existing)) { + if(config.enable != existing.enable) { + if(!existing.enable) { + wifiChanged = true; + } else { + ntpChanged = true; + } + } + ntpChanged |= config.dhcp != existing.dhcp; + ntpChanged |= config.offset != existing.offset; + ntpChanged |= config.summerOffset != existing.summerOffset; + ntpChanged |= strcmp(config.server, existing.server) != 0; + } else { + ntpChanged = true; + } + EEPROM.begin(EEPROM_SIZE); + EEPROM.put(CONFIG_NTP_START, config); + bool ret = EEPROM.commit(); + EEPROM.end(); + return ret; } bool AmsConfiguration::isNtpChanged() { @@ -625,63 +420,60 @@ void AmsConfiguration::ackNtpChange() { ntpChanged = false; } -void AmsConfiguration::clearNtp() { - setNtpEnable(true); - setNtpDhcp(true); - setNtpOffset(3600); - setNtpSummerOffset(3600); - setNtpServer("pool.ntp.org"); +void AmsConfiguration::clearNtp(NtpConfig& config) { + config.enable = true; + config.dhcp = true; + config.offset = 360; + config.summerOffset = 360; + strcpy(config.server, "pool.ntp.org"); } - -char* AmsConfiguration::getEntsoeApiToken() { - return config.entsoeApiToken; +bool AmsConfiguration::getEntsoeConfig(EntsoeConfig& config) { + if(hasConfig()) { + EEPROM.begin(EEPROM_SIZE); + EEPROM.get(CONFIG_ENTSOE_START, config); + EEPROM.end(); + return true; + } else { + return false; + } } -void AmsConfiguration::setEntsoeApiToken(const char* token) { - strcpy(config.entsoeApiToken, token); +bool AmsConfiguration::setEntsoeConfig(EntsoeConfig& config) { + EEPROM.begin(EEPROM_SIZE); + EEPROM.put(CONFIG_ENTSOE_START, config); + bool ret = EEPROM.commit(); + EEPROM.end(); + return ret; } -char* AmsConfiguration::getEntsoeApiArea() { - return config.entsoeApiArea; -} - -void AmsConfiguration::setEntsoeApiArea(const char* area) { - strcpy(config.entsoeApiArea, area); -} - -char* AmsConfiguration::getEntsoeApiCurrency() { - return config.entsoeApiCurrency; -} - -void AmsConfiguration::setEntsoeApiCurrency(const char* currency) { - strcpy(config.entsoeApiCurrency, currency); -} - -double AmsConfiguration::getEntsoeApiMultiplier() { - return config.entsoeApiMultiplier; -} - -void AmsConfiguration::setEntsoeApiMultiplier(double multiplier) { - config.entsoeApiMultiplier = multiplier; -} - - - void AmsConfiguration::clear() { - clearMeter(); - clearWifi(); - clearMqtt(); - clearAuth(); - clearDomo(); - clearNtp(); + MeterConfig meter; + clearMeter(meter); + setMeterConfig(meter); - int address = EEPROM_CONFIG_ADDRESS; + WiFiConfig wifi; + clearWifi(wifi); + setWiFiConfig(wifi); + + MqttConfig mqtt; + clearMqtt(mqtt); + setMqttConfig(mqtt); + + WebConfig web; + clearAuth(web); + setWebConfig(web); + + DomoticzConfig domo; + clearDomo(domo); + setDomoticzConfig(domo); + + NtpConfig ntp; + clearNtp(ntp); + setNtpConfig(ntp); EEPROM.begin(EEPROM_SIZE); - while(address < EEPROM_CONFIG_ADDRESS+EEPROM_SIZE) { - EEPROM.put(address++, 0); - } + EEPROM.put(EEPROM_CONFIG_ADDRESS, -1); EEPROM.commit(); EEPROM.end(); } @@ -693,10 +485,23 @@ bool AmsConfiguration::hasConfig() { EEPROM.end(); } switch(configVersion) { - case 81: case 82: + if(loadConfig82(EEPROM_CONFIG_ADDRESS+1)) { + return true; + } else { + configVersion = 0; + return false; + } + break; case 83: - case 84: + if(loadConfig83(EEPROM_CONFIG_ADDRESS+1)) { + return true; + } else { + configVersion = 0; + return false; + } + break; + case EEPROM_CHECK_SUM: return true; default: configVersion = 0; @@ -708,36 +513,8 @@ int AmsConfiguration::getConfigVersion() { return configVersion; } -bool AmsConfiguration::load() { - int address = EEPROM_CONFIG_ADDRESS; - bool success = false; - - EEPROM.begin(EEPROM_SIZE); - int cs = EEPROM.read(address++); - switch(cs) { - case 82: // v1.3 - success = loadConfig82(address); - break; - case 83: // v1.4 - success = loadConfig83(address); - break; - case 84: // v1.5 - EEPROM.get(address, config); - loadTempSensors(); - success = true; - break; - } - EEPROM.end(); - - - if(config.apPin >= 0) - pinMode(config.apPin, INPUT_PULLUP); - meterChanged = true; - - return success; -} - void AmsConfiguration::loadTempSensors() { + this->tempSensors = new TempSensorConfig*[32]; int address = EEPROM_TEMP_CONFIG_ADDRESS; int c = 0; int storedCount = EEPROM.read(address++); @@ -767,136 +544,199 @@ void AmsConfiguration::saveTempSensors() { } bool AmsConfiguration::loadConfig82(int address) { - ConfigObject82 config82; - EEPROM.get(address, config82); - config.boardType = config82.boardType; - strcpy(config.wifiSsid, config82.wifiSsid); - strcpy(config.wifiPassword, config82.wifiPassword); - strcpy(config.wifiIp, config82.wifiIp); - strcpy(config.wifiGw, config82.wifiGw); - strcpy(config.wifiSubnet, config82.wifiSubnet); - strcpy(config.wifiDns1, config82.wifiDns1); - strcpy(config.wifiDns2, config82.wifiDns2); - strcpy(config.wifiHostname, config82.wifiHostname); - strcpy(config.mqttHost, config82.mqttHost); - config.mqttPort = config82.mqttPort; - strcpy(config.mqttClientId, config82.mqttClientId); - strcpy(config.mqttPublishTopic, config82.mqttPublishTopic); - strcpy(config.mqttSubscribeTopic, config82.mqttSubscribeTopic); - strcpy(config.mqttUser, config82.mqttUser); - strcpy(config.mqttPassword, config82.mqttPassword); - config.mqttPayloadFormat = config82.mqttPayloadFormat; - config.mqttSsl = config82.mqttSsl; - config.authSecurity = config82.authSecurity; - strcpy(config.authUser, config82.authUser); - strcpy(config.authPassword, config82.authPassword); - - config.meterType = config82.meterType; - config.distributionSystem = config82.distributionSystem; - config.mainFuse = config82.mainFuse; - config.productionCapacity = config82.productionCapacity; - config.substituteMissing = config82.substituteMissing; - config.sendUnknown = config82.sendUnknown; + ConfigObject82 c; + EEPROM.begin(EEPROM_SIZE); + EEPROM.get(address, c); + EEPROM.end(); - config.debugTelnet = config82.debugTelnet; - config.debugSerial = config82.debugSerial; - config.debugLevel = config82.debugLevel; + DomoticzConfig domo { + c.domoELIDX, + c.domoVL1IDX, + c.domoVL2IDX, + c.domoVL3IDX, + c.domoCL1IDX + }; + setDomoticzConfig(domo); - config.hanPin = config82.hanPin; - config.apPin = config82.apPin; - config.ledPin = config82.ledPin; - config.ledInverted = config82.ledInverted; - config.ledPinRed = config82.ledPinRed; - config.ledPinGreen = config82.ledPinGreen; - config.ledPinBlue = config82.ledPinBlue; - config.ledRgbInverted = config82.ledRgbInverted; - config.tempSensorPin = config82.tempSensorPin; - config.vccPin = config82.vccPin; - config.vccMultiplier = config82.vccMultiplier; - config.vccBootLimit = config82.vccBootLimit; + 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 + }; + setGpioConfig(gpio); - config.domoELIDX = config82.domoELIDX; - config.domoVL1IDX = config82.domoVL1IDX; - config.domoVL2IDX = config82.domoVL2IDX; - config.domoVL3IDX = config82.domoVL3IDX; - config.domoCL1IDX = config82.domoCL1IDX; + DebugConfig debug { + c.debugTelnet, + c.debugSerial, + c.debugLevel + }; + setDebugConfig(debug); + + MeterConfig meter { + c.meterType, + c.distributionSystem, + c.mainFuse, + c.productionCapacity, + {0}, + {0}, + c.substituteMissing, + c.sendUnknown + }; + setMeterConfig(meter); + + WebConfig web { + c.authSecurity + }; + strcpy(web.username, c.authUser); + strcpy(web.password, c.authPassword); + setWebConfig(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; + setMqttConfig(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; + setWiFiConfig(wifi); + + SystemConfig sys { + c.boardType + }; + setSystemConfig(sys); + return save(); } bool AmsConfiguration::loadConfig83(int address) { - ConfigObject83 config83; - EEPROM.get(address, config83); - config.boardType = config83.boardType; - strcpy(config.wifiSsid, config83.wifiSsid); - strcpy(config.wifiPassword, config83.wifiPassword); - strcpy(config.wifiIp, config83.wifiIp); - strcpy(config.wifiGw, config83.wifiGw); - strcpy(config.wifiSubnet, config83.wifiSubnet); - strcpy(config.wifiDns1, config83.wifiDns1); - strcpy(config.wifiDns2, config83.wifiDns2); - strcpy(config.wifiHostname, config83.wifiHostname); - strcpy(config.mqttHost, config83.mqttHost); - config.mqttPort = config83.mqttPort; - strcpy(config.mqttClientId, config83.mqttClientId); - strcpy(config.mqttPublishTopic, config83.mqttPublishTopic); - strcpy(config.mqttSubscribeTopic, config83.mqttSubscribeTopic); - strcpy(config.mqttUser, config83.mqttUser); - strcpy(config.mqttPassword, config83.mqttPassword); - config.mqttPayloadFormat = config83.mqttPayloadFormat; - config.mqttSsl = config83.mqttSsl; - config.authSecurity = config83.authSecurity; - strcpy(config.authUser, config83.authUser); - strcpy(config.authPassword, config83.authPassword); - - config.meterType = config83.meterType; - config.distributionSystem = config83.distributionSystem; - config.mainFuse = config83.mainFuse; - config.productionCapacity = config83.productionCapacity; - memcpy(config.meterEncryptionKey, config83.meterEncryptionKey, 16); - memcpy(config.meterAuthenticationKey, config83.meterAuthenticationKey, 16); - config.substituteMissing = config83.substituteMissing; - config.sendUnknown = config83.sendUnknown; + ConfigObject83 c; + EEPROM.begin(EEPROM_SIZE); + EEPROM.get(address, c); + EEPROM.end(); - config.debugTelnet = config83.debugTelnet; - config.debugSerial = config83.debugSerial; - config.debugLevel = config83.debugLevel; + NtpConfig ntp { + c.ntpEnable, + c.ntpDhcp, + c.ntpOffset, + c.ntpSummerOffset + }; + strcpy(ntp.server, c.ntpServer); + setNtpConfig(ntp); - config.hanPin = config83.hanPin; - config.apPin = config83.apPin; - config.ledPin = config83.ledPin; - config.ledInverted = config83.ledInverted; - config.ledPinRed = config83.ledPinRed; - config.ledPinGreen = config83.ledPinGreen; - config.ledPinBlue = config83.ledPinBlue; - config.ledRgbInverted = config83.ledRgbInverted; - config.tempSensorPin = config83.tempSensorPin; - config.vccPin = config83.vccPin; - config.vccOffset = config83.vccOffset; - config.vccMultiplier = config83.vccMultiplier; - config.vccBootLimit = config83.vccBootLimit; + DomoticzConfig domo { + c.domoELIDX, + c.domoVL1IDX, + c.domoVL2IDX, + c.domoVL3IDX, + c.domoCL1IDX + }; + setDomoticzConfig(domo); - config.domoELIDX = config83.domoELIDX; - config.domoVL1IDX = config83.domoVL1IDX; - config.domoVL2IDX = config83.domoVL2IDX; - config.domoVL3IDX = config83.domoVL3IDX; - config.domoCL1IDX = config83.domoCL1IDX; + GpioConfig gpio { + c.hanPin, + c.apPin, + c.ledPin, + c.ledInverted, + c.ledPinRed, + c.ledPinGreen, + c.ledPinBlue, + c.ledRgbInverted, + c.tempSensorPin, + c.tempAnalogSensorPin, + c.vccPin, + c.vccOffset, + c.vccMultiplier, + c.vccBootLimit + }; + setGpioConfig(gpio); - config.mDnsEnable = config83.mDnsEnable; - config.ntpEnable = config83.ntpEnable; - config.ntpDhcp = config83.ntpDhcp; - config.ntpOffset = config83.ntpOffset; - config.ntpSummerOffset = config83.ntpSummerOffset; - strcpy(config.ntpServer, config83.ntpServer); + DebugConfig debug { + c.debugTelnet, + c.debugSerial, + c.debugLevel + }; + setDebugConfig(debug); - config.tempAnalogSensorPin = config83.tempAnalogSensorPin; + MeterConfig meter { + c.meterType, + c.distributionSystem, + c.mainFuse, + c.productionCapacity, + {0}, + {0}, + c.substituteMissing, + c.sendUnknown + }; + memcpy(meter.encryptionKey, c.meterEncryptionKey, 16); + memcpy(meter.authenticationKey, c.meterAuthenticationKey, 16); + setMeterConfig(meter); + + WebConfig web { + c.authSecurity + }; + strcpy(web.username, c.authUser); + strcpy(web.password, c.authPassword); + setWebConfig(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; + setMqttConfig(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 = c.mDnsEnable; + setWiFiConfig(wifi); + + SystemConfig sys { + c.boardType + }; + setSystemConfig(sys); + return save(); } bool AmsConfiguration::save() { - int address = EEPROM_CONFIG_ADDRESS; - EEPROM.begin(EEPROM_SIZE); - EEPROM.put(address, EEPROM_CHECK_SUM); - address++; - EEPROM.put(address, config); + EEPROM.put(EEPROM_CONFIG_ADDRESS, EEPROM_CHECK_SUM); saveTempSensors(); bool success = EEPROM.commit(); EEPROM.end(); @@ -909,8 +749,14 @@ uint8_t AmsConfiguration::getTempSensorCount() { return tempSensorCount; } -TempSensorConfig* AmsConfiguration::getTempSensorConfig(uint8_t i) { - return tempSensors[i]; +TempSensorConfig* AmsConfiguration::getTempSensorConfig(uint8_t address[8]) { + for(int x = 0; x < tempSensorCount; x++) { + TempSensorConfig *conf = tempSensors[x]; + if(isSensorAddressEqual(conf->address, address)) { + return conf; + } + } + return NULL; } void AmsConfiguration::updateTempSensorConfig(uint8_t address[8], const char name[32], bool common) { @@ -975,89 +821,146 @@ int AmsConfiguration::readByte(int address, byte *value) { void AmsConfiguration::print(Print* debugger) { - debugger->print("Configuration size: "); - debugger->println(sizeof(config)); debugger->println("-----------------------------------------------"); - debugger->printf("WiFi SSID: '%s'\r\n", this->getWifiSsid()); - debugger->printf("WiFi Psk: '%s'\r\n", this->getWifiPassword()); - delay(1); - - if(strlen(getWifiIp()) > 0) { - debugger->printf("IP: '%s'\r\n", this->getWifiIp()); - debugger->printf("Gateway: '%s'\r\n", this->getWifiGw()); - debugger->printf("Subnet: '%s'\r\n", this->getWifiSubnet()); - debugger->printf("Primary DNS: '%s'\r\n", this->getWifiDns1()); - debugger->printf("Secondary DNS: '%s'\r\n", this->getWifiDns2()); - } - delay(1); - - debugger->printf("WiFi Host: '%s'\r\n", this->getWifiHostname()); - - if(strlen(getMqttHost()) > 0) { - debugger->printf("mqttHost: '%s'\r\n", this->getMqttHost()); - debugger->printf("mqttPort: %i\r\n", this->getMqttPort()); - debugger->printf("mqttClientID: '%s'\r\n", this->getMqttClientId()); - debugger->printf("mqttPublishTopic: '%s'\r\n", this->getMqttPublishTopic()); - debugger->printf("mqttSubscribeTopic: '%s'\r\n", this->getMqttSubscribeTopic()); - if (this->getMqttUser()) { - debugger->printf("SECURE MQTT CONNECTION:\r\n"); - debugger->printf("mqttUser: '%s'\r\n", this->getMqttUser()); - debugger->printf("mqttPass: '%s'\r\n", this->getMqttPassword()); + WiFiConfig wifi; + if(getWiFiConfig(wifi)) { + debugger->println("--WiFi configuration--"); + debugger->printf("SSID: '%s'\r\n", wifi.ssid); + debugger->printf("Psk: '%s'\r\n", wifi.psk); + if(strlen(wifi.ip) > 0) { + debugger->printf("IP: '%s'\r\n", wifi.ip); + debugger->printf("Gateway: '%s'\r\n", wifi.gateway); + debugger->printf("Subnet: '%s'\r\n", wifi.subnet); + debugger->printf("DNS1: '%s'\r\n", wifi.dns1); + debugger->printf("DNS2: '%s'\r\n", wifi.dns2); } - debugger->printf("payload format: %i\r\n", this->getMqttPayloadFormat()); - } - delay(1); - - if (this->getAuthSecurity()) { - debugger->printf("WEB AUTH:\r\n"); - debugger->printf("authSecurity: %i\r\n", this->getAuthSecurity()); - debugger->printf("authUser: '%s'\r\n", this->getAuthUser()); - debugger->printf("authPass: '%s'\r\n", this->getAuthPassword()); + debugger->printf("Hostname: '%s'\r\n", wifi.hostname); + debugger->printf("mDNS: '%s'\r\n", wifi.mdns ? "Yes" : "No"); + debugger->println(""); + delay(10); + Serial.flush(); } - debugger->printf("meterType: %i\r\n", this->getMeterType()); - debugger->printf("distSys: %i\r\n", this->getDistributionSystem()); - debugger->printf("fuseSize: %i\r\n", this->getMainFuse()); - debugger->printf("productionCapacity: %i\r\n", this->getProductionCapacity()); - debugger->printf("Substitute missing: %s\r\n", this->isSubstituteMissing() ? "Yes" : "No"); - Serial.flush(); - delay(1); - - debugger->printf("HAN pin: %i\r\n", this->getHanPin()); - debugger->printf("LED pin: %i\r\n", this->getLedPin()); - debugger->printf("LED inverted: %s\r\n", this->isLedInverted() ? "Yes" : "No"); - debugger->printf("LED red pin: %i\r\n", this->getLedPinRed()); - debugger->printf("LED green pin: %i\r\n", this->getLedPinGreen()); - debugger->printf("LED blue pin: %i\r\n", this->getLedPinBlue()); - debugger->printf("LED inverted: %s\r\n", this->isLedRgbInverted() ? "Yes" : "No"); - debugger->printf("AP pin: %i\r\n", this->getApPin()); - debugger->printf("Temperature pin: %i\r\n", this->getTempSensorPin()); - Serial.flush(); - delay(1); - - debugger->printf("Vcc pin: %i\r\n", this->getVccPin()); - debugger->printf("Vcc multiplier: %f\r\n", this->getVccMultiplier()); - debugger->printf("Vcc offset: %f\r\n", this->getVccOffset()); - debugger->printf("Vcc boot limit: %f\r\n", this->getVccBootLimit()); - - if(this->getDomoELIDX() > 0) { - debugger->printf("Domoticz ELIDX: %i\r\n", this->getDomoELIDX()); - debugger->printf("Domoticz VL1IDX: %i\r\n", this->getDomoVL1IDX()); - debugger->printf("Domoticz VL2IDX: %i\r\n", this->getDomoVL2IDX()); - debugger->printf("Domoticz VL3IDX: %i\r\n", this->getDomoVL3IDX()); - debugger->printf("Domoticz CL1IDX: %i\r\n", this->getDomoCL1IDX()); + MqttConfig mqtt; + if(getMqttConfig(mqtt)) { + debugger->println("--MQTT configuration--"); + if(strlen(mqtt.host) > 0) { + debugger->printf("Enabled: Yes\r\n"); + debugger->printf("Host: '%s'\r\n", mqtt.host); + debugger->printf("Port: %i\r\n", mqtt.port); + debugger->printf("Client ID: '%s'\r\n", mqtt.clientId); + debugger->printf("Publish topic: '%s'\r\n", mqtt.publishTopic); + debugger->printf("Subscribe topic: '%s'\r\n", mqtt.subscribeTopic); + if (strlen(mqtt.username) > 0) { + debugger->printf("Username: '%s'\r\n", mqtt.username); + debugger->printf("Password: '%s'\r\n", mqtt.password); + } + debugger->printf("Payload format: %i\r\n", mqtt.payloadFormat); + debugger->printf("SSL: %s\r\n", mqtt.ssl ? "Yes" : "No"); + } else { + debugger->printf("Enabled: No\r\n"); + } + debugger->println(""); + delay(10); + Serial.flush(); } - delay(1); - debugger->printf("NTP: %s\r\n", this->isNtpEnable() ? "Yes" : "No"); - if(this->isNtpEnable()) { - debugger->printf("NTP offset: %i\r\n", this->getNtpOffset()); - debugger->printf("NTP summer offset: %i\r\n", this->getNtpSummerOffset()); - debugger->printf("NTP server: %s\r\n", this->getNtpServer()); - debugger->printf("NTP DHCP: %s\r\n", this->isNtpDhcp() ? "Yes" : "No"); + WebConfig web; + if(getWebConfig(web)) { + debugger->println("--Web configuration--"); + debugger->printf("Security: %i\r\n", web.security); + if (web.security > 0) { + debugger->printf("Username: '%s'\r\n", web.username); + debugger->printf("Password: '%s'\r\n", web.password); + } + debugger->println(""); + delay(10); + Serial.flush(); } - delay(1); - + + MeterConfig meter; + if(getMeterConfig(meter)) { + debugger->println("--Meter configuration--"); + debugger->printf("Type: %i\r\n", meter.type); + 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->printf("Send unknown: %s\r\n", meter.sendUnknown ? "Yes" : "No"); + debugger->println(""); + delay(10); + Serial.flush(); + } + + GpioConfig gpio; + if(getGpioConfig(gpio)) { + debugger->println("--GPIO configuration--"); + debugger->printf("HAN pin: %i\r\n", gpio.hanPin); + debugger->printf("LED pin: %i\r\n", gpio.ledPin); + debugger->printf("LED inverted: %s\r\n", gpio.ledInverted ? "Yes" : "No"); + debugger->printf("LED red pin: %i\r\n", gpio.ledPinRed); + debugger->printf("LED green pin: %i\r\n", gpio.ledPinGreen); + debugger->printf("LED blue pin: %i\r\n", gpio.ledPinBlue); + debugger->printf("LED inverted: %s\r\n", gpio.ledRgbInverted ? "Yes" : "No"); + debugger->printf("AP pin: %i\r\n", gpio.apPin); + debugger->printf("Temperature pin: %i\r\n", gpio.tempSensorPin); + debugger->printf("Temp analog pin: %i\r\n", gpio.tempAnalogSensorPin); + debugger->printf("Vcc pin: %i\r\n", gpio.vccPin); + debugger->printf("Vcc multiplier: %f\r\n", gpio.vccMultiplier / 1000.0); + debugger->printf("Vcc offset: %f\r\n", gpio.vccOffset / 100.0); + debugger->printf("Vcc boot limit: %f\r\n", gpio.vccBootLimit / 10.0); + debugger->println(""); + delay(10); + Serial.flush(); + } + + DomoticzConfig domo; + if(getDomoticzConfig(domo)) { + debugger->println("--Domoticz configuration--"); + if(mqtt.payloadFormat == 3 && domo.elidx > 0) { + debugger->printf("Enabled: Yes\r\n"); + debugger->printf("Domoticz ELIDX: %i\r\n", domo.elidx); + debugger->printf("Domoticz VL1IDX: %i\r\n", domo.vl1idx); + debugger->printf("Domoticz VL2IDX: %i\r\n", domo.vl2idx); + debugger->printf("Domoticz VL3IDX: %i\r\n", domo.vl3idx); + debugger->printf("Domoticz CL1IDX: %i\r\n", domo.cl1idx); + } else { + debugger->printf("Enabled: No\r\n"); + } + debugger->println(""); + delay(10); + Serial.flush(); + } + + NtpConfig ntp; + if(getNtpConfig(ntp)) { + debugger->println("--NTP configuration--"); + debugger->printf("Enabled: %s\r\n", ntp.enable ? "Yes" : "No"); + if(ntp.enable) { + debugger->printf("Offset: %i\r\n", ntp.offset); + debugger->printf("Summer offset: %i\r\n", ntp.summerOffset); + debugger->printf("Server: %s\r\n", ntp.server); + debugger->printf("DHCP: %s\r\n", ntp.dhcp ? "Yes" : "No"); + } + debugger->println(""); + delay(10); + Serial.flush(); + } + + EntsoeConfig entsoe; + if(getEntsoeConfig(entsoe)) { + debugger->println("--ENTSO-E configuration--"); + debugger->printf("Token: %s\r\n", entsoe.token); + if(strlen(entsoe.token) > 0) { + debugger->printf("Area: %s\r\n", entsoe.area); + debugger->printf("Currency: %s\r\n", entsoe.currency); + debugger->printf("Multiplier: %f\r\n", entsoe.multiplier / 1000.0); + } + debugger->println(""); + delay(10); + Serial.flush(); + } + debugger->printf("Temp sensor count: %i\r\n", this->getTempSensorCount()); debugger->println("-----------------------------------------------"); diff --git a/src/AmsConfiguration.h b/src/AmsConfiguration.h index 71856e18..449c8053 100644 --- a/src/AmsConfiguration.h +++ b/src/AmsConfiguration.h @@ -3,42 +3,74 @@ #include #include "Arduino.h" -struct ConfigObject { +#define EEPROM_SIZE 1024 * 3 +#define EEPROM_CHECK_SUM 86 // 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_MQTT_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 +#define CONFIG_NTP_START 872 +#define CONFIG_ENTSOE_START 944 + +struct SystemConfig { 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; +}; // 1 + +struct WiFiConfig { + char ssid[32]; + char psk[64]; + char ip[15]; + char gateway[15]; + char subnet[15]; + char dns1[15]; + char dns2[15]; + char hostname[32]; + bool mdns; +}; // 204 + +struct MqttConfig { + char host[128]; + uint16_t port; + char clientId[32]; + char publishTopic[64]; + char subscribeTopic[64]; + char username[64]; + char password[64]; + uint8_t payloadFormat; + bool ssl; +}; // 420 + +struct WebConfig { + uint8_t security; + char username[64]; + char password[64]; +}; // 129 + +struct MeterConfig { + uint8_t type; uint8_t distributionSystem; uint8_t mainFuse; uint8_t productionCapacity; - uint8_t meterEncryptionKey[16]; - uint8_t meterAuthenticationKey[16]; + uint8_t encryptionKey[16]; + uint8_t authenticationKey[16]; bool substituteMissing; bool sendUnknown; +}; // 38 - bool debugTelnet; - bool debugSerial; - uint8_t debugLevel; +struct DebugConfig { + bool telnet; + bool serial; + uint8_t level; +}; // 3 +struct GpioConfig { uint8_t hanPin; uint8_t apPin; uint8_t ledPin; @@ -53,25 +85,30 @@ struct ConfigObject { int16_t vccOffset; uint16_t vccMultiplier; uint8_t vccBootLimit; +}; // 16 - uint16_t domoELIDX; - uint16_t domoVL1IDX; - uint16_t domoVL2IDX; - uint16_t domoVL3IDX; - uint16_t domoCL1IDX; +struct DomoticzConfig { + uint16_t elidx; + uint16_t vl1idx; + uint16_t vl2idx; + uint16_t vl3idx; + uint16_t cl1idx; +}; // 10 - bool mDnsEnable; - bool ntpEnable; - bool ntpDhcp; - int16_t ntpOffset; - int16_t ntpSummerOffset; - char ntpServer[64]; +struct NtpConfig { + bool enable; + bool dhcp; + int16_t offset; + int16_t summerOffset; + char server[64]; +}; // 70 - char entsoeApiToken[37]; - char entsoeApiArea[17]; - char entsoeApiCurrency[4]; - double entsoeApiMultiplier; -}; +struct EntsoeConfig { + char token[37]; + char area[17]; + char currency[4]; + uint16_t multiplier; +}; // 60 struct ConfigObject83 { uint8_t boardType; @@ -204,173 +241,63 @@ public: bool hasConfig(); int getConfigVersion(); - bool load(); bool save(); - uint8_t getBoardType(); - void setBoardType(uint8_t boardType); - - char* getWifiSsid(); - void setWifiSsid(const char* wifiSsid); - char* getWifiPassword(); - void setWifiPassword(const char* wifiPassword); - char* getWifiIp(); - void setWifiIp(const char* wifiIp); - char* getWifiGw(); - void setWifiGw(const char* wifiGw); - char* getWifiSubnet(); - void setWifiSubnet(const char* wifiSubnet); - char* getWifiDns1(); - void setWifiDns1(const char* wifiDns1); - char* getWifiDns2(); - void setWifiDns2(const char* wifiDns1); - char* getWifiHostname(); - void setWifiHostname(const char* wifiHostname); - void clearWifi(); - void clearWifiIp(); + bool getSystemConfig(SystemConfig&); + bool setSystemConfig(SystemConfig&); + bool getWiFiConfig(WiFiConfig&); + bool setWiFiConfig(WiFiConfig&); + void clearWifi(WiFiConfig&); + void clearWifiIp(WiFiConfig&); bool isWifiChanged(); void ackWifiChange(); - char* getMqttHost(); - void setMqttHost(const char* mqttHost); - uint16_t getMqttPort(); - void setMqttPort(uint16_t mqttPort); - char* getMqttClientId(); - void setMqttClientId(const char* mqttClientId); - char* getMqttPublishTopic(); - void setMqttPublishTopic(const char* mqttPublishTopic); - char* getMqttSubscribeTopic(); - void setMqttSubscribeTopic(const char* mqttSubscribeTopic); - char* getMqttUser(); - void setMqttUser(const char* mqttUser); - char* getMqttPassword(); - void setMqttPassword(const char* mqttPassword); - uint8_t getMqttPayloadFormat(); - void setMqttPayloadFormat(uint8_t mqttPayloadFormat); - bool isMqttSsl(); - void setMqttSsl(bool mqttSsl); - void clearMqtt(); - + bool getMqttConfig(MqttConfig&); + bool setMqttConfig(MqttConfig&); + void clearMqtt(MqttConfig&); void setMqttChanged(); bool isMqttChanged(); void ackMqttChange(); - byte getAuthSecurity(); - void setAuthSecurity(byte authSecurity); - char* getAuthUser(); - void setAuthUser(const char* authUser); - char* getAuthPassword(); - void setAuthPassword(const char* authPassword); - void clearAuth(); - - uint8_t getMeterType(); - void setMeterType(uint8_t meterType); - uint8_t getDistributionSystem(); - void setDistributionSystem(uint8_t distributionSystem); - uint8_t getMainFuse(); - void setMainFuse(uint8_t mainFuse); - uint8_t getProductionCapacity(); - void setProductionCapacity(uint8_t productionCapacity); - uint8_t* getMeterEncryptionKey(); - void setMeterEncryptionKey(uint8_t* meterEncryptionKey); - uint8_t* getMeterAuthenticationKey(); - void setMeterAuthenticationKey(uint8_t* meterAuthenticationKey); - bool isSubstituteMissing(); - void setSubstituteMissing(bool substituteMissing); - bool isSendUnknown(); - void setSendUnknown(bool sendUnknown); - void clearMeter(); + bool getWebConfig(WebConfig&); + bool setWebConfig(WebConfig&); + void clearAuth(WebConfig&); + bool getMeterConfig(MeterConfig&); + bool setMeterConfig(MeterConfig&); + void clearMeter(MeterConfig&); bool isMeterChanged(); void ackMeterChanged(); - bool isDebugTelnet(); - void setDebugTelnet(bool debugTelnet); - bool isDebugSerial(); - void setDebugSerial(bool debugSerial); - uint8_t getDebugLevel(); - void setDebugLevel(uint8_t debugLevel); + bool getDebugConfig(DebugConfig&); + bool setDebugConfig(DebugConfig&); - bool pinUsed(uint8_t pin); + bool pinUsed(uint8_t, GpioConfig&); - uint8_t getHanPin(); - void setHanPin(uint8_t hanPin); - uint8_t getApPin(); - void setApPin(uint8_t apPin); - uint8_t getLedPin(); - void setLedPin(uint8_t ledPin); - bool isLedInverted(); - void setLedInverted(bool ledInverted); - - uint8_t getLedPinRed(); - void setLedPinRed(uint8_t ledPinRed); - uint8_t getLedPinGreen(); - void setLedPinGreen(uint8_t ledPinGreen); - uint8_t getLedPinBlue(); - void setLedPinBlue(uint8_t ledPinBlue); - bool isLedRgbInverted(); - void setLedRgbInverted(bool ledRgbInverted); - - uint8_t getTempSensorPin(); - void setTempSensorPin(uint8_t tempSensorPin); - uint8_t getTempAnalogSensorPin(); - void setTempAnalogSensorPin(uint8_t tempSensorPin); - uint8_t getVccPin(); - void setVccPin(uint8_t vccPin); - double getVccOffset(); - void setVccOffset(double vccOffset); - double getVccMultiplier(); - void setVccMultiplier(double vccMultiplier); - double getVccBootLimit(); - void setVccBootLimit(double vccBootLimit); + bool getGpioConfig(GpioConfig&); + bool setGpioConfig(GpioConfig&); + void clearGpio(GpioConfig&); void print(Print* debugger); - uint16_t getDomoELIDX(); - uint16_t getDomoVL1IDX(); - uint16_t getDomoVL2IDX(); - uint16_t getDomoVL3IDX(); - uint16_t getDomoCL1IDX(); - void setDomoELIDX(uint16_t domoELIDX); - void setDomoVL1IDX(uint16_t domoVL1IDX); - void setDomoVL2IDX(uint16_t domoVL2IDX); - void setDomoVL3IDX(uint16_t domoVL3IDX); - void setDomoCL1IDX(uint16_t domoCL1IDX); - void clearDomo(); - + bool getDomoticzConfig(DomoticzConfig&); + bool setDomoticzConfig(DomoticzConfig&); + void clearDomo(DomoticzConfig&); bool isDomoChanged(); void ackDomoChange(); - - bool isMdnsEnable(); - void setMdnsEnable(bool mdnsEnable); - bool isNtpEnable(); - void setNtpEnable(bool ntpEnable); - bool isNtpDhcp(); - void setNtpDhcp(bool ntpDhcp); - int32_t getNtpOffset(); - void setNtpOffset(uint32_t ntpOffset); - int32_t getNtpSummerOffset(); - void setNtpSummerOffset(uint32_t ntpSummerOffset); - char* getNtpServer(); - void setNtpServer(const char* ntpServer); - void clearNtp(); - + bool getNtpConfig(NtpConfig&); + bool setNtpConfig(NtpConfig&); + void clearNtp(NtpConfig&); bool isNtpChanged(); void ackNtpChange(); - char* getEntsoeApiToken(); - void setEntsoeApiToken(const char* token); - char* getEntsoeApiArea(); - void setEntsoeApiArea(const char* area); - char* getEntsoeApiCurrency(); - void setEntsoeApiCurrency(const char* currency); - double getEntsoeApiMultiplier(); - void setEntsoeApiMultiplier(double multiplier); + bool getEntsoeConfig(EntsoeConfig&); + bool setEntsoeConfig(EntsoeConfig&); uint8_t getTempSensorCount(); - TempSensorConfig* getTempSensorConfig(uint8_t i); + TempSensorConfig* getTempSensorConfig(uint8_t address[8]); void updateTempSensorConfig(uint8_t address[8], const char name[32], bool common); bool isSensorAddressEqual(uint8_t a[8], uint8_t b[8]); @@ -380,81 +307,12 @@ public: protected: private: - int configVersion = 0; - ConfigObject config { - 0, // Board type - "", // SSID - "", // PSK - "", // IP - "", // GW - "", // Subnet - "", // DNS 1 - "", // DNS 2 - "", // Hostname - "", // MQTT host - 1883, // Port - "", // Client ID - "", // Publish topic - "", // Subscribe topic - "", // Username - "", // Password - 0, // Format - false, // SSL - 0, // Web security - "", // Username - "", // Password - 0, // Meter type - 0, // Distribution system - 0, // Main fuse - 0, // Production capacity - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Encryption key - { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // Authentication key - false, // Substitute - false, // Send unknown - false, // Debug telnet - false, // Debug serial - 5, // Debug level - 0x03, // HAN pin - 0xFF, // AP pin - 0x02, // LED pin - true, // Inverted - 0xFF, // Red - 0xFF, // Green - 0xFF, // Blue - true, // Inverted - 0xFF, // Temp sensor - 0xFF, // Analog temp sensor - 0xFF, // Vcc - 0, // Offset - 100, // Multiplier - 0, // Boot limit - //Domoticz - 0, // ELIDX - 0, // VL1IDX - 0, // VL2IDX - 0, // VL3IDX - 0, // CL1IDX - true, // mDNS - true, // NTP - true, // NTP DHCP - 360, // Timezone (*10) - 360, // Summertime offset (*10) - "pool.ntp.org", // NTP server - "", // Entsoe token - "", // Entsoe area - "", // Entsoe currency - 1.00, // Entsoe multiplier - // 960 bytes - }; + uint8_t configVersion = 0; + bool wifiChanged, mqttChanged, meterChanged = true, domoChanged, ntpChanged; uint8_t tempSensorCount = 0; - TempSensorConfig* tempSensors[32]; - - const int EEPROM_SIZE = 1024 * 3; - const int EEPROM_CHECK_SUM = 84; // Used to check if config is stored. Change if structure changes - const int EEPROM_CONFIG_ADDRESS = 0; - const int EEPROM_TEMP_CONFIG_ADDRESS = 2048; + TempSensorConfig** tempSensors; void loadTempSensors(); void saveTempSensors(); diff --git a/src/AmsData.cpp b/src/AmsData.cpp index 1082462e..a83adf53 100644 --- a/src/AmsData.cpp +++ b/src/AmsData.cpp @@ -6,7 +6,7 @@ AmsData::AmsData() {} -AmsData::AmsData(int meterType, bool substituteMissing, HanReader& hanReader) { +AmsData::AmsData(uint8_t meterType, bool substituteMissing, HanReader& hanReader) { lastUpdateMillis = millis(); packageTimestamp = hanReader.getPackageTime(true, true); @@ -27,34 +27,34 @@ AmsData::AmsData(int meterType, bool substituteMissing, HanReader& hanReader) { } } -void AmsData::extractFromKaifa(HanReader& hanReader, int listSize) { +void AmsData::extractFromKaifa(HanReader& hanReader, uint8_t listSize) { switch(listSize) { - case (int)Kaifa::List1: + case (uint8_t)Kaifa::List1: listType = 1; break; - case (int)Kaifa::List3PhaseShort: + case (uint8_t)Kaifa::List3PhaseShort: threePhase = true; - case (int)Kaifa::List1PhaseShort: + case (uint8_t)Kaifa::List1PhaseShort: listType = 2; break; - case (int)Kaifa::List3PhaseLong: + case (uint8_t)Kaifa::List3PhaseLong: threePhase = true; - case (int)Kaifa::List1PhaseLong: + case (uint8_t)Kaifa::List1PhaseLong: listType = 3; break; } - if(listSize == (int)Kaifa::List1) { + if(listSize == (uint8_t)Kaifa::List1) { activeImportPower = hanReader.getInt((int)Kaifa_List1::ActivePowerImported); } else { switch(listSize) { - case (int)Kaifa::List3PhaseLong: + case (uint8_t)Kaifa::List3PhaseLong: meterTimestamp = hanReader.getTime( (int)Kaifa_List3Phase::MeterClock, false, false); - activeImportCounter = ((double) hanReader.getUint((int)Kaifa_List3Phase::CumulativeActiveImportEnergy)) / 1000; - activeExportCounter = ((double) hanReader.getUint((int)Kaifa_List3Phase::CumulativeActiveExportEnergy)) / 1000; - reactiveImportCounter = ((double) hanReader.getUint((int)Kaifa_List3Phase::CumulativeReactiveImportEnergy)) / 1000; - reactiveExportCounter = ((double) hanReader.getUint((int)Kaifa_List3Phase::CumulativeReactiveExportEnergy)) / 1000; - case (int)Kaifa::List3PhaseShort: + activeImportCounter = ((float) hanReader.getUint((int)Kaifa_List3Phase::CumulativeActiveImportEnergy)) / 1000; + activeExportCounter = ((float) hanReader.getUint((int)Kaifa_List3Phase::CumulativeActiveExportEnergy)) / 1000; + reactiveImportCounter = ((float) hanReader.getUint((int)Kaifa_List3Phase::CumulativeReactiveImportEnergy)) / 1000; + reactiveExportCounter = ((float) hanReader.getUint((int)Kaifa_List3Phase::CumulativeReactiveExportEnergy)) / 1000; + case (uint8_t)Kaifa::List3PhaseShort: listId = hanReader.getString( (int)Kaifa_List3Phase::ListVersionIdentifier); meterId = hanReader.getString( (int)Kaifa_List3Phase::MeterID); meterType = hanReader.getString( (int)Kaifa_List3Phase::MeterType); @@ -62,20 +62,20 @@ void AmsData::extractFromKaifa(HanReader& hanReader, int listSize) { reactiveImportPower = hanReader.getUint( (int)Kaifa_List3Phase::ReactiveImportPower); activeExportPower = hanReader.getUint( (int)Kaifa_List3Phase::ActiveExportPower); reactiveExportPower = hanReader.getUint( (int)Kaifa_List3Phase::ReactiveExportPower); - l1current = ((double) hanReader.getInt( (int)Kaifa_List3Phase::CurrentL1)) / 1000; - l2current = ((double) hanReader.getInt( (int)Kaifa_List3Phase::CurrentL2)) / 1000; - l3current = ((double) hanReader.getInt( (int)Kaifa_List3Phase::CurrentL3)) / 1000; - l1voltage = ((double) hanReader.getInt( (int)Kaifa_List3Phase::VoltageL1)) / 10; - l2voltage = ((double) hanReader.getInt( (int)Kaifa_List3Phase::VoltageL2)) / 10; - l3voltage = ((double) hanReader.getInt( (int)Kaifa_List3Phase::VoltageL3)) / 10; + l1current = ((float) hanReader.getInt( (int)Kaifa_List3Phase::CurrentL1)) / 1000; + l2current = ((float) hanReader.getInt( (int)Kaifa_List3Phase::CurrentL2)) / 1000; + l3current = ((float) hanReader.getInt( (int)Kaifa_List3Phase::CurrentL3)) / 1000; + l1voltage = ((float) hanReader.getInt( (int)Kaifa_List3Phase::VoltageL1)) / 10; + l2voltage = ((float) hanReader.getInt( (int)Kaifa_List3Phase::VoltageL2)) / 10; + l3voltage = ((float) hanReader.getInt( (int)Kaifa_List3Phase::VoltageL3)) / 10; break; - case (int)Kaifa::List1PhaseLong: + case (uint8_t)Kaifa::List1PhaseLong: meterTimestamp = hanReader.getTime( (int)Kaifa_List1Phase::MeterClock, false, false); - activeImportCounter = ((double) hanReader.getUint((int)Kaifa_List1Phase::CumulativeActiveImportEnergy)); - activeExportCounter = ((double) hanReader.getUint((int)Kaifa_List1Phase::CumulativeActiveExportEnergy)); - reactiveImportCounter = ((double) hanReader.getUint((int)Kaifa_List1Phase::CumulativeReactiveImportEnergy)); - reactiveExportCounter = ((double) hanReader.getUint((int)Kaifa_List1Phase::CumulativeReactiveExportEnergy)); - case (int)Kaifa::List1PhaseShort: + activeImportCounter = ((float) hanReader.getUint((int)Kaifa_List1Phase::CumulativeActiveImportEnergy)); + activeExportCounter = ((float) hanReader.getUint((int)Kaifa_List1Phase::CumulativeActiveExportEnergy)); + reactiveImportCounter = ((float) hanReader.getUint((int)Kaifa_List1Phase::CumulativeReactiveImportEnergy)); + reactiveExportCounter = ((float) hanReader.getUint((int)Kaifa_List1Phase::CumulativeReactiveExportEnergy)); + case (uint8_t)Kaifa::List1PhaseShort: listId = hanReader.getString( (int)Kaifa_List1Phase::ListVersionIdentifier); meterId = hanReader.getString( (int)Kaifa_List1Phase::MeterID); meterType = hanReader.getString( (int)Kaifa_List1Phase::MeterType); @@ -83,94 +83,94 @@ void AmsData::extractFromKaifa(HanReader& hanReader, int listSize) { reactiveImportPower = hanReader.getUint( (int)Kaifa_List1Phase::ReactiveImportPower); activeExportPower = hanReader.getUint( (int)Kaifa_List1Phase::ActiveExportPower); reactiveExportPower = hanReader.getUint( (int)Kaifa_List1Phase::ReactiveExportPower); - l1current = ((double) hanReader.getInt( (int)Kaifa_List1Phase::CurrentL1)) / 1000; - l1voltage = ((double) hanReader.getInt( (int)Kaifa_List1Phase::VoltageL1)) / 10; + l1current = ((float) hanReader.getInt( (int)Kaifa_List1Phase::CurrentL1)) / 1000; + l1voltage = ((float) hanReader.getInt( (int)Kaifa_List1Phase::VoltageL1)) / 10; break; } } } -void AmsData::extractFromAidon(HanReader& hanReader, int listSize, bool substituteMissing) { +void AmsData::extractFromAidon(HanReader& hanReader, uint8_t listSize, bool substituteMissing) { switch(listSize) { - case (int)Aidon::List1: + case (uint8_t)Aidon::List1: listType = 1; break; - case (int)Aidon::List3PhaseITShort: - case (int)Aidon::List3PhaseShort: + case (uint8_t)Aidon::List3PhaseITShort: + case (uint8_t)Aidon::List3PhaseShort: threePhase = true; - case (int)Aidon::List1PhaseShort: + case (uint8_t)Aidon::List1PhaseShort: listType = 2; break; - case (int)Aidon::List3PhaseITLong: - case (int)Aidon::List3PhaseLong: + case (uint8_t)Aidon::List3PhaseITLong: + case (uint8_t)Aidon::List3PhaseLong: threePhase = true; - case (int)Aidon::List1PhaseLong: + case (uint8_t)Aidon::List1PhaseLong: listType = 3; break; } - if(listSize == (int)Aidon::List1) { - activeImportPower = hanReader.getUint((int)Aidon_List1::ActiveImportPower); + if(listSize == (uint8_t)Aidon::List1) { + activeImportPower = hanReader.getUint((uint8_t)Aidon_List1::ActiveImportPower); } else { switch(listSize) { - case (int)Aidon::List3PhaseLong: - meterTimestamp = hanReader.getTime( (int)Aidon_List3Phase::Timestamp, false, false); - activeImportCounter = ((double) hanReader.getUint( (int)Aidon_List3Phase::CumulativeActiveImportEnergy)) / 100; - activeExportCounter = ((double) hanReader.getUint( (int)Aidon_List3Phase::CumulativeActiveExportEnergy)) / 100; - reactiveImportCounter = ((double) hanReader.getUint( (int)Aidon_List3Phase::CumulativeReactiveImportEnergy)) / 100; - reactiveExportCounter = ((double) hanReader.getUint( (int)Aidon_List3Phase::CumulativeReactiveExportEnergy)) / 100; - case (int)Aidon::List3PhaseShort: - listId = hanReader.getString( (int)Aidon_List3Phase::ListVersionIdentifier); - meterId = hanReader.getString( (int)Aidon_List3Phase::MeterID); - meterType = hanReader.getString( (int)Aidon_List3Phase::MeterType); - activeImportPower = hanReader.getUint( (int)Aidon_List3Phase::ActiveImportPower); - reactiveImportPower = hanReader.getUint( (int)Aidon_List3Phase::ReactiveImportPower); - activeExportPower = hanReader.getUint( (int)Aidon_List3Phase::ActiveExportPower); - reactiveExportPower = hanReader.getUint( (int)Aidon_List3Phase::ReactiveExportPower); - l1current = ((double) hanReader.getInt( (int)Aidon_List3Phase::CurrentL1)) / 10; - l2current = ((double) hanReader.getInt( (int)Aidon_List3Phase::CurrentL2)) / 10; - l3current = ((double) hanReader.getInt( (int)Aidon_List3Phase::CurrentL3)) / 10; - l1voltage = ((double) hanReader.getInt( (int)Aidon_List3Phase::VoltageL1)) / 10; - l2voltage = ((double) hanReader.getInt( (int)Aidon_List3Phase::VoltageL2)) / 10; - l3voltage = ((double) hanReader.getInt( (int)Aidon_List3Phase::VoltageL3)) / 10; + case (uint8_t)Aidon::List3PhaseLong: + meterTimestamp = hanReader.getTime( (uint8_t)Aidon_List3Phase::Timestamp, false, false); + activeImportCounter = ((float) hanReader.getUint( (uint8_t)Aidon_List3Phase::CumulativeActiveImportEnergy)) / 100; + activeExportCounter = ((float) hanReader.getUint( (uint8_t)Aidon_List3Phase::CumulativeActiveExportEnergy)) / 100; + reactiveImportCounter = ((float) hanReader.getUint( (uint8_t)Aidon_List3Phase::CumulativeReactiveImportEnergy)) / 100; + reactiveExportCounter = ((float) hanReader.getUint( (uint8_t)Aidon_List3Phase::CumulativeReactiveExportEnergy)) / 100; + case (uint8_t)Aidon::List3PhaseShort: + listId = hanReader.getString( (uint8_t)Aidon_List3Phase::ListVersionIdentifier); + meterId = hanReader.getString( (uint8_t)Aidon_List3Phase::MeterID); + meterType = hanReader.getString( (uint8_t)Aidon_List3Phase::MeterType); + activeImportPower = hanReader.getUint( (uint8_t)Aidon_List3Phase::ActiveImportPower); + reactiveImportPower = hanReader.getUint( (uint8_t)Aidon_List3Phase::ReactiveImportPower); + activeExportPower = hanReader.getUint( (uint8_t)Aidon_List3Phase::ActiveExportPower); + reactiveExportPower = hanReader.getUint( (uint8_t)Aidon_List3Phase::ReactiveExportPower); + l1current = ((float) hanReader.getInt( (uint8_t)Aidon_List3Phase::CurrentL1)) / 10; + l2current = ((float) hanReader.getInt( (uint8_t)Aidon_List3Phase::CurrentL2)) / 10; + l3current = ((float) hanReader.getInt( (uint8_t)Aidon_List3Phase::CurrentL3)) / 10; + l1voltage = ((float) hanReader.getInt( (uint8_t)Aidon_List3Phase::VoltageL1)) / 10; + l2voltage = ((float) hanReader.getInt( (uint8_t)Aidon_List3Phase::VoltageL2)) / 10; + l3voltage = ((float) hanReader.getInt( (uint8_t)Aidon_List3Phase::VoltageL3)) / 10; break; - case (int)Aidon::List1PhaseLong: - meterTimestamp = hanReader.getTime( (int)Aidon_List1Phase::Timestamp, false, false); - activeImportCounter = ((double) hanReader.getUint( (int)Aidon_List1Phase::CumulativeActiveImportEnergy)) / 100; - activeExportCounter = ((double) hanReader.getUint( (int)Aidon_List1Phase::CumulativeActiveExportEnergy)) / 100; - reactiveImportCounter = ((double) hanReader.getUint( (int)Aidon_List1Phase::CumulativeReactiveImportEnergy)) / 100; - reactiveExportCounter = ((double) hanReader.getUint( (int)Aidon_List1Phase::CumulativeReactiveExportEnergy)) / 100; - case (int)Aidon::List1PhaseShort: - listId = hanReader.getString( (int)Aidon_List1Phase::ListVersionIdentifier); - meterId = hanReader.getString( (int)Aidon_List1Phase::MeterID); - meterType = hanReader.getString( (int)Aidon_List1Phase::MeterType); - activeImportPower = hanReader.getUint( (int)Aidon_List1Phase::ActiveImportPower); - reactiveImportPower = hanReader.getUint( (int)Aidon_List1Phase::ReactiveImportPower); - activeExportPower = hanReader.getUint( (int)Aidon_List1Phase::ActiveExportPower); - reactiveExportPower = hanReader.getUint( (int)Aidon_List1Phase::ReactiveExportPower); - l1current = ((double) hanReader.getInt( (int)Aidon_List1Phase::CurrentL1)) / 10; - l1voltage = ((double) hanReader.getInt( (int)Aidon_List1Phase::VoltageL1)) / 10; + case (uint8_t)Aidon::List1PhaseLong: + meterTimestamp = hanReader.getTime( (uint8_t)Aidon_List1Phase::Timestamp, false, false); + activeImportCounter = ((float) hanReader.getUint( (uint8_t)Aidon_List1Phase::CumulativeActiveImportEnergy)) / 100; + activeExportCounter = ((float) hanReader.getUint( (uint8_t)Aidon_List1Phase::CumulativeActiveExportEnergy)) / 100; + reactiveImportCounter = ((float) hanReader.getUint( (uint8_t)Aidon_List1Phase::CumulativeReactiveImportEnergy)) / 100; + reactiveExportCounter = ((float) hanReader.getUint( (uint8_t)Aidon_List1Phase::CumulativeReactiveExportEnergy)) / 100; + case (uint8_t)Aidon::List1PhaseShort: + listId = hanReader.getString( (uint8_t)Aidon_List1Phase::ListVersionIdentifier); + meterId = hanReader.getString( (uint8_t)Aidon_List1Phase::MeterID); + meterType = hanReader.getString( (uint8_t)Aidon_List1Phase::MeterType); + activeImportPower = hanReader.getUint( (uint8_t)Aidon_List1Phase::ActiveImportPower); + reactiveImportPower = hanReader.getUint( (uint8_t)Aidon_List1Phase::ReactiveImportPower); + activeExportPower = hanReader.getUint( (uint8_t)Aidon_List1Phase::ActiveExportPower); + reactiveExportPower = hanReader.getUint( (uint8_t)Aidon_List1Phase::ReactiveExportPower); + l1current = ((float) hanReader.getInt( (uint8_t)Aidon_List1Phase::CurrentL1)) / 10; + l1voltage = ((float) hanReader.getInt( (uint8_t)Aidon_List1Phase::VoltageL1)) / 10; break; - case (int)Aidon::List3PhaseITLong: - meterTimestamp = hanReader.getTime( (int)Aidon_List3PhaseIT::Timestamp, false, false); - activeImportCounter = ((double) hanReader.getUint( (int)Aidon_List3PhaseIT::CumulativeActiveImportEnergy)) / 100; - activeExportCounter = ((double) hanReader.getUint( (int)Aidon_List3PhaseIT::CumulativeActiveExportEnergy)) / 100; - reactiveImportCounter = ((double) hanReader.getUint( (int)Aidon_List3PhaseIT::CumulativeReactiveImportEnergy)) / 100; - reactiveExportCounter = ((double) hanReader.getUint( (int)Aidon_List3PhaseIT::CumulativeReactiveExportEnergy)) / 100; - case (int)Aidon::List3PhaseITShort: - listId = hanReader.getString( (int)Aidon_List3PhaseIT::ListVersionIdentifier); - meterId = hanReader.getString( (int)Aidon_List3PhaseIT::MeterID); - meterType = hanReader.getString( (int)Aidon_List3PhaseIT::MeterType); - activeImportPower = hanReader.getUint( (int)Aidon_List3PhaseIT::ActiveImportPower); - reactiveImportPower = hanReader.getUint( (int)Aidon_List3PhaseIT::ReactiveImportPower); - activeExportPower = hanReader.getUint( (int)Aidon_List3PhaseIT::ActiveExportPower); - reactiveExportPower = hanReader.getUint( (int)Aidon_List3PhaseIT::ReactiveExportPower); - l1current = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::CurrentL1)) / 10; + case (uint8_t)Aidon::List3PhaseITLong: + meterTimestamp = hanReader.getTime( (uint8_t)Aidon_List3PhaseIT::Timestamp, false, false); + activeImportCounter = ((float) hanReader.getUint( (uint8_t)Aidon_List3PhaseIT::CumulativeActiveImportEnergy)) / 100; + activeExportCounter = ((float) hanReader.getUint( (uint8_t)Aidon_List3PhaseIT::CumulativeActiveExportEnergy)) / 100; + reactiveImportCounter = ((float) hanReader.getUint( (uint8_t)Aidon_List3PhaseIT::CumulativeReactiveImportEnergy)) / 100; + reactiveExportCounter = ((float) hanReader.getUint( (uint8_t)Aidon_List3PhaseIT::CumulativeReactiveExportEnergy)) / 100; + case (uint8_t)Aidon::List3PhaseITShort: + listId = hanReader.getString( (uint8_t)Aidon_List3PhaseIT::ListVersionIdentifier); + meterId = hanReader.getString( (uint8_t)Aidon_List3PhaseIT::MeterID); + meterType = hanReader.getString( (uint8_t)Aidon_List3PhaseIT::MeterType); + activeImportPower = hanReader.getUint( (uint8_t)Aidon_List3PhaseIT::ActiveImportPower); + reactiveImportPower = hanReader.getUint( (uint8_t)Aidon_List3PhaseIT::ReactiveImportPower); + activeExportPower = hanReader.getUint( (uint8_t)Aidon_List3PhaseIT::ActiveExportPower); + reactiveExportPower = hanReader.getUint( (uint8_t)Aidon_List3PhaseIT::ReactiveExportPower); + l1current = ((float) hanReader.getInt( (uint8_t)Aidon_List3PhaseIT::CurrentL1)) / 10; l2current = 0; - l3current = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::CurrentL3)) / 10; - l1voltage = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::VoltageL1)) / 10; - l2voltage = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::VoltageL2)) / 10; - l3voltage = ((double) hanReader.getInt( (int)Aidon_List3PhaseIT::VoltageL3)) / 10; + l3current = ((float) hanReader.getInt( (uint8_t)Aidon_List3PhaseIT::CurrentL3)) / 10; + l1voltage = ((float) hanReader.getInt( (uint8_t)Aidon_List3PhaseIT::VoltageL1)) / 10; + l2voltage = ((float) hanReader.getInt( (uint8_t)Aidon_List3PhaseIT::VoltageL2)) / 10; + l3voltage = ((float) hanReader.getInt( (uint8_t)Aidon_List3PhaseIT::VoltageL3)) / 10; if(substituteMissing) { l2current = (((activeImportPower - activeExportPower) * sqrt(3)) - (l1voltage * l1current) - (l3voltage * l3current)) / l2voltage; } @@ -179,81 +179,81 @@ void AmsData::extractFromAidon(HanReader& hanReader, int listSize, bool substitu } } -void AmsData::extractFromKamstrup(HanReader& hanReader, int listSize, bool substituteMissing) { +void AmsData::extractFromKamstrup(HanReader& hanReader, uint8_t listSize, bool substituteMissing) { switch(listSize) { - case (int)Kamstrup::List3PhaseITShort: - case (int)Kamstrup::List3PhaseShort: + case (uint8_t)Kamstrup::List3PhaseITShort: + case (uint8_t)Kamstrup::List3PhaseShort: threePhase = true; - case (int)Kamstrup::List1PhaseShort: + case (uint8_t)Kamstrup::List1PhaseShort: listType = 2; break; - case (int)Kamstrup::List3PhaseITLong: - case (int)Kamstrup::List3PhaseLong: + case (uint8_t)Kamstrup::List3PhaseITLong: + case (uint8_t)Kamstrup::List3PhaseLong: threePhase = true; - case (int)Kamstrup::List1PhaseLong: + case (uint8_t)Kamstrup::List1PhaseLong: listType = 3; break; } switch(listSize) { - case (int)Kamstrup::List1PhaseLong: - meterTimestamp = hanReader.getTime( (int)Kamstrup_List1Phase::MeterClock, true, true); - activeImportCounter = ((double) hanReader.getInt((int)Kamstrup_List1Phase::CumulativeActiveImportEnergy)) / 100; - activeExportCounter = ((double) hanReader.getInt((int)Kamstrup_List1Phase::CumulativeActiveExportEnergy)) / 100; - reactiveImportCounter = ((double) hanReader.getInt((int)Kamstrup_List1Phase::CumulativeReactiveImportEnergy)) / 100; - reactiveExportCounter = ((double) hanReader.getInt((int)Kamstrup_List1Phase::CumulativeReactiveExportEnergy)) / 100; - case (int)Kamstrup::List1PhaseShort: - listId = hanReader.getString( (int)Kamstrup_List1Phase::ListVersionIdentifier); - meterId = hanReader.getString( (int)Kamstrup_List1Phase::MeterID); - meterType = hanReader.getString( (int)Kamstrup_List1Phase::MeterType); - activeImportPower = hanReader.getInt( (int)Kamstrup_List1Phase::ActiveImportPower); - reactiveImportPower = hanReader.getInt( (int)Kamstrup_List1Phase::ReactiveImportPower); - activeExportPower = hanReader.getInt( (int)Kamstrup_List1Phase::ActiveExportPower); - reactiveExportPower = hanReader.getInt( (int)Kamstrup_List1Phase::ReactiveExportPower); - l1current = ((double) hanReader.getInt((int)Kamstrup_List1Phase::CurrentL1)) / 100; - l1voltage = hanReader.getInt( (int)Kamstrup_List1Phase::VoltageL1); + case (uint8_t)Kamstrup::List1PhaseLong: + meterTimestamp = hanReader.getTime( (uint8_t)Kamstrup_List1Phase::MeterClock, true, true); + activeImportCounter = ((float) hanReader.getInt((uint8_t)Kamstrup_List1Phase::CumulativeActiveImportEnergy)) / 100; + activeExportCounter = ((float) hanReader.getInt((uint8_t)Kamstrup_List1Phase::CumulativeActiveExportEnergy)) / 100; + reactiveImportCounter = ((float) hanReader.getInt((uint8_t)Kamstrup_List1Phase::CumulativeReactiveImportEnergy)) / 100; + reactiveExportCounter = ((float) hanReader.getInt((uint8_t)Kamstrup_List1Phase::CumulativeReactiveExportEnergy)) / 100; + case (uint8_t)Kamstrup::List1PhaseShort: + listId = hanReader.getString( (uint8_t)Kamstrup_List1Phase::ListVersionIdentifier); + meterId = hanReader.getString( (uint8_t)Kamstrup_List1Phase::MeterID); + meterType = hanReader.getString( (uint8_t)Kamstrup_List1Phase::MeterType); + activeImportPower = hanReader.getInt( (uint8_t)Kamstrup_List1Phase::ActiveImportPower); + reactiveImportPower = hanReader.getInt( (uint8_t)Kamstrup_List1Phase::ReactiveImportPower); + activeExportPower = hanReader.getInt( (uint8_t)Kamstrup_List1Phase::ActiveExportPower); + reactiveExportPower = hanReader.getInt( (uint8_t)Kamstrup_List1Phase::ReactiveExportPower); + l1current = ((float) hanReader.getInt((uint8_t)Kamstrup_List1Phase::CurrentL1)) / 100; + l1voltage = hanReader.getInt( (uint8_t)Kamstrup_List1Phase::VoltageL1); break; - case (int)Kamstrup::List3PhaseLong: - meterTimestamp = hanReader.getTime( (int)Kamstrup_List3Phase::MeterClock, true, true); - activeImportCounter = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CumulativeActiveImportEnergy)) / 100; - activeExportCounter = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CumulativeActiveExportEnergy)) / 100; - reactiveImportCounter = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CumulativeReactiveImportEnergy)) / 100; - reactiveExportCounter = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CumulativeReactiveExportEnergy)) / 100; - case (int)Kamstrup::List3PhaseShort: - listId = hanReader.getString( (int)Kamstrup_List3Phase::ListVersionIdentifier); - meterId = hanReader.getString( (int)Kamstrup_List3Phase::MeterID); - meterType = hanReader.getString( (int)Kamstrup_List3Phase::MeterType); - activeImportPower = hanReader.getInt( (int)Kamstrup_List3Phase::ActiveImportPower); - reactiveImportPower = hanReader.getInt( (int)Kamstrup_List3Phase::ReactiveImportPower); - activeExportPower = hanReader.getInt( (int)Kamstrup_List3Phase::ActiveExportPower); - reactiveExportPower = hanReader.getInt( (int)Kamstrup_List3Phase::ReactiveExportPower); - l1current = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CurrentL1)) / 100; - l2current = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CurrentL2)) / 100; - l3current = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CurrentL3)) / 100; - l1voltage = hanReader.getInt( (int)Kamstrup_List3Phase::VoltageL1); - l2voltage = hanReader.getInt( (int)Kamstrup_List3Phase::VoltageL2); - l3voltage = hanReader.getInt( (int)Kamstrup_List3Phase::VoltageL3); + case (uint8_t)Kamstrup::List3PhaseLong: + meterTimestamp = hanReader.getTime( (uint8_t)Kamstrup_List3Phase::MeterClock, true, true); + activeImportCounter = ((float) hanReader.getInt((uint8_t)Kamstrup_List3Phase::CumulativeActiveImportEnergy)) / 100; + activeExportCounter = ((float) hanReader.getInt((uint8_t)Kamstrup_List3Phase::CumulativeActiveExportEnergy)) / 100; + reactiveImportCounter = ((float) hanReader.getInt((uint8_t)Kamstrup_List3Phase::CumulativeReactiveImportEnergy)) / 100; + reactiveExportCounter = ((float) hanReader.getInt((uint8_t)Kamstrup_List3Phase::CumulativeReactiveExportEnergy)) / 100; + case (uint8_t)Kamstrup::List3PhaseShort: + listId = hanReader.getString( (uint8_t)Kamstrup_List3Phase::ListVersionIdentifier); + meterId = hanReader.getString( (uint8_t)Kamstrup_List3Phase::MeterID); + meterType = hanReader.getString( (uint8_t)Kamstrup_List3Phase::MeterType); + activeImportPower = hanReader.getInt( (uint8_t)Kamstrup_List3Phase::ActiveImportPower); + reactiveImportPower = hanReader.getInt( (uint8_t)Kamstrup_List3Phase::ReactiveImportPower); + activeExportPower = hanReader.getInt( (uint8_t)Kamstrup_List3Phase::ActiveExportPower); + reactiveExportPower = hanReader.getInt( (uint8_t)Kamstrup_List3Phase::ReactiveExportPower); + l1current = ((float) hanReader.getInt((uint8_t)Kamstrup_List3Phase::CurrentL1)) / 100; + l2current = ((float) hanReader.getInt((uint8_t)Kamstrup_List3Phase::CurrentL2)) / 100; + l3current = ((float) hanReader.getInt((uint8_t)Kamstrup_List3Phase::CurrentL3)) / 100; + l1voltage = hanReader.getInt( (uint8_t)Kamstrup_List3Phase::VoltageL1); + l2voltage = hanReader.getInt( (uint8_t)Kamstrup_List3Phase::VoltageL2); + l3voltage = hanReader.getInt( (uint8_t)Kamstrup_List3Phase::VoltageL3); break; - case (int)Kamstrup::List3PhaseITLong: - meterTimestamp = hanReader.getTime( (int)Kamstrup_List3Phase::MeterClock, true, true); - activeImportCounter = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CumulativeActiveImportEnergy)) / 100; - activeExportCounter = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CumulativeActiveExportEnergy)) / 100; - reactiveImportCounter = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CumulativeReactiveImportEnergy)) / 100; - reactiveExportCounter = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CumulativeReactiveExportEnergy)) / 100; - case (int)Kamstrup::List3PhaseITShort: - listId = hanReader.getString( (int)Kamstrup_List3Phase::ListVersionIdentifier); - meterId = hanReader.getString( (int)Kamstrup_List3Phase::MeterID); - meterType = hanReader.getString( (int)Kamstrup_List3Phase::MeterType); - activeImportPower = hanReader.getInt( (int)Kamstrup_List3Phase::ActiveImportPower); - reactiveImportPower = hanReader.getInt( (int)Kamstrup_List3Phase::ReactiveImportPower); - activeExportPower = hanReader.getInt( (int)Kamstrup_List3Phase::ActiveExportPower); - reactiveExportPower = hanReader.getInt( (int)Kamstrup_List3Phase::ReactiveExportPower); - l1current = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CurrentL1)) / 100; + case (uint8_t)Kamstrup::List3PhaseITLong: + meterTimestamp = hanReader.getTime( (uint8_t)Kamstrup_List3Phase::MeterClock, true, true); + activeImportCounter = ((float) hanReader.getInt((uint8_t)Kamstrup_List3Phase::CumulativeActiveImportEnergy)) / 100; + activeExportCounter = ((float) hanReader.getInt((uint8_t)Kamstrup_List3Phase::CumulativeActiveExportEnergy)) / 100; + reactiveImportCounter = ((float) hanReader.getInt((uint8_t)Kamstrup_List3Phase::CumulativeReactiveImportEnergy)) / 100; + reactiveExportCounter = ((float) hanReader.getInt((uint8_t)Kamstrup_List3Phase::CumulativeReactiveExportEnergy)) / 100; + case (uint8_t)Kamstrup::List3PhaseITShort: + listId = hanReader.getString( (uint8_t)Kamstrup_List3Phase::ListVersionIdentifier); + meterId = hanReader.getString( (uint8_t)Kamstrup_List3Phase::MeterID); + meterType = hanReader.getString( (uint8_t)Kamstrup_List3Phase::MeterType); + activeImportPower = hanReader.getInt( (uint8_t)Kamstrup_List3Phase::ActiveImportPower); + reactiveImportPower = hanReader.getInt( (uint8_t)Kamstrup_List3Phase::ReactiveImportPower); + activeExportPower = hanReader.getInt( (uint8_t)Kamstrup_List3Phase::ActiveExportPower); + reactiveExportPower = hanReader.getInt( (uint8_t)Kamstrup_List3Phase::ReactiveExportPower); + l1current = ((float) hanReader.getInt((uint8_t)Kamstrup_List3Phase::CurrentL1)) / 100; l2current = 0; - l3current = ((double) hanReader.getInt((int)Kamstrup_List3Phase::CurrentL3)) / 100; - l1voltage = hanReader.getInt( (int)Kamstrup_List3Phase::VoltageL1); - l2voltage = hanReader.getInt( (int)Kamstrup_List3Phase::VoltageL2); - l3voltage = hanReader.getInt( (int)Kamstrup_List3Phase::VoltageL3); + l3current = ((float) hanReader.getInt((uint8_t)Kamstrup_List3Phase::CurrentL3)) / 100; + l1voltage = hanReader.getInt( (uint8_t)Kamstrup_List3Phase::VoltageL1); + l2voltage = hanReader.getInt( (uint8_t)Kamstrup_List3Phase::VoltageL2); + l3voltage = hanReader.getInt( (uint8_t)Kamstrup_List3Phase::VoltageL3); if(substituteMissing) { l2current = (((activeImportPower - activeExportPower) * sqrt(3)) - (l1voltage * l1current) - (l3voltage * l3current)) / l2voltage; } @@ -261,25 +261,25 @@ void AmsData::extractFromKamstrup(HanReader& hanReader, int listSize, bool subst } } -void AmsData::extractFromOmnipower(HanReader& hanReader, int listSize) { +void AmsData::extractFromOmnipower(HanReader& hanReader, uint8_t listSize) { switch(listSize) { - case (int)Omnipower::DLMS: - meterTimestamp = hanReader.getTime( (int)Omnipower_DLMS::MeterClock, true, true); - activeImportCounter = ((double) hanReader.getInt((int)Omnipower_DLMS::CumulativeActiveImportEnergy)) / 100; - activeExportCounter = ((double) hanReader.getInt((int)Omnipower_DLMS::CumulativeActiveExportEnergy)) / 100; - reactiveImportCounter = ((double) hanReader.getInt((int)Omnipower_DLMS::CumulativeReactiveImportEnergy)) / 100; - reactiveExportCounter = ((double) hanReader.getInt((int)Omnipower_DLMS::CumulativeReactiveExportEnergy)) / 100; - listId = hanReader.getString( (int)Omnipower_DLMS::ListVersionIdentifier); - activeImportPower = hanReader.getInt( (int)Omnipower_DLMS::ActiveImportPower); - reactiveImportPower = hanReader.getInt( (int)Omnipower_DLMS::ReactiveImportPower); - activeExportPower = hanReader.getInt( (int)Omnipower_DLMS::ActiveExportPower); - reactiveExportPower = hanReader.getInt( (int)Omnipower_DLMS::ReactiveExportPower); - l1current = ((double) hanReader.getInt((int)Omnipower_DLMS::CurrentL1)) / 100; - l2current = ((double) hanReader.getInt((int)Omnipower_DLMS::CurrentL2)) / 100; - l3current = ((double) hanReader.getInt((int)Omnipower_DLMS::CurrentL3)) / 100; - l1voltage = hanReader.getInt( (int)Omnipower_DLMS::VoltageL1); - l2voltage = hanReader.getInt( (int)Omnipower_DLMS::VoltageL2); - l3voltage = hanReader.getInt( (int)Omnipower_DLMS::VoltageL3); + case (uint8_t)Omnipower::DLMS: + meterTimestamp = hanReader.getTime( (uint8_t)Omnipower_DLMS::MeterClock, true, true); + activeImportCounter = ((float) hanReader.getInt((uint8_t)Omnipower_DLMS::CumulativeActiveImportEnergy)) / 100; + activeExportCounter = ((float) hanReader.getInt((uint8_t)Omnipower_DLMS::CumulativeActiveExportEnergy)) / 100; + reactiveImportCounter = ((float) hanReader.getInt((uint8_t)Omnipower_DLMS::CumulativeReactiveImportEnergy)) / 100; + reactiveExportCounter = ((float) hanReader.getInt((uint8_t)Omnipower_DLMS::CumulativeReactiveExportEnergy)) / 100; + listId = hanReader.getString( (uint8_t)Omnipower_DLMS::ListVersionIdentifier); + activeImportPower = hanReader.getInt( (uint8_t)Omnipower_DLMS::ActiveImportPower); + reactiveImportPower = hanReader.getInt( (uint8_t)Omnipower_DLMS::ReactiveImportPower); + activeExportPower = hanReader.getInt( (uint8_t)Omnipower_DLMS::ActiveExportPower); + reactiveExportPower = hanReader.getInt( (uint8_t)Omnipower_DLMS::ReactiveExportPower); + l1current = ((float) hanReader.getInt((uint8_t)Omnipower_DLMS::CurrentL1)) / 100; + l2current = ((float) hanReader.getInt((uint8_t)Omnipower_DLMS::CurrentL2)) / 100; + l3current = ((float) hanReader.getInt((uint8_t)Omnipower_DLMS::CurrentL3)) / 100; + l1voltage = hanReader.getInt( (uint8_t)Omnipower_DLMS::VoltageL1); + l2voltage = hanReader.getInt( (uint8_t)Omnipower_DLMS::VoltageL2); + l3voltage = hanReader.getInt( (uint8_t)Omnipower_DLMS::VoltageL3); listType = 3; break; } @@ -292,28 +292,24 @@ void AmsData::apply(AmsData& other) { if(ms > 0) { if(other.getActiveImportPower() > 0) - activeImportCounter += (((double) ms) * other.getActiveImportPower()) / 3600000000; - counterEstimated = true; - } + activeImportCounter += (((float) ms) * other.getActiveImportPower()) / 3600000000; - if(other.getListType() > 1) { - unsigned long ms2 = this->lastList2UpdateMillis > other.getLastUpdateMillis() ? 0 : other.getLastUpdateMillis() - this->lastList2UpdateMillis; - if(ms2 > 0) { - // Not sure why, but I cannot make these numbers correct. It seems to be double of what it should, so dividing it by two... + if(other.getListType() > 1) { if(other.getActiveExportPower() > 0) - activeExportCounter += (((double) ms2/2) * other.getActiveExportPower()) / 3600000000; + activeExportCounter += (((float) ms*2) * other.getActiveExportPower()) / 3600000000; if(other.getReactiveImportPower() > 0) - reactiveImportCounter += (((double) ms2/2) * other.getReactiveImportPower()) / 3600000000; + reactiveImportCounter += (((float) ms*2) * other.getReactiveImportPower()) / 3600000000; if(other.getReactiveExportPower() > 0) - reactiveExportCounter += (((double) ms2/2) * other.getReactiveExportPower()) / 3600000000; - counterEstimated = true; + reactiveExportCounter += (((float) ms*2) * other.getReactiveExportPower()) / 3600000000; } + counterEstimated = true; } } this->lastUpdateMillis = other.getLastUpdateMillis(); this->packageTimestamp = other.getPackageTimestamp(); - this->listType = max(this->listType, other.getListType()); + if(other.getListType() > this->listType) + this->listType = other.getListType(); switch(other.getListType()) { case 3: this->meterTimestamp = other.getMeterTimestamp(); @@ -336,7 +332,6 @@ void AmsData::apply(AmsData& other) { this->l2voltage = other.getL2Voltage(); this->l3voltage = other.getL3Voltage(); this->threePhase = other.isThreePhase(); - this->lastList2UpdateMillis = other.getLastUpdateMillis(); case 1: this->activeImportPower = other.getActiveImportPower(); } @@ -346,11 +341,11 @@ unsigned long AmsData::getLastUpdateMillis() { return this->lastUpdateMillis; } -unsigned long AmsData::getPackageTimestamp() { +time_t AmsData::getPackageTimestamp() { return this->packageTimestamp; } -int AmsData::getListType() { +uint8_t AmsData::getListType() { return this->listType; } @@ -366,63 +361,63 @@ String AmsData::getMeterType() { return this->meterType; } -unsigned long AmsData::getMeterTimestamp() { +time_t AmsData::getMeterTimestamp() { return this->meterTimestamp; } -int AmsData::getActiveImportPower() { +uint16_t AmsData::getActiveImportPower() { return this->activeImportPower; } -int AmsData::getReactiveImportPower() { +uint16_t AmsData::getReactiveImportPower() { return this->reactiveImportPower; } -int AmsData::getActiveExportPower() { +uint16_t AmsData::getActiveExportPower() { return this->activeExportPower; } -int AmsData::getReactiveExportPower() { +uint16_t AmsData::getReactiveExportPower() { return this->reactiveExportPower; } -double AmsData::getL1Voltage() { +float AmsData::getL1Voltage() { return this->l1voltage; } -double AmsData::getL2Voltage() { +float AmsData::getL2Voltage() { return this->l2voltage; } -double AmsData::getL3Voltage() { +float AmsData::getL3Voltage() { return this->l3voltage; } -double AmsData::getL1Current() { +float AmsData::getL1Current() { return this->l1current; } -double AmsData::getL2Current() { +float AmsData::getL2Current() { return this->l2current; } -double AmsData::getL3Current() { +float AmsData::getL3Current() { return this->l3current; } -double AmsData::getActiveImportCounter() { +float AmsData::getActiveImportCounter() { return this->activeImportCounter; } -double AmsData::getReactiveImportCounter() { +float AmsData::getReactiveImportCounter() { return this->reactiveImportCounter; } -double AmsData::getActiveExportCounter() { +float AmsData::getActiveExportCounter() { return this->activeExportCounter; } -double AmsData::getReactiveExportCounter() { +float AmsData::getReactiveExportCounter() { return this->reactiveExportCounter; } diff --git a/src/AmsData.h b/src/AmsData.h index a5d3f680..7647a743 100644 --- a/src/AmsData.h +++ b/src/AmsData.h @@ -13,58 +13,57 @@ class AmsData { public: AmsData(); - AmsData(int meterType, bool substituteMissing, HanReader& hanReader); + AmsData(uint8_t meterType, bool substituteMissing, HanReader& hanReader); void apply(AmsData& other); unsigned long getLastUpdateMillis(); - unsigned long getPackageTimestamp(); + time_t getPackageTimestamp(); - int getListType(); + uint8_t getListType(); String getListId(); String getMeterId(); String getMeterType(); - unsigned long getMeterTimestamp(); + time_t getMeterTimestamp(); - int getActiveImportPower(); - int getReactiveImportPower(); - int getActiveExportPower(); - int getReactiveExportPower(); + uint16_t getActiveImportPower(); + uint16_t getReactiveImportPower(); + uint16_t getActiveExportPower(); + uint16_t getReactiveExportPower(); - double getL1Voltage(); - double getL2Voltage(); - double getL3Voltage(); + float getL1Voltage(); + float getL2Voltage(); + float getL3Voltage(); - double getL1Current(); - double getL2Current(); - double getL3Current(); + float getL1Current(); + float getL2Current(); + float getL3Current(); - double getActiveImportCounter(); - double getReactiveImportCounter(); - double getActiveExportCounter(); - double getReactiveExportCounter(); + float getActiveImportCounter(); + float getReactiveImportCounter(); + float getActiveExportCounter(); + float getReactiveExportCounter(); bool isThreePhase(); private: unsigned long lastUpdateMillis = 0; - unsigned long lastList2UpdateMillis = 0; - int listType = 0; - unsigned long packageTimestamp = 0; + uint8_t listType = 0; + time_t packageTimestamp = 0; String listId, meterId, meterType; - unsigned long meterTimestamp = 0; - int activeImportPower = 0, reactiveImportPower = 0, activeExportPower = 0, reactiveExportPower = 0; - double l1voltage = 0, l2voltage = 0, l3voltage = 0, l1current = 0, l2current = 0, l3current = 0; - double activeImportCounter = 0, reactiveImportCounter = 0, activeExportCounter = 0, reactiveExportCounter = 0; + time_t meterTimestamp = 0; + uint16_t activeImportPower = 0, reactiveImportPower = 0, activeExportPower = 0, reactiveExportPower = 0; + 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, counterEstimated = false; - void extractFromKaifa(HanReader& hanReader, int listSize); - void extractFromAidon(HanReader& hanReader, int listSize, bool substituteMissing); - void extractFromKamstrup(HanReader& hanReader, int listSize, bool substituteMissing); - void extractFromOmnipower(HanReader& hanReader, int listSize); + void extractFromKaifa(HanReader& hanReader, uint8_t listSize); + void extractFromAidon(HanReader& hanReader, uint8_t listSize, bool substituteMissing); + void extractFromKamstrup(HanReader& hanReader, uint8_t listSize, bool substituteMissing); + void extractFromOmnipower(HanReader& hanReader, uint8_t listSize); }; #endif diff --git a/src/AmsToMqttBridge.ino b/src/AmsToMqttBridge.ino index 5725a605..37012515 100644 --- a/src/AmsToMqttBridge.ino +++ b/src/AmsToMqttBridge.ino @@ -51,7 +51,7 @@ ADC_MODE(ADC_VCC); HwTools hw; -DNSServer dnsServer; +DNSServer* dnsServer = NULL; AmsConfiguration config; @@ -69,89 +69,79 @@ HanReader hanReader; Stream *hanSerial; +GpioConfig gpioConfig; +MeterConfig meterConfig; +DomoticzConfig* domoConfig = NULL; +float energy = 0.0; +bool mqttEnabled = false; +String clientId = "ams-reader"; +uint8_t payloadFormat = 0; +String topic = "ams"; +AmsData meterState; + void setup() { - if(config.hasConfig()) { - config.load(); + WiFiConfig wifi; + Serial.begin(115200); - TimeChangeRule std = {"STD", Last, Sun, Oct, 3, config.getNtpOffset() / 60}; - TimeChangeRule dst = {"DST", Last, Sun, Mar, 2, (config.getNtpOffset() + config.getNtpSummerOffset()) / 60}; - tz = new Timezone(dst, std); - } - - if(!config.hasConfig() || config.getConfigVersion() < 81) { - debugI("Setting default hostname"); - uint16_t chipId; - #if defined(ESP32) - chipId = ESP.getEfuseMac(); - #else - chipId = ESP.getChipId(); - #endif - config.setWifiHostname((String("ams-") + String(chipId, HEX)).c_str()); - } - - if(!config.hasConfig() || config.getConfigVersion() < 82) { - config.setVccMultiplier(1.0); - config.setVccBootLimit(0); + if(!config.getGpioConfig(gpioConfig)) { #if HW_ROARFRED - config.setHanPin(3); - config.setApPin(0); - config.setLedPin(2); - config.setLedInverted(true); - config.setTempSensorPin(5); + gpioConfig.hanPin = 3; + gpioConfig.apPin = 0; + gpioConfig.ledPin = 2; + gpioConfig.ledInverted = true; + gpioConfig.tempSensorPin = 5; #elif defined(ARDUINO_ESP8266_WEMOS_D1MINI) - config.setHanPin(5); - config.setApPin(4); - config.setLedPin(2); - config.setLedInverted(true); - config.setTempSensorPin(14); - config.setVccMultiplier(1.1); + gpioConfig.hanPin = 5; + gpioConfig.apPin = 4; + gpioConfig.ledPin = 2; + gpioConfig.ledInverted = true; + gpioConfig.tempSensorPin = 14; + gpioConfig.vccMultiplier = 1100; #elif defined(ARDUINO_LOLIN_D32) - config.setHanPin(16); - config.setLedPin(5); - config.setLedInverted(true); - config.setTempSensorPin(14); - config.setVccPin(35); - config.setVccMultiplier(2.25); + gpioConfig.hanPin = 16; + gpioConfig.ledPin = 5; + gpioConfig.ledInverted = true; + gpioConfig.tempSensorPin = 14; + gpioConfig.vccPin = 35; + gpioConfig.vccMultiplier = 2250; #elif defined(ARDUINO_FEATHER_ESP32) - config.setHanPin(16); - config.setLedPin(2); - config.setTempSensorPin(14); + gpioConfig.hanPin = 16; + gpioConfig.ledPin = 2; + gpioConfig.tempSensorPin = 14; #elif defined(ARDUINO_ESP32_DEV) - config.setHanPin(16); - config.setLedPin(2); - config.setLedInverted(false); + gpioConfig.hanPin = 16; + gpioConfig.ledPin = 2; + gpioConfig.ledInverted = true; #elif defined(ESP8266) - config.setHanPin(3); - config.setLedPin(2); - config.setLedInverted(true); + gpioConfig.hanPin = 3; + gpioConfig.ledPin = 2; + gpioConfig.ledInverted = true; #elif defined(ESP32) - config.setHanPin(16); - config.setLedPin(2); - config.setLedInverted(true); - config.setTempSensorPin(14); + gpioConfig.hanPin = 16; + gpioConfig.ledPin = 2; + gpioConfig.ledInverted = true; + gpioConfig.tempSensorPin = 14; #endif } delay(1); - hw.setLed(config.getLedPin(), config.isLedInverted()); - hw.setLedRgb(config.getLedPinRed(), config.getLedPinGreen(), config.getLedPinBlue(), config.isLedRgbInverted()); - hw.setTempSensorPin(config.getTempSensorPin()); - hw.setTempAnalogSensorPin(config.getTempAnalogSensorPin()); - hw.setVccPin(config.getVccPin()); - hw.setVccMultiplier(config.getVccMultiplier()); - hw.setVccOffset(config.getVccOffset()); + hw.setup(&gpioConfig, &config); hw.ledBlink(LED_INTERNAL, 1); hw.ledBlink(LED_RED, 1); hw.ledBlink(LED_YELLOW, 1); hw.ledBlink(LED_GREEN, 1); hw.ledBlink(LED_BLUE, 1); - eapi.setToken(config.getEntsoeApiToken()); - eapi.setArea(config.getEntsoeApiArea()); - eapi.setCurrency(config.getEntsoeApiCurrency()); - eapi.setMultiplier(config.getEntsoeApiMultiplier()); - if(config.getHanPin() == 3) { - switch(config.getMeterType()) { + EntsoeConfig entsoe; + if(config.getEntsoeConfig(entsoe)) { + eapi.setup(entsoe); + } + + bool shared = false; + 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); @@ -160,34 +150,30 @@ void setup() { Serial.begin(2400, SERIAL_8E1); break; } - } else { + } + + if(!shared) { Serial.begin(115200); } - if(config.hasConfig() && config.isDebugSerial()) { - Debug.setSerialEnabled(config.isDebugSerial()); - } else { - #if DEBUG_MODE - Debug.setSerialEnabled(true); - #endif + DebugConfig debug; + if(config.getDebugConfig(debug)) { + Debug.setSerialEnabled(debug.serial); } + #if DEBUG_MODE + Debug.setSerialEnabled(true); + #endif delay(1); - uint8_t c = config.getTempSensorCount(); - for(int i = 0; i < c; i++) { - TempSensorConfig* tsc = config.getTempSensorConfig(i); - hw.confTempSensor(tsc->address, tsc->name, tsc->common); - } - - double vcc = hw.getVcc(); + float vcc = hw.getVcc(); if (Debug.isActive(RemoteDebug::INFO)) { debugI("AMS bridge started"); debugI("Voltage: %.2fV", vcc); } - double vccBootLimit = config.getVccBootLimit(); - if(vccBootLimit > 0 && (config.getApPin() == 0xFF || digitalRead(config.getApPin()) == HIGH)) { // Skip if user is holding AP button while booting (HIGH = button is released) + float vccBootLimit = gpioConfig.vccBootLimit == 0 ? 0 : gpioConfig.vccBootLimit / 10.0; + if(vccBootLimit > 0 && (gpioConfig.apPin == 0xFF || digitalRead(gpioConfig.apPin) == HIGH)) { // Skip if user is holding AP button while booting (HIGH = button is released) if (vcc < vccBootLimit) { if(Debug.isActive(RemoteDebug::INFO)) { debugI("Voltage is too low, sleeping"); @@ -271,9 +257,17 @@ void setup() { if(config.hasConfig()) { if(Debug.isActive(RemoteDebug::INFO)) config.print(&Debug); WiFi_connect(); - if(config.isNtpEnable()) { - configTime(config.getNtpOffset(), config.getNtpSummerOffset(), config.getNtpServer()); - sntp_servermode_dhcp(config.isNtpDhcp() ? 1 : 0); + + NtpConfig ntp; + if(config.getNtpConfig(ntp)) { + if(ntp.enable) { + configTime(ntp.offset*10, ntp.summerOffset*10, ntp.server); + sntp_servermode_dhcp(ntp.dhcp ? 1 : 0); + } + TimeChangeRule std = {"STD", Last, Sun, Oct, 3, ntp.offset / 60}; + TimeChangeRule dst = {"DST", Last, Sun, Mar, 2, (ntp.offset + ntp.summerOffset) / 60}; + tz = new Timezone(dst, std); + ws.setTimezone(tz); } } else { if(Debug.isActive(RemoteDebug::INFO)) { @@ -282,10 +276,9 @@ void setup() { swapWifiMode(); } - ws.setup(&config, &mqtt); + ws.setup(&config, &gpioConfig, &meterConfig, &meterState, &mqtt); } - int buttonTimer = 0; bool buttonActive = false; unsigned long longPressTime = 5000; @@ -301,9 +294,6 @@ unsigned long lastSuccessfulRead = 0; unsigned long lastErrorBlink = 0; int lastError = 0; -// domoticz energy init -double energy = -1.0; - String toHex(uint8_t* in) { String hex; for(int i = 0; i < sizeof(in)*2; i++) { @@ -316,12 +306,11 @@ String toHex(uint8_t* in) { return hex; } - void loop() { Debug.handle(); unsigned long now = millis(); - if(config.getApPin() != 0xFF) { - if (digitalRead(config.getApPin()) == LOW) { + if(gpioConfig.apPin != 0xFF) { + if (digitalRead(gpioConfig.apPin) == LOW) { if (buttonActive == false) { buttonActive = true; buttonTimer = now; @@ -342,7 +331,7 @@ void loop() { } } } - + if(now - lastTemperatureRead > 15000) { unsigned long start = millis(); hw.updateTemperatures(); @@ -350,7 +339,7 @@ void loop() { uint8_t c = hw.getTempSensorCount(); - if(strlen(config.getMqttHost()) > 0) { + if(WiFi.getMode() != WIFI_AP && WiFi.status() == WL_CONNECTED && mqtt.connected() && !topic.isEmpty()) { bool anyChanged = false; for(int i = 0; i < c; i++) { bool changed = false; @@ -360,25 +349,28 @@ void loop() { temperatures[i] = data->lastValidRead; } - if((changed && config.getMqttPayloadFormat() == 1) || config.getMqttPayloadFormat() == 2) { - mqtt.publish(String(config.getMqttPublishTopic()) + "/temperature/" + toHex(data->address), String(temperatures[i], 2)); + if((changed && payloadFormat == 1) || payloadFormat == 2) { + mqtt.publish(topic + "/temperature/" + toHex(data->address), String(temperatures[i], 2)); } anyChanged |= changed; } - if(anyChanged && config.getMqttPayloadFormat() == 0) { + if(anyChanged && payloadFormat == 0) { StaticJsonDocument<512> json; JsonObject temps = json.createNestedObject("temperatures"); for(int i = 0; i < c; i++) { - TempSensorData* data = hw.getTempSensorData(i); + TempSensorData* data = hw.getTempSensorData(i); + TempSensorConfig* conf = config.getTempSensorConfig(data->address); JsonObject obj = temps.createNestedObject(toHex(data->address)); - obj["name"] = data->name; + if(conf != NULL) { + obj["name"] = conf->name; + } obj["value"] = serialized(String(temperatures[i], 2)); } String msg; serializeJson(json, msg); - mqtt.publish(config.getMqttPublishTopic(), msg.c_str()); + mqtt.publish(topic, msg.c_str()); } } debugD("Used %d ms to update temperature", millis()-start); @@ -393,32 +385,55 @@ void loop() { } else { if(!wifiConnected) { wifiConnected = true; - if(config.getAuthSecurity() > 0) { - Debug.setPassword(config.getAuthPassword()); - } - Debug.begin(config.getWifiHostname(), (uint8_t) config.getDebugLevel()); - Debug.setSerialEnabled(config.isDebugSerial()); - if(!config.isDebugTelnet()) { - Debug.stop(); - } - if(Debug.isActive(RemoteDebug::INFO)) { - debugI("Successfully connected to WiFi!"); - debugI("IP: %s", WiFi.localIP().toString().c_str()); - } - if(strlen(config.getWifiHostname()) > 0 && config.isMdnsEnable()) { - debugD("mDNS is enabled, using host: %s", config.getWifiHostname()); - if(MDNS.begin(config.getWifiHostname())) { - MDNS.addService("http", "tcp", 80); - } else { - debugE("Failed to set up mDNS!"); + + WiFiConfig wifi; + if(config.getWiFiConfig(wifi)) { + WebConfig web; + if(config.getWebConfig(web) && web.security > 0) { + Debug.setPassword(web.password); } + DebugConfig debug; + if(config.getDebugConfig(debug)) { + Debug.begin(wifi.hostname, (uint8_t) debug.level); + Debug.setSerialEnabled(debug.serial); + if(!debug.telnet) { + Debug.stop(); + } + } + if(Debug.isActive(RemoteDebug::INFO)) { + debugI("Successfully connected to WiFi!"); + debugI("IP: %s", WiFi.localIP().toString().c_str()); + debugI("GW: %s", WiFi.gatewayIP().toString().c_str()); + debugI("DNS: %s", WiFi.dnsIP().toString().c_str()); + } + if(strlen(wifi.hostname) > 0 && wifi.mdns) { + debugD("mDNS is enabled, using host: %s", wifi.hostname); + if(MDNS.begin(wifi.hostname)) { + MDNS.addService("http", "tcp", 80); + } else { + debugE("Failed to set up mDNS!"); + } + } + } + + MqttConfig mqttConfig; + if(config.getMqttConfig(mqttConfig)) { + mqttEnabled = strlen(mqttConfig.host) > 0; } } if(config.isNtpChanged()) { - if(config.isNtpEnable()) { - configTime(config.getNtpOffset(), config.getNtpSummerOffset(), config.getNtpServer()); - sntp_servermode_dhcp(config.isNtpDhcp() ? 1 : 0); + NtpConfig ntp; + if(config.getNtpConfig(ntp) && ntp.enable && strlen(ntp.server) > 0) { + configTime(ntp.offset*10, ntp.summerOffset*10, ntp.server); + sntp_servermode_dhcp(ntp.dhcp ? 1 : 0); } + + if(tz != NULL) delete tz; + TimeChangeRule std = {"STD", Last, Sun, Oct, 3, ntp.offset / 60}; + TimeChangeRule dst = {"DST", Last, Sun, Mar, 2, (ntp.offset + ntp.summerOffset) / 60}; + tz = new Timezone(dst, std); + ws.setTimezone(tz); + config.ackNtpChange(); } #if defined ESP8266 @@ -429,13 +444,13 @@ void loop() { errorBlink(); } - if (strlen(config.getMqttHost()) > 0) { + if (mqttEnabled || config.isMqttChanged()) { mqtt.loop(); delay(10); // Needed to preserve power. After adding this, the voltage is super smooth on a HAN powered device if(!mqtt.connected() || config.isMqttChanged()) { MQTT_connect(); } - if(config.getMqttPayloadFormat() == 1) { + if(payloadFormat == 1) { sendSystemStatusToMqtt(); } } else if(mqtt.connected()) { @@ -443,7 +458,9 @@ void loop() { } } } else { - dnsServer.processNextRequest(); + if(dnsServer != NULL) { + dnsServer->processNextRequest(); + } // Continously flash the LED when AP mode if (now / 50 % 64 == 0) { if(!hw.ledBlink(LED_YELLOW, 1)) { @@ -453,7 +470,8 @@ void loop() { } if(config.isMeterChanged()) { - setupHanPort(config.getHanPin(), config.getMeterType()); + config.getMeterConfig(meterConfig); + setupHanPort(gpioConfig.hanPin, meterConfig.type); config.ackMeterChanged(); } delay(1); @@ -521,8 +539,8 @@ void setupHanPort(int pin, int newMeterType) { } hanReader.setup(hanSerial, &Debug); - hanReader.setEncryptionKey(config.getMeterEncryptionKey()); - hanReader.setAuthenticationKey(config.getMeterAuthenticationKey()); + hanReader.setEncryptionKey(meterConfig.encryptionKey); + hanReader.setAuthenticationKey(meterConfig.authenticationKey); // Compensate for the known Kaifa bug hanReader.compensateFor09HeaderBug = (newMeterType == 1); @@ -531,16 +549,6 @@ void setupHanPort(int pin, int newMeterType) { while (hanSerial->available() > 0) { hanSerial->read(); } - - if(config.hasConfig() && config.isDebugSerial()) { - if(WiFi.status() == WL_CONNECTED) { - Debug.begin(config.getWifiHostname(), (uint8_t) config.getDebugLevel()); - } - Debug.setSerialEnabled(config.isDebugSerial()); - if(!config.isDebugTelnet()) { - Debug.stop(); - } - } } void errorBlink() { @@ -556,7 +564,7 @@ void errorBlink() { } break; case 1: - if(strlen(config.getMqttHost()) > 0 && mqtt.lastError() != 0) { + if(mqttEnabled && mqtt.lastError() != 0) { hw.ledBlink(LED_RED, 2); // If MQTT error, blink twice return; } @@ -576,7 +584,9 @@ void swapWifiMode() { hw.ledOn(LED_INTERNAL); } WiFiMode_t mode = WiFi.getMode(); - dnsServer.stop(); + if(dnsServer != NULL) { + dnsServer->stop(); + } WiFi.disconnect(true); WiFi.softAPdisconnect(true); WiFi.mode(WIFI_OFF); @@ -587,10 +597,17 @@ void swapWifiMode() { WiFi.softAP("AMS2MQTT"); WiFi.mode(WIFI_AP); - dnsServer.setErrorReplyCode(DNSReplyCode::NoError); - dnsServer.start(53, "*", WiFi.softAPIP()); + if(dnsServer == NULL) { + dnsServer = new DNSServer(); + } + dnsServer->setErrorReplyCode(DNSReplyCode::NoError); + dnsServer->start(53, "*", WiFi.softAPIP()); } else { if(Debug.isActive(RemoteDebug::INFO)) debugI("Swapping to STA mode"); + if(dnsServer != NULL) { + delete dnsServer; + dnsServer = NULL; + } WiFi_connect(); } delay(500); @@ -611,18 +628,18 @@ void mqttMessageReceived(String &topic, String &payload) } void sendPricesToMqtt() { - if(strlen(config.getMqttHost()) == 0 || strlen(config.getMqttPublishTopic()) == 0) + if(!mqttEnabled || topic.isEmpty() || !mqtt.connected()) return; - if(strcmp(config.getEntsoeApiToken(), "") != 0) + if(strcmp(eapi.getToken(), "") != 0) return; time_t now = time(nullptr); double min1hr, min3hr, min6hr; - int min1hrIdx = -1, min3hrIdx = -1, min6hrIdx = -1; + uint8_t min1hrIdx = -1, min3hrIdx = -1, min6hrIdx = -1; double min = INT16_MAX, max = INT16_MIN; double values[24] = {0}; - for(int i = 0; i < 24; i++) { + for(uint8_t i = 0; i < 24; i++) { double val = eapi.getValueForHour(now, i); values[i] = val; @@ -637,8 +654,9 @@ void sendPricesToMqtt() { } if(i >= 2) { - double val1 = values[i-2]; - double val2 = values[i-1]; + i -= 2; + double val1 = values[i++]; + double val2 = values[i++]; double val3 = val; if(val1 == ENTSOE_NO_VALUE || val2 == ENTSOE_NO_VALUE || val3 == ENTSOE_NO_VALUE) continue; double val3hr = val1+val2+val3; @@ -648,13 +666,13 @@ void sendPricesToMqtt() { } } - if(i >= 5) { - double val1 = values[i-5]; - double val2 = values[i-4]; - double val3 = values[i-3]; - double val4 = values[i-2]; - double val5 = values[i-1]; + i -= 5; + double val1 = values[i++]; + double val2 = values[i++]; + double val3 = values[i++]; + double val4 = values[i++]; + double val5 = values[i++]; double val6 = val; if(val1 == ENTSOE_NO_VALUE || val2 == ENTSOE_NO_VALUE || val3 == ENTSOE_NO_VALUE || val4 == ENTSOE_NO_VALUE || val5 == ENTSOE_NO_VALUE || val6 == ENTSOE_NO_VALUE) continue; double val6hr = val1+val2+val3+val4+val5+val6; @@ -685,12 +703,12 @@ void sendPricesToMqtt() { sprintf(ts6hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour); } - switch(config.getMqttPayloadFormat()) { + switch(payloadFormat) { case 0: // JSON { StaticJsonDocument<512> json; json["id"] = WiFi.macAddress(); - json["name"] = config.getMqttClientId(); + json["name"] = clientId; json["up"] = millis(); JsonObject jp = json.createNestedObject("prices"); for(int i = 0; i < 24; i++) { @@ -717,7 +735,7 @@ void sendPricesToMqtt() { String msg; serializeJson(json, msg); - mqtt.publish(config.getMqttPublishTopic(), msg.c_str()); + mqtt.publish(topic, msg.c_str()); break; } case 1: // RAW @@ -726,29 +744,29 @@ void sendPricesToMqtt() { for(int i = 0; i < 24; i++) { double val = values[i]; if(val == ENTSOE_NO_VALUE) { - mqtt.publish(String(config.getMqttPublishTopic()) + "/price/" + String(i), ""); + mqtt.publish(topic + "/price/" + String(i), ""); break; } else { - mqtt.publish(String(config.getMqttPublishTopic()) + "/price/" + String(i), String(val, 4)); + mqtt.publish(topic + "/price/" + String(i), String(val, 4)); } mqtt.loop(); delay(10); } if(min != INT16_MAX) { - mqtt.publish(String(config.getMqttPublishTopic()) + "/price/min", String(min, 4)); + mqtt.publish(topic + "/price/min", String(min, 4)); } if(max != INT16_MIN) { - mqtt.publish(String(config.getMqttPublishTopic()) + "/price/max", String(max, 4)); + mqtt.publish(topic + "/price/max", String(max, 4)); } if(min1hrIdx != -1) { - mqtt.publish(String(config.getMqttPublishTopic()) + "/price/cheapest/1hr", String(ts1hr)); + mqtt.publish(topic + "/price/cheapest/1hr", String(ts1hr)); } if(min3hrIdx != -1) { - mqtt.publish(String(config.getMqttPublishTopic()) + "/price/cheapest/3hr", String(ts3hr)); + mqtt.publish(topic + "/price/cheapest/3hr", String(ts3hr)); } if(min6hrIdx != -1) { - mqtt.publish(String(config.getMqttPublishTopic()) + "/price/cheapest/6hr", String(ts6hr)); + mqtt.publish(topic + "/price/cheapest/6hr", String(ts6hr)); } } break; @@ -756,23 +774,20 @@ void sendPricesToMqtt() { } int currentMeterType = 0; -AmsData lastMqttData; void readHanPort() { if (hanReader.read()) { lastSuccessfulRead = millis(); - if(config.getMeterType() > 0) { + if(meterConfig.type > 0) { if(!hw.ledBlink(LED_GREEN, 1)) hw.ledBlink(LED_INTERNAL, 1); - AmsData data(config.getMeterType(), config.isSubstituteMissing(), hanReader); + AmsData data(meterConfig.type, meterConfig.substituteMissing, hanReader); if(data.getListType() > 0) { - ws.setData(data); - - if(strlen(config.getMqttHost()) > 0 && strlen(config.getMqttPublishTopic()) > 0) { - if(config.getMqttPayloadFormat() == 0) { + if(mqttEnabled && !topic.isEmpty()) { + if(payloadFormat == 0) { StaticJsonDocument<512> json; - hanToJson(json, data, hw, hw.getTemperature(), config.getMqttClientId()); + hanToJson(json, data, hw, hw.getTemperature(), clientId); if (Debug.isActive(RemoteDebug::INFO)) { debugI("Sending data to MQTT"); if (Debug.isActive(RemoteDebug::DEBUG)) { @@ -782,204 +797,158 @@ void readHanPort() { String msg; serializeJson(json, msg); - mqtt.publish(config.getMqttPublishTopic(), msg.c_str()); + mqtt.publish(topic, msg.c_str()); // // Start DOMOTICZ // - } else if(config.getMqttPayloadFormat() == 3) { + } else if(payloadFormat == 3) { debugI("Sending data to MQTT"); - // - // Special MQTT messages for DOMOTIZ (https://www.domoticz.com/wiki/MQTT) - // -All messages should be published to topic "domoticz/in" - // - // message msg_PE : send active power and and cumulative energy consuption to virtual meter "Electricity (instant and counter)" - // - // /json.htm?type=command¶m=udevice&idx=IDX&nvalue=0&svalue=POWER;ENERGY - // - // MQTT sample message: {"command": "udevice", "idx" : IDX , "nvalue" : 0, "svalue" : "POWER;ENERGY"} - // IDX = id of your device (This number can be found in the devices tab in the column "IDX") - // POWER = current power (Watt) - // ENERGY = cumulative energy in Watt-hours (Wh) This is an incrementing counter. - // (if you choose as type "Energy read : Computed", this is just a "dummy" counter, not updatable because it's the result of DomoticZ calculs from POWER) - // - // message msg_V1 : send Voltage of L1 to virtual Voltage meter - // - // /json.htm?type=command¶m=udevice&idx=IDX&nvalue=0&svalue=VOLTAGE - // - // MQTT sample message: {"command": "udevice", "idx" : IDX , "nvalue" : 0, "svalue" : "VOLTAGE"} - // IDX = id of your device (This number can be found in the devices tab in the column "IDX") - // VOLTAGE = Voltage (V) - // - - int idx1 = config.getDomoELIDX(); - if (idx1 > 0) { - String PowerEnergy; - int p; - // double energy = config.getDomoEnergy(); - double tmp_energy; - StaticJsonDocument<200> json_PE; - p = data.getActiveImportPower(); - // cumulative energy is given only once pr hour. check if value is different from 0 and store last valid value on global variable. - tmp_energy = data.getActiveImportCounter(); - if (tmp_energy > 1.0) energy = tmp_energy; - // power_unit: watt, energy_unit: watt*h. Stored as kwh, need watth - PowerEnergy = String((double) p/1.0) + ";" + String((double) energy*1000.0) ; - json_PE["command"] = "udevice"; - json_PE["idx"] = idx1; - json_PE["nvalue"] = 0; - json_PE["svalue"] = PowerEnergy; - // Stringify the json - String msg_PE; - serializeJson(json_PE, msg_PE); - // publish power data directly to domoticz/in, but only after first reading of total power, once an hour... . (otherwise total consumtion will be wrong.) - if (energy > 0.0 ) mqtt.publish("domoticz/in", msg_PE.c_str()); + if(config.isDomoChanged()) { + if(domoConfig == NULL) + domoConfig = new DomoticzConfig(); + if(config.getDomoticzConfig(*domoConfig)) { + config.ackDomoChange(); + } } - int idxu1 =config.getDomoVL1IDX(); - if (idxu1 > 0){ - StaticJsonDocument<200> json_u1; - double u1; - // - // prepare message msg_u1 for virtual Voltage meter" - // - u1 = data.getL1Voltage(); - if (u1 > 0.1){ + + if (domoConfig->elidx > 0) { + if(data.getActiveImportCounter() > 1.0) { + energy = data.getActiveImportCounter(); + } + if(energy > 0.0) { + String PowerEnergy; + int p; + StaticJsonDocument<200> json_PE; + p = data.getActiveImportPower(); + PowerEnergy = String((double) p/1.0) + ";" + String(energy*1000.0, 0); + json_PE["command"] = "udevice"; + json_PE["idx"] = domoConfig->elidx; + json_PE["nvalue"] = 0; + json_PE["svalue"] = PowerEnergy; + String msg_PE; + serializeJson(json_PE, msg_PE); + mqtt.publish("domoticz/in", msg_PE.c_str()); + } + } + + if (domoConfig->vl1idx > 0){ + if (data.getL1Voltage() > 0.1){ + StaticJsonDocument<200> json_u1; json_u1["command"] = "udevice"; - json_u1["idx"] = idxu1; + json_u1["idx"] = domoConfig->vl1idx; json_u1["nvalue"] = 0; - json_u1["svalue"] = String(u1); - // Stringify the json + json_u1["svalue"] = String(data.getL1Voltage(), 2); String msg_u1; serializeJson(json_u1, msg_u1); - // publish power data directly to domoticz/in mqtt.publish("domoticz/in", msg_u1.c_str()); } } - int idxu2 =config.getDomoVL2IDX(); - if (idxu2 > 0){ - StaticJsonDocument<200> json_u2; - double u2; - // - // prepare message msg_u2 for virtual Voltage meter" - // - u2 = data.getL2Voltage(); - if (u2 > 0.1){ + + if (domoConfig->vl2idx > 0){ + if (data.getL2Voltage() > 0.1){ + StaticJsonDocument<200> json_u2; json_u2["command"] = "udevice"; - json_u2["idx"] = idxu2; + json_u2["idx"] = domoConfig->vl2idx; json_u2["nvalue"] = 0; - json_u2["svalue"] = String(u2); - // Stringify the json + json_u2["svalue"] = String(data.getL2Voltage(), 2); String msg_u2; serializeJson(json_u2, msg_u2); - // publish power data directly to domoticz/in mqtt.publish("domoticz/in", msg_u2.c_str()); } } - int idxu3 =config.getDomoVL3IDX(); - if (idxu3 > 0){ - StaticJsonDocument<200> json_u3; - double u3; - // - // prepare message msg_u3 for virtual Voltage meter" - // - u3 = data.getL3Voltage(); - if (u3 > 0.1){ + + if (domoConfig->vl3idx > 0){ + if (data.getL3Voltage() > 0.1){ + StaticJsonDocument<200> json_u3; json_u3["command"] = "udevice"; - json_u3["idx"] = idxu3; + json_u3["idx"] = domoConfig->vl3idx; json_u3["nvalue"] = 0; - json_u3["svalue"] = String(u3); - // Stringify the json + json_u3["svalue"] = String(data.getL3Voltage()); String msg_u3; serializeJson(json_u3, msg_u3); - // publish power data directly to domoticz/in mqtt.publish("domoticz/in", msg_u3.c_str()); } } - int idxi1 =config.getDomoCL1IDX(); - if (idxi1 > 0){ - StaticJsonDocument<200> json_i1; - double i1, i2, i3; - String Ampere3; - // - // prepare message msg_i1 for virtual Current/Ampere 3phase mater" - // - i1 = data.getL1Current(); - i2 = data.getL2Current(); - i3 = data.getL3Current(); - Ampere3 = String(i1) + ";" + String(i2) + ";" + String(i3) ; - json_i1["command"] = "udevice"; - json_i1["idx"] = idxi1; - json_i1["nvalue"] = 0; - json_i1["svalue"] = Ampere3; - // Stringify the json - String msg_i1; - serializeJson(json_i1, msg_i1); - // publish power data directly to domoticz/in - if (i1 > 0.0) mqtt.publish("domoticz/in", msg_i1.c_str()); + if (domoConfig->cl1idx > 0){ + if(data.getL1Current() > 0.0) { + StaticJsonDocument<200> json_i1; + String Ampere3; + Ampere3 = String(data.getL1Current(), 1) + ";" + String(data.getL2Current(), 1) + ";" + String(data.getL3Current(), 1) ; + json_i1["command"] = "udevice"; + json_i1["idx"] = domoConfig->cl1idx; + json_i1["nvalue"] = 0; + json_i1["svalue"] = Ampere3; + String msg_i1; + serializeJson(json_i1, msg_i1); + mqtt.publish("domoticz/in", msg_i1.c_str()); + } } // // End DOMOTICZ // - } else if(config.getMqttPayloadFormat() == 1 || config.getMqttPayloadFormat() == 2) { - mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/dlms/timestamp", String(data.getPackageTimestamp())); + } else if(payloadFormat == 1 || payloadFormat == 2) { + if(data.getPackageTimestamp() > 0) { + mqtt.publish(topic + "/meter/dlms/timestamp", String(data.getPackageTimestamp())); + } switch(data.getListType()) { case 3: // ID and type belongs to List 2, but I see no need to send that every 10s - mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/id", data.getMeterId()); - mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/type", data.getMeterType()); - mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/clock", String(data.getMeterTimestamp())); - mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/import/reactive/accumulated", String(data.getReactiveImportCounter(), 2)); - mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/import/active/accumulated", String(data.getActiveImportCounter(), 2)); - mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/export/reactive/accumulated", String(data.getReactiveExportCounter(), 2)); - mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/export/active/accumulated", String(data.getActiveExportCounter(), 2)); + mqtt.publish(topic + "/meter/id", data.getMeterId()); + mqtt.publish(topic + "/meter/type", data.getMeterType()); + mqtt.publish(topic + "/meter/clock", String(data.getMeterTimestamp())); + mqtt.publish(topic + "/meter/import/reactive/accumulated", String(data.getReactiveImportCounter(), 2)); + mqtt.publish(topic + "/meter/import/active/accumulated", String(data.getActiveImportCounter(), 2)); + mqtt.publish(topic + "/meter/export/reactive/accumulated", String(data.getReactiveExportCounter(), 2)); + mqtt.publish(topic + "/meter/export/active/accumulated", String(data.getActiveExportCounter(), 2)); sendPricesToMqtt(); case 2: // Only send data if changed. ID and Type is sent on the 10s interval only if changed - if(lastMqttData.getMeterId() != data.getMeterId() || config.getMqttPayloadFormat() == 2) { - mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/id", data.getMeterId()); + if(meterState.getMeterId() != data.getMeterId() || payloadFormat == 2) { + mqtt.publish(topic + "/meter/id", data.getMeterId()); } - if(lastMqttData.getMeterType() != data.getMeterType() || config.getMqttPayloadFormat() == 2) { - mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/type", data.getMeterType()); + if(meterState.getMeterType() != data.getMeterType() || payloadFormat == 2) { + mqtt.publish(topic + "/meter/type", data.getMeterType()); } - if(lastMqttData.getL1Current() != data.getL1Current() || config.getMqttPayloadFormat() == 2) { - mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/l1/current", String(data.getL1Current(), 2)); + if(meterState.getL1Current() != data.getL1Current() || payloadFormat == 2) { + mqtt.publish(topic + "/meter/l1/current", String(data.getL1Current(), 2)); } - if(lastMqttData.getL1Voltage() != data.getL1Voltage() || config.getMqttPayloadFormat() == 2) { - mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/l1/voltage", String(data.getL1Voltage(), 2)); + if(meterState.getL1Voltage() != data.getL1Voltage() || payloadFormat == 2) { + mqtt.publish(topic + "/meter/l1/voltage", String(data.getL1Voltage(), 2)); } - if(lastMqttData.getL2Current() != data.getL2Current() || config.getMqttPayloadFormat() == 2) { - mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/l2/current", String(data.getL2Current(), 2)); + if(meterState.getL2Current() != data.getL2Current() || payloadFormat == 2) { + mqtt.publish(topic + "/meter/l2/current", String(data.getL2Current(), 2)); } - if(lastMqttData.getL2Voltage() != data.getL2Voltage() || config.getMqttPayloadFormat() == 2) { - mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/l2/voltage", String(data.getL2Voltage(), 2)); + if(meterState.getL2Voltage() != data.getL2Voltage() || payloadFormat == 2) { + mqtt.publish(topic + "/meter/l2/voltage", String(data.getL2Voltage(), 2)); } - if(lastMqttData.getL3Current() != data.getL3Current() || config.getMqttPayloadFormat() == 2) { - mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/l3/current", String(data.getL3Current(), 2)); + if(meterState.getL3Current() != data.getL3Current() || payloadFormat == 2) { + mqtt.publish(topic + "/meter/l3/current", String(data.getL3Current(), 2)); } - if(lastMqttData.getL3Voltage() != data.getL3Voltage() || config.getMqttPayloadFormat() == 2) { - mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/l3/voltage", String(data.getL3Voltage(), 2)); + if(meterState.getL3Voltage() != data.getL3Voltage() || payloadFormat == 2) { + mqtt.publish(topic + "/meter/l3/voltage", String(data.getL3Voltage(), 2)); } - if(lastMqttData.getReactiveExportPower() != data.getReactiveExportPower() || config.getMqttPayloadFormat() == 2) { - mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/export/reactive", String(data.getReactiveExportPower())); + if(meterState.getReactiveExportPower() != data.getReactiveExportPower() || payloadFormat == 2) { + mqtt.publish(topic + "/meter/export/reactive", String(data.getReactiveExportPower())); } - if(lastMqttData.getActiveExportPower() != data.getActiveExportPower() || config.getMqttPayloadFormat() == 2) { - mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/export/active", String(data.getActiveExportPower())); + if(meterState.getActiveExportPower() != data.getActiveExportPower() || payloadFormat == 2) { + mqtt.publish(topic + "/meter/export/active", String(data.getActiveExportPower())); } - if(lastMqttData.getReactiveImportPower() != data.getReactiveImportPower() || config.getMqttPayloadFormat() == 2) { - mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/import/reactive", String(data.getReactiveImportPower())); + if(meterState.getReactiveImportPower() != data.getReactiveImportPower() || payloadFormat == 2) { + mqtt.publish(topic + "/meter/import/reactive", String(data.getReactiveImportPower())); } case 1: - if(lastMqttData.getActiveImportPower() != data.getActiveImportPower() || config.getMqttPayloadFormat() == 2) { - mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/import/active", String(data.getActiveImportPower())); + if(meterState.getActiveImportPower() != data.getActiveImportPower() || payloadFormat == 2) { + mqtt.publish(topic + "/meter/import/active", String(data.getActiveImportPower())); } } } - lastMqttData.apply(data); mqtt.loop(); delay(10); } + meterState.apply(data); } else { - if(config.isSendUnknown() && strlen(config.getMqttHost()) > 0 && strlen(config.getMqttPublishTopic()) > 0) { + if(meterConfig.sendUnknown && mqttEnabled && mqtt.connected()) { byte buf[512]; int length = hanReader.getBuffer(buf); String hexstring = ""; @@ -991,7 +960,7 @@ void readHanPort() { hexstring += String(buf[i], HEX); } - mqtt.publish(String(config.getMqttPublishTopic()), hexstring); + mqtt.publish(topic, hexstring); } } } else { @@ -1012,31 +981,34 @@ void readHanPort() { if(!list.isEmpty()) { list.toLowerCase(); if(list.startsWith("kfm")) { - config.setMeterType(1); + meterConfig.type = 1; + config.setMeterConfig(meterConfig); if(Debug.isActive(RemoteDebug::INFO)) debugI("Detected Kaifa meter"); break; } else if(list.startsWith("aidon")) { - config.setMeterType(2); + meterConfig.type = 2; + config.setMeterConfig(meterConfig); if(Debug.isActive(RemoteDebug::INFO)) debugI("Detected Aidon meter"); break; } else if(list.startsWith("kamstrup")) { - config.setMeterType(3); + meterConfig.type = 3; + config.setMeterConfig(meterConfig); if(Debug.isActive(RemoteDebug::INFO)) debugI("Detected Kamstrup meter"); break; } } } - hanReader.compensateFor09HeaderBug = (config.getMeterType() == 1); + hanReader.compensateFor09HeaderBug = (meterConfig.type == 1); } } // Switch parity if meter is still not detected - if(config.getMeterType() == 0 && millis() - lastSuccessfulRead > 10000) { + 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(config.getHanPin(), currentMeterType); + setupHanPort(gpioConfig.hanPin, currentMeterType); } delay(1); } @@ -1050,44 +1022,53 @@ void WiFi_connect() { } lastWifiRetry = millis(); - if (Debug.isActive(RemoteDebug::INFO)) debugI("Connecting to WiFi network: %s", config.getWifiSsid()); - if (WiFi.status() != WL_CONNECTED) { + WiFiConfig wifi; + if(!config.getWiFiConfig(wifi) || strlen(wifi.ssid) == 0) { + swapWifiMode(); + return; + } + + if (Debug.isActive(RemoteDebug::INFO)) debugI("Connecting to WiFi network: %s", wifi.ssid); + MDNS.end(); WiFi.disconnect(); yield(); WiFi.enableAP(false); WiFi.mode(WIFI_STA); - if(strlen(config.getWifiIp()) > 0) { + if(strlen(wifi.ip) > 0) { IPAddress ip, gw, sn(255,255,255,0), dns1, dns2; - ip.fromString(config.getWifiIp()); - gw.fromString(config.getWifiGw()); - sn.fromString(config.getWifiSubnet()); - dns1.fromString(config.getWifiDns1()); - dns2.fromString(config.getWifiDns2()); + ip.fromString(wifi.ip); + gw.fromString(wifi.gateway); + sn.fromString(wifi.subnet); + dns1.fromString(wifi.dns1); + dns2.fromString(wifi.dns2); WiFi.config(ip, gw, sn, dns1, dns2); } else { -#if defined(ESP32) + #if defined(ESP32) WiFi.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); // Workaround to make DHCP hostname work for ESP32. See: https://github.com/espressif/arduino-esp32/issues/2537 -#endif + #endif } - if(strlen(config.getWifiHostname()) > 0) { -#if defined(ESP8266) - WiFi.hostname(config.getWifiHostname()); -#elif defined(ESP32) - WiFi.setHostname(config.getWifiHostname()); -#endif + if(strlen(wifi.hostname) > 0) { + #if defined(ESP8266) + WiFi.hostname(wifi.hostname); + #elif defined(ESP32) + WiFi.setHostname(wifi.hostname); + #endif } - WiFi.begin(config.getWifiSsid(), config.getWifiPassword()); + WiFi.begin(wifi.ssid, wifi.psk); yield(); } } unsigned long lastMqttRetry = -10000; void MQTT_connect() { - if(strlen(config.getMqttHost()) == 0) { + MqttConfig mqttConfig; + if(!config.getMqttConfig(mqttConfig) || strlen(mqttConfig.host) == 0) { if(Debug.isActive(RemoteDebug::WARNING)) debugW("No MQTT config"); + mqttEnabled = false; + config.ackMqttChange(); return; } if(millis() - lastMqttRetry < (mqtt.lastError() == 0 || config.isMqttChanged() ? 5000 : 30000)) { @@ -1095,6 +1076,12 @@ void MQTT_connect() { return; } lastMqttRetry = millis(); + + clientId = String(mqttConfig.clientId); + mqttEnabled = true; + payloadFormat = mqttConfig.payloadFormat; + topic = String(mqttConfig.publishTopic); + if(Debug.isActive(RemoteDebug::INFO)) { debugD("Disconnecting MQTT before connecting"); } @@ -1104,13 +1091,13 @@ void MQTT_connect() { WiFiClientSecure *secureClient = NULL; Client *client = NULL; - if(config.isMqttSsl()) { + if(mqttConfig.ssl) { debugI("MQTT SSL is configured"); secureClient = new WiFiClientSecure(); -#if defined(ESP8266) + #if defined(ESP8266) secureClient->setBufferSizes(512, 512); -#endif + #endif if(SPIFFS.begin()) { char *ca = NULL; @@ -1140,33 +1127,33 @@ void MQTT_connect() { } if(Debug.isActive(RemoteDebug::INFO)) { - debugI("Connecting to MQTT %s:%d", config.getMqttHost(), config.getMqttPort()); + debugI("Connecting to MQTT %s:%d", mqttConfig.host, mqttConfig.port); } - mqtt.begin(config.getMqttHost(), config.getMqttPort(), *client); + mqtt.begin(mqttConfig.host, mqttConfig.port, *client); -#if defined(ESP8266) + #if defined(ESP8266) if(secureClient) { time_t epoch = time(nullptr); debugD("Setting NTP time %i for secure MQTT connection", epoch); secureClient->setX509Time(epoch); } -#endif + #endif // Connect to a unsecure or secure MQTT server - if ((strlen(config.getMqttUser()) == 0 && mqtt.connect(config.getMqttClientId())) || - (strlen(config.getMqttUser()) > 0 && mqtt.connect(config.getMqttClientId(), config.getMqttUser(), config.getMqttPassword()))) { + if ((strlen(mqttConfig.username) == 0 && mqtt.connect(mqttConfig.clientId)) || + (strlen(mqttConfig.username) > 0 && mqtt.connect(mqttConfig.clientId, mqttConfig.username, mqttConfig.password))) { if (Debug.isActive(RemoteDebug::INFO)) debugI("Successfully connected to MQTT!"); config.ackMqttChange(); // Subscribe to the chosen MQTT topic, if set in configuration - if (strlen(config.getMqttSubscribeTopic()) > 0) { - mqtt.subscribe(config.getMqttSubscribeTopic()); - if (Debug.isActive(RemoteDebug::INFO)) debugI(" Subscribing to [%s]\r\n", config.getMqttSubscribeTopic()); + if (strlen(mqttConfig.subscribeTopic) > 0) { + mqtt.subscribe(mqttConfig.subscribeTopic); + if (Debug.isActive(RemoteDebug::INFO)) debugI(" Subscribing to [%s]\r\n", mqttConfig.subscribeTopic); } - if(config.getMqttPayloadFormat() == 0) { + if(payloadFormat == 0) { sendMqttData("Connected!"); - } else if(config.getMqttPayloadFormat() == 1) { + } else if(payloadFormat == 1 || payloadFormat == 2) { sendSystemStatusToMqtt(); } } else { @@ -1174,8 +1161,8 @@ void MQTT_connect() { debugE("Failed to connect to MQTT"); #if defined(ESP8266) if(secureClient) { - char buf[256]; - secureClient->getLastSSLError(buf,256); + char buf[64]; + secureClient->getLastSSLError(buf,64); Debug.println(buf); } #endif @@ -1188,7 +1175,7 @@ void MQTT_connect() { void sendMqttData(String data) { // Make sure we have configured a publish topic - if (strlen(config.getMqttPublishTopic()) == 0) + if (topic.isEmpty()) return; // Build a json with the message in a "data" attribute @@ -1207,7 +1194,7 @@ void sendMqttData(String data) serializeJson(json, msg); // Send the json over MQTT - mqtt.publish(config.getMqttPublishTopic(), msg.c_str()); + mqtt.publish(topic, msg.c_str()); if (Debug.isActive(RemoteDebug::INFO)) debugI("Sending MQTT data"); if (Debug.isActive(RemoteDebug::DEBUG)) debugD("[%s]", data.c_str()); @@ -1215,20 +1202,20 @@ void sendMqttData(String data) unsigned long lastSystemDataSent = -10000; void sendSystemStatusToMqtt() { - if (strlen(config.getMqttPublishTopic()) == 0) + if (topic.isEmpty()) return; if(millis() - lastSystemDataSent < 10000) return; lastSystemDataSent = millis(); - mqtt.publish(String(config.getMqttPublishTopic()) + "/id", WiFi.macAddress()); - mqtt.publish(String(config.getMqttPublishTopic()) + "/uptime", String((unsigned long) millis64()/1000)); + mqtt.publish(topic + "/id", WiFi.macAddress()); + mqtt.publish(topic + "/uptime", String((unsigned long) millis64()/1000)); double vcc = hw.getVcc(); if(vcc > 0) { - mqtt.publish(String(config.getMqttPublishTopic()) + "/vcc", String(vcc, 2)); + mqtt.publish(topic + "/vcc", String(vcc, 2)); } - mqtt.publish(String(config.getMqttPublishTopic()) + "/rssi", String(hw.getWifiRssi())); + mqtt.publish(topic + "/rssi", String(hw.getWifiRssi())); if(hw.getTemperature() > -85) { - mqtt.publish(String(config.getMqttPublishTopic()) + "/temperature", String(hw.getTemperature(), 2)); + mqtt.publish(topic + "/temperature", String(hw.getTemperature(), 2)); } } diff --git a/src/HwTools.cpp b/src/HwTools.cpp index 94219145..67a0ae6b 100644 --- a/src/HwTools.cpp +++ b/src/HwTools.cpp @@ -1,56 +1,69 @@ #include "HwTools.h" -void HwTools::setTempSensorPin(int tempSensorPin) { - if(tempSensorPin != this->tempSensorPin) { - this->tempSensorInit = false; - if(sensorApi) - delete sensorApi; - if(oneWire) - delete oneWire; - if(tempSensorPin > 0 && tempSensorPin < 40) { - this->tempSensorPin = tempSensorPin; - pinMode(tempSensorPin, INPUT); - } else { - this->tempSensorPin = 0xFF; - } - } -} - -void HwTools::setTempAnalogSensorPin(int tempAnalogSensorPin) { - if(tempAnalogSensorPin != this->tempAnalogSensorPin) { - if(tempAnalogSensorPin > 0 && tempAnalogSensorPin < 40) { - this->tempAnalogSensorPin = tempAnalogSensorPin; - pinMode(tempAnalogSensorPin, INPUT); - } else { - this->tempAnalogSensorPin = 0xFF; - } - } -} - -void HwTools::setVccPin(int vccPin) { - if(vccPin > 0 && vccPin < 40) { - pinMode(vccPin, INPUT); - this->vccPin = vccPin; +void HwTools::setup(GpioConfig* config, AmsConfiguration* amsConf) { + this->config = config; + this->amsConf = amsConf; + this->tempSensorInit = false; + if(this->tempSensors == NULL) + this->tempSensors = new TempSensorData*[32]; + if(sensorApi != NULL) + delete sensorApi; + if(oneWire != NULL) + delete oneWire; + if(config->tempSensorPin > 0 && config->tempSensorPin < 40) { + pinMode(config->tempSensorPin, INPUT); } else { - this->vccPin = 0xFF; + config->tempSensorPin = 0xFF; } -} -void HwTools::setVccOffset(double vccOffset) { - this->vccOffset = vccOffset; -} + if(config->tempAnalogSensorPin > 0 && config->tempAnalogSensorPin < 40) { + pinMode(config->tempAnalogSensorPin, INPUT); + } else { + config->tempAnalogSensorPin = 0xFF; + } -void HwTools::setVccMultiplier(double vccMultiplier) { - this->vccMultiplier = vccMultiplier; + if(config->vccPin > 0 && config->vccPin < 40) { + pinMode(config->vccPin, INPUT); + } else { + config->vccPin = 0xFF; + } + + if(config->ledPin > 0 && config->ledPin < 40) { + pinMode(config->ledPin, OUTPUT); + ledOff(LED_INTERNAL); + } else { + config->ledPin = 0xFF; + } + + if(config->ledPinRed > 0 && config->ledPinRed < 40) { + pinMode(config->ledPinRed, OUTPUT); + ledOff(LED_RED); + } else { + config->ledPinRed = 0xFF; + } + + if(config->ledPinGreen > 0 && config->ledPinGreen < 40) { + pinMode(config->ledPinGreen, OUTPUT); + ledOff(LED_GREEN); + } else { + config->ledPinGreen = 0xFF; + } + + if(config->ledPinBlue > 0 && config->ledPinBlue < 40) { + pinMode(config->ledPinBlue, OUTPUT); + ledOff(LED_BLUE); + } else { + config->ledPinBlue = 0xFF; + } } double HwTools::getVcc() { double volts = 0.0; - if(vccPin != 0xFF) { + if(config->vccPin != 0xFF) { #if defined(ESP8266) - volts = (analogRead(vccPin) / 1024.0) * 3.3; + volts = (analogRead(config->vccPin) / 1024.0) * 3.3; #elif defined(ESP32) - volts = (analogRead(vccPin) / 4095.0) * 3.3; + volts = (analogRead(config->vccPin) / 4095.0) * 3.3; #endif } else { #if defined(ESP8266) @@ -58,31 +71,11 @@ double HwTools::getVcc() { #endif } + float vccOffset = config->vccOffset / 100.0; + float vccMultiplier = config->vccMultiplier / 1000.0; return vccOffset + (volts > 0.0 ? volts * vccMultiplier : 0.0); } -void HwTools::confTempSensor(uint8_t address[8], const char name[32], bool common) { - bool found = false; - for(int x = 0; x < sensorCount; x++) { - TempSensorData *data = tempSensors[x]; - if(isSensorAddressEqual(data->address, address)) { - found = true; - strcpy(data->name, name); - data->common = common; - } - } - if(!found) { - TempSensorData *data = new TempSensorData(); - memcpy(data->address, address, 8); - strcpy(data->name, name); - data->common = common; - data->lastRead = DEVICE_DISCONNECTED_C; - data->lastValidRead = DEVICE_DISCONNECTED_C; - tempSensors[sensorCount] = data; - sensorCount++; - } -} - uint8_t HwTools::getTempSensorCount() { return sensorCount; } @@ -92,9 +85,9 @@ TempSensorData* HwTools::getTempSensorData(uint8_t i) { } bool HwTools::updateTemperatures() { - if(tempSensorPin != 0xFF) { + if(config->tempSensorPin != 0xFF) { if(!tempSensorInit) { - oneWire = new OneWire(tempSensorPin); + oneWire = new OneWire(config->tempSensorPin); sensorApi = new DallasTemperature(this->oneWire); sensorApi->begin(); delay(100); @@ -120,14 +113,12 @@ bool HwTools::updateTemperatures() { if(!found) { TempSensorData *data = new TempSensorData(); memcpy(data->address, addr, 8); - data->common = true; data->lastRead = t; if(t > -85) { data->lastValidRead = t; } - tempSensors[sensorCount] = data; - sensorCount++; + tempSensors[sensorCount++] = data; } delay(10); } @@ -166,7 +157,8 @@ double HwTools::getTemperature() { } for(int x = 0; x < sensorCount; x++) { TempSensorData data = *tempSensors[x]; - if(data.common && data.lastValidRead > -85) { + TempSensorConfig* conf = amsConf->getTempSensorConfig(data.address); + if((conf == NULL || conf->common) && data.lastValidRead > -85) { ret += data.lastValidRead; c++; } @@ -174,13 +166,13 @@ double HwTools::getTemperature() { return c == 0 ? DEVICE_DISCONNECTED_C : ret/c; } double HwTools::getTemperatureAnalog() { - if(tempAnalogSensorPin != 0xFF) { + if(config->tempAnalogSensorPin != 0xFF) { float adcCalibrationFactor = 1.06587; int volts; #if defined(ESP8266) - volts = (analogRead(tempAnalogSensorPin) / 1024.0) * 3.3; + volts = (analogRead(config->tempAnalogSensorPin) / 1024.0) * 3.3; #elif defined(ESP32) - volts = (analogRead(tempAnalogSensorPin) / 4095.0) * 3.3; + volts = (analogRead(config->tempAnalogSensorPin) / 4095.0) * 3.3; #endif return ((volts * adcCalibrationFactor) - 0.4) / 0.0195; } @@ -192,55 +184,19 @@ int HwTools::getWifiRssi() { return isnan(rssi) ? -100.0 : rssi; } -void HwTools::setLed(uint8_t ledPin, bool ledInverted) { - if(ledPin > 0 && ledPin < 40) { - this->ledPin = ledPin; - this->ledInverted = ledInverted; - pinMode(ledPin, OUTPUT); - ledOff(LED_INTERNAL); - } else { - this->ledPin = 0xFF; - } -} - -void HwTools::setLedRgb(uint8_t ledPinRed, uint8_t ledPinGreen, uint8_t ledPinBlue, bool ledRgbInverted) { - this->ledRgbInverted = ledRgbInverted; - if(ledPinRed > 0 && ledPinRed < 40) { - this->ledPinRed = ledPinRed; - pinMode(ledPinRed, OUTPUT); - ledOff(LED_RED); - } else { - this->ledPinRed = 0xFF; - } - if(ledPinGreen > 0 && ledPinGreen < 40) { - this->ledPinGreen = ledPinGreen; - pinMode(ledPinGreen, OUTPUT); - ledOff(LED_GREEN); - } else { - this->ledPinGreen = 0xFF; - } - if(ledPinBlue > 0 && ledPinBlue < 40) { - this->ledPinBlue = ledPinBlue; - pinMode(ledPinBlue, OUTPUT); - ledOff(LED_BLUE); - } else { - this->ledPinBlue = 0xFF; - } -} - bool HwTools::ledOn(uint8_t color) { if(color == LED_INTERNAL) { - return writeLedPin(color, ledInverted ? LOW : HIGH); + return writeLedPin(color, config->ledInverted ? LOW : HIGH); } else { - return writeLedPin(color, ledRgbInverted ? LOW : HIGH); + return writeLedPin(color, config->ledRgbInverted ? LOW : HIGH); } } bool HwTools::ledOff(uint8_t color) { if(color == LED_INTERNAL) { - return writeLedPin(color, ledInverted ? HIGH : LOW); + return writeLedPin(color, config->ledInverted ? HIGH : LOW); } else { - return writeLedPin(color, ledRgbInverted ? HIGH : LOW); + return writeLedPin(color, config->ledRgbInverted ? HIGH : LOW); } } @@ -256,47 +212,52 @@ bool HwTools::ledBlink(uint8_t color, uint8_t blink) { bool HwTools::writeLedPin(uint8_t color, uint8_t state) { switch(color) { - case LED_INTERNAL: - if(ledPin != 0xFF) { - digitalWrite(ledPin, state); + case LED_INTERNAL: { + if(config->ledPin != 0xFF) { + digitalWrite(config->ledPin, state); return true; } else { return false; } break; - case LED_RED: - if(ledPinRed != 0xFF) { - digitalWrite(ledPinRed, state); + } + case LED_RED: { + if(config->ledPinRed != 0xFF) { + digitalWrite(config->ledPinRed, state); return true; } else { return false; } break; - case LED_GREEN: - if(ledPinGreen != 0xFF) { - digitalWrite(ledPinGreen, state); + } + case LED_GREEN: { + if(config->ledPinGreen != 0xFF) { + digitalWrite(config->ledPinGreen, state); return true; } else { return false; } break; - case LED_BLUE: - if(ledPinBlue != 0xFF) { - digitalWrite(ledPinBlue, state); + } + case LED_BLUE: { + if(config->ledPinBlue != 0xFF) { + digitalWrite(config->ledPinBlue, state); return true; } else { return false; } break; - case LED_YELLOW: - if(ledPinRed != 0xFF && ledPinGreen != 0xFF) { - digitalWrite(ledPinRed, state); - digitalWrite(ledPinGreen, state); + } + case LED_YELLOW: { + if(config->ledPinRed != 0xFF && config->ledPinGreen != 0xFF) { + digitalWrite(config->ledPinRed, state); + digitalWrite(config->ledPinGreen, state); return true; } else { return false; } break; + } } return false; } diff --git a/src/HwTools.h b/src/HwTools.h index d414cbff..7976b06b 100644 --- a/src/HwTools.h +++ b/src/HwTools.h @@ -11,6 +11,7 @@ #include #include +#include "AmsConfiguration.h" #define LED_INTERNAL 0 #define LED_RED 1 @@ -20,48 +21,34 @@ struct TempSensorData { uint8_t address[8]; - char name[32]; - bool common; float lastRead; float lastValidRead; }; class HwTools { public: - void setTempSensorPin(int tempSensorPin); - void setTempAnalogSensorPin(int tempAnalogSensorPin); - void setVccPin(int vccPin); - void setVccOffset(double vccOffset); - void setVccMultiplier(double vccMultiplier); + void setup(GpioConfig*, AmsConfiguration*); double getVcc(); - void confTempSensor(uint8_t address[8], const char name[32], bool common); uint8_t getTempSensorCount(); - TempSensorData* getTempSensorData(uint8_t i); + TempSensorData* getTempSensorData(uint8_t); bool updateTemperatures(); double getTemperature(); double getTemperatureAnalog(); double getTemperature(uint8_t address[8]); int getWifiRssi(); - void setLed(uint8_t ledPin, bool ledInverted); - void setLedRgb(uint8_t ledPinRed, uint8_t ledPinGreen, uint8_t ledPinBlue, bool ledRgbInverted); bool ledOn(uint8_t color); bool ledOff(uint8_t color); bool ledBlink(uint8_t color, uint8_t blink); HwTools() {}; private: - uint8_t tempSensorPin = 0xFF, tempAnalogSensorPin = 0xFF; - uint8_t vccPin = 0xFF; - uint8_t ledPin = 0xFF, ledPinRed = 0xFF, ledPinGreen = 0xFF, ledPinBlue = 0xFF; - bool ledInverted, ledRgbInverted; - double vccOffset = 0.0; - double vccMultiplier = 1.0; - + GpioConfig* config; + AmsConfiguration* amsConf; bool tempSensorInit; - OneWire *oneWire; - DallasTemperature *sensorApi; + OneWire *oneWire = NULL; + DallasTemperature *sensorApi = NULL; uint8_t sensorCount = 0; - TempSensorData *tempSensors[32]; + TempSensorData** tempSensors = NULL; bool writeLedPin(uint8_t color, uint8_t state); bool isSensorAddressEqual(uint8_t a[8], uint8_t b[8]); diff --git a/src/entsoe/DnbCurrParser.cpp b/src/entsoe/DnbCurrParser.cpp index 52e6c738..c2f45bbf 100644 --- a/src/entsoe/DnbCurrParser.cpp +++ b/src/entsoe/DnbCurrParser.cpp @@ -1,7 +1,7 @@ #include "DnbCurrParser.h" #include "HardwareSerial.h" -double DnbCurrParser::getValue() { +float DnbCurrParser::getValue() { return value; } @@ -49,7 +49,7 @@ size_t DnbCurrParser::write(uint8_t byte) { break; } } - value = String(buf+pos).toDouble(); + value = String(buf+pos).toFloat(); } pos = 0; } else { diff --git a/src/entsoe/DnbCurrParser.h b/src/entsoe/DnbCurrParser.h index 99ff1e93..cb6002a3 100644 --- a/src/entsoe/DnbCurrParser.h +++ b/src/entsoe/DnbCurrParser.h @@ -5,7 +5,7 @@ class DnbCurrParser: public Stream { public: - double getValue(); + float getValue(); int available(); int read(); @@ -15,9 +15,9 @@ public: size_t write(uint8_t); private: - double value = 1.0; + float value = 1.0; - char buf[256]; + char buf[64]; uint8_t pos = 0; uint8_t mode = 0; }; diff --git a/src/entsoe/EntsoeA44Parser.cpp b/src/entsoe/EntsoeA44Parser.cpp index ea8e4ac3..7a211e3f 100644 --- a/src/entsoe/EntsoeA44Parser.cpp +++ b/src/entsoe/EntsoeA44Parser.cpp @@ -13,7 +13,7 @@ char* EntsoeA44Parser::getMeasurementUnit() { return measurementUnit; } -double EntsoeA44Parser::getPoint(uint8_t position) { +float EntsoeA44Parser::getPoint(uint8_t position) { return points[position]; } @@ -69,7 +69,7 @@ size_t EntsoeA44Parser::write(uint8_t byte) { } else if(docPos == DOCPOS_AMOUNT) { if(byte == '<') { buf[pos] = '\0'; - points[pointNum] = String(buf).toDouble(); + points[pointNum] = String(buf).toFloat(); docPos = DOCPOS_SEEK; pos = 0; } else { diff --git a/src/entsoe/EntsoeA44Parser.h b/src/entsoe/EntsoeA44Parser.h index 30804f0b..28750896 100644 --- a/src/entsoe/EntsoeA44Parser.h +++ b/src/entsoe/EntsoeA44Parser.h @@ -15,7 +15,7 @@ public: char* getCurrency(); char* getMeasurementUnit(); - double getPoint(uint8_t position); + float getPoint(uint8_t position); int available(); int read(); @@ -27,9 +27,9 @@ public: private: char currency[4]; char measurementUnit[4]; - double points[24]; + float points[24]; - char buf[256]; + char buf[64]; uint8_t pos = 0; uint8_t docPos = 0; uint8_t pointNum = 0; diff --git a/src/entsoe/EntsoeApi.cpp b/src/entsoe/EntsoeApi.cpp index 1fd346d8..c3b29808 100644 --- a/src/entsoe/EntsoeApi.cpp +++ b/src/entsoe/EntsoeApi.cpp @@ -21,31 +21,23 @@ EntsoeApi::EntsoeApi(RemoteDebug* Debug) { tz = new Timezone(CEST, CET); } -void EntsoeApi::setToken(const char* token) { - strcpy(this->token, token); +void EntsoeApi::setup(EntsoeConfig& config) { + if(this->config == NULL) { + this->config = new EntsoeConfig(); + } + memcpy(this->config, &config, sizeof(config)); } -void EntsoeApi::setArea(const char* area) { - strcpy(this->area, area); +char* EntsoeApi::getToken() { + return this->config->token; } -void EntsoeApi::setCurrency(const char* currency) { - strcpy(this->currency, currency); -} - -void EntsoeApi::setMultiplier(double multiplier) { - this->multiplier = multiplier; -} - -char* EntsoeApi::getCurrency() { - return currency; -} -double EntsoeApi::getValueForHour(int hour) { +float EntsoeApi::getValueForHour(uint8_t hour) { time_t cur = time(nullptr); return getValueForHour(cur, hour); } -double EntsoeApi::getValueForHour(time_t cur, int hour) { +float EntsoeApi::getValueForHour(time_t cur, uint8_t hour) { tmElements_t tm; if(tz != NULL) cur = tz->toLocal(cur); @@ -55,7 +47,7 @@ double EntsoeApi::getValueForHour(time_t cur, int hour) { return ENTSOE_NO_VALUE; double value = ENTSOE_NO_VALUE; - double multiplier = this->multiplier; + double multiplier = config->multiplier / 1000.0; if(pos > 23) { if(tomorrow == NULL) return ENTSOE_NO_VALUE; @@ -65,7 +57,7 @@ double EntsoeApi::getValueForHour(time_t cur, int hour) { } else { return ENTSOE_NO_VALUE; } - multiplier *= getCurrencyMultiplier(tomorrow->getCurrency(), currency); + multiplier *= getCurrencyMultiplier(tomorrow->getCurrency(), config->currency); } else { if(today == NULL) return ENTSOE_NO_VALUE; @@ -75,13 +67,13 @@ double EntsoeApi::getValueForHour(time_t cur, int hour) { } else { return ENTSOE_NO_VALUE; } - multiplier *= getCurrencyMultiplier(today->getCurrency(), currency); + multiplier *= getCurrencyMultiplier(today->getCurrency(), config->currency); } return value * multiplier; } bool EntsoeApi::loop() { - if(strlen(token) == 0) + if(strlen(config->token) == 0) return false; bool ret = false; @@ -116,10 +108,10 @@ bool EntsoeApi::loop() { char url[256]; snprintf(url, sizeof(url), "%s?securityToken=%s&documentType=A44&periodStart=%04d%02d%02d%02d%02d&periodEnd=%04d%02d%02d%02d%02d&in_Domain=%s&out_Domain=%s", - "https://transparency.entsoe.eu/api", token, + "https://transparency.entsoe.eu/api", config->token, d1.Year+1970, d1.Month, d1.Day, 23, 00, d2.Year+1970, d2.Month, d2.Day, 23, 00, - area, area); + config->area, config->area); printD("Fetching prices for today"); printD(url); @@ -146,10 +138,10 @@ bool EntsoeApi::loop() { char url[256]; snprintf(url, sizeof(url), "%s?securityToken=%s&documentType=A44&periodStart=%04d%02d%02d%02d%02d&periodEnd=%04d%02d%02d%02d%02d&in_Domain=%s&out_Domain=%s", - "https://transparency.entsoe.eu/api", token, + "https://transparency.entsoe.eu/api", config->token, d1.Year+1970, d1.Month, d1.Day, 23, 00, d2.Year+1970, d2.Month, d2.Day, 23, 00, - area, area); + config->area, config->area); printD("Fetching prices for tomorrow"); printD(url); @@ -169,8 +161,9 @@ bool EntsoeApi::loop() { bool EntsoeApi::retrieve(const char* url, Stream* doc) { WiFiClientSecure client; #if defined(ESP8266) - client.setBufferSizes(512, 512); + client.setBufferSizes(SSL_BUF_SIZE, SSL_BUF_SIZE); client.setInsecure(); + client.setX509Time(time(nullptr)); #endif HTTPClient https; @@ -191,8 +184,8 @@ bool EntsoeApi::retrieve(const char* url, Stream* doc) { printD(https.getString()); #if defined(ESP8266) - char buf[256]; - client.getLastSSLError(buf,256); + char buf[64]; + client.getLastSSLError(buf,64); printE(buf); #endif @@ -201,53 +194,32 @@ bool EntsoeApi::retrieve(const char* url, Stream* doc) { } } else { #if defined(ESP8266) - char buf[256]; - client.getLastSSLError(buf,256); + char buf[64]; + client.getLastSSLError(buf,64); printE(buf); #endif return false; } + client.stop(); } -double EntsoeApi::getCurrencyMultiplier(const char* from, const char* to) { +float EntsoeApi::getCurrencyMultiplier(const char* from, const char* to) { if(strcmp(from, to) == 0) return 1.00; uint64_t now = millis64(); if(lastCurrencyFetch == 0 || now - lastCurrencyFetch > (SECS_PER_HOUR * 1000)) { - WiFiClientSecure client; - #if defined(ESP8266) - client.setBufferSizes(512, 512); - client.setInsecure(); - #endif - HTTPClient https; - #if defined(ESP8266) - https.setFollowRedirects(true); - #endif - char url[256]; snprintf(url, sizeof(url), "https://data.norges-bank.no/api/data/EXR/M.%s.%s.SP?lastNObservations=1", from, to ); - if(https.begin(client, url)) { - int status = https.GET(); - if(status == HTTP_CODE_OK) { - DnbCurrParser p; - https.writeToStream(&p); - currencyMultiplier = p.getValue(); - } else { - printE("Communication error: "); - printE(https.errorToString(status)); - printI(url); - printD(https.getString()); - } - lastCurrencyFetch = now; - https.end(); - } else { - return false; + DnbCurrParser p; + if(retrieve(url, &p)) { + currencyMultiplier = p.getValue(); } + lastCurrencyFetch = now; } return currencyMultiplier; } diff --git a/src/entsoe/EntsoeApi.h b/src/entsoe/EntsoeApi.h index 54f9a38e..3744f649 100644 --- a/src/entsoe/EntsoeApi.h +++ b/src/entsoe/EntsoeApi.h @@ -5,27 +5,25 @@ #include "Timezone.h" #include "RemoteDebug.h" #include "EntsoeA44Parser.h" +#include "AmsConfiguration.h" #define ENTSOE_NO_VALUE -127 #define ENTSOE_DEFAULT_MULTIPLIER 1.00 +#define SSL_BUF_SIZE 512 class EntsoeApi { public: - EntsoeApi(RemoteDebug* Debug); + EntsoeApi(RemoteDebug*); + void setup(EntsoeConfig&); bool loop(); - double getValueForHour(int hour); - double getValueForHour(time_t now, int hour); - char* getCurrency(); - - void setToken(const char* token); - void setArea(const char* area); - void setCurrency(const char* currency); - void setMultiplier(double multiplier); + char* getToken(); + float getValueForHour(uint8_t); + float getValueForHour(time_t, uint8_t); private: RemoteDebug* debugger; - char token[37]; // UUID + null terminator + EntsoeConfig* config = NULL; uint64_t midnightMillis = 0; uint64_t lastTodayFetch = 0; @@ -36,13 +34,10 @@ private: Timezone* tz = NULL; - char area[32]; - char currency[4]; - double multiplier = ENTSOE_DEFAULT_MULTIPLIER; - double currencyMultiplier = ENTSOE_DEFAULT_MULTIPLIER; + float currencyMultiplier = ENTSOE_DEFAULT_MULTIPLIER; bool retrieve(const char* url, Stream* doc); - double getCurrencyMultiplier(const char* from, const char* to); + float getCurrencyMultiplier(const char* from, const char* to); void printD(String fmt, ...); void printI(String fmt, ...); diff --git a/src/web/AmsWebServer.cpp b/src/web/AmsWebServer.cpp index 6811726a..03cd4829 100644 --- a/src/web/AmsWebServer.cpp +++ b/src/web/AmsWebServer.cpp @@ -36,8 +36,11 @@ AmsWebServer::AmsWebServer(RemoteDebug* Debug, HwTools* hw, EntsoeApi* eapi) { this->eapi = eapi; } -void AmsWebServer::setup(AmsConfiguration* config, MQTTClient* mqtt) { +void AmsWebServer::setup(AmsConfiguration* config, GpioConfig* gpioConfig, MeterConfig* meterConfig, AmsData* meterState, MQTTClient* mqtt) { this->config = config; + this->gpioConfig = gpioConfig; + this->meterConfig = meterConfig; + this->meterState = meterState; this->mqtt = mqtt; server.on("/", HTTP_GET, std::bind(&AmsWebServer::indexHtml, this)); @@ -83,39 +86,37 @@ void AmsWebServer::setup(AmsConfiguration* config, MQTTClient* mqtt) { server.on("/reset", HTTP_POST, std::bind(&AmsWebServer::factoryResetPost, this)); server.onNotFound(std::bind(&AmsWebServer::notFound, this)); - - TimeChangeRule STD = {"STD", Last, Sun, Oct, 3, config->getNtpOffset() / 60}; - TimeChangeRule DST = {"DST", Last, Sun, Mar, 2, (config->getNtpOffset() + config->getNtpSummerOffset()) / 60}; - tz = new Timezone(DST, STD); server.begin(); // Web server start + + config->getWebConfig(webConfig); + MqttConfig mqttConfig; + config->getMqttConfig(mqttConfig); + mqttEnabled = strlen(mqttConfig.host) > 0; +} + +void AmsWebServer::setTimezone(Timezone* tz) { + this->tz = tz; } void AmsWebServer::loop() { server.handleClient(); -} - -void AmsWebServer::setData(AmsData& data) { - millis64(); // Make sure it catch all those rollovers - - this->data.apply(data); - - if(maxPwr == 0 && data.getListType() > 1 && config->hasConfig() && config->getMainFuse() > 0 && config->getDistributionSystem() > 0) { - int volt = config->getDistributionSystem() == 2 ? 400 : 230; - if(data.isThreePhase()) { - maxPwr = config->getMainFuse() * sqrt(3) * volt; + if(maxPwr == 0 && meterState->getListType() > 1 && meterConfig->mainFuse > 0 && meterConfig->distributionSystem > 0) { + if(meterState->isThreePhase()) { + int voltage = meterConfig->distributionSystem == 2 ? 400 : 230; + maxPwr = meterConfig->mainFuse * sqrt(3) * voltage; } else { - maxPwr = config->getMainFuse() * 230; + maxPwr = meterConfig->mainFuse * 230; } } } bool AmsWebServer::checkSecurity(byte level) { - bool access = WiFi.getMode() == WIFI_AP || !config->hasConfig() || config->getAuthSecurity() < level; - if(!access && config->getAuthSecurity() >= level && server.hasHeader("Authorization")) { + bool access = WiFi.getMode() == WIFI_AP || webConfig.security < level; + if(!access && webConfig.security >= level && server.hasHeader("Authorization")) { printD(" forcing web security"); - String expectedAuth = String(config->getAuthUser()) + ":" + String(config->getAuthPassword()); + String expectedAuth = String(webConfig.username) + ":" + String(webConfig.password); String providedPwd = server.header("Authorization"); providedPwd.replace("Basic ", ""); @@ -176,13 +177,6 @@ void AmsWebServer::temperaturePost() { printD("Successfully saved temperature sensors"); server.sendHeader("Location", String("/temperature"), true); server.send (302, "text/plain", ""); - - uint8_t c = config->getTempSensorCount(); - for(int i = 0; i < c; i++) { - TempSensorConfig* tsc = config->getTempSensorConfig(i); - hw->confTempSensor(tsc->address, tsc->name, tsc->common); - delay(1); - } } } @@ -199,12 +193,13 @@ void AmsWebServer::temperatureJson() { JsonArray sensors = json.createNestedArray("s"); for(int i = 0; i < count; i++) { TempSensorData* data = hw->getTempSensorData(i); + TempSensorConfig* conf = config->getTempSensorConfig(data->address); JsonObject obj = sensors.createNestedObject(); obj["i"] = i; obj["a"] = toHex(data->address, 8); - obj["n"] = String(data->name).substring(0,16); + obj["n"] = conf == NULL ? "" : String(conf->name).substring(0,16); + obj["c"] = conf == NULL ? true : conf->common; obj["v"] = String(data->lastRead, 2); - obj["c"] = data->common; delay(1); } @@ -259,22 +254,28 @@ void AmsWebServer::indexHtml() { server.sendHeader("Expires", "-1"); if(WiFi.getMode() == WIFI_AP) { + SystemConfig sys; + config->getSystemConfig(sys); + + WiFiConfig wifi; + config->clearWifi(wifi); + String html = String((const __FlashStringHelper*) SETUP_HTML); for(int i = 0; i<255; i++) { - html.replace("${config.boardType" + String(i) + "}", config->getBoardType() == i ? "selected" : ""); + html.replace("${config.boardType" + String(i) + "}", sys.boardType == i ? "selected" : ""); } for(int i = 0; i<5; i++) { - html.replace("${config.meterType" + String(i) + "}", config->getMeterType() == i ? "selected" : ""); + html.replace("${config.meterType" + String(i) + "}", sys.boardType == i ? "selected" : ""); } - html.replace("${config.wifiSsid}", config->getWifiSsid()); - html.replace("${config.wifiPassword}", config->getWifiPassword()); - html.replace("${config.wifiStaticIp}", strlen(config->getWifiIp()) > 0 ? "checked" : ""); - html.replace("${config.wifiIp}", config->getWifiIp()); - html.replace("${config.wifiGw}", config->getWifiGw()); - html.replace("${config.wifiSubnet}", config->getWifiSubnet()); - html.replace("${config.wifiDns1}", config->getWifiDns1()); - html.replace("${config.wifiDns2}", config->getWifiDns2()); - html.replace("${config.wifiHostname}", config->getWifiHostname()); + html.replace("${config.wifiSsid}", wifi.ssid); + html.replace("${config.wifiPassword}", wifi.psk); + html.replace("${config.wifiStaticIp}", strlen(wifi.ip) > 0 ? "checked" : ""); + html.replace("${config.wifiIp}", wifi.ip); + html.replace("${config.wifiGw}", wifi.gateway); + html.replace("${config.wifiSubnet}", wifi.subnet); + html.replace("${config.wifiDns1}", wifi.dns1); + html.replace("${config.wifiDns2}", wifi.dns2); + html.replace("${config.wifiHostname}", wifi.hostname); server.send(200, "text/html", html); } else { if(!checkSecurity(2)) @@ -282,23 +283,23 @@ void AmsWebServer::indexHtml() { String html = String((const __FlashStringHelper*) INDEX_HTML); - double u1 = data.getL1Voltage(); - double u2 = data.getL2Voltage(); - double u3 = data.getL3Voltage(); - double i1 = data.getL1Current(); - double i2 = data.getL2Current(); - double i3 = data.getL3Current(); - double tpi = data.getActiveImportCounter(); - double tpo = data.getActiveExportCounter(); - double tqi = data.getReactiveImportCounter(); - double tqo = data.getReactiveExportCounter(); + double u1 = meterState->getL1Voltage(); + double u2 = meterState->getL2Voltage(); + double u3 = meterState->getL3Voltage(); + double i1 = meterState->getL1Current(); + double i2 = meterState->getL2Current(); + double i3 = meterState->getL3Current(); + double tpi = meterState->getActiveImportCounter(); + double tpo = meterState->getActiveExportCounter(); + double tqi = meterState->getReactiveImportCounter(); + double tqo = meterState->getReactiveExportCounter(); - html.replace("{P}", String(data.getActiveImportPower())); - html.replace("{PO}", String(data.getActiveExportPower())); - html.replace("{de}", config->getProductionCapacity() > 0 ? "" : "none"); - html.replace("{dn}", config->getProductionCapacity() > 0 ? "none" : ""); - html.replace("{ti}", config->getProductionCapacity() > 0 ? "Import" : "Use"); - html.replace("{3p}", data.isThreePhase() ? "" : "none"); + html.replace("{P}", String(meterState->getActiveImportPower())); + html.replace("{PO}", String(meterState->getActiveExportPower())); + html.replace("{de}", meterConfig->productionCapacity > 0 ? "" : "none"); + html.replace("{dn}", meterConfig->productionCapacity > 0 ? "none" : ""); + html.replace("{ti}", meterConfig->productionCapacity > 0 ? "Import" : "Use"); + html.replace("{3p}", meterState->isThreePhase() ? "" : "none"); html.replace("{U1}", u1 > 0 ? String(u1, 1) : ""); html.replace("{I1}", u1 > 0 ? String(i1, 1) : ""); @@ -351,35 +352,35 @@ void AmsWebServer::configMeterHtml() { server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server.sendHeader("Pragma", "no-cache"); - html.replace("{m}", String(config->getMainFuse())); + html.replace("{m}", String(meterConfig->mainFuse)); for(int i = 0; i<5; i++) { - html.replace("{m" + String(i) + "}", config->getMeterType() == i ? "selected" : ""); + html.replace("{m" + String(i) + "}", meterConfig->type == i ? "selected" : ""); } - html.replace("{d}", String(config->getDistributionSystem())); + html.replace("{d}", String(meterConfig->distributionSystem)); for(int i = 0; i<3; i++) { - html.replace("{d" + String(i) + "}", config->getDistributionSystem() == i ? "selected" : ""); + html.replace("{d" + String(i) + "}", meterConfig->distributionSystem == i ? "selected" : ""); } - html.replace("{f}", String(config->getMainFuse())); + html.replace("{f}", String(meterConfig->mainFuse)); for(int i = 0; i<64; i++) { - html.replace("{f" + String(i) + "}", config->getMainFuse() == i ? "selected" : ""); + html.replace("{f" + String(i) + "}", meterConfig->mainFuse == i ? "selected" : ""); } - html.replace("{p}", String(config->getProductionCapacity())); + html.replace("{p}", String(meterConfig->productionCapacity)); - if(config->getMeterType() == METER_TYPE_OMNIPOWER) { + if(meterConfig->type == METER_TYPE_OMNIPOWER) { String encryptionKeyHex = "0x"; - encryptionKeyHex += toHex(config->getMeterEncryptionKey(), 16); + encryptionKeyHex += toHex(meterConfig->encryptionKey, 16); html.replace("{e}", encryptionKeyHex); String authenticationKeyHex = "0x"; - authenticationKeyHex += toHex(config->getMeterAuthenticationKey(), 16); + authenticationKeyHex += toHex(meterConfig->authenticationKey, 16); html.replace("{a}", authenticationKeyHex); } else { html.replace("{e}", ""); html.replace("{a}", ""); } - html.replace("{s}", config->isSubstituteMissing() ? "checked" : ""); - html.replace("{u}", config->isSendUnknown() ? "checked" : ""); + html.replace("{s}", meterConfig->substituteMissing ? "checked" : ""); + html.replace("{u}", meterConfig->sendUnknown ? "checked" : ""); server.setContentLength(html.length() + HEAD_HTML_LEN + FOOT_HTML_LEN); server.send_P(200, "text/html", HEAD_HTML); @@ -416,16 +417,19 @@ void AmsWebServer::configWifiHtml() { server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server.sendHeader("Pragma", "no-cache"); - html.replace("{s}", config->getWifiSsid()); - html.replace("{p}", config->getWifiPassword()); - html.replace("{st}", strlen(config->getWifiIp()) > 0 ? "checked" : ""); - html.replace("{i}", config->getWifiIp()); - html.replace("{g}", config->getWifiGw()); - html.replace("{sn}", config->getWifiSubnet()); - html.replace("{d1}", config->getWifiDns1()); - html.replace("{d2}", config->getWifiDns2()); - html.replace("{h}", config->getWifiHostname()); - html.replace("{m}", config->isMdnsEnable() ? "checked" : ""); + WiFiConfig wifi; + config->getWiFiConfig(wifi); + + html.replace("{s}", wifi.ssid); + html.replace("{p}", wifi.psk); + html.replace("{st}", strlen(wifi.ip) > 0 ? "checked" : ""); + html.replace("{i}", wifi.ip); + html.replace("{g}", wifi.gateway); + html.replace("{sn}", wifi.subnet); + html.replace("{d1}", wifi.dns1); + html.replace("{d2}", wifi.dns2); + html.replace("{h}", wifi.hostname); + html.replace("{m}", wifi.mdns ? "checked" : ""); server.setContentLength(html.length() + HEAD_HTML_LEN + FOOT_HTML_LEN); server.send_P(200, "text/html", HEAD_HTML); @@ -444,24 +448,27 @@ void AmsWebServer::configMqttHtml() { server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server.sendHeader("Pragma", "no-cache"); - html.replace("{m}", strlen(config->getMqttHost()) == 0 ? "" : "checked"); - html.replace("{h}", config->getMqttHost()); - if(config->getMqttPort() > 0) { - html.replace("{p}", String(config->getMqttPort())); + MqttConfig mqtt; + config->getMqttConfig(mqtt); + + html.replace("{m}", strlen(mqtt.host) == 0 ? "" : "checked"); + html.replace("{h}", mqtt.host); + if(mqtt.port > 0) { + html.replace("{p}", String(mqtt.port)); } else { html.replace("{p}", String(1883)); } - html.replace("{i}", config->getMqttClientId()); - html.replace("{t}", config->getMqttPublishTopic()); - html.replace("{st}", config->getMqttSubscribeTopic()); - html.replace("{u}", config->getMqttUser()); - html.replace("{pw}", config->getMqttPassword()); - html.replace("{f}", String(config->getMqttPayloadFormat())); + html.replace("{i}", mqtt.clientId); + html.replace("{t}", mqtt.publishTopic); + html.replace("{st}", mqtt.subscribeTopic); + html.replace("{u}", mqtt.username); + html.replace("{pw}", mqtt.password); + html.replace("{f}", String(mqtt.payloadFormat)); for(int i = 0; i<4; i++) { - html.replace("{f" + String(i) + "}", config->getMqttPayloadFormat() == i ? "selected" : ""); + html.replace("{f" + String(i) + "}", mqtt.payloadFormat == i ? "selected" : ""); } - html.replace("{s}", config->isMqttSsl() ? "checked" : ""); + html.replace("{s}", mqtt.ssl ? "checked" : ""); if(SPIFFS.begin()) { html.replace("{dcu}", SPIFFS.exists(FILE_MQTT_CA) ? "none" : ""); @@ -497,16 +504,14 @@ void AmsWebServer::configDomoticzHtml() { server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server.sendHeader("Pragma", "no-cache"); - if(config->getDomoELIDX() > 0){ html.replace("{elidx}", String(config->getDomoELIDX())); - } else { html.replace("{elidx}", ""); } - if(config->getDomoVL1IDX() > 0){ html.replace("{vl1idx}", String(config->getDomoVL1IDX())); - } else { html.replace("{vl1idx}", ""); } - if(config->getDomoVL2IDX() > 0){ html.replace("{vl2idx}", String(config->getDomoVL2IDX())); - } else { html.replace("{vl2idx}", ""); } - if(config->getDomoVL3IDX() > 0){ html.replace("{vl3idx}", String(config->getDomoVL3IDX())); - } else { html.replace("{vl3idx}", ""); } - if(config->getDomoCL1IDX() > 0){ html.replace("{cl1idx}", String(config->getDomoCL1IDX())); - } else { html.replace("{cl1idx}", ""); } + DomoticzConfig domo; + config->getDomoticzConfig(domo); + + html.replace("{elidx}", domo.elidx ? String(domo.elidx, 10) : ""); + html.replace("{vl1idx}", domo.vl1idx ? String(domo.vl1idx, 10) : ""); + html.replace("{vl2idx}", domo.vl2idx ? String(domo.vl2idx, 10) : ""); + html.replace("{vl3idx}", domo.vl3idx ? String(domo.vl3idx, 10) : ""); + html.replace("{cl1idx}", domo.cl1idx ? String(domo.cl1idx, 10) : ""); server.setContentLength(html.length() + HEAD_HTML_LEN + FOOT_HTML_LEN); server.send_P(200, "text/html", HEAD_HTML); @@ -522,27 +527,30 @@ void AmsWebServer::configEntsoeHtml() { String html = String((const __FlashStringHelper*) ENTSOE_HTML); - html.replace("{et}", config->getEntsoeApiToken()); - html.replace("{em}", String(config->getEntsoeApiMultiplier(), 3)); + EntsoeConfig entsoe; + config->getEntsoeConfig(entsoe); - html.replace("{eaNo1}", strcmp(config->getEntsoeApiArea(), "10YNO-1--------2") == 0 ? "selected" : ""); - html.replace("{eaNo2}", strcmp(config->getEntsoeApiArea(), "10YNO-2--------T") == 0 ? "selected" : ""); - html.replace("{eaNo3}", strcmp(config->getEntsoeApiArea(), "10YNO-3--------J") == 0 ? "selected" : ""); - html.replace("{eaNo4}", strcmp(config->getEntsoeApiArea(), "10YNO-4--------9") == 0 ? "selected" : ""); - html.replace("{eaNo5}", strcmp(config->getEntsoeApiArea(), "10Y1001A1001A48H") == 0 ? "selected" : ""); + html.replace("{et}", entsoe.token); + html.replace("{em}", String(entsoe.multiplier / 1000.0, 3)); - html.replace("{eaSe1}", strcmp(config->getEntsoeApiArea(), "10Y1001A1001A44P") == 0 ? "selected" : ""); - html.replace("{eaSe2}", strcmp(config->getEntsoeApiArea(), "10Y1001A1001A45N") == 0 ? "selected" : ""); - html.replace("{eaSe3}", strcmp(config->getEntsoeApiArea(), "10Y1001A1001A46L") == 0 ? "selected" : ""); - html.replace("{eaSe4}", strcmp(config->getEntsoeApiArea(), "10Y1001A1001A47J") == 0 ? "selected" : ""); + html.replace("{eaNo1}", strcmp(entsoe.area, "10YNO-1--------2") == 0 ? "selected" : ""); + html.replace("{eaNo2}", strcmp(entsoe.area, "10YNO-2--------T") == 0 ? "selected" : ""); + html.replace("{eaNo3}", strcmp(entsoe.area, "10YNO-3--------J") == 0 ? "selected" : ""); + html.replace("{eaNo4}", strcmp(entsoe.area, "10YNO-4--------9") == 0 ? "selected" : ""); + html.replace("{eaNo5}", strcmp(entsoe.area, "10Y1001A1001A48H") == 0 ? "selected" : ""); - html.replace("{eaDk1}", strcmp(config->getEntsoeApiArea(), "10YDK-1--------W") == 0 ? "selected" : ""); - html.replace("{eaDk2}", strcmp(config->getEntsoeApiArea(), "10YDK-2--------M") == 0 ? "selected" : ""); + html.replace("{eaSe1}", strcmp(entsoe.area, "10Y1001A1001A44P") == 0 ? "selected" : ""); + html.replace("{eaSe2}", strcmp(entsoe.area, "10Y1001A1001A45N") == 0 ? "selected" : ""); + html.replace("{eaSe3}", strcmp(entsoe.area, "10Y1001A1001A46L") == 0 ? "selected" : ""); + html.replace("{eaSe4}", strcmp(entsoe.area, "10Y1001A1001A47J") == 0 ? "selected" : ""); - html.replace("{ecNOK}", strcmp(config->getEntsoeApiArea(), "NOK") == 0 ? "selected" : ""); - html.replace("{ecSEK}", strcmp(config->getEntsoeApiArea(), "SEK") == 0 ? "selected" : ""); - html.replace("{ecDKK}", strcmp(config->getEntsoeApiArea(), "DKK") == 0 ? "selected" : ""); - html.replace("{ecEUR}", strcmp(config->getEntsoeApiArea(), "EUR") == 0 ? "selected" : ""); + html.replace("{eaDk1}", strcmp(entsoe.area, "10YDK-1--------W") == 0 ? "selected" : ""); + html.replace("{eaDk2}", strcmp(entsoe.area, "10YDK-2--------M") == 0 ? "selected" : ""); + + html.replace("{ecNOK}", strcmp(entsoe.area, "NOK") == 0 ? "selected" : ""); + html.replace("{ecSEK}", strcmp(entsoe.area, "SEK") == 0 ? "selected" : ""); + html.replace("{ecDKK}", strcmp(entsoe.area, "DKK") == 0 ? "selected" : ""); + html.replace("{ecEUR}", strcmp(entsoe.area, "EUR") == 0 ? "selected" : ""); server.setContentLength(html.length() + HEAD_HTML_LEN + FOOT_HTML_LEN); server.send_P(200, "text/html", HEAD_HTML); @@ -561,12 +569,12 @@ void AmsWebServer::configWebHtml() { server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server.sendHeader("Pragma", "no-cache"); - html.replace("{as}", String(config->getAuthSecurity())); + html.replace("{as}", String(webConfig.security)); for(int i = 0; i<3; i++) { - html.replace("{as" + String(i) + "}", config->getAuthSecurity() == i ? "selected" : ""); + html.replace("{as" + String(i) + "}", webConfig.security == i ? "selected" : ""); } - html.replace("{au}", config->getAuthUser()); - html.replace("{ap}", config->getAuthPassword()); + html.replace("{au}", webConfig.username); + html.replace("{ap}", webConfig.password); server.setContentLength(html.length() + HEAD_HTML_LEN + FOOT_HTML_LEN); server.send_P(200, "text/html", HEAD_HTML); @@ -604,32 +612,33 @@ void AmsWebServer::dataJson() { StaticJsonDocument<768> json; String jsonStr; - if(data.getLastUpdateMillis() > 0) { + if(meterState->getLastUpdateMillis() > 0) { int maxPwr = this->maxPwr; if(maxPwr == 0) { - if(data.isThreePhase()) { + if(meterState->isThreePhase()) { maxPwr = 20000; } else { maxPwr = 10000; } } - json["up"] = data.getLastUpdateMillis(); - json["t"] = data.getPackageTimestamp(); + json["up"] = meterState->getLastUpdateMillis(); + json["t"] = meterState->getPackageTimestamp(); + json["freemem"] = ESP.getFreeHeap(); json.createNestedObject("data"); - json["data"]["P"] = data.getActiveImportPower(); - json["data"]["PO"] = data.getActiveExportPower(); + json["data"]["P"] = meterState->getActiveImportPower(); + json["data"]["PO"] = meterState->getActiveExportPower(); - double u1 = data.getL1Voltage(); - double u2 = data.getL2Voltage(); - double u3 = data.getL3Voltage(); - double i1 = data.getL1Current(); - double i2 = data.getL2Current(); - double i3 = data.getL3Current(); - double tpi = data.getActiveImportCounter(); - double tpo = data.getActiveExportCounter(); - double tqi = data.getReactiveImportCounter(); - double tqo = data.getReactiveExportCounter(); + double u1 = meterState->getL1Voltage(); + double u2 = meterState->getL2Voltage(); + double u3 = meterState->getL3Voltage(); + double i1 = meterState->getL1Current(); + double i2 = meterState->getL2Current(); + double i3 = meterState->getL3Current(); + double tpi = meterState->getActiveImportCounter(); + double tpo = meterState->getActiveExportCounter(); + double tqi = meterState->getReactiveImportCounter(); + double tqo = meterState->getReactiveExportCounter(); double volt = u1; double amp = i1; @@ -657,19 +666,19 @@ void AmsWebServer::dataJson() { json["data"]["tQO"] = tqo; } - json["p_pct"] = min(data.getActiveImportPower()*100/maxPwr, 100); + json["p_pct"] = min(meterState->getActiveImportPower()*100/maxPwr, 100); json["v"] = volt; json["v_pct"] = (max((int)volt-207, 1)*100/46); - int maxAmp = config->getMainFuse() == 0 ? 32 : config->getMainFuse(); + int maxAmp = meterConfig->mainFuse == 0 ? 32 : meterConfig->mainFuse; json["a"] = amp; json["a_pct"] = amp * 100 / maxAmp; - if(config->getProductionCapacity() > 0) { - int maxPrd = config->getProductionCapacity() * 1000; - json["po_pct"] = min(data.getActiveExportPower()*100/maxPrd, 100); + if(meterConfig->productionCapacity > 0) { + int maxPrd = meterConfig->productionCapacity * 1000; + json["po_pct"] = min(meterState->getActiveExportPower()*100/maxPrd, 100); } } else { json["p_pct"] = -1; @@ -678,7 +687,7 @@ void AmsWebServer::dataJson() { json["id"] = WiFi.macAddress(); json["maxPower"] = maxPwr; - json["meterType"] = config->getMeterType(); + json["meterType"] = meterConfig->type; json["uptime_seconds"] = millis64() / 1000; double vcc = hw->getVcc(); json["vcc"] = serialized(String(vcc, 3)); @@ -709,11 +718,11 @@ void AmsWebServer::dataJson() { unsigned long now = millis(); String hanStatus; - if(config->getMeterType() == 0) { + if(meterConfig->type == 0) { hanStatus = "secondary"; - } else if(now - data.getLastUpdateMillis() < 15000) { + } else if(now - meterState->getLastUpdateMillis() < 15000) { hanStatus = "success"; - } else if(now - data.getLastUpdateMillis() < 30000) { + } else if(now - meterState->getLastUpdateMillis() < 30000) { hanStatus = "warning"; } else { hanStatus = "danger"; @@ -721,9 +730,7 @@ void AmsWebServer::dataJson() { json["status"]["han"] = hanStatus; String wifiStatus; - if(strlen(config->getWifiSsid()) == 0) { - wifiStatus = "secondary"; - } else if(rssi > -75) { + if(rssi > -75) { wifiStatus = "success"; } else if(rssi > -95) { wifiStatus = "warning"; @@ -733,7 +740,7 @@ void AmsWebServer::dataJson() { json["status"]["wifi"] = wifiStatus; String mqttStatus; - if(strlen(config->getMqttHost()) == 0) { + if(!mqttEnabled) { mqttStatus = "secondary"; } else if(mqtt->connected()) { mqttStatus = "success"; @@ -758,107 +765,143 @@ void AmsWebServer::dataJson() { } void AmsWebServer::handleSetup() { + printD("Handling setup method from http"); + if(!server.hasArg("wifiSsid") || server.arg("wifiSsid").isEmpty() || !server.hasArg("wifiPassword") || server.arg("wifiPassword").isEmpty()) { server.sendHeader("Location", String("/"), true); server.send (302, "text/plain", ""); } else { - config->setLedPin(0xFF); - config->setLedPinRed(0xFF); - config->setLedPinGreen(0xFF); - config->setLedPinBlue(0xFF); - config->setApPin(0xFF); - config->setTempSensorPin(0xFF); - config->setVccPin(0xFF); + SystemConfig sys { server.arg("board").toInt() }; - config->setBoardType(server.arg("board").toInt()); - config->setVccOffset(0.0); - config->setVccMultiplier(1.0); - config->setVccBootLimit(0); - switch(config->getBoardType()) { + config->clearGpio(*gpioConfig); + config->clearMeter(*meterConfig); + + switch(sys.boardType) { case 0: // roarfred - config->setHanPin(3); - config->setApPin(0); - config->setLedPin(2); - config->setLedInverted(true); - config->setTempSensorPin(5); + gpioConfig->hanPin = 3; + gpioConfig->apPin = 0; + gpioConfig->ledPin = 2; + gpioConfig->ledInverted = true; + gpioConfig->tempSensorPin = 5; break; case 1: // Arnio Kamstrup - config->setHanPin(3); - config->setApPin(0); - config->setLedPin(2); - config->setLedInverted(true); - config->setTempSensorPin(5); - config->setLedPinRed(13); - config->setLedPinGreen(14); - config->setLedRgbInverted(true); + gpioConfig->hanPin = 3; + gpioConfig->apPin = 0; + gpioConfig->ledPin = 2; + gpioConfig->ledInverted = true; + gpioConfig->tempSensorPin = 5; + gpioConfig->ledPinRed = 13; + gpioConfig->ledPinGreen = 14; + gpioConfig->ledRgbInverted = true; break; case 2: // spenceme - config->setHanPin(3); - config->setApPin(0); - config->setLedPin(2); - config->setLedInverted(true); - config->setTempSensorPin(5); - config->setVccBootLimit(3.3); + gpioConfig->hanPin = 3; + gpioConfig->apPin = 0; + gpioConfig->ledPin = 2; + gpioConfig->ledInverted = true; + gpioConfig->tempSensorPin = 5; + gpioConfig->vccBootLimit = 33; break; case 101: // D1 - config->setHanPin(5); - config->setApPin(4); - config->setLedPin(2); - config->setLedInverted(true); - config->setTempSensorPin(14); - config->setVccMultiplier(1.1); + gpioConfig->hanPin = 5; + gpioConfig->apPin = 4; + gpioConfig->ledPin = 2; + gpioConfig->ledInverted = true; + gpioConfig->tempSensorPin = 14; + gpioConfig->vccMultiplier = 1100; break; case 100: // ESP8266 - config->setHanPin(3); - config->setLedPin(2); - config->setLedInverted(true); + gpioConfig->hanPin = 3; + gpioConfig->ledPin = 2; + gpioConfig->ledInverted = true; break; case 201: // D32 - config->setHanPin(16); - config->setApPin(4); - config->setLedPin(5); - config->setLedInverted(true); - config->setTempSensorPin(14); - config->setVccPin(35); - config->setVccMultiplier(2.25); + gpioConfig->hanPin = 16; + gpioConfig->apPin = 4; + gpioConfig->ledPin = 5; + gpioConfig->ledInverted = true; + gpioConfig->tempSensorPin = 14; + gpioConfig->vccPin = 35; + gpioConfig->vccMultiplier = 2250; break; case 202: // Feather - config->setHanPin(16); - config->setLedPin(2); - config->setLedInverted(false); - config->setTempSensorPin(14); + gpioConfig->hanPin = 16; + gpioConfig->ledPin = 2; + gpioConfig->ledInverted = false; + gpioConfig->tempSensorPin = 14; break; case 203: // DevKitC - config->setHanPin(16); - config->setLedPin(2); - config->setLedInverted(false); + gpioConfig->hanPin = 16; + gpioConfig->ledPin = 2; + gpioConfig->ledInverted = false; break; case 200: // ESP32 - config->setHanPin(16); - config->setApPin(0); - config->setLedPin(2); - config->setLedInverted(false); - config->setTempSensorPin(14); + gpioConfig->hanPin = 16; + gpioConfig->apPin = 0; + gpioConfig->ledPin = 2; + gpioConfig->ledInverted = false; + gpioConfig->tempSensorPin = 14; break; } - config->setMeterType(server.arg("meterType").toInt()); - config->setWifiSsid(server.arg("wifiSsid").c_str()); - config->setWifiPassword(server.arg("wifiPassword").c_str()); + + WiFiConfig wifi; + config->clearWifi(wifi); + + strcpy(wifi.ssid, server.arg("wifiSsid").c_str()); + strcpy(wifi.psk, server.arg("wifiPassword").c_str()); + if(server.hasArg("wifiIpType") && server.arg("wifiIpType").toInt() == 1) { - config->setWifiIp(server.arg("wifiIp").c_str()); - config->setWifiGw(server.arg("wifiGw").c_str()); - config->setWifiSubnet(server.arg("wifiSubnet").c_str()); - config->setWifiDns1(server.arg("wifiDns1").c_str()); - } else { - config->clearWifiIp(); + strcpy(wifi.ip, server.arg("wifiIp").c_str()); + strcpy(wifi.gateway, server.arg("wifiGw").c_str()); + strcpy(wifi.subnet, server.arg("wifiSubnet").c_str()); + strcpy(wifi.dns1, server.arg("wifiDns1").c_str()); } if(server.hasArg("wifiHostname") && !server.arg("wifiHostname").isEmpty()) { - config->setWifiHostname(server.arg("wifiHostname").c_str()); - config->setMdnsEnable(true); + strcpy(wifi.hostname, server.arg("wifiHostname").c_str()); + wifi.mdns = true; } else { - config->setMdnsEnable(false); + wifi.mdns = false; } - if(config->save()) { + + MqttConfig mqttConfig; + config->clearMqtt(mqttConfig); + + config->clearAuth(webConfig); + + NtpConfig ntp; + config->clearNtp(ntp); + + bool success = true; + if(!config->setSystemConfig(sys)) { + printD("Unable to set system config"); + success = false; + } + if(!config->setWiFiConfig(wifi)) { + printD("Unable to set WiFi config"); + success = false; + } + if(!config->setMqttConfig(mqttConfig)) { + printD("Unable to set MQTT config"); + success = false; + } + if(!config->setWebConfig(webConfig)) { + printD("Unable to set web config"); + success = false; + } + if(!config->setMeterConfig(*meterConfig)) { + printD("Unable to set meter config"); + success = false; + } + if(!config->setGpioConfig(*gpioConfig)) { + printD("Unable to set GPIO config"); + success = false; + } + if(!config->setNtpConfig(ntp)) { + printD("Unable to set NTP config"); + success = false; + } + + if(success && config->save()) { performRestart = true; server.sendHeader("Location","/restart-wait"); server.send(303); @@ -878,153 +921,163 @@ void AmsWebServer::handleSave() { String temp; if(server.hasArg("mc") && server.arg("mc") == "true") { - config->setMeterType(server.arg("m").toInt()); - config->setDistributionSystem(server.arg("d").toInt()); - config->setMainFuse(server.arg("f").toInt()); - config->setProductionCapacity(server.arg("p").toInt()); - config->setSubstituteMissing(server.hasArg("s") && server.arg("substituteMissing") == "true"); - config->setSendUnknown(server.hasArg("u") && server.arg("sendUnknown") == "true"); + printD("Received meter config"); + meterConfig->type = server.arg("m").toInt(); + meterConfig->distributionSystem = server.arg("d").toInt(); + meterConfig->mainFuse = server.arg("f").toInt(); + meterConfig->productionCapacity = server.arg("p").toInt(); String encryptionKeyHex = server.arg("e"); if(!encryptionKeyHex.isEmpty()) { encryptionKeyHex.replace("0x", ""); - uint8_t hexStr[16]; - fromHex(hexStr, encryptionKeyHex, 16); - config->setMeterEncryptionKey(hexStr); + fromHex(meterConfig->encryptionKey, encryptionKeyHex, 16); } String authenticationKeyHex = server.arg("a"); if(!authenticationKeyHex.isEmpty()) { authenticationKeyHex.replace("0x", ""); - uint8_t hexStr[16]; - fromHex(hexStr, encryptionKeyHex, 16); - config->setMeterAuthenticationKey(hexStr); + fromHex(meterConfig->authenticationKey, encryptionKeyHex, 16); } + meterConfig->substituteMissing = server.hasArg("s") && server.arg("substituteMissing") == "true"; + meterConfig->sendUnknown = server.hasArg("u") && server.arg("sendUnknown") == "true"; + config->setMeterConfig(*meterConfig); } if(server.hasArg("wc") && server.arg("wc") == "true") { - config->setWifiSsid(server.arg("s").c_str()); - config->setWifiPassword(server.arg("p").c_str()); + printD("Received WiFi config"); + WiFiConfig wifi; + config->clearWifi(wifi); + strcpy(wifi.ssid, server.arg("s").c_str()); + strcpy(wifi.psk, server.arg("p").c_str()); + if(server.hasArg("st") && server.arg("st").toInt() == 1) { - config->setWifiIp(server.arg("i").c_str()); - config->setWifiGw(server.arg("g").c_str()); - config->setWifiSubnet(server.arg("sn").c_str()); - config->setWifiDns1(server.arg("d1").c_str()); - config->setWifiDns2(server.arg("d2").c_str()); - } else { - config->clearWifiIp(); + strcpy(wifi.ip, server.arg("i").c_str()); + strcpy(wifi.gateway, server.arg("g").c_str()); + strcpy(wifi.subnet, server.arg("sn").c_str()); + strcpy(wifi.dns1, server.arg("d1").c_str()); + strcpy(wifi.dns2, server.arg("d2").c_str()); } - config->setWifiHostname(server.arg("h").c_str()); - config->setMdnsEnable(server.hasArg("m") && server.arg("m") == "true"); + if(server.hasArg("h") && !server.arg("h").isEmpty()) { + strcpy(wifi.hostname, server.arg("h").c_str()); + } + config->setWiFiConfig(wifi); } if(server.hasArg("mqc") && server.arg("mqc") == "true") { + printD("Received MQTT config"); + MqttConfig mqtt; if(server.hasArg("m") && server.arg("m") == "true") { - config->setMqttHost(server.arg("h").c_str()); - int port = server.arg("p").toInt(); - config->setMqttPort(port == 0 ? 1883 : port); - config->setMqttClientId(server.arg("i").c_str()); - config->setMqttPublishTopic(server.arg("t").c_str()); - config->setMqttSubscribeTopic(server.arg("st").c_str()); - config->setMqttUser(server.arg("u").c_str()); - config->setMqttPassword(server.arg("pw").c_str()); - config->setMqttPayloadFormat(server.arg("f").toInt()); - config->setMqttSsl(server.arg("s") == "true"); + strcpy(mqtt.host, server.arg("h").c_str()); + strcpy(mqtt.clientId, server.arg("i").c_str()); + strcpy(mqtt.publishTopic, server.arg("t").c_str()); + strcpy(mqtt.subscribeTopic, server.arg("st").c_str()); + strcpy(mqtt.username, server.arg("u").c_str()); + strcpy(mqtt.password, server.arg("pw").c_str()); + mqtt.payloadFormat = server.arg("f").toInt(); + mqtt.ssl = server.arg("s") == "true"; + + mqtt.port = server.arg("p").toInt(); + if(mqtt.port == 0) { + mqtt.port = mqtt.ssl ? 8883 : 1883; + } } else { - config->clearMqtt(); + config->clearMqtt(mqtt); } + config->setMqttConfig(mqtt); } if(server.hasArg("dc") && server.arg("dc") == "true") { - config->setDomoELIDX(server.arg("elidx").toInt()); - config->setDomoVL1IDX(server.arg("vl1idx").toInt()); - config->setDomoVL2IDX(server.arg("vl2idx").toInt()); - config->setDomoVL3IDX(server.arg("vl3idx").toInt()); - config->setDomoCL1IDX(server.arg("cl1idx").toInt()); + printD("Received Domoticz config"); + DomoticzConfig domo { + server.arg("elidx").toInt(), + server.arg("vl1idx").toInt(), + server.arg("vl2idx").toInt(), + server.arg("vl3idx").toInt(), + server.arg("cl1idx").toInt() + }; + config->setDomoticzConfig(domo); } - if(server.hasArg("ac") && server.arg("ac") == "true") { - config->setAuthSecurity((byte)server.arg("as").toInt()); - if(config->getAuthSecurity() > 0) { - config->setAuthUser(server.arg("au").c_str()); - config->setAuthPassword(server.arg("ap").c_str()); - debugger->setPassword(config->getAuthPassword()); + printD("Received web config"); + webConfig.security = server.arg("as").toInt(); + if(webConfig.security > 0) { + strcpy(webConfig.username, server.arg("au").c_str()); + strcpy(webConfig.password, server.arg("ap").c_str()); + debugger->setPassword(webConfig.password); } else { + strcpy(webConfig.username, ""); + strcpy(webConfig.password, ""); debugger->setPassword(""); - config->clearAuth(); } + config->setWebConfig(webConfig); } if(server.hasArg("gpioConfig") && server.arg("gpioConfig") == "true") { - // Unset all pins to avoid conflicts if GPIO have been swapped between pins - config->setLedPin(0xFF); - config->setLedPinRed(0xFF); - config->setLedPinGreen(0xFF); - config->setLedPinBlue(0xFF); - config->setApPin(0xFF); - config->setTempSensorPin(0xFF); - config->setTempAnalogSensorPin(0xFF); - config->setVccPin(0xFF); - - config->setHanPin(server.hasArg("hanPin") && !server.arg("hanPin").isEmpty() ? server.arg("hanPin").toInt() : 3); - config->setLedPin(server.hasArg("ledPin") && !server.arg("ledPin").isEmpty() ? server.arg("ledPin").toInt() : 0xFF); - config->setLedInverted(server.hasArg("ledInverted") && server.arg("ledInverted") == "true"); - config->setLedPinRed(server.hasArg("ledPinRed") && !server.arg("ledPinRed").isEmpty() ? server.arg("ledPinRed").toInt() : 0xFF); - config->setLedPinGreen(server.hasArg("ledPinGreen") && !server.arg("ledPinGreen").isEmpty() ? server.arg("ledPinGreen").toInt() : 0xFF); - config->setLedPinBlue(server.hasArg("ledPinBlue") && !server.arg("ledPinBlue").isEmpty() ? server.arg("ledPinBlue").toInt() : 0xFF); - config->setLedRgbInverted(server.hasArg("ledRgbInverted") && server.arg("ledRgbInverted") == "true"); - config->setApPin(server.hasArg("apPin") && !server.arg("apPin").isEmpty() ? server.arg("apPin").toInt() : 0xFF); - config->setTempSensorPin(server.hasArg("tempSensorPin") && !server.arg("tempSensorPin").isEmpty() ?server.arg("tempSensorPin").toInt() : 0xFF); - config->setTempAnalogSensorPin(server.hasArg("tempAnalogSensorPin") && !server.arg("tempAnalogSensorPin").isEmpty() ?server.arg("tempAnalogSensorPin").toInt() : 0xFF); - config->setVccPin(server.hasArg("vccPin") && !server.arg("vccPin").isEmpty() ? server.arg("vccPin").toInt() : 0xFF); - config->setVccOffset(server.hasArg("vccOffset") && !server.arg("vccOffset").isEmpty() ? server.arg("vccOffset").toDouble() : 0.0); - config->setVccMultiplier(server.hasArg("vccMultiplier") && !server.arg("vccMultiplier").isEmpty() ? server.arg("vccMultiplier").toDouble() : 1.0); - config->setVccBootLimit(server.hasArg("vccBootLimit") && !server.arg("vccBootLimit").isEmpty() ? server.arg("vccBootLimit").toDouble() : 0.0); + printD("Received GPIO config"); + gpioConfig->hanPin = server.hasArg("hanPin") && !server.arg("hanPin").isEmpty() ? server.arg("hanPin").toInt() : 3; + gpioConfig->ledPin = server.hasArg("ledPin") && !server.arg("ledPin").isEmpty() ? server.arg("ledPin").toInt() : 0xFF; + gpioConfig->ledInverted = server.hasArg("ledInverted") && server.arg("ledInverted") == "true"; + gpioConfig->ledPinRed = server.hasArg("ledPinRed") && !server.arg("ledPinRed").isEmpty() ? server.arg("ledPinRed").toInt() : 0xFF; + gpioConfig->ledPinGreen = server.hasArg("ledPinGreen") && !server.arg("ledPinGreen").isEmpty() ? server.arg("ledPinGreen").toInt() : 0xFF; + gpioConfig->ledPinBlue = server.hasArg("ledPinBlue") && !server.arg("ledPinBlue").isEmpty() ? server.arg("ledPinBlue").toInt() : 0xFF; + gpioConfig->ledRgbInverted = server.hasArg("ledRgbInverted") && server.arg("ledRgbInverted") == "true"; + gpioConfig->apPin = server.hasArg("apPin") && !server.arg("apPin").isEmpty() ? server.arg("apPin").toInt() : 0xFF; + gpioConfig->tempSensorPin = server.hasArg("tempSensorPin") && !server.arg("tempSensorPin").isEmpty() ?server.arg("tempSensorPin").toInt() : 0xFF; + gpioConfig->tempAnalogSensorPin = server.hasArg("tempAnalogSensorPin") && !server.arg("tempAnalogSensorPin").isEmpty() ?server.arg("tempAnalogSensorPin").toInt() : 0xFF; + gpioConfig->vccPin = server.hasArg("vccPin") && !server.arg("vccPin").isEmpty() ? server.arg("vccPin").toInt() : 0xFF; + gpioConfig->vccOffset = server.hasArg("vccOffset") && !server.arg("vccOffset").isEmpty() ? server.arg("vccOffset").toFloat() * 100 : 0; + gpioConfig->vccMultiplier = server.hasArg("vccMultiplier") && !server.arg("vccMultiplier").isEmpty() ? server.arg("vccMultiplier").toFloat() * 1000 : 1000; + gpioConfig->vccBootLimit = server.hasArg("vccBootLimit") && !server.arg("vccBootLimit").isEmpty() ? server.arg("vccBootLimit").toFloat() * 10 : 0; + config->setGpioConfig(*gpioConfig); } if(server.hasArg("debugConfig") && server.arg("debugConfig") == "true") { - config->setDebugTelnet(server.hasArg("debugTelnet") && server.arg("debugTelnet") == "true"); - config->setDebugSerial(server.hasArg("debugSerial") && server.arg("debugSerial") == "true"); - config->setDebugLevel(server.arg("debugLevel").toInt()); + printD("Received Debug config"); + DebugConfig debug; + debug.telnet = server.hasArg("debugTelnet") && server.arg("debugTelnet") == "true"; + debug.serial = server.hasArg("debugSerial") && server.arg("debugSerial") == "true"; + debug.level = server.arg("debugLevel").toInt(); debugger->stop(); - if(config->getAuthSecurity() > 0) { - debugger->setPassword(config->getAuthPassword()); + if(webConfig.security > 0) { + debugger->setPassword(webConfig.password); } else { debugger->setPassword(""); } - debugger->setSerialEnabled(config->isDebugSerial()); - debugger->begin(config->getWifiHostname(), (uint8_t) config->getDebugLevel()); - if(!config->isDebugTelnet()) { - debugger->stop(); + debugger->setSerialEnabled(debug.serial); + WiFiConfig wifi; + if(config->getWiFiConfig(wifi) && strlen(wifi.hostname) > 0) { + debugger->begin(wifi.hostname, (uint8_t) debug.level); + if(!debug.telnet) { + debugger->stop(); + } } + config->setDebugConfig(debug); } if(server.hasArg("nc") && server.arg("nc") == "true") { - config->setNtpEnable(server.hasArg("n") && server.arg("n") == "true"); - config->setNtpDhcp(server.hasArg("nd") && server.arg("nd") == "true"); - if(server.hasArg("o") && !server.arg("o").isEmpty()) { - int offset = server.arg("o").toInt(); - config->setNtpOffset(offset); - if(server.hasArg("so") && !server.arg("so").isEmpty()) { - int summerOffset = server.arg("so").toInt(); - config->setNtpSummerOffset(summerOffset); - } else { - config->setNtpSummerOffset(0); - } - } else { - config->setNtpOffset(0); - } - config->setNtpServer(server.arg("ns").c_str()); + printD("Received NTP config"); + NtpConfig ntp { + server.hasArg("n") && server.arg("n") == "true", + server.hasArg("nd") && server.arg("nd") == "true", + server.arg("o").toInt() / 10, + server.arg("so").toInt() / 10 + }; + strcpy(ntp.server, server.arg("ns").c_str()); + config->setNtpConfig(ntp); } if(server.hasArg("ec") && server.arg("ec") == "true") { - config->setEntsoeApiToken(server.arg("et").c_str()); - config->setEntsoeApiArea(server.arg("ea").c_str()); - config->setEntsoeApiCurrency(server.arg("ec").c_str()); - config->setEntsoeApiMultiplier(server.arg("em").toDouble()); + printD("Received ENTSO-E config"); + EntsoeConfig entsoe; + strcpy(entsoe.token, server.arg("et").c_str()); + strcpy(entsoe.area, server.arg("ea").c_str()); + strcpy(entsoe.currency, server.arg("ecu").c_str()); + entsoe.multiplier = server.arg("em").toFloat() * 1000; + config->setEntsoeConfig(entsoe); + eapi->setup(entsoe); } printI("Saving configuration now..."); @@ -1040,18 +1093,7 @@ void AmsWebServer::handleSave() { server.sendHeader("Location", String("/"), true); server.send (302, "text/plain", ""); - hw->setLed(config->getLedPin(), config->isLedInverted()); - hw->setLedRgb(config->getLedPinRed(), config->getLedPinGreen(), config->getLedPinBlue(), config->isLedRgbInverted()); - hw->setTempSensorPin(config->getTempSensorPin()); - hw->setTempAnalogSensorPin(config->getTempAnalogSensorPin()); - hw->setVccPin(config->getVccPin()); - hw->setVccOffset(config->getVccOffset()); - hw->setVccMultiplier(config->getVccMultiplier()); - - eapi->setToken(config->getEntsoeApiToken()); - eapi->setArea(config->getEntsoeApiArea()); - eapi->setCurrency(config->getEntsoeApiCurrency()); - eapi->setMultiplier(config->getEntsoeApiMultiplier()); + hw->setup(gpioConfig, config); } } else { printE("Error saving configuration"); @@ -1068,18 +1110,21 @@ void AmsWebServer::configNtpHtml() { String html = String((const __FlashStringHelper*) NTP_HTML); - html.replace("{n}", config->isNtpEnable() ? "checked" : ""); + NtpConfig ntp; + config->getNtpConfig(ntp); + + html.replace("{n}", ntp.enable ? "checked" : ""); for(int i = (3600*-13); i<(3600*15); i+=3600) { - html.replace("{o" + String(i) + "}", config->getNtpOffset() == i ? "selected" : ""); + html.replace("{o" + String(i) + "}", ntp.offset * 10 == i ? "selected" : ""); } for(int i = 0; i<(3600*3); i+=3600) { - html.replace("{so" + String(i) + "}", config->getNtpSummerOffset() == i ? "selected" : ""); + html.replace("{so" + String(i) + "}", ntp.summerOffset * 10 == i ? "selected" : ""); } - html.replace("{ns}", config->getNtpServer()); - html.replace("{nd}", config->isNtpDhcp() ? "checked" : ""); + html.replace("{ns}", ntp.server); + html.replace("{nd}", ntp.dhcp ? "checked" : ""); server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server.sendHeader("Pragma", "no-cache"); @@ -1104,21 +1149,22 @@ void AmsWebServer::configGpioHtml() { html.replace("${gpio.max}", "16"); #endif - html.replace("${options.han}", getSerialSelectOptions(config->getHanPin())); + html.replace("${options.han}", getSerialSelectOptions(gpioConfig->hanPin)); - html.replace("${config.ledPin}", config->getLedPin() == 0xFF ? "" : String(config->getLedPin())); - html.replace("${config.ledInverted}", config->isLedInverted() ? "checked" : ""); - html.replace("${config.ledPinRed}", config->getLedPinRed() == 0xFF ? "" : String(config->getLedPinRed())); - html.replace("${config.ledPinGreen}", config->getLedPinGreen() == 0xFF ? "" : String(config->getLedPinGreen())); - html.replace("${config.ledPinBlue}", config->getLedPinBlue() == 0xFF ? "" : String(config->getLedPinBlue())); - html.replace("${config.ledRgbInverted}", config->isLedRgbInverted() ? "checked" : ""); - html.replace("${config.apPin}", config->getApPin() == 0xFF ? "" : String(config->getApPin())); - html.replace("${config.tempSensorPin}", config->getTempSensorPin() == 0xFF ? "" : String(config->getTempSensorPin())); - html.replace("${config.vccPin}", config->getVccPin() == 0xFF ? "" : String(config->getVccPin())); + html.replace("${config.ledPin}", gpioConfig->ledPin == 0xFF ? "" : String(gpioConfig->ledPin)); + html.replace("${config.ledInverted}", gpioConfig->ledInverted ? "checked" : ""); + html.replace("${config.ledPinRed}", gpioConfig->ledPinRed == 0xFF ? "" : String(gpioConfig->ledPinRed)); + html.replace("${config.ledPinGreen}", gpioConfig->ledPinGreen == 0xFF ? "" : String(gpioConfig->ledPinGreen)); + html.replace("${config.ledPinBlue}", gpioConfig->ledPinBlue == 0xFF ? "" : String(gpioConfig->ledPinBlue)); + html.replace("${config.ledRgbInverted}", gpioConfig->ledRgbInverted ? "checked" : ""); + html.replace("${config.apPin}", gpioConfig->apPin == 0xFF ? "" : String(gpioConfig->apPin)); + html.replace("${config.tempSensorPin}", gpioConfig->tempSensorPin == 0xFF ? "" : String(gpioConfig->tempSensorPin)); + html.replace("${config.tempAnalogSensorPin}", gpioConfig->tempAnalogSensorPin == 0xFF ? "" : String(gpioConfig->tempAnalogSensorPin)); + html.replace("${config.vccPin}", gpioConfig->vccPin == 0xFF ? "" : String(gpioConfig->vccPin)); - html.replace("${config.vccOffset}", config->getVccOffset() > 0 ? String(config->getVccOffset(), 2) : ""); - html.replace("${config.vccMultiplier}", config->getVccMultiplier() > 0 ? String(config->getVccMultiplier(), 2) : ""); - html.replace("${config.vccBootLimit}", config->getVccBootLimit() > 0.0 ? String(config->getVccBootLimit(), 1) : ""); + html.replace("${config.vccOffset}", gpioConfig->vccOffset > 0 ? String(gpioConfig->vccOffset / 100.0, 2) : ""); + html.replace("${config.vccMultiplier}", gpioConfig->vccMultiplier > 0 ? String(gpioConfig->vccMultiplier / 1000.0, 2) : ""); + html.replace("${config.vccBootLimit}", gpioConfig->vccBootLimit > 0 ? String(gpioConfig->vccBootLimit / 10.0, 1) : ""); server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server.sendHeader("Pragma", "no-cache"); @@ -1137,11 +1183,14 @@ void AmsWebServer::configDebugHtml() { String html = String((const __FlashStringHelper*) DEBUGGING_HTML); - html.replace("${config.debugTelnet}", config->isDebugTelnet() ? "checked" : ""); - html.replace("${config.debugSerial}", config->isDebugSerial() ? "checked" : ""); - html.replace("${config.debugLevel}", String(config->getDebugLevel())); + DebugConfig debug; + config->getDebugConfig(debug); + + html.replace("${config.debugTelnet}", debug.telnet ? "checked" : ""); + html.replace("${config.debugSerial}", debug.serial ? "checked" : ""); + html.replace("${config.debugLevel}", String(debug.level)); for(int i = 0; i<=RemoteDebug::ANY; i++) { - html.replace("${config.debugLevel" + String(i) + "}", config->getDebugLevel() == i ? "selected" : ""); + html.replace("${config.debugLevel" + String(i) + "}", debug.level == i ? "selected" : ""); } server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); @@ -1315,11 +1364,13 @@ void AmsWebServer::firmwareDownload() { } } else { printE("Unable to configure HTTP client"); -#if defined(ESP8266) - char buf[256]; - client.getLastSSLError(buf,256); + + #if defined(ESP8266) + char buf[64]; + client.getLastSSLError(buf,64); printE(buf); -#endif + #endif + server.sendHeader("Location","/"); server.send(303); } @@ -1364,15 +1415,18 @@ void AmsWebServer::restartWaitHtml() { String html = String((const __FlashStringHelper*) RESTARTWAIT_HTML); + WiFiConfig wifi; + config->getWiFiConfig(wifi); + if(WiFi.getMode() != WIFI_AP) { html.replace("boot.css", BOOTSTRAP_URL); } - if(strlen(config->getWifiIp()) == 0 && WiFi.getMode() != WIFI_AP) { + if(strlen(wifi.ip) == 0 && WiFi.getMode() != WIFI_AP) { html.replace("${ip}", WiFi.localIP().toString()); } else { - html.replace("${ip}", config->getWifiIp()); + html.replace("${ip}", wifi.ip); } - html.replace("${hostname}", config->getWifiHostname()); + html.replace("${hostname}", wifi.hostname); server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server.sendHeader("Pragma", "no-cache"); @@ -1383,7 +1437,7 @@ void AmsWebServer::restartWaitHtml() { yield(); if(performRestart) { SPIFFS.end(); - printI("Firmware uploaded, rebooting"); + printI("Rebooting"); delay(1000); #if defined(ESP8266) ESP.reset(); @@ -1447,7 +1501,9 @@ void AmsWebServer::mqttCaUpload() { if(upload.status == UPLOAD_FILE_END) { server.sendHeader("Location","/config-mqtt"); server.send(303); - if(config->isMqttSsl()) { + + MqttConfig mqttConfig; + if(config->getMqttConfig(mqttConfig) && mqttConfig.ssl) { config->setMqttChanged(); } } @@ -1461,7 +1517,8 @@ void AmsWebServer::mqttCaDelete() { deleteFile(FILE_MQTT_CA); server.sendHeader("Location","/config-mqtt"); server.send(303); - if(config->isMqttSsl()) { + MqttConfig mqttConfig; + if(config->getMqttConfig(mqttConfig) && mqttConfig.ssl) { config->setMqttChanged(); } } else { @@ -1498,7 +1555,8 @@ void AmsWebServer::mqttCertUpload() { if(upload.status == UPLOAD_FILE_END) { server.sendHeader("Location","/config-mqtt"); server.send(303); - if(config->isMqttSsl()) { + MqttConfig mqttConfig; + if(config->getMqttConfig(mqttConfig) && mqttConfig.ssl) { config->setMqttChanged(); } } @@ -1512,7 +1570,8 @@ void AmsWebServer::mqttCertDelete() { deleteFile(FILE_MQTT_CERT); server.sendHeader("Location","/config-mqtt"); server.send(303); - if(config->isMqttSsl()) { + MqttConfig mqttConfig; + if(config->getMqttConfig(mqttConfig) && mqttConfig.ssl) { config->setMqttChanged(); } } else { @@ -1549,7 +1608,8 @@ void AmsWebServer::mqttKeyUpload() { if(upload.status == UPLOAD_FILE_END) { server.sendHeader("Location","/config-mqtt"); server.send(303); - if(config->isMqttSsl()) { + MqttConfig mqttConfig; + if(config->getMqttConfig(mqttConfig) && mqttConfig.ssl) { config->setMqttChanged(); } } @@ -1563,7 +1623,8 @@ void AmsWebServer::mqttKeyDelete() { deleteFile(FILE_MQTT_KEY); server.sendHeader("Location","/config-mqtt"); server.send(303); - if(config->isMqttSsl()) { + MqttConfig mqttConfig; + if(config->getMqttConfig(mqttConfig) && mqttConfig.ssl) { config->setMqttChanged(); } } else { diff --git a/src/web/AmsWebServer.h b/src/web/AmsWebServer.h index 6e45c6ec..af1aca1d 100644 --- a/src/web/AmsWebServer.h +++ b/src/web/AmsWebServer.h @@ -3,6 +3,7 @@ #define BOOTSTRAP_URL "https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/css/bootstrap.min.css" +#include "Arduino.h" #include #include #include "AmsConfiguration.h" @@ -12,12 +13,6 @@ #include "RemoteDebug.h" #include "entsoe/EntsoeApi.h" -#if defined(ARDUINO) && ARDUINO >= 100 - #include "Arduino.h" -#else - #include "WProgram.h" -#endif - #if defined(ESP8266) #include #include @@ -27,7 +22,6 @@ #include #include #include "SPIFFS.h" - #include "Update.h" #else #warning "Unsupported board type" #endif @@ -35,19 +29,22 @@ class AmsWebServer { public: AmsWebServer(RemoteDebug* Debug, HwTools* hw, EntsoeApi* eapi); - void setup(AmsConfiguration* config, MQTTClient* mqtt); + void setup(AmsConfiguration*, GpioConfig*, MeterConfig*, AmsData*, MQTTClient*); void loop(); - - void setData(AmsData& data); + void setTimezone(Timezone* tz); private: RemoteDebug* debugger; + bool mqttEnabled = false; int maxPwr = 0; HwTools* hw; Timezone* tz; EntsoeApi* eapi; - AmsConfiguration* config; - AmsData data; + AmsConfiguration* config; + GpioConfig* gpioConfig; + MeterConfig* meterConfig; + WebConfig webConfig; + AmsData* meterState; MQTTClient* mqtt; bool uploading = false; File file; diff --git a/web/application.js b/web/application.js index 6eb77d8e..fc56cf3e 100644 --- a/web/application.js +++ b/web/application.js @@ -249,10 +249,10 @@ var fetch = function() { continue; } if(isNaN(str)) { - $('#'+id).html(str); + $('.'+id).html(str); } else { var num = parseFloat(str); - $('#'+id).html(num.toFixed(num < 0 ? 0 : num < 10 ? 2 : 1)); + $('.'+id).html(num.toFixed(num < 0 ? 0 : num < 10 ? 2 : 1)); } } @@ -276,13 +276,13 @@ var fetch = function() { if(json.wifi) { for(var id in json.wifi) { var str = json.wifi[id]; - dst = $('#'+id); + dst = $('.'+id); if(isNaN(str)) { dst.html(str); } else { var num = parseFloat(str); dst.html(num.toFixed(0)); - $('#'+id+'-row').show(); + $('.'+id+'-row').show(); } } } @@ -355,7 +355,6 @@ var fetch = function() { } else { var num = parseFloat(str); $('.'+id).html(num.toFixed(1)); - $('#'+id+'-row').show(); $('.'+id+'-row').show(); } } diff --git a/web/entsoe.html b/web/entsoe.html index 215e14f3..92a31566 100644 --- a/web/entsoe.html +++ b/web/entsoe.html @@ -42,7 +42,7 @@
Currency
- diff --git a/web/index.html b/web/index.html index 048e7fb5..48659897 100644 --- a/web/index.html +++ b/web/index.html @@ -21,7 +21,7 @@
-
+
{P} W
-
+
{tPI} kWh
@@ -43,7 +43,7 @@
-
+
{PO} W
-
+
{tPO} kWh
@@ -65,20 +65,20 @@
Reactive
-
-
Import
+
+
In
{tQI} kvarh
-
Export
+
Out
{tQO} kvarh
-
-
Import
+
+
In
{tQI} kvarh
-
Export
+
Out
{tQO} kvarh
@@ -99,7 +99,7 @@ data-label="Volt" >
-
+
{U1}V
{U2}V
{U3}V
@@ -115,12 +115,12 @@ data-text_size="0.15" data-width="25" data-style="Arch" - data-theme="Green-Red" + data-theme="Green-Gold-Red" data-animationstep="0" data-label="Ampere" >
-
+
{I1}A
{I2}A
{I3}A