Compare commits

..

2 Commits

Author SHA1 Message Date
Gunnar Skjold
32fa2f5632 Merge branch 'master' into dev-v2.1.8 2022-10-06 17:30:49 +02:00
Gunnar Skjold
12be475b02 Reverted HA changes for 2.1.8 release 2022-10-06 17:29:01 +02:00
45 changed files with 824 additions and 1147 deletions

View File

@@ -33,7 +33,6 @@ If applicable, add screenshots to help explain your problem.
**Relevant firmware information:** **Relevant firmware information:**
- Version: [e.g. 2.1.0] - Version: [e.g. 2.1.0]
- MQTT: [yes/no] - MQTT: [yes/no]
- MQTT payload type: [e.g. JSON]
- HAN GPIO: [e.g. GPIO5] - HAN GPIO: [e.g. GPIO5]
- HAN baud and parity: [e.g. 2400 8E1] - HAN baud and parity: [e.g. 2400 8E1]
- Temperature sensors [e.g. 3xDS18B20] - Temperature sensors [e.g. 3xDS18B20]

View File

@@ -20,7 +20,6 @@ A clear and concise description of what the problem is.
**Relevant firmware information:** **Relevant firmware information:**
- Version: [e.g. 2.1.0] - Version: [e.g. 2.1.0]
- MQTT: [yes/no] - MQTT: [yes/no]
- MQTT payload type: [e.g. JSON]
- HAN GPIO: [e.g. GPIO5] - HAN GPIO: [e.g. GPIO5]
- HAN baud and parity: [e.g. 2400 8E1] - HAN baud and parity: [e.g. 2400 8E1]
- Temperature sensors [e.g. 3xDS18B20] - Temperature sensors [e.g. 3xDS18B20]

View File

