Compare commits

...

16 Commits

Author SHA1 Message Date
Gunnar Skjold
34ebe9601a Changed blink behaviour 2022-10-16 18:31:11 +02:00
Gunnar Skjold
fa299198fc Fixed all build warnings 2022-10-13 20:33:59 +02:00
Gunnar Skjold
6d81b0a856 Fixed all build warnings 2022-10-13 20:24:56 +02:00
Gunnar Skjold
dd095da97b Reduced footprint of GPIO config page 2022-10-13 19:27:25 +02:00
Gunnar Skjold
1b6ce203b7 Better debug output whem receiving unknown data 2022-10-13 17:40:44 +02:00
Gunnar Skjold
2850be4e48 Merge pull request #322 from tbarnekov/extend_power_info
Populate Active Import and Export per phase and export to HA
2022-10-12 20:34:09 +02:00
Gunnar Skjold
7eca31de84 Fixed build errors 2022-10-12 20:01:55 +02:00
Gunnar Skjold
a64f960cc7 Added Pow-U+ profile 2022-10-12 19:30:00 +02:00
Gunnar Skjold
ce3a47a7e6 Fixed error blinks and improved WiFi reconnect 2022-10-12 19:25:48 +02:00
Thomas Barnekov
8395e1dc77 Merge remote-tracking branch 'origin/master' into extend_power_info 2022-10-10 17:06:09 +02:00
Thomas Barnekov
39a4761415 Add DOCTYPE to html to fix quirks mode 2022-10-10 16:59:43 +02:00
Gunnar Skjold
867ab9d6c2 Build variable for upgrade URL 2022-10-07 19:35:30 +02:00
Thomas Barnekov
5e03e3d3c2 Move per-phase power consumption and power factor values to new ha4.json 2022-10-07 13:40:29 +02:00
Thomas Barnekov
adb5050621 Merge branch 'gskjold:master' into extend_power_info 2022-10-06 17:31:43 +02:00
Thomas Barnekov
7cd52d5689 Add individual power reading for all phases (include in HA) 2022-10-06 00:35:30 +02:00
Thomas Barnekov
ad78ff3082 Fix implicit cast and non-const char pointer warnings 2022-10-05 22:42:43 +02:00
39 changed files with 376 additions and 166 deletions

View File

@@ -743,7 +743,7 @@ bool AmsConfiguration::relocateConfig86() {
} }
bool AmsConfiguration::relocateConfig87() { bool AmsConfiguration::relocateConfig87() {
MeterConfig87 meter87; MeterConfig87 meter87 = {0,0,0,0,0,0,0};
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

@@ -45,6 +45,12 @@ 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();
@@ -161,6 +167,30 @@ 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,6 +54,14 @@ 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();
@@ -71,6 +79,8 @@ 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

@@ -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,7 +119,6 @@ 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)) {
@@ -246,7 +245,6 @@ void setup() {
} }
Debug.setSerialEnabled(true); Debug.setSerialEnabled(true);
DebugConfig debug;
delay(1); delay(1);
float vcc = hw.getVcc(); float vcc = hw.getVcc();
@@ -436,6 +434,10 @@ 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) {
@@ -506,10 +508,6 @@ 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();
@@ -591,7 +589,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 %d ms to update temperature", millis()-start); debugD("Used %ld 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()) {
@@ -725,22 +723,25 @@ void errorBlink() {
if(lastError == 3) if(lastError == 3)
lastError = 0; lastError = 0;
lastErrorBlink = millis(); lastErrorBlink = millis();
for(;lastError < 3;lastError++) { while(lastError < 3) {
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;
} }
@@ -827,6 +828,11 @@ 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) {
@@ -985,17 +991,34 @@ void debugPrint(byte *buffer, int start, int length) {
Debug.println(""); Debug.println("");
} }
unsigned long wifiTimeout = WIFI_CONNECTION_TIMEOUT;
unsigned long lastWifiRetry = -WIFI_CONNECTION_TIMEOUT; unsigned long lastWifiRetry = -WIFI_CONNECTION_TIMEOUT;
void WiFi_connect() { void WiFi_connect() {
if(millis() - lastWifiRetry < wifiTimeout) {
delay(50);
return;
}
lastWifiRetry = millis();
if (WiFi.status() != WL_CONNECTED) { if (WiFi.status() != WL_CONNECTED) {
if(WiFi.status() == WL_DISCONNECTED) {
if(millis() - lastWifiRetry < WIFI_CONNECTION_TIMEOUT) {
return;
}
}
if(WiFi.getMode() != WIFI_OFF) { if(WiFi.getMode() != WIFI_OFF) {
switch(WiFi.status()) {
case WL_NO_SSID_AVAIL:
debugE("WiFi error, no SSID available");
break;
case WL_CONNECT_FAILED:
debugE("WiFi error, connection failed");
break;
case WL_CONNECTION_LOST:
debugE("WiFi error, connection lost");
break;
#if defined(ESP8266)
case WL_WRONG_PASSWORD:
debugE("WiFi error, wrong password");
break;
#endif
default:
debugE("WiFi error, %d", WiFi.status());
break;
}
if(wifiReconnectCount > 3) { if(wifiReconnectCount > 3) {
ESP.restart(); ESP.restart();
return; return;
@@ -1029,11 +1052,13 @@ void WiFi_connect() {
WiFi.softAPdisconnect(true); WiFi.softAPdisconnect(true);
WiFi.enableAP(false); WiFi.enableAP(false);
WiFi.mode(WIFI_OFF); WiFi.mode(WIFI_OFF);
#if defined(ESP8266)
WiFi.forceSleepBegin();
#endif
yield(); yield();
wifiTimeout = 5000;
return; return;
} }
wifiTimeout = WIFI_CONNECTION_TIMEOUT; lastWifiRetry = millis();
WiFiConfig wifi; WiFiConfig wifi;
if(!config.getWiFiConfig(wifi) || strlen(wifi.ssid) == 0) { if(!config.getWiFiConfig(wifi) || strlen(wifi.ssid) == 0) {
@@ -1121,16 +1146,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 = {payload.length()/2}; //DataParserContext ctx = {static_cast<uint8_t>(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; int16_t ret = 0;
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);
@@ -1375,7 +1400,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 %i for secure MQTT connection", epoch); debugD("Setting NTP time %lld for secure MQTT connection", epoch);
mqttSecureClient->setX509Time(epoch); mqttSecureClient->setX509Time(epoch);
} }
#endif #endif

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: %d, this month: %d, last month: %d\n", data.costYesterday / 10.0, data.costThisMonth, data.costLastMonth); debugger->printf("(EnergyAccounting) Loaded cost yesterday: %.2f, this month: %d, last month: %d\n", data.costYesterday / 10.0, data.costThisMonth, data.costLastMonth);
} }
init = true; init = true;
} }

View File

@@ -373,8 +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);
if(i != blink) if(i != blink-1)
delay(50); delay(200);
} }
return true; return true;
} }

