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
39 changed files with 179 additions and 491 deletions

View File

@@ -743,7 +743,7 @@ bool AmsConfiguration::relocateConfig86() {
}
bool AmsConfiguration::relocateConfig87() {
MeterConfig87 meter87 = {0,0,0,0,0,0,0};
MeterConfig87 meter87;
MeterConfig meter;
EEPROM.begin(EEPROM_SIZE);
EEPROM.get(CONFIG_METER_START_87, meter87);

View File

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

View File

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

View File

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

View File

@@ -119,6 +119,7 @@ DLMSParser *dlmsParser = NULL;
DSMRParser *dsmrParser = NULL;
void setup() {
WiFiConfig wifi;
Serial.begin(115200);
if(!config.getGpioConfig(gpioConfig)) {
@@ -245,6 +246,7 @@ void setup() {
}
Debug.setSerialEnabled(true);
DebugConfig debug;
delay(1);
float vcc = hw.getVcc();
@@ -434,10 +436,6 @@ void loop() {
}
}
if(now > 10000 && now - lastErrorBlink > 3000) {
errorBlink();
}
// Only do normal stuff if we're not booted as AP
if (WiFi.getMode() != WIFI_AP) {
if (WiFi.status() != WL_CONNECTED) {
@@ -508,6 +506,10 @@ void loop() {
MDNS.update();
#endif
if(now > 10000 && now - lastErrorBlink > 3000) {
errorBlink();
}
if (mqttEnabled || config.isMqttChanged()) {
if(mqtt == NULL || !mqtt->connected() || config.isMqttChanged()) {
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()) {
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(mqtt != NULL && mqttHandler != NULL && WiFi.getMode() != WIFI_AP && WiFi.status() == WL_CONNECTED && mqtt->connected() && !topic.isEmpty()) {
@@ -723,25 +725,22 @@ void errorBlink() {
if(lastError == 3)
lastError = 0;
lastErrorBlink = millis();
while(lastError < 3) {
switch(lastError++) {
for(;lastError < 3;lastError++) {
switch(lastError) {
case 0:
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
return;
}
break;
case 1:
if(mqttEnabled && mqtt != NULL && mqtt->lastError() != 0) {
debugW("MQTT connection not available, double blink");
hw.ledBlink(LED_RED, 2); // If MQTT error, blink twice
return;
}
break;
case 2:
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
return;
}
@@ -828,11 +827,6 @@ bool readHanPort() {
}
if(pos == DATA_PARSE_INCOMPLETE) {
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) {
@@ -991,34 +985,17 @@ void debugPrint(byte *buffer, int start, int length) {
Debug.println("");
}
unsigned long wifiTimeout = WIFI_CONNECTION_TIMEOUT;
unsigned long lastWifiRetry = -WIFI_CONNECTION_TIMEOUT;
void WiFi_connect() {
if(millis() - lastWifiRetry < wifiTimeout) {
delay(50);
return;
}
lastWifiRetry = millis();
if (WiFi.status() != WL_CONNECTED) {
if(WiFi.status() == WL_DISCONNECTED) {
if(millis() - lastWifiRetry < WIFI_CONNECTION_TIMEOUT) {
return;
}
}
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) {
ESP.restart();
return;
@@ -1052,13 +1029,11 @@ void WiFi_connect() {
WiFi.softAPdisconnect(true);
WiFi.enableAP(false);
WiFi.mode(WIFI_OFF);
#if defined(ESP8266)
WiFi.forceSleepBegin();
#endif
yield();
wifiTimeout = 5000;
return;
}
lastWifiRetry = millis();
wifiTimeout = WIFI_CONNECTION_TIMEOUT;
WiFiConfig wifi;
if(!config.getWiFiConfig(wifi) || strlen(wifi.ssid) == 0) {
@@ -1146,16 +1121,16 @@ void WiFi_connect() {
void mqttMessageReceived(String &topic, String &payload) {
debugI("Received message for topic %s", topic.c_str() );
//if(meterConfig.source == METER_SOURCE_MQTT) {
//DataParserContext ctx = {static_cast<uint8_t>(payload.length()/2)};
//fromHex(hanBuffer, payload, ctx.length);
//uint16_t pos = unwrapData(hanBuffer, ctx);
if(meterConfig.source == METER_SOURCE_MQTT) {
DataParserContext ctx = {payload.length()/2};
fromHex(hanBuffer, payload, ctx.length);
uint16_t pos = unwrapData(hanBuffer, ctx);
// TODO: Run through DLMS/DMSR parser and apply AmsData
//}
}
}
int16_t unwrapData(uint8_t *buf, DataParserContext &context) {
int16_t ret = 0;
int16_t ret;
bool doRet = false;
uint16_t end = BUF_SIZE_HAN;
uint8_t tag = (*buf);
@@ -1400,7 +1375,7 @@ void MQTT_connect() {
#if defined(ESP8266)
if(mqttSecureClient) {
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);
}
#endif

View File

@@ -57,7 +57,7 @@ bool EnergyAccounting::update(AmsData* amsData) {
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) 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;
}

View File

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

View File

@@ -296,38 +296,6 @@ IEC6205675::IEC6205675(const char* d, uint8_t useMeterType, MeterConfig* meterCo
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(listType >= 3) {
activeImportCounter *= 10;
@@ -368,16 +336,12 @@ IEC6205675::IEC6205675(const char* d, uint8_t useMeterType, MeterConfig* meterCo
if(mid != NULL) {
switch(mid->base.type) {
case CosemTypeString:
memcpy(str, mid->oct.data, mid->oct.length);
str[mid->oct.length] = 0x00;
meterId = String(str);
memcpy(&meterId, mid->str.data, mid->str.length);
meterId[mid->str.length] = 0;
break;
case CosemTypeOctetString:
memcpy(str, mid->str.data, mid->str.length);
str[mid->str.length] = 0x00;
meterId = String(str);
meterId[mid->str.length] = 0;
memcpy(&meterId, mid->oct.data, mid->oct.length);
meterId[mid->oct.length] = 0;
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_L2[4] = { 53, 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

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[4] == 0) {
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) {
if(descriptor->obis[4] == 0) {
activeImportCounter = ntohl(item->dlu.data) / 1000.0;
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) {
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) {
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) {
if(descriptor->obis[3] == 7) {
if(descriptor->obis[4] == 0) {
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) {
if(descriptor->obis[4] == 0) {
activeExportCounter = ntohl(item->dlu.data) / 1000.0;
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) {
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) {
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) {

View File

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

View File

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

View File

@@ -4,6 +4,7 @@ int8_t DSMRParser::parse(uint8_t *buf, DataParserContext &ctx, bool verified) {
uint16_t crcPos = 0;
bool reachedEnd = verified;
uint8_t lastByte = 0x00;
int c = 0;
for(int pos = 0; pos < ctx.length; pos++) {
uint8_t b = *(buf+pos);
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(initialization_vector, ctx.system_title, systemTitleLength);
int len = 0;
int len;
int headersize = 2 + systemTitleLength;
ptr += systemTitleLength;
if(((*ptr) & 0xFF) == 0x81) {

View File

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

View File

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

View File

@@ -5,6 +5,8 @@ int8_t MBUSParser::parse(uint8_t *d, DataParserContext &ctx) {
int headersize = 3;
int footersize = 1;
uint8_t flag = *d;
uint8_t* ptr;
// 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) {
for(size_t i = 0; i < size; i++) {
for(int i = 0; i < size; i++) {
write(buffer[i]);
}
return size;

View File

@@ -5,10 +5,6 @@ EntsoeA44Parser::EntsoeA44Parser() {
for(int i = 0; i < 24; i++) points[i] = ENTSOE_NO_VALUE;
}
EntsoeA44Parser::~EntsoeA44Parser() {
}
char* EntsoeA44Parser::getCurrency() {
return currency;
}
@@ -39,7 +35,7 @@ void EntsoeA44Parser::flush() {
}
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]);
}
return size;

View File

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

View File

@@ -106,11 +106,11 @@ bool EntsoeApi::loop() {
if(midnightMillis == 0) {
uint32_t curDayMillis = (((((tm.Hour * 60) + tm.Minute) * 60) + tm.Second) * 1000);
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;
return false;
} 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(tomorrow != NULL) {
today = tomorrow;

View File

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

View File

@@ -6,7 +6,6 @@
#include "web/root/ha1_json.h"
#include "web/root/ha2_json.h"
#include "web/root/ha3_json.h"
#include "web/root/ha4_json.h"
#include "web/root/jsonsys_json.h"
#include "web/root/jsonprices_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,
data->getActiveImportPower()
);
mqtt->publish(topic + "/power", json);
} else if(data->getListType() <= 3) { // publish power counts and volts/amps
return mqtt->publish(topic + "/power", json);
} else if(data->getListType() >= 2) { // publish power counts and volts/amps
snprintf_P(json, BufferSize, HA3_JSON,
data->getListId().c_str(),
data->getMeterId().c_str(),
@@ -49,63 +48,15 @@ bool HomeAssistantMqttHandler::publish(AmsData* data, AmsData* previousState, En
data->getL3Current(),
data->getL1Voltage(),
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->getPowerFactor() == 0 ? 1 : data->getPowerFactor(),
data->getPowerFactor() == 0 ? 1 : data->getL1PowerFactor(),
data->getPowerFactor() == 0 ? 1 : data->getL2PowerFactor(),
data->getPowerFactor() == 0 ? 1 : data->getL3PowerFactor()
);
mqtt->publish(topic + "/power", json);
return mqtt->publish(topic + "/power", json);
}
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;
}
return false;}
bool HomeAssistantMqttHandler::publishTemperatures(AmsConfiguration* config, HwTools* hw) {
int count = hw->getTempSensorCount();
@@ -141,7 +92,7 @@ bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) {
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;
float min = INT16_MAX, max = INT16_MIN;
float values[24];
@@ -191,7 +142,7 @@ bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) {
}
char ts1hr[24];
char ts1hr[21];
if(min1hrIdx > -1) {
time_t ts = now + (SECS_PER_HOUR * min1hrIdx);
//Serial.printf("1hr: %d %lu\n", min1hrIdx, ts);
@@ -199,7 +150,7 @@ bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) {
breakTime(ts, tm);
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) {
time_t ts = now + (SECS_PER_HOUR * min3hrIdx);
//Serial.printf("3hr: %d %lu\n", min3hrIdx, ts);
@@ -207,7 +158,7 @@ bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) {
breakTime(ts, tm);
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) {
time_t ts = now + (SECS_PER_HOUR * min6hrIdx);
//Serial.printf("6hr: %d %lu\n", min6hrIdx, ts);
@@ -236,7 +187,7 @@ bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) {
ts3hr,
ts6hr
);
return mqtt->publish(topic + "/prices", json, true, 0);
return mqtt->publish(topic + "/prices", json);
}
bool HomeAssistantMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea) {
@@ -266,48 +217,28 @@ bool HomeAssistantMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, Energ
#endif
String haUrl = "http://" + haUID + ".local/";
// 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<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++;
}
for(int i=0;i<17;i++){
snprintf_P(json, BufferSize, HADISCOVER_JSON,
sensor.name,
topic.c_str(), sensor.topic,
haUID.c_str(), uid.c_str(),
haUID.c_str(), uid.c_str(),
uom.c_str(),
sensor.path,
sensor.devcl,
FPSTR(HA_NAMES[i]),
topic.c_str(), FPSTR(HA_TOPICS[i]),
haUID.c_str(), FPSTR(HA_PARAMS[i]),
haUID.c_str(), FPSTR(HA_PARAMS[i]),
FPSTR(HA_UOM[i]),
FPSTR(HA_PARAMS[i]),
FPSTR(HA_DEVCL[i]),
haUID.c_str(),
haName.c_str(),
haModel.c_str(),
VERSION,
haManuf.c_str(),
haUrl.c_str(),
strlen_P(sensor.stacl) > 0 ? ", \"stat_cla\" :" : "",
strlen_P(sensor.stacl) > 0 ? (char *) FPSTR(sensor.stacl) : ""
strlen_P(HA_STACL[i]) > 0 ? ", \"stat_cla\" :" : "",
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;
}
if(listType>0) sequence++;
return true;
}
return true;}

View File

@@ -3,79 +3,12 @@
#include "Arduino.h"
struct HomeAssistantSensor {
const char* name;
const char* topic;
const char* path;
const char* uom;
const char* devcl;
const char* stacl;
};
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* HA_NAMES[17] PROGMEM = {"Status", "Supply volt", "Temperature", "Active import", "Reactive import", "Active export", "Reactive export", "L1 current", "L2 current", "L3 current",
"L1 voltage", "L2 voltage", "L3 voltage", "Accumulated active import", "Accumulated active export", "Accumulated reactive import", "Accumulated reactive export"};
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* HA_UOM[17] PROGMEM = {"dBm", "V", "C", "W", "W", "W", "W", "A", "A", "A", "V", "V", "V", "kWh", "kWh", "kWh", "kWh"};
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* HA_STACL[17] PROGMEM = {"", "", "", "\"measurement\"", "\"measurement\"", "\"measurement\"", "\"measurement\"", "", "", "", "", "", "", "\"total_increasing\"", "\"total_increasing\"", "\"total_increasing\"", "\"total_increasing\""};
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
#endif

View File

@@ -111,14 +111,8 @@ bool JsonMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyAccou
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(),
@@ -149,9 +143,8 @@ bool JsonMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyAccou
bool JsonMqttHandler::publishTemperatures(AmsConfiguration* config, HwTools* hw) {
int count = hw->getTempSensorCount();
if(count < 2) {
if(count < 2)
return false;
}
snprintf(json, 24, "{\"temperatures\":{");
@@ -180,7 +173,7 @@ bool JsonMqttHandler::publishPrices(EntsoeApi* eapi) {
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;
float min = INT16_MAX, max = INT16_MIN;
float values[24];
@@ -230,7 +223,7 @@ bool JsonMqttHandler::publishPrices(EntsoeApi* eapi) {
}
char ts1hr[24];
char ts1hr[21];
if(min1hrIdx > -1) {
time_t ts = now + (SECS_PER_HOUR * min1hrIdx);
//Serial.printf("1hr: %d %lu\n", min1hrIdx, ts);
@@ -238,7 +231,7 @@ bool JsonMqttHandler::publishPrices(EntsoeApi* eapi) {
breakTime(ts, tm);
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) {
time_t ts = now + (SECS_PER_HOUR * min3hrIdx);
//Serial.printf("3hr: %d %lu\n", min3hrIdx, ts);
@@ -246,7 +239,7 @@ bool JsonMqttHandler::publishPrices(EntsoeApi* eapi) {
breakTime(ts, tm);
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) {
time_t ts = now + (SECS_PER_HOUR * min6hrIdx);
//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()) {
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()) {
mqtt->publish(topic + "/meter/powerfactor", String(data->getPowerFactor(), 2));
}
@@ -124,7 +106,7 @@ bool RawMqttHandler::publishPrices(EntsoeApi* eapi) {
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;
float min = INT16_MAX, max = INT16_MIN;
float values[34];
@@ -175,7 +157,7 @@ bool RawMqttHandler::publishPrices(EntsoeApi* eapi) {
}
char ts1hr[24];
char ts1hr[21];
if(min1hrIdx > -1) {
time_t ts = now + (SECS_PER_HOUR * min1hrIdx);
//Serial.printf("1hr: %d %lu\n", min1hrIdx, ts);
@@ -183,7 +165,7 @@ bool RawMqttHandler::publishPrices(EntsoeApi* eapi) {
breakTime(ts, tm);
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) {
time_t ts = now + (SECS_PER_HOUR * min3hrIdx);
//Serial.printf("3hr: %d %lu\n", min3hrIdx, ts);
@@ -191,7 +173,7 @@ bool RawMqttHandler::publishPrices(EntsoeApi* eapi) {
breakTime(ts, tm);
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) {
time_t ts = now + (SECS_PER_HOUR * min6hrIdx);
//Serial.printf("6hr: %d %lu\n", min6hrIdx, ts);

View File

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

View File

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

View File

@@ -23,8 +23,8 @@
"v" : %.3f,
"r" : %d,
"t" : %.2f,
"u" : %u,
"m" : %u,
"u" : %lu,
"m" : %lu,
"em" : %d,
"hm" : %d,
"wm" : %d,
@@ -53,5 +53,5 @@
"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>
<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">
<h6>GPIO settings</h6>
<div class="d-flex flex-row flex-wrap">
@@ -8,18 +8,18 @@
<div class="input-group-prepend">
<span class="input-group-text">HAN</span>
</div>
<select name="h" class="form-control">
${h}
<select name="hanPin" class="form-control">
${options.han}
</select>
</div>
<div class="m-2 input-group input-group-sm" style="width: 150px;">
<div class="input-group-prepend">
<span class="input-group-text">LED</span>
</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">
<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>
</div>
</div>
@@ -27,12 +27,12 @@
<div class="input-group-prepend">
<span class="input-group-text">RGB</span>
</div>
<input name="r" type="number" min="2" max="${g}" class="form-control" value="${r}"/>
<input name="e" type="number" min="2" max="${g}" class="form-control" value="${e}"/>
<input name="b" type="number" min="2" max="${g}" class="form-control" value="${b}"/>
<input name="ledPinRed" type="number" min="2" max="${gpio.max}" class="form-control" value="${config.ledPinRed}"/>
<input name="ledPinGreen" type="number" min="2" max="${gpio.max}" class="form-control" value="${config.ledPinGreen}"/>
<input name="ledPinBlue" type="number" min="2" max="${gpio.max}" class="form-control" value="${config.ledPinBlue}"/>
<div class="input-group-append" title="Inverted">
<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>
</div>
</div>
@@ -40,31 +40,31 @@
<div class="input-group-prepend">
<span class="input-group-text">AP button</span>
</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 class="m-2 input-group input-group-sm" style="width: 150px;">
<div class="input-group-prepend">
<span class="input-group-text">Temperature</span>
</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 class="m-2 input-group input-group-sm" style="width: 150px;">
<div class="input-group-prepend">
<span class="input-group-text">Analog temp</span>
</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 class="m-2 input-group input-group-sm" style="width: 100px;">
<div class="input-group-prepend">
<span class="input-group-text">Vcc</span>
</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 class="m-2 input-group input-group-sm" style="width: 200px;">
<div class="input-group-prepend">
<span class="input-group-text">GND resistor</span>
</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">
<label class="input-group-text">k&ohm;</label>
</div>
@@ -73,7 +73,7 @@
<div class="input-group-prepend">
<span class="input-group-text">Vcc resistor</span>
</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">
<label class="input-group-text">k&ohm;</label>
</div>
@@ -82,19 +82,19 @@
<div class="input-group-prepend">
<span class="input-group-text">Multiplier</span>
</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 class="m-2 input-group input-group-sm" style="width: 120px;">
<div class="input-group-prepend">
<span class="input-group-text">Offset</span>
</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 class="m-2 input-group input-group-sm" style="width: 130px;">
<div class="input-group-prepend">
<span class="input-group-text">Boot limit</span>
</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>

View File

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

View File

@@ -11,5 +11,9 @@
"I3" : %.2f,
"U1" : %.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>
<head>
<meta charset="UTF-8">

View File

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

View File

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

View File

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

View File

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

View File

@@ -26,7 +26,6 @@
<select name="board" class="form-control" required>
<option value=""></option>
<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="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>