@@ -24,7 +24,6 @@ bool AmsConfiguration::getWiFiConfig(WiFiConfig& config) {
EEPROM.begin(EEPROM_SIZE); EEPROM.begin(EEPROM_SIZE);
EEPROM.get(CONFIG_WIFI_START, config); EEPROM.get(CONFIG_WIFI_START, config);
EEPROM.end(); EEPROM.end();
if(config.sleep > 2) config.sleep = 1;
return true; return true;
} else { } else {
clearWifi(config); clearWifi(config);
@@ -34,7 +33,6 @@ bool AmsConfiguration::getWiFiConfig(WiFiConfig& config) {
bool AmsConfiguration::setWiFiConfig(WiFiConfig& config) { bool AmsConfiguration::setWiFiConfig(WiFiConfig& config) {
WiFiConfig existing; WiFiConfig existing;
if(config.sleep > 2) config.sleep = 1;
if(getWiFiConfig(existing)) { if(getWiFiConfig(existing)) {
wifiChanged |= strcmp(config.ssid, existing.ssid) != 0; wifiChanged |= strcmp(config.ssid, existing.ssid) != 0;
wifiChanged |= strcmp(config.psk, existing.psk) != 0; wifiChanged |= strcmp(config.psk, existing.psk) != 0;
@@ -47,7 +45,6 @@ bool AmsConfiguration::setWiFiConfig(WiFiConfig& config) {
} }
wifiChanged |= strcmp(config.hostname, existing.hostname) != 0; wifiChanged |= strcmp(config.hostname, existing.hostname) != 0;
wifiChanged |= config.power != existing.power; wifiChanged |= config.power != existing.power;
wifiChanged |= config.sleep != existing.sleep;
} else { } else {
wifiChanged = true; wifiChanged = true;
} }
@@ -73,7 +70,6 @@ void AmsConfiguration::clearWifi(WiFiConfig& config) {
#endif #endif
strcpy(config.hostname, (String("ams-") + String(chipId, HEX)).c_str()); strcpy(config.hostname, (String("ams-") + String(chipId, HEX)).c_str());
config.mdns = true; config.mdns = true;
config.sleep = 0xFF;
} }
void AmsConfiguration::clearWifiIp(WiFiConfig& config) { void AmsConfiguration::clearWifiIp(WiFiConfig& config) {
@@ -514,7 +510,6 @@ bool AmsConfiguration::getEnergyAccountingConfig(EnergyAccountingConfig& config)
if(config.thresholds[9] != 255) { if(config.thresholds[9] != 255) {
clearEnergyAccountingConfig(config); clearEnergyAccountingConfig(config);
} }
if(config.hours > 5) config.hours = 5;
return true; return true;
} else { } else {
return false; return false;
@@ -554,7 +549,6 @@ void AmsConfiguration::clearEnergyAccountingConfig(EnergyAccountingConfig& confi
config.thresholds[7] = 100; config.thresholds[7] = 100;
config.thresholds[8] = 150; config.thresholds[8] = 150;
config.thresholds[9] = 255; config.thresholds[9] = 255;
config.hours = 3;
} }
bool AmsConfiguration::isEnergyAccountingChanged() { bool AmsConfiguration::isEnergyAccountingChanged() {
@@ -749,7 +743,7 @@ bool AmsConfiguration::relocateConfig86() {
} }
bool AmsConfiguration::relocateConfig87() { bool AmsConfiguration::relocateConfig87() {
MeterConfig87 meter87 = {0,0,0,0,0,0,0}; MeterConfig87 meter87;
MeterConfig meter; MeterConfig meter;
EEPROM.begin(EEPROM_SIZE); EEPROM.begin(EEPROM_SIZE);
EEPROM.get(CONFIG_METER_START_87, meter87); EEPROM.get(CONFIG_METER_START_87, meter87);

View File

@@ -54,8 +54,7 @@ struct WiFiConfig {
char hostname[32]; char hostname[32];
bool mdns; bool mdns;
uint8_t power; uint8_t power;
uint8_t sleep; }; // 210
}; // 211
struct MqttConfig86 { struct MqttConfig86 {
char host[128]; char host[128];

View File

@@ -45,12 +45,6 @@ void AmsData::apply(AmsData& other) {
this->l1PowerFactor = other.getL1PowerFactor(); this->l1PowerFactor = other.getL1PowerFactor();
this->l2PowerFactor = other.getL2PowerFactor(); this->l2PowerFactor = other.getL2PowerFactor();
this->l3PowerFactor = other.getL3PowerFactor(); this->l3PowerFactor = other.getL3PowerFactor();
this->l1activeImportPower = other.getL1ActiveImportPower();
this->l2activeImportPower = other.getL2ActiveImportPower();
this->l3activeImportPower = other.getL3ActiveImportPower();
this->l1activeExportPower = other.getL1ActiveExportPower();
this->l2activeExportPower = other.getL2ActiveExportPower();
this->l3activeExportPower = other.getL3ActiveExportPower();
case 3: case 3:
this->meterTimestamp = other.getMeterTimestamp(); this->meterTimestamp = other.getMeterTimestamp();
this->activeImportCounter = other.getActiveImportCounter(); this->activeImportCounter = other.getActiveImportCounter();
@@ -167,30 +161,6 @@ float AmsData::getL3PowerFactor() {
return this->l3PowerFactor; return this->l3PowerFactor;
} }
float AmsData::getL1ActiveImportPower() {
return this->l1activeImportPower;
}
float AmsData::getL2ActiveImportPower() {
return this->l2activeImportPower;
}
float AmsData::getL3ActiveImportPower() {
return this->l3activeImportPower;
}
float AmsData::getL1ActiveExportPower() {
return this->l1activeExportPower;
}
float AmsData::getL2ActiveExportPower() {
return this->l2activeExportPower;
}
float AmsData::getL3ActiveExportPower() {
return this->l3activeExportPower;
}
double AmsData::getActiveImportCounter() { double AmsData::getActiveImportCounter() {
return this->activeImportCounter; return this->activeImportCounter;
} }

View File

@@ -54,14 +54,6 @@ public:
float getL2PowerFactor(); float getL2PowerFactor();
float getL3PowerFactor(); float getL3PowerFactor();
float getL1ActiveImportPower();
float getL2ActiveImportPower();
float getL3ActiveImportPower();
float getL1ActiveExportPower();
float getL2ActiveExportPower();
float getL3ActiveExportPower();
double getActiveImportCounter(); double getActiveImportCounter();
double getReactiveImportCounter(); double getReactiveImportCounter();
double getActiveExportCounter(); double getActiveExportCounter();
@@ -79,8 +71,6 @@ protected:
time_t meterTimestamp = 0; time_t meterTimestamp = 0;
uint16_t activeImportPower = 0, reactiveImportPower = 0, activeExportPower = 0, reactiveExportPower = 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 l1voltage = 0, l2voltage = 0, l3voltage = 0, l1current = 0, l2current = 0, l3current = 0;
float l1activeImportPower = 0, l2activeImportPower = 0, l3activeImportPower = 0;
float l1activeExportPower = 0, l2activeExportPower = 0, l3activeExportPower = 0;
float powerFactor = 0, l1PowerFactor = 0, l2PowerFactor = 0, l3PowerFactor = 0; float powerFactor = 0, l1PowerFactor = 0, l2PowerFactor = 0, l3PowerFactor = 0;
double activeImportCounter = 0, reactiveImportCounter = 0, activeExportCounter = 0, reactiveExportCounter = 0; double activeImportCounter = 0, reactiveImportCounter = 0, activeExportCounter = 0, reactiveExportCounter = 0;
bool threePhase = false, twoPhase = false, counterEstimated = false; bool threePhase = false, twoPhase = false, counterEstimated = false;

View File

@@ -7,20 +7,20 @@
struct DayDataPoints { struct DayDataPoints {
uint8_t version; uint8_t version;
uint16_t hImport[24]; int16_t hImport[24];
time_t lastMeterReadTime; time_t lastMeterReadTime;
uint32_t activeImport; uint32_t activeImport;
uint32_t activeExport; uint32_t activeExport;
uint16_t hExport[24]; int16_t hExport[24];
}; // 112 bytes }; // 112 bytes
struct MonthDataPoints { struct MonthDataPoints {
uint8_t version; uint8_t version;
uint16_t dImport[31]; int16_t dImport[31];
time_t lastMeterReadTime; time_t lastMeterReadTime;
uint32_t activeImport; uint32_t activeImport;
uint32_t activeExport; uint32_t activeExport;
uint16_t dExport[31]; int16_t dExport[31];
}; // 141 bytes }; // 141 bytes
class AmsDataStorage { class AmsDataStorage {

View File

@@ -1,7 +1,7 @@
#ifndef _AMSTOMQTTBRIDGE_H #ifndef _AMSTOMQTTBRIDGE_H
#define _AMSTOMQTTBRIDGE_H #define _AMSTOMQTTBRIDGE_H
#define WIFI_CONNECTION_TIMEOUT 30000 #define WIFI_CONNECTION_TIMEOUT 30000;
#define INVALID_BUTTON_PIN 0xFFFFFFFF #define INVALID_BUTTON_PIN 0xFFFFFFFF

View File

@@ -119,6 +119,7 @@ DLMSParser *dlmsParser = NULL;
DSMRParser *dsmrParser = NULL; DSMRParser *dsmrParser = NULL;
void setup() { void setup() {
WiFiConfig wifi;
Serial.begin(115200); Serial.begin(115200);
if(!config.getGpioConfig(gpioConfig)) { if(!config.getGpioConfig(gpioConfig)) {
@@ -245,6 +246,7 @@ void setup() {
} }
Debug.setSerialEnabled(true); Debug.setSerialEnabled(true);
DebugConfig debug;
delay(1); delay(1);
float vcc = hw.getVcc(); float vcc = hw.getVcc();
@@ -307,7 +309,7 @@ void setup() {
} }
debugI(" flashing"); debugI(" flashing");
File firmwareFile = LittleFS.open(FILE_FIRMWARE, (char*) "r"); File firmwareFile = LittleFS.open(FILE_FIRMWARE, "r");
debugD(" firmware size: %d", firmwareFile.size()); debugD(" firmware size: %d", firmwareFile.size());
uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000; uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
debugD(" available: %d", maxSketchSpace); debugD(" available: %d", maxSketchSpace);
@@ -358,7 +360,7 @@ void setup() {
NtpConfig ntp; NtpConfig ntp;
if(config.getNtpConfig(ntp)) { if(config.getNtpConfig(ntp)) {
configTime(ntp.offset*10, ntp.summerOffset*10, ntp.enable ? strlen(ntp.server) > 0 ? ntp.server : (char*) F("pool.ntp.org") : (char*) F("")); // Add NTP server by default if none is configured configTime(ntp.offset*10, ntp.summerOffset*10, ntp.enable ? strlen(ntp.server) > 0 ? ntp.server : "pool.ntp.org" : ""); // Add NTP server by default if none is configured
sntp_servermode_dhcp(ntp.enable && ntp.dhcp ? 1 : 0); sntp_servermode_dhcp(ntp.enable && ntp.dhcp ? 1 : 0);
ntpEnabled = ntp.enable; ntpEnabled = ntp.enable;
TimeChangeRule std = {"STD", Last, Sun, Oct, 3, ntp.offset / 6}; TimeChangeRule std = {"STD", Last, Sun, Oct, 3, ntp.offset / 6};
@@ -434,10 +436,6 @@ void loop() {
} }
} }
if(now > 10000 && now - lastErrorBlink > 3000) {
errorBlink();
}
// Only do normal stuff if we're not booted as AP // Only do normal stuff if we're not booted as AP
if (WiFi.getMode() != WIFI_AP) { if (WiFi.getMode() != WIFI_AP) {
if (WiFi.status() != WL_CONNECTED) { if (WiFi.status() != WL_CONNECTED) {
@@ -473,7 +471,7 @@ void loop() {
if(strlen(wifi.hostname) > 0 && wifi.mdns) { if(strlen(wifi.hostname) > 0 && wifi.mdns) {
debugD("mDNS is enabled, using host: %s", wifi.hostname); debugD("mDNS is enabled, using host: %s", wifi.hostname);
if(MDNS.begin(wifi.hostname)) { if(MDNS.begin(wifi.hostname)) {
MDNS.addService(F("http"), F("tcp"), 80); MDNS.addService("http", "tcp", 80);
} else { } else {
debugE("Failed to set up mDNS!"); debugE("Failed to set up mDNS!");
} }
@@ -508,6 +506,10 @@ void loop() {
MDNS.update(); MDNS.update();
#endif #endif
if(now > 10000 && now - lastErrorBlink > 3000) {
errorBlink();
}
if (mqttEnabled || config.isMqttChanged()) { if (mqttEnabled || config.isMqttChanged()) {
if(mqtt == NULL || !mqtt->connected() || config.isMqttChanged()) { if(mqtt == NULL || !mqtt->connected() || config.isMqttChanged()) {
MQTT_connect(); MQTT_connect();
@@ -589,7 +591,7 @@ void loop() {
if(mqtt != NULL && mqttHandler != NULL && WiFi.getMode() != WIFI_AP && WiFi.status() == WL_CONNECTED && mqtt->connected() && !topic.isEmpty()) { if(mqtt != NULL && mqttHandler != NULL && WiFi.getMode() != WIFI_AP && WiFi.status() == WL_CONNECTED && mqtt->connected() && !topic.isEmpty()) {
mqttHandler->publishTemperatures(&config, &hw); mqttHandler->publishTemperatures(&config, &hw);
} }
debugD("Used %ld ms to update temperature", millis()-start); debugD("Used %d ms to update temperature", millis()-start);
} }
if(now - lastSysupdate > 10000) { if(now - lastSysupdate > 10000) {
if(mqtt != NULL && mqttHandler != NULL && WiFi.getMode() != WIFI_AP && WiFi.status() == WL_CONNECTED && mqtt->connected() && !topic.isEmpty()) { if(mqtt != NULL && mqttHandler != NULL && WiFi.getMode() != WIFI_AP && WiFi.status() == WL_CONNECTED && mqtt->connected() && !topic.isEmpty()) {
@@ -607,7 +609,7 @@ void loop() {
} }
void setupHanPort(uint8_t pin, uint32_t baud, uint8_t parityOrdinal, bool invert) { void setupHanPort(uint8_t pin, uint32_t baud, uint8_t parityOrdinal, bool invert) {
if(Debug.isActive(RemoteDebug::INFO)) Debug.printf((char*) F("(setupHanPort) Setting up HAN on pin %d with baud %d and parity %d\n"), pin, baud, parityOrdinal); if(Debug.isActive(RemoteDebug::INFO)) Debug.printf("(setupHanPort) Setting up HAN on pin %d with baud %d and parity %d\n", pin, baud, parityOrdinal);
HardwareSerial *hwSerial = NULL; HardwareSerial *hwSerial = NULL;
if(pin == 3 || pin == 113) { if(pin == 3 || pin == 113) {
@@ -658,11 +660,14 @@ void setupHanPort(uint8_t pin, uint32_t baud, uint8_t parityOrdinal, bool invert
#if defined(CONFIG_IDF_TARGET_ESP32S2) #if defined(CONFIG_IDF_TARGET_ESP32S2)
hwSerial->begin(baud, serialConfig, -1, -1, invert); hwSerial->begin(baud, serialConfig, -1, -1, invert);
hwSerial->setRxBufferSize(768);
uart_set_pin(UART_NUM_1, UART_PIN_NO_CHANGE, pin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); uart_set_pin(UART_NUM_1, UART_PIN_NO_CHANGE, pin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
#elif defined(ESP32) #elif defined(ESP32)
hwSerial->begin(baud, serialConfig, -1, -1, invert); hwSerial->begin(baud, serialConfig, -1, -1, invert);
hwSerial->setRxBufferSize(768);
#else #else
hwSerial->begin(baud, serialConfig, SERIAL_FULL, 1, invert); hwSerial->begin(baud, serialConfig, SERIAL_FULL, 1, invert);
hwSerial->setRxBufferSize(768);
#endif #endif
#if defined(ESP8266) #if defined(ESP8266)
@@ -720,25 +725,22 @@ void errorBlink() {
if(lastError == 3) if(lastError == 3)
lastError = 0; lastError = 0;
lastErrorBlink = millis(); lastErrorBlink = millis();
while(lastError < 3) { for(;lastError < 3;lastError++) {
switch(lastError++) { switch(lastError) {
case 0: case 0:
if(lastErrorBlink - meterState.getLastUpdateMillis() > 30000) { if(lastErrorBlink - meterState.getLastUpdateMillis() > 30000) {
debugW("No HAN data received last 30s, single blink");
hw.ledBlink(LED_RED, 1); // If no message received from AMS in 30 sec, blink once hw.ledBlink(LED_RED, 1); // If no message received from AMS in 30 sec, blink once
return; return;
} }
break; break;
case 1: case 1:
if(mqttEnabled && mqtt != NULL && mqtt->lastError() != 0) { if(mqttEnabled && mqtt != NULL && mqtt->lastError() != 0) {
debugW("MQTT connection not available, double blink");
hw.ledBlink(LED_RED, 2); // If MQTT error, blink twice hw.ledBlink(LED_RED, 2); // If MQTT error, blink twice
return; return;
} }
break; break;
case 2: case 2:
if(WiFi.getMode() != WIFI_AP && WiFi.status() != WL_CONNECTED) { if(WiFi.getMode() != WIFI_AP && WiFi.status() != WL_CONNECTED) {
debugW("WiFi not connected, tripe blink");
hw.ledBlink(LED_RED, 3); // If WiFi not connected, blink three times hw.ledBlink(LED_RED, 3); // If WiFi not connected, blink three times
return; return;
} }
@@ -762,14 +764,14 @@ void swapWifiMode() {
if (mode != WIFI_AP || !config.hasConfig()) { if (mode != WIFI_AP || !config.hasConfig()) {
if(Debug.isActive(RemoteDebug::INFO)) debugI("Swapping to AP mode"); if(Debug.isActive(RemoteDebug::INFO)) debugI("Swapping to AP mode");
WiFi.softAP((char*) F("AMS2MQTT")); WiFi.softAP("AMS2MQTT");
WiFi.mode(WIFI_AP); WiFi.mode(WIFI_AP);
if(dnsServer == NULL) { if(dnsServer == NULL) {
dnsServer = new DNSServer(); dnsServer = new DNSServer();
} }
dnsServer->setErrorReplyCode(DNSReplyCode::NoError); dnsServer->setErrorReplyCode(DNSReplyCode::NoError);
dnsServer->start(53, (char*) F("*"), WiFi.softAPIP()); dnsServer->start(53, "*", WiFi.softAPIP());
} else { } else {
if(Debug.isActive(RemoteDebug::INFO)) debugI("Swapping to STA mode"); if(Debug.isActive(RemoteDebug::INFO)) debugI("Swapping to STA mode");
if(dnsServer != NULL) { if(dnsServer != NULL) {
@@ -825,11 +827,6 @@ bool readHanPort() {
} }
if(pos == DATA_PARSE_INCOMPLETE) { if(pos == DATA_PARSE_INCOMPLETE) {
return false; return false;
} else if(pos == DATA_PARSE_UNKNOWN_DATA) {
len = len + hanSerial->readBytes(hanBuffer+len, BUF_SIZE_HAN-len);
debugPrint(hanBuffer, 0, len);
len = 0;
return false;
} }
if(pos == DATA_PARSE_INTERMEDIATE_SEGMENT) { if(pos == DATA_PARSE_INTERMEDIATE_SEGMENT) {
@@ -975,13 +972,13 @@ void printHanReadError(int pos) {
void debugPrint(byte *buffer, int start, int length) { void debugPrint(byte *buffer, int start, int length) {
for (int i = start; i < start + length; i++) { for (int i = start; i < start + length; i++) {
if (buffer[i] < 0x10) if (buffer[i] < 0x10)
Debug.print(F("0")); Debug.print("0");
Debug.print(buffer[i], HEX); Debug.print(buffer[i], HEX);
Debug.print(F(" ")); Debug.print(" ");
if ((i - start + 1) % 16 == 0) if ((i - start + 1) % 16 == 0)
Debug.println(""); Debug.println("");
else if ((i - start + 1) % 4 == 0) else if ((i - start + 1) % 4 == 0)
Debug.print(F(" ")); Debug.print(" ");
yield(); // Let other get some resources too yield(); // Let other get some resources too
} }
@@ -1054,6 +1051,7 @@ void WiFi_connect() {
} }
#endif #endif
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
WiFi.setSleep(WIFI_PS_MAX_MODEM);
#if defined(ESP32) #if defined(ESP32)
if(wifi.power >= 195) if(wifi.power >= 195)
WiFi.setTxPower(WIFI_POWER_19_5dBm); WiFi.setTxPower(WIFI_POWER_19_5dBm);
@@ -1095,7 +1093,7 @@ void WiFi_connect() {
if(strlen(wifi.dns2) > 0) { if(strlen(wifi.dns2) > 0) {
dns2.fromString(wifi.dns2); dns2.fromString(wifi.dns2);
} else if(dns1.toString().isEmpty()) { } else if(dns1.toString().isEmpty()) {
dns2.fromString(F("208.67.220.220")); // Add OpenDNS as second by default if nothing is configured dns2.fromString("208.67.220.220"); // Add OpenDNS as second by default if nothing is configured
} }
if(!WiFi.config(ip, gw, sn, dns1, dns2)) { if(!WiFi.config(ip, gw, sn, dns1, dns2)) {
debugE("Static IP configuration is invalid, not using"); debugE("Static IP configuration is invalid, not using");
@@ -1114,9 +1112,6 @@ void WiFi_connect() {
WiFi.setAutoReconnect(true); WiFi.setAutoReconnect(true);
WiFi.persistent(true); WiFi.persistent(true);
if(WiFi.begin(wifi.ssid, wifi.psk)) { if(WiFi.begin(wifi.ssid, wifi.psk)) {
if(wifi.sleep <= 2) {
WiFi.setSleep(wifi.sleep);
}
yield(); yield();
} else { } else {
if (Debug.isActive(RemoteDebug::ERROR)) debugI("Unable to start WiFi"); if (Debug.isActive(RemoteDebug::ERROR)) debugI("Unable to start WiFi");
@@ -1126,16 +1121,16 @@ void WiFi_connect() {
void mqttMessageReceived(String &topic, String &payload) { void mqttMessageReceived(String &topic, String &payload) {
debugI("Received message for topic %s", topic.c_str() ); debugI("Received message for topic %s", topic.c_str() );
//if(meterConfig.source == METER_SOURCE_MQTT) { if(meterConfig.source == METER_SOURCE_MQTT) {
//DataParserContext ctx = {static_cast<uint8_t>(payload.length()/2)}; DataParserContext ctx = {payload.length()/2};
//fromHex(hanBuffer, payload, ctx.length); fromHex(hanBuffer, payload, ctx.length);
//uint16_t pos = unwrapData(hanBuffer, ctx); uint16_t pos = unwrapData(hanBuffer, ctx);
// TODO: Run through DLMS/DMSR parser and apply AmsData // TODO: Run through DLMS/DMSR parser and apply AmsData
//} }
} }
int16_t unwrapData(uint8_t *buf, DataParserContext &context) { int16_t unwrapData(uint8_t *buf, DataParserContext &context) {
int16_t ret = 0; int16_t ret;
bool doRet = false; bool doRet = false;
uint16_t end = BUF_SIZE_HAN; uint16_t end = BUF_SIZE_HAN;
uint8_t tag = (*buf); uint8_t tag = (*buf);
@@ -1326,7 +1321,7 @@ void MQTT_connect() {
if(LittleFS.exists(FILE_MQTT_CA)) { if(LittleFS.exists(FILE_MQTT_CA)) {
debugI("Found MQTT CA file (%dkb free heap)", ESP.getFreeHeap()); debugI("Found MQTT CA file (%dkb free heap)", ESP.getFreeHeap());
file = LittleFS.open(FILE_MQTT_CA, (char*) "r"); file = LittleFS.open(FILE_MQTT_CA, "r");
#if defined(ESP8266) #if defined(ESP8266)
BearSSL::X509List *serverTrustedCA = new BearSSL::X509List(file); BearSSL::X509List *serverTrustedCA = new BearSSL::X509List(file);
mqttSecureClient->setTrustAnchors(serverTrustedCA); mqttSecureClient->setTrustAnchors(serverTrustedCA);
@@ -1339,12 +1334,12 @@ void MQTT_connect() {
if(LittleFS.exists(FILE_MQTT_CERT) && LittleFS.exists(FILE_MQTT_KEY)) { if(LittleFS.exists(FILE_MQTT_CERT) && LittleFS.exists(FILE_MQTT_KEY)) {
#if defined(ESP8266) #if defined(ESP8266)
debugI("Found MQTT certificate file (%dkb free heap)", ESP.getFreeHeap()); debugI("Found MQTT certificate file (%dkb free heap)", ESP.getFreeHeap());
file = LittleFS.open(FILE_MQTT_CERT, (char*) "r"); file = LittleFS.open(FILE_MQTT_CERT, "r");
BearSSL::X509List *serverCertList = new BearSSL::X509List(file); BearSSL::X509List *serverCertList = new BearSSL::X509List(file);
file.close(); file.close();
debugI("Found MQTT key file (%dkb free heap)", ESP.getFreeHeap()); debugI("Found MQTT key file (%dkb free heap)", ESP.getFreeHeap());
file = LittleFS.open(FILE_MQTT_KEY, (char*) "r"); file = LittleFS.open(FILE_MQTT_KEY, "r");
BearSSL::PrivateKey *serverPrivKey = new BearSSL::PrivateKey(file); BearSSL::PrivateKey *serverPrivKey = new BearSSL::PrivateKey(file);
file.close(); file.close();
@@ -1352,12 +1347,12 @@ void MQTT_connect() {
mqttSecureClient->setClientRSACert(serverCertList, serverPrivKey); mqttSecureClient->setClientRSACert(serverCertList, serverPrivKey);
#elif defined(ESP32) #elif defined(ESP32)
debugI("Found MQTT certificate file (%dkb free heap)", ESP.getFreeHeap()); debugI("Found MQTT certificate file (%dkb free heap)", ESP.getFreeHeap());
file = LittleFS.open(FILE_MQTT_CERT, (char*) "r"); file = LittleFS.open(FILE_MQTT_CERT, "r");
mqttSecureClient->loadCertificate(file, file.size()); mqttSecureClient->loadCertificate(file, file.size());
file.close(); file.close();
debugI("Found MQTT key file (%dkb free heap)", ESP.getFreeHeap()); debugI("Found MQTT key file (%dkb free heap)", ESP.getFreeHeap());
file = LittleFS.open(FILE_MQTT_KEY, (char*) "r"); file = LittleFS.open(FILE_MQTT_KEY, "r");
mqttSecureClient->loadPrivateKey(file, file.size()); mqttSecureClient->loadPrivateKey(file, file.size());
file.close(); file.close();
#endif #endif
@@ -1380,7 +1375,7 @@ void MQTT_connect() {
#if defined(ESP8266) #if defined(ESP8266)
if(mqttSecureClient) { if(mqttSecureClient) {
time_t epoch = time(nullptr); time_t epoch = time(nullptr);
debugD("Setting NTP time %lld for secure MQTT connection", epoch); debugD("Setting NTP time %i for secure MQTT connection", epoch);
mqttSecureClient->setX509Time(epoch); mqttSecureClient->setX509Time(epoch);
} }
#endif #endif
@@ -1423,7 +1418,7 @@ void configFileParse() {
return; return;
} }
File file = LittleFS.open(FILE_CFG, (char*) "r"); File file = LittleFS.open(FILE_CFG, "r");
bool lSys = false; bool lSys = false;
bool lWiFi = false; bool lWiFi = false;
@@ -1453,196 +1448,195 @@ void configFileParse() {
char* buf = (char*) commonBuffer; char* buf = (char*) commonBuffer;
memset(buf, 0, 1024); memset(buf, 0, 1024);
while((size = file.readBytesUntil('\n', buf, 1024)) > 0) { while((size = file.readBytesUntil('\n', buf, 1024)) > 0) {
if(strncmp_P(buf, PSTR("boardType "), 10) == 0) { if(strncmp(buf, "boardType ", 10) == 0) {
if(!lSys) { config.getSystemConfig(sys); lSys = true; }; if(!lSys) { config.getSystemConfig(sys); lSys = true; };
sys.boardType = String(buf+10).toInt(); sys.boardType = String(buf+10).toInt();
} else if(strncmp_P(buf, PSTR("ssid "), 5) == 0) { } else if(strncmp(buf, "ssid ", 5) == 0) {
if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; }; if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; };
memcpy(wifi.ssid, buf+5, size-5); memcpy(wifi.ssid, buf+5, size-5);
} else if(strncmp_P(buf, PSTR("psk "), 4) == 0) { } else if(strncmp(buf, "psk ", 4) == 0) {
if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; }; if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; };
memcpy(wifi.psk, buf+4, size-4); memcpy(wifi.psk, buf+4, size-4);
} else if(strncmp_P(buf, PSTR("ip "), 3) == 0) { } else if(strncmp(buf, "ip ", 3) == 0) {
if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; }; if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; };
memcpy(wifi.ip, buf+3, size-3); memcpy(wifi.ip, buf+3, size-3);
} else if(strncmp_P(buf, PSTR("gateway "), 8) == 0) { } else if(strncmp(buf, "gateway ", 8) == 0) {
if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; }; if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; };
memcpy(wifi.gateway, buf+8, size-8); memcpy(wifi.gateway, buf+8, size-8);
} else if(strncmp_P(buf, PSTR("subnet "), 7) == 0) { } else if(strncmp(buf, "subnet ", 7) == 0) {
if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; }; if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; };
memcpy(wifi.subnet, buf+7, size-7); memcpy(wifi.subnet, buf+7, size-7);
} else if(strncmp_P(buf, PSTR("dns1 "), 5) == 0) { } else if(strncmp(buf, "dns1 ", 5) == 0) {
if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; }; if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; };
memcpy(wifi.dns1, buf+5, size-5); memcpy(wifi.dns1, buf+5, size-5);
} else if(strncmp_P(buf, PSTR("dns2 "), 5) == 0) { } else if(strncmp(buf, "dns2 ", 5) == 0) {
if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; }; if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; };
memcpy(wifi.dns2, buf+5, size-5); memcpy(wifi.dns2, buf+5, size-5);
} else if(strncmp_P(buf, PSTR("hostname "), 9) == 0) { } else if(strncmp(buf, "hostname ", 9) == 0) {
if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; }; if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; };
memcpy(wifi.hostname, buf+9, size-9); memcpy(wifi.hostname, buf+9, size-9);
} else if(strncmp_P(buf, PSTR("mdns "), 5) == 0) { } else if(strncmp(buf, "mdns ", 5) == 0) {
if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; }; if(!lWiFi) { config.getWiFiConfig(wifi); lWiFi = true; };
wifi.mdns = String(buf+5).toInt() == 1;; wifi.mdns = String(buf+5).toInt() == 1;;
} else if(strncmp_P(buf, PSTR("mqttHost "), 9) == 0) { } else if(strncmp(buf, "mqttHost ", 9) == 0) {
if(!lMqtt) { config.getMqttConfig(mqtt); lMqtt = true; }; if(!lMqtt) { config.getMqttConfig(mqtt); lMqtt = true; };
memcpy(mqtt.host, buf+9, size-9); memcpy(mqtt.host, buf+9, size-9);
} else if(strncmp_P(buf, PSTR("mqttPort "), 9) == 0) { } else if(strncmp(buf, "mqttPort ", 9) == 0) {
if(!lMqtt) { config.getMqttConfig(mqtt); lMqtt = true; }; if(!lMqtt) { config.getMqttConfig(mqtt); lMqtt = true; };
mqtt.port = String(buf+9).toInt(); mqtt.port = String(buf+9).toInt();
} else if(strncmp_P(buf, PSTR("mqttClientId "), 13) == 0) { } else if(strncmp(buf, "mqttClientId ", 13) == 0) {
if(!lMqtt) { config.getMqttConfig(mqtt); lMqtt = true; }; if(!lMqtt) { config.getMqttConfig(mqtt); lMqtt = true; };
memcpy(mqtt.clientId, buf+13, size-13); memcpy(mqtt.clientId, buf+13, size-13);
} else if(strncmp_P(buf, PSTR("mqttPublishTopic "), 17) == 0) { } else if(strncmp(buf, "mqttPublishTopic ", 17) == 0) {
if(!lMqtt) { config.getMqttConfig(mqtt); lMqtt = true; }; if(!lMqtt) { config.getMqttConfig(mqtt); lMqtt = true; };
memcpy(mqtt.publishTopic, buf+17, size-17); memcpy(mqtt.publishTopic, buf+17, size-17);
} else if(strncmp_P(buf, PSTR("mqttUsername "), 13) == 0) { } else if(strncmp(buf, "mqttUsername ", 13) == 0) {
if(!lMqtt) { config.getMqttConfig(mqtt); lMqtt = true; }; if(!lMqtt) { config.getMqttConfig(mqtt); lMqtt = true; };
memcpy(mqtt.username, buf+13, size-13); memcpy(mqtt.username, buf+13, size-13);
} else if(strncmp_P(buf, PSTR("mqttPassword "), 13) == 0) { } else if(strncmp(buf, "mqttPassword ", 13) == 0) {
if(!lMqtt) { config.getMqttConfig(mqtt); lMqtt = true; }; if(!lMqtt) { config.getMqttConfig(mqtt); lMqtt = true; };
memcpy(mqtt.password, buf+13, size-13); memcpy(mqtt.password, buf+13, size-13);
} else if(strncmp_P(buf, PSTR("mqttPayloadFormat "), 18) == 0) { } else if(strncmp(buf, "mqttPayloadFormat ", 18) == 0) {
if(!lMqtt) { config.getMqttConfig(mqtt); lMqtt = true; }; if(!lMqtt) { config.getMqttConfig(mqtt); lMqtt = true; };
mqtt.payloadFormat = String(buf+18).toInt(); mqtt.payloadFormat = String(buf+18).toInt();
} else if(strncmp_P(buf, PSTR("mqttSsl "), 8) == 0) { } else if(strncmp(buf, "mqttSsl ", 8) == 0) {
if(!lMqtt) { config.getMqttConfig(mqtt); lMqtt = true; }; if(!lMqtt) { config.getMqttConfig(mqtt); lMqtt = true; };
mqtt.ssl = String(buf+8).toInt() == 1;; mqtt.ssl = String(buf+8).toInt() == 1;;
} else if(strncmp_P(buf, PSTR("webSecurity "), 12) == 0) { } else if(strncmp(buf, "webSecurity ", 12) == 0) {
if(!lWeb) { config.getWebConfig(web); lWeb = true; }; if(!lWeb) { config.getWebConfig(web); lWeb = true; };
web.security = String(buf+12).toInt(); web.security = String(buf+12).toInt();
} else if(strncmp_P(buf, PSTR("webUsername "), 12) == 0) { } else if(strncmp(buf, "webUsername ", 12) == 0) {
if(!lWeb) { config.getWebConfig(web); lWeb = true; }; if(!lWeb) { config.getWebConfig(web); lWeb = true; };
memcpy(web.username, buf+12, size-12); memcpy(web.username, buf+12, size-12);
} else if(strncmp_P(buf, PSTR("webPassword "), 12) == 0) { } else if(strncmp(buf, "webPassword ", 12) == 0) {
if(!lWeb) { config.getWebConfig(web); lWeb = true; }; if(!lWeb) { config.getWebConfig(web); lWeb = true; };
memcpy(web.username, buf+12, size-12); memcpy(web.username, buf+12, size-12);
} else if(strncmp_P(buf, PSTR("meterBaud "), 10) == 0) { } else if(strncmp(buf, "meterBaud ", 10) == 0) {
if(!lMeter) { config.getMeterConfig(meter); lMeter = true; }; if(!lMeter) { config.getMeterConfig(meter); lMeter = true; };
meter.baud = String(buf+10).toInt(); meter.baud = String(buf+10).toInt();
} else if(strncmp_P(buf, PSTR("meterParity "), 12) == 0) { } else if(strncmp(buf, "meterParity ", 12) == 0) {
if(!lMeter) { config.getMeterConfig(meter); lMeter = true; }; if(!lMeter) { config.getMeterConfig(meter); lMeter = true; };
if(strncmp_P(buf+12, PSTR("7N1"), 3) == 0) meter.parity = 2; if(strncmp(buf+12, "7N1", 3) == 0) meter.parity = 2;
if(strncmp_P(buf+12, PSTR("8N1"), 3) == 0) meter.parity = 3; if(strncmp(buf+12, "8N1", 3) == 0) meter.parity = 3;
if(strncmp_P(buf+12, PSTR("7E1"), 3) == 0) meter.parity = 10; if(strncmp(buf+12, "7E1", 3) == 0) meter.parity = 10;
if(strncmp_P(buf+12, PSTR("8E1"), 3) == 0) meter.parity = 11; if(strncmp(buf+12, "8E1", 3) == 0) meter.parity = 11;
} else if(strncmp_P(buf, PSTR("meterInvert "), 12) == 0) { } else if(strncmp(buf, "meterInvert ", 12) == 0) {
if(!lMeter) { config.getMeterConfig(meter); lMeter = true; }; if(!lMeter) { config.getMeterConfig(meter); lMeter = true; };
meter.invert = String(buf+12).toInt() == 1;; meter.invert = String(buf+12).toInt() == 1;;
} else if(strncmp_P(buf, PSTR("meterDistributionSystem "), 24) == 0) { } else if(strncmp(buf, "meterDistributionSystem ", 24) == 0) {
if(!lMeter) { config.getMeterConfig(meter); lMeter = true; }; if(!lMeter) { config.getMeterConfig(meter); lMeter = true; };
meter.distributionSystem = String(buf+24).toInt(); meter.distributionSystem = String(buf+24).toInt();
} else if(strncmp_P(buf, PSTR("meterMainFuse "), 14) == 0) { } else if(strncmp(buf, "meterMainFuse ", 14) == 0) {
if(!lMeter) { config.getMeterConfig(meter); lMeter = true; }; if(!lMeter) { config.getMeterConfig(meter); lMeter = true; };
meter.mainFuse = String(buf+14).toInt(); meter.mainFuse = String(buf+14).toInt();
} else if(strncmp_P(buf, PSTR("meterProductionCapacity "), 24) == 0) { } else if(strncmp(buf, "meterProductionCapacity ", 24) == 0) {
if(!lMeter) { config.getMeterConfig(meter); lMeter = true; }; if(!lMeter) { config.getMeterConfig(meter); lMeter = true; };
meter.productionCapacity = String(buf+24).toInt(); meter.productionCapacity = String(buf+24).toInt();
} else if(strncmp_P(buf, PSTR("meterEncryptionKey "), 19) == 0) { } else if(strncmp(buf, "meterEncryptionKey ", 19) == 0) {
if(!lMeter) { config.getMeterConfig(meter); lMeter = true; }; if(!lMeter) { config.getMeterConfig(meter); lMeter = true; };
fromHex(meter.encryptionKey, String(buf+19), 16); fromHex(meter.encryptionKey, String(buf+19), 16);
} else if(strncmp_P(buf, PSTR("meterAuthenticationKey "), 23) == 0) { } else if(strncmp(buf, "meterAuthenticationKey ", 23) == 0) {
if(!lMeter) { config.getMeterConfig(meter); lMeter = true; }; if(!lMeter) { config.getMeterConfig(meter); lMeter = true; };
fromHex(meter.authenticationKey, String(buf+19), 16); fromHex(meter.authenticationKey, String(buf+19), 16);
} else if(strncmp_P(buf, PSTR("gpioHanPin "), 11) == 0) { } else if(strncmp(buf, "gpioHanPin ", 11) == 0) {
if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; }; if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; };
gpio.hanPin = String(buf+11).toInt(); gpio.hanPin = String(buf+11).toInt();
} else if(strncmp_P(buf, PSTR("gpioApPin "), 10) == 0) { } else if(strncmp(buf, "gpioApPin ", 10) == 0) {
if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; }; if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; };
gpio.apPin = String(buf+10).toInt(); gpio.apPin = String(buf+10).toInt();
} else if(strncmp_P(buf, PSTR("gpioLedPin "), 11) == 0) { } else if(strncmp(buf, "gpioLedPin ", 11) == 0) {
if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; }; if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; };
gpio.ledPin = String(buf+11).toInt(); gpio.ledPin = String(buf+11).toInt();
} else if(strncmp_P(buf, PSTR("gpioLedInverted "), 16) == 0) { } else if(strncmp(buf, "gpioLedInverted ", 16) == 0) {
if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; }; if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; };
gpio.ledInverted = String(buf+16).toInt() == 1; gpio.ledInverted = String(buf+16).toInt() == 1;
} else if(strncmp_P(buf, PSTR("gpioLedPinRed "), 14) == 0) { } else if(strncmp(buf, "gpioLedPinRed ", 14) == 0) {
if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; }; if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; };
gpio.ledPinRed = String(buf+14).toInt(); gpio.ledPinRed = String(buf+14).toInt();
} else if(strncmp_P(buf, PSTR("gpioLedPinGreen "), 16) == 0) { } else if(strncmp(buf, "gpioLedPinGreen ", 16) == 0) {
if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; }; if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; };
gpio.ledPinGreen = String(buf+16).toInt(); gpio.ledPinGreen = String(buf+16).toInt();
} else if(strncmp_P(buf, PSTR("gpioLedPinBlue "), 15) == 0) { } else if(strncmp(buf, "gpioLedPinBlue ", 15) == 0) {
if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; }; if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; };
gpio.ledPinBlue = String(buf+15).toInt(); gpio.ledPinBlue = String(buf+15).toInt();
} else if(strncmp_P(buf, PSTR("gpioLedRgbInverted "), 19) == 0) { } else if(strncmp(buf, "gpioLedRgbInverted ", 19) == 0) {
if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; }; if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; };
gpio.ledRgbInverted = String(buf+19).toInt() == 1; gpio.ledRgbInverted = String(buf+19).toInt() == 1;
} else if(strncmp_P(buf, PSTR("gpioTempSensorPin "), 18) == 0) { } else if(strncmp(buf, "gpioTempSensorPin ", 18) == 0) {
if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; }; if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; };
gpio.tempSensorPin = String(buf+18).toInt(); gpio.tempSensorPin = String(buf+18).toInt();
} else if(strncmp_P(buf, PSTR("gpioTempAnalogSensorPin "), 24) == 0) { } else if(strncmp(buf, "gpioTempAnalogSensorPin ", 24) == 0) {
if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; }; if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; };
gpio.tempAnalogSensorPin = String(buf+24).toInt(); gpio.tempAnalogSensorPin = String(buf+24).toInt();
} else if(strncmp_P(buf, PSTR("gpioVccPin "), 11) == 0) { } else if(strncmp(buf, "gpioVccPin ", 11) == 0) {
if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; }; if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; };
gpio.vccPin = String(buf+11).toInt(); gpio.vccPin = String(buf+11).toInt();
} else if(strncmp_P(buf, PSTR("gpioVccOffset "), 14) == 0) { } else if(strncmp(buf, "gpioVccOffset ", 14) == 0) {
if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; }; if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; };
gpio.vccOffset = String(buf+14).toDouble() * 100; gpio.vccOffset = String(buf+14).toDouble() * 100;
} else if(strncmp_P(buf, PSTR("gpioVccMultiplier "), 18) == 0) { } else if(strncmp(buf, "gpioVccMultiplier ", 18) == 0) {
if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; }; if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; };
gpio.vccMultiplier = String(buf+18).toDouble() * 1000; gpio.vccMultiplier = String(buf+18).toDouble() * 1000;
} else if(strncmp_P(buf, PSTR("gpioVccBootLimit "), 17) == 0) { } else if(strncmp(buf, "gpioVccBootLimit ", 17) == 0) {
if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; }; if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; };
gpio.vccBootLimit = String(buf+17).toDouble() * 10; gpio.vccBootLimit = String(buf+17).toDouble() * 10;
} else if(strncmp_P(buf, PSTR("gpioVccResistorGnd "), 19) == 0) { } else if(strncmp(buf, "gpioVccResistorGnd ", 19) == 0) {
if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; }; if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; };
gpio.vccResistorGnd = String(buf+19).toInt(); gpio.vccResistorGnd = String(buf+19).toInt();
} else if(strncmp_P(buf, PSTR("gpioVccResistorVcc "), 19) == 0) { } else if(strncmp(buf, "gpioVccResistorVcc ", 19) == 0) {
if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; }; if(!lGpio) { config.getGpioConfig(gpio); lGpio = true; };
gpio.vccResistorVcc = String(buf+19).toInt(); gpio.vccResistorVcc = String(buf+19).toInt();
} else if(strncmp_P(buf, PSTR("domoticzElidx "), 14) == 0) { } else if(strncmp(buf, "domoticzElidx ", 14) == 0) {
if(!lDomo) { config.getDomoticzConfig(domo); lDomo = true; }; if(!lDomo) { config.getDomoticzConfig(domo); lDomo = true; };
domo.elidx = String(buf+14).toInt(); domo.elidx = String(buf+14).toInt();
} else if(strncmp_P(buf, PSTR("domoticzVl1idx "), 15) == 0) { } else if(strncmp(buf, "domoticzVl1idx ", 15) == 0) {
if(!lDomo) { config.getDomoticzConfig(domo); lDomo = true; }; if(!lDomo) { config.getDomoticzConfig(domo); lDomo = true; };
domo.vl1idx = String(buf+15).toInt(); domo.vl1idx = String(buf+15).toInt();
} else if(strncmp_P(buf, PSTR("domoticzVl2idx "), 15) == 0) { } else if(strncmp(buf, "domoticzVl2idx ", 15) == 0) {
if(!lDomo) { config.getDomoticzConfig(domo); lDomo = true; }; if(!lDomo) { config.getDomoticzConfig(domo); lDomo = true; };
domo.vl2idx = String(buf+15).toInt(); domo.vl2idx = String(buf+15).toInt();
} else if(strncmp_P(buf, PSTR("domoticzVl3idx "), 15) == 0) { } else if(strncmp(buf, "domoticzVl3idx ", 15) == 0) {
if(!lDomo) { config.getDomoticzConfig(domo); lDomo = true; }; if(!lDomo) { config.getDomoticzConfig(domo); lDomo = true; };
domo.vl3idx = String(buf+15).toInt(); domo.vl3idx = String(buf+15).toInt();
} else if(strncmp_P(buf, PSTR("domoticzCl1idx "), 15) == 0) { } else if(strncmp(buf, "domoticzCl1idx ", 15) == 0) {
if(!lDomo) { config.getDomoticzConfig(domo); lDomo = true; }; if(!lDomo) { config.getDomoticzConfig(domo); lDomo = true; };
domo.cl1idx = String(buf+15).toInt(); domo.cl1idx = String(buf+15).toInt();
} else if(strncmp_P(buf, PSTR("ntpEnable "), 10) == 0) { } else if(strncmp(buf, "ntpEnable ", 10) == 0) {
if(!lNtp) { config.getNtpConfig(ntp); lNtp = true; }; if(!lNtp) { config.getNtpConfig(ntp); lNtp = true; };
ntp.enable = String(buf+10).toInt() == 1; ntp.enable = String(buf+10).toInt() == 1;
} else if(strncmp_P(buf, PSTR("ntpDhcp "), 8) == 0) { } else if(strncmp(buf, "ntpDhcp ", 8) == 0) {
if(!lNtp) { config.getNtpConfig(ntp); lNtp = true; }; if(!lNtp) { config.getNtpConfig(ntp); lNtp = true; };
ntp.dhcp = String(buf+8).toInt() == 1; ntp.dhcp = String(buf+8).toInt() == 1;
} else if(strncmp_P(buf, PSTR("ntpOffset "), 10) == 0) { } else if(strncmp(buf, "ntpOffset ", 10) == 0) {
if(!lNtp) { config.getNtpConfig(ntp); lNtp = true; }; if(!lNtp) { config.getNtpConfig(ntp); lNtp = true; };
ntp.offset = String(buf+10).toInt() / 10; ntp.offset = String(buf+10).toInt() / 10;
} else if(strncmp_P(buf, PSTR("ntpSummerOffset "), 16) == 0) { } else if(strncmp(buf, "ntpSummerOffset ", 16) == 0) {
if(!lNtp) { config.getNtpConfig(ntp); lNtp = true; }; if(!lNtp) { config.getNtpConfig(ntp); lNtp = true; };
ntp.summerOffset = String(buf+16).toInt() / 10; ntp.summerOffset = String(buf+16).toInt() / 10;
} else if(strncmp_P(buf, PSTR("ntpServer "), 10) == 0) { } else if(strncmp(buf, "ntpServer ", 10) == 0) {
if(!lNtp) { config.getNtpConfig(ntp); lNtp = true; }; if(!lNtp) { config.getNtpConfig(ntp); lNtp = true; };
memcpy(ntp.server, buf+10, size-10); memcpy(ntp.server, buf+10, size-10);
} else if(strncmp_P(buf, PSTR("entsoeToken "), 12) == 0) { } else if(strncmp(buf, "entsoeToken ", 12) == 0) {
if(!lEntsoe) { config.getEntsoeConfig(entsoe); lEntsoe = true; }; if(!lEntsoe) { config.getEntsoeConfig(entsoe); lEntsoe = true; };
memcpy(entsoe.token, buf+12, size-12); memcpy(entsoe.token, buf+12, size-12);
} else if(strncmp_P(buf, PSTR("entsoeArea "), 11) == 0) { } else if(strncmp(buf, "entsoeArea ", 11) == 0) {
if(!lEntsoe) { config.getEntsoeConfig(entsoe); lEntsoe = true; }; if(!lEntsoe) { config.getEntsoeConfig(entsoe); lEntsoe = true; };
memcpy(entsoe.area, buf+11, size-11); memcpy(entsoe.area, buf+11, size-11);
} else if(strncmp_P(buf, PSTR("entsoeCurrency "), 15) == 0) { } else if(strncmp(buf, "entsoeCurrency ", 15) == 0) {
if(!lEntsoe) { config.getEntsoeConfig(entsoe); lEntsoe = true; }; if(!lEntsoe) { config.getEntsoeConfig(entsoe); lEntsoe = true; };
memcpy(entsoe.currency, buf+15, size-15); memcpy(entsoe.currency, buf+15, size-15);
} else if(strncmp_P(buf, PSTR("entsoeMultiplier "), 17) == 0) { } else if(strncmp(buf, "entsoeMultiplier ", 17) == 0) {
if(!lEntsoe) { config.getEntsoeConfig(entsoe); lEntsoe = true; }; if(!lEntsoe) { config.getEntsoeConfig(entsoe); lEntsoe = true; };
entsoe.multiplier = String(buf+17).toDouble() * 1000; entsoe.multiplier = String(buf+17).toDouble() * 1000;
} else if(strncmp_P(buf, PSTR("thresholds "), 11) == 0) { } else if(strncmp(buf, "thresholds ", 11) == 0) {
if(!lEac) { config.getEnergyAccountingConfig(eac); lEac = true; }; if(!lEac) { config.getEnergyAccountingConfig(eac); lEac = true; };
int i = 0; int i = 0;
char * pch = strtok (buf+11," "); char * pch = strtok (buf+11," ");
while (pch != NULL && i < 10) { while (pch != NULL) {
eac.thresholds[i++] = String(pch).toInt(); eac.thresholds[i++] = String(pch).toInt();
pch = strtok (NULL, " "); pch = strtok (NULL, " ");
} }
eac.hours = String(pch).toInt(); } else if(strncmp(buf, "dayplot ", 8) == 0) {
} else if(strncmp_P(buf, PSTR("dayplot "), 8) == 0) {
int i = 0; int i = 0;
DayDataPoints day = { 4 }; // Use a version we know the multiplier of the data points DayDataPoints day = { 4 }; // Use a version we know the multiplier of the data points
char * pch = strtok (buf+8," "); char * pch = strtok (buf+8," ");
@@ -1665,7 +1659,7 @@ void configFileParse() {
} }
ds.setDayData(day); ds.setDayData(day);
sDs = true; sDs = true;
} else if(strncmp_P(buf, PSTR("monthplot "), 10) == 0) { } else if(strncmp(buf, "monthplot ", 10) == 0) {
int i = 0; int i = 0;
MonthDataPoints month = { 5 }; // Use a version we know the multiplier of the data points MonthDataPoints month = { 5 }; // Use a version we know the multiplier of the data points
char * pch = strtok (buf+10," "); char * pch = strtok (buf+10," ");
@@ -1688,7 +1682,7 @@ void configFileParse() {
} }
ds.setMonthData(month); ds.setMonthData(month);
sDs = true; sDs = true;
} else if(strncmp_P(buf, PSTR("energyaccounting "), 17) == 0) { } else if(strncmp(buf, "energyaccounting ", 17) == 0) {
uint8_t i = 0; uint8_t i = 0;
EnergyAccountingData ead = { 4, 0, EnergyAccountingData ead = { 4, 0,
0, 0, 0, 0, 0, 0,
@@ -1753,7 +1747,6 @@ void configFileParse() {
if(lDomo) config.setDomoticzConfig(domo); if(lDomo) config.setDomoticzConfig(domo);
if(lNtp) config.setNtpConfig(ntp); if(lNtp) config.setNtpConfig(ntp);
if(lEntsoe) config.setEntsoeConfig(entsoe); if(lEntsoe) config.setEntsoeConfig(entsoe);
if(lEac) config.setEnergyAccountingConfig(eac);
if(sDs) ds.save(); if(sDs) ds.save();
if(sEa) ea.save(); if(sEa) ea.save();
config.save(); config.save();

View File

@@ -57,7 +57,7 @@ bool EnergyAccounting::update(AmsData* amsData) {
for(uint8_t i = 0; i < 5; i++) { for(uint8_t i = 0; i < 5; i++) {
debugger->printf("(EnergyAccounting) Peak hour from day %d: %d\n", data.peaks[i].day, data.peaks[i].value*10); debugger->printf("(EnergyAccounting) Peak hour from day %d: %d\n", data.peaks[i].day, data.peaks[i].value*10);
} }
debugger->printf("(EnergyAccounting) Loaded cost yesterday: %.2f, this month: %d, last month: %d\n", data.costYesterday / 10.0, data.costThisMonth, data.costLastMonth); debugger->printf("(EnergyAccounting) Loaded cost yesterday: %d, this month: %d, last month: %d\n", data.costYesterday / 10.0, data.costThisMonth, data.costLastMonth);
} }
init = true; init = true;
} }
@@ -237,7 +237,7 @@ float EnergyAccounting::getMonthMax() {
uint32_t maxHour = 0.0; uint32_t maxHour = 0.0;
bool included[5] = { false, false, false, false, false }; bool included[5] = { false, false, false, false, false };
for(uint8_t x = 0;x < min((uint8_t) 5, config->hours); x++) { while(count < config->hours && count <= 5) {
uint8_t maxIdx = 0; uint8_t maxIdx = 0;
uint16_t maxVal = 0; uint16_t maxVal = 0;
for(uint8_t i = 0; i < 5; i++) { for(uint8_t i = 0; i < 5; i++) {
@@ -248,10 +248,8 @@ float EnergyAccounting::getMonthMax() {
maxIdx = i; maxIdx = i;
} }
} }
if(maxVal > 0) { included[maxIdx] = true;
included[maxIdx] = true; count++;
count++;
}
} }
for(uint8_t i = 0; i < 5; i++) { for(uint8_t i = 0; i < 5; i++) {
@@ -267,7 +265,7 @@ float EnergyAccounting::getPeak(uint8_t num) {
uint8_t count = 0; uint8_t count = 0;
bool included[5] = { false, false, false, false, false }; bool included[5] = { false, false, false, false, false };
for(uint8_t x = 0;x < min((uint8_t) 5, config->hours); x++) { while(count < config->hours && count <= 5) {
uint8_t maxIdx = 0; uint8_t maxIdx = 0;
uint16_t maxVal = 0; uint16_t maxVal = 0;
for(uint8_t i = 0; i < 5; i++) { for(uint8_t i = 0; i < 5; i++) {
@@ -277,10 +275,8 @@ float EnergyAccounting::getPeak(uint8_t num) {
maxIdx = i; maxIdx = i;
} }
} }
if(maxVal > 0) { included[maxIdx] = true;
included[maxIdx] = true; count++;
count++;
}
} }
uint8_t pos = 0; uint8_t pos = 0;

View File

@@ -373,7 +373,8 @@ bool HwTools::ledBlink(uint8_t color, uint8_t blink) {
if(!ledOn(color)) return false; if(!ledOn(color)) return false;
delay(50); delay(50);
ledOff(color); ledOff(color);
delay(200); if(i != blink)
delay(50);
} }
return true; return true;
} }

View File

@@ -296,38 +296,6 @@ IEC6205675::IEC6205675(const char* d, uint8_t useMeterType, MeterConfig* meterCo
l3PowerFactor = val; l3PowerFactor = val;
} }
val = getNumber(AMS_OBIS_ACTIVE_IMPORT_L1, sizeof(AMS_OBIS_ACTIVE_IMPORT_L1), ((char *) (d)));
if (val != NOVALUE) {
listType = 4;
l1activeImportPower = val;
}
val = getNumber(AMS_OBIS_ACTIVE_IMPORT_L2, sizeof(AMS_OBIS_ACTIVE_IMPORT_L2), ((char *) (d)));
if (val != NOVALUE) {
listType = 4;
l2activeImportPower = val;
}
val = getNumber(AMS_OBIS_ACTIVE_IMPORT_L3, sizeof(AMS_OBIS_ACTIVE_IMPORT_L3), ((char *) (d)));
if (val != NOVALUE) {
listType = 4;
l3activeImportPower = val;
}
val = getNumber(AMS_OBIS_ACTIVE_EXPORT_L1, sizeof(AMS_OBIS_ACTIVE_EXPORT_L1), ((char *) (d)));
if (val != NOVALUE) {
listType = 4;
l1activeExportPower = val;
}
val = getNumber(AMS_OBIS_ACTIVE_EXPORT_L2, sizeof(AMS_OBIS_ACTIVE_EXPORT_L2), ((char *) (d)));
if (val != NOVALUE) {
listType = 4;
l2activeExportPower = val;
}
val = getNumber(AMS_OBIS_ACTIVE_EXPORT_L3, sizeof(AMS_OBIS_ACTIVE_EXPORT_L3), ((char *) (d)));
if (val != NOVALUE) {
listType = 4;
l3activeExportPower = val;
}
if(meterType == AmsTypeKamstrup) { if(meterType == AmsTypeKamstrup) {
if(listType >= 3) { if(listType >= 3) {
activeImportCounter *= 10; activeImportCounter *= 10;
@@ -368,14 +336,12 @@ IEC6205675::IEC6205675(const char* d, uint8_t useMeterType, MeterConfig* meterCo
if(mid != NULL) { if(mid != NULL) {
switch(mid->base.type) { switch(mid->base.type) {
case CosemTypeString: case CosemTypeString:
memcpy(str, mid->oct.data, mid->oct.length); memcpy(&meterId, mid->str.data, mid->str.length);
str[mid->oct.length] = 0x00; meterId[mid->str.length] = 0;
meterId = String(str);
break; break;
case CosemTypeOctetString: case CosemTypeOctetString:
memcpy(str, mid->str.data, mid->str.length); memcpy(&meterId, mid->oct.data, mid->oct.length);
str[mid->str.length] = 0x00; meterId[mid->oct.length] = 0;
meterId = String(str);
break; break;
} }
} }

View File

@@ -49,12 +49,6 @@ private:
uint8_t AMS_OBIS_POWER_FACTOR_L1[4] = { 33, 7, 0, 255 }; uint8_t AMS_OBIS_POWER_FACTOR_L1[4] = { 33, 7, 0, 255 };
uint8_t AMS_OBIS_POWER_FACTOR_L2[4] = { 53, 7, 0, 255 }; uint8_t AMS_OBIS_POWER_FACTOR_L2[4] = { 53, 7, 0, 255 };
uint8_t AMS_OBIS_POWER_FACTOR_L3[4] = { 73, 7, 0, 255 }; uint8_t AMS_OBIS_POWER_FACTOR_L3[4] = { 73, 7, 0, 255 };
uint8_t AMS_OBIS_ACTIVE_IMPORT_L1[4] = { 21, 7, 0, 255 };
uint8_t AMS_OBIS_ACTIVE_IMPORT_L2[4] = { 41, 7, 0, 255 };
uint8_t AMS_OBIS_ACTIVE_IMPORT_L3[4] = { 61, 7, 0, 255 };
uint8_t AMS_OBIS_ACTIVE_EXPORT_L1[4] = { 22, 7, 0, 255 };
uint8_t AMS_OBIS_ACTIVE_EXPORT_L2[4] = { 42, 7, 0, 255 };
uint8_t AMS_OBIS_ACTIVE_EXPORT_L3[4] = { 62, 7, 0, 255 };
}; };
#endif #endif

View File

@@ -25,38 +25,38 @@ LNG::LNG(const char* payload, uint8_t useMeterType, MeterConfig* meterConfig, Da
if(descriptor->obis[3] == 7) { if(descriptor->obis[3] == 7) {
if(descriptor->obis[4] == 0) { if(descriptor->obis[4] == 0) {
o170 = ntohl(item->dlu.data); o170 = ntohl(item->dlu.data);
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu (dlu)", ntohl(item->dlu.data)); if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %d (dlu)", ntohl(item->dlu.data));
} }
} else if(descriptor->obis[3] == 8) { } else if(descriptor->obis[3] == 8) {
if(descriptor->obis[4] == 0) { if(descriptor->obis[4] == 0) {
activeImportCounter = ntohl(item->dlu.data) / 1000.0; activeImportCounter = ntohl(item->dlu.data) / 1000.0;
listType = listType >= 3 ? listType : 3; listType = listType >= 3 ? listType : 3;
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu (dlu)", ntohl(item->dlu.data)); if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %d (dlu)", ntohl(item->dlu.data));
} else if(descriptor->obis[4] == 1) { } else if(descriptor->obis[4] == 1) {
o181 = ntohl(item->dlu.data); o181 = ntohl(item->dlu.data);
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu (dlu)", ntohl(item->dlu.data)); if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %d (dlu)", ntohl(item->dlu.data));
} else if(descriptor->obis[4] == 2) { } else if(descriptor->obis[4] == 2) {
o182 = ntohl(item->dlu.data); o182 = ntohl(item->dlu.data);
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu (dlu)", ntohl(item->dlu.data)); if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %d (dlu)", ntohl(item->dlu.data));
} }
} }
} else if(descriptor->obis[2] == 2) { } else if(descriptor->obis[2] == 2) {
if(descriptor->obis[3] == 7) { if(descriptor->obis[3] == 7) {
if(descriptor->obis[4] == 0) { if(descriptor->obis[4] == 0) {
o270 = ntohl(item->dlu.data); o270 = ntohl(item->dlu.data);
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu (dlu)", ntohl(item->dlu.data)); if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %d (dlu)", ntohl(item->dlu.data));
} }
} else if(descriptor->obis[3] == 8) { } else if(descriptor->obis[3] == 8) {
if(descriptor->obis[4] == 0) { if(descriptor->obis[4] == 0) {
activeExportCounter = ntohl(item->dlu.data) / 1000.0; activeExportCounter = ntohl(item->dlu.data) / 1000.0;
listType = listType >= 3 ? listType : 3; listType = listType >= 3 ? listType : 3;
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu (dlu)", ntohl(item->dlu.data)); if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %d (dlu)", ntohl(item->dlu.data));
} else if(descriptor->obis[4] == 1) { } else if(descriptor->obis[4] == 1) {
o281 = ntohl(item->dlu.data); o281 = ntohl(item->dlu.data);
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu (dlu)", ntohl(item->dlu.data)); if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %d (dlu)", ntohl(item->dlu.data));
} else if(descriptor->obis[4] == 2) { } else if(descriptor->obis[4] == 2) {
o282 = ntohl(item->dlu.data); o282 = ntohl(item->dlu.data);
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu (dlu)", ntohl(item->dlu.data)); if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %d (dlu)", ntohl(item->dlu.data));
} }
} }
} else if(descriptor->obis[2] == 96) { } else if(descriptor->obis[2] == 96) {

View File

@@ -1,8 +1,5 @@
#include "Uptime.h" #include "Uptime.h"
uint32_t _uptime_last_value = 0;
uint32_t _uptime_rollovers = 0;
uint64_t millis64() { uint64_t millis64() {
uint32_t new_low32 = millis(); uint32_t new_low32 = millis();
if (new_low32 < _uptime_last_value) _uptime_rollovers++; if (new_low32 < _uptime_last_value) _uptime_rollovers++;

View File

@@ -3,6 +3,8 @@
#include "Arduino.h" #include "Arduino.h"
static uint32_t _uptime_last_value = 0;
static uint32_t _uptime_rollovers = 0;
uint64_t millis64(); uint64_t millis64();
#endif #endif

View File

@@ -4,6 +4,7 @@ int8_t DSMRParser::parse(uint8_t *buf, DataParserContext &ctx, bool verified) {
uint16_t crcPos = 0; uint16_t crcPos = 0;
bool reachedEnd = verified; bool reachedEnd = verified;
uint8_t lastByte = 0x00; uint8_t lastByte = 0x00;
int c = 0;
for(int pos = 0; pos < ctx.length; pos++) { for(int pos = 0; pos < ctx.length; pos++) {
uint8_t b = *(buf+pos); uint8_t b = *(buf+pos);
if(pos == 0 && b != '/') return DATA_PARSE_BOUNDRY_FLAG_MISSING; if(pos == 0 && b != '/') return DATA_PARSE_BOUNDRY_FLAG_MISSING;

View File

@@ -27,7 +27,7 @@ int8_t GCMParser::parse(uint8_t *d, DataParserContext &ctx) {
memcpy(ctx.system_title, ptr, systemTitleLength); memcpy(ctx.system_title, ptr, systemTitleLength);
memcpy(initialization_vector, ctx.system_title, systemTitleLength); memcpy(initialization_vector, ctx.system_title, systemTitleLength);
int len = 0; int len;
int headersize = 2 + systemTitleLength; int headersize = 2 + systemTitleLength;
ptr += systemTitleLength; ptr += systemTitleLength;
if(((*ptr) & 0xFF) == 0x81) { if(((*ptr) & 0xFF) == 0x81) {

View File

@@ -5,6 +5,8 @@
int8_t HDLCParser::parse(uint8_t *d, DataParserContext &ctx) { int8_t HDLCParser::parse(uint8_t *d, DataParserContext &ctx) {
int len; int len;
uint8_t flag = *d;
uint8_t* ptr; uint8_t* ptr;
if(ctx.length < 3) if(ctx.length < 3)
return DATA_PARSE_INCOMPLETE; return DATA_PARSE_INCOMPLETE;

View File

@@ -1,6 +1,7 @@
#include "LlcParser.h" #include "LlcParser.h"
int8_t LLCParser::parse(uint8_t *buf, DataParserContext &ctx) { int8_t LLCParser::parse(uint8_t *buf, DataParserContext &ctx) {
LLCHeader* llc = (LLCHeader*) buf;
ctx.length -= 3; ctx.length -= 3;
return 3; return 3;
} }

View File

@@ -5,6 +5,8 @@ int8_t MBUSParser::parse(uint8_t *d, DataParserContext &ctx) {
int headersize = 3; int headersize = 3;
int footersize = 1; int footersize = 1;
uint8_t flag = *d;
uint8_t* ptr; uint8_t* ptr;
// https://m-bus.com/documentation-wired/06-application-layer // https://m-bus.com/documentation-wired/06-application-layer

View File

@@ -22,7 +22,7 @@ void DnbCurrParser::flush() {
} }
size_t DnbCurrParser::write(const uint8_t *buffer, size_t size) { size_t DnbCurrParser::write(const uint8_t *buffer, size_t size) {
for(size_t i = 0; i < size; i++) { for(int i = 0; i < size; i++) {
write(buffer[i]); write(buffer[i]);
} }
return size; return size;

View File

@@ -5,10 +5,6 @@ EntsoeA44Parser::EntsoeA44Parser() {
for(int i = 0; i < 24; i++) points[i] = ENTSOE_NO_VALUE; for(int i = 0; i < 24; i++) points[i] = ENTSOE_NO_VALUE;
} }
EntsoeA44Parser::~EntsoeA44Parser() {
}
char* EntsoeA44Parser::getCurrency() { char* EntsoeA44Parser::getCurrency() {
return currency; return currency;
} }
@@ -39,7 +35,7 @@ void EntsoeA44Parser::flush() {
} }
size_t EntsoeA44Parser::write(const uint8_t *buffer, size_t size) { size_t EntsoeA44Parser::write(const uint8_t *buffer, size_t size) {
for(size_t i = 0; i < size; i++) { for(int i = 0; i < size; i++) {
write(buffer[i]); write(buffer[i]);
} }
return size; return size;

View File

@@ -14,7 +14,6 @@
class EntsoeA44Parser: public Stream { class EntsoeA44Parser: public Stream {
public: public:
EntsoeA44Parser(); EntsoeA44Parser();
virtual ~EntsoeA44Parser();
char* getCurrency(); char* getCurrency();
char* getMeasurementUnit(); char* getMeasurementUnit();

View File

@@ -106,11 +106,11 @@ bool EntsoeApi::loop() {
if(midnightMillis == 0) { if(midnightMillis == 0) {
uint32_t curDayMillis = (((((tm.Hour * 60) + tm.Minute) * 60) + tm.Second) * 1000); uint32_t curDayMillis = (((((tm.Hour * 60) + tm.Minute) * 60) + tm.Second) * 1000);
midnightMillis = now + (SECS_PER_DAY * 1000) - curDayMillis; midnightMillis = now + (SECS_PER_DAY * 1000) - curDayMillis;
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf("(EntsoeApi) Setting midnight millis %llu\n", midnightMillis); if(debugger->isActive(RemoteDebug::INFO)) debugger->printf("(EntsoeApi) Setting midnight millis %lu\n", midnightMillis);
currentDay = tm.Day; currentDay = tm.Day;
return false; return false;
} else if(now > midnightMillis && currentDay != tm.Day) { } else if(now > midnightMillis && currentDay != tm.Day) {
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf("(EntsoeApi) Rotating price objects at %lld\n", t); if(debugger->isActive(RemoteDebug::INFO)) debugger->printf("(EntsoeApi) Rotating price objects at %lu\n", t);
if(today != NULL) delete today; if(today != NULL) delete today;
if(tomorrow != NULL) { if(tomorrow != NULL) {
today = tomorrow; today = tomorrow;

View File

@@ -15,7 +15,6 @@ public:
this->mqtt = mqtt; this->mqtt = mqtt;
this->json = buf; this->json = buf;
}; };
virtual ~AmsMqttHandler() {};
virtual bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea); virtual bool publish(AmsData* data, AmsData* previousState, EnergyAccounting* ea);
virtual bool publishTemperatures(AmsConfiguration*, HwTools*); virtual bool publishTemperatures(AmsConfiguration*, HwTools*);

View File

@@ -6,7 +6,6 @@
#include "web/root/ha1_json.h" #include "web/root/ha1_json.h"
#include "web/root/ha2_json.h" #include "web/root/ha2_json.h"
#include "web/root/ha3_json.h" #include "web/root/ha3_json.h"
#include "web/root/ha4_json.h"
#include "web/root/jsonsys_json.h" #include "web/root/jsonsys_json.h"
#include "web/root/jsonprices_json.h" #include "web/root/jsonprices_json.h"
#include "web/root/hadiscover_json.h" #include "web/root/hadiscover_json.h"
@@ -34,8 +33,8 @@ bool HomeAssistantMqttHandler::publish(AmsData* data, AmsData* previousState, En
snprintf_P(json, BufferSize, HA1_JSON, snprintf_P(json, BufferSize, HA1_JSON,
data->getActiveImportPower() data->getActiveImportPower()
); );
mqtt->publish(topic + "/power", json); return mqtt->publish(topic + "/power", json);
} else if(data->getListType() <= 3) { // publish power counts and volts/amps } else if(data->getListType() >= 2) { // publish power counts and volts/amps
snprintf_P(json, BufferSize, HA3_JSON, snprintf_P(json, BufferSize, HA3_JSON,
data->getListId().c_str(), data->getListId().c_str(),
data->getMeterId().c_str(), data->getMeterId().c_str(),
@@ -49,63 +48,15 @@ bool HomeAssistantMqttHandler::publish(AmsData* data, AmsData* previousState, En
data->getL3Current(), data->getL3Current(),
data->getL1Voltage(), data->getL1Voltage(),
data->getL2Voltage(), data->getL2Voltage(),
data->getL3Voltage()
);
mqtt->publish(topic + "/power", json);
} else if(data->getListType() == 4) { // publish power counts and volts/amps/phase power and PF
snprintf_P(json, BufferSize, HA4_JSON,
data->getListId().c_str(),
data->getMeterId().c_str(),
meterModel.c_str(),
data->getActiveImportPower(),
data->getL1ActiveImportPower(),
data->getL2ActiveImportPower(),
data->getL3ActiveImportPower(),
data->getReactiveImportPower(),
data->getActiveExportPower(),
data->getL1ActiveExportPower(),
data->getL2ActiveExportPower(),
data->getL3ActiveExportPower(),
data->getReactiveExportPower(),
data->getL1Current(),
data->getL2Current(),
data->getL3Current(),
data->getL1Voltage(),
data->getL2Voltage(),
data->getL3Voltage(), data->getL3Voltage(),
data->getPowerFactor() == 0 ? 1 : data->getPowerFactor(), data->getPowerFactor() == 0 ? 1 : data->getPowerFactor(),
data->getPowerFactor() == 0 ? 1 : data->getL1PowerFactor(), data->getPowerFactor() == 0 ? 1 : data->getL1PowerFactor(),
data->getPowerFactor() == 0 ? 1 : data->getL2PowerFactor(), data->getPowerFactor() == 0 ? 1 : data->getL2PowerFactor(),
data->getPowerFactor() == 0 ? 1 : data->getL3PowerFactor() data->getPowerFactor() == 0 ? 1 : data->getL3PowerFactor()
); );
mqtt->publish(topic + "/power", json); return mqtt->publish(topic + "/power", json);
} }
return false;}
String peaks = "";
uint8_t peakCount = ea->getConfig()->hours;
if(peakCount > 5) peakCount = 5;
for(uint8_t i = 1; i <= peakCount; i++) {
if(!peaks.isEmpty()) peaks += ",";
peaks += String(ea->getPeak(i), 2);
}
snprintf_P(json, BufferSize, REALTIME_JSON,
ea->getMonthMax(),
peaks.c_str(),
ea->getCurrentThreshold(),
ea->getUseThisHour(),
ea->getCostThisHour(),
ea->getProducedThisHour(),
ea->getUseToday(),
ea->getCostToday(),
ea->getProducedToday(),
ea->getUseThisMonth(),
ea->getCostThisMonth(),
ea->getProducedThisMonth()
);
mqtt->publish(topic + "/realtime", json);
return true;
}
bool HomeAssistantMqttHandler::publishTemperatures(AmsConfiguration* config, HwTools* hw) { bool HomeAssistantMqttHandler::publishTemperatures(AmsConfiguration* config, HwTools* hw) {
int count = hw->getTempSensorCount(); int count = hw->getTempSensorCount();
@@ -141,7 +92,7 @@ bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) {
time_t now = time(nullptr); time_t now = time(nullptr);
float min1hr = 0.0, min3hr = 0.0, min6hr = 0.0; float min1hr, min3hr, min6hr;
int8_t min1hrIdx = -1, min3hrIdx = -1, min6hrIdx = -1; int8_t min1hrIdx = -1, min3hrIdx = -1, min6hrIdx = -1;
float min = INT16_MAX, max = INT16_MIN; float min = INT16_MAX, max = INT16_MIN;
float values[24]; float values[24];
@@ -191,7 +142,7 @@ bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) {
} }
char ts1hr[24]; char ts1hr[21];
if(min1hrIdx > -1) { if(min1hrIdx > -1) {
time_t ts = now + (SECS_PER_HOUR * min1hrIdx); time_t ts = now + (SECS_PER_HOUR * min1hrIdx);
//Serial.printf("1hr: %d %lu\n", min1hrIdx, ts); //Serial.printf("1hr: %d %lu\n", min1hrIdx, ts);
@@ -199,7 +150,7 @@ bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) {
breakTime(ts, tm); breakTime(ts, tm);
sprintf(ts1hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour); sprintf(ts1hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour);
} }
char ts3hr[24]; char ts3hr[21];
if(min3hrIdx > -1) { if(min3hrIdx > -1) {
time_t ts = now + (SECS_PER_HOUR * min3hrIdx); time_t ts = now + (SECS_PER_HOUR * min3hrIdx);
//Serial.printf("3hr: %d %lu\n", min3hrIdx, ts); //Serial.printf("3hr: %d %lu\n", min3hrIdx, ts);
@@ -207,7 +158,7 @@ bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) {
breakTime(ts, tm); breakTime(ts, tm);
sprintf(ts3hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour); sprintf(ts3hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour);
} }
char ts6hr[24]; char ts6hr[21];
if(min6hrIdx > -1) { if(min6hrIdx > -1) {
time_t ts = now + (SECS_PER_HOUR * min6hrIdx); time_t ts = now + (SECS_PER_HOUR * min6hrIdx);
//Serial.printf("6hr: %d %lu\n", min6hrIdx, ts); //Serial.printf("6hr: %d %lu\n", min6hrIdx, ts);
@@ -236,7 +187,7 @@ bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) {
ts3hr, ts3hr,
ts6hr ts6hr
); );
return mqtt->publish(topic + "/prices", json, true, 0); return mqtt->publish(topic + "/prices", json);
} }
bool HomeAssistantMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea) { bool HomeAssistantMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea) {
@@ -266,48 +217,28 @@ bool HomeAssistantMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, Energ
#endif #endif
String haUrl = "http://" + haUID + ".local/"; String haUrl = "http://" + haUID + ".local/";
// Could this be necessary? haUID.replace("-", "_"); // Could this be necessary? haUID.replace("-", "_");
uint8_t peakCount = ea->getConfig()->hours;
if(peakCount > 5) peakCount = 5;
uint8_t peaks = 0; for(int i=0;i<17;i++){
for(int i=0;i<HA_SENSOR_COUNT;i++) {
HomeAssistantSensor sensor = HA_SENSORS[i];
String uid = String(sensor.path);
uid.replace(".", "");
uid.replace("[", "");
uid.replace("]", "");
uid.replace("'", "");
String uom = String(sensor.uom);
if(strncmp(sensor.devcl, "monetary", 8) == 0) {
if(eapi == NULL) continue;
uom = String(eapi->getCurrency());
}
if(strncmp(sensor.path, "peaks[", 6) == 0) {
if(peaks >= peakCount) continue;
peaks++;
}
snprintf_P(json, BufferSize, HADISCOVER_JSON, snprintf_P(json, BufferSize, HADISCOVER_JSON,
sensor.name, FPSTR(HA_NAMES[i]),
topic.c_str(), sensor.topic, topic.c_str(), FPSTR(HA_TOPICS[i]),
haUID.c_str(), uid.c_str(), haUID.c_str(), FPSTR(HA_PARAMS[i]),
haUID.c_str(), uid.c_str(), haUID.c_str(), FPSTR(HA_PARAMS[i]),
uom.c_str(), FPSTR(HA_UOM[i]),
sensor.path, FPSTR(HA_PARAMS[i]),
sensor.devcl, FPSTR(HA_DEVCL[i]),
haUID.c_str(), haUID.c_str(),
haName.c_str(), haName.c_str(),
haModel.c_str(), haModel.c_str(),
VERSION, VERSION,
haManuf.c_str(), haManuf.c_str(),
haUrl.c_str(), haUrl.c_str(),
strlen_P(sensor.stacl) > 0 ? ", \"stat_cla\" :" : "", strlen_P(HA_STACL[i]) > 0 ? ", \"stat_cla\" :" : "",
strlen_P(sensor.stacl) > 0 ? (char *) FPSTR(sensor.stacl) : "" strlen_P(HA_STACL[i]) > 0 ? (char *) FPSTR(HA_STACL[i]) : ""
); );
mqtt->publish(haTopic + haUID + "_" + uid.c_str() + "/config", json, true, 0); mqtt->publish(haTopic + haUID + "_" + FPSTR(HA_PARAMS[i]) + "/config", json, true, 0);
} }
autodiscoverInit = true; autodiscoverInit = true;
} }
if(listType>0) sequence++; if(listType>0) sequence++;
return true; return true;}
}

View File

@@ -3,79 +3,12 @@
#include "Arduino.h" #include "Arduino.h"
struct HomeAssistantSensor { const char* HA_TOPICS[17] PROGMEM = {"/state", "/state", "/state", "/power", "/power", "/power", "/power", "/power", "/power", "/power", "/power", "/power", "/power", "/energy", "/energy", "/energy", "/energy"};
const char* name; const char* HA_NAMES[17] PROGMEM = {"Status", "Supply volt", "Temperature", "Active import", "Reactive import", "Active export", "Reactive export", "L1 current", "L2 current", "L3 current",
const char* topic; "L1 voltage", "L2 voltage", "L3 voltage", "Accumulated active import", "Accumulated active export", "Accumulated reactive import", "Accumulated reactive export"};
const char* path; const char* HA_PARAMS[17] PROGMEM = {"rssi", "vcc", "temp", "P", "Q", "PO", "QO", "I1", "I2", "I3", "U1", "U2", "U3", "tPI", "tPO", "tQI", "tQO"};
const char* uom; const char* HA_UOM[17] PROGMEM = {"dBm", "V", "C", "W", "W", "W", "W", "A", "A", "A", "V", "V", "V", "kWh", "kWh", "kWh", "kWh"};
const char* devcl; const char* HA_DEVCL[17] PROGMEM = {"signal_strength", "voltage", "temperature", "power", "power", "power", "power", "current", "current", "current", "voltage", "voltage", "voltage", "energy", "energy", "energy", "energy"};
const char* stacl; const char* HA_STACL[17] PROGMEM = {"", "", "", "\"measurement\"", "\"measurement\"", "\"measurement\"", "\"measurement\"", "", "", "", "", "", "", "\"total_increasing\"", "\"total_increasing\"", "\"total_increasing\"", "\"total_increasing\""};
};
#endif
const uint8_t HA_SENSOR_COUNT PROGMEM = 60;
HomeAssistantSensor HA_SENSORS[HA_SENSOR_COUNT] PROGMEM = {
{"Status", "/state", "rssi", "dBm", "signal_strength", "\"measurement\""},
{"Supply volt", "/state", "vcc", "V", "voltage", "\"measurement\""},
{"Temperature", "/state", "temp", "C", "temperature", "\"measurement\""},
{"Active import", "/power", "P", "W", "power", "\"measurement\""},
{"L1 active import", "/power", "P1", "W", "power", "\"measurement\""},
{"L2 active import", "/power", "P2", "W", "power", "\"measurement\""},
{"L3 active import", "/power", "P3", "W", "power", "\"measurement\""},
{"Reactive import", "/power", "Q", "VAr", "reactive_power", "\"measurement\""},
{"Active export", "/power", "PO", "W", "power", "\"measurement\""},
{"L1 active export", "/power", "PO1", "W", "power", "\"measurement\""},
{"L2 active export", "/power", "PO2", "W", "power", "\"measurement\""},
{"L3 active export", "/power", "PO3", "W", "power", "\"measurement\""},
{"Reactive export", "/power", "QO", "VAr", "reactive_power", "\"measurement\""},
{"L1 current", "/power", "I1", "A", "current", "\"measurement\""},
{"L2 current", "/power", "I2", "A", "current", "\"measurement\""},
{"L3 current", "/power", "I3", "A", "current", "\"measurement\""},
{"L1 voltage", "/power", "U1", "V", "voltage", "\"measurement\""},
{"L2 voltage", "/power", "U2", "V", "voltage", "\"measurement\""},
{"L3 voltage", "/power", "U3", "V", "voltage", "\"measurement\""},
{"Accumulated active import", "/energy", "tPI", "kWh", "energy", "\"total_increasing\""},
{"Accumulated active export", "/energy", "tPO", "kWh", "energy", "\"total_increasing\""},
{"Accumulated reactive import","/energy", "tQI", "kVArh","energy", "\"total_increasing\""},
{"Accumulated reactive export","/energy", "tQO", "kVArh","energy", "\"total_increasing\""},
{"Power factor", "/power", "PF", "", "power_factor", "\"measurement\""},
{"L1 power factor", "/power", "PF1", "", "power_factor", "\"measurement\""},
{"L2 power factor", "/power", "PF2", "", "power_factor", "\"measurement\""},
{"L3 power factor", "/power", "PF3", "", "power_factor", "\"measurement\""},
{"Price current hour", "/prices", "prices['0']", "", "monetary", ""},
{"Price next hour", "/prices", "prices['1']", "", "monetary", ""},
{"Price in two hour", "/prices", "prices['2']", "", "monetary", ""},
{"Price in three hour", "/prices", "prices['3']", "", "monetary", ""},
{"Price in four hour", "/prices", "prices['4']", "", "monetary", ""},
{"Price in five hour", "/prices", "prices['5']", "", "monetary", ""},
{"Price in six hour", "/prices", "prices['6']", "", "monetary", ""},
{"Price in seven hour", "/prices", "prices['7']", "", "monetary", ""},
{"Price in eight hour", "/prices", "prices['8']", "", "monetary", ""},
{"Price in nine hour", "/prices", "prices['9']", "", "monetary", ""},
{"Price in ten hour", "/prices", "prices['10']", "", "monetary", ""},
{"Price in eleven hour", "/prices", "prices['11']", "", "monetary", ""},
{"Minimum price ahead", "/prices", "prices.min", "", "monetary", ""},
{"Maximum price ahead", "/prices", "prices.max", "", "monetary", ""},
{"Cheapest 1hr period ahead", "/prices", "prices.cheapest1hr","", "timestamp", ""},
{"Cheapest 3hr period ahead", "/prices", "prices.cheapest3hr","", "timestamp", ""},
{"Cheapest 6hr period ahead", "/prices", "prices.cheapest6hr","", "timestamp", ""},
{"Month max", "/realtime","max", "kWh", "energy", "\"total_increasing\""},
{"Tariff threshold", "/realtime","threshold", "kWh", "energy", "\"total_increasing\""},
{"Current hour used", "/realtime","hour.use", "kWh", "energy", "\"total_increasing\""},
{"Current hour cost", "/realtime","hour.cost", "", "monetary", "\"total_increasing\""},
{"Current hour produced", "/realtime","hour.produced", "kWh", "energy", "\"total_increasing\""},
{"Current day used", "/realtime","day.use", "kWh", "energy", "\"total_increasing\""},
{"Current day cost", "/realtime","day.cost", "", "monetary", "\"total_increasing\""},
{"Current day produced", "/realtime","day.produced", "kWh", "energy", "\"total_increasing\""},
{"Current month used", "/realtime","month.use", "kWh", "energy", "\"total_increasing\""},
{"Current month cost", "/realtime","month.cost", "", "monetary", "\"total_increasing\""},
{"Current month produced", "/realtime","month.produced", "kWh", "energy", "\"total_increasing\""},
{"Current month peak 1", "/realtime","peaks[0]", "kWh", "energy", ""},
{"Current month peak 2", "/realtime","peaks[1]", "kWh", "energy", ""},
{"Current month peak 3", "/realtime","peaks[2]", "kWh", "energy", ""},
{"Current month peak 4", "/realtime","peaks[3]", "kWh", "energy", ""},
{"Current month peak 5", "/realtime","peaks[4]", "kWh", "energy", ""},
};
#endif

View File

@@ -111,14 +111,8 @@ bool JsonMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyAccou
data->getMeterId().c_str(), data->getMeterId().c_str(),
meterModel.c_str(), meterModel.c_str(),
data->getActiveImportPower(), data->getActiveImportPower(),
data->getL1ActiveImportPower(),
data->getL2ActiveImportPower(),
data->getL3ActiveImportPower(),
data->getReactiveImportPower(), data->getReactiveImportPower(),
data->getActiveExportPower(), data->getActiveExportPower(),
data->getL1ActiveExportPower(),
data->getL2ActiveExportPower(),
data->getL3ActiveExportPower(),
data->getReactiveExportPower(), data->getReactiveExportPower(),
data->getL1Current(), data->getL1Current(),
data->getL2Current(), data->getL2Current(),
@@ -149,9 +143,8 @@ bool JsonMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyAccou
bool JsonMqttHandler::publishTemperatures(AmsConfiguration* config, HwTools* hw) { bool JsonMqttHandler::publishTemperatures(AmsConfiguration* config, HwTools* hw) {
int count = hw->getTempSensorCount(); int count = hw->getTempSensorCount();
if(count < 2) { if(count < 2)
return false; return false;
}
snprintf(json, 24, "{\"temperatures\":{"); snprintf(json, 24, "{\"temperatures\":{");
@@ -180,7 +173,7 @@ bool JsonMqttHandler::publishPrices(EntsoeApi* eapi) {
time_t now = time(nullptr); time_t now = time(nullptr);
float min1hr = 0.0, min3hr = 0.0, min6hr = 0.0; float min1hr, min3hr, min6hr;
int8_t min1hrIdx = -1, min3hrIdx = -1, min6hrIdx = -1; int8_t min1hrIdx = -1, min3hrIdx = -1, min6hrIdx = -1;
float min = INT16_MAX, max = INT16_MIN; float min = INT16_MAX, max = INT16_MIN;
float values[24]; float values[24];
@@ -230,7 +223,7 @@ bool JsonMqttHandler::publishPrices(EntsoeApi* eapi) {
} }
char ts1hr[24]; char ts1hr[21];
if(min1hrIdx > -1) { if(min1hrIdx > -1) {
time_t ts = now + (SECS_PER_HOUR * min1hrIdx); time_t ts = now + (SECS_PER_HOUR * min1hrIdx);
//Serial.printf("1hr: %d %lu\n", min1hrIdx, ts); //Serial.printf("1hr: %d %lu\n", min1hrIdx, ts);
@@ -238,7 +231,7 @@ bool JsonMqttHandler::publishPrices(EntsoeApi* eapi) {
breakTime(ts, tm); breakTime(ts, tm);
sprintf(ts1hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour); sprintf(ts1hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour);
} }
char ts3hr[24]; char ts3hr[21];
if(min3hrIdx > -1) { if(min3hrIdx > -1) {
time_t ts = now + (SECS_PER_HOUR * min3hrIdx); time_t ts = now + (SECS_PER_HOUR * min3hrIdx);
//Serial.printf("3hr: %d %lu\n", min3hrIdx, ts); //Serial.printf("3hr: %d %lu\n", min3hrIdx, ts);
@@ -246,7 +239,7 @@ bool JsonMqttHandler::publishPrices(EntsoeApi* eapi) {
breakTime(ts, tm); breakTime(ts, tm);
sprintf(ts3hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour); sprintf(ts3hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour);
} }
char ts6hr[24]; char ts6hr[21];
if(min6hrIdx > -1) { if(min6hrIdx > -1) {
time_t ts = now + (SECS_PER_HOUR * min6hrIdx); time_t ts = now + (SECS_PER_HOUR * min6hrIdx);
//Serial.printf("6hr: %d %lu\n", min6hrIdx, ts); //Serial.printf("6hr: %d %lu\n", min6hrIdx, ts);

View File

@@ -11,24 +11,6 @@ bool RawMqttHandler::publish(AmsData* data, AmsData* meterState, EnergyAccountin
} }
switch(data->getListType()) { switch(data->getListType()) {
case 4: case 4:
if(full || meterState->getL1ActiveImportPower() != data->getL1ActiveImportPower()) {
mqtt->publish(topic + "/meter/import/l1", String(data->getL1ActiveImportPower(), 2));
}
if(full || meterState->getL2ActiveImportPower() != data->getL2ActiveImportPower()) {
mqtt->publish(topic + "/meter/import/l2", String(data->getL2ActiveImportPower(), 2));
}
if(full || meterState->getL3ActiveImportPower() != data->getL3ActiveImportPower()) {
mqtt->publish(topic + "/meter/import/l3", String(data->getL3ActiveImportPower(), 2));
}
if(full || meterState->getL1ActiveExportPower() != data->getL1ActiveExportPower()) {
mqtt->publish(topic + "/meter/export/l1", String(data->getL1ActiveExportPower(), 2));
}
if(full || meterState->getL2ActiveExportPower() != data->getL2ActiveExportPower()) {
mqtt->publish(topic + "/meter/export/l2", String(data->getL2ActiveExportPower(), 2));
}
if(full || meterState->getL3ActiveExportPower() != data->getL3ActiveExportPower()) {
mqtt->publish(topic + "/meter/export/l3", String(data->getL3ActiveExportPower(), 2));
}
if(full || meterState->getPowerFactor() != data->getPowerFactor()) { if(full || meterState->getPowerFactor() != data->getPowerFactor()) {
mqtt->publish(topic + "/meter/powerfactor", String(data->getPowerFactor(), 2)); mqtt->publish(topic + "/meter/powerfactor", String(data->getPowerFactor(), 2));
} }
@@ -92,9 +74,7 @@ bool RawMqttHandler::publish(AmsData* data, AmsData* meterState, EnergyAccountin
} }
mqtt->publish(topic + "/realtime/import/hour", String(ea->getUseThisHour(), 3)); mqtt->publish(topic + "/realtime/import/hour", String(ea->getUseThisHour(), 3));
mqtt->publish(topic + "/realtime/import/day", String(ea->getUseToday(), 2)); mqtt->publish(topic + "/realtime/import/day", String(ea->getUseToday(), 2));
uint8_t peakCount = ea->getConfig()->hours; for(uint8_t i = 1; i <= ea->getConfig()->hours; i++) {
if(peakCount > 5) peakCount = 5;
for(uint8_t i = 1; i <= peakCount; i++) {
mqtt->publish(topic + "/realtime/import/peak/" + String(i, 10), String(ea->getPeak(i), 10), true, 0); mqtt->publish(topic + "/realtime/import/peak/" + String(i, 10), String(ea->getPeak(i), 10), true, 0);
} }
mqtt->publish(topic + "/realtime/import/threshold", String(ea->getCurrentThreshold(), 10), true, 0); mqtt->publish(topic + "/realtime/import/threshold", String(ea->getCurrentThreshold(), 10), true, 0);
@@ -126,7 +106,7 @@ bool RawMqttHandler::publishPrices(EntsoeApi* eapi) {
time_t now = time(nullptr); time_t now = time(nullptr);
float min1hr = 0.0, min3hr = 0.0, min6hr = 0.0; float min1hr, min3hr, min6hr;
int8_t min1hrIdx = -1, min3hrIdx = -1, min6hrIdx = -1; int8_t min1hrIdx = -1, min3hrIdx = -1, min6hrIdx = -1;
float min = INT16_MAX, max = INT16_MIN; float min = INT16_MAX, max = INT16_MIN;
float values[34]; float values[34];
@@ -177,7 +157,7 @@ bool RawMqttHandler::publishPrices(EntsoeApi* eapi) {
} }
char ts1hr[24]; char ts1hr[21];
if(min1hrIdx > -1) { if(min1hrIdx > -1) {
time_t ts = now + (SECS_PER_HOUR * min1hrIdx); time_t ts = now + (SECS_PER_HOUR * min1hrIdx);
//Serial.printf("1hr: %d %lu\n", min1hrIdx, ts); //Serial.printf("1hr: %d %lu\n", min1hrIdx, ts);
@@ -185,7 +165,7 @@ bool RawMqttHandler::publishPrices(EntsoeApi* eapi) {
breakTime(ts, tm); breakTime(ts, tm);
sprintf(ts1hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour); sprintf(ts1hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour);
} }
char ts3hr[24]; char ts3hr[21];
if(min3hrIdx > -1) { if(min3hrIdx > -1) {
time_t ts = now + (SECS_PER_HOUR * min3hrIdx); time_t ts = now + (SECS_PER_HOUR * min3hrIdx);
//Serial.printf("3hr: %d %lu\n", min3hrIdx, ts); //Serial.printf("3hr: %d %lu\n", min3hrIdx, ts);
@@ -193,7 +173,7 @@ bool RawMqttHandler::publishPrices(EntsoeApi* eapi) {
breakTime(ts, tm); breakTime(ts, tm);
sprintf(ts3hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour); sprintf(ts3hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour);
} }
char ts6hr[24]; char ts6hr[21];
if(min6hrIdx > -1) { if(min6hrIdx > -1) {
time_t ts = now + (SECS_PER_HOUR * min6hrIdx); time_t ts = now + (SECS_PER_HOUR * min6hrIdx);
//Serial.printf("6hr: %d %lu\n", min6hrIdx, ts); //Serial.printf("6hr: %d %lu\n", min6hrIdx, ts);

View File

@@ -2,7 +2,6 @@ static const char HEADER_CACHE_CONTROL[] PROGMEM = "Cache-Control";
static const char HEADER_PRAGMA[] PROGMEM = "Pragma"; static const char HEADER_PRAGMA[] PROGMEM = "Pragma";
static const char HEADER_EXPIRES[] PROGMEM = "Expires"; static const char HEADER_EXPIRES[] PROGMEM = "Expires";
static const char HEADER_AUTHENTICATE[] PROGMEM = "WWW-Authenticate"; static const char HEADER_AUTHENTICATE[] PROGMEM = "WWW-Authenticate";
static const char HEADER_LOCATION[] PROGMEM = "Location";
static const char CACHE_CONTROL_NO_CACHE[] PROGMEM = "no-cache, no-store, must-revalidate"; static const char CACHE_CONTROL_NO_CACHE[] PROGMEM = "no-cache, no-store, must-revalidate";
static const char CACHE_1HR[] PROGMEM = "public, max-age=3600"; static const char CACHE_1HR[] PROGMEM = "public, max-age=3600";

File diff suppressed because it is too large Load Diff

View File

@@ -61,11 +61,7 @@ private:
bool performRestart = false; bool performRestart = false;
bool performUpgrade = false; bool performUpgrade = false;
bool rebootForUpgrade = false; bool rebootForUpgrade = false;
#if defined(AMS2MQTT_FIRMWARE_URL)
String customFirmwareUrl = AMS2MQTT_FIRMWARE_URL;
#else
String customFirmwareUrl; String customFirmwareUrl;
#endif
static const uint16_t BufferSize = 2048; static const uint16_t BufferSize = 2048;
char* buf; char* buf;

View File

@@ -657,7 +657,7 @@ var fetch = function() {
if(ip) { if(ip) {
var v = parseInt(json.i); var v = parseInt(json.i);
var pct = Math.min((v*100)/parseInt(json.im), 100); var pct = (v*100)/parseInt(json.im);
var append = "W"; var append = "W";
if(v > 1000 && !swatt) { if(v > 1000 && !swatt) {
v = (v/1000).toFixed(1); v = (v/1000).toFixed(1);
@@ -683,7 +683,7 @@ var fetch = function() {
$('.rim').hide(); $('.rim').hide();
if(xp) { if(xp) {
var v = parseInt(json.e); var v = parseInt(json.e);
var pct = Math.min((v*100)/(om*1000), 100); var pct = (v*100)/(om*1000);
var append = "W"; var append = "W";
if(v > 1000 && !swatt) { if(v > 1000 && !swatt) {
v = (v/1000).toFixed(1); v = (v/1000).toFixed(1);
@@ -723,21 +723,21 @@ var fetch = function() {
var u1 = parseFloat(json.u1); var u1 = parseFloat(json.u1);
t += u1; t += u1;
c++; c++;
var pct = Math.min(Math.max(parseFloat(json.u1)-195.5, 1)*100/69, 100); var pct = (Math.max(parseFloat(json.u1)-195.5, 1)*100/69);
arr[r++] = [ds == 1 ? 'L1-L2' : 'L1', u1, "color: " + voltcol(pct) + ";opacity: 0.9;", u1 + "V"]; arr[r++] = [ds == 1 ? 'L1-L2' : 'L1', u1, "color: " + voltcol(pct) + ";opacity: 0.9;", u1 + "V"];
} }
if(json.u2) { if(json.u2) {
var u2 = parseFloat(json.u2); var u2 = parseFloat(json.u2);
t += u2; t += u2;
c++; c++;
var pct = Math.min(Math.max(parseFloat(json.u2)-195.5, 1)*100/69, 100); var pct = (Math.max(parseFloat(json.u2)-195.5, 1)*100/69);
arr[r++] = [ds == 1 ? 'L1-L3' : 'L2', u2, "color: " + voltcol(pct) + ";opacity: 0.9;", u2 + "V"]; arr[r++] = [ds == 1 ? 'L1-L3' : 'L2', u2, "color: " + voltcol(pct) + ";opacity: 0.9;", u2 + "V"];
} }
if(json.u3) { if(json.u3) {
var u3 = parseFloat(json.u3); var u3 = parseFloat(json.u3);
t += u3; t += u3;
c++; c++;
var pct = Math.min(Math.max(parseFloat(json.u3)-195.5, 1)*100/69, 100); var pct = (Math.max(parseFloat(json.u3)-195.5, 1)*100/69);
arr[r++] = [ds == 1 ? 'L2-L3' : 'L3', u3, "color: " + voltcol(pct) + ";opacity: 0.9;", u3 + "V"]; arr[r++] = [ds == 1 ? 'L2-L3' : 'L3', u3, "color: " + voltcol(pct) + ";opacity: 0.9;", u3 + "V"];
} }
v = t/c; v = t/c;
@@ -762,19 +762,19 @@ var fetch = function() {
if(json.i1 || json.u1) { if(json.i1 || json.u1) {
var i1 = parseFloat(json.i1); var i1 = parseFloat(json.i1);
dA = true; dA = true;
var pct = Math.min((parseFloat(json.i1)/parseInt(json.mf))*100, 100); var pct = (parseFloat(json.i1)/parseInt(json.mf))*100;
arr[r++] = ['L1', pct, "color: " + ampcol(pct) + ";opacity: 0.9;", i1 + "A"]; arr[r++] = ['L1', pct, "color: " + ampcol(pct) + ";opacity: 0.9;", i1 + "A"];
} }
if(json.i2 || json.u2) { if(json.i2 || json.u2) {
var i2 = parseFloat(json.i2); var i2 = parseFloat(json.i2);
dA = true; dA = true;
var pct = Math.min((parseFloat(json.i2)/parseInt(json.mf))*100, 100); var pct = (parseFloat(json.i2)/parseInt(json.mf))*100;
arr[r++] = ['L2', pct, "color: " + ampcol(pct) + ";opacity: 0.9;", i2 + "A"]; arr[r++] = ['L2', pct, "color: " + ampcol(pct) + ";opacity: 0.9;", i2 + "A"];
} }
if(json.i3 || json.u3) { if(json.i3 || json.u3) {
var i3 = parseFloat(json.i3); var i3 = parseFloat(json.i3);
dA = true; dA = true;
var pct = Math.min((parseFloat(json.i3)/parseInt(json.mf))*100, 100); var pct = (parseFloat(json.i3)/parseInt(json.mf))*100;
arr[r++] = ['L3', pct, "color: " + ampcol(pct) + ";opacity: 0.9;", i3 + "A"]; arr[r++] = ['L3', pct, "color: " + ampcol(pct) + ";opacity: 0.9;", i3 + "A"];
} }
if(dA) { if(dA) {

View File

@@ -23,8 +23,8 @@
"v" : %.3f, "v" : %.3f,
"r" : %d, "r" : %d,
"t" : %.2f, "t" : %.2f,
"u" : %u, "u" : %lu,
"m" : %u, "m" : %lu,
"em" : %d, "em" : %d,
"hm" : %d, "hm" : %d,
"wm" : %d, "wm" : %d,
@@ -53,5 +53,5 @@
"p" : %.2f "p" : %.2f
} }
}, },
"c" : %u "c" : %lu
} }

View File

@@ -1,6 +1,6 @@
<div class="alert alert-warning">!!WARNING!!<br/>Do not change anything here unless you know exactly what you are doing! Changing things here could cause the device to stop responding</div> <div class="alert alert-warning">!!WARNING!!<br/>Do not change anything here unless you know exactly what you are doing! Changing things here could cause the device to stop responding</div>
<form method="post" action="/save"> <form method="post" action="/save">
<input type="hidden" name="gc" value="true"/> <input type="hidden" name="gpioConfig" value="true"/>
<div class="my-3 p-3 bg-white rounded shadow"> <div class="my-3 p-3 bg-white rounded shadow">
<h6>GPIO settings</h6> <h6>GPIO settings</h6>
<div class="d-flex flex-row flex-wrap"> <div class="d-flex flex-row flex-wrap">
@@ -8,18 +8,18 @@
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text">HAN</span> <span class="input-group-text">HAN</span>
</div> </div>
<select name="h" class="form-control"> <select name="hanPin" class="form-control">
${h} ${options.han}
</select> </select>
</div> </div>
<div class="m-2 input-group input-group-sm" style="width: 150px;"> <div class="m-2 input-group input-group-sm" style="width: 150px;">
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text">LED</span> <span class="input-group-text">LED</span>
</div> </div>
<input name="l" type="number" min="2" max="${g}" class="form-control" value="${l}"/> <input name="ledPin" type="number" min="2" max="${gpio.max}" class="form-control" value="${config.ledPin}"/>
<div class="input-group-append" title="Inverted"> <div class="input-group-append" title="Inverted">
<label class="input-group-text"> <label class="input-group-text">
<input type="checkbox" name="i" value="true" ${i}/> inv <input type="checkbox" name="ledInverted" value="true" ${config.ledInverted}/> inv
</label> </label>
</div> </div>
</div> </div>
@@ -27,12 +27,12 @@
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text">RGB</span> <span class="input-group-text">RGB</span>
</div> </div>
<input name="r" type="number" min="2" max="${g}" class="form-control" value="${r}"/> <input name="ledPinRed" type="number" min="2" max="${gpio.max}" class="form-control" value="${config.ledPinRed}"/>
<input name="e" type="number" min="2" max="${g}" class="form-control" value="${e}"/> <input name="ledPinGreen" type="number" min="2" max="${gpio.max}" class="form-control" value="${config.ledPinGreen}"/>
<input name="b" type="number" min="2" max="${g}" class="form-control" value="${b}"/> <input name="ledPinBlue" type="number" min="2" max="${gpio.max}" class="form-control" value="${config.ledPinBlue}"/>
<div class="input-group-append" title="Inverted"> <div class="input-group-append" title="Inverted">
<label class="input-group-text"> <label class="input-group-text">
<input type="checkbox" name="n" value="true" ${n}/> inv <input type="checkbox" name="ledRgbInverted" value="true" ${config.ledRgbInverted}/> inv
</label> </label>
</div> </div>
</div> </div>
@@ -40,31 +40,31 @@
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text">AP button</span> <span class="input-group-text">AP button</span>
</div> </div>
<input name="a" type="number" min="0" max="${g}" class="form-control" value="${a}"/> <input name="apPin" type="number" min="0" max="${gpio.max}" class="form-control" value="${config.apPin}"/>
</div> </div>
<div class="m-2 input-group input-group-sm" style="width: 150px;"> <div class="m-2 input-group input-group-sm" style="width: 150px;">
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text">Temperature</span> <span class="input-group-text">Temperature</span>
</div> </div>
<input name="t" type="number" min="0" max="${g}" class="form-control" value="${t}"/> <input name="tempSensorPin" type="number" min="0" max="${gpio.max}" class="form-control" value="${config.tempSensorPin}"/>
</div> </div>
<div class="m-2 input-group input-group-sm" style="width: 150px;"> <div class="m-2 input-group input-group-sm" style="width: 150px;">
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text">Analog temp</span> <span class="input-group-text">Analog temp</span>
</div> </div>
<input name="m" type="number" min="0" max="${g}" class="form-control" value="${m}"/> <input name="tempAnalogSensorPin" type="number" min="0" max="${gpio.max}" class="form-control" value="${config.tempAnalogSensorPin}"/>
</div> </div>
<div class="m-2 input-group input-group-sm" style="width: 100px;"> <div class="m-2 input-group input-group-sm" style="width: 100px;">
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text">Vcc</span> <span class="input-group-text">Vcc</span>
</div> </div>
<input name="v" type="number" min="0" max="${g}" class="form-control" value="${v}"/> <input name="vccPin" type="number" min="0" max="${gpio.max}" class="form-control" value="${config.vccPin}"/>
</div> </div>
<div class="m-2 input-group input-group-sm" style="width: 200px;"> <div class="m-2 input-group input-group-sm" style="width: 200px;">
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text">GND resistor</span> <span class="input-group-text">GND resistor</span>
</div> </div>
<input type="number" min="1" max="1000" step="1" class="form-control" name="d" value="${d}" /> <input type="number" min="1" max="1000" step="1" class="form-control" name="vccResistorGnd" value="${config.vccResistorGnd}" />
<div class="input-group-append" title="Inverted"> <div class="input-group-append" title="Inverted">
<label class="input-group-text">k&ohm;</label> <label class="input-group-text">k&ohm;</label>
</div> </div>
@@ -73,7 +73,7 @@
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text">Vcc resistor</span> <span class="input-group-text">Vcc resistor</span>
</div> </div>
<input type="number" min="1" max="1000" step="1" class="form-control" name="s" value="${s}" /> <input type="number" min="1" max="1000" step="1" class="form-control" name="vccResistorVcc" value="${config.vccResistorVcc}" />
<div class="input-group-append" title="Inverted"> <div class="input-group-append" title="Inverted">
<label class="input-group-text">k&ohm;</label> <label class="input-group-text">k&ohm;</label>
</div> </div>
@@ -82,19 +82,19 @@
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text">Multiplier</span> <span class="input-group-text">Multiplier</span>
</div> </div>
<input type="number" min="0.1" max="10" step="0.01" class="form-control" name="u" value="${u}" /> <input type="number" min="0.1" max="10" step="0.01" class="form-control" name="vccMultiplier" value="${config.vccMultiplier}" />
</div> </div>
<div class="m-2 input-group input-group-sm" style="width: 120px;"> <div class="m-2 input-group input-group-sm" style="width: 120px;">
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text">Offset</span> <span class="input-group-text">Offset</span>
</div> </div>
<input type="number" min="0.0" max="3.5" step="0.01" class="form-control" name="o" value="${o}" /> <input type="number" min="0.0" max="3.5" step="0.01" class="form-control" name="vccOffset" value="${config.vccOffset}" />
</div> </div>
<div class="m-2 input-group input-group-sm" style="width: 130px;"> <div class="m-2 input-group input-group-sm" style="width: 130px;">
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text">Boot limit</span> <span class="input-group-text">Boot limit</span>
</div> </div>
<input type="number" min="2.5" max="3.5" step="0.1" class="form-control" name="c" value="${c}" /> <input type="number" min="2.5" max="3.5" step="0.1" class="form-control" name="vccBootLimit" value="${config.vccBootLimit}" />
</div> </div>
</div> </div>
</div> </div>

View File

@@ -11,5 +11,9 @@
"I3" : %.2f, "I3" : %.2f,
"U1" : %.2f, "U1" : %.2f,
"U2" : %.2f, "U2" : %.2f,
"U3" : %.2f "U3" : %.2f,
"PF" : %.2f,
"PF1" : %.2f,
"PF2" : %.2f,
"PF3" : %.2f
} }

View File

@@ -1,25 +0,0 @@
{
"lv" : "%s",
"id" : "%s",
"type" : "%s",
"P" : %d,
"P1" : %.2f,
"P2" : %.2f,
"P3" : %.2f,
"Q" : %d,
"PO" : %d,
"PO1" : %.2f,
"PO2" : %.2f,
"PO3" : %.2f,
"QO" : %d,
"I1" : %.2f,
"I2" : %.2f,
"I3" : %.2f,
"U1" : %.2f,
"U2" : %.2f,
"U3" : %.2f,
"PF" : %.2f,
"PF1" : %.2f,
"PF2" : %.2f,
"PF3" : %.2f
}

View File

@@ -1,4 +1,3 @@
<!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">

View File

@@ -1,7 +1,7 @@
{ {
"id" : "%s", "id" : "%s",
"name" : "%s", "name" : "%s",
"up" : %u, "up" : %lu,
"t" : %lu, "t" : %lu,
"vcc" : %.3f, "vcc" : %.3f,
"rssi": %d, "rssi": %d,

View File

@@ -1,7 +1,7 @@
{ {
"id" : "%s", "id" : "%s",
"name" : "%s", "name" : "%s",
"up" : %u, "up" : %lu,
"t" : %lu, "t" : %lu,
"vcc" : %.3f, "vcc" : %.3f,
"rssi": %d, "rssi": %d,

View File

@@ -1,7 +1,7 @@
{ {
"id" : "%s", "id" : "%s",
"name" : "%s", "name" : "%s",
"up" : %u, "up" : %lu,
"t" : %lu, "t" : %lu,
"vcc" : %.3f, "vcc" : %.3f,
"rssi": %d, "rssi": %d,

View File

@@ -1,7 +1,7 @@
{ {
"id" : "%s", "id" : "%s",
"name" : "%s", "name" : "%s",
"up" : %u, "up" : %lu,
"t" : %lu, "t" : %lu,
"vcc" : %.3f, "vcc" : %.3f,
"rssi": %d, "rssi": %d,
@@ -11,14 +11,8 @@
"id" : "%s", "id" : "%s",
"type" : "%s", "type" : "%s",
"P" : %d, "P" : %d,
"P1" : %.2f,
"P2" : %.2f,
"P3" : %.2f,
"Q" : %d, "Q" : %d,
"PO" : %d, "PO" : %d,
"PO1" : %.2f,
"PO2" : %.2f,
"PO3" : %.2f,
"QO" : %d, "QO" : %d,
"I1" : %.2f, "I1" : %.2f,
"I2" : %.2f, "I2" : %.2f,

View File

@@ -26,7 +26,6 @@
<select name="board" class="form-control" required> <select name="board" class="form-control" required>
<option value=""></option> <option value=""></option>
<optgroup label="Custom hardware"> <optgroup label="Custom hardware">
<option value="7" ${config.boardType7}>Pow-U+ (ESP32) from amsleser.no</option>
<option value="6" ${config.boardType6}>Pow-P1 from amsleser.no</option> <option value="6" ${config.boardType6}>Pow-P1 from amsleser.no</option>
<option value="5" ${config.boardType5}>Pow-K+ (ESP32) from amsleser.no</option> <option value="5" ${config.boardType5}>Pow-K+ (ESP32) from amsleser.no</option>
<option value="4" ${config.boardType4}>Pow-U or Pow-K from amsleser.no (GPIO12)</option> <option value="4" ${config.boardType4}>Pow-U or Pow-K from amsleser.no (GPIO12)</option>

View File

@@ -37,7 +37,7 @@
</div> </div>
</div> </div>
<div class="row" id="i"> <div class="row" id="i">
<div class="col-xl-3 col-lg-4 col-md-6 form-group"> <div class="col-xl-3 col-lg-4 form-group">
<div class="input-group input-group-sm"> <div class="input-group input-group-sm">
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text">IP</span> <span class="input-group-text">IP</span>
@@ -45,7 +45,7 @@
<input type="text" name="i" class="form-control sip" pattern="\d?\d?\d.\d?\d?\d.\d?\d?\d.\d?\d?\d" value="{i}"/> <input type="text" name="i" class="form-control sip" pattern="\d?\d?\d.\d?\d?\d.\d?\d?\d.\d?\d?\d" value="{i}"/>
</div> </div>
</div> </div>
<div class="col-xl-3 col-lg-4 col-md-6 form-group"> <div class="col-xl-3 col-lg-4 form-group">
<div class="input-group input-group-sm"> <div class="input-group input-group-sm">
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text">Netmask</span> <span class="input-group-text">Netmask</span>
@@ -53,7 +53,7 @@
<input type="text" name="sn" class="form-control sip" pattern="\d?\d?\d.\d?\d?\d.\d?\d?\d.\d?\d?\d" value="{sn}"/> <input type="text" name="sn" class="form-control sip" pattern="\d?\d?\d.\d?\d?\d.\d?\d?\d.\d?\d?\d" value="{sn}"/>
</div> </div>
</div> </div>
<div class="col-xl-3 col-lg-4 col-md-6 form-group"> <div class="col-xl-3 col-lg-4 form-group">
<div class="input-group input-group-sm"> <div class="input-group input-group-sm">
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text">Gateway</span> <span class="input-group-text">Gateway</span>
@@ -61,7 +61,7 @@
<input type="text" name="g" class="form-control sip" pattern="\d?\d?\d.\d?\d?\d.\d?\d?\d.\d?\d?\d" value="{g}"/> <input type="text" name="g" class="form-control sip" pattern="\d?\d?\d.\d?\d?\d.\d?\d?\d.\d?\d?\d" value="{g}"/>
</div> </div>
</div> </div>
<div class="col-xl-4 col-lg-5 col-md-6 form-group"> <div class="col-xl-4 col-lg-5 form-group">
<div class="input-group input-group-sm"> <div class="input-group input-group-sm">
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text">DNS 1</span> <span class="input-group-text">DNS 1</span>
@@ -69,7 +69,7 @@
<input type="text" name="d1" class="form-control sip" pattern="\d?\d?\d.\d?\d?\d.\d?\d?\d.\d?\d?\d" value="{d1}"/> <input type="text" name="d1" class="form-control sip" pattern="\d?\d?\d.\d?\d?\d.\d?\d?\d.\d?\d?\d" value="{d1}"/>
</div> </div>
</div> </div>
<div class="col-xl-4 col-lg-5 col-md-6 form-group"> <div class="col-xl-4 col-lg-5 form-group">
<div class="input-group input-group-sm"> <div class="input-group input-group-sm">
<div class="input-group-prepend"> <div class="input-group-prepend">
<span class="input-group-text">DNS 2</span> <span class="input-group-text">DNS 2</span>
@@ -89,21 +89,7 @@
</div> </div>
</div> </div>
</div> </div>
</div>
<div class="col-lg-3 col-md-4 col-sm-6 form-group">
<div class="input-group input-group-sm">
<div class="input-group-prepend">
<span class="input-group-text">Power saving</span>
</div>
<select name="z" class="form-control">
<option value="255">Default</option>
<option value="0" {z0}>Off</option>
<option value="1" {z1}>Minimum</option>
<option value="2" {z2}>Maximum</option>
</select>
</div>
</div>
</div>
</div> </div>
<hr/> <hr/>
<div class="row form-group"> <div class="row form-group">