View File

@@ -296,6 +296,38 @@ 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;
@@ -336,12 +368,16 @@ 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(&meterId, mid->str.data, mid->str.length); memcpy(str, mid->oct.data, mid->oct.length);
str[mid->oct.length] = 0x00;
meterId = String(str);
meterId[mid->str.length] = 0; meterId[mid->str.length] = 0;
break; break;
case CosemTypeOctetString: case CosemTypeOctetString:
memcpy(&meterId, mid->oct.data, mid->oct.length); memcpy(str, mid->str.data, mid->str.length);
meterId[mid->oct.length] = 0; str[mid->str.length] = 0x00;
meterId = String(str);
meterId[mid->str.length] = 0;
break; break;
} }
} }

View File

@@ -49,6 +49,12 @@ 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 %d (dlu)", ntohl(item->dlu.data)); if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu (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 %d (dlu)", ntohl(item->dlu.data)); if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu (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 %d (dlu)", ntohl(item->dlu.data)); if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu (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 %d (dlu)", ntohl(item->dlu.data)); if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu (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 %d (dlu)", ntohl(item->dlu.data)); if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu (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 %d (dlu)", ntohl(item->dlu.data)); if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu (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 %d (dlu)", ntohl(item->dlu.data)); if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu (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 %d (dlu)", ntohl(item->dlu.data)); if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu (dlu)", ntohl(item->dlu.data));
} }
} }
} else if(descriptor->obis[2] == 96) { } else if(descriptor->obis[2] == 96) {

View File

@@ -1,5 +1,8 @@
#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,8 +3,6 @@
#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,7 +4,6 @@ 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; int len = 0;
int headersize = 2 + systemTitleLength; int headersize = 2 + systemTitleLength;
ptr += systemTitleLength; ptr += systemTitleLength;
if(((*ptr) & 0xFF) == 0x81) { if(((*ptr) & 0xFF) == 0x81) {

View File

@@ -5,8 +5,6 @@
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,7 +1,6 @@
#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,8 +5,6 @@ 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(int i = 0; i < size; i++) { for(size_t i = 0; i < size; i++) {
write(buffer[i]); write(buffer[i]);
} }
return size; return size;

View File

@@ -5,6 +5,10 @@ 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;
} }
@@ -35,7 +39,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(int i = 0; i < size; i++) { for(size_t i = 0; i < size; i++) {
write(buffer[i]); write(buffer[i]);
} }
return size; return size;

View File

