Compare commits

...

18 Commits

Author SHA1 Message Date
Gunnar Skjold
e232b875fa Fixed Aidon timestamp 2022-08-23 21:07:06 +02:00
Gunnar Skjold
f18171fecc Fixed MQTT byte mode 2022-08-23 20:39:47 +02:00
Gunnar Skjold
a3c7a09211 Adding peaks to data.json and MQTT RAW 2022-08-23 20:21:19 +02:00
Gunnar Skjold
a6f3bc3f71 Added version to system json 2022-08-23 19:49:19 +02:00
Gunnar Skjold
4e451c51e1 HW serial fix for S2 2022-08-17 17:33:06 +02:00
Gunnar Skjold
43def1c311 Fixed Pow-P1 profile 2022-08-17 17:32:53 +02:00
Gunnar Skjold
2978116207 Fixed formatting error in HA payload 2022-08-16 11:55:07 +02:00
Gunnar Skjold
998b986604 Adjusted modem sleep to a safer value 2022-08-12 20:48:34 +02:00
Gunnar Skjold
7799431405 Remove unused files 2022-08-12 20:42:13 +02:00
Gunnar Skjold
508c14a671 Fixed modem sleep on S2 and fixed default wifi power 2022-08-12 09:02:04 +02:00
Gunnar Skjold
4a7ef87269 Fixed realtime day calculation 2022-08-10 17:43:51 +02:00
Gunnar Skjold
3a4fc707b0 Show real time production 2022-08-10 10:53:16 +02:00
Gunnar Skjold
5d2e320b07 Fixed export labels on graph 2022-08-10 10:28:31 +02:00
Gunnar Skjold
d12613b91a Trying to fix HA accumulated 2022-08-10 10:01:24 +02:00
Gunnar Skjold
e6a02f34ab USB power warning when upgrading 2022-08-10 09:31:50 +02:00
Gunnar Skjold
0b2ffbfd77 Revert to arduino 2.0.3 because of #298 2022-08-10 09:30:31 +02:00
Gunnar Skjold
cab6c54ed9 Correct Vcc GPIO for Pow-K+ 2022-08-01 12:48:31 +02:00
Gunnar Skjold
313024f273 Support OTA upgrade from ESP8266 2022-08-01 08:17:24 +02:00
22 changed files with 285 additions and 170 deletions

View File

@@ -17,8 +17,10 @@ extra_scripts =
pre:scripts/addversion.py
scripts/makeweb.py
# Sticking to v2.0.3 because of #298
[env:esp32]
platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.4/platform-espressif32-2.0.4.zip
platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.3/platform-espressif32-2.0.3.zip
framework = arduino
board = esp32dev
board_build.f_cpu = 160000000L
@@ -33,8 +35,8 @@ extra_scripts =
# https://github.com/Jason2866/esp32-arduino-lib-builder
[env:esp32s2]
platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.4/platform-espressif32-2.0.4.zip
platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.4
platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.3/platform-espressif32-2.0.3.zip
platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.3
framework = arduino
board = esp32dev
board_build.mcu = esp32s2
@@ -50,7 +52,7 @@ extra_scripts =
scripts/makeweb.py
[env:esp32solo]
platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.4/platform-espressif32-solo1-2.0.4.zip
platform = https://github.com/tasmota/platform-espressif32/releases/download/v.2.0.3/platform-espressif32-solo1-v.2.0.3.zip
framework = arduino
board = esp32dev
board_build.f_cpu = 160000000L

View File

