mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-03-11 04:57:28 +00:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
39e86fa180 | ||
|
|
5d278a9d5a | ||
|
|
61040e3e7c | ||
|
|
c4005f10a3 | ||
|
|
7bed5add5d | ||
|
|
18e382f21f | ||
|
|
94865b632e | ||
|
|
f0461a7cdb | ||
|
|
4cd6013d64 | ||
|
|
b06dbb8d79 | ||
|
|
02fe2073c2 | ||
|
|
ec7ceafa84 | ||
|
|
276ac67d2e | ||
|
|
be116d5b35 | ||
|
|
9c8788225d | ||
|
|
df44b05792 | ||
|
|
8ee8eee6c4 | ||
|
|
28e13b73e6 | ||
|
|
088e5645c7 | ||
|
|
3e3d61912d | ||
|
|
b7854baa6d | ||
|
|
68bbfd6527 | ||
|
|
c1ca3d0c65 | ||
|
|
71cac46470 |
@@ -11,6 +11,7 @@
|
||||
|
||||
#define CONFIG_SYSTEM_START 8
|
||||
#define CONFIG_METER_START 32
|
||||
#define CONFIG_UPGRADE_INFO_START 216
|
||||
#define CONFIG_UI_START 248
|
||||
#define CONFIG_GPIO_START 266
|
||||
#define CONFIG_ENTSOE_START 290
|
||||
@@ -213,6 +214,13 @@ struct TempSensorConfig {
|
||||
bool common;
|
||||
};
|
||||
|
||||
struct UpgradeInformation {
|
||||
char fromVersion[8];
|
||||
char toVersion[8];
|
||||
int16_t exitCode;
|
||||
int16_t errorCode;
|
||||
}; // 20
|
||||
|
||||
class AmsConfiguration {
|
||||
public:
|
||||
bool hasConfig();
|
||||
@@ -244,6 +252,7 @@ public:
|
||||
bool getMeterConfig(MeterConfig&);
|
||||
bool setMeterConfig(MeterConfig&);
|
||||
void clearMeter(MeterConfig&);
|
||||
void setMeterChanged();
|
||||
bool isMeterChanged();
|
||||
void ackMeterChanged();
|
||||
|
||||
@@ -297,6 +306,10 @@ public:
|
||||
|
||||
bool isSensorAddressEqual(uint8_t a[8], uint8_t b[8]);
|
||||
|
||||
bool getUpgradeInformation(UpgradeInformation&);
|
||||
bool setUpgradeInformation(int16_t exitCode, int16_t errorCode, const char* currentVersion, const char* nextVersion);
|
||||
void clearUpgradeInformation(UpgradeInformation&);
|
||||
|
||||
void clear();
|
||||
|
||||
protected:
|
||||
|
||||
@@ -7,6 +7,6 @@
|
||||
String toHex(uint8_t* in);
|
||||
String toHex(uint8_t* in, uint16_t size);
|
||||
void fromHex(uint8_t *out, String in, uint16_t size);
|
||||
void stripNonAscii(uint8_t* in, uint16_t size, bool extended = false);
|
||||
bool stripNonAscii(uint8_t* in, uint16_t size, bool extended = false);
|
||||
|
||||
#endif
|
||||
@@ -266,6 +266,10 @@ void AmsConfiguration::ackMeterChanged() {
|
||||
meterChanged = false;
|
||||
}
|
||||
|
||||
void AmsConfiguration::setMeterChanged() {
|
||||
meterChanged = true;
|
||||
}
|
||||
|
||||
bool AmsConfiguration::getDebugConfig(DebugConfig& config) {
|
||||
if(hasConfig()) {
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
@@ -337,6 +341,9 @@ bool AmsConfiguration::getHomeAssistantConfig(HomeAssistantConfig& config) {
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
EEPROM.get(CONFIG_HA_START, config);
|
||||
EEPROM.end();
|
||||
if(stripNonAscii((uint8_t*) config.discoveryPrefix, 64) || stripNonAscii((uint8_t*) config.discoveryHostname, 64) || stripNonAscii((uint8_t*) config.discoveryNameTag, 16)) {
|
||||
clearHomeAssistantConfig(config);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
clearHomeAssistantConfig(config);
|
||||
@@ -408,39 +415,39 @@ bool AmsConfiguration::setGpioConfig(GpioConfig& config) {
|
||||
}
|
||||
/* This currently does not work, as it checks its own pin
|
||||
if(pinUsed(config.hanPin, config)) {
|
||||
Serial.println("HAN pin already used");
|
||||
debugger->println(F("HAN pin already used"));
|
||||
return false;
|
||||
}
|
||||
if(pinUsed(config.apPin, config)) {
|
||||
Serial.println("AP pin already used");
|
||||
debugger->println(F("AP pin already used"));
|
||||
return false;
|
||||
}
|
||||
if(pinUsed(config.ledPin, config)) {
|
||||
Serial.println("LED pin already used");
|
||||
debugger->println(F("LED pin already used"));
|
||||
return false;
|
||||
}
|
||||
if(pinUsed(config.ledPinRed, config)) {
|
||||
Serial.println("LED RED pin already used");
|
||||
debugger->println(F("LED RED pin already used"));
|
||||
return false;
|
||||
}
|
||||
if(pinUsed(config.ledPinGreen, config)) {
|
||||
Serial.println("LED GREEN pin already used");
|
||||
debugger->println(F("LED GREEN pin already used"));
|
||||
return false;
|
||||
}
|
||||
if(pinUsed(config.ledPinBlue, config)) {
|
||||
Serial.println("LED BLUE pin already used");
|
||||
debugger->println(F("LED BLUE pin already used"));
|
||||
return false;
|
||||
}
|
||||
if(pinUsed(config.tempSensorPin, config)) {
|
||||
Serial.println("Temp sensor pin already used");
|
||||
debugger->println(F("Temp sensor pin already used"));
|
||||
return false;
|
||||
}
|
||||
if(pinUsed(config.tempAnalogSensorPin, config)) {
|
||||
Serial.println("Analog temp sensor pin already used");
|
||||
debugger->println(F("Analog temp sensor pin already used"));
|
||||
return false;
|
||||
}
|
||||
if(pinUsed(config.vccPin, config)) {
|
||||
Serial.println("Vcc pin already used");
|
||||
debugger->println(F("Vcc pin already used"));
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
@@ -679,6 +686,45 @@ void AmsConfiguration::clearUiConfig(UiConfig& config) {
|
||||
config.showTemperaturePlot = 2;
|
||||
}
|
||||
|
||||
bool AmsConfiguration::setUpgradeInformation(int16_t exitCode, int16_t errorCode, const char* currentVersion, const char* nextVersion) {
|
||||
UpgradeInformation upinfo;
|
||||
upinfo.exitCode = exitCode;
|
||||
upinfo.errorCode = errorCode;
|
||||
strcpy(upinfo.fromVersion, currentVersion);
|
||||
strcpy(upinfo.toVersion, nextVersion);
|
||||
|
||||
stripNonAscii((uint8_t*) upinfo.fromVersion, 8);
|
||||
stripNonAscii((uint8_t*) upinfo.toVersion, 8);
|
||||
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
EEPROM.put(CONFIG_UPGRADE_INFO_START, upinfo);
|
||||
bool ret = EEPROM.commit();
|
||||
EEPROM.end();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool AmsConfiguration::getUpgradeInformation(UpgradeInformation& upinfo) {
|
||||
if(hasConfig()) {
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
EEPROM.get(CONFIG_UPGRADE_INFO_START, upinfo);
|
||||
EEPROM.end();
|
||||
if(stripNonAscii((uint8_t*) upinfo.fromVersion, 8) || stripNonAscii((uint8_t*) upinfo.toVersion, 8)) {
|
||||
clearUpgradeInformation(upinfo);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
clearUpgradeInformation(upinfo);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void AmsConfiguration::clearUpgradeInformation(UpgradeInformation& upinfo) {
|
||||
upinfo.exitCode = -1;
|
||||
upinfo.errorCode = 0;
|
||||
memset(upinfo.fromVersion, 0, 8);
|
||||
memset(upinfo.toVersion, 0, 8);
|
||||
}
|
||||
|
||||
|
||||
void AmsConfiguration::clear() {
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
@@ -710,6 +756,10 @@ void AmsConfiguration::clear() {
|
||||
clearDomo(domo);
|
||||
EEPROM.put(CONFIG_DOMOTICZ_START, domo);
|
||||
|
||||
HomeAssistantConfig haconf;
|
||||
clearHomeAssistantConfig(haconf);
|
||||
EEPROM.put(CONFIG_HA_START, haconf);
|
||||
|
||||
NtpConfig ntp;
|
||||
clearNtp(ntp);
|
||||
EEPROM.put(CONFIG_NTP_START, ntp);
|
||||
@@ -730,6 +780,10 @@ void AmsConfiguration::clear() {
|
||||
clearUiConfig(ui);
|
||||
EEPROM.put(CONFIG_UI_START, ui);
|
||||
|
||||
UpgradeInformation upinfo;
|
||||
clearUpgradeInformation(upinfo);
|
||||
EEPROM.put(CONFIG_UPGRADE_INFO_START, upinfo);
|
||||
|
||||
EEPROM.put(EEPROM_CONFIG_ADDRESS, EEPROM_CLEARED_INDICATOR);
|
||||
EEPROM.commit();
|
||||
EEPROM.end();
|
||||
@@ -825,8 +879,6 @@ void AmsConfiguration::loadTempSensors() {
|
||||
int address = EEPROM_TEMP_CONFIG_ADDRESS;
|
||||
int c = 0;
|
||||
int storedCount = EEPROM.read(address++);
|
||||
Serial.print("Sensors: ");
|
||||
Serial.println(storedCount);
|
||||
if(storedCount > 0 && storedCount <= 32) {
|
||||
for(int i = 0; i < storedCount; i++) {
|
||||
TempSensorConfig* tsc = new TempSensorConfig();
|
||||
@@ -1128,155 +1180,155 @@ void AmsConfiguration::deleteFromFs(uint8_t version) {
|
||||
|
||||
void AmsConfiguration::print(Print* debugger)
|
||||
{
|
||||
debugger->println("-----------------------------------------------");
|
||||
debugger->println(F("-----------------------------------------------"));
|
||||
WiFiConfig wifi;
|
||||
if(getWiFiConfig(wifi)) {
|
||||
debugger->println("--WiFi configuration--");
|
||||
debugger->printf("SSID: '%s'\r\n", wifi.ssid);
|
||||
debugger->printf("Psk: '%s'\r\n", wifi.psk);
|
||||
debugger->println(F("--WiFi configuration--"));
|
||||
debugger->printf_P(PSTR("SSID: '%s'\r\n"), wifi.ssid);
|
||||
debugger->printf_P(PSTR("Psk: '%s'\r\n"), wifi.psk);
|
||||
if(strlen(wifi.ip) > 0) {
|
||||
debugger->printf("IP: '%s'\r\n", wifi.ip);
|
||||
debugger->printf("Gateway: '%s'\r\n", wifi.gateway);
|
||||
debugger->printf("Subnet: '%s'\r\n", wifi.subnet);
|
||||
debugger->printf("DNS1: '%s'\r\n", wifi.dns1);
|
||||
debugger->printf("DNS2: '%s'\r\n", wifi.dns2);
|
||||
debugger->printf_P(PSTR("IP: '%s'\r\n"), wifi.ip);
|
||||
debugger->printf_P(PSTR("Gateway: '%s'\r\n"), wifi.gateway);
|
||||
debugger->printf_P(PSTR("Subnet: '%s'\r\n"), wifi.subnet);
|
||||
debugger->printf_P(PSTR("DNS1: '%s'\r\n"), wifi.dns1);
|
||||
debugger->printf_P(PSTR("DNS2: '%s'\r\n"), wifi.dns2);
|
||||
}
|
||||
debugger->printf("Hostname: '%s'\r\n", wifi.hostname);
|
||||
debugger->printf("mDNS: '%s'\r\n", wifi.mdns ? "Yes" : "No");
|
||||
debugger->println("");
|
||||
debugger->printf_P(PSTR("Hostname: '%s'\r\n"), wifi.hostname);
|
||||
debugger->printf_P(PSTR("mDNS: '%s'\r\n"), wifi.mdns ? "Yes" : "No");
|
||||
debugger->println(F(""));
|
||||
delay(10);
|
||||
Serial.flush();
|
||||
debugger->flush();
|
||||
}
|
||||
|
||||
MqttConfig mqtt;
|
||||
if(getMqttConfig(mqtt)) {
|
||||
debugger->println("--MQTT configuration--");
|
||||
debugger->println(F("--MQTT configuration--"));
|
||||
if(strlen(mqtt.host) > 0) {
|
||||
debugger->printf("Enabled: Yes\r\n");
|
||||
debugger->printf("Host: '%s'\r\n", mqtt.host);
|
||||
debugger->printf("Port: %i\r\n", mqtt.port);
|
||||
debugger->printf("Client ID: '%s'\r\n", mqtt.clientId);
|
||||
debugger->printf("Publish topic: '%s'\r\n", mqtt.publishTopic);
|
||||
debugger->printf("Subscribe topic: '%s'\r\n", mqtt.subscribeTopic);
|
||||
debugger->printf_P(PSTR("Enabled: Yes\r\n"));
|
||||
debugger->printf_P(PSTR("Host: '%s'\r\n"), mqtt.host);
|
||||
debugger->printf_P(PSTR("Port: %i\r\n"), mqtt.port);
|
||||
debugger->printf_P(PSTR("Client ID: '%s'\r\n"), mqtt.clientId);
|
||||
debugger->printf_P(PSTR("Publish topic: '%s'\r\n"), mqtt.publishTopic);
|
||||
debugger->printf_P(PSTR("Subscribe topic: '%s'\r\n"), mqtt.subscribeTopic);
|
||||
if (strlen(mqtt.username) > 0) {
|
||||
debugger->printf("Username: '%s'\r\n", mqtt.username);
|
||||
debugger->printf("Password: '%s'\r\n", mqtt.password);
|
||||
debugger->printf_P(PSTR("Username: '%s'\r\n"), mqtt.username);
|
||||
debugger->printf_P(PSTR("Password: '%s'\r\n"), mqtt.password);
|
||||
}
|
||||
debugger->printf("Payload format: %i\r\n", mqtt.payloadFormat);
|
||||
debugger->printf("SSL: %s\r\n", mqtt.ssl ? "Yes" : "No");
|
||||
debugger->printf_P(PSTR("Payload format: %i\r\n"), mqtt.payloadFormat);
|
||||
debugger->printf_P(PSTR("SSL: %s\r\n"), mqtt.ssl ? "Yes" : "No");
|
||||
} else {
|
||||
debugger->printf("Enabled: No\r\n");
|
||||
debugger->printf_P(PSTR("Enabled: No\r\n"));
|
||||
}
|
||||
debugger->println("");
|
||||
debugger->println(F(""));
|
||||
delay(10);
|
||||
Serial.flush();
|
||||
debugger->flush();
|
||||
}
|
||||
|
||||
WebConfig web;
|
||||
if(getWebConfig(web)) {
|
||||
debugger->println("--Web configuration--");
|
||||
debugger->printf("Security: %i\r\n", web.security);
|
||||
debugger->println(F("--Web configuration--"));
|
||||
debugger->printf_P(PSTR("Security: %i\r\n"), web.security);
|
||||
if (web.security > 0) {
|
||||
debugger->printf("Username: '%s'\r\n", web.username);
|
||||
debugger->printf("Password: '%s'\r\n", web.password);
|
||||
debugger->printf_P(PSTR("Username: '%s'\r\n"), web.username);
|
||||
debugger->printf_P(PSTR("Password: '%s'\r\n"), web.password);
|
||||
}
|
||||
debugger->println("");
|
||||
debugger->println(F(""));
|
||||
delay(10);
|
||||
Serial.flush();
|
||||
debugger->flush();
|
||||
}
|
||||
|
||||
MeterConfig meter;
|
||||
if(getMeterConfig(meter)) {
|
||||
debugger->println("--Meter configuration--");
|
||||
debugger->printf("Baud: %i\r\n", meter.baud);
|
||||
debugger->printf("Parity: %i\r\n", meter.parity);
|
||||
debugger->printf("Invert serial: %s\r\n", meter.invert ? "Yes" : "No");
|
||||
debugger->printf("Distribution system: %i\r\n", meter.distributionSystem);
|
||||
debugger->printf("Main fuse: %i\r\n", meter.mainFuse);
|
||||
debugger->printf("Production Capacity: %i\r\n", meter.productionCapacity);
|
||||
debugger->println("");
|
||||
debugger->println(F("--Meter configuration--"));
|
||||
debugger->printf_P(PSTR("Baud: %i\r\n"), meter.baud);
|
||||
debugger->printf_P(PSTR("Parity: %i\r\n"), meter.parity);
|
||||
debugger->printf_P(PSTR("Invert serial: %s\r\n"), meter.invert ? "Yes" : "No");
|
||||
debugger->printf_P(PSTR("Distribution system: %i\r\n"), meter.distributionSystem);
|
||||
debugger->printf_P(PSTR("Main fuse: %i\r\n"), meter.mainFuse);
|
||||
debugger->printf_P(PSTR("Production Capacity: %i\r\n"), meter.productionCapacity);
|
||||
debugger->println(F(""));
|
||||
delay(10);
|
||||
Serial.flush();
|
||||
debugger->flush();
|
||||
}
|
||||
|
||||
GpioConfig gpio;
|
||||
if(getGpioConfig(gpio)) {
|
||||
debugger->println("--GPIO configuration--");
|
||||
debugger->printf("HAN pin: %i\r\n", gpio.hanPin);
|
||||
debugger->printf("HAN pin pullup %s\r\n", gpio.hanPinPullup ? "Yes" : "No");
|
||||
debugger->printf("LED pin: %i\r\n", gpio.ledPin);
|
||||
debugger->printf("LED inverted: %s\r\n", gpio.ledInverted ? "Yes" : "No");
|
||||
debugger->printf("LED red pin: %i\r\n", gpio.ledPinRed);
|
||||
debugger->printf("LED green pin: %i\r\n", gpio.ledPinGreen);
|
||||
debugger->printf("LED blue pin: %i\r\n", gpio.ledPinBlue);
|
||||
debugger->printf("LED inverted: %s\r\n", gpio.ledRgbInverted ? "Yes" : "No");
|
||||
debugger->printf("AP pin: %i\r\n", gpio.apPin);
|
||||
debugger->printf("Temperature pin: %i\r\n", gpio.tempSensorPin);
|
||||
debugger->printf("Temp analog pin: %i\r\n", gpio.tempAnalogSensorPin);
|
||||
debugger->printf("Vcc pin: %i\r\n", gpio.vccPin);
|
||||
debugger->println(F("--GPIO configuration--"));
|
||||
debugger->printf_P(PSTR("HAN pin: %i\r\n"), gpio.hanPin);
|
||||
debugger->printf_P(PSTR("HAN pin pullup %s\r\n"), gpio.hanPinPullup ? "Yes" : "No");
|
||||
debugger->printf_P(PSTR("LED pin: %i\r\n"), gpio.ledPin);
|
||||
debugger->printf_P(PSTR("LED inverted: %s\r\n"), gpio.ledInverted ? "Yes" : "No");
|
||||
debugger->printf_P(PSTR("LED red pin: %i\r\n"), gpio.ledPinRed);
|
||||
debugger->printf_P(PSTR("LED green pin: %i\r\n"), gpio.ledPinGreen);
|
||||
debugger->printf_P(PSTR("LED blue pin: %i\r\n"), gpio.ledPinBlue);
|
||||
debugger->printf_P(PSTR("LED inverted: %s\r\n"), gpio.ledRgbInverted ? "Yes" : "No");
|
||||
debugger->printf_P(PSTR("AP pin: %i\r\n"), gpio.apPin);
|
||||
debugger->printf_P(PSTR("Temperature pin: %i\r\n"), gpio.tempSensorPin);
|
||||
debugger->printf_P(PSTR("Temp analog pin: %i\r\n"), gpio.tempAnalogSensorPin);
|
||||
debugger->printf_P(PSTR("Vcc pin: %i\r\n"), gpio.vccPin);
|
||||
if(gpio.vccMultiplier > 0) {
|
||||
debugger->printf("Vcc multiplier: %f\r\n", gpio.vccMultiplier / 1000.0);
|
||||
debugger->printf_P(PSTR("Vcc multiplier: %f\r\n"), gpio.vccMultiplier / 1000.0);
|
||||
}
|
||||
if(gpio.vccOffset > 0) {
|
||||
debugger->printf("Vcc offset: %f\r\n", gpio.vccOffset / 100.0);
|
||||
debugger->printf_P(PSTR("Vcc offset: %f\r\n"), gpio.vccOffset / 100.0);
|
||||
}
|
||||
if(gpio.vccBootLimit > 0) {
|
||||
debugger->printf("Vcc boot limit: %f\r\n", gpio.vccBootLimit / 10.0);
|
||||
debugger->printf_P(PSTR("Vcc boot limit: %f\r\n"), gpio.vccBootLimit / 10.0);
|
||||
}
|
||||
debugger->printf("GND resistor: %i\r\n", gpio.vccResistorGnd);
|
||||
debugger->printf("Vcc resistor: %i\r\n", gpio.vccResistorVcc);
|
||||
debugger->println("");
|
||||
debugger->printf_P(PSTR("GND resistor: %i\r\n"), gpio.vccResistorGnd);
|
||||
debugger->printf_P(PSTR("Vcc resistor: %i\r\n"), gpio.vccResistorVcc);
|
||||
debugger->println(F(""));
|
||||
delay(10);
|
||||
Serial.flush();
|
||||
debugger->flush();
|
||||
}
|
||||
|
||||
DomoticzConfig domo;
|
||||
if(getDomoticzConfig(domo)) {
|
||||
debugger->println("--Domoticz configuration--");
|
||||
debugger->println(F("--Domoticz configuration--"));
|
||||
if(mqtt.payloadFormat == 3 && domo.elidx > 0) {
|
||||
debugger->printf("Enabled: Yes\r\n");
|
||||
debugger->printf("Domoticz ELIDX: %i\r\n", domo.elidx);
|
||||
debugger->printf("Domoticz VL1IDX: %i\r\n", domo.vl1idx);
|
||||
debugger->printf("Domoticz VL2IDX: %i\r\n", domo.vl2idx);
|
||||
debugger->printf("Domoticz VL3IDX: %i\r\n", domo.vl3idx);
|
||||
debugger->printf("Domoticz CL1IDX: %i\r\n", domo.cl1idx);
|
||||
debugger->printf_P(PSTR("Enabled: Yes\r\n"));
|
||||
debugger->printf_P(PSTR("Domoticz ELIDX: %i\r\n"), domo.elidx);
|
||||
debugger->printf_P(PSTR("Domoticz VL1IDX: %i\r\n"), domo.vl1idx);
|
||||
debugger->printf_P(PSTR("Domoticz VL2IDX: %i\r\n"), domo.vl2idx);
|
||||
debugger->printf_P(PSTR("Domoticz VL3IDX: %i\r\n"), domo.vl3idx);
|
||||
debugger->printf_P(PSTR("Domoticz CL1IDX: %i\r\n"), domo.cl1idx);
|
||||
} else {
|
||||
debugger->printf("Enabled: No\r\n");
|
||||
debugger->printf_P(PSTR("Enabled: No\r\n"));
|
||||
}
|
||||
debugger->println("");
|
||||
debugger->println(F(""));
|
||||
delay(10);
|
||||
Serial.flush();
|
||||
debugger->flush();
|
||||
}
|
||||
|
||||
NtpConfig ntp;
|
||||
if(getNtpConfig(ntp)) {
|
||||
debugger->println("--NTP configuration--");
|
||||
debugger->printf("Enabled: %s\r\n", ntp.enable ? "Yes" : "No");
|
||||
debugger->println(F("--NTP configuration--"));
|
||||
debugger->printf_P(PSTR("Enabled: %s\r\n"), ntp.enable ? "Yes" : "No");
|
||||
if(ntp.enable) {
|
||||
debugger->printf("Timezone: %s\r\n", ntp.timezone);
|
||||
debugger->printf("Server: %s\r\n", ntp.server);
|
||||
debugger->printf("DHCP: %s\r\n", ntp.dhcp ? "Yes" : "No");
|
||||
debugger->printf_P(PSTR("Timezone: %s\r\n"), ntp.timezone);
|
||||
debugger->printf_P(PSTR("Server: %s\r\n"), ntp.server);
|
||||
debugger->printf_P(PSTR("DHCP: %s\r\n"), ntp.dhcp ? "Yes" : "No");
|
||||
}
|
||||
debugger->println("");
|
||||
debugger->println(F(""));
|
||||
delay(10);
|
||||
Serial.flush();
|
||||
debugger->flush();
|
||||
}
|
||||
|
||||
EntsoeConfig entsoe;
|
||||
if(getEntsoeConfig(entsoe)) {
|
||||
if(strlen(entsoe.area) > 0) {
|
||||
debugger->println("--ENTSO-E configuration--");
|
||||
debugger->printf("Area: %s\r\n", entsoe.area);
|
||||
debugger->printf("Currency: %s\r\n", entsoe.currency);
|
||||
debugger->printf("Multiplier: %f\r\n", entsoe.multiplier / 1000.0);
|
||||
debugger->printf("Token: %s\r\n", entsoe.token);
|
||||
debugger->println(F("--ENTSO-E configuration--"));
|
||||
debugger->printf_P(PSTR("Area: %s\r\n"), entsoe.area);
|
||||
debugger->printf_P(PSTR("Currency: %s\r\n"), entsoe.currency);
|
||||
debugger->printf_P(PSTR("Multiplier: %f\r\n"), entsoe.multiplier / 1000.0);
|
||||
debugger->printf_P(PSTR("Token: %s\r\n"), entsoe.token);
|
||||
}
|
||||
debugger->println("");
|
||||
debugger->println(F(""));
|
||||
delay(10);
|
||||
Serial.flush();
|
||||
debugger->flush();
|
||||
}
|
||||
|
||||
debugger->printf("Temp sensor count: %i\r\n", this->getTempSensorCount());
|
||||
debugger->printf_P(PSTR("Temp sensor count: %i\r\n"), this->getTempSensorCount());
|
||||
|
||||
debugger->println("-----------------------------------------------");
|
||||
debugger->println(F("-----------------------------------------------"));
|
||||
}
|
||||
|
||||
@@ -22,7 +22,8 @@ void fromHex(uint8_t *out, String in, uint16_t size) {
|
||||
}
|
||||
}
|
||||
|
||||
void stripNonAscii(uint8_t* in, uint16_t size, bool extended) {
|
||||
bool stripNonAscii(uint8_t* in, uint16_t size, bool extended) {
|
||||
bool ret = false;
|
||||
for(uint16_t i = 0; i < size; i++) {
|
||||
if(in[i] == 0) { // Clear the rest with null-terminator
|
||||
memset(in+i, 0, size-i);
|
||||
@@ -30,9 +31,12 @@ void stripNonAscii(uint8_t* in, uint16_t size, bool extended) {
|
||||
}
|
||||
if(extended && (in[i] < 32 || in[i] == 127 || in[i] == 129 || in[i] == 141 || in[i] == 143 || in[i] == 144 || in[i] == 157)) {
|
||||
memset(in+i, ' ', 1);
|
||||
} else if(in[i] < 32 || in[i] > 126) {
|
||||
ret = true;
|
||||
} else if(!extended && (in[i] < 32 || in[i] > 126)) {
|
||||
memset(in+i, ' ', 1);
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
memset(in+size-1, 0, 1); // Make sure the last character is null-terminator
|
||||
return ret;
|
||||
}
|
||||
@@ -9,6 +9,10 @@
|
||||
#include "HwTools.h"
|
||||
#include "EntsoeApi.h"
|
||||
|
||||
#if defined(ESP32)
|
||||
#include <esp_task_wdt.h>
|
||||
#endif
|
||||
|
||||
class AmsMqttHandler {
|
||||
public:
|
||||
AmsMqttHandler(MQTTClient* mqtt, char* buf) {
|
||||
@@ -25,7 +29,9 @@ public:
|
||||
protected:
|
||||
MQTTClient* mqtt;
|
||||
char* json;
|
||||
uint16_t BufferSize = 1024;
|
||||
uint16_t BufferSize = 2048;
|
||||
|
||||
bool loop();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -219,7 +219,7 @@ bool AmsData::isTwoPhase() {
|
||||
}
|
||||
|
||||
int8_t AmsData::getLastError() {
|
||||
return lastErrorCount > 3 ? lastError : 0;
|
||||
return lastErrorCount > 2 ? lastError : 0;
|
||||
}
|
||||
|
||||
void AmsData::setLastError(int8_t lastError) {
|
||||
|
||||
@@ -18,32 +18,32 @@ void AmsDataStorage::setTimezone(Timezone* tz) {
|
||||
|
||||
bool AmsDataStorage::update(AmsData* data) {
|
||||
if(isHappy()) {
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf("(AmsDataStorage) Data is up to date\n");
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(AmsDataStorage) Data is up to date\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
time_t now = time(nullptr);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf("(AmsDataStorage) Time is: %lu\n", (int32_t) now);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(AmsDataStorage) Time is: %lu\n"), (int32_t) now);
|
||||
if(tz == NULL) {
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf("(AmsDataStorage) Timezone is missing\n");
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(AmsDataStorage) Timezone is missing\n"));
|
||||
return false;
|
||||
}
|
||||
if(now < BUILD_EPOCH) {
|
||||
if(data->getMeterTimestamp() > BUILD_EPOCH) {
|
||||
now = data->getMeterTimestamp();
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) {
|
||||
debugger->printf("(AmsDataStorage) Using meter timestamp, which is: %lu\n", (int32_t) now);
|
||||
debugger->printf_P(PSTR("(AmsDataStorage) Using meter timestamp, which is: %lu\n"), (int32_t) now);
|
||||
}
|
||||
} else if(data->getPackageTimestamp() > BUILD_EPOCH) {
|
||||
now = data->getPackageTimestamp();
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) {
|
||||
debugger->printf("(AmsDataStorage) Using package timestamp, which is: %lu\n", (int32_t) now);
|
||||
debugger->printf_P(PSTR("(AmsDataStorage) Using package timestamp, which is: %lu\n"), (int32_t) now);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(now < BUILD_EPOCH) {
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) {
|
||||
debugger->printf("(AmsDataStorage) Invalid time: %lu\n", (int32_t) now);
|
||||
debugger->printf_P(PSTR("(AmsDataStorage) Invalid time: %lu\n"), (int32_t) now);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -54,13 +54,13 @@ bool AmsDataStorage::update(AmsData* data) {
|
||||
breakTime(now-3600, utcYesterday);
|
||||
breakTime(tz->toLocal(now-3600), ltzYesterDay);
|
||||
|
||||
uint64_t importCounter = data->getActiveImportCounter() * 1000;
|
||||
uint64_t exportCounter = data->getActiveExportCounter() * 1000;
|
||||
uint32_t importCounter = data->getActiveImportCounter() * 1000;
|
||||
uint32_t exportCounter = data->getActiveExportCounter() * 1000;
|
||||
|
||||
// Clear hours between last update and now
|
||||
if(day.lastMeterReadTime > now) {
|
||||
if(debugger->isActive(RemoteDebug::WARNING)) {
|
||||
debugger->printf("(AmsDataStorage) Invalid future timestamp for day plot, resetting\n");
|
||||
debugger->printf_P(PSTR("(AmsDataStorage) Invalid future timestamp for day plot, resetting\n"));
|
||||
}
|
||||
day.activeImport = importCounter;
|
||||
day.activeExport = exportCounter;
|
||||
@@ -68,13 +68,13 @@ bool AmsDataStorage::update(AmsData* data) {
|
||||
return true;
|
||||
} else {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) {
|
||||
debugger->printf("(AmsDataStorage) Last day update: %lu\n", (int32_t) day.lastMeterReadTime);
|
||||
debugger->printf_P(PSTR("(AmsDataStorage) Last day update: %lu\n"), (int32_t) day.lastMeterReadTime);
|
||||
}
|
||||
tmElements_t last;
|
||||
breakTime(day.lastMeterReadTime, last);
|
||||
for(int i = last.Hour; i < utc.Hour; i++) {
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) {
|
||||
debugger->printf("(AmsDataStorage) Clearing hour: %d\n", i);
|
||||
debugger->printf_P(PSTR("(AmsDataStorage) Clearing hour: %d\n"), i);
|
||||
}
|
||||
setHourImport(i, 0);
|
||||
setHourExport(i, 0);
|
||||
@@ -84,20 +84,20 @@ bool AmsDataStorage::update(AmsData* data) {
|
||||
// Clear days between last update and now
|
||||
if(month.lastMeterReadTime > now) {
|
||||
if(debugger->isActive(RemoteDebug::WARNING)) {
|
||||
debugger->printf("(AmsDataStorage) Invalid future timestamp for month plot, resetting\n");
|
||||
debugger->printf_P(PSTR("(AmsDataStorage) Invalid future timestamp for month plot, resetting\n"));
|
||||
}
|
||||
month.activeImport = importCounter;
|
||||
month.activeExport = exportCounter;
|
||||
month.lastMeterReadTime = now;
|
||||
} else {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) {
|
||||
debugger->printf("(AmsDataStorage) Last month update: %lu\n", (int32_t) month.lastMeterReadTime);
|
||||
debugger->printf_P(PSTR("(AmsDataStorage) Last month update: %lu\n"), (int32_t) month.lastMeterReadTime);
|
||||
}
|
||||
tmElements_t last;
|
||||
breakTime(tz->toLocal(month.lastMeterReadTime), last);
|
||||
for(int i = last.Day; i < ltz.Day; i++) {
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) {
|
||||
debugger->printf("(AmsDataStorage) Clearing day: %d\n", i);
|
||||
debugger->printf_P(PSTR("(AmsDataStorage) Clearing day: %d\n"), i);
|
||||
}
|
||||
setDayImport(i, 0);
|
||||
setDayExport(i, 0);
|
||||
@@ -105,7 +105,7 @@ bool AmsDataStorage::update(AmsData* data) {
|
||||
}
|
||||
|
||||
if(data->getListType() < 3) {
|
||||
debugger->printf("(AmsDataStorage) Not enough data in list type: %d\n", data->getListType());
|
||||
debugger->printf_P(PSTR("(AmsDataStorage) Not enough data in list type: %d\n"), data->getListType());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ bool AmsDataStorage::update(AmsData* data) {
|
||||
day.activeExport = exportCounter;
|
||||
day.lastMeterReadTime = now;
|
||||
if(debugger->isActive(RemoteDebug::WARNING)) {
|
||||
debugger->printf("(AmsDataStorage) Too long since last day update, clearing data\n");
|
||||
debugger->printf_P(PSTR("(AmsDataStorage) Too long since last day update, clearing data\n"));
|
||||
}
|
||||
for(int i = 0; i<24; i++) {
|
||||
setHourImport(i, 0);
|
||||
@@ -136,7 +136,7 @@ bool AmsDataStorage::update(AmsData* data) {
|
||||
setHourImport(utcYesterday.Hour, imp);
|
||||
setHourExport(utcYesterday.Hour, exp);
|
||||
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf("(AmsDataStorage) Usage for hour %d: %d - %d\n", ltzYesterDay.Hour, imp, exp);
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("(AmsDataStorage) Usage for hour %d: %d - %d\n"), ltzYesterDay.Hour, imp, exp);
|
||||
day.activeImport = importCounter;
|
||||
day.activeExport = exportCounter;
|
||||
day.lastMeterReadTime = now;
|
||||
@@ -148,7 +148,7 @@ bool AmsDataStorage::update(AmsData* data) {
|
||||
float epm = ex / mins;
|
||||
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) {
|
||||
debugger->printf("(AmsDataStorage) Since last day update, minutes: %.1f, import: %d (%.2f/min), export: %d (%.2f/min)\n", mins, im, ipm, ex, epm);
|
||||
debugger->printf_P(PSTR("(AmsDataStorage) Since last day update, minutes: %.1f, import: %d (%.2f/min), export: %d (%.2f/min)\n"), mins, im, ipm, ex, epm);
|
||||
}
|
||||
|
||||
tmElements_t last;
|
||||
@@ -167,7 +167,7 @@ bool AmsDataStorage::update(AmsData* data) {
|
||||
setHourExport(last.Hour, exp);
|
||||
|
||||
if(debugger->isActive(RemoteDebug::INFO)) {
|
||||
debugger->printf("(AmsDataStorage) Estimated usage for hour %u: %.1f - %.1f (%lu)\n", last.Hour, imp, exp, (int32_t) cur);
|
||||
debugger->printf_P(PSTR("(AmsDataStorage) Estimated usage for hour %u: %.1f - %.1f (%lu)\n"), last.Hour, imp, exp, (int32_t) cur);
|
||||
}
|
||||
|
||||
day.activeImport += imp;
|
||||
@@ -191,7 +191,7 @@ bool AmsDataStorage::update(AmsData* data) {
|
||||
month.activeExport = exportCounter;
|
||||
month.lastMeterReadTime = now;
|
||||
if(debugger->isActive(RemoteDebug::WARNING)) {
|
||||
debugger->printf("(AmsDataStorage) Too long since last month update, clearing data\n");
|
||||
debugger->printf_P(PSTR("(AmsDataStorage) Too long since last month update, clearing data\n"));
|
||||
}
|
||||
for(int i = 1; i<=31; i++) {
|
||||
setDayImport(i, 0);
|
||||
@@ -202,7 +202,7 @@ bool AmsDataStorage::update(AmsData* data) {
|
||||
int32_t exp = exportCounter - month.activeExport;
|
||||
|
||||
if(debugger->isActive(RemoteDebug::INFO)) {
|
||||
debugger->printf("(AmsDataStorage) Usage for day %d: %d - %d\n", ltzYesterDay.Day, imp, exp);
|
||||
debugger->printf_P(PSTR("(AmsDataStorage) Usage for day %d: %d - %d\n"), ltzYesterDay.Day, imp, exp);
|
||||
}
|
||||
|
||||
setDayImport(ltzYesterDay.Day, imp);
|
||||
@@ -216,7 +216,7 @@ bool AmsDataStorage::update(AmsData* data) {
|
||||
breakTime(tz->toLocal(month.lastMeterReadTime), last);
|
||||
month.lastMeterReadTime = month.lastMeterReadTime - (last.Hour * 3600) - (last.Minute * 60) - last.Second;
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) {
|
||||
debugger->printf("(AmsDataStorage) Last month read after resetting to midnight: %lu\n", (int32_t) month.lastMeterReadTime);
|
||||
debugger->printf_P(PSTR("(AmsDataStorage) Last month read after resetting to midnight: %lu\n"), (int32_t) month.lastMeterReadTime);
|
||||
}
|
||||
|
||||
float hrs = (now - month.lastMeterReadTime) / 3600.0;
|
||||
@@ -226,7 +226,7 @@ bool AmsDataStorage::update(AmsData* data) {
|
||||
float eph = ex / hrs;
|
||||
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) {
|
||||
debugger->printf("(AmsDataStorage) Since last month update, hours: %.1f, import: %d (%.2f/hr), export: %d (%.2f/hr)\n", hrs, im, iph, ex, eph);
|
||||
debugger->printf_P(PSTR("(AmsDataStorage) Since last month update, hours: %.1f, import: %d (%.2f/hr), export: %d (%.2f/hr)\n"), hrs, im, iph, ex, eph);
|
||||
}
|
||||
|
||||
time_t stopAt = now - (ltz.Hour * 3600) - (ltz.Minute * 60) - ltz.Second;
|
||||
@@ -241,7 +241,7 @@ bool AmsDataStorage::update(AmsData* data) {
|
||||
setDayExport(last.Day, exp);
|
||||
|
||||
if(debugger->isActive(RemoteDebug::INFO)) {
|
||||
debugger->printf("(AmsDataStorage) Estimated usage for day %u: %.1f - %.1f (%lu)\n", last.Day, imp, exp, (int32_t) cur);
|
||||
debugger->printf_P(PSTR("(AmsDataStorage) Estimated usage for day %u: %.1f - %.1f (%lu)\n"), last.Day, imp, exp, (int32_t) cur);
|
||||
}
|
||||
|
||||
month.activeImport += imp;
|
||||
@@ -413,7 +413,7 @@ uint32_t AmsDataStorage::getDayExport(uint8_t day) {
|
||||
bool AmsDataStorage::load() {
|
||||
if(!LittleFS.begin()) {
|
||||
if(debugger->isActive(RemoteDebug::ERROR)) {
|
||||
debugger->printf("(AmsDataStorage) Unable to load LittleFS\n");
|
||||
debugger->printf_P(PSTR("(AmsDataStorage) Unable to load LittleFS\n"));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -437,15 +437,13 @@ bool AmsDataStorage::load() {
|
||||
ret = ret && setMonthData(*month);
|
||||
}
|
||||
|
||||
LittleFS.end();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool AmsDataStorage::save() {
|
||||
if(!LittleFS.begin()) {
|
||||
if(debugger->isActive(RemoteDebug::ERROR)) {
|
||||
debugger->printf("(AmsDataStorage) Unable to load LittleFS\n");
|
||||
debugger->printf_P(PSTR("(AmsDataStorage) Unable to load LittleFS\n"));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -467,8 +465,6 @@ bool AmsDataStorage::save() {
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
LittleFS.end();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -559,17 +555,17 @@ bool AmsDataStorage::isDayHappy() {
|
||||
tmElements_t tm, last;
|
||||
|
||||
if(now < day.lastMeterReadTime) {
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf("(AmsDataStorage) Day data timestamp %lu < %lu\n", (int32_t) now, (int32_t) day.lastMeterReadTime);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(AmsDataStorage) Day data timestamp %lu < %lu\n"), (int32_t) now, (int32_t) day.lastMeterReadTime);
|
||||
return false;
|
||||
}
|
||||
breakTime(tz->toLocal(now), tm);
|
||||
breakTime(tz->toLocal(day.lastMeterReadTime), last);
|
||||
if(now-day.lastMeterReadTime > 3600) {
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf("(AmsDataStorage) Day data timestamp age %lu - %lu > 3600\n", (int32_t) now, (int32_t) day.lastMeterReadTime);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(AmsDataStorage) Day data timestamp age %lu - %lu > 3600\n"), (int32_t) now, (int32_t) day.lastMeterReadTime);
|
||||
return false;
|
||||
}
|
||||
if(tm.Hour > last.Hour) {
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf("(AmsDataStorage) Day data hour of last timestamp %d > %d\n", tm.Hour, last.Hour);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(AmsDataStorage) Day data hour of last timestamp %d > %d\n"), tm.Hour, last.Hour);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -578,7 +574,7 @@ bool AmsDataStorage::isDayHappy() {
|
||||
|
||||
bool AmsDataStorage::isMonthHappy() {
|
||||
if(tz == NULL) {
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf("(AmsDataStorage) Timezone is missing\n");
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(AmsDataStorage) Timezone is missing\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -587,14 +583,14 @@ bool AmsDataStorage::isMonthHappy() {
|
||||
tmElements_t tm, last;
|
||||
|
||||
if(now < month.lastMeterReadTime) {
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf("(AmsDataStorage) Month data timestamp %lu < %lu\n", (int32_t) now, (int32_t) month.lastMeterReadTime);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(AmsDataStorage) Month data timestamp %lu < %lu\n"), (int32_t) now, (int32_t) month.lastMeterReadTime);
|
||||
return false;
|
||||
}
|
||||
|
||||
breakTime(tz->toLocal(now), tm);
|
||||
breakTime(tz->toLocal(month.lastMeterReadTime), last);
|
||||
if(tm.Day > last.Day) {
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf("(AmsDataStorage) Month data day of last timestamp %d > %d\n", tm.Day, last.Day);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(AmsDataStorage) Month data day of last timestamp %d > %d\n"), tm.Day, last.Day);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
47
lib/CloudConnector/include/CloudConnector.h
Normal file
47
lib/CloudConnector/include/CloudConnector.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#ifndef _CLOUDCONNECTOR_H
|
||||
#define _CLOUDCONNECTOR_H
|
||||
|
||||
#include "RemoteDebug.h"
|
||||
#include "mbedtls/ssl.h"
|
||||
#include "mbedtls/platform.h"
|
||||
#include "mbedtls/net.h"
|
||||
#include "mbedtls/esp_debug.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
#include "mbedtls/error.h"
|
||||
#include "mbedtls/certs.h"
|
||||
#include "mbedtls/rsa.h"
|
||||
|
||||
|
||||
const unsigned char PUBLIC_KEY[] = \
|
||||
"-----BEGIN PUBLIC KEY-----\n"\
|
||||
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDoIo0CSuuX3tAdF7KPssdlzJNX\n"\
|
||||
"QryhgVV1rQIFPhHv3SxzyKtRrRM9s0CVfymcibhnEBXxxg3pxlGmwI/R6k7HHXJN\n"\
|
||||
"lBsXzzDtZ/GHDVnw+xRakTfRT0Zt+xdJSH5xJNWq4EwpvJfjA22L1Nz4dKSpgWMx\n"\
|
||||
"VRndAaXf0s7Q1XBz2wIDAQAB\n"\
|
||||
"-----END PUBLIC KEY-----\0";
|
||||
|
||||
|
||||
//const unsigned char PUBLIC_KEY[] = { 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xe8, 0x22, 0x8d, 0x02, 0x4a, 0xeb, 0x97, 0xde, 0xd0, 0x1d, 0x17, 0xb2, 0x8f, 0xb2, 0xc7, 0x65, 0xcc, 0x93, 0x57, 0x42, 0xbc, 0xa1, 0x81, 0x55, 0x75, 0xad, 0x02, 0x05, 0x3e, 0x11, 0xef, 0xdd, 0x2c, 0x73, 0xc8, 0xab, 0x51, 0xad, 0x13, 0x3d, 0xb3, 0x40, 0x95, 0x7f, 0x29, 0x9c, 0x89, 0xb8, 0x67, 0x10, 0x15, 0xf1, 0xc6, 0x0d, 0xe9, 0xc6, 0x51, 0xa6, 0xc0, 0x8f, 0xd1, 0xea, 0x4e, 0xc7, 0x1d, 0x72, 0x4d, 0x94, 0x1b, 0x17, 0xcf, 0x30, 0xed, 0x67, 0xf1, 0x87, 0x0d, 0x59, 0xf0, 0xfb, 0x14, 0x5a, 0x91, 0x37, 0xd1, 0x4f, 0x46, 0x6d, 0xfb, 0x17, 0x49, 0x48, 0x7e, 0x71, 0x24, 0xd5, 0xaa, 0xe0, 0x4c, 0x29, 0xbc, 0x97, 0xe3, 0x03, 0x6d, 0x8b, 0xd4, 0xdc, 0xf8, 0x74, 0xa4, 0xa9, 0x81, 0x63, 0x31, 0x55, 0x19, 0xdd, 0x01, 0xa5, 0xdf, 0xd2, 0xce, 0xd0, 0xd5, 0x70, 0x73, 0xdb, 0x02, 0x03, 0x01, 0x00, 0x01};
|
||||
|
||||
struct CloudData {
|
||||
uint8_t type;
|
||||
int16_t data;
|
||||
} __attribute__((packed));
|
||||
|
||||
class CloudConnector {
|
||||
public:
|
||||
CloudConnector(RemoteDebug*);
|
||||
void setup(const unsigned char * key);
|
||||
void send();
|
||||
|
||||
private:
|
||||
RemoteDebug* debugger;
|
||||
|
||||
unsigned char buf[4096];
|
||||
mbedtls_rsa_context* rsa = nullptr;
|
||||
|
||||
void debugPrint(byte *buffer, int start, int length);
|
||||
|
||||
};
|
||||
#endif
|
||||
56
lib/CloudConnector/src/CloudConnector.cpp
Normal file
56
lib/CloudConnector/src/CloudConnector.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#include "CloudConnector.h"
|
||||
|
||||
CloudConnector::CloudConnector(RemoteDebug* debugger) {
|
||||
this->debugger = debugger;
|
||||
mbedtls_pk_context pk;
|
||||
mbedtls_pk_init(&pk);
|
||||
|
||||
int error_code = 0;
|
||||
if((error_code = mbedtls_pk_parse_public_key(&pk, PUBLIC_KEY, sizeof(PUBLIC_KEY))) == 0){
|
||||
debugger->printf("RSA public key OK\n");
|
||||
rsa = mbedtls_pk_rsa(pk);
|
||||
} else {
|
||||
debugger->printf("RSA public key read error: ");
|
||||
mbedtls_strerror(error_code, (char*) buf, 4096);
|
||||
debugger->printf("%s\n", buf);
|
||||
}
|
||||
debugger->flush();
|
||||
//send();
|
||||
}
|
||||
|
||||
void CloudConnector::send() {
|
||||
if(rsa != nullptr && mbedtls_rsa_check_pubkey(rsa) == 0) {
|
||||
memset(buf, 0, 4096);
|
||||
|
||||
CloudData data = {65, 127};
|
||||
unsigned char toEncrypt[4096] = {0};
|
||||
|
||||
debugger->println("RSA clear data: ");
|
||||
debugPrint(toEncrypt, 0, 256);
|
||||
|
||||
mbedtls_rsa_rsaes_pkcs1_v15_encrypt(rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, 256, toEncrypt, buf);
|
||||
|
||||
//byte hashResult[32];
|
||||
//mbedtls_sha256(toEncrypt, strlen((char*) toEncrypt), hashResult, 0);
|
||||
//int success = mbedtls_rsa_rsassa_pkcs1_v15_sign(rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256, strlen((char*) hashResult), hashResult, buf);
|
||||
debugger->println("RSA encrypted data: ");
|
||||
debugPrint(buf, 0, 256);
|
||||
} else {
|
||||
debugger->println("RSA key is invalid");
|
||||
}
|
||||
}
|
||||
void CloudConnector::debugPrint(byte *buffer, int start, int length) {
|
||||
for (int i = start; i < start + length; i++) {
|
||||
if (buffer[i] < 0x10)
|
||||
debugger->print(F("0"));
|
||||
debugger->print(buffer[i], HEX);
|
||||
debugger->print(F(" "));
|
||||
if ((i - start + 1) % 16 == 0)
|
||||
debugger->println(F(""));
|
||||
else if ((i - start + 1) % 4 == 0)
|
||||
debugger->print(F(" "));
|
||||
|
||||
yield(); // Let other get some resources too
|
||||
}
|
||||
debugger->println(F(""));
|
||||
}
|
||||
@@ -9,12 +9,12 @@ bool DomoticzMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyA
|
||||
}
|
||||
if(energy > 0.0) {
|
||||
char val[16];
|
||||
snprintf(val, 16, "%.1f;%.1f", (data->getActiveImportPower()/1.0), energy*1000.0);
|
||||
snprintf_P(val, 16, PSTR("%.1f;%.1f"), (data->getActiveImportPower()/1.0), energy*1000.0);
|
||||
snprintf_P(json, BufferSize, DOMOTICZ_JSON,
|
||||
config.elidx,
|
||||
val
|
||||
);
|
||||
ret = mqtt->publish("domoticz/in", json);
|
||||
ret = mqtt->publish(F("domoticz/in"), json);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,22 +23,22 @@ bool DomoticzMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyA
|
||||
|
||||
if (config.vl1idx > 0){
|
||||
char val[16];
|
||||
snprintf(val, 16, "%.2f", data->getL1Voltage());
|
||||
snprintf_P(val, 16, PSTR("%.2f"), data->getL1Voltage());
|
||||
snprintf_P(json, BufferSize, DOMOTICZ_JSON,
|
||||
config.vl1idx,
|
||||
val
|
||||
);
|
||||
ret |= mqtt->publish("domoticz/in", json);
|
||||
ret |= mqtt->publish(F("domoticz/in"), json);
|
||||
}
|
||||
|
||||
if (config.vl2idx > 0){
|
||||
char val[16];
|
||||
snprintf(val, 16, "%.2f", data->getL2Voltage());
|
||||
snprintf_P(val, 16, PSTR("%.2f"), data->getL2Voltage());
|
||||
snprintf_P(json, BufferSize, DOMOTICZ_JSON,
|
||||
config.vl2idx,
|
||||
val
|
||||
);
|
||||
ret |= mqtt->publish("domoticz/in", json);
|
||||
ret |= mqtt->publish(F("domoticz/in"), json);
|
||||
}
|
||||
|
||||
if (config.vl3idx > 0){
|
||||
@@ -48,7 +48,7 @@ bool DomoticzMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyA
|
||||
config.vl3idx,
|
||||
val
|
||||
);
|
||||
ret |= mqtt->publish("domoticz/in", json);
|
||||
ret |= mqtt->publish(F("domoticz/in"), json);
|
||||
}
|
||||
|
||||
if (config.cl1idx > 0){
|
||||
@@ -58,7 +58,7 @@ bool DomoticzMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyA
|
||||
config.cl1idx,
|
||||
val
|
||||
);
|
||||
ret |= mqtt->publish("domoticz/in", json);
|
||||
ret |= mqtt->publish(F("domoticz/in"), json);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -54,24 +54,24 @@ public:
|
||||
bool save();
|
||||
bool isInitialized();
|
||||
|
||||
double getUseThisHour();
|
||||
double getUseToday();
|
||||
double getUseThisMonth();
|
||||
float getUseThisHour();
|
||||
float getUseToday();
|
||||
float getUseThisMonth();
|
||||
|
||||
double getProducedThisHour();
|
||||
double getProducedToday();
|
||||
double getProducedThisMonth();
|
||||
float getProducedThisHour();
|
||||
float getProducedToday();
|
||||
float getProducedThisMonth();
|
||||
|
||||
double getCostThisHour();
|
||||
double getCostToday();
|
||||
double getCostYesterday();
|
||||
double getCostThisMonth();
|
||||
float getCostThisHour();
|
||||
float getCostToday();
|
||||
float getCostYesterday();
|
||||
float getCostThisMonth();
|
||||
uint16_t getCostLastMonth();
|
||||
|
||||
double getIncomeThisHour();
|
||||
double getIncomeToday();
|
||||
double getIncomeYesterday();
|
||||
double getIncomeThisMonth();
|
||||
float getIncomeThisHour();
|
||||
float getIncomeToday();
|
||||
float getIncomeYesterday();
|
||||
float getIncomeThisMonth();
|
||||
uint16_t getIncomeLastMonth();
|
||||
|
||||
float getMonthMax();
|
||||
@@ -81,8 +81,8 @@ public:
|
||||
EnergyAccountingData getData();
|
||||
void setData(EnergyAccountingData&);
|
||||
|
||||
void setFixedPrice(double price);
|
||||
double getPriceForHour(uint8_t h);
|
||||
void setFixedPrice(float price);
|
||||
float getPriceForHour(uint8_t h);
|
||||
|
||||
private:
|
||||
RemoteDebug* debugger = NULL;
|
||||
@@ -93,10 +93,10 @@ private:
|
||||
EnergyAccountingConfig *config = NULL;
|
||||
Timezone *tz = NULL;
|
||||
uint8_t currentHour = 0, currentDay = 0, currentThresholdIdx = 0;
|
||||
double use = 0, costHour = 0, costDay = 0;
|
||||
double produce = 0, incomeHour = 0, incomeDay = 0;
|
||||
float use = 0, costHour = 0, costDay = 0;
|
||||
float produce = 0, incomeHour = 0, incomeDay = 0;
|
||||
EnergyAccountingData data = { 0, 0, 0, 0, 0, 0 };
|
||||
double fixedPrice = 0;
|
||||
float fixedPrice = 0;
|
||||
|
||||
void calcDayCost();
|
||||
bool updateMax(uint16_t val, uint8_t day);
|
||||
|
||||
@@ -35,7 +35,7 @@ bool EnergyAccounting::update(AmsData* amsData) {
|
||||
time_t now = time(nullptr);
|
||||
if(now < BUILD_EPOCH) return false;
|
||||
if(tz == NULL) {
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf("(EnergyAccounting) Timezone is missing\n");
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(EnergyAccounting) Timezone is missing\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -46,9 +46,9 @@ bool EnergyAccounting::update(AmsData* amsData) {
|
||||
if(!init) {
|
||||
currentHour = local.Hour;
|
||||
currentDay = local.Day;
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("(EnergyAccounting) Initializing data at %lu\n", (int32_t) now);
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("(EnergyAccounting) Initializing data at %lu\n"), (int32_t) now);
|
||||
if(!load()) {
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf("(EnergyAccounting) Unable to load existing data\n");
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("(EnergyAccounting) Unable to load existing data\n"));
|
||||
data = { 5, local.Month,
|
||||
0, 0, 0, // Cost
|
||||
0, 0, 0, // Income
|
||||
@@ -60,21 +60,22 @@ bool EnergyAccounting::update(AmsData* amsData) {
|
||||
};
|
||||
} else if(debugger->isActive(RemoteDebug::DEBUG)) {
|
||||
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_P(PSTR("(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 income yesterday: %.2f, this month: %d, last month: %d\n", data.incomeYesterday / 10.0, data.incomeThisMonth, data.incomeLastMonth);
|
||||
debugger->printf_P(PSTR("(EnergyAccounting) Loaded cost yesterday: %.2f, this month: %d, last month: %d\n"), data.costYesterday / 10.0, data.costThisMonth, data.costLastMonth);
|
||||
debugger->printf_P(PSTR("(EnergyAccounting) Loaded income yesterday: %.2f, this month: %d, last month: %d\n"), data.incomeYesterday / 10.0, data.incomeThisMonth, data.incomeLastMonth);
|
||||
}
|
||||
init = true;
|
||||
}
|
||||
|
||||
if(!initPrice && eapi != NULL && getPriceForHour(0) != ENTSOE_NO_VALUE) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("(EnergyAccounting) Initializing prices at %lu\n", (int32_t) now);
|
||||
float price = getPriceForHour(0);
|
||||
if(!initPrice && price != ENTSOE_NO_VALUE) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("(EnergyAccounting) Initializing prices at %lu\n"), (int32_t) now);
|
||||
calcDayCost();
|
||||
}
|
||||
|
||||
if(local.Hour != currentHour && (amsData->getListType() >= 3 || local.Minute == 1)) {
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf("(EnergyAccounting) New local hour %d\n", local.Hour);
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("(EnergyAccounting) New local hour %d\n"), local.Hour);
|
||||
|
||||
tmElements_t oneHrAgo, oneHrAgoLocal;
|
||||
breakTime(now-3600, oneHrAgo);
|
||||
@@ -94,7 +95,7 @@ bool EnergyAccounting::update(AmsData* amsData) {
|
||||
incomeHour = 0;
|
||||
|
||||
if(local.Day != currentDay) {
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf("(EnergyAccounting) New day %d\n", local.Day);
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("(EnergyAccounting) New day %d\n"), local.Day);
|
||||
data.costYesterday = costDay * 10;
|
||||
data.costThisMonth += costDay;
|
||||
costDay = 0;
|
||||
@@ -108,7 +109,7 @@ bool EnergyAccounting::update(AmsData* amsData) {
|
||||
}
|
||||
|
||||
if(local.Month != data.month) {
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf("(EnergyAccounting) New month %d\n", local.Month);
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("(EnergyAccounting) New month %d\n"), local.Month);
|
||||
data.costLastMonth = data.costThisMonth;
|
||||
data.costThisMonth = 0;
|
||||
data.incomeLastMonth = data.incomeThisMonth;
|
||||
@@ -127,32 +128,30 @@ bool EnergyAccounting::update(AmsData* amsData) {
|
||||
float kwhe = (amsData->getActiveExportPower() * (((float) ms) / 3600000.0)) / 1000.0;
|
||||
lastUpdateMillis = amsData->getLastUpdateMillis();
|
||||
if(kwhi > 0) {
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf("(EnergyAccounting) Adding %.4f kWh import\n", kwhi);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(EnergyAccounting) Adding %.4f kWh import\n"), kwhi);
|
||||
use += kwhi;
|
||||
if(getPriceForHour(0) != ENTSOE_NO_VALUE) {
|
||||
float price = getPriceForHour(0);
|
||||
if(price != ENTSOE_NO_VALUE) {
|
||||
float cost = price * kwhi;
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf("(EnergyAccounting) and %.4f %s\n", cost / 100.0, eapi->getCurrency());
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(EnergyAccounting) and %.4f %s\n"), cost / 100.0, eapi->getCurrency());
|
||||
costHour += cost;
|
||||
costDay += cost;
|
||||
}
|
||||
}
|
||||
if(kwhe > 0) {
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf("(EnergyAccounting) Adding %.4f kWh export\n", kwhe);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(EnergyAccounting) Adding %.4f kWh export\n"), kwhe);
|
||||
produce += kwhe;
|
||||
if(getPriceForHour(0) != ENTSOE_NO_VALUE) {
|
||||
float price = getPriceForHour(0);
|
||||
if(price != ENTSOE_NO_VALUE) {
|
||||
float income = price * kwhe;
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf("(EnergyAccounting) and %.4f %s\n", income / 100.0, eapi->getCurrency());
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(EnergyAccounting) and %.4f %s\n"), income / 100.0, eapi->getCurrency());
|
||||
incomeHour += income;
|
||||
incomeDay += income;
|
||||
}
|
||||
}
|
||||
|
||||
if(config != NULL) {
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf("(EnergyAccounting) calculating threshold, currently at %d\n", currentThresholdIdx);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(EnergyAccounting) calculating threshold, currently at %d\n"), currentThresholdIdx);
|
||||
while(getMonthMax() > config->thresholds[currentThresholdIdx] && currentThresholdIdx < 10) currentThresholdIdx++;
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf("(EnergyAccounting) new threshold %d\n", currentThresholdIdx);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(EnergyAccounting) new threshold %d\n"), currentThresholdIdx);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -163,12 +162,12 @@ void EnergyAccounting::calcDayCost() {
|
||||
tmElements_t local, utc;
|
||||
breakTime(tz->toLocal(now), local);
|
||||
|
||||
if(eapi != NULL && getPriceForHour(0) != ENTSOE_NO_VALUE) {
|
||||
if(getPriceForHour(0) != ENTSOE_NO_VALUE) {
|
||||
if(initPrice) {
|
||||
costDay = 0;
|
||||
incomeDay = 0;
|
||||
}
|
||||
for(int i = 0; i < currentHour; i++) {
|
||||
for(uint8_t i = 0; i < currentHour; i++) {
|
||||
float price = getPriceForHour(i - local.Hour);
|
||||
if(price == ENTSOE_NO_VALUE) break;
|
||||
breakTime(now - ((local.Hour - i) * 3600), utc);
|
||||
@@ -182,75 +181,75 @@ void EnergyAccounting::calcDayCost() {
|
||||
}
|
||||
}
|
||||
|
||||
double EnergyAccounting::getUseThisHour() {
|
||||
float EnergyAccounting::getUseThisHour() {
|
||||
return use;
|
||||
}
|
||||
|
||||
double EnergyAccounting::getUseToday() {
|
||||
float EnergyAccounting::getUseToday() {
|
||||
float ret = 0.0;
|
||||
time_t now = time(nullptr);
|
||||
if(now < BUILD_EPOCH) return 0.0;
|
||||
if(tz == NULL) return 0.0;
|
||||
tmElements_t utc, local;
|
||||
breakTime(tz->toLocal(now), local);
|
||||
for(int i = 0; i < currentHour; i++) {
|
||||
for(uint8_t i = 0; i < currentHour; i++) {
|
||||
breakTime(now - ((local.Hour - i) * 3600), utc);
|
||||
ret += ds->getHourImport(utc.Hour) / 1000.0;
|
||||
}
|
||||
return ret + getUseThisHour();
|
||||
}
|
||||
|
||||
double EnergyAccounting::getUseThisMonth() {
|
||||
float EnergyAccounting::getUseThisMonth() {
|
||||
time_t now = time(nullptr);
|
||||
if(now < BUILD_EPOCH) return 0.0;
|
||||
float ret = 0;
|
||||
for(int i = 0; i < currentDay; i++) {
|
||||
for(uint8_t i = 0; i < currentDay; i++) {
|
||||
ret += ds->getDayImport(i) / 1000.0;
|
||||
}
|
||||
return ret + getUseToday();
|
||||
}
|
||||
|
||||
double EnergyAccounting::getProducedThisHour() {
|
||||
float EnergyAccounting::getProducedThisHour() {
|
||||
return produce;
|
||||
}
|
||||
|
||||
double EnergyAccounting::getProducedToday() {
|
||||
float EnergyAccounting::getProducedToday() {
|
||||
float ret = 0.0;
|
||||
time_t now = time(nullptr);
|
||||
if(now < BUILD_EPOCH) return 0.0;
|
||||
tmElements_t utc, local;
|
||||
breakTime(tz->toLocal(now), local);
|
||||
for(int i = 0; i < currentHour; i++) {
|
||||
for(uint8_t i = 0; i < currentHour; i++) {
|
||||
breakTime(now - ((local.Hour - i) * 3600), utc);
|
||||
ret += ds->getHourExport(utc.Hour) / 1000.0;
|
||||
}
|
||||
return ret + getProducedThisHour();
|
||||
}
|
||||
|
||||
double EnergyAccounting::getProducedThisMonth() {
|
||||
float EnergyAccounting::getProducedThisMonth() {
|
||||
time_t now = time(nullptr);
|
||||
if(now < BUILD_EPOCH) return 0.0;
|
||||
float ret = 0;
|
||||
for(int i = 0; i < currentDay; i++) {
|
||||
for(uint8_t i = 0; i < currentDay; i++) {
|
||||
ret += ds->getDayExport(i) / 1000.0;
|
||||
}
|
||||
return ret + getProducedToday();
|
||||
}
|
||||
|
||||
|
||||
double EnergyAccounting::getCostThisHour() {
|
||||
float EnergyAccounting::getCostThisHour() {
|
||||
return costHour;
|
||||
}
|
||||
|
||||
double EnergyAccounting::getCostToday() {
|
||||
float EnergyAccounting::getCostToday() {
|
||||
return costDay;
|
||||
}
|
||||
|
||||
double EnergyAccounting::getCostYesterday() {
|
||||
float EnergyAccounting::getCostYesterday() {
|
||||
return data.costYesterday / 10.0;
|
||||
}
|
||||
|
||||
double EnergyAccounting::getCostThisMonth() {
|
||||
float EnergyAccounting::getCostThisMonth() {
|
||||
return data.costThisMonth + getCostToday();
|
||||
}
|
||||
|
||||
@@ -258,19 +257,19 @@ uint16_t EnergyAccounting::getCostLastMonth() {
|
||||
return data.costLastMonth;
|
||||
}
|
||||
|
||||
double EnergyAccounting::getIncomeThisHour() {
|
||||
float EnergyAccounting::getIncomeThisHour() {
|
||||
return incomeHour;
|
||||
}
|
||||
|
||||
double EnergyAccounting::getIncomeToday() {
|
||||
float EnergyAccounting::getIncomeToday() {
|
||||
return incomeDay;
|
||||
}
|
||||
|
||||
double EnergyAccounting::getIncomeYesterday() {
|
||||
float EnergyAccounting::getIncomeYesterday() {
|
||||
return data.incomeYesterday / 10.0;
|
||||
}
|
||||
|
||||
double EnergyAccounting::getIncomeThisMonth() {
|
||||
float EnergyAccounting::getIncomeThisMonth() {
|
||||
return data.incomeThisMonth + getIncomeToday();
|
||||
}
|
||||
|
||||
@@ -353,7 +352,7 @@ EnergyAccountingPeak EnergyAccounting::getPeak(uint8_t num) {
|
||||
bool EnergyAccounting::load() {
|
||||
if(!LittleFS.begin()) {
|
||||
if(debugger->isActive(RemoteDebug::ERROR)) {
|
||||
debugger->printf("(EnergyAccounting) Unable to load LittleFS\n");
|
||||
debugger->printf_P(PSTR("(EnergyAccounting) Unable to load LittleFS\n"));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -364,7 +363,7 @@ bool EnergyAccounting::load() {
|
||||
char buf[file.size()];
|
||||
file.readBytes(buf, file.size());
|
||||
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("(EnergyAccounting) Data version %d\n", buf[0]);
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("(EnergyAccounting) Data version %d\n"), buf[0]);
|
||||
if(buf[0] == 5) {
|
||||
EnergyAccountingData* data = (EnergyAccountingData*) buf;
|
||||
memcpy(&this->data, data, sizeof(this->data));
|
||||
@@ -429,25 +428,23 @@ bool EnergyAccounting::load() {
|
||||
this->data.peaks[0].value = data->maxHour;
|
||||
ret = true;
|
||||
} else {
|
||||
if(debugger->isActive(RemoteDebug::WARNING)) debugger->printf("(EnergyAccounting) Unknown version\n");
|
||||
if(debugger->isActive(RemoteDebug::WARNING)) debugger->printf_P(PSTR("(EnergyAccounting) Unknown version\n"));
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
} else {
|
||||
if(debugger->isActive(RemoteDebug::WARNING)) debugger->printf("(EnergyAccounting) File not found\n");
|
||||
if(debugger->isActive(RemoteDebug::WARNING)) debugger->printf_P(PSTR("(EnergyAccounting) File not found\n"));
|
||||
}
|
||||
|
||||
LittleFS.end();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool EnergyAccounting::save() {
|
||||
if(!LittleFS.begin()) {
|
||||
if(debugger->isActive(RemoteDebug::ERROR)) {
|
||||
debugger->printf("(EnergyAccounting) Unable to load LittleFS\n");
|
||||
debugger->printf_P(PSTR("(EnergyAccounting) Unable to load LittleFS\n"));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -460,8 +457,6 @@ bool EnergyAccounting::save() {
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
LittleFS.end();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -477,7 +472,7 @@ bool EnergyAccounting::updateMax(uint16_t val, uint8_t day) {
|
||||
for(uint8_t i = 0; i < 5; i++) {
|
||||
if(data.peaks[i].day == day || data.peaks[i].day == 0) {
|
||||
if(val > data.peaks[i].value) {
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf("(EnergyAccounting) Adding new max %d for day %d which is larger than %d\n", val*10, day, data.peaks[i].value*10);
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("(EnergyAccounting) Adding new max %d for day %d which is larger than %d\n"), val*10, day, data.peaks[i].value*10);
|
||||
data.peaks[i].day = day;
|
||||
data.peaks[i].value = val;
|
||||
return true;
|
||||
@@ -496,7 +491,7 @@ bool EnergyAccounting::updateMax(uint16_t val, uint8_t day) {
|
||||
}
|
||||
}
|
||||
if(idx < 5) {
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf("(EnergyAccounting) Adding new max %d for day %d\n", val*10, day);
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("(EnergyAccounting) Adding new max %d for day %d\n"), val*10, day);
|
||||
data.peaks[idx].value = val;
|
||||
data.peaks[idx].day = day;
|
||||
return true;
|
||||
@@ -504,11 +499,11 @@ bool EnergyAccounting::updateMax(uint16_t val, uint8_t day) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void EnergyAccounting::setFixedPrice(double price) {
|
||||
void EnergyAccounting::setFixedPrice(float price) {
|
||||
this->fixedPrice = price;
|
||||
}
|
||||
|
||||
double EnergyAccounting::getPriceForHour(uint8_t h) {
|
||||
float EnergyAccounting::getPriceForHour(uint8_t h) {
|
||||
if(fixedPrice > 0.0) return fixedPrice;
|
||||
if(eapi == NULL) return ENTSOE_NO_VALUE;
|
||||
return eapi->getValueForHour(h);
|
||||
|
||||
@@ -38,6 +38,7 @@ private:
|
||||
|
||||
uint8_t currentDay = 0, currentHour = 0;
|
||||
uint8_t tomorrowFetchMinute = 15; // How many minutes over 13:00 should it fetch prices
|
||||
uint8_t nextFetchDelayMinutes = 15;
|
||||
uint64_t lastTodayFetch = 0;
|
||||
uint64_t lastTomorrowFetch = 0;
|
||||
uint64_t lastCurrencyFetch = 0;
|
||||
@@ -61,8 +62,6 @@ private:
|
||||
bool retrieve(const char* url, Stream* doc);
|
||||
float getCurrencyMultiplier(const char* from, const char* to, time_t t);
|
||||
|
||||
void printD(String fmt, ...);
|
||||
void printE(String fmt, ...);
|
||||
void debugPrint(byte *buffer, int start, int length);
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -92,8 +92,8 @@ float EntsoeApi::getValueForHour(time_t ts, int8_t hour) {
|
||||
if(pos >= 48)
|
||||
return ENTSOE_NO_VALUE;
|
||||
|
||||
double value = ENTSOE_NO_VALUE;
|
||||
double multiplier = config->multiplier / 1000.0;
|
||||
float value = ENTSOE_NO_VALUE;
|
||||
float multiplier = config->multiplier / 1000.0;
|
||||
if(pos >= hoursToday) {
|
||||
if(tomorrow == NULL)
|
||||
return ENTSOE_NO_VALUE;
|
||||
@@ -158,7 +158,7 @@ bool EntsoeApi::loop() {
|
||||
}
|
||||
|
||||
if(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_P(PSTR("(EntsoeApi) Rotating price objects at %lu\n"), t);
|
||||
if(today != NULL) delete today;
|
||||
if(tomorrow != NULL) {
|
||||
today = tomorrow;
|
||||
@@ -172,14 +172,17 @@ bool EntsoeApi::loop() {
|
||||
return today != NULL; // Only trigger MQTT publish if we have todays prices.
|
||||
}
|
||||
|
||||
bool readyToFetchForTomorrow = tomorrow == NULL && (tm.Hour > 13 || (tm.Hour == 13 && tm.Minute >= tomorrowFetchMinute)) && (lastTomorrowFetch == 0 || now - lastTomorrowFetch > 900000);
|
||||
bool readyToFetchForTomorrow = tomorrow == NULL && (tm.Hour > 13 || (tm.Hour == 13 && tm.Minute >= tomorrowFetchMinute)) && (lastTomorrowFetch == 0 || now - lastTomorrowFetch > (nextFetchDelayMinutes*60000));
|
||||
|
||||
if(today == NULL && (lastTodayFetch == 0 || now - lastTodayFetch > 60000)) {
|
||||
if(today == NULL && (lastTodayFetch == 0 || now - lastTodayFetch > (nextFetchDelayMinutes*60000))) {
|
||||
try {
|
||||
lastTodayFetch = now;
|
||||
today = fetchPrices(t);
|
||||
} catch(const std::exception& e) {
|
||||
if(lastError == 0) lastError = 900;
|
||||
if(lastError == 0) {
|
||||
lastError = 900;
|
||||
nextFetchDelayMinutes = 60;
|
||||
}
|
||||
today = NULL;
|
||||
}
|
||||
return today != NULL && !readyToFetchForTomorrow; // Only trigger MQTT publish if we have todays prices and we are not immediately ready to fetch price for tomorrow.
|
||||
@@ -192,7 +195,10 @@ bool EntsoeApi::loop() {
|
||||
lastTomorrowFetch = now;
|
||||
tomorrow = fetchPrices(t+SECS_PER_DAY);
|
||||
} catch(const std::exception& e) {
|
||||
if(lastError == 0) lastError = 900;
|
||||
if(lastError == 0) {
|
||||
lastError = 900;
|
||||
nextFetchDelayMinutes = 60;
|
||||
}
|
||||
tomorrow = NULL;
|
||||
}
|
||||
return tomorrow != NULL;
|
||||
@@ -204,7 +210,7 @@ bool EntsoeApi::loop() {
|
||||
bool EntsoeApi::retrieve(const char* url, Stream* doc) {
|
||||
#if defined(ESP32)
|
||||
if(http.begin(url)) {
|
||||
printD("Connection established");
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Connection established\n"));
|
||||
|
||||
#if defined(ESP32)
|
||||
esp_task_wdt_reset();
|
||||
@@ -221,16 +227,24 @@ bool EntsoeApi::retrieve(const char* url, Stream* doc) {
|
||||
#endif
|
||||
|
||||
if(status == HTTP_CODE_OK) {
|
||||
printD("Receiving data");
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Receiving data\n"));
|
||||
http.writeToStream(doc);
|
||||
http.end();
|
||||
lastError = 0;
|
||||
nextFetchDelayMinutes = 1;
|
||||
return true;
|
||||
} else {
|
||||
lastError = status;
|
||||
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf("(EntsoeApi) Communication error, returned status: %d\n", status);
|
||||
printE(http.errorToString(status));
|
||||
printD(http.getString());
|
||||
if(status == 429) {
|
||||
nextFetchDelayMinutes = 60;
|
||||
} else if(status == 404) {
|
||||
nextFetchDelayMinutes = 180;
|
||||
} else {
|
||||
nextFetchDelayMinutes = 30;
|
||||
}
|
||||
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("(EntsoeApi) Communication error, returned status: %d\n"), status);
|
||||
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf(http.errorToString(status).c_str());
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(http.getString().c_str());
|
||||
|
||||
http.end();
|
||||
return false;
|
||||
@@ -258,18 +272,18 @@ float EntsoeApi::getCurrencyMultiplier(const char* from, const char* to, time_t
|
||||
ESP.wdtFeed();
|
||||
#endif
|
||||
|
||||
snprintf(buf, BufferSize, "https://data.norges-bank.no/api/data/EXR/M.%s.NOK.SP?lastNObservations=1", from);
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf("(EntsoeApi) Retrieving %s to NOK conversion\n", from);
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("(EntsoeApi) url: %s\n", buf);
|
||||
snprintf_P(buf, BufferSize, PSTR("https://data.norges-bank.no/api/data/EXR/M.%s.NOK.SP?lastNObservations=1"), from);
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("(EntsoeApi) Retrieving %s to NOK conversion\n"), from);
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("(EntsoeApi) url: %s\n"), buf);
|
||||
if(retrieve(buf, &p)) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("(EntsoeApi) got exchange rate %.4f\n", p.getValue());
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("(EntsoeApi) got exchange rate %.4f\n"), p.getValue());
|
||||
currencyMultiplier = p.getValue();
|
||||
if(strncmp(to, "NOK", 3) != 0) {
|
||||
snprintf(buf, BufferSize, "https://data.norges-bank.no/api/data/EXR/M.%s.NOK.SP?lastNObservations=1", to);
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf("(EntsoeApi) Retrieving %s to NOK conversion\n", to);
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("(EntsoeApi) url: %s\n", buf);
|
||||
snprintf_P(buf, BufferSize, PSTR("https://data.norges-bank.no/api/data/EXR/M.%s.NOK.SP?lastNObservations=1"), to);
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("(EntsoeApi) Retrieving %s to NOK conversion\n"), to);
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("(EntsoeApi) url: %s\n"), buf);
|
||||
if(retrieve(buf, &p)) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("(EntsoeApi) got exchange rate %.4f\n", p.getValue());
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("(EntsoeApi) got exchange rate %.4f\n"), p.getValue());
|
||||
currencyMultiplier /= p.getValue();
|
||||
} else {
|
||||
return 0;
|
||||
@@ -278,7 +292,7 @@ float EntsoeApi::getCurrencyMultiplier(const char* from, const char* to, time_t
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("(EntsoeApi) Resulting currency multiplier: %.4f\n", currencyMultiplier);
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("(EntsoeApi) Resulting currency multiplier: %.4f\n"), currencyMultiplier);
|
||||
tmElements_t tm;
|
||||
breakTime(t, tm);
|
||||
lastCurrencyFetch = now + (SECS_PER_DAY * 1000) - (((((tm.Hour * 60) + tm.Minute) * 60) + tm.Second) * 1000);
|
||||
@@ -296,8 +310,8 @@ PricesContainer* EntsoeApi::fetchPrices(time_t t) {
|
||||
breakTime(tz->toUTC(e1), d1); // To get day and hour for CET/CEST at UTC midnight
|
||||
breakTime(tz->toUTC(e2), d2);
|
||||
|
||||
snprintf(buf, BufferSize, "%s?securityToken=%s&documentType=A44&periodStart=%04d%02d%02d%02d%02d&periodEnd=%04d%02d%02d%02d%02d&in_Domain=%s&out_Domain=%s",
|
||||
"https://web-api.tp.entsoe.eu/api", getToken(),
|
||||
snprintf_P(buf, BufferSize, PSTR("https://web-api.tp.entsoe.eu/api?securityToken=%s&documentType=A44&periodStart=%04d%02d%02d%02d%02d&periodEnd=%04d%02d%02d%02d%02d&in_Domain=%s&out_Domain=%s"),
|
||||
getToken(),
|
||||
d1.Year+1970, d1.Month, d1.Day, d1.Hour, 00,
|
||||
d2.Year+1970, d2.Month, d2.Day, d2.Hour, 00,
|
||||
config->area, config->area);
|
||||
@@ -308,8 +322,8 @@ PricesContainer* EntsoeApi::fetchPrices(time_t t) {
|
||||
ESP.wdtFeed();
|
||||
#endif
|
||||
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf("(EntsoeApi) Fetching prices for %d.%d.%d\n", tm.Day, tm.Month, tm.Year+1970);
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("(EntsoeApi) url: %s\n", buf);
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("(EntsoeApi) Fetching prices for %d.%d.%d\n"), tm.Day, tm.Month, tm.Year+1970);
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("(EntsoeApi) url: %s\n"), buf);
|
||||
EntsoeA44Parser a44;
|
||||
if(retrieve(buf, &a44) && a44.getPoint(0) != ENTSOE_NO_VALUE) {
|
||||
PricesContainer* ret = new PricesContainer();
|
||||
@@ -320,8 +334,7 @@ PricesContainer* EntsoeApi::fetchPrices(time_t t) {
|
||||
}
|
||||
} else if(hub) {
|
||||
String data;
|
||||
snprintf(buf, BufferSize, "%s/%s/%d/%d/%d?currency=%s",
|
||||
"http://hub.amsleser.no/hub/price",
|
||||
snprintf_P(buf, BufferSize, PSTR("http://hub.amsleser.no/hub/price/%s/%d/%d/%d?currency=%s"),
|
||||
config->area,
|
||||
tm.Year+1970,
|
||||
tm.Month,
|
||||
@@ -344,26 +357,26 @@ PricesContainer* EntsoeApi::fetchPrices(time_t t) {
|
||||
#endif
|
||||
|
||||
if(status == HTTP_CODE_OK) {
|
||||
printD("Receiving data");
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Receiving data\n"));
|
||||
data = http.getString();
|
||||
http.end();
|
||||
|
||||
uint8_t* content = (uint8_t*) (data.c_str());
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) {
|
||||
printD("Received content for prices:");
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Received content for prices:\n"));
|
||||
debugPrint(content, 0, data.length());
|
||||
}
|
||||
|
||||
DataParserContext ctx;
|
||||
DataParserContext ctx = {0,0,0,0};
|
||||
ctx.length = data.length();
|
||||
GCMParser gcm(key, auth);
|
||||
int8_t gcmRet = gcm.parse(content, ctx);
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) {
|
||||
printD("Decrypted content for prices:");
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Decrypted content for prices:\n"));
|
||||
debugPrint(content, 0, data.length());
|
||||
}
|
||||
if(gcmRet > 0) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("(EntsoeApi) Price data starting at: %d\n", gcmRet);
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("(EntsoeApi) Price data starting at: %d\n"), gcmRet);
|
||||
PricesContainer* ret = new PricesContainer();
|
||||
for(uint8_t i = 0; i < 25; i++) {
|
||||
ret->points[i] = ENTSOE_NO_VALUE;
|
||||
@@ -373,16 +386,25 @@ PricesContainer* EntsoeApi::fetchPrices(time_t t) {
|
||||
ret->points[i] = ntohl(ret->points[i]);
|
||||
}
|
||||
lastError = 0;
|
||||
nextFetchDelayMinutes = 1;
|
||||
return ret;
|
||||
} else {
|
||||
lastError = gcmRet;
|
||||
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf("(EntsoeApi) Error code while decrypting prices: %d\n", gcmRet);
|
||||
nextFetchDelayMinutes = 60;
|
||||
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("(EntsoeApi) Error code while decrypting prices: %d\n"), gcmRet);
|
||||
}
|
||||
} else {
|
||||
lastError = status;
|
||||
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf("(EntsoeApi) Communication error, returned status: %d\n", status);
|
||||
printE(http.errorToString(status));
|
||||
printD(http.getString());
|
||||
if(status == 429) {
|
||||
nextFetchDelayMinutes = 60;
|
||||
} else if(status == 404) {
|
||||
nextFetchDelayMinutes = 180;
|
||||
} else {
|
||||
nextFetchDelayMinutes = 30;
|
||||
}
|
||||
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("(EntsoeApi) Communication error, returned status: %d\n"), status);
|
||||
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf(http.errorToString(status).c_str());
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(http.getString().c_str());
|
||||
|
||||
http.end();
|
||||
}
|
||||
@@ -391,34 +413,20 @@ PricesContainer* EntsoeApi::fetchPrices(time_t t) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void EntsoeApi::printD(String fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(String("(EntsoeApi)" + fmt + "\n").c_str(), args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void EntsoeApi::printE(String fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf(String("(EntsoeApi)" + fmt + "\n").c_str(), args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void EntsoeApi::debugPrint(byte *buffer, int start, int length) {
|
||||
for (int i = start; i < start + length; i++) {
|
||||
if (buffer[i] < 0x10)
|
||||
debugger->print("0");
|
||||
debugger->print(F("0"));
|
||||
debugger->print(buffer[i], HEX);
|
||||
debugger->print(" ");
|
||||
debugger->print(F(" "));
|
||||
if ((i - start + 1) % 16 == 0)
|
||||
debugger->println("");
|
||||
debugger->println(F(""));
|
||||
else if ((i - start + 1) % 4 == 0)
|
||||
debugger->print(" ");
|
||||
debugger->print(F(" "));
|
||||
|
||||
yield(); // Let other get some resources too
|
||||
}
|
||||
debugger->println("");
|
||||
debugger->println(F(""));
|
||||
}
|
||||
|
||||
int16_t EntsoeApi::getLastError() {
|
||||
|
||||
@@ -57,20 +57,8 @@ public:
|
||||
bool publishPrices(EntsoeApi*);
|
||||
bool publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea);
|
||||
|
||||
void publishSensor(const HomeAssistantSensor& sensor);
|
||||
void publishList1Sensors();
|
||||
void publishList1ExportSensors();
|
||||
void publishList2Sensors();
|
||||
void publishList2ExportSensors();
|
||||
void publishList3Sensors();
|
||||
void publishList3ExportSensors();
|
||||
void publishList4Sensors();
|
||||
void publishList4ExportSensors();
|
||||
void publishRealtimeSensors(EnergyAccounting* ea, EntsoeApi* eapi);
|
||||
void publishRealtimeExportSensors(EnergyAccounting* ea, EntsoeApi* eapi);
|
||||
void publishTemperatureSensor(uint8_t index, String id);
|
||||
void publishPriceSensors(EntsoeApi* eapi);
|
||||
void publishSystemSensors();
|
||||
protected:
|
||||
bool loop();
|
||||
|
||||
private:
|
||||
String deviceName;
|
||||
@@ -90,6 +78,27 @@ private:
|
||||
String topic;
|
||||
HwTools* hw;
|
||||
|
||||
bool publishList1(AmsData* data, EnergyAccounting* ea);
|
||||
bool publishList2(AmsData* data, EnergyAccounting* ea);
|
||||
bool publishList3(AmsData* data, EnergyAccounting* ea);
|
||||
bool publishList4(AmsData* data, EnergyAccounting* ea);
|
||||
String getMeterModel(AmsData* data);
|
||||
bool publishRealtime(AmsData* data, EnergyAccounting* ea, EntsoeApi* eapi);
|
||||
void publishSensor(const HomeAssistantSensor& sensor);
|
||||
void publishList1Sensors();
|
||||
void publishList1ExportSensors();
|
||||
void publishList2Sensors();
|
||||
void publishList2ExportSensors();
|
||||
void publishList3Sensors();
|
||||
void publishList3ExportSensors();
|
||||
void publishList4Sensors();
|
||||
void publishList4ExportSensors();
|
||||
void publishRealtimeSensors(EnergyAccounting* ea, EntsoeApi* eapi);
|
||||
void publishRealtimeExportSensors(EnergyAccounting* ea, EntsoeApi* eapi);
|
||||
void publishTemperatureSensor(uint8_t index, String id);
|
||||
void publishPriceSensors(EntsoeApi* eapi);
|
||||
void publishSystemSensors();
|
||||
|
||||
String boardTypeToString(uint8_t b) {
|
||||
switch(b) {
|
||||
case 5:
|
||||
|
||||
@@ -20,110 +20,136 @@ bool HomeAssistantMqttHandler::publish(AmsData* data, AmsData* previousState, En
|
||||
return false;
|
||||
|
||||
if(data->getListType() >= 3) { // publish energy counts
|
||||
publishList3Sensors();
|
||||
if(data->getActiveExportCounter() > 0.0) publishList3ExportSensors();
|
||||
snprintf_P(json, BufferSize, HA2_JSON,
|
||||
data->getActiveImportCounter(),
|
||||
data->getActiveExportCounter(),
|
||||
data->getReactiveImportCounter(),
|
||||
data->getReactiveExportCounter(),
|
||||
data->getMeterTimestamp()
|
||||
);
|
||||
mqtt->publish(topic + "/energy", json);
|
||||
mqtt->loop();
|
||||
delay(10);
|
||||
publishList3(data, ea);
|
||||
loop();
|
||||
}
|
||||
String meterModel = data->getMeterModel();
|
||||
meterModel.replace("\\", "\\\\");
|
||||
|
||||
if(data->getListType() == 1) { // publish power counts
|
||||
publishList1Sensors();
|
||||
snprintf_P(json, BufferSize, HA1_JSON,
|
||||
data->getActiveImportPower()
|
||||
);
|
||||
mqtt->publish(topic + "/power", json);
|
||||
publishList1(data, ea);
|
||||
} else if(data->getListType() <= 3) { // publish power counts and volts/amps
|
||||
publishList2Sensors();
|
||||
if(data->getActiveExportPower() > 0) publishList2ExportSensors();
|
||||
snprintf_P(json, BufferSize, HA3_JSON,
|
||||
data->getListId().c_str(),
|
||||
data->getMeterId().c_str(),
|
||||
meterModel.c_str(),
|
||||
data->getActiveImportPower(),
|
||||
data->getReactiveImportPower(),
|
||||
data->getActiveExportPower(),
|
||||
data->getReactiveExportPower(),
|
||||
data->getL1Current(),
|
||||
data->getL2Current(),
|
||||
data->getL3Current(),
|
||||
data->getL1Voltage(),
|
||||
data->getL2Voltage(),
|
||||
data->getL3Voltage()
|
||||
);
|
||||
mqtt->publish(topic + "/power", json);
|
||||
publishList2(data, ea);
|
||||
} else if(data->getListType() == 4) { // publish power counts and volts/amps/phase power and PF
|
||||
publishList4Sensors();
|
||||
if(data->getL1ActiveExportPower() > 0 || data->getL2ActiveExportPower() > 0 || data->getL3ActiveExportPower() > 0) publishList4ExportSensors();
|
||||
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);
|
||||
publishList4(data, ea);
|
||||
}
|
||||
loop();
|
||||
|
||||
if(ea->isInitialized()) {
|
||||
publishRealtimeSensors(ea, eapi);
|
||||
if(ea->getProducedThisHour() > 0.0 || ea->getProducedToday() > 0.0 || ea->getProducedThisMonth() > 0.0) publishRealtimeExportSensors(ea, eapi);
|
||||
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).value / 100.0, 2);
|
||||
}
|
||||
snprintf_P(json, BufferSize, REALTIME_JSON,
|
||||
ea->getMonthMax(),
|
||||
peaks.c_str(),
|
||||
ea->getCurrentThreshold(),
|
||||
ea->getUseThisHour(),
|
||||
ea->getCostThisHour(),
|
||||
ea->getProducedThisHour(),
|
||||
ea->getIncomeThisHour(),
|
||||
ea->getUseToday(),
|
||||
ea->getCostToday(),
|
||||
ea->getProducedToday(),
|
||||
ea->getIncomeToday(),
|
||||
ea->getUseThisMonth(),
|
||||
ea->getCostThisMonth(),
|
||||
ea->getProducedThisMonth(),
|
||||
ea->getIncomeThisMonth()
|
||||
);
|
||||
mqtt->publish(topic + "/realtime", json);
|
||||
publishRealtime(data, ea, eapi);
|
||||
loop();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HomeAssistantMqttHandler::publishList1(AmsData* data, EnergyAccounting* ea) {
|
||||
publishList1Sensors();
|
||||
snprintf_P(json, BufferSize, HA1_JSON,
|
||||
data->getActiveImportPower()
|
||||
);
|
||||
return mqtt->publish(topic + "/power", json);
|
||||
}
|
||||
|
||||
bool HomeAssistantMqttHandler::publishList2(AmsData* data, EnergyAccounting* ea) {
|
||||
publishList2Sensors();
|
||||
if(data->getActiveExportPower() > 0) publishList2ExportSensors();
|
||||
snprintf_P(json, BufferSize, HA3_JSON,
|
||||
data->getListId().c_str(),
|
||||
data->getMeterId().c_str(),
|
||||
getMeterModel(data).c_str(),
|
||||
data->getActiveImportPower(),
|
||||
data->getReactiveImportPower(),
|
||||
data->getActiveExportPower(),
|
||||
data->getReactiveExportPower(),
|
||||
data->getL1Current(),
|
||||
data->getL2Current(),
|
||||
data->getL3Current(),
|
||||
data->getL1Voltage(),
|
||||
data->getL2Voltage(),
|
||||
data->getL3Voltage()
|
||||
);
|
||||
return mqtt->publish(topic + "/power", json);
|
||||
}
|
||||
|
||||
bool HomeAssistantMqttHandler::publishList3(AmsData* data, EnergyAccounting* ea) {
|
||||
publishList3Sensors();
|
||||
if(data->getActiveExportCounter() > 0.0) publishList3ExportSensors();
|
||||
snprintf_P(json, BufferSize, HA2_JSON,
|
||||
data->getActiveImportCounter(),
|
||||
data->getActiveExportCounter(),
|
||||
data->getReactiveImportCounter(),
|
||||
data->getReactiveExportCounter(),
|
||||
data->getMeterTimestamp()
|
||||
);
|
||||
return mqtt->publish(topic + "/energy", json);
|
||||
}
|
||||
|
||||
bool HomeAssistantMqttHandler::publishList4(AmsData* data, EnergyAccounting* ea) {
|
||||
publishList4Sensors();
|
||||
if(data->getL1ActiveExportPower() > 0 || data->getL2ActiveExportPower() > 0 || data->getL3ActiveExportPower() > 0) publishList4ExportSensors();
|
||||
snprintf_P(json, BufferSize, HA4_JSON,
|
||||
data->getListId().c_str(),
|
||||
data->getMeterId().c_str(),
|
||||
getMeterModel(data).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()
|
||||
);
|
||||
return mqtt->publish(topic + "/power", json);
|
||||
}
|
||||
|
||||
String HomeAssistantMqttHandler::getMeterModel(AmsData* data) {
|
||||
String meterModel = data->getMeterModel();
|
||||
meterModel.replace("\\", "\\\\");
|
||||
return meterModel;
|
||||
}
|
||||
|
||||
bool HomeAssistantMqttHandler::publishRealtime(AmsData* data, EnergyAccounting* ea, EntsoeApi* eapi) {
|
||||
publishRealtimeSensors(ea, eapi);
|
||||
if(ea->getProducedThisHour() > 0.0 || ea->getProducedToday() > 0.0 || ea->getProducedThisMonth() > 0.0) publishRealtimeExportSensors(ea, eapi);
|
||||
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).value / 100.0, 2);
|
||||
}
|
||||
snprintf_P(json, BufferSize, REALTIME_JSON,
|
||||
ea->getMonthMax(),
|
||||
peaks.c_str(),
|
||||
ea->getCurrentThreshold(),
|
||||
ea->getUseThisHour(),
|
||||
ea->getCostThisHour(),
|
||||
ea->getProducedThisHour(),
|
||||
ea->getIncomeThisHour(),
|
||||
ea->getUseToday(),
|
||||
ea->getCostToday(),
|
||||
ea->getProducedToday(),
|
||||
ea->getIncomeToday(),
|
||||
ea->getUseThisMonth(),
|
||||
ea->getCostThisMonth(),
|
||||
ea->getProducedThisMonth(),
|
||||
ea->getIncomeThisMonth()
|
||||
);
|
||||
return mqtt->publish(topic + "/realtime", json);
|
||||
}
|
||||
|
||||
|
||||
bool HomeAssistantMqttHandler::publishTemperatures(AmsConfiguration* config, HwTools* hw) {
|
||||
int count = hw->getTempSensorCount();
|
||||
if(count < 2) return false;
|
||||
@@ -138,18 +164,19 @@ bool HomeAssistantMqttHandler::publishTemperatures(AmsConfiguration* config, HwT
|
||||
if(data != NULL) {
|
||||
char* pos = buf+strlen(buf);
|
||||
String id = toHex(data->address, 8);
|
||||
snprintf(pos, 26, "\"%s\":%.2f,",
|
||||
snprintf_P(pos, 26, PSTR("\"%s\":%.2f,"),
|
||||
id.c_str(),
|
||||
data->lastRead
|
||||
);
|
||||
data->changed = false;
|
||||
publishTemperatureSensor(i+1, id);
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
char* pos = buf+strlen(buf);
|
||||
snprintf_P(count == 0 ? pos : pos-1, 8, PSTR("}}"));
|
||||
return mqtt->publish(topic + "/temperatures", buf);
|
||||
bool ret = mqtt->publish(topic + "/temperatures", buf);
|
||||
loop();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) {
|
||||
@@ -216,7 +243,6 @@ bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) {
|
||||
memset(ts1hr, 0, 24);
|
||||
if(min1hrIdx > -1) {
|
||||
time_t ts = now + (SECS_PER_HOUR * min1hrIdx);
|
||||
//Serial.printf("1hr: %d %lu\n", min1hrIdx, ts);
|
||||
tmElements_t tm;
|
||||
breakTime(ts, tm);
|
||||
sprintf_P(ts1hr, PSTR("%04d-%02d-%02dT%02d:00:00Z"), tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
@@ -225,7 +251,6 @@ bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) {
|
||||
memset(ts3hr, 0, 24);
|
||||
if(min3hrIdx > -1) {
|
||||
time_t ts = now + (SECS_PER_HOUR * min3hrIdx);
|
||||
//Serial.printf("3hr: %d %lu\n", min3hrIdx, ts);
|
||||
tmElements_t tm;
|
||||
breakTime(ts, tm);
|
||||
sprintf_P(ts3hr, PSTR("%04d-%02d-%02dT%02d:00:00Z"), tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
@@ -234,7 +259,6 @@ bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) {
|
||||
memset(ts6hr, 0, 24);
|
||||
if(min6hrIdx > -1) {
|
||||
time_t ts = now + (SECS_PER_HOUR * min6hrIdx);
|
||||
//Serial.printf("6hr: %d %lu\n", min6hrIdx, ts);
|
||||
tmElements_t tm;
|
||||
breakTime(ts, tm);
|
||||
sprintf_P(ts6hr, PSTR("%04d-%02d-%02dT%02d:00:00Z"), tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
@@ -286,7 +310,9 @@ bool HomeAssistantMqttHandler::publishPrices(EntsoeApi* eapi) {
|
||||
ts3hr,
|
||||
ts6hr
|
||||
);
|
||||
return mqtt->publish(topic + "/prices", json, true, 0);
|
||||
bool ret = mqtt->publish(topic + "/prices", json, true, 0);
|
||||
loop();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool HomeAssistantMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea) {
|
||||
@@ -305,7 +331,9 @@ bool HomeAssistantMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, Energ
|
||||
hw->getTemperature(),
|
||||
VERSION
|
||||
);
|
||||
return mqtt->publish(topic + "/state", json);
|
||||
bool ret = mqtt->publish(topic + "/state", json);
|
||||
loop();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void HomeAssistantMqttHandler::publishSensor(const HomeAssistantSensor& sensor) {
|
||||
@@ -333,14 +361,7 @@ void HomeAssistantMqttHandler::publishSensor(const HomeAssistantSensor& sensor)
|
||||
strlen_P(sensor.stacl) > 0 ? (char *) FPSTR(sensor.stacl) : ""
|
||||
);
|
||||
mqtt->publish(discoveryTopic + deviceUid + "_" + uid.c_str() + "/config", json, true, 0);
|
||||
mqtt->loop();
|
||||
delay(10);
|
||||
|
||||
#if defined(ESP32)
|
||||
esp_task_wdt_reset();
|
||||
#elif defined(ESP8266)
|
||||
ESP.wdtFeed();
|
||||
#endif
|
||||
loop();
|
||||
}
|
||||
|
||||
void HomeAssistantMqttHandler::publishList1Sensors() {
|
||||
@@ -352,6 +373,7 @@ void HomeAssistantMqttHandler::publishList1Sensors() {
|
||||
}
|
||||
|
||||
void HomeAssistantMqttHandler::publishList2Sensors() {
|
||||
publishList1Sensors();
|
||||
if(l2Init) return;
|
||||
for(uint8_t i = 0; i < List2SensorCount; i++) {
|
||||
publishSensor(List2Sensors[i]);
|
||||
@@ -368,6 +390,7 @@ void HomeAssistantMqttHandler::publishList2ExportSensors() {
|
||||
}
|
||||
|
||||
void HomeAssistantMqttHandler::publishList3Sensors() {
|
||||
publishList2Sensors();
|
||||
if(l3Init) return;
|
||||
for(uint8_t i = 0; i < List3SensorCount; i++) {
|
||||
publishSensor(List3Sensors[i]);
|
||||
@@ -376,6 +399,7 @@ void HomeAssistantMqttHandler::publishList3Sensors() {
|
||||
}
|
||||
|
||||
void HomeAssistantMqttHandler::publishList3ExportSensors() {
|
||||
publishList2ExportSensors();
|
||||
if(l3eInit) return;
|
||||
for(uint8_t i = 0; i < List3ExportSensorCount; i++) {
|
||||
publishSensor(List3ExportSensors[i]);
|
||||
@@ -384,6 +408,7 @@ void HomeAssistantMqttHandler::publishList3ExportSensors() {
|
||||
}
|
||||
|
||||
void HomeAssistantMqttHandler::publishList4Sensors() {
|
||||
publishList3Sensors();
|
||||
if(l4Init) return;
|
||||
for(uint8_t i = 0; i < List4SensorCount; i++) {
|
||||
publishSensor(List4Sensors[i]);
|
||||
@@ -392,6 +417,7 @@ void HomeAssistantMqttHandler::publishList4Sensors() {
|
||||
}
|
||||
|
||||
void HomeAssistantMqttHandler::publishList4ExportSensors() {
|
||||
publishList3ExportSensors();
|
||||
if(l4eInit) return;
|
||||
for(uint8_t i = 0; i < List4ExportSensorCount; i++) {
|
||||
publishSensor(List4ExportSensors[i]);
|
||||
@@ -509,4 +535,16 @@ void HomeAssistantMqttHandler::publishSystemSensors() {
|
||||
publishSensor(SystemSensors[i]);
|
||||
}
|
||||
sInit = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool HomeAssistantMqttHandler::loop() {
|
||||
bool ret = mqtt->loop();
|
||||
delay(10);
|
||||
yield();
|
||||
#if defined(ESP32)
|
||||
esp_task_wdt_reset();
|
||||
#elif defined(ESP8266)
|
||||
ESP.wdtFeed();
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -37,13 +37,13 @@ struct AdcConfig {
|
||||
class HwTools {
|
||||
public:
|
||||
void setup(GpioConfig*, AmsConfiguration*);
|
||||
double getVcc();
|
||||
float getVcc();
|
||||
uint8_t getTempSensorCount();
|
||||
TempSensorData* getTempSensorData(uint8_t);
|
||||
bool updateTemperatures();
|
||||
double getTemperature();
|
||||
double getTemperatureAnalog();
|
||||
double getTemperature(uint8_t address[8]);
|
||||
float getTemperature();
|
||||
float getTemperatureAnalog();
|
||||
float getTemperature(uint8_t address[8]);
|
||||
int getWifiRssi();
|
||||
bool ledOn(uint8_t color);
|
||||
bool ledOff(uint8_t color);
|
||||
|
||||
@@ -213,8 +213,8 @@ void HwTools::getAdcChannel(uint8_t pin, AdcConfig& config) {
|
||||
#endif
|
||||
}
|
||||
|
||||
double HwTools::getVcc() {
|
||||
double volts = 0.0;
|
||||
float HwTools::getVcc() {
|
||||
float volts = 0.0;
|
||||
if(config->vccPin != 0xFF) {
|
||||
#if defined(ESP32)
|
||||
if(voltAdc.unit != 0xFF) {
|
||||
@@ -257,7 +257,7 @@ double HwTools::getVcc() {
|
||||
if(volts == 0.0) return 0.0;
|
||||
|
||||
if(config->vccResistorGnd > 0 && config->vccResistorVcc > 0) {
|
||||
volts *= ((double) (config->vccResistorGnd + config->vccResistorVcc) / config->vccResistorGnd);
|
||||
volts *= ((float) (config->vccResistorGnd + config->vccResistorVcc) / config->vccResistorGnd);
|
||||
}
|
||||
|
||||
|
||||
@@ -318,7 +318,7 @@ bool HwTools::updateTemperatures() {
|
||||
}
|
||||
tempSensors[sensorCount++] = data;
|
||||
}
|
||||
delay(10);
|
||||
yield();
|
||||
}
|
||||
} else {
|
||||
if(sensorCount > 0) {
|
||||
@@ -348,10 +348,10 @@ bool HwTools::isSensorAddressEqual(uint8_t a[8], uint8_t b[8]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
double HwTools::getTemperature() {
|
||||
float HwTools::getTemperature() {
|
||||
uint8_t c = 0;
|
||||
double ret = 0;
|
||||
double analogTemp = getTemperatureAnalog();
|
||||
float ret = 0;
|
||||
float analogTemp = getTemperatureAnalog();
|
||||
if(analogTemp != DEVICE_DISCONNECTED_C) {
|
||||
ret += analogTemp;
|
||||
c++;
|
||||
@@ -366,10 +366,10 @@ double HwTools::getTemperature() {
|
||||
}
|
||||
return c == 0 ? DEVICE_DISCONNECTED_C : ret/c;
|
||||
}
|
||||
double HwTools::getTemperatureAnalog() {
|
||||
float HwTools::getTemperatureAnalog() {
|
||||
if(config->tempAnalogSensorPin != 0xFF) {
|
||||
float adcCalibrationFactor = 1.06587;
|
||||
int volts = ((double) analogRead(config->tempAnalogSensorPin) / analogRange) * 3.3;
|
||||
int volts = ((float) analogRead(config->tempAnalogSensorPin) / analogRange) * 3.3;
|
||||
return ((volts * adcCalibrationFactor) - 0.4) / 0.0195;
|
||||
}
|
||||
return DEVICE_DISCONNECTED_C;
|
||||
|
||||
@@ -15,9 +15,18 @@ public:
|
||||
bool publishPrices(EntsoeApi*);
|
||||
bool publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea);
|
||||
|
||||
protected:
|
||||
bool loop();
|
||||
|
||||
private:
|
||||
String clientId;
|
||||
String topic;
|
||||
HwTools* hw;
|
||||
|
||||
bool publishList1(AmsData* data, EnergyAccounting* ea);
|
||||
bool publishList2(AmsData* data, EnergyAccounting* ea);
|
||||
bool publishList3(AmsData* data, EnergyAccounting* ea);
|
||||
bool publishList4(AmsData* data, EnergyAccounting* ea);
|
||||
String getMeterModel(AmsData* data);
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -13,138 +13,161 @@ bool JsonMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyAccou
|
||||
if(topic.isEmpty() || !mqtt->connected())
|
||||
return false;
|
||||
|
||||
bool ret = false;
|
||||
|
||||
if(data->getListType() == 1) {
|
||||
ret = publishList1(data, ea);
|
||||
} else if(data->getListType() == 2) {
|
||||
ret = publishList2(data, ea);
|
||||
} else if(data->getListType() == 3) {
|
||||
ret = publishList3(data, ea);
|
||||
} else if(data->getListType() == 4) {
|
||||
ret = publishList4(data, ea);
|
||||
}
|
||||
loop();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool JsonMqttHandler::publishList1(AmsData* data, EnergyAccounting* ea) {
|
||||
snprintf_P(json, BufferSize, JSON1_JSON,
|
||||
WiFi.macAddress().c_str(),
|
||||
clientId.c_str(),
|
||||
(uint32_t) (millis64()/1000),
|
||||
data->getPackageTimestamp(),
|
||||
hw->getVcc(),
|
||||
hw->getWifiRssi(),
|
||||
hw->getTemperature(),
|
||||
data->getActiveImportPower(),
|
||||
ea->getUseThisHour(),
|
||||
ea->getUseToday(),
|
||||
ea->getCurrentThreshold(),
|
||||
ea->getMonthMax(),
|
||||
ea->getProducedThisHour(),
|
||||
ea->getProducedToday()
|
||||
);
|
||||
return mqtt->publish(topic, json);
|
||||
}
|
||||
|
||||
bool JsonMqttHandler::publishList2(AmsData* data, EnergyAccounting* ea) {
|
||||
snprintf_P(json, BufferSize, JSON2_JSON,
|
||||
WiFi.macAddress().c_str(),
|
||||
clientId.c_str(),
|
||||
(uint32_t) (millis64()/1000),
|
||||
data->getPackageTimestamp(),
|
||||
hw->getVcc(),
|
||||
hw->getWifiRssi(),
|
||||
hw->getTemperature(),
|
||||
data->getListId().c_str(),
|
||||
data->getMeterId().c_str(),
|
||||
getMeterModel(data).c_str(),
|
||||
data->getActiveImportPower(),
|
||||
data->getReactiveImportPower(),
|
||||
data->getActiveExportPower(),
|
||||
data->getReactiveExportPower(),
|
||||
data->getL1Current(),
|
||||
data->getL2Current(),
|
||||
data->getL3Current(),
|
||||
data->getL1Voltage(),
|
||||
data->getL2Voltage(),
|
||||
data->getL3Voltage(),
|
||||
ea->getUseThisHour(),
|
||||
ea->getUseToday(),
|
||||
ea->getCurrentThreshold(),
|
||||
ea->getMonthMax(),
|
||||
ea->getProducedThisHour(),
|
||||
ea->getProducedToday()
|
||||
);
|
||||
return mqtt->publish(topic, json);
|
||||
}
|
||||
|
||||
bool JsonMqttHandler::publishList3(AmsData* data, EnergyAccounting* ea) {
|
||||
snprintf_P(json, BufferSize, JSON3_JSON,
|
||||
WiFi.macAddress().c_str(),
|
||||
clientId.c_str(),
|
||||
(uint32_t) (millis64()/1000),
|
||||
data->getPackageTimestamp(),
|
||||
hw->getVcc(),
|
||||
hw->getWifiRssi(),
|
||||
hw->getTemperature(),
|
||||
data->getListId().c_str(),
|
||||
data->getMeterId().c_str(),
|
||||
getMeterModel(data).c_str(),
|
||||
data->getActiveImportPower(),
|
||||
data->getReactiveImportPower(),
|
||||
data->getActiveExportPower(),
|
||||
data->getReactiveExportPower(),
|
||||
data->getL1Current(),
|
||||
data->getL2Current(),
|
||||
data->getL3Current(),
|
||||
data->getL1Voltage(),
|
||||
data->getL2Voltage(),
|
||||
data->getL3Voltage(),
|
||||
data->getActiveImportCounter(),
|
||||
data->getActiveExportCounter(),
|
||||
data->getReactiveImportCounter(),
|
||||
data->getReactiveExportCounter(),
|
||||
data->getMeterTimestamp(),
|
||||
ea->getUseThisHour(),
|
||||
ea->getUseToday(),
|
||||
ea->getCurrentThreshold(),
|
||||
ea->getMonthMax(),
|
||||
ea->getProducedThisHour(),
|
||||
ea->getProducedToday()
|
||||
);
|
||||
return mqtt->publish(topic, json);
|
||||
}
|
||||
|
||||
bool JsonMqttHandler::publishList4(AmsData* data, EnergyAccounting* ea) {
|
||||
snprintf_P(json, BufferSize, JSON4_JSON,
|
||||
WiFi.macAddress().c_str(),
|
||||
clientId.c_str(),
|
||||
(uint32_t) (millis64()/1000),
|
||||
data->getPackageTimestamp(),
|
||||
hw->getVcc(),
|
||||
hw->getWifiRssi(),
|
||||
hw->getTemperature(),
|
||||
data->getListId().c_str(),
|
||||
data->getMeterId().c_str(),
|
||||
getMeterModel(data).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(),
|
||||
data->getL1PowerFactor(),
|
||||
data->getL2PowerFactor(),
|
||||
data->getL3PowerFactor(),
|
||||
data->getActiveImportCounter(),
|
||||
data->getActiveExportCounter(),
|
||||
data->getReactiveImportCounter(),
|
||||
data->getReactiveExportCounter(),
|
||||
data->getMeterTimestamp(),
|
||||
ea->getUseThisHour(),
|
||||
ea->getUseToday(),
|
||||
ea->getCurrentThreshold(),
|
||||
ea->getMonthMax(),
|
||||
ea->getProducedThisHour(),
|
||||
ea->getProducedToday()
|
||||
);
|
||||
return mqtt->publish(topic, json);
|
||||
}
|
||||
|
||||
String JsonMqttHandler::getMeterModel(AmsData* data) {
|
||||
String meterModel = data->getMeterModel();
|
||||
meterModel.replace("\\", "\\\\");
|
||||
if(data->getListType() == 1) {
|
||||
snprintf_P(json, BufferSize, JSON1_JSON,
|
||||
WiFi.macAddress().c_str(),
|
||||
clientId.c_str(),
|
||||
(uint32_t) (millis64()/1000),
|
||||
data->getPackageTimestamp(),
|
||||
hw->getVcc(),
|
||||
hw->getWifiRssi(),
|
||||
hw->getTemperature(),
|
||||
data->getActiveImportPower(),
|
||||
ea->getUseThisHour(),
|
||||
ea->getUseToday(),
|
||||
ea->getCurrentThreshold(),
|
||||
ea->getMonthMax(),
|
||||
ea->getProducedThisHour(),
|
||||
ea->getProducedToday()
|
||||
);
|
||||
return mqtt->publish(topic, json);
|
||||
} else if(data->getListType() == 2) {
|
||||
snprintf_P(json, BufferSize, JSON2_JSON,
|
||||
WiFi.macAddress().c_str(),
|
||||
clientId.c_str(),
|
||||
(uint32_t) (millis64()/1000),
|
||||
data->getPackageTimestamp(),
|
||||
hw->getVcc(),
|
||||
hw->getWifiRssi(),
|
||||
hw->getTemperature(),
|
||||
data->getListId().c_str(),
|
||||
data->getMeterId().c_str(),
|
||||
meterModel.c_str(),
|
||||
data->getActiveImportPower(),
|
||||
data->getReactiveImportPower(),
|
||||
data->getActiveExportPower(),
|
||||
data->getReactiveExportPower(),
|
||||
data->getL1Current(),
|
||||
data->getL2Current(),
|
||||
data->getL3Current(),
|
||||
data->getL1Voltage(),
|
||||
data->getL2Voltage(),
|
||||
data->getL3Voltage(),
|
||||
ea->getUseThisHour(),
|
||||
ea->getUseToday(),
|
||||
ea->getCurrentThreshold(),
|
||||
ea->getMonthMax(),
|
||||
ea->getProducedThisHour(),
|
||||
ea->getProducedToday()
|
||||
);
|
||||
return mqtt->publish(topic, json);
|
||||
} else if(data->getListType() == 3) {
|
||||
snprintf_P(json, BufferSize, JSON3_JSON,
|
||||
WiFi.macAddress().c_str(),
|
||||
clientId.c_str(),
|
||||
(uint32_t) (millis64()/1000),
|
||||
data->getPackageTimestamp(),
|
||||
hw->getVcc(),
|
||||
hw->getWifiRssi(),
|
||||
hw->getTemperature(),
|
||||
data->getListId().c_str(),
|
||||
data->getMeterId().c_str(),
|
||||
meterModel.c_str(),
|
||||
data->getActiveImportPower(),
|
||||
data->getReactiveImportPower(),
|
||||
data->getActiveExportPower(),
|
||||
data->getReactiveExportPower(),
|
||||
data->getL1Current(),
|
||||
data->getL2Current(),
|
||||
data->getL3Current(),
|
||||
data->getL1Voltage(),
|
||||
data->getL2Voltage(),
|
||||
data->getL3Voltage(),
|
||||
data->getActiveImportCounter(),
|
||||
data->getActiveExportCounter(),
|
||||
data->getReactiveImportCounter(),
|
||||
data->getReactiveExportCounter(),
|
||||
data->getMeterTimestamp(),
|
||||
ea->getUseThisHour(),
|
||||
ea->getUseToday(),
|
||||
ea->getCurrentThreshold(),
|
||||
ea->getMonthMax(),
|
||||
ea->getProducedThisHour(),
|
||||
ea->getProducedToday()
|
||||
);
|
||||
return mqtt->publish(topic, json);
|
||||
} else if(data->getListType() == 4) {
|
||||
snprintf_P(json, BufferSize, JSON4_JSON,
|
||||
WiFi.macAddress().c_str(),
|
||||
clientId.c_str(),
|
||||
(uint32_t) (millis64()/1000),
|
||||
data->getPackageTimestamp(),
|
||||
hw->getVcc(),
|
||||
hw->getWifiRssi(),
|
||||
hw->getTemperature(),
|
||||
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(),
|
||||
data->getL1PowerFactor(),
|
||||
data->getL2PowerFactor(),
|
||||
data->getL3PowerFactor(),
|
||||
data->getActiveImportCounter(),
|
||||
data->getActiveExportCounter(),
|
||||
data->getReactiveImportCounter(),
|
||||
data->getReactiveExportCounter(),
|
||||
data->getMeterTimestamp(),
|
||||
ea->getUseThisHour(),
|
||||
ea->getUseToday(),
|
||||
ea->getCurrentThreshold(),
|
||||
ea->getMonthMax(),
|
||||
ea->getProducedThisHour(),
|
||||
ea->getProducedToday()
|
||||
);
|
||||
return mqtt->publish(topic, json);
|
||||
}
|
||||
return false;
|
||||
return meterModel;
|
||||
}
|
||||
|
||||
bool JsonMqttHandler::publishTemperatures(AmsConfiguration* config, HwTools* hw) {
|
||||
@@ -153,23 +176,24 @@ bool JsonMqttHandler::publishTemperatures(AmsConfiguration* config, HwTools* hw)
|
||||
return false;
|
||||
}
|
||||
|
||||
snprintf(json, 24, "{\"temperatures\":{");
|
||||
snprintf_P(json, 24, PSTR("{\"temperatures\":{"));
|
||||
|
||||
for(int i = 0; i < count; i++) {
|
||||
TempSensorData* data = hw->getTempSensorData(i);
|
||||
if(data != NULL) {
|
||||
char* pos = json+strlen(json);
|
||||
snprintf(pos, 26, "\"%s\":%.2f,",
|
||||
snprintf_P(pos, 26, PSTR("\"%s\":%.2f,"),
|
||||
toHex(data->address, 8).c_str(),
|
||||
data->lastRead
|
||||
);
|
||||
data->changed = false;
|
||||
delay(1);
|
||||
}
|
||||
}
|
||||
char* pos = json+strlen(json);
|
||||
snprintf(count == 0 ? pos : pos-1, 8, "}}");
|
||||
return mqtt->publish(topic, json);
|
||||
snprintf_P(count == 0 ? pos : pos-1, 8, PSTR("}}"));
|
||||
bool ret = mqtt->publish(topic, json);
|
||||
loop();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool JsonMqttHandler::publishPrices(EntsoeApi* eapi) {
|
||||
@@ -234,28 +258,25 @@ bool JsonMqttHandler::publishPrices(EntsoeApi* eapi) {
|
||||
memset(ts1hr, 0, 24);
|
||||
if(min1hrIdx > -1) {
|
||||
time_t ts = now + (SECS_PER_HOUR * min1hrIdx);
|
||||
//Serial.printf("1hr: %d %lu\n", min1hrIdx, ts);
|
||||
tmElements_t tm;
|
||||
breakTime(ts, tm);
|
||||
sprintf(ts1hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
sprintf_P(ts1hr, PSTR("%04d-%02d-%02dT%02d:00:00Z"), tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
}
|
||||
char ts3hr[24];
|
||||
memset(ts3hr, 0, 24);
|
||||
if(min3hrIdx > -1) {
|
||||
time_t ts = now + (SECS_PER_HOUR * min3hrIdx);
|
||||
//Serial.printf("3hr: %d %lu\n", min3hrIdx, ts);
|
||||
tmElements_t tm;
|
||||
breakTime(ts, tm);
|
||||
sprintf(ts3hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
sprintf_P(ts3hr, PSTR("%04d-%02d-%02dT%02d:00:00Z"), tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
}
|
||||
char ts6hr[24];
|
||||
memset(ts6hr, 0, 24);
|
||||
if(min6hrIdx > -1) {
|
||||
time_t ts = now + (SECS_PER_HOUR * min6hrIdx);
|
||||
//Serial.printf("6hr: %d %lu\n", min6hrIdx, ts);
|
||||
tmElements_t tm;
|
||||
breakTime(ts, tm);
|
||||
sprintf(ts6hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
sprintf_P(ts6hr, PSTR("%04d-%02d-%02dT%02d:00:00Z"), tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
}
|
||||
|
||||
snprintf_P(json, BufferSize, JSONPRICES_JSON,
|
||||
@@ -304,7 +325,9 @@ bool JsonMqttHandler::publishPrices(EntsoeApi* eapi) {
|
||||
ts3hr,
|
||||
ts6hr
|
||||
);
|
||||
return mqtt->publish(topic, json);
|
||||
bool ret = mqtt->publish(topic, json);
|
||||
loop();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool JsonMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea) {
|
||||
@@ -320,5 +343,19 @@ bool JsonMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounti
|
||||
hw->getTemperature(),
|
||||
VERSION
|
||||
);
|
||||
return mqtt->publish(topic, json);
|
||||
bool ret = mqtt->publish(topic, json);
|
||||
loop();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool JsonMqttHandler::loop() {
|
||||
bool ret = mqtt->loop();
|
||||
delay(10);
|
||||
yield();
|
||||
#if defined(ESP32)
|
||||
esp_task_wdt_reset();
|
||||
#elif defined(ESP8266)
|
||||
ESP.wdtFeed();
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -14,8 +14,17 @@ public:
|
||||
bool publishPrices(EntsoeApi*);
|
||||
bool publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccounting* ea);
|
||||
|
||||
protected:
|
||||
bool loop();
|
||||
|
||||
private:
|
||||
String topic;
|
||||
bool full;
|
||||
|
||||
bool publishList1(AmsData* data, AmsData* meterState);
|
||||
bool publishList2(AmsData* data, AmsData* meterState);
|
||||
bool publishList3(AmsData* data, AmsData* meterState);
|
||||
bool publishList4(AmsData* data, AmsData* meterState);
|
||||
bool publishRealtime(EnergyAccounting* ea);
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -11,103 +11,133 @@ 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));
|
||||
}
|
||||
if(full || meterState->getL1PowerFactor() != data->getL1PowerFactor()) {
|
||||
mqtt->publish(topic + "/meter/l1/powerfactor", String(data->getL1PowerFactor(), 2));
|
||||
}
|
||||
if(full || meterState->getL2PowerFactor() != data->getL2PowerFactor()) {
|
||||
mqtt->publish(topic + "/meter/l2/powerfactor", String(data->getL2PowerFactor(), 2));
|
||||
}
|
||||
if(full || meterState->getL3PowerFactor() != data->getL3PowerFactor()) {
|
||||
mqtt->publish(topic + "/meter/l3/powerfactor", String(data->getL3PowerFactor(), 2));
|
||||
}
|
||||
publishList4(data, meterState);
|
||||
loop();
|
||||
case 3:
|
||||
// ID and type belongs to List 2, but I see no need to send that every 10s
|
||||
mqtt->publish(topic + "/meter/id", data->getMeterId(), true, 0);
|
||||
mqtt->publish(topic + "/meter/type", data->getMeterModel(), true, 0);
|
||||
mqtt->publish(topic + "/meter/clock", String(data->getMeterTimestamp()));
|
||||
mqtt->publish(topic + "/meter/import/reactive/accumulated", String(data->getReactiveImportCounter(), 3), true, 0);
|
||||
mqtt->publish(topic + "/meter/import/active/accumulated", String(data->getActiveImportCounter(), 3), true, 0);
|
||||
mqtt->publish(topic + "/meter/export/reactive/accumulated", String(data->getReactiveExportCounter(), 3), true, 0);
|
||||
mqtt->publish(topic + "/meter/export/active/accumulated", String(data->getActiveExportCounter(), 3), true, 0);
|
||||
publishList3(data, meterState);
|
||||
loop();
|
||||
case 2:
|
||||
// Only send data if changed. ID and Type is sent on the 10s interval only if changed
|
||||
if(full || meterState->getMeterId() != data->getMeterId()) {
|
||||
mqtt->publish(topic + "/meter/id", data->getMeterId());
|
||||
}
|
||||
if(full || meterState->getMeterModel() != data->getMeterModel()) {
|
||||
mqtt->publish(topic + "/meter/type", data->getMeterModel());
|
||||
}
|
||||
if(full || meterState->getL1Current() != data->getL1Current()) {
|
||||
mqtt->publish(topic + "/meter/l1/current", String(data->getL1Current(), 2));
|
||||
}
|
||||
if(full || meterState->getL1Voltage() != data->getL1Voltage()) {
|
||||
mqtt->publish(topic + "/meter/l1/voltage", String(data->getL1Voltage(), 2));
|
||||
}
|
||||
if(full || meterState->getL2Current() != data->getL2Current()) {
|
||||
mqtt->publish(topic + "/meter/l2/current", String(data->getL2Current(), 2));
|
||||
}
|
||||
if(full || meterState->getL2Voltage() != data->getL2Voltage()) {
|
||||
mqtt->publish(topic + "/meter/l2/voltage", String(data->getL2Voltage(), 2));
|
||||
}
|
||||
if(full || meterState->getL3Current() != data->getL3Current()) {
|
||||
mqtt->publish(topic + "/meter/l3/current", String(data->getL3Current(), 2));
|
||||
}
|
||||
if(full || meterState->getL3Voltage() != data->getL3Voltage()) {
|
||||
mqtt->publish(topic + "/meter/l3/voltage", String(data->getL3Voltage(), 2));
|
||||
}
|
||||
if(full || meterState->getReactiveExportPower() != data->getReactiveExportPower()) {
|
||||
mqtt->publish(topic + "/meter/export/reactive", String(data->getReactiveExportPower()));
|
||||
}
|
||||
if(full || meterState->getActiveExportPower() != data->getActiveExportPower()) {
|
||||
mqtt->publish(topic + "/meter/export/active", String(data->getActiveExportPower()));
|
||||
}
|
||||
if(full || meterState->getReactiveImportPower() != data->getReactiveImportPower()) {
|
||||
mqtt->publish(topic + "/meter/import/reactive", String(data->getReactiveImportPower()));
|
||||
}
|
||||
publishList2(data, meterState);
|
||||
loop();
|
||||
case 1:
|
||||
if(full || meterState->getActiveImportPower() != data->getActiveImportPower()) {
|
||||
mqtt->publish(topic + "/meter/import/active", String(data->getActiveImportPower()));
|
||||
}
|
||||
publishList1(data, meterState);
|
||||
loop();
|
||||
}
|
||||
if(ea->isInitialized()) {
|
||||
mqtt->publish(topic + "/realtime/import/hour", String(ea->getUseThisHour(), 3));
|
||||
mqtt->publish(topic + "/realtime/import/day", String(ea->getUseToday(), 2));
|
||||
mqtt->publish(topic + "/realtime/import/month", String(ea->getUseThisMonth(), 1));
|
||||
uint8_t peakCount = ea->getConfig()->hours;
|
||||
if(peakCount > 5) peakCount = 5;
|
||||
for(uint8_t i = 1; i <= peakCount; i++) {
|
||||
mqtt->publish(topic + "/realtime/import/peak/" + String(i, 10), String(ea->getPeak(i).value / 100.0, 10), true, 0);
|
||||
}
|
||||
mqtt->publish(topic + "/realtime/import/threshold", String(ea->getCurrentThreshold(), 10), true, 0);
|
||||
mqtt->publish(topic + "/realtime/import/monthmax", String(ea->getMonthMax(), 3), true, 0);
|
||||
mqtt->publish(topic + "/realtime/export/hour", String(ea->getProducedThisHour(), 3));
|
||||
mqtt->publish(topic + "/realtime/export/day", String(ea->getProducedToday(), 2));
|
||||
mqtt->publish(topic + "/realtime/export/month", String(ea->getProducedThisMonth(), 1));
|
||||
publishRealtime(ea);
|
||||
loop();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RawMqttHandler::publishList1(AmsData* data, AmsData* meterState) {
|
||||
if(full || meterState->getActiveImportPower() != data->getActiveImportPower()) {
|
||||
mqtt->publish(topic + "/meter/import/active", String(data->getActiveImportPower()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RawMqttHandler::publishList2(AmsData* data, AmsData* meterState) {
|
||||
// Only send data if changed. ID and Type is sent on the 10s interval only if changed
|
||||
if(full || meterState->getMeterId() != data->getMeterId()) {
|
||||
mqtt->publish(topic + "/meter/id", data->getMeterId());
|
||||
}
|
||||
if(full || meterState->getMeterModel() != data->getMeterModel()) {
|
||||
mqtt->publish(topic + "/meter/type", data->getMeterModel());
|
||||
}
|
||||
if(full || meterState->getL1Current() != data->getL1Current()) {
|
||||
mqtt->publish(topic + "/meter/l1/current", String(data->getL1Current(), 2));
|
||||
}
|
||||
if(full || meterState->getL1Voltage() != data->getL1Voltage()) {
|
||||
mqtt->publish(topic + "/meter/l1/voltage", String(data->getL1Voltage(), 2));
|
||||
}
|
||||
if(full || meterState->getL2Current() != data->getL2Current()) {
|
||||
mqtt->publish(topic + "/meter/l2/current", String(data->getL2Current(), 2));
|
||||
}
|
||||
if(full || meterState->getL2Voltage() != data->getL2Voltage()) {
|
||||
mqtt->publish(topic + "/meter/l2/voltage", String(data->getL2Voltage(), 2));
|
||||
}
|
||||
if(full || meterState->getL3Current() != data->getL3Current()) {
|
||||
mqtt->publish(topic + "/meter/l3/current", String(data->getL3Current(), 2));
|
||||
}
|
||||
if(full || meterState->getL3Voltage() != data->getL3Voltage()) {
|
||||
mqtt->publish(topic + "/meter/l3/voltage", String(data->getL3Voltage(), 2));
|
||||
}
|
||||
if(full || meterState->getReactiveExportPower() != data->getReactiveExportPower()) {
|
||||
mqtt->publish(topic + "/meter/export/reactive", String(data->getReactiveExportPower()));
|
||||
}
|
||||
if(full || meterState->getActiveExportPower() != data->getActiveExportPower()) {
|
||||
mqtt->publish(topic + "/meter/export/active", String(data->getActiveExportPower()));
|
||||
}
|
||||
if(full || meterState->getReactiveImportPower() != data->getReactiveImportPower()) {
|
||||
mqtt->publish(topic + "/meter/import/reactive", String(data->getReactiveImportPower()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RawMqttHandler::publishList3(AmsData* data, AmsData* meterState) {
|
||||
// ID and type belongs to List 2, but I see no need to send that every 10s
|
||||
mqtt->publish(topic + "/meter/id", data->getMeterId(), true, 0);
|
||||
mqtt->publish(topic + "/meter/type", data->getMeterModel(), true, 0);
|
||||
mqtt->publish(topic + "/meter/clock", String(data->getMeterTimestamp()));
|
||||
mqtt->publish(topic + "/meter/import/reactive/accumulated", String(data->getReactiveImportCounter(), 3), true, 0);
|
||||
mqtt->publish(topic + "/meter/import/active/accumulated", String(data->getActiveImportCounter(), 3), true, 0);
|
||||
mqtt->publish(topic + "/meter/export/reactive/accumulated", String(data->getReactiveExportCounter(), 3), true, 0);
|
||||
mqtt->publish(topic + "/meter/export/active/accumulated", String(data->getActiveExportCounter(), 3), true, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RawMqttHandler::publishList4(AmsData* data, AmsData* meterState) {
|
||||
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));
|
||||
}
|
||||
if(full || meterState->getL1PowerFactor() != data->getL1PowerFactor()) {
|
||||
mqtt->publish(topic + "/meter/l1/powerfactor", String(data->getL1PowerFactor(), 2));
|
||||
}
|
||||
if(full || meterState->getL2PowerFactor() != data->getL2PowerFactor()) {
|
||||
mqtt->publish(topic + "/meter/l2/powerfactor", String(data->getL2PowerFactor(), 2));
|
||||
}
|
||||
if(full || meterState->getL3PowerFactor() != data->getL3PowerFactor()) {
|
||||
mqtt->publish(topic + "/meter/l3/powerfactor", String(data->getL3PowerFactor(), 2));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RawMqttHandler::publishRealtime(EnergyAccounting* ea) {
|
||||
mqtt->publish(topic + "/realtime/import/hour", String(ea->getUseThisHour(), 3));
|
||||
mqtt->publish(topic + "/realtime/import/day", String(ea->getUseToday(), 2));
|
||||
mqtt->publish(topic + "/realtime/import/month", String(ea->getUseThisMonth(), 1));
|
||||
uint8_t peakCount = ea->getConfig()->hours;
|
||||
if(peakCount > 5) peakCount = 5;
|
||||
for(uint8_t i = 1; i <= peakCount; i++) {
|
||||
mqtt->publish(topic + "/realtime/import/peak/" + String(i, 10), String(ea->getPeak(i).value / 100.0, 10), true, 0);
|
||||
}
|
||||
mqtt->publish(topic + "/realtime/import/threshold", String(ea->getCurrentThreshold(), 10), true, 0);
|
||||
mqtt->publish(topic + "/realtime/import/monthmax", String(ea->getMonthMax(), 3), true, 0);
|
||||
mqtt->publish(topic + "/realtime/export/hour", String(ea->getProducedThisHour(), 3));
|
||||
mqtt->publish(topic + "/realtime/export/day", String(ea->getProducedToday(), 2));
|
||||
mqtt->publish(topic + "/realtime/export/month", String(ea->getProducedThisMonth(), 1));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RawMqttHandler::publishTemperatures(AmsConfiguration* config, HwTools* hw) {
|
||||
uint8_t c = hw->getTempSensorCount();
|
||||
for(int i = 0; i < c; i++) {
|
||||
@@ -184,7 +214,6 @@ bool RawMqttHandler::publishPrices(EntsoeApi* eapi) {
|
||||
char ts1hr[24];
|
||||
if(min1hrIdx > -1) {
|
||||
time_t ts = now + (SECS_PER_HOUR * min1hrIdx);
|
||||
//Serial.printf("1hr: %d %lu\n", min1hrIdx, ts);
|
||||
tmElements_t tm;
|
||||
breakTime(ts, tm);
|
||||
sprintf(ts1hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
@@ -192,7 +221,6 @@ bool RawMqttHandler::publishPrices(EntsoeApi* eapi) {
|
||||
char ts3hr[24];
|
||||
if(min3hrIdx > -1) {
|
||||
time_t ts = now + (SECS_PER_HOUR * min3hrIdx);
|
||||
//Serial.printf("3hr: %d %lu\n", min3hrIdx, ts);
|
||||
tmElements_t tm;
|
||||
breakTime(ts, tm);
|
||||
sprintf(ts3hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
@@ -200,7 +228,6 @@ bool RawMqttHandler::publishPrices(EntsoeApi* eapi) {
|
||||
char ts6hr[24];
|
||||
if(min6hrIdx > -1) {
|
||||
time_t ts = now + (SECS_PER_HOUR * min6hrIdx);
|
||||
//Serial.printf("6hr: %d %lu\n", min6hrIdx, ts);
|
||||
tmElements_t tm;
|
||||
breakTime(ts, tm);
|
||||
sprintf(ts6hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
@@ -251,4 +278,16 @@ bool RawMqttHandler::publishSystem(HwTools* hw, EntsoeApi* eapi, EnergyAccountin
|
||||
mqtt->publish(topic + "/temperature", String(hw->getTemperature(), 2));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool RawMqttHandler::loop() {
|
||||
bool ret = mqtt->loop();
|
||||
delay(10);
|
||||
yield();
|
||||
#if defined(ESP32)
|
||||
esp_task_wdt_reset();
|
||||
#elif defined(ESP8266)
|
||||
ESP.wdtFeed();
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
18
lib/SvelteUi/app/dist/index.js
vendored
18
lib/SvelteUi/app/dist/index.js
vendored
File diff suppressed because one or more lines are too long
@@ -9,8 +9,8 @@
|
||||
let hasCost = false;
|
||||
let cols = 3
|
||||
$: {
|
||||
cols = currency ? 3 : 2;
|
||||
hasCost = data && data.h && (data.h.c || data.d.c || data.m.c || data.h.i || data.d.i || data.m.i);
|
||||
cols = hasCost ? 3 : 2;
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -52,7 +52,9 @@
|
||||
<g class="axis x-axis">
|
||||
{#each config.x.ticks as point, i}
|
||||
<g class="tick" transform="translate({xScale(i)},{heightAvailable})">
|
||||
{#if barWidth > 20 || i%2 == 0}
|
||||
<text x="{barWidth/2}" y="-4">{point.label}</text>
|
||||
{/if}
|
||||
</g>
|
||||
{/each}
|
||||
</g>
|
||||
|
||||
@@ -8,5 +8,5 @@
|
||||
{#if Math.abs(new Date().getTime()-timestamp.getTime()) < 300000 }
|
||||
{`${zeropad(timestamp.getDate())}. ${monthnames[timestamp.getMonth()]} ${zeropad(timestamp.getHours())}:${zeropad(timestamp.getMinutes())}`}
|
||||
{:else}
|
||||
<span class="{fullTimeColor}">{`${zeropad(timestamp.getDate())}.${zeropad(timestamp.getMonth())}.${timestamp.getFullYear()} ${zeropad(timestamp.getHours())}:${zeropad(timestamp.getMinutes())}`}</span>
|
||||
<span class="{fullTimeColor}">{`${zeropad(timestamp.getDate())}.${zeropad(timestamp.getMonth()+1)}.${timestamp.getFullYear()} ${zeropad(timestamp.getHours())}:${zeropad(timestamp.getMinutes())}`}</span>
|
||||
{/if}
|
||||
|
||||
@@ -26,6 +26,13 @@ let sysinfo = {
|
||||
upgrading: false,
|
||||
ui: {},
|
||||
security: 0,
|
||||
boot_reason: 0,
|
||||
upgrade: {
|
||||
x: -1,
|
||||
e: 0,
|
||||
f: null,
|
||||
t: null
|
||||
},
|
||||
trying: null
|
||||
};
|
||||
export const sysinfoStore = writable(sysinfo);
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
s.upgrading = true;
|
||||
return s;
|
||||
});
|
||||
upgrade(nextVersion);
|
||||
upgrade(nextVersion.tag_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,6 +117,12 @@ export function hanError(err) {
|
||||
case -52: return "Decryption failed";
|
||||
case -53: return "Encryption key invalid";
|
||||
case 90: return "No HAN data received last 30s";
|
||||
case 91: return "Serial break";
|
||||
case 92: return "Serial buffer full";
|
||||
case 93: return "Serial FIFO overflow";
|
||||
case 94: return "Serial frame error";
|
||||
case 95: return "Serial parity error";
|
||||
case 96: return "RX error";
|
||||
case 98: return "Exception in code, debugging necessary";
|
||||
case 99: return "Autodetection failed";
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
s.upgrading = true;
|
||||
return s;
|
||||
});
|
||||
upgrade(nextVersion);
|
||||
upgrade(nextVersion.tag_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,7 +109,7 @@
|
||||
{/if}
|
||||
</div>
|
||||
<div class="my-2">
|
||||
Reason: {getResetReason(sysinfo)} ({sysinfo.boot_reason})
|
||||
Reason: {getResetReason(sysinfo)} ({sysinfo.boot_reason}/{sysinfo.ex_cause})
|
||||
</div>
|
||||
{/if}
|
||||
<div class="my-2">
|
||||
@@ -155,6 +155,11 @@
|
||||
<div class="my-2">
|
||||
Installed version: {sysinfo.version}
|
||||
</div>
|
||||
{#if sysinfo.upgrade.t && sysinfo.upgrade.t != sysinfo.version}
|
||||
<div class="my-2">
|
||||
<div class="bd-yellow">Previous upgrade attempt ({sysinfo.upgrade.t}) does not match current version ({sysinfo.version}) [{sysinfo.upgrade.x}/{sysinfo.upgrade.e}]</div>
|
||||
</div>
|
||||
{/if}
|
||||
{#if nextVersion}
|
||||
<div class="my-2 flex">
|
||||
Latest version:
|
||||
|
||||
@@ -2,8 +2,8 @@ export function upgradeWarningText(board) {
|
||||
return 'WARNING: ' + board + ' must be connected to an external power supply during firmware upgrade. Failure to do so may cause power-down during upload resulting in non-functioning unit.'
|
||||
}
|
||||
|
||||
export async function upgrade() {
|
||||
const response = await fetch('/upgrade', {
|
||||
export async function upgrade(expected_version) {
|
||||
const response = await fetch('/upgrade?expected_version='+expected_version, {
|
||||
method: 'POST'
|
||||
});
|
||||
await response.json();
|
||||
|
||||
@@ -17,18 +17,18 @@ export default defineConfig({
|
||||
plugins: [svelte()],
|
||||
server: {
|
||||
proxy: {
|
||||
"/data.json": "http://192.168.233.235",
|
||||
"/energyprice.json": "http://192.168.233.235",
|
||||
"/dayplot.json": "http://192.168.233.235",
|
||||
"/monthplot.json": "http://192.168.233.235",
|
||||
"/temperature.json": "http://192.168.233.235",
|
||||
"/sysinfo.json": "http://192.168.233.235",
|
||||
"/configuration.json": "http://192.168.233.235",
|
||||
"/tariff.json": "http://192.168.233.235",
|
||||
"/save": "http://192.168.233.235",
|
||||
"/reboot": "http://192.168.233.235",
|
||||
"/configfile": "http://192.168.233.235",
|
||||
"/upgrade": "http://192.168.233.235"
|
||||
"/data.json": "http://192.168.233.244",
|
||||
"/energyprice.json": "http://192.168.233.244",
|
||||
"/dayplot.json": "http://192.168.233.244",
|
||||
"/monthplot.json": "http://192.168.233.244",
|
||||
"/temperature.json": "http://192.168.233.244",
|
||||
"/sysinfo.json": "http://192.168.233.244",
|
||||
"/configuration.json": "http://192.168.233.244",
|
||||
"/tariff.json": "http://192.168.233.244",
|
||||
"/save": "http://192.168.233.244",
|
||||
"/reboot": "http://192.168.233.244",
|
||||
"/configfile": "http://192.168.233.244",
|
||||
"/upgrade": "http://192.168.233.244"
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -97,6 +97,7 @@ private:
|
||||
void handleSave();
|
||||
void reboot();
|
||||
void upgrade();
|
||||
void upgradeFromUrl(String url, String nextVersion);
|
||||
void firmwareHtml();
|
||||
void firmwarePost();
|
||||
void firmwareUpload();
|
||||
|
||||
@@ -37,5 +37,12 @@
|
||||
"s": %d
|
||||
},
|
||||
"security": %d,
|
||||
"boot_reason": %d
|
||||
"boot_reason": %d,
|
||||
"ex_cause": %d,
|
||||
"upgrade": {
|
||||
"x": %d,
|
||||
"e": %d,
|
||||
"f": "%s",
|
||||
"t": "%s"
|
||||
}
|
||||
}
|
||||
@@ -158,11 +158,11 @@ void AmsWebServer::loop() {
|
||||
|
||||
bool AmsWebServer::checkSecurity(byte level, bool send401) {
|
||||
bool access = WiFi.getMode() == WIFI_AP || webConfig.security < level;
|
||||
if(!access && webConfig.security >= level && server.hasHeader("Authorization")) {
|
||||
if(!access && webConfig.security >= level && server.hasHeader(F("Authorization"))) {
|
||||
String expectedAuth = String(webConfig.username) + ":" + String(webConfig.password);
|
||||
|
||||
String providedPwd = server.header("Authorization");
|
||||
providedPwd.replace("Basic ", "");
|
||||
String providedPwd = server.header(F("Authorization"));
|
||||
providedPwd.replace(F("Basic "), F(""));
|
||||
|
||||
#if defined(ESP8266)
|
||||
String expectedBase64 = base64::encode(expectedAuth, false);
|
||||
@@ -170,9 +170,6 @@ bool AmsWebServer::checkSecurity(byte level, bool send401) {
|
||||
String expectedBase64 = base64::encode(expectedAuth);
|
||||
#endif
|
||||
|
||||
debugger->printf("Expected auth: %s\n", expectedBase64.c_str());
|
||||
debugger->printf("Provided auth: %s\n", providedPwd.c_str());
|
||||
|
||||
access = providedPwd.equals(expectedBase64);
|
||||
}
|
||||
|
||||
@@ -192,21 +189,21 @@ void AmsWebServer::notFound() {
|
||||
}
|
||||
|
||||
void AmsWebServer::githubSvg() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /github.svg over http...\n");
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Serving /github.svg over http...\n"));
|
||||
|
||||
server.sendHeader(HEADER_CACHE_CONTROL, CACHE_1HR);
|
||||
server.send_P(200, "image/svg+xml", GITHUB_SVG);
|
||||
}
|
||||
|
||||
void AmsWebServer::faviconSvg() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /favicon.ico over http...\n");
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Serving /favicon.ico over http...\n"));
|
||||
|
||||
server.sendHeader(HEADER_CACHE_CONTROL, CACHE_1HR);
|
||||
server.send_P(200, "image/svg+xml", FAVICON_SVG);
|
||||
}
|
||||
|
||||
void AmsWebServer::sysinfoJson() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /sysinfo.json over http...\n");
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Serving /sysinfo.json over http...\n"));
|
||||
|
||||
SystemConfig sys;
|
||||
config->getSystemConfig(sys);
|
||||
@@ -254,13 +251,16 @@ void AmsWebServer::sysinfoJson() {
|
||||
UiConfig ui;
|
||||
config->getUiConfig(ui);
|
||||
|
||||
UpgradeInformation upinfo;
|
||||
config->getUpgradeInformation(upinfo);
|
||||
|
||||
String meterModel = meterState->getMeterModel();
|
||||
if(!meterModel.isEmpty())
|
||||
meterModel.replace("\\", "\\\\");
|
||||
meterModel.replace(F("\\"), F("\\\\"));
|
||||
|
||||
String meterId = meterState->getMeterId();
|
||||
if(!meterId.isEmpty())
|
||||
meterId.replace("\\", "\\\\");
|
||||
meterId.replace(F("\\"), F("\\\\"));
|
||||
|
||||
int size = snprintf_P(buf, BufferSize, SYSINFO_JSON,
|
||||
VERSION,
|
||||
@@ -314,10 +314,16 @@ void AmsWebServer::sysinfoJson() {
|
||||
ui.showTemperaturePlot,
|
||||
webConfig.security,
|
||||
#if defined(ESP32)
|
||||
rtc_get_reset_reason(0)
|
||||
rtc_get_reset_reason(0),
|
||||
0,
|
||||
#else
|
||||
ESP.getResetInfoPtr()->reason
|
||||
ESP.getResetInfoPtr()->reason,
|
||||
ESP.getResetInfoPtr()->exccause,
|
||||
#endif
|
||||
upinfo.exitCode,
|
||||
upinfo.errorCode,
|
||||
upinfo.fromVersion,
|
||||
upinfo.toVersion
|
||||
);
|
||||
|
||||
stripNonAscii((uint8_t*) buf, size+1);
|
||||
@@ -329,26 +335,23 @@ void AmsWebServer::sysinfoJson() {
|
||||
server.setContentLength(strlen(buf));
|
||||
server.send(200, MIME_JSON, buf);
|
||||
|
||||
server.handleClient();
|
||||
delay(250);
|
||||
|
||||
if(performRestart || rebootForUpgrade) {
|
||||
server.handleClient();
|
||||
delay(250);
|
||||
|
||||
if(ds != NULL) {
|
||||
ds->save();
|
||||
}
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf(PSTR("Rebooting"));
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Rebooting\n"));
|
||||
debugger->flush();
|
||||
delay(1000);
|
||||
#if defined(ESP8266)
|
||||
ESP.reset();
|
||||
#elif defined(ESP32)
|
||||
ESP.restart();
|
||||
#endif
|
||||
ESP.restart();
|
||||
performRestart = false;
|
||||
}
|
||||
}
|
||||
|
||||
void AmsWebServer::dataJson() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /data.json over http...\n");
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Serving /data.json over http...\n"));
|
||||
uint64_t millis = millis64();
|
||||
|
||||
if(!checkSecurity(2, true))
|
||||
@@ -491,7 +494,7 @@ void AmsWebServer::dataJson() {
|
||||
}
|
||||
|
||||
void AmsWebServer::dayplotJson() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /dayplot.json over http...\n");
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Serving /dayplot.json over http...\n"));
|
||||
|
||||
if(!checkSecurity(2))
|
||||
return;
|
||||
@@ -560,7 +563,7 @@ void AmsWebServer::dayplotJson() {
|
||||
}
|
||||
|
||||
void AmsWebServer::monthplotJson() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /monthplot.json over http...\n");
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Serving /monthplot.json over http...\n"));
|
||||
|
||||
if(!checkSecurity(2))
|
||||
return;
|
||||
@@ -643,7 +646,7 @@ void AmsWebServer::monthplotJson() {
|
||||
}
|
||||
|
||||
void AmsWebServer::energyPriceJson() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /energyprice.json over http...\n");
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Serving /energyprice.json over http...\n"));
|
||||
|
||||
if(!checkSecurity(2))
|
||||
return;
|
||||
@@ -702,13 +705,13 @@ void AmsWebServer::energyPriceJson() {
|
||||
}
|
||||
|
||||
void AmsWebServer::temperatureJson() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /temperature.json over http...\n");
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Serving /temperature.json over http...\n"));
|
||||
|
||||
if(!checkSecurity(2))
|
||||
return;
|
||||
|
||||
int count = hw->getTempSensorCount();
|
||||
snprintf(buf, 16, "{\"c\":%d,\"s\":[", count);
|
||||
snprintf_P(buf, 16, PSTR("{\"c\":%d,\"s\":["), count);
|
||||
|
||||
for(int i = 0; i < count; i++) {
|
||||
TempSensorData* data = hw->getTempSensorData(i);
|
||||
@@ -723,10 +726,10 @@ void AmsWebServer::temperatureJson() {
|
||||
conf == NULL || conf->common ? 1 : 0,
|
||||
data->lastRead
|
||||
);
|
||||
delay(10);
|
||||
yield();
|
||||
}
|
||||
char* pos = buf+strlen(buf);
|
||||
snprintf(count == 0 ? pos : pos-1, 8, "]}");
|
||||
snprintf_P(count == 0 ? pos : pos-1, 8, PSTR("]}"));
|
||||
|
||||
server.sendHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE);
|
||||
server.sendHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE);
|
||||
@@ -737,7 +740,7 @@ void AmsWebServer::temperatureJson() {
|
||||
}
|
||||
|
||||
void AmsWebServer::indexHtml() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /index.html over http...\n");
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Serving /index.html over http...\n"));
|
||||
|
||||
server.sendHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE);
|
||||
server.sendHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE);
|
||||
@@ -750,7 +753,7 @@ void AmsWebServer::indexHtml() {
|
||||
}
|
||||
|
||||
void AmsWebServer::indexCss() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /index.css over http...\n");
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Serving /index.css over http...\n"));
|
||||
|
||||
if(!checkSecurity(2))
|
||||
return;
|
||||
@@ -761,7 +764,7 @@ void AmsWebServer::indexCss() {
|
||||
}
|
||||
|
||||
void AmsWebServer::indexJs() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /index.js over http...\n");
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Serving /index.js over http...\n"));
|
||||
|
||||
if(!checkSecurity(2))
|
||||
return;
|
||||
@@ -772,7 +775,7 @@ void AmsWebServer::indexJs() {
|
||||
}
|
||||
|
||||
void AmsWebServer::configurationJson() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /configuration.json over http...\n");
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Serving /configuration.json over http...\n"));
|
||||
|
||||
if(!checkSecurity(1))
|
||||
return;
|
||||
@@ -960,11 +963,11 @@ void AmsWebServer::configurationJson() {
|
||||
haconf.discoveryNameTag
|
||||
);
|
||||
server.sendContent(buf);
|
||||
server.sendContent("}");
|
||||
server.sendContent_P(PSTR("}"));
|
||||
}
|
||||
|
||||
void AmsWebServer::handleSave() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Handling save method from http"));
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Handling save method from http\n"));
|
||||
if(!checkSecurity(1))
|
||||
return;
|
||||
|
||||
@@ -1176,7 +1179,7 @@ void AmsWebServer::handleSave() {
|
||||
}
|
||||
|
||||
if(server.hasArg(F("m")) && server.arg(F("m")) == F("true")) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Received meter config"));
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Received meter config\n"));
|
||||
config->getMeterConfig(*meterConfig);
|
||||
meterConfig->baud = server.arg(F("mb")).toInt();
|
||||
meterConfig->parity = server.arg(F("mp")).toInt();
|
||||
@@ -1207,15 +1210,15 @@ void AmsWebServer::handleSave() {
|
||||
memset(meterConfig->authenticationKey, 0, 16);
|
||||
}
|
||||
|
||||
meterConfig->wattageMultiplier = server.arg(F("mmw")).toDouble() * 1000;
|
||||
meterConfig->voltageMultiplier = server.arg(F("mmv")).toDouble() * 1000;
|
||||
meterConfig->amperageMultiplier = server.arg(F("mma")).toDouble() * 1000;
|
||||
meterConfig->accumulatedMultiplier = server.arg(F("mmc")).toDouble() * 1000;
|
||||
meterConfig->wattageMultiplier = server.arg(F("mmw")).toFloat() * 1000;
|
||||
meterConfig->voltageMultiplier = server.arg(F("mmv")).toFloat() * 1000;
|
||||
meterConfig->amperageMultiplier = server.arg(F("mma")).toFloat() * 1000;
|
||||
meterConfig->accumulatedMultiplier = server.arg(F("mmc")).toFloat() * 1000;
|
||||
config->setMeterConfig(*meterConfig);
|
||||
}
|
||||
|
||||
if(server.hasArg(F("w")) && server.arg(F("w")) == F("true")) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Received WiFi config"));
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Received WiFi config\n"));
|
||||
WiFiConfig wifi;
|
||||
config->getWiFiConfig(wifi);
|
||||
strcpy(wifi.ssid, server.arg(F("ws")).c_str());
|
||||
@@ -1257,7 +1260,7 @@ void AmsWebServer::handleSave() {
|
||||
}
|
||||
|
||||
if(server.hasArg(F("q")) && server.arg(F("q")) == F("true")) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Received MQTT config"));
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Received MQTT config\n"));
|
||||
MqttConfig mqtt;
|
||||
config->getMqttConfig(mqtt);
|
||||
if(server.hasArg(F("qh")) && !server.arg(F("qh")).isEmpty()) {
|
||||
@@ -1288,7 +1291,7 @@ void AmsWebServer::handleSave() {
|
||||
}
|
||||
|
||||
if(server.hasArg(F("o")) && server.arg(F("o")) == F("true")) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Received Domoticz config"));
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Received Domoticz config\n"));
|
||||
DomoticzConfig domo {
|
||||
static_cast<uint16_t>(server.arg(F("oe")).toInt()),
|
||||
static_cast<uint16_t>(server.arg(F("ou1")).toInt()),
|
||||
@@ -1300,7 +1303,7 @@ void AmsWebServer::handleSave() {
|
||||
}
|
||||
|
||||
if(server.hasArg(F("h")) && server.arg(F("h")) == F("true")) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Received Home-Assistant config"));
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Received Home-Assistant config\n"));
|
||||
HomeAssistantConfig haconf;
|
||||
config->getHomeAssistantConfig(haconf);
|
||||
strcpy(haconf.discoveryPrefix, server.arg(F("ht")).c_str());
|
||||
@@ -1310,7 +1313,7 @@ void AmsWebServer::handleSave() {
|
||||
}
|
||||
|
||||
if(server.hasArg(F("g")) && server.arg(F("g")) == F("true")) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Received web config"));
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Received web config\n"));
|
||||
webConfig.security = server.arg(F("gs")).toInt();
|
||||
if(webConfig.security > 0) {
|
||||
strcpy(webConfig.username, server.arg(F("gu")).c_str());
|
||||
@@ -1340,7 +1343,7 @@ void AmsWebServer::handleSave() {
|
||||
}
|
||||
|
||||
if(server.hasArg(F("i")) && server.arg(F("i")) == F("true")) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Received GPIO config"));
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Received GPIO config\n"));
|
||||
gpioConfig->hanPin = server.hasArg(F("ihp")) && !server.arg(F("ihp")).isEmpty() ? server.arg(F("ihp")).toInt() : 3;
|
||||
gpioConfig->hanPinPullup = server.hasArg(F("ihu")) && server.arg(F("ihu")) == F("true");
|
||||
gpioConfig->ledPin = server.hasArg(F("ilp")) && !server.arg(F("ilp")).isEmpty() ? server.arg(F("ilp")).toInt() : 0xFF;
|
||||
@@ -1359,7 +1362,7 @@ void AmsWebServer::handleSave() {
|
||||
}
|
||||
|
||||
if(server.hasArg(F("iv")) && server.arg(F("iv")) == F("true")) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Received Vcc config"));
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Received Vcc config\n"));
|
||||
gpioConfig->vccOffset = server.hasArg(F("ivo")) && !server.arg(F("ivo")).isEmpty() ? server.arg(F("ivo")).toFloat() * 100 : 0;
|
||||
gpioConfig->vccMultiplier = server.hasArg(F("ivm")) && !server.arg(F("ivm")).isEmpty() ? server.arg(F("ivm")).toFloat() * 1000 : 1000;
|
||||
gpioConfig->vccBootLimit = server.hasArg(F("ivb")) && !server.arg(F("ivb")).isEmpty() ? server.arg(F("ivb")).toFloat() * 10 : 0;
|
||||
@@ -1367,7 +1370,7 @@ void AmsWebServer::handleSave() {
|
||||
}
|
||||
|
||||
if(server.hasArg(F("d")) && server.arg(F("d")) == F("true")) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Received Debug config"));
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Received Debug config\n"));
|
||||
DebugConfig debug;
|
||||
config->getDebugConfig(debug);
|
||||
bool active = debug.serial || debug.telnet;
|
||||
@@ -1414,7 +1417,7 @@ void AmsWebServer::handleSave() {
|
||||
}
|
||||
|
||||
if(server.hasArg(F("p")) && server.arg(F("p")) == F("true")) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Received price API config"));
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Received price API config\n"));
|
||||
|
||||
priceRegion = server.arg(F("pr"));
|
||||
|
||||
@@ -1429,7 +1432,7 @@ void AmsWebServer::handleSave() {
|
||||
}
|
||||
|
||||
if(server.hasArg(F("t")) && server.arg(F("t")) == F("true")) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Received energy accounting config"));
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Received energy accounting config\n"));
|
||||
EnergyAccountingConfig eac;
|
||||
eac.thresholds[0] = server.arg(F("t0")).toInt();
|
||||
eac.thresholds[1] = server.arg(F("t1")).toInt();
|
||||
@@ -1444,10 +1447,10 @@ void AmsWebServer::handleSave() {
|
||||
config->setEnergyAccountingConfig(eac);
|
||||
}
|
||||
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf(PSTR("Saving configuration now..."));
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Saving configuration now...\n"));
|
||||
|
||||
if (config->save()) {
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf(PSTR("Successfully saved."));
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Successfully saved.\n"));
|
||||
if(config->isWifiChanged() || performRestart) {
|
||||
performRestart = true;
|
||||
} else {
|
||||
@@ -1465,26 +1468,23 @@ void AmsWebServer::handleSave() {
|
||||
server.setContentLength(strlen(buf));
|
||||
server.send(200, MIME_JSON, buf);
|
||||
|
||||
server.handleClient();
|
||||
delay(250);
|
||||
|
||||
if(performRestart || rebootForUpgrade) {
|
||||
server.handleClient();
|
||||
delay(250);
|
||||
|
||||
if(ds != NULL) {
|
||||
ds->save();
|
||||
}
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf(PSTR("Rebooting"));
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Rebooting\n"));
|
||||
debugger->flush();
|
||||
delay(1000);
|
||||
#if defined(ESP8266)
|
||||
ESP.reset();
|
||||
#elif defined(ESP32)
|
||||
ESP.restart();
|
||||
#endif
|
||||
ESP.restart();
|
||||
performRestart = false;
|
||||
}
|
||||
}
|
||||
|
||||
void AmsWebServer::reboot() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /reboot over http...\n");
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Serving /reboot over http...\n"));
|
||||
|
||||
if(!checkSecurity(1))
|
||||
return;
|
||||
@@ -1494,18 +1494,15 @@ void AmsWebServer::reboot() {
|
||||
server.handleClient();
|
||||
delay(250);
|
||||
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf(PSTR("Rebooting"));
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Rebooting\n"));
|
||||
debugger->flush();
|
||||
delay(1000);
|
||||
#if defined(ESP8266)
|
||||
ESP.reset();
|
||||
#elif defined(ESP32)
|
||||
ESP.restart();
|
||||
#endif
|
||||
ESP.restart();
|
||||
performRestart = false;
|
||||
}
|
||||
|
||||
void AmsWebServer::upgrade() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /upgrade over http...\n");
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Serving /upgrade over http...\n"));
|
||||
|
||||
if(!checkSecurity(1))
|
||||
return;
|
||||
@@ -1534,46 +1531,59 @@ void AmsWebServer::upgrade() {
|
||||
if(server.hasArg(F("version"))) {
|
||||
url += "/" + server.arg(F("version"));
|
||||
}
|
||||
|
||||
WiFiClient client;
|
||||
#if defined(ESP8266)
|
||||
String chipType = F("esp8266");
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
String chipType = F("esp32s2");
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
String chipType = F("esp32c3");
|
||||
#elif defined(ESP32)
|
||||
#if defined(CONFIG_FREERTOS_UNICORE)
|
||||
String chipType = F("esp32solo");
|
||||
#else
|
||||
String chipType = F("esp32");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(ESP8266)
|
||||
ESPhttpUpdate.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||
t_httpUpdate_return ret = ESPhttpUpdate.update(client, url, VERSION);
|
||||
#elif defined(ESP32)
|
||||
HTTPUpdate httpUpdate;
|
||||
httpUpdate.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||
HTTPUpdateResult ret = httpUpdate.update(client, url, String(VERSION) + "-" + chipType);
|
||||
#endif
|
||||
|
||||
switch(ret) {
|
||||
case HTTP_UPDATE_FAILED:
|
||||
debugger->printf(PSTR("Update failed"));
|
||||
break;
|
||||
case HTTP_UPDATE_NO_UPDATES:
|
||||
debugger->printf(PSTR("No Update"));
|
||||
break;
|
||||
case HTTP_UPDATE_OK:
|
||||
debugger->printf(PSTR("Update OK"));
|
||||
break;
|
||||
}
|
||||
upgradeFromUrl(url, server.arg(F("expected_version")));
|
||||
}
|
||||
}
|
||||
|
||||
void AmsWebServer::upgradeFromUrl(String url, String nextVersion) {
|
||||
config->setUpgradeInformation(0xFF, 0xFF, VERSION, nextVersion.c_str());
|
||||
|
||||
WiFiClient client;
|
||||
#if defined(ESP8266)
|
||||
String chipType = F("esp8266");
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
String chipType = F("esp32s2");
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
String chipType = F("esp32c3");
|
||||
#elif defined(ESP32)
|
||||
#if defined(CONFIG_FREERTOS_UNICORE)
|
||||
String chipType = F("esp32solo");
|
||||
#else
|
||||
String chipType = F("esp32");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(ESP8266)
|
||||
ESP8266HTTPUpdate httpUpdate = ESP8266HTTPUpdate(60000);
|
||||
String currentVersion = VERSION;
|
||||
#elif defined(ESP32)
|
||||
HTTPUpdate httpUpdate = HTTPUpdate(60000);
|
||||
String currentVersion = String(VERSION) + "-" + chipType;
|
||||
#endif
|
||||
|
||||
httpUpdate.rebootOnUpdate(false);
|
||||
httpUpdate.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||
HTTPUpdateResult ret = httpUpdate.update(client, url, currentVersion);
|
||||
int lastError = httpUpdate.getLastError();
|
||||
|
||||
config->setUpgradeInformation(ret, ret == HTTP_UPDATE_OK ? 0 : lastError, VERSION, nextVersion.c_str());
|
||||
switch(ret) {
|
||||
case HTTP_UPDATE_FAILED:
|
||||
debugger->printf_P(PSTR("Update failed\n"));
|
||||
break;
|
||||
case HTTP_UPDATE_NO_UPDATES:
|
||||
debugger->printf_P(PSTR("No Update\n"));
|
||||
break;
|
||||
case HTTP_UPDATE_OK:
|
||||
debugger->printf_P(PSTR("Update OK\n"));
|
||||
debugger->flush();
|
||||
ESP.restart();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void AmsWebServer::firmwareHtml() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Serving /firmware.html over http..."));
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Serving /firmware.html over http...\n"));
|
||||
|
||||
if(!checkSecurity(1))
|
||||
return;
|
||||
@@ -1587,53 +1597,20 @@ void AmsWebServer::firmwareHtml() {
|
||||
}
|
||||
|
||||
void AmsWebServer::firmwarePost() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Handling firmware post..."));
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Handling firmware post...\n"));
|
||||
if(!checkSecurity(1))
|
||||
return;
|
||||
|
||||
if(rebootForUpgrade) {
|
||||
server.send(200);
|
||||
} else {
|
||||
config->setUpgradeInformation(0xFF, 0xFF, VERSION, "");
|
||||
if(server.hasArg(F("url"))) {
|
||||
String url = server.arg(F("url"));
|
||||
if(!url.isEmpty() && (url.startsWith(F("http://")) || url.startsWith(F("https://")))) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Custom firmware URL was provided"));
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Custom firmware URL was provided\n"));
|
||||
|
||||
WiFiClient client;
|
||||
#if defined(ESP8266)
|
||||
String chipType = F("esp8266");
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
|
||||
String chipType = F("esp32s2");
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
String chipType = F("esp32c3");
|
||||
#elif defined(ESP32)
|
||||
#if defined(CONFIG_FREERTOS_UNICORE)
|
||||
String chipType = F("esp32solo");
|
||||
#else
|
||||
String chipType = F("esp32");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(ESP8266)
|
||||
ESPhttpUpdate.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||
t_httpUpdate_return ret = ESPhttpUpdate.update(client, url, VERSION);
|
||||
#elif defined(ESP32)
|
||||
HTTPUpdate httpUpdate;
|
||||
httpUpdate.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||
HTTPUpdateResult ret = httpUpdate.update(client, url, String(VERSION) + "-" + chipType);
|
||||
#endif
|
||||
|
||||
switch(ret) {
|
||||
case HTTP_UPDATE_FAILED:
|
||||
debugger->printf(PSTR("Update failed"));
|
||||
break;
|
||||
case HTTP_UPDATE_NO_UPDATES:
|
||||
debugger->printf(PSTR("No Update"));
|
||||
break;
|
||||
case HTTP_UPDATE_OK:
|
||||
debugger->printf(PSTR("Update OK"));
|
||||
break;
|
||||
}
|
||||
upgradeFromUrl(url, "");
|
||||
server.send(200, MIME_PLAIN, "OK");
|
||||
return;
|
||||
}
|
||||
@@ -1652,11 +1629,11 @@ void AmsWebServer::firmwareUpload() {
|
||||
if(upload.status == UPLOAD_FILE_START) {
|
||||
String filename = upload.filename;
|
||||
if(filename.isEmpty()) {
|
||||
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf(PSTR("No file, falling back to post\n"));
|
||||
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("No file, falling back to post\n"));
|
||||
return;
|
||||
}
|
||||
if(!filename.endsWith(".bin")) {
|
||||
server.send(500, MIME_PLAIN, "500: couldn't create file");
|
||||
if(!filename.endsWith(F(".bin"))) {
|
||||
server.send_P(500, MIME_PLAIN, PSTR("500: couldn't create file"));
|
||||
} else {
|
||||
#if defined(ESP32)
|
||||
esp_task_wdt_delete(NULL);
|
||||
@@ -1669,7 +1646,7 @@ void AmsWebServer::firmwareUpload() {
|
||||
uploadFile(FILE_FIRMWARE);
|
||||
if(upload.status == UPLOAD_FILE_END) {
|
||||
rebootForUpgrade = true;
|
||||
server.sendHeader("Location","/");
|
||||
server.sendHeader(HEADER_LOCATION,F("/"));
|
||||
server.send(302);
|
||||
}
|
||||
}
|
||||
@@ -1678,10 +1655,10 @@ HTTPUpload& AmsWebServer::uploadFile(const char* path) {
|
||||
HTTPUpload& upload = server.upload();
|
||||
if(upload.status == UPLOAD_FILE_START){
|
||||
if(uploading) {
|
||||
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf(PSTR("Upload already in progress\n"));
|
||||
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("Upload already in progress\n"));
|
||||
server.send_P(500, MIME_HTML, PSTR("<html><body><h1>Upload already in progress!</h1></body></html>"));
|
||||
} else if (!LittleFS.begin()) {
|
||||
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf(PSTR("An Error has occurred while mounting LittleFS\n"));
|
||||
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("An Error has occurred while mounting LittleFS\n"));
|
||||
server.send_P(500, MIME_HTML, PSTR("<html><body><h1>Unable to mount LittleFS!</h1></body></html>"));
|
||||
} else {
|
||||
uploading = true;
|
||||
@@ -1716,7 +1693,7 @@ HTTPUpload& AmsWebServer::uploadFile(const char* path) {
|
||||
LittleFS.remove(path);
|
||||
LittleFS.end();
|
||||
|
||||
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf(PSTR("An Error has occurred while writing file"));
|
||||
if(debugger->isActive(RemoteDebug::ERROR)) debugger->printf_P(PSTR("An Error has occurred while writing file\n"));
|
||||
snprintf_P(buf, BufferSize, RESPONSE_JSON,
|
||||
"false",
|
||||
"File size does not match",
|
||||
@@ -1733,7 +1710,7 @@ HTTPUpload& AmsWebServer::uploadFile(const char* path) {
|
||||
if(file) {
|
||||
file.flush();
|
||||
file.close();
|
||||
// LittleFS.end();
|
||||
LittleFS.end();
|
||||
} else {
|
||||
debugger->printf_P(PSTR("File was not valid in the end... Write error: %d, \n"), file.getWriteError());
|
||||
snprintf_P(buf, BufferSize, RESPONSE_JSON,
|
||||
@@ -1757,13 +1734,13 @@ void AmsWebServer::factoryResetPost() {
|
||||
if(!checkSecurity(1))
|
||||
return;
|
||||
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Performing factory reset"));
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Performing factory reset\n"));
|
||||
|
||||
bool success = false;
|
||||
if(server.hasArg(F("perform")) && server.arg(F("perform")) == F("true")) {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Formatting LittleFS"));
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Formatting LittleFS\n"));
|
||||
LittleFS.format();
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Clearing configuration"));
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Clearing configuration\n"));
|
||||
config->clear();
|
||||
|
||||
success = true;
|
||||
@@ -1780,13 +1757,10 @@ void AmsWebServer::factoryResetPost() {
|
||||
server.handleClient();
|
||||
delay(250);
|
||||
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf(PSTR("Rebooting"));
|
||||
if(debugger->isActive(RemoteDebug::INFO)) debugger->printf_P(PSTR("Rebooting\n"));
|
||||
debugger->flush();
|
||||
delay(1000);
|
||||
#if defined(ESP8266)
|
||||
ESP.reset();
|
||||
#elif defined(ESP32)
|
||||
ESP.restart();
|
||||
#endif
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
void AmsWebServer::robotstxt() {
|
||||
@@ -1843,7 +1817,7 @@ void AmsWebServer::mqttKeyUpload() {
|
||||
}
|
||||
|
||||
void AmsWebServer::tariffJson() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /tariff.json over http...\n");
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Serving /tariff.json over http...\n"));
|
||||
|
||||
if(!checkSecurity(2))
|
||||
return;
|
||||
@@ -1892,7 +1866,7 @@ void AmsWebServer::setPriceSettings(String region, String currency) {
|
||||
}
|
||||
|
||||
void AmsWebServer::configFileDownload() {
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /configfile.cfg over http...\n");
|
||||
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf_P(PSTR("Serving /configfile.cfg over http...\n"));
|
||||
|
||||
if(!checkSecurity(1))
|
||||
return;
|
||||
@@ -2233,7 +2207,7 @@ void AmsWebServer::configFileDownload() {
|
||||
ead.peaks[4].day,
|
||||
ead.peaks[4].value / 100.0
|
||||
));
|
||||
server.sendContent("\n");
|
||||
server.sendContent_P(PSTR("\n"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2244,12 +2218,12 @@ void AmsWebServer::configFileUpload() {
|
||||
HTTPUpload& upload = uploadFile(FILE_CFG);
|
||||
if(upload.status == UPLOAD_FILE_END) {
|
||||
performRestart = true;
|
||||
server.sendHeader("Location","/");
|
||||
server.sendHeader(HEADER_LOCATION,F("/"));
|
||||
server.send(303);
|
||||
}
|
||||
}
|
||||
|
||||
void AmsWebServer::redirectToMain() {
|
||||
server.sendHeader("Location","/");
|
||||
server.sendHeader(HEADER_LOCATION,F("/"));
|
||||
server.send(302);
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
extra_configs = platformio-user.ini
|
||||
|
||||
[common]
|
||||
lib_deps = EEPROM, LittleFS, DNSServer, 256dpi/MQTT@2.5.0, OneWireNg@0.10.0, DallasTemperature@3.9.1, EspSoftwareSerial@6.14.1, https://github.com/gskjold/RemoteDebug.git, Time@1.6.1, Timezone@1.2.4, AmsConfiguration, AmsData, AmsDataStorage, HwTools, Uptime, AmsDecoder, EntsoePriceApi, EnergyAccounting, RawMqttHandler, JsonMqttHandler, DomoticzMqttHandler, HomeAssistantMqttHandler, SvelteUi
|
||||
lib_deps = EEPROM, LittleFS, DNSServer, https://github.com/256dpi/arduino-mqtt.git, OneWireNg@0.10.0, DallasTemperature@3.9.1, EspSoftwareSerial@6.14.1, https://github.com/gskjold/RemoteDebug.git, Time@1.6.1, Timezone@1.2.4, AmsConfiguration, AmsData, AmsDataStorage, HwTools, Uptime, AmsDecoder, EntsoePriceApi, EnergyAccounting, RawMqttHandler, JsonMqttHandler, DomoticzMqttHandler, HomeAssistantMqttHandler, SvelteUi
|
||||
lib_ignore = OneWire
|
||||
extra_scripts =
|
||||
pre:scripts/addversion.py
|
||||
@@ -20,7 +20,7 @@ build_flags =
|
||||
lib_deps = WiFi, ESPmDNS, WiFiClientSecure, HTTPClient, FS, Update, HTTPUpdate, WebServer, ${common.lib_deps}
|
||||
|
||||
[env:esp8266]
|
||||
platform = espressif8266@3.2.0
|
||||
platform = espressif8266@4.2.0
|
||||
framework = arduino
|
||||
board = esp12e
|
||||
board_build.ldscript = eagle.flash.4m2m.ld
|
||||
@@ -32,7 +32,7 @@ lib_ignore = ${common.lib_ignore}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
|
||||
[env:esp32]
|
||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.5.3/platform-espressif32-2.0.5.3.zip
|
||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.02.00/platform-espressif32.zip
|
||||
framework = arduino
|
||||
board = esp32dev
|
||||
board_build.f_cpu = 160000000L
|
||||
@@ -47,7 +47,7 @@ extra_scripts = ${common.extra_scripts}
|
||||
# https://github.com/Jason2866/esp32-arduino-lib-builder
|
||||
|
||||
[env:esp32s2]
|
||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.5.3/platform-espressif32-2.0.5.3.zip
|
||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.02.00/platform-espressif32.zip
|
||||
framework = arduino
|
||||
board = esp32-s2-saola-1
|
||||
board_build.mcu = esp32s2
|
||||
@@ -63,7 +63,7 @@ lib_ignore = ${common.lib_ignore}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
|
||||
[env:esp32solo]
|
||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.5.3/platform-espressif32-2.0.5.3.zip
|
||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.02.00/platform-espressif32.zip
|
||||
framework = arduino
|
||||
board = esp32-solo1
|
||||
board_build.f_cpu = 160000000L
|
||||
@@ -75,7 +75,7 @@ lib_ignore = ${common.lib_ignore}
|
||||
extra_scripts = ${common.extra_scripts}
|
||||
|
||||
[env:esp32c3]
|
||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.5.3/platform-espressif32-2.0.5.3.zip
|
||||
platform = https://github.com/tasmota/platform-espressif32/releases/download/2023.02.00/platform-espressif32.zip
|
||||
framework = arduino
|
||||
board = esp32-c3-devkitm-1
|
||||
board_build.mcu = esp32c3
|
||||
|
||||
@@ -6,12 +6,23 @@
|
||||
#define INVALID_BUTTON_PIN 0xFFFFFFFF
|
||||
|
||||
#define MAX_PEM_SIZE 4096
|
||||
#define MAX_RX_BUFFER_SIZE 1024
|
||||
|
||||
#define METER_SOURCE_NONE 0
|
||||
#define METER_SOURCE_SERIAL 1
|
||||
#define METER_SOURCE_MQTT 2
|
||||
#define METER_SOURCE_ESPNOW 3
|
||||
|
||||
#define METER_ERROR_NO_DATA 90
|
||||
#define METER_ERROR_BREAK 91
|
||||
#define METER_ERROR_BUFFER 92
|
||||
#define METER_ERROR_FIFO 93
|
||||
#define METER_ERROR_FRAME 94
|
||||
#define METER_ERROR_PARITY 95
|
||||
#define METER_ERROR_RX 96
|
||||
#define METER_ERROR_EXCEPTION 98
|
||||
#define METER_ERROR_AUTODETECT 99
|
||||
|
||||
#include <SoftwareSerial.h>
|
||||
|
||||
#if defined(ESP8266)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,25 +9,25 @@ IEC6205621::IEC6205621(const char* p) {
|
||||
lastUpdateMillis = millis();
|
||||
listId = payload.substring(payload.startsWith("/") ? 1 : 0, payload.indexOf("\n"));
|
||||
|
||||
if(listId.startsWith("ADN")) {
|
||||
if(listId.startsWith(F("ADN"))) {
|
||||
meterType = AmsTypeAidon;
|
||||
listId = listId.substring(0,4);
|
||||
} else if(listId.startsWith("KFM")) {
|
||||
} else if(listId.startsWith(F("KFM"))) {
|
||||
meterType = AmsTypeKaifa;
|
||||
listId = listId.substring(0,4);
|
||||
} else if(listId.startsWith("KMP")) {
|
||||
} else if(listId.startsWith(F("KMP"))) {
|
||||
meterType = AmsTypeKamstrup;
|
||||
listId = listId.substring(0,4);
|
||||
} else if(listId.startsWith("ISk")) {
|
||||
} else if(listId.startsWith(F("ISk"))) {
|
||||
meterType = AmsTypeIskra;
|
||||
listId = listId.substring(0,5);
|
||||
} else if(listId.startsWith("XMX")) {
|
||||
} else if(listId.startsWith(F("XMX"))) {
|
||||
meterType = AmsTypeLandisGyr;
|
||||
listId = listId.substring(0,6);
|
||||
} else if(listId.startsWith("Ene") || listId.startsWith("EST")) {
|
||||
} else if(listId.startsWith(F("Ene")) || listId.startsWith(F("EST"))) {
|
||||
meterType = AmsTypeSagemcom;
|
||||
listId = listId.substring(0,4);
|
||||
} else if(listId.startsWith("LGF")) {
|
||||
} else if(listId.startsWith(F("LGF"))) {
|
||||
meterType = AmsTypeLandisGyr;
|
||||
listId = listId.substring(0,4);
|
||||
} else {
|
||||
@@ -35,21 +35,21 @@ IEC6205621::IEC6205621(const char* p) {
|
||||
listId = listId.substring(0,4);
|
||||
}
|
||||
|
||||
meterId = extract(payload, "96.1.0");
|
||||
meterId = extract(payload, F("96.1.0"));
|
||||
if(meterId.isEmpty()) {
|
||||
meterId = extract(payload, "0.0.5");
|
||||
meterId = extract(payload, F("0.0.5"));
|
||||
}
|
||||
|
||||
meterModel = extract(payload, "96.1.1");
|
||||
meterModel = extract(payload, F("96.1.1"));
|
||||
if(meterModel.isEmpty()) {
|
||||
meterModel = extract(payload, "96.1.7");
|
||||
meterModel = extract(payload, F("96.1.7"));
|
||||
if(meterModel.isEmpty()) {
|
||||
meterModel = payload.substring(payload.indexOf(listId) + listId.length(), payload.indexOf("\n"));
|
||||
meterModel = payload.substring(payload.indexOf(listId) + listId.length(), payload.indexOf(F("\n")));
|
||||
meterModel.trim();
|
||||
}
|
||||
}
|
||||
|
||||
String timestamp = extract(payload, "1.0.0");
|
||||
String timestamp = extract(payload, F("1.0.0"));
|
||||
if(timestamp.length() > 10) {
|
||||
tmElements_t tm;
|
||||
tm.Year = (timestamp.substring(0,2).toInt() + 2000) - 1970;
|
||||
@@ -61,36 +61,36 @@ IEC6205621::IEC6205621(const char* p) {
|
||||
meterTimestamp = makeTime(tm); // TODO: Adjust for time zone
|
||||
}
|
||||
|
||||
activeImportPower = (uint16_t) (extractDouble(payload, "1.7.0"));
|
||||
activeExportPower = (uint16_t) (extractDouble(payload, "2.7.0"));
|
||||
reactiveImportPower = (uint16_t) (extractDouble(payload, "3.7.0"));
|
||||
reactiveExportPower = (uint16_t) (extractDouble(payload, "4.7.0"));
|
||||
activeImportPower = (uint16_t) (extractDouble(payload, F("1.7.0")));
|
||||
activeExportPower = (uint16_t) (extractDouble(payload, F("2.7.0")));
|
||||
reactiveImportPower = (uint16_t) (extractDouble(payload, F("3.7.0")));
|
||||
reactiveExportPower = (uint16_t) (extractDouble(payload, F("4.7.0")));
|
||||
|
||||
if(activeImportPower > 0)
|
||||
listType = 1;
|
||||
|
||||
l1voltage = extractDouble(payload, "32.7.0");
|
||||
l2voltage = extractDouble(payload, "52.7.0");
|
||||
l3voltage = extractDouble(payload, "72.7.0");
|
||||
l1voltage = extractFloat(payload, F("32.7.0"));
|
||||
l2voltage = extractFloat(payload, F("52.7.0"));
|
||||
l3voltage = extractFloat(payload, F("72.7.0"));
|
||||
|
||||
l1current = extractDouble(payload, "31.7.0");
|
||||
l2current = extractDouble(payload, "51.7.0");
|
||||
l3current = extractDouble(payload, "71.7.0");
|
||||
l1current = extractFloat(payload, F("31.7.0"));
|
||||
l2current = extractFloat(payload, F("51.7.0"));
|
||||
l3current = extractFloat(payload, F("71.7.0"));
|
||||
|
||||
l1activeImportPower = extractDouble(payload, "21.7.0");
|
||||
l2activeImportPower = extractDouble(payload, "41.7.0");
|
||||
l3activeImportPower = extractDouble(payload, "61.7.0");
|
||||
l1activeImportPower = extractFloat(payload, F("21.7.0"));
|
||||
l2activeImportPower = extractFloat(payload, F("41.7.0"));
|
||||
l3activeImportPower = extractFloat(payload, F("61.7.0"));
|
||||
|
||||
l1activeExportPower = extractDouble(payload, "22.7.0");
|
||||
l2activeExportPower = extractDouble(payload, "42.7.0");
|
||||
l3activeExportPower = extractDouble(payload, "62.7.0");
|
||||
l1activeExportPower = extractFloat(payload, F("22.7.0"));
|
||||
l2activeExportPower = extractFloat(payload, F("42.7.0"));
|
||||
l3activeExportPower = extractFloat(payload, F("62.7.0"));
|
||||
|
||||
if(l1voltage > 0 || l2voltage > 0 || l3voltage > 0)
|
||||
listType = 2;
|
||||
|
||||
double val = 0.0;
|
||||
|
||||
val = extractDouble(payload, "1.8.0");
|
||||
val = extractDouble(payload, F("1.8.0"));
|
||||
if(val == 0) {
|
||||
for(int i = 1; i < 9; i++) {
|
||||
val += extractDouble(payload, "1.8." + String(i,10));
|
||||
@@ -98,7 +98,7 @@ IEC6205621::IEC6205621(const char* p) {
|
||||
}
|
||||
if(val > 0) activeImportCounter = val / 1000;
|
||||
|
||||
val = extractDouble(payload, "2.8.0");
|
||||
val = extractDouble(payload, F("2.8.0"));
|
||||
if(val == 0) {
|
||||
for(int i = 1; i < 9; i++) {
|
||||
val += extractDouble(payload, "2.8." + String(i,10));
|
||||
@@ -106,7 +106,7 @@ IEC6205621::IEC6205621(const char* p) {
|
||||
}
|
||||
if(val > 0) activeExportCounter = val / 1000;
|
||||
|
||||
val = extractDouble(payload, "3.8.0");
|
||||
val = extractDouble(payload, F("3.8.0"));
|
||||
if(val == 0) {
|
||||
for(int i = 1; i < 9; i++) {
|
||||
val += extractDouble(payload, "3.8." + String(i,10));
|
||||
@@ -114,7 +114,7 @@ IEC6205621::IEC6205621(const char* p) {
|
||||
}
|
||||
if(val > 0) reactiveImportCounter = val / 1000;
|
||||
|
||||
val = extractDouble(payload, "4.8.0");
|
||||
val = extractDouble(payload, F("4.8.0"));
|
||||
if(val == 0) {
|
||||
for(int i = 1; i < 9; i++) {
|
||||
val += extractDouble(payload, "4.8." + String(i,10));
|
||||
@@ -135,7 +135,7 @@ IEC6205621::IEC6205621(const char* p) {
|
||||
String IEC6205621::extract(String payload, String obis) {
|
||||
int a = payload.indexOf(String(":" + obis + "("));
|
||||
if(a > 0) {
|
||||
int b = payload.indexOf(")", a);
|
||||
int b = payload.indexOf(F(")"), a);
|
||||
if(b > a) {
|
||||
return payload.substring(a+obis.length()+2, b);
|
||||
}
|
||||
@@ -149,9 +149,22 @@ double IEC6205621::extractDouble(String payload, String obis) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
int a = str.indexOf("*");
|
||||
int a = str.indexOf(F("*"));
|
||||
String val = str.substring(0,a);
|
||||
String unit = str.substring(a+1);
|
||||
|
||||
return unit.startsWith("k") ? val.toDouble() * 1000 : val.toDouble();
|
||||
return unit.startsWith(F("k")) ? val.toDouble() * 1000 : val.toDouble();
|
||||
}
|
||||
|
||||
float IEC6205621::extractFloat(String payload, String obis) {
|
||||
String str = extract(payload, obis);
|
||||
if(str.isEmpty()) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
int a = str.indexOf(F("*"));
|
||||
String val = str.substring(0,a);
|
||||
String unit = str.substring(a+1);
|
||||
|
||||
return unit.startsWith(F("k")) ? val.toFloat() * 1000 : val.toFloat();
|
||||
}
|
||||
|
||||
@@ -11,5 +11,6 @@ public:
|
||||
private:
|
||||
String extract(String payload, String obis);
|
||||
double extractDouble(String payload, String obis);
|
||||
float extractFloat(String payload, String obis);
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "ntohll.h"
|
||||
|
||||
IEC6205675::IEC6205675(const char* d, uint8_t useMeterType, MeterConfig* meterConfig, DataParserContext &ctx) {
|
||||
double val;
|
||||
float val;
|
||||
char str[64];
|
||||
|
||||
TimeChangeRule CEST = {"CEST", Last, Sun, Mar, 2, 120};
|
||||
@@ -24,7 +24,7 @@ IEC6205675::IEC6205675(const char* d, uint8_t useMeterType, MeterConfig* meterCo
|
||||
memcpy(str, data->oct.data, data->oct.length);
|
||||
str[data->oct.length] = 0x00;
|
||||
String listId = String(str);
|
||||
if(listId.startsWith("KFM_001")) {
|
||||
if(listId.startsWith(F("KFM_001"))) {
|
||||
this->listId = listId;
|
||||
meterType = AmsTypeKaifa;
|
||||
|
||||
@@ -539,14 +539,14 @@ uint8_t IEC6205675::getString(uint8_t* obis, int matchlength, const char* ptr, c
|
||||
return 0;
|
||||
}
|
||||
|
||||
double IEC6205675::getNumber(uint8_t* obis, int matchlength, const char* ptr) {
|
||||
float IEC6205675::getNumber(uint8_t* obis, int matchlength, const char* ptr) {
|
||||
CosemData* item = findObis(obis, matchlength, ptr);
|
||||
return getNumber(item);
|
||||
}
|
||||
|
||||
double IEC6205675::getNumber(CosemData* item) {
|
||||
float IEC6205675::getNumber(CosemData* item) {
|
||||
if(item != NULL) {
|
||||
double ret = 0.0;
|
||||
float ret = 0.0;
|
||||
char* pos = ((char*) item);
|
||||
switch(item->base.type) {
|
||||
case CosemTypeLongSigned: {
|
||||
|
||||
@@ -21,8 +21,8 @@ private:
|
||||
CosemData* getCosemDataAt(uint8_t index, const char* ptr);
|
||||
CosemData* findObis(uint8_t* obis, int matchlength, const char* ptr);
|
||||
uint8_t getString(uint8_t* obis, int matchlength, const char* ptr, char* target);
|
||||
double getNumber(uint8_t* obis, int matchlength, const char* ptr);
|
||||
double getNumber(CosemData*);
|
||||
float getNumber(uint8_t* obis, int matchlength, const char* ptr);
|
||||
float getNumber(CosemData*);
|
||||
time_t getTimestamp(uint8_t* obis, int matchlength, const char* ptr);
|
||||
|
||||
uint8_t AMS_OBIS_VERSION[4] = { 0, 2, 129, 255 };
|
||||
|
||||
24
src/LNG.cpp
24
src/LNG.cpp
@@ -19,7 +19,7 @@ LNG::LNG(const char* payload, uint8_t useMeterType, MeterConfig* meterConfig, Da
|
||||
for(uint8_t x = 0; x < h->arrayLength-1; x++) {
|
||||
ptr = (uint8_t*) &descriptor[1];
|
||||
descriptor = (LngObisDescriptor*) ptr;
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf("(L&G) OBIS %d.%d.%d with type 0x%02X", descriptor->obis[2], descriptor->obis[3], descriptor->obis[4], *data);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("(L&G) OBIS %d.%d.%d with type 0x%02X\n"), descriptor->obis[2], descriptor->obis[3], descriptor->obis[4], *data);
|
||||
|
||||
CosemData* item = (CosemData*) data;
|
||||
if(descriptor->obis[2] == 1) {
|
||||
@@ -27,22 +27,22 @@ LNG::LNG(const char* payload, uint8_t useMeterType, MeterConfig* meterConfig, Da
|
||||
if(descriptor->obis[4] == 0) {
|
||||
o170 = getNumber(item);
|
||||
listType = listType >= 1 ? listType : 1;
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu", o170);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR(" and value %lu\n"), o170);
|
||||
}
|
||||
} else if(descriptor->obis[3] == 8) {
|
||||
if(descriptor->obis[4] == 0) {
|
||||
o180 = getNumber(item);
|
||||
listType = listType >= 3 ? listType : 3;
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu", o180);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR(" and value %lu\n"), o180);
|
||||
activeImportCounter = o180 / 1000.0;
|
||||
} else if(descriptor->obis[4] == 1) {
|
||||
o181 = getNumber(item);
|
||||
listType = listType >= 3 ? listType : 3;
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu", o181);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR(" and value %lu\n"), o181);
|
||||
} else if(descriptor->obis[4] == 2) {
|
||||
o182 = getNumber(item);
|
||||
listType = listType >= 3 ? listType : 3;
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu", o182);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR(" and value %lu\n"), o182);
|
||||
}
|
||||
}
|
||||
} else if(descriptor->obis[2] == 2) {
|
||||
@@ -50,22 +50,22 @@ LNG::LNG(const char* payload, uint8_t useMeterType, MeterConfig* meterConfig, Da
|
||||
if(descriptor->obis[4] == 0) {
|
||||
o270 = getNumber(item);
|
||||
listType = listType >= 2 ? listType : 2;
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu", o270);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR(" and value %lu\n"), o270);
|
||||
}
|
||||
} else if(descriptor->obis[3] == 8) {
|
||||
if(descriptor->obis[4] == 0) {
|
||||
o280 = getNumber(item);
|
||||
listType = listType >= 3 ? listType : 3;
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu", o280);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR(" and value %lu\n"), o280);
|
||||
activeExportCounter = o280 / 1000.0;
|
||||
} else if(descriptor->obis[4] == 1) {
|
||||
o281 = getNumber(item);
|
||||
listType = listType >= 3 ? listType : 3;
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu", o281);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR(" and value %lu\n"), o281);
|
||||
} else if(descriptor->obis[4] == 2) {
|
||||
o282 = getNumber(item);
|
||||
listType = listType >= 3 ? listType : 3;
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %lu", o282);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR(" and value %lu\n"), o282);
|
||||
}
|
||||
}
|
||||
} else if(descriptor->obis[2] == 96) {
|
||||
@@ -76,19 +76,19 @@ LNG::LNG(const char* payload, uint8_t useMeterType, MeterConfig* meterConfig, Da
|
||||
str[item->oct.length] = '\0';
|
||||
meterId = String(str);
|
||||
listType = listType >= 2 ? listType : 2;
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %s (oct)", str);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR(" and value %s (oct)\n"), str);
|
||||
} else if(descriptor->obis[4] == 1) {
|
||||
char str[item->oct.length+1];
|
||||
memcpy(str, item->oct.data, item->oct.length);
|
||||
str[item->oct.length] = '\0';
|
||||
meterModel = String(str);
|
||||
listType = listType >= 2 ? listType : 2;
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf(" and value %s (oct)", str);
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR(" and value %s (oct)\n"), str);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf("\n");
|
||||
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf_P(PSTR("\n"));
|
||||
|
||||
if(o170 > 0 || o270 > 0) {
|
||||
int32_t sum = o170-o270;
|
||||
|
||||
Reference in New Issue
Block a user