@@ -14,6 +14,7 @@
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 %lu\n", midnightMillis); if(debugger->isActive(RemoteDebug::INFO)) debugger->printf("(EntsoeApi) Setting midnight millis %llu\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 %lu\n", t); if(debugger->isActive(RemoteDebug::INFO)) debugger->printf("(EntsoeApi) Rotating price objects at %lld\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,6 +15,7 @@ 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,6 +6,7 @@
#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,7 +35,7 @@ bool HomeAssistantMqttHandler::publish(AmsData* data, AmsData* previousState, En
data->getActiveImportPower() data->getActiveImportPower()
); );
mqtt->publish(topic + "/power", json); mqtt->publish(topic + "/power", json);
} else if(data->getListType() >= 2) { // publish power counts and volts/amps } else if(data->getListType() <= 3) { // 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(),
@@ -48,6 +49,29 @@ 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(),
@@ -117,7 +141,7 @@ bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) {
time_t now = time(nullptr); time_t now = time(nullptr);
float min1hr, min3hr, min6hr; float min1hr = 0.0, min3hr = 0.0, min6hr = 0.0;
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];
@@ -167,7 +191,7 @@ bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) {
} }
char ts1hr[21]; char ts1hr[24];
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);
@@ -175,7 +199,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[21]; char ts3hr[24];
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);
@@ -183,7 +207,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[21]; char ts6hr[24];
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);
@@ -263,13 +287,13 @@ bool HomeAssistantMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, Energ
peaks++; peaks++;
} }
snprintf_P(json, BufferSize, HADISCOVER_JSON, snprintf_P(json, BufferSize, HADISCOVER_JSON,
FPSTR(sensor.name), sensor.name,
topic.c_str(), FPSTR(sensor.topic), topic.c_str(), sensor.topic,
haUID.c_str(), uid.c_str(), haUID.c_str(), uid.c_str(),
haUID.c_str(), uid.c_str(), haUID.c_str(), uid.c_str(),
uom.c_str(), uom.c_str(),
FPSTR(sensor.path), sensor.path,
FPSTR(sensor.devcl), sensor.devcl,
haUID.c_str(), haUID.c_str(),
haName.c_str(), haName.c_str(),
haModel.c_str(), haModel.c_str(),

View File

@@ -4,23 +4,29 @@
#include "Arduino.h" #include "Arduino.h"
struct HomeAssistantSensor { struct HomeAssistantSensor {
char* name; const char* name;
char* topic; const char* topic;
char* path; const char* path;
char* uom; const char* uom;
char* devcl; const char* devcl;
char* stacl; const char* stacl;
}; };
const uint8_t HA_SENSOR_COUNT PROGMEM = 50; const uint8_t HA_SENSOR_COUNT PROGMEM = 60;
HomeAssistantSensor HA_SENSORS[HA_SENSOR_COUNT] PROGMEM = { HomeAssistantSensor HA_SENSORS[HA_SENSOR_COUNT] PROGMEM = {
{"Status", "/state", "rssi", "dBm", "signal_strength", "\"measurement\""}, {"Status", "/state", "rssi", "dBm", "signal_strength", "\"measurement\""},
{"Supply volt", "/state", "vcc", "V", "voltage", "\"measurement\""}, {"Supply volt", "/state", "vcc", "V", "voltage", "\"measurement\""},
{"Temperature", "/state", "temp", "C", "temperature", "\"measurement\""}, {"Temperature", "/state", "temp", "C", "temperature", "\"measurement\""},
{"Active import", "/power", "P", "W", "power", "\"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\""}, {"Reactive import", "/power", "Q", "VAr", "reactive_power", "\"measurement\""},
{"Active export", "/power", "PO", "W", "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\""}, {"Reactive export", "/power", "QO", "VAr", "reactive_power", "\"measurement\""},
{"L1 current", "/power", "I1", "A", "current", "\"measurement\""}, {"L1 current", "/power", "I1", "A", "current", "\"measurement\""},
{"L2 current", "/power", "I2", "A", "current", "\"measurement\""}, {"L2 current", "/power", "I2", "A", "current", "\"measurement\""},
@@ -32,6 +38,10 @@ HomeAssistantSensor HA_SENSORS[HA_SENSOR_COUNT] PROGMEM = {
{"Accumulated active export", "/energy", "tPO", "kWh", "energy", "\"total_increasing\""}, {"Accumulated active export", "/energy", "tPO", "kWh", "energy", "\"total_increasing\""},
{"Accumulated reactive import","/energy", "tQI", "kVArh","energy", "\"total_increasing\""}, {"Accumulated reactive import","/energy", "tQI", "kVArh","energy", "\"total_increasing\""},
{"Accumulated reactive export","/energy", "tQO", "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 current hour", "/prices", "prices['0']", "", "monetary", ""},
{"Price next hour", "/prices", "prices['1']", "", "monetary", ""}, {"Price next hour", "/prices", "prices['1']", "", "monetary", ""},
{"Price in two hour", "/prices", "prices['2']", "", "monetary", ""}, {"Price in two hour", "/prices", "prices['2']", "", "monetary", ""},

View File

@@ -111,8 +111,14 @@ 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(),
@@ -143,8 +149,9 @@ 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\":{");
@@ -173,7 +180,7 @@ bool JsonMqttHandler::publishPrices(EntsoeApi* eapi) {
time_t now = time(nullptr); time_t now = time(nullptr);
float min1hr, min3hr, min6hr; float min1hr = 0.0, min3hr = 0.0, min6hr = 0.0;
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];
@@ -223,7 +230,7 @@ bool JsonMqttHandler::publishPrices(EntsoeApi* eapi) {
} }
char ts1hr[21]; char ts1hr[24];
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);
@@ -231,7 +238,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[21]; char ts3hr[24];
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);
@@ -239,7 +246,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[21]; char ts6hr[24];
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,6 +11,24 @@ 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));
} }
@@ -106,7 +124,7 @@ bool RawMqttHandler::publishPrices(EntsoeApi* eapi) {
time_t now = time(nullptr); time_t now = time(nullptr);
float min1hr, min3hr, min6hr; float min1hr = 0.0, min3hr = 0.0, min6hr = 0.0;
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];
@@ -157,7 +175,7 @@ bool RawMqttHandler::publishPrices(EntsoeApi* eapi) {
} }
char ts1hr[21]; char ts1hr[24];
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);
@@ -165,7 +183,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[21]; char ts3hr[24];
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);
@@ -173,7 +191,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[21]; char ts6hr[24];
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