@@ -63,8 +63,10 @@ void AmsConfiguration::clearWifi(WiFiConfig& config) {
uint16_t chipId;
#if defined(ESP32)
chipId = ESP.getEfuseMac();
config.power = 195;
#else
chipId = ESP.getChipId();
config.power = 205;
#endif
strcpy(config.hostname, (String("ams-") + String(chipId, HEX)).c_str());
config.mdns = true;

View File

@@ -32,6 +32,10 @@ ADC_MODE(ADC_VCC);
#endif
#define WDT_TIMEOUT 60
#if defined(CONFIG_IDF_TARGET_ESP32S2)
#include <driver/uart.h>
#endif
#include "version.h"
#include "AmsToMqttBridge.h"
@@ -148,6 +152,8 @@ void setup() {
gpioConfig.hanPin = 3;
gpioConfig.ledPin = 2;
gpioConfig.ledInverted = true;
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
gpioConfig.hanPin = 18;
#elif defined(ESP32)
gpioConfig.hanPin = 16;
gpioConfig.ledPin = 2;
@@ -155,6 +161,7 @@ void setup() {
gpioConfig.tempSensorPin = 14;
#endif
}
delay(1);
config.loadTempSensors();
hw.setup(&gpioConfig, &config);
@@ -616,9 +623,7 @@ void setupHanPort(uint8_t pin, uint32_t baud, uint8_t parityOrdinal, bool invert
hwSerial = &Serial2;
}
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
if(pin == 18) {
hwSerial = &Serial1;
}
hwSerial = &Serial1;
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
#endif
#endif
@@ -651,7 +656,11 @@ void setupHanPort(uint8_t pin, uint32_t baud, uint8_t parityOrdinal, bool invert
break;
}
#if defined(ESP32)
#if defined(CONFIG_IDF_TARGET_ESP32S2)
hwSerial->begin(baud, serialConfig, -1, -1, invert);
hwSerial->setRxBufferSize(768);
uart_set_pin(UART_NUM_1, UART_PIN_NO_CHANGE, pin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
#elif defined(ESP32)
hwSerial->begin(baud, serialConfig, -1, -1, invert);
hwSerial->setRxBufferSize(768);
#else
@@ -826,6 +835,7 @@ bool readHanPort() {
len += hanSerial->readBytes(hanBuffer+len, BUF_SIZE_HAN-len);
if(mqttEnabled && mqtt != NULL && mqttHandler == NULL) {
mqtt->publish(topic.c_str(), toHex(hanBuffer+pos, len));
mqtt->loop();
}
while(hanSerial->available()) hanSerial->read(); // Make sure it is all empty, in case we overflowed buffer above
len = 0;
@@ -842,6 +852,7 @@ bool readHanPort() {
// If MQTT bytestream payload is selected (mqttHandler == NULL), send the payload to MQTT
if(mqttEnabled && mqtt != NULL && mqttHandler == NULL) {
mqtt->publish(topic.c_str(), toHex(hanBuffer+pos, ctx.length));
mqtt->loop();
}
debugV("Using application data:");
@@ -1032,6 +1043,7 @@ void WiFi_connect() {
}
#endif
WiFi.mode(WIFI_STA);
WiFi.setSleep(WIFI_PS_MIN_MODEM);
#if defined(ESP32)
if(wifi.power >= 195)
WiFi.setTxPower(WIFI_POWER_19_5dBm);
@@ -1055,6 +1067,8 @@ void WiFi_connect() {
WiFi.setTxPower(WIFI_POWER_5dBm);
else if(wifi.power >= 20)
WiFi.setTxPower(WIFI_POWER_2dBm);
else
WiFi.setTxPower(WIFI_POWER_MINUS_1dBm);
#elif defined(ESP8266)
WiFi.setOutputPower(wifi.power / 10.0);
#endif
@@ -1163,6 +1177,7 @@ int16_t unwrapData(uint8_t *buf, DataParserContext &context) {
// If MQTT bytestream payload is selected (mqttHandler == NULL), send the payload to MQTT
if(mqttEnabled && mqtt != NULL && mqttHandler == NULL) {
mqtt->publish(topic.c_str(), toHex(buf, curLen));
mqtt->loop();
}
break;
case DATA_TAG_MBUS:
@@ -1170,6 +1185,7 @@ int16_t unwrapData(uint8_t *buf, DataParserContext &context) {
// If MQTT bytestream payload is selected (mqttHandler == NULL), send the payload to MQTT
if(mqttEnabled && mqtt != NULL && mqttHandler == NULL) {
mqtt->publish(topic.c_str(), toHex(buf, curLen));
mqtt->loop();
}
break;
case DATA_TAG_GBT:
@@ -1188,6 +1204,7 @@ int16_t unwrapData(uint8_t *buf, DataParserContext &context) {
debugV("DSMR frame:");
if(mqttEnabled && mqtt != NULL && mqttHandler == NULL) {
mqtt->publish(topic.c_str(), (char*) buf);
mqtt->loop();
}
break;
}

View File

@@ -80,6 +80,7 @@ bool EnergyAccounting::update(AmsData* amsData) {
}
use = 0;
produce = 0;
costHour = 0;
currentHour = local.Hour;
@@ -106,19 +107,24 @@ bool EnergyAccounting::update(AmsData* amsData) {
}
unsigned long ms = this->lastUpdateMillis > amsData->getLastUpdateMillis() ? 0 : amsData->getLastUpdateMillis() - this->lastUpdateMillis;
float kwh = (amsData->getActiveImportPower() * (((float) ms) / 3600000.0)) / 1000.0;
float kwhi = (amsData->getActiveImportPower() * (((float) ms) / 3600000.0)) / 1000.0;
float kwhe = (amsData->getActiveExportPower() * (((float) ms) / 3600000.0)) / 1000.0;
lastUpdateMillis = amsData->getLastUpdateMillis();
if(kwh > 0) {
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf("(EnergyAccounting) Adding %.4f kWh\n", kwh);
use += kwh;
if(kwhi > 0) {
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf("(EnergyAccounting) Adding %.4f kWh import\n", kwhi);
use += kwhi;
if(eapi != NULL && eapi->getValueForHour(0) != ENTSOE_NO_VALUE) {
float price = eapi->getValueForHour(0);
float cost = price * kwh;
float cost = price * kwhi;
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf("(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);
produce += kwhe;
}
if(config != NULL) {
if(debugger->isActive(RemoteDebug::VERBOSE)) debugger->printf("(EnergyAccounting) calculating threshold, currently at %d\n", currentThresholdIdx);
@@ -136,10 +142,10 @@ void EnergyAccounting::calcDayCost() {
if(eapi != NULL && eapi->getValueForHour(0) != ENTSOE_NO_VALUE) {
if(initPrice) costDay = 0;
for(int i = 0; i < local.Hour; i++) {
float price = eapi->getValueForHour(i - local.Hour);
for(int i = 0; i < currentHour; i++) {
float price = eapi->getValueForHour(i - currentHour);
if(price == ENTSOE_NO_VALUE) break;
breakTime(now - ((local.Hour - i) * 3600), utc);
breakTime(now - ((currentHour - i) * 3600), utc);
int16_t wh = ds->getHourImport(utc.Hour);
costDay += price * (wh / 1000.0);
}
@@ -151,23 +157,59 @@ double EnergyAccounting::getUseThisHour() {
return use;
}
double EnergyAccounting::getCostThisHour() {
return costHour;
}
double EnergyAccounting::getUseToday() {
float ret = 0.0;
time_t now = time(nullptr);
if(now < BUILD_EPOCH) return 0;
tmElements_t local, utc;
breakTime(tz->toLocal(now), local);
for(int i = 0; i < local.Hour; i++) {
breakTime(now - ((local.Hour - i) * 3600), utc);
tmElements_t utc;
for(int i = 0; i < currentHour; i++) {
breakTime(now - ((currentHour - i) * 3600), utc);
ret += ds->getHourImport(utc.Hour) / 1000.0;
}
return ret + getUseThisHour();
}
double EnergyAccounting::getUseThisMonth() {
time_t now = time(nullptr);
if(now < BUILD_EPOCH) return 0;
float ret = 0;
for(int i = 0; i < currentDay; i++) {
ret += ds->getDayImport(i) / 1000.0;
}
return ret + getUseToday();
}
double EnergyAccounting::getProducedThisHour() {
return produce;
}
double EnergyAccounting::getProducedToday() {
float ret = 0.0;
time_t now = time(nullptr);
if(now < BUILD_EPOCH) return 0;
tmElements_t utc;
for(int i = 0; i < currentHour; i++) {
breakTime(now - ((currentHour - i) * 3600), utc);
ret += ds->getHourExport(utc.Hour) / 1000.0;
}
return ret + getProducedThisHour();
}
double EnergyAccounting::getProducedThisMonth() {
time_t now = time(nullptr);
if(now < BUILD_EPOCH) return 0;
float ret = 0;
for(int i = 0; i < currentDay; i++) {
ret += ds->getDayExport(i) / 1000.0;
}
return ret + getProducedToday();
}
double EnergyAccounting::getCostThisHour() {
return costHour;
}
double EnergyAccounting::getCostToday() {
return costDay;
}
@@ -176,21 +218,6 @@ double EnergyAccounting::getCostYesterday() {
return data.costYesterday / 10.0;
}
double EnergyAccounting::getUseThisMonth() {
time_t now = time(nullptr);
if(now < BUILD_EPOCH) return 0;
tmElements_t tm;
if(tz != NULL)
breakTime(tz->toLocal(now), tm);
else
breakTime(now, tm);
float ret = 0;
for(int i = 0; i < tm.Day; i++) {
ret += ds->getDayImport(i) / 1000.0;
}
return ret + getUseToday();
}
double EnergyAccounting::getCostThisMonth() {
return data.costThisMonth + getCostToday();
}
@@ -233,6 +260,37 @@ float EnergyAccounting::getMonthMax() {
return maxHour > 0 ? maxHour / count / 100.0 : 0.0;
}
float EnergyAccounting::getPeak(uint8_t num) {
if(num < 1 || num > 5) return 0.0;
uint8_t count = 0;
bool included[5] = { false, false, false, false, false };
while(count < config->hours) {
uint8_t maxIdx = 0;
uint16_t maxVal = 0;
for(uint8_t i = 0; i < 5; i++) {
if(included[i]) continue;
if(data.peaks[i].value > maxVal) {
maxVal = data.peaks[i].value;
maxIdx = i;
}
}
included[maxIdx] = true;
count++;
}
uint8_t pos = 0;
for(uint8_t i = 0; i < 5; i++) {
if(!included[i]) continue;
pos++;
if(pos == num) {
return data.peaks[i].value / 100.0;
}
}
return 0.0;
}
bool EnergyAccounting::load() {
if(!LittleFS.begin()) {
if(debugger->isActive(RemoteDebug::ERROR)) {

View File

@@ -42,16 +42,22 @@ public:
bool save();
double getUseThisHour();
double getCostThisHour();
double getUseToday();
double getUseThisMonth();
double getProducedThisHour();
double getProducedToday();
double getProducedThisMonth();
double getCostThisHour();
double getCostToday();
double getCostYesterday();
double getUseThisMonth();
double getCostThisMonth();
uint16_t getCostLastMonth();
float getMonthMax();
uint8_t getCurrentThreshold();
float getPeak(uint8_t);
EnergyAccountingData getData();
void setData(EnergyAccountingData&);
@@ -66,6 +72,7 @@ private:
Timezone *tz = NULL;
uint8_t currentHour = 0, currentDay = 0, currentThresholdIdx = 0;
double use, costHour, costDay;
double produce;
EnergyAccountingData data = { 0, 0, 0, 0, 0, 0 };
void calcDayCost();

View File

@@ -266,7 +266,9 @@ IEC6205675::IEC6205675(const char* d, uint8_t useMeterType, MeterConfig* meterCo
if(meterTs != NULL) {
AmsOctetTimestamp* amst = (AmsOctetTimestamp*) meterTs;
time_t ts = decodeCosemDateTime(amst->dt);
if(meterType == AmsTypeKamstrup || meterType == AmsTypeAidon) {
if(meterType == AmsTypeAidon) {
meterTimestamp = ts - 3600;
} else if(meterType == AmsTypeKamstrup) {
meterTimestamp = tz.toUTC(ts);
} else {
meterTimestamp = ts;

View File

@@ -24,6 +24,7 @@ bool HomeAssistantMqttHandler::publish(AmsData* data, AmsData* previousState, En
data->getMeterTimestamp()
);
mqtt->publish(topic + "/energy", json);
mqtt->loop();
}
String meterModel = data->getMeterModel();
meterModel.replace("\\", "\\\\");
@@ -202,7 +203,8 @@ bool HomeAssistantMqttHandler::publishSystem(HwTools* hw) {
(uint32_t) (millis64()/1000),
hw->getVcc(),
hw->getWifiRssi(),
hw->getTemperature()
hw->getTemperature(),
VERSION
);
mqtt->publish(topic + "/state", json);
}

View File

@@ -1,4 +1,5 @@
#include "JsonMqttHandler.h"
#include "version.h"
#include "hexutils.h"
#include "Uptime.h"
#include "web/root/json1_json.h"
@@ -27,7 +28,9 @@ bool JsonMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyAccou
ea->getUseThisHour(),
ea->getUseToday(),
ea->getCurrentThreshold(),
ea->getMonthMax()
ea->getMonthMax(),
ea->getProducedThisHour(),
ea->getProducedToday()
);
return mqtt->publish(topic, json);
} else if(data->getListType() == 2) {
@@ -55,7 +58,9 @@ bool JsonMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyAccou
ea->getUseThisHour(),
ea->getUseToday(),
ea->getCurrentThreshold(),
ea->getMonthMax()
ea->getMonthMax(),
ea->getProducedThisHour(),
ea->getProducedToday()
);
return mqtt->publish(topic, json);
} else if(data->getListType() == 3) {
@@ -88,7 +93,9 @@ bool JsonMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyAccou
ea->getUseThisHour(),
ea->getUseToday(),
ea->getCurrentThreshold(),
ea->getMonthMax()
ea->getMonthMax(),
ea->getProducedThisHour(),
ea->getProducedToday()
);
return mqtt->publish(topic, json);
} else if(data->getListType() == 4) {
@@ -125,7 +132,9 @@ bool JsonMqttHandler::publish(AmsData* data, AmsData* previousState, EnergyAccou
ea->getUseThisHour(),
ea->getUseToday(),
ea->getCurrentThreshold(),
ea->getMonthMax()
ea->getMonthMax(),
ea->getProducedThisHour(),
ea->getProducedToday()
);
return mqtt->publish(topic, json);
}
@@ -272,7 +281,8 @@ bool JsonMqttHandler::publishSystem(HwTools* hw) {
(uint32_t) (millis64()/1000),
hw->getVcc(),
hw->getWifiRssi(),
hw->getTemperature()
hw->getTemperature(),
VERSION
);
init = mqtt->publish(topic, json);
return init;

View File

@@ -74,8 +74,13 @@ bool RawMqttHandler::publish(AmsData* data, AmsData* meterState, EnergyAccountin
}
mqtt->publish(topic + "/realtime/import/hour", String(ea->getUseThisHour(), 3));
mqtt->publish(topic + "/realtime/import/day", String(ea->getUseToday(), 2));
for(uint8_t i = 1; i <= ea->getConfig()->hours; i++) {
mqtt->publish(topic + "/realtime/import/peak/" + String(i, 10), String(ea->getPeak(i), 10), true, 0);
}
mqtt->publish(topic + "/realtime/import/threshold", String(ea->getCurrentThreshold(), 10), true, 0);
mqtt->publish(topic + "/realtime/import/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));
return true;
}

View File

@@ -591,9 +591,9 @@ void AmsWebServer::configThresholdsHtml() {
String html = String((const __FlashStringHelper*) THRESHOLDS_HTML);
for(int i = 0; i < 9; i++) {
html.replace("{t" + String(i) + "}", String(config->thresholds[i]));
html.replace("{t" + String(i) + "}", String(config->thresholds[i], 10));
}
html.replace("{h}", String(config->hours));
html.replace("{h}", String(config->hours, 10));
server.setContentLength(html.length() + HEAD_HTML_LEN + FOOT_HTML_LEN);
server.send_P(200, MIME_HTML, HEAD_HTML);
@@ -708,6 +708,12 @@ void AmsWebServer::dataJson() {
if(eapi != NULL && strlen(eapi->getToken()) > 0)
price = eapi->getValueForHour(0);
String peaks = "";
for(uint8_t i = 1; i <= ea->getConfig()->hours; i++) {
if(!peaks.isEmpty()) peaks += ",";
peaks += String(ea->getPeak(i));
}
snprintf_P(buf, BufferSize, DATA_JSON,
maxPwr == 0 ? meterState->isThreePhase() ? 20000 : 10000 : maxPwr,
meterConfig->productionCapacity,
@@ -744,13 +750,17 @@ void AmsWebServer::dataJson() {
meterState->getMeterType(),
meterConfig->distributionSystem,
ea->getMonthMax(),
peaks.c_str(),
ea->getCurrentThreshold(),
ea->getUseThisHour(),
ea->getCostThisHour(),
ea->getProducedThisHour(),
ea->getUseToday(),
ea->getCostToday(),
ea->getProducedToday(),
ea->getUseThisMonth(),
ea->getCostThisMonth(),
ea->getProducedThisMonth(),
(uint32_t) time(nullptr)
);
@@ -1036,12 +1046,12 @@ void AmsWebServer::handleSetup() {
gpioConfig->ledPinRed = 13;
gpioConfig->ledPinGreen = 14;
gpioConfig->ledRgbInverted = true;
gpioConfig->vccPin = 35;
gpioConfig->vccPin = 10;
gpioConfig->vccResistorGnd = 22;
gpioConfig->vccResistorVcc = 33;
break;
case 6: // Pow-P1
gpioConfig->hanPin = 18;
gpioConfig->hanPin = 16;
gpioConfig->apPin = 0;
gpioConfig->ledPinRed = 13;
gpioConfig->ledPinGreen = 14;
@@ -1659,7 +1669,7 @@ void AmsWebServer::firmwareUpload() {
}
uploadFile(FILE_FIRMWARE);
if(upload.status == UPLOAD_FILE_END) {
performRestart = true;
rebootForUpgrade = true;
server.sendHeader("Location","/restart-wait");
server.send(303);
}
@@ -1672,102 +1682,9 @@ void AmsWebServer::firmwareDownload() {
return;
printD("Firmware download URL triggered");
if(server.hasArg("version")) {
String version = server.arg("version");
String versionStripped = version.substring(1);
printI("Downloading firmware...");
HTTPClient httpClient;
httpClient.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
httpClient.setReuse(false);
httpClient.setTimeout(60000);
httpClient.setUserAgent("ams2mqtt/" + String(VERSION));
#if defined(ESP8266)
WiFiClient client;
String url = "http://ams2mqtt.no23.cc/hub/firmware/update";
server.sendHeader("Location","/");
server.send(303);
t_httpUpdate_return ret = ESPhttpUpdate.update(client, url, VERSION);
switch(ret) {
case HTTP_UPDATE_FAILED:
printE("[update] Update failed.");
break;
case HTTP_UPDATE_NO_UPDATES:
printI("[update] Update no Update.");
break;
case HTTP_UPDATE_OK:
printI("[update] Update ok.");
break;
}
return;
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
httpClient.setConnectTimeout(60000);
String url = "https://github.com/gskjold/AmsToMqttBridge/releases/download/" + version + "/ams2mqtt-esp32s2-" + versionStripped + ".bin";
httpClient.addHeader("Referer", "https://github.com/gskjold/AmsToMqttBridge/releases");
#elif defined(ESP32)
httpClient.setConnectTimeout(60000);
#if defined(CONFIG_FREERTOS_UNICORE)
String url = "https://github.com/gskjold/AmsToMqttBridge/releases/download/" + version + "/ams2mqtt-esp32solo-" + versionStripped + ".bin";
#else
String url = "https://github.com/gskjold/AmsToMqttBridge/releases/download/" + version + "/ams2mqtt-esp32-" + versionStripped + ".bin";
#endif
httpClient.addHeader("Referer", "https://github.com/gskjold/AmsToMqttBridge/releases");
#endif
printD("Downloading from URL:");
printD(url);
#if defined(ESP8266)
if(httpClient.begin(client, url)) {
#elif defined(ESP32)
if(httpClient.begin(url)) {
#endif
printD("HTTP client setup successful");
int status = httpClient.GET();
if(status == HTTP_CODE_OK) {
printD("Received OK from server");
if(LittleFS.begin()) {
#if defined(ESP32)
esp_task_wdt_delete(NULL);
esp_task_wdt_deinit();
#elif defined(ESP8266)
ESP.wdtDisable();
#endif
printI("Downloading firmware to LittleFS");
file = LittleFS.open(FILE_FIRMWARE, "w");
int len = httpClient.writeToStream(&file);
file.close();
LittleFS.end();
performRestart = true;
server.sendHeader("Location","/restart-wait");
server.send(303);
} else {
printE("Unable to open LittleFS for writing");
server.sendHeader("Location","/");
server.send(303);
}
} else {
printE("Communication error: ");
debugger->printf("%d\n", status);
printE(httpClient.errorToString(status));
printD(httpClient.getString());
server.sendHeader("Location","/");
server.send(303);
}
} else {
printE("Unable to configure HTTP client");
server.sendHeader("Location","/");
server.send(303);
}
httpClient.end();
} else {
printI("No firmware version specified...");
server.sendHeader("Location","/");
server.send(303);
}
performUpgrade = true;
server.sendHeader("Location","/restart-wait");
server.send(303);
}
void AmsWebServer::restartHtml() {
@@ -1817,6 +1734,14 @@ void AmsWebServer::restartWaitHtml() {
}
html.replace("${hostname}", wifi.hostname);
if(performUpgrade || rebootForUpgrade) {
html.replace("{rs}", "d-none");
html.replace("{us}", "");
} else {
html.replace("{rs}", "");
html.replace("{us}", "d-none");
}
server.sendHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE);
server.sendHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE);
server.sendHeader(HEADER_EXPIRES, EXPIRES_OFF);
@@ -1825,7 +1750,7 @@ void AmsWebServer::restartWaitHtml() {
server.send(200, MIME_HTML, html);
yield();
if(performRestart) {
if(performRestart || rebootForUpgrade) {
if(ds != NULL) {
ds->save();
}
@@ -1837,6 +1762,40 @@ void AmsWebServer::restartWaitHtml() {
ESP.restart();
#endif
performRestart = false;
} else if(performUpgrade) {
WiFiClient client;
String url = "http://ams2mqtt.rewiredinvent.no/hub/firmware/update";
#if defined(ESP8266)
String chipType = "esp8266";
#elif defined(CONFIG_IDF_TARGET_ESP32S2)
String chipType = "esp32s2";
#elif defined(ESP32)
#if defined(CONFIG_FREERTOS_UNICORE)
String chipType = "esp32solo";
#else
String chipType = "esp32";
#endif
#endif
#if defined(ESP8266)
t_httpUpdate_return ret = ESPhttpUpdate.update(client, url, VERSION);
#elif defined(ESP32)
HTTPUpdate httpUpdate;
HTTPUpdateResult ret = httpUpdate.update(client, url, String(VERSION) + "-" + chipType);
#endif
switch(ret) {
case HTTP_UPDATE_FAILED:
printE("Update failed");
break;
case HTTP_UPDATE_NO_UPDATES:
printI("No Update");
break;
case HTTP_UPDATE_OK:
printI("Update OK");
break;
}
performUpgrade = false;
}
}

View File

@@ -24,6 +24,7 @@
#include <WiFi.h>
#include <WebServer.h>
#include <HTTPClient.h>
#include <HTTPUpdate.h>
#else
#warning "Unsupported board type"
#endif
@@ -58,6 +59,8 @@ private:
bool uploading = false;
File file;
bool performRestart = false;
bool performUpgrade = false;
bool rebootForUpgrade = false;
static const uint16_t BufferSize = 2048;
char* buf;

View File

@@ -478,7 +478,7 @@ var drawDay = function() {
timeout: 30000,
dataType: 'json',
}).done(function(json) {
data = [['Hour', 'Import', { role: 'style' }, { role: 'annotation' }, 'Export', { role: 'style' }]];
data = [['Hour', 'Import', { role: 'style' }, { role: 'annotation' }, 'Export', { role: 'style' }, { role: 'annotation' }]];
var r = 1;
var hour = moment.utc().hours();
var offset = moment().utcOffset()/60;
@@ -486,13 +486,13 @@ var drawDay = function() {
for(var i = hour; i<24; i++) {
var imp = json["i"+zeropad(i)];
var exp = json["e"+zeropad(i)];
data[r++] = [zeropad((i+offset)%24), imp, "opacity: 0.9;", exp == 0 ? imp.toFixed(1) : imp.toFixed(1) + '\n' + -exp.toFixed(1), exp == 0 ? 0 : -exp, "opacity: 0.9;"];
data[r++] = [zeropad((i+offset)%24), imp, "opacity: 0.9;", imp == 0 ? "" : imp.toFixed(1), exp == 0 ? 0 : -exp, "opacity: 0.9;", exp == 0 ? "" : -exp.toFixed(1)];
min = Math.min(0, -exp);
};
for(var i = 0; i < hour; i++) {
var imp = json["i"+zeropad(i)];
var exp = json["e"+zeropad(i)];
data[r++] = [zeropad((i+offset)%24), imp, "opacity: 0.9;", exp == 0 ? imp.toFixed(1) : imp.toFixed(1) + '\n' + -exp.toFixed(1), exp == 0 ? 0 : -exp, "opacity: 0.9;"];
data[r++] = [zeropad((i+offset)%24), imp, "opacity: 0.9;", imp == 0 ? "" : imp.toFixed(1), exp == 0 ? 0 : -exp, "opacity: 0.9;", exp == 0 ? "" : -exp.toFixed(1)];
min = Math.min(0, -exp);
};
ea = google.visualization.arrayToDataTable(data);
@@ -511,7 +511,7 @@ var drawMonth = function() {
timeout: 30000,
dataType: 'json',
}).done(function(json) {
data = [['Hour', 'Import', { role: 'style' }, { role: 'annotation' }, 'Export', { role: 'style' }]];
data = [['Hour', 'Import', { role: 'style' }, { role: 'annotation' }, 'Export', { role: 'style' }, { role: 'annotation' }]];
var r = 1;
var day = moment().date();
var eom = moment().subtract(1, 'months').endOf('month').date();
@@ -519,13 +519,13 @@ var drawMonth = function() {
for(var i = day; i<=eom; i++) {
var imp = json["i"+zeropad(i)];
var exp = json["e"+zeropad(i)];
data[r++] = [zeropad(i), imp, "opacity: 0.9;", exp == 0 ? imp.toFixed(0) : imp.toFixed(0) + '\n' + -exp.toFixed(0), exp == 0 ? 0 : -exp, "opacity: 0.9;"];
data[r++] = [zeropad(i), imp, "opacity: 0.9;", imp == 0 ? "" : imp.toFixed(0), exp == 0 ? 0 : -exp, "opacity: 0.9;", exp == 0 ? "" : -exp.toFixed(0)];
min = Math.min(0, -exp);
}
for(var i = 1; i < day; i++) {
var imp = json["i"+zeropad(i)];
var exp = json["e"+zeropad(i)];
data[r++] = [zeropad(i), imp, "opacity: 0.9;", exp == 0 ? imp.toFixed(0) : imp.toFixed(0) + '\n' + -exp.toFixed(0), exp == 0 ? 0 : -exp, "opacity: 0.9;"];
data[r++] = [zeropad(i), imp, "opacity: 0.9;", imp == 0 ? "" : imp.toFixed(0), exp == 0 ? 0 : -exp, "opacity: 0.9;", exp == 0 ? "" : -exp.toFixed(0)];
min = Math.min(0, -exp);
}
ma = google.visualization.arrayToDataTable(data);
@@ -790,6 +790,12 @@ var fetch = function() {
if(currency) {
$('.sp').show();
}
if(om > 0) {
$('.se').removeClass('d-none');
$('#eache').html(json.ea.h.p.toFixed(2));
$('#eacde').html(json.ea.d.p.toFixed(1));
$('#eacme').html(json.ea.m.p.toFixed(0));
}
}
if(json.me) {
@@ -878,7 +884,7 @@ var fetch = function() {
var upgrade = function() {
if(nextVersion) {
if(confirm("Are you sure you want to perform upgrade to " + nextVersion.tag_name + "?")) {
if(confirm("WARNING: Please keep USB power connected while upgrading. Are you sure you want to perform upgrade to " + nextVersion.tag_name + "?")) {
$('#loading-indicator').show();
window.location.href="/upgrade?version=" + nextVersion.tag_name;
}

View File

@@ -35,18 +35,22 @@
"ds" : %d,
"ea" : {
"x" : %.1f,
"p" : [ %s ],
"t" : %d,
"h" : {
"u" : %.2f,
"c" : %.2f
"c" : %.2f,
"p" : %.2f
},
"d" : {
"u" : %.2f,
"c" : %.2f
"c" : %.2f,
"p" : %.2f
},
"m" : {
"u" : %.2f,
"c" : %.2f
"c" : %.2f,
"p" : %.2f
}
},
"c" : %lu

View File

@@ -1,6 +1,5 @@
<div id="newVersion" class="alert alert-info d-none">New version <span id="newVersionTag"></span>!
<a id="newVersionUrl" href="#" target="_blank">view</a>
<span class="d-none ssl-capable"> or <a href="javascript:upgrade();">upgrade</a></span>
<a id="newVersionUrl" href="#" target="_blank">view</a> or <a href="javascript:upgrade();">click here to upgrade</a>
</div>
</main>

View File

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

View File

@@ -113,7 +113,7 @@
<div class="col-xl-12 mb-3">
<div class="bg-white rounded shadow pt-3 pb-3" style="font-size: 14px;">
<strong class="mr-3 ml-3">Real time calculation</strong><br/>
<strong class="mr-3 ml-3">Real time consumption</strong><br/>
<div class="row">
<div class="col-lg-3 col-sm-6">
<div class="mr-3 ml-3 d-flex">
@@ -151,6 +151,35 @@
</div>
</div>
</div>
<strong class="mr-3 ml-3 se d-none">Real time production</strong><br/>
<div class="row se d-none">
<div class="col-lg-3 col-sm-6">
<div class="mr-3 ml-3 d-flex">
<div>Hour</div>
<div class="flex-fill text-right">
<span id="eache"></span> kWh
</div>
</div>
</div>
<div class="col-lg-3 col-sm-6">
<div class="mr-3 ml-3 d-flex">
<div>Day</div>
<div class="flex-fill text-right">
<span id="eacde"></span> kWh
</div>
</div>
</div>
<div class="col-lg-3 col-sm-6">
<div class="mr-3 ml-3 d-flex">
<div>Month</div>
<div class="flex-fill text-right">
<span id="eacme"></span> kWh
</div>
</div>
</div>
<div class="col-lg-3 col-sm-6"></div>
</div>
</div>
</div>

View File

@@ -13,6 +13,8 @@
"h" : %.2f,
"d" : %.1f,
"t" : %d,
"x" : %.2f
"x" : %.2f,
"he" : %.2f,
"de" : %.1f
}
}

View File

@@ -25,6 +25,8 @@
"h" : %.2f,
"d" : %.1f,
"t" : %d,
"x" : %.2f
"x" : %.2f,
"he" : %.2f,
"de" : %.1f
}
}

View File

@@ -30,6 +30,8 @@
"h" : %.2f,
"d" : %.1f,
"t" : %d,
"x" : %.2f
"x" : %.2f,
"he" : %.2f,
"de" : %.1f
}
}

View File

@@ -34,6 +34,8 @@
"h" : %.2f,
"d" : %.1f,
"t" : %d,
"x" : %.2f
"x" : %.2f,
"he" : %.2f,
"de" : %.1f
}
}

View File

@@ -4,5 +4,6 @@
"up" : %d,
"vcc" : %.3f,
"rssi": %d,
"temp": %.2f
"temp": %.2f,
"version": "%s"
}

View File

@@ -18,9 +18,10 @@
</li>
</ul>
</header>
<div class="my-3 p-3 bg-white rounded shadow">
<div class="my-3 p-3 bg-white rounded shadow {rs}">
Device is rebooting. You will be redirected to the main page when it is available again.
</div>
<div class="alert alert-warning shadow {us}">Firmware upgrade in progress, DO NOT disconnect power from the device. You will be redirected to the main page when firmware upgrade is complete.</div>
</main>
<script>
var tries = 0;