@@ -1007,7 +1007,7 @@ void AmsWebServer::handleSetup() {
server.sendHeader("Location", String("/"), true); server.sendHeader("Location", String("/"), true);
server.send (302, MIME_PLAIN, ""); server.send (302, MIME_PLAIN, "");
} else { } else {
SystemConfig sys { server.arg("board").toInt() }; SystemConfig sys { static_cast<uint8_t>(server.arg("board").toInt()) };
DebugConfig debugConfig; DebugConfig debugConfig;
config->getDebugConfig(debugConfig); config->getDebugConfig(debugConfig);
@@ -1077,6 +1077,16 @@ void AmsWebServer::handleSetup() {
gpioConfig->vccResistorGnd = 22; gpioConfig->vccResistorGnd = 22;
gpioConfig->vccResistorVcc = 33; gpioConfig->vccResistorVcc = 33;
break; break;
case 7: // Pow-U+
gpioConfig->hanPin = 16;
gpioConfig->apPin = 0;
gpioConfig->ledPinRed = 13;
gpioConfig->ledPinGreen = 14;
gpioConfig->ledRgbInverted = true;
gpioConfig->vccPin = 10;
gpioConfig->vccResistorGnd = 22;
gpioConfig->vccResistorVcc = 33;
break;
case 101: // D1 case 101: // D1
gpioConfig->hanPin = 5; gpioConfig->hanPin = 5;
gpioConfig->apPin = 4; gpioConfig->apPin = 4;
@@ -1277,11 +1287,11 @@ void AmsWebServer::handleSave() {
if(server.hasArg("dc") && server.arg("dc") == "true") { if(server.hasArg("dc") && server.arg("dc") == "true") {
printD("Received Domoticz config"); printD("Received Domoticz config");
DomoticzConfig domo { DomoticzConfig domo {
server.arg("elidx").toInt(), static_cast<uint16_t>(server.arg("elidx").toInt()),
server.arg("vl1idx").toInt(), static_cast<uint16_t>(server.arg("vl1idx").toInt()),
server.arg("vl2idx").toInt(), static_cast<uint16_t>(server.arg("vl2idx").toInt()),
server.arg("vl3idx").toInt(), static_cast<uint16_t>(server.arg("vl3idx").toInt()),
server.arg("cl1idx").toInt() static_cast<uint16_t>(server.arg("cl1idx").toInt())
}; };
config->setDomoticzConfig(domo); config->setDomoticzConfig(domo);
} }
@@ -1302,24 +1312,24 @@ void AmsWebServer::handleSave() {
config->setWebConfig(webConfig); config->setWebConfig(webConfig);
} }
if(server.hasArg("gpioConfig") && server.arg("gpioConfig") == "true") { if(server.hasArg("gc") && server.arg("gc") == "true") {
printD("Received GPIO config"); printD("Received GPIO config");
gpioConfig->hanPin = server.hasArg("hanPin") && !server.arg("hanPin").isEmpty() ? server.arg("hanPin").toInt() : 3; gpioConfig->hanPin = server.hasArg("h") && !server.arg("h").isEmpty() ? server.arg("h").toInt() : 3;
gpioConfig->ledPin = server.hasArg("ledPin") && !server.arg("ledPin").isEmpty() ? server.arg("ledPin").toInt() : 0xFF; gpioConfig->ledPin = server.hasArg("l") && !server.arg("l").isEmpty() ? server.arg("l").toInt() : 0xFF;
gpioConfig->ledInverted = server.hasArg("ledInverted") && server.arg("ledInverted") == "true"; gpioConfig->ledInverted = server.hasArg("i") && server.arg("i") == "true";
gpioConfig->ledPinRed = server.hasArg("ledPinRed") && !server.arg("ledPinRed").isEmpty() ? server.arg("ledPinRed").toInt() : 0xFF; gpioConfig->ledPinRed = server.hasArg("r") && !server.arg("r").isEmpty() ? server.arg("r").toInt() : 0xFF;
gpioConfig->ledPinGreen = server.hasArg("ledPinGreen") && !server.arg("ledPinGreen").isEmpty() ? server.arg("ledPinGreen").toInt() : 0xFF; gpioConfig->ledPinGreen = server.hasArg("e") && !server.arg("e").isEmpty() ? server.arg("e").toInt() : 0xFF;
gpioConfig->ledPinBlue = server.hasArg("ledPinBlue") && !server.arg("ledPinBlue").isEmpty() ? server.arg("ledPinBlue").toInt() : 0xFF; gpioConfig->ledPinBlue = server.hasArg("b") && !server.arg("b").isEmpty() ? server.arg("b").toInt() : 0xFF;
gpioConfig->ledRgbInverted = server.hasArg("ledRgbInverted") && server.arg("ledRgbInverted") == "true"; gpioConfig->ledRgbInverted = server.hasArg("n") && server.arg("n") == "true";
gpioConfig->apPin = server.hasArg("apPin") && !server.arg("apPin").isEmpty() ? server.arg("apPin").toInt() : 0xFF; gpioConfig->apPin = server.hasArg("a") && !server.arg("a").isEmpty() ? server.arg("a").toInt() : 0xFF;
gpioConfig->tempSensorPin = server.hasArg("tempSensorPin") && !server.arg("tempSensorPin").isEmpty() ?server.arg("tempSensorPin").toInt() : 0xFF; gpioConfig->tempSensorPin = server.hasArg("t") && !server.arg("t").isEmpty() ?server.arg("t").toInt() : 0xFF;
gpioConfig->tempAnalogSensorPin = server.hasArg("tempAnalogSensorPin") && !server.arg("tempAnalogSensorPin").isEmpty() ?server.arg("tempAnalogSensorPin").toInt() : 0xFF; gpioConfig->tempAnalogSensorPin = server.hasArg("m") && !server.arg("m").isEmpty() ?server.arg("m").toInt() : 0xFF;
gpioConfig->vccPin = server.hasArg("vccPin") && !server.arg("vccPin").isEmpty() ? server.arg("vccPin").toInt() : 0xFF; gpioConfig->vccPin = server.hasArg("v") && !server.arg("v").isEmpty() ? server.arg("v").toInt() : 0xFF;
gpioConfig->vccOffset = server.hasArg("vccOffset") && !server.arg("vccOffset").isEmpty() ? server.arg("vccOffset").toFloat() * 100 : 0; gpioConfig->vccOffset = server.hasArg("o") && !server.arg("o").isEmpty() ? server.arg("o").toFloat() * 100 : 0;
gpioConfig->vccMultiplier = server.hasArg("vccMultiplier") && !server.arg("vccMultiplier").isEmpty() ? server.arg("vccMultiplier").toFloat() * 1000 : 1000; gpioConfig->vccMultiplier = server.hasArg("u") && !server.arg("u").isEmpty() ? server.arg("u").toFloat() * 1000 : 1000;
gpioConfig->vccBootLimit = server.hasArg("vccBootLimit") && !server.arg("vccBootLimit").isEmpty() ? server.arg("vccBootLimit").toFloat() * 10 : 0; gpioConfig->vccBootLimit = server.hasArg("c") && !server.arg("c").isEmpty() ? server.arg("c").toFloat() * 10 : 0;
gpioConfig->vccResistorGnd = server.hasArg("vccResistorGnd") && !server.arg("vccResistorGnd").isEmpty() ? server.arg("vccResistorGnd").toInt() : 0; gpioConfig->vccResistorGnd = server.hasArg("d") && !server.arg("d").isEmpty() ? server.arg("d").toInt() : 0;
gpioConfig->vccResistorVcc = server.hasArg("vccResistorVcc") && !server.arg("vccResistorVcc").isEmpty() ? server.arg("vccResistorVcc").toInt() : 0; gpioConfig->vccResistorVcc = server.hasArg("s") && !server.arg("s").isEmpty() ? server.arg("s").toInt() : 0;
config->setGpioConfig(*gpioConfig); config->setGpioConfig(*gpioConfig);
} }
@@ -1358,8 +1368,8 @@ void AmsWebServer::handleSave() {
NtpConfig ntp { NtpConfig ntp {
server.hasArg("n") && server.arg("n") == "true", server.hasArg("n") && server.arg("n") == "true",
server.hasArg("nd") && server.arg("nd") == "true", server.hasArg("nd") && server.arg("nd") == "true",
server.arg("o").toInt() / 10, static_cast<int16_t>(server.arg("o").toInt() / 10),
server.arg("so").toInt() / 10 static_cast<int16_t>(server.arg("so").toInt() / 10)
}; };
strcpy(ntp.server, server.arg("ns").c_str()); strcpy(ntp.server, server.arg("ns").c_str());
config->setNtpConfig(ntp); config->setNtpConfig(ntp);
@@ -1451,32 +1461,32 @@ void AmsWebServer::configGpioHtml() {
String html = String((const __FlashStringHelper*) GPIO_HTML); String html = String((const __FlashStringHelper*) GPIO_HTML);
#if defined(CONFIG_IDF_TARGET_ESP32S2) #if defined(CONFIG_IDF_TARGET_ESP32S2)
html.replace("${gpio.max}", "44"); html.replace("${g}", "44");
#elif defined(ESP32) #elif defined(ESP32)
html.replace("${gpio.max}", "39"); html.replace("${g}", "39");
#else #else
html.replace("${gpio.max}", "16"); html.replace("${g}", "16");
#endif #endif
html.replace("${options.han}", getSerialSelectOptions(gpioConfig->hanPin)); html.replace("${h}", getSerialSelectOptions(gpioConfig->hanPin));
html.replace("${config.ledPin}", gpioConfig->ledPin == 0xFF ? "" : String(gpioConfig->ledPin)); html.replace("${l}", gpioConfig->ledPin == 0xFF ? "" : String(gpioConfig->ledPin));
html.replace("${config.ledInverted}", gpioConfig->ledInverted ? "checked" : ""); html.replace("${i}", gpioConfig->ledInverted ? "checked" : "");
html.replace("${config.ledPinRed}", gpioConfig->ledPinRed == 0xFF ? "" : String(gpioConfig->ledPinRed)); html.replace("${r}", gpioConfig->ledPinRed == 0xFF ? "" : String(gpioConfig->ledPinRed));
html.replace("${config.ledPinGreen}", gpioConfig->ledPinGreen == 0xFF ? "" : String(gpioConfig->ledPinGreen)); html.replace("${e}", gpioConfig->ledPinGreen == 0xFF ? "" : String(gpioConfig->ledPinGreen));
html.replace("${config.ledPinBlue}", gpioConfig->ledPinBlue == 0xFF ? "" : String(gpioConfig->ledPinBlue)); html.replace("${b}", gpioConfig->ledPinBlue == 0xFF ? "" : String(gpioConfig->ledPinBlue));
html.replace("${config.ledRgbInverted}", gpioConfig->ledRgbInverted ? "checked" : ""); html.replace("${n}", gpioConfig->ledRgbInverted ? "checked" : "");
html.replace("${config.apPin}", gpioConfig->apPin == 0xFF ? "" : String(gpioConfig->apPin)); html.replace("${a}", gpioConfig->apPin == 0xFF ? "" : String(gpioConfig->apPin));
html.replace("${config.tempSensorPin}", gpioConfig->tempSensorPin == 0xFF ? "" : String(gpioConfig->tempSensorPin)); html.replace("${t}", gpioConfig->tempSensorPin == 0xFF ? "" : String(gpioConfig->tempSensorPin));
html.replace("${config.tempAnalogSensorPin}", gpioConfig->tempAnalogSensorPin == 0xFF ? "" : String(gpioConfig->tempAnalogSensorPin)); html.replace("${m}", gpioConfig->tempAnalogSensorPin == 0xFF ? "" : String(gpioConfig->tempAnalogSensorPin));
html.replace("${config.vccPin}", gpioConfig->vccPin == 0xFF ? "" : String(gpioConfig->vccPin)); html.replace("${v}", gpioConfig->vccPin == 0xFF ? "" : String(gpioConfig->vccPin));
html.replace("${config.vccOffset}", gpioConfig->vccOffset > 0 ? String(gpioConfig->vccOffset / 100.0, 2) : ""); html.replace("${o}", gpioConfig->vccOffset > 0 ? String(gpioConfig->vccOffset / 100.0, 2) : "");
html.replace("${config.vccMultiplier}", gpioConfig->vccMultiplier > 0 ? String(gpioConfig->vccMultiplier / 1000.0, 2) : ""); html.replace("${u}", gpioConfig->vccMultiplier > 0 ? String(gpioConfig->vccMultiplier / 1000.0, 2) : "");
html.replace("${config.vccBootLimit}", gpioConfig->vccBootLimit > 0 ? String(gpioConfig->vccBootLimit / 10.0, 1) : ""); html.replace("${c}", gpioConfig->vccBootLimit > 0 ? String(gpioConfig->vccBootLimit / 10.0, 1) : "");
html.replace("${config.vccResistorGnd}", gpioConfig->vccResistorGnd > 0 ? String(gpioConfig->vccResistorGnd) : ""); html.replace("${d}", gpioConfig->vccResistorGnd > 0 ? String(gpioConfig->vccResistorGnd) : "");
html.replace("${config.vccResistorVcc}", gpioConfig->vccResistorVcc > 0 ? String(gpioConfig->vccResistorVcc) : ""); html.replace("${s}", gpioConfig->vccResistorVcc > 0 ? String(gpioConfig->vccResistorVcc) : "");
server.sendHeader(HEADER_CACHE_CONTROL, "no-cache, no-store, must-revalidate"); server.sendHeader(HEADER_CACHE_CONTROL, "no-cache, no-store, must-revalidate");
server.sendHeader("Pragma", "no-cache"); server.sendHeader("Pragma", "no-cache");
@@ -1589,21 +1599,21 @@ HTTPUpload& AmsWebServer::uploadFile(const char* path) {
} }
file = LittleFS.open(path, "w"); file = LittleFS.open(path, "w");
if(debugger->isActive(RemoteDebug::DEBUG)) { if(debugger->isActive(RemoteDebug::DEBUG)) {
debugger->printf("handleFileUpload Open file and write: %lu\n", upload.currentSize); debugger->printf("handleFileUpload Open file and write: %u\n", upload.currentSize);
} }
size_t written = file.write(upload.buf, upload.currentSize); size_t written = file.write(upload.buf, upload.currentSize);
if(debugger->isActive(RemoteDebug::DEBUG)) { if(debugger->isActive(RemoteDebug::DEBUG)) {
debugger->printf("handleFileUpload Written: %lu\n", written); debugger->printf("handleFileUpload Written: %u\n", written);
} }
} }
} else if(upload.status == UPLOAD_FILE_WRITE) { } else if(upload.status == UPLOAD_FILE_WRITE) {
if(debugger->isActive(RemoteDebug::DEBUG)) { if(debugger->isActive(RemoteDebug::DEBUG)) {
debugger->printf("handleFileUpload Writing: %lu\n", upload.currentSize); debugger->printf("handleFileUpload Writing: %u\n", upload.currentSize);
} }
if(file) { if(file) {
size_t written = file.write(upload.buf, upload.currentSize); size_t written = file.write(upload.buf, upload.currentSize);
if(debugger->isActive(RemoteDebug::DEBUG)) { if(debugger->isActive(RemoteDebug::DEBUG)) {
debugger->printf("handleFileUpload Written: %lu\n", written); debugger->printf("handleFileUpload Written: %u\n", written);
} }
delay(1); delay(1);
if(written != upload.currentSize) { if(written != upload.currentSize) {
@@ -2322,7 +2332,7 @@ void AmsWebServer::configFileDownload() {
ds->getHourImport(23) ds->getHourImport(23)
)); ));
if(day.activeExport > 0) { if(day.activeExport > 0) {
server.sendContent(buf, snprintf(buf, BufferSize, " %lu %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n", server.sendContent(buf, snprintf(buf, BufferSize, " %u %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
day.activeExport, day.activeExport,
ds->getHourExport(0), ds->getHourExport(0),
ds->getHourExport(1), ds->getHourExport(1),
@@ -2391,7 +2401,7 @@ void AmsWebServer::configFileDownload() {
ds->getDayImport(31) ds->getDayImport(31)
)); ));
if(month.activeExport > 0) { if(month.activeExport > 0) {
server.sendContent(buf, snprintf_P(buf, BufferSize, " %lu %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n", server.sendContent(buf, snprintf_P(buf, BufferSize, " %u %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
month.activeExport, month.activeExport,
ds->getDayExport(1), ds->getDayExport(1),
ds->getDayExport(2), ds->getDayExport(2),

View File

@@ -61,7 +61,11 @@ 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

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

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="gpioConfig" value="true"/> <input type="hidden" name="gc" 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="hanPin" class="form-control"> <select name="h" class="form-control">
${options.han} ${h}
</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="ledPin" type="number" min="2" max="${gpio.max}" class="form-control" value="${config.ledPin}"/> <input name="l" type="number" min="2" max="${g}" class="form-control" value="${l}"/>
<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="ledInverted" value="true" ${config.ledInverted}/> inv <input type="checkbox" name="i" value="true" ${i}/> 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="ledPinRed" type="number" min="2" max="${gpio.max}" class="form-control" value="${config.ledPinRed}"/> <input name="r" type="number" min="2" max="${g}" class="form-control" value="${r}"/>
<input name="ledPinGreen" type="number" min="2" max="${gpio.max}" class="form-control" value="${config.ledPinGreen}"/> <input name="e" type="number" min="2" max="${g}" class="form-control" value="${e}"/>
<input name="ledPinBlue" type="number" min="2" max="${gpio.max}" class="form-control" value="${config.ledPinBlue}"/> <input name="b" type="number" min="2" max="${g}" class="form-control" value="${b}"/>
<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="ledRgbInverted" value="true" ${config.ledRgbInverted}/> inv <input type="checkbox" name="n" value="true" ${n}/> 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="apPin" type="number" min="0" max="${gpio.max}" class="form-control" value="${config.apPin}"/> <input name="a" type="number" min="0" max="${g}" class="form-control" value="${a}"/>
</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="tempSensorPin" type="number" min="0" max="${gpio.max}" class="form-control" value="${config.tempSensorPin}"/> <input name="t" type="number" min="0" max="${g}" class="form-control" value="${t}"/>
</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="tempAnalogSensorPin" type="number" min="0" max="${gpio.max}" class="form-control" value="${config.tempAnalogSensorPin}"/> <input name="m" type="number" min="0" max="${g}" class="form-control" value="${m}"/>
</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="vccPin" type="number" min="0" max="${gpio.max}" class="form-control" value="${config.vccPin}"/> <input name="v" type="number" min="0" max="${g}" class="form-control" value="${v}"/>
</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="vccResistorGnd" value="${config.vccResistorGnd}" /> <input type="number" min="1" max="1000" step="1" class="form-control" name="d" value="${d}" />
<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="vccResistorVcc" value="${config.vccResistorVcc}" /> <input type="number" min="1" max="1000" step="1" class="form-control" name="s" value="${s}" />
<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="vccMultiplier" value="${config.vccMultiplier}" /> <input type="number" min="0.1" max="10" step="0.01" class="form-control" name="u" value="${u}" />
</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="vccOffset" value="${config.vccOffset}" /> <input type="number" min="0.0" max="3.5" step="0.01" class="form-control" name="o" value="${o}" />
</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="vccBootLimit" value="${config.vccBootLimit}" /> <input type="number" min="2.5" max="3.5" step="0.1" class="form-control" name="c" value="${c}" />
</div> </div>
</div> </div>
</div> </div>

View File

@@ -3,5 +3,5 @@
"tPO" : %.2f, "tPO" : %.2f,
"tQI" : %.2f, "tQI" : %.2f,
"tQO" : %.2f, "tQO" : %.2f,
"rtc" : %lu "rtc" : %lld
} }

View File

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

25
web/ha4.json Normal file
View File

@@ -0,0 +1,25 @@
{
"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,3 +1,4 @@
<!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">

View File

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

View File

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

View File

@@ -1,8 +1,8 @@
{ {
"id" : "%s", "id" : "%s",
"name" : "%s", "name" : "%s",
"up" : %lu, "up" : %u,
"t" : %lu, "t" : %lld,
"vcc" : %.3f, "vcc" : %.3f,
"rssi": %d, "rssi": %d,
"temp": %.2f, "temp": %.2f,
@@ -24,7 +24,7 @@
"tPO" : %.3f, "tPO" : %.3f,
"tQI" : %.3f, "tQI" : %.3f,
"tQO" : %.3f, "tQO" : %.3f,
"rtc" : %lu "rtc" : %lld
}, },
"realtime" : { "realtime" : {
"h" : %.2f, "h" : %.2f,

View File

@@ -1,8 +1,8 @@
{ {
"id" : "%s", "id" : "%s",
"name" : "%s", "name" : "%s",
"up" : %lu, "up" : %u,
"t" : %lu, "t" : %lld,
"vcc" : %.3f, "vcc" : %.3f,
"rssi": %d, "rssi": %d,
"temp": %.2f, "temp": %.2f,
@@ -11,8 +11,14 @@
"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,
@@ -28,7 +34,7 @@
"tPO" : %.2f, "tPO" : %.2f,
"tQI" : %.2f, "tQI" : %.2f,
"tQO" : %.2f, "tQO" : %.2f,
"rtc" : %lu "rtc" : %lld
}, },
"realtime" : { "realtime" : {
"h" : %.2f, "h" : %.2f,

View File

@@ -26,6 +26,7 @@
<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>