mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-03-12 21:44:21 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2978116207 | ||
|
|
998b986604 | ||
|
|
7799431405 | ||
|
|
508c14a671 | ||
|
|
4a7ef87269 | ||
|
|
3a4fc707b0 | ||
|
|
5d2e320b07 | ||
|
|
d12613b91a | ||
|
|
e6a02f34ab | ||
|
|
0b2ffbfd77 | ||
|
|
cab6c54ed9 | ||
|
|
313024f273 | ||
|
|
91fc078c5e | ||
|
|
5b9d44a3e9 |
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -148,6 +148,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 +157,7 @@ void setup() {
|
||||
gpioConfig.tempSensorPin = 14;
|
||||
#endif
|
||||
}
|
||||
|
||||
delay(1);
|
||||
config.loadTempSensors();
|
||||
hw.setup(&gpioConfig, &config);
|
||||
@@ -1032,6 +1035,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 +1059,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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
@@ -251,6 +278,7 @@ bool EnergyAccounting::load() {
|
||||
if(buf[0] == 4) {
|
||||
EnergyAccountingData* data = (EnergyAccountingData*) buf;
|
||||
memcpy(&this->data, data, sizeof(this->data));
|
||||
ret = true;
|
||||
} else if(buf[0] == 3) {
|
||||
EnergyAccountingData* data = (EnergyAccountingData*) buf;
|
||||
this->data = { 4, data->month,
|
||||
|
||||
@@ -42,11 +42,16 @@ 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();
|
||||
|
||||
@@ -66,6 +71,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();
|
||||
|
||||
@@ -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("\\", "\\\\");
|
||||
|
||||
@@ -27,7 +27,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 +57,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 +92,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 +131,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);
|
||||
}
|
||||
|
||||
@@ -76,6 +76,8 @@ bool RawMqttHandler::publish(AmsData* data, AmsData* meterState, EnergyAccountin
|
||||
mqtt->publish(topic + "/realtime/import/day", String(ea->getUseToday(), 2));
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -747,10 +747,13 @@ void AmsWebServer::dataJson() {
|
||||
ea->getCurrentThreshold(),
|
||||
ea->getUseThisHour(),
|
||||
ea->getCostThisHour(),
|
||||
ea->getProducedThisHour(),
|
||||
ea->getUseToday(),
|
||||
ea->getCostToday(),
|
||||
ea->getProducedToday(),
|
||||
ea->getUseThisMonth(),
|
||||
ea->getCostThisMonth(),
|
||||
ea->getProducedThisMonth(),
|
||||
(uint32_t) time(nullptr)
|
||||
);
|
||||
|
||||
@@ -927,42 +930,42 @@ void AmsWebServer::energyPriceJson() {
|
||||
|
||||
snprintf_P(buf, BufferSize, ENERGYPRICE_JSON,
|
||||
eapi == NULL ? "" : eapi->getCurrency(),
|
||||
prices[0] == ENTSOE_NO_VALUE ? "null" : String(prices[0], 2).c_str(),
|
||||
prices[1] == ENTSOE_NO_VALUE ? "null" : String(prices[1], 2).c_str(),
|
||||
prices[2] == ENTSOE_NO_VALUE ? "null" : String(prices[2], 2).c_str(),
|
||||
prices[3] == ENTSOE_NO_VALUE ? "null" : String(prices[3], 2).c_str(),
|
||||
prices[4] == ENTSOE_NO_VALUE ? "null" : String(prices[4], 2).c_str(),
|
||||
prices[5] == ENTSOE_NO_VALUE ? "null" : String(prices[5], 2).c_str(),
|
||||
prices[6] == ENTSOE_NO_VALUE ? "null" : String(prices[6], 2).c_str(),
|
||||
prices[7] == ENTSOE_NO_VALUE ? "null" : String(prices[7], 2).c_str(),
|
||||
prices[8] == ENTSOE_NO_VALUE ? "null" : String(prices[8], 2).c_str(),
|
||||
prices[9] == ENTSOE_NO_VALUE ? "null" : String(prices[9], 2).c_str(),
|
||||
prices[10] == ENTSOE_NO_VALUE ? "null" : String(prices[10], 2).c_str(),
|
||||
prices[11] == ENTSOE_NO_VALUE ? "null" : String(prices[11], 2).c_str(),
|
||||
prices[12] == ENTSOE_NO_VALUE ? "null" : String(prices[12], 2).c_str(),
|
||||
prices[13] == ENTSOE_NO_VALUE ? "null" : String(prices[13], 2).c_str(),
|
||||
prices[14] == ENTSOE_NO_VALUE ? "null" : String(prices[14], 2).c_str(),
|
||||
prices[15] == ENTSOE_NO_VALUE ? "null" : String(prices[15], 2).c_str(),
|
||||
prices[16] == ENTSOE_NO_VALUE ? "null" : String(prices[16], 2).c_str(),
|
||||
prices[17] == ENTSOE_NO_VALUE ? "null" : String(prices[17], 2).c_str(),
|
||||
prices[18] == ENTSOE_NO_VALUE ? "null" : String(prices[18], 2).c_str(),
|
||||
prices[19] == ENTSOE_NO_VALUE ? "null" : String(prices[19], 2).c_str(),
|
||||
prices[20] == ENTSOE_NO_VALUE ? "null" : String(prices[20], 2).c_str(),
|
||||
prices[21] == ENTSOE_NO_VALUE ? "null" : String(prices[21], 2).c_str(),
|
||||
prices[22] == ENTSOE_NO_VALUE ? "null" : String(prices[22], 2).c_str(),
|
||||
prices[23] == ENTSOE_NO_VALUE ? "null" : String(prices[23], 2).c_str(),
|
||||
prices[24] == ENTSOE_NO_VALUE ? "null" : String(prices[24], 2).c_str(),
|
||||
prices[25] == ENTSOE_NO_VALUE ? "null" : String(prices[25], 2).c_str(),
|
||||
prices[26] == ENTSOE_NO_VALUE ? "null" : String(prices[26], 2).c_str(),
|
||||
prices[27] == ENTSOE_NO_VALUE ? "null" : String(prices[27], 2).c_str(),
|
||||
prices[28] == ENTSOE_NO_VALUE ? "null" : String(prices[28], 2).c_str(),
|
||||
prices[29] == ENTSOE_NO_VALUE ? "null" : String(prices[29], 2).c_str(),
|
||||
prices[30] == ENTSOE_NO_VALUE ? "null" : String(prices[30], 2).c_str(),
|
||||
prices[31] == ENTSOE_NO_VALUE ? "null" : String(prices[31], 2).c_str(),
|
||||
prices[32] == ENTSOE_NO_VALUE ? "null" : String(prices[32], 2).c_str(),
|
||||
prices[33] == ENTSOE_NO_VALUE ? "null" : String(prices[33], 2).c_str(),
|
||||
prices[34] == ENTSOE_NO_VALUE ? "null" : String(prices[34], 2).c_str(),
|
||||
prices[35] == ENTSOE_NO_VALUE ? "null" : String(prices[35], 2).c_str()
|
||||
prices[0] == ENTSOE_NO_VALUE ? "null" : String(prices[0], 4).c_str(),
|
||||
prices[1] == ENTSOE_NO_VALUE ? "null" : String(prices[1], 4).c_str(),
|
||||
prices[2] == ENTSOE_NO_VALUE ? "null" : String(prices[2], 4).c_str(),
|
||||
prices[3] == ENTSOE_NO_VALUE ? "null" : String(prices[3], 4).c_str(),
|
||||
prices[4] == ENTSOE_NO_VALUE ? "null" : String(prices[4], 4).c_str(),
|
||||
prices[5] == ENTSOE_NO_VALUE ? "null" : String(prices[5], 4).c_str(),
|
||||
prices[6] == ENTSOE_NO_VALUE ? "null" : String(prices[6], 4).c_str(),
|
||||
prices[7] == ENTSOE_NO_VALUE ? "null" : String(prices[7], 4).c_str(),
|
||||
prices[8] == ENTSOE_NO_VALUE ? "null" : String(prices[8], 4).c_str(),
|
||||
prices[9] == ENTSOE_NO_VALUE ? "null" : String(prices[9], 4).c_str(),
|
||||
prices[10] == ENTSOE_NO_VALUE ? "null" : String(prices[10], 4).c_str(),
|
||||
prices[11] == ENTSOE_NO_VALUE ? "null" : String(prices[11], 4).c_str(),
|
||||
prices[12] == ENTSOE_NO_VALUE ? "null" : String(prices[12], 4).c_str(),
|
||||
prices[13] == ENTSOE_NO_VALUE ? "null" : String(prices[13], 4).c_str(),
|
||||
prices[14] == ENTSOE_NO_VALUE ? "null" : String(prices[14], 4).c_str(),
|
||||
prices[15] == ENTSOE_NO_VALUE ? "null" : String(prices[15], 4).c_str(),
|
||||
prices[16] == ENTSOE_NO_VALUE ? "null" : String(prices[16], 4).c_str(),
|
||||
prices[17] == ENTSOE_NO_VALUE ? "null" : String(prices[17], 4).c_str(),
|
||||
prices[18] == ENTSOE_NO_VALUE ? "null" : String(prices[18], 4).c_str(),
|
||||
prices[19] == ENTSOE_NO_VALUE ? "null" : String(prices[19], 4).c_str(),
|
||||
prices[20] == ENTSOE_NO_VALUE ? "null" : String(prices[20], 4).c_str(),
|
||||
prices[21] == ENTSOE_NO_VALUE ? "null" : String(prices[21], 4).c_str(),
|
||||
prices[22] == ENTSOE_NO_VALUE ? "null" : String(prices[22], 4).c_str(),
|
||||
prices[23] == ENTSOE_NO_VALUE ? "null" : String(prices[23], 4).c_str(),
|
||||
prices[24] == ENTSOE_NO_VALUE ? "null" : String(prices[24], 4).c_str(),
|
||||
prices[25] == ENTSOE_NO_VALUE ? "null" : String(prices[25], 4).c_str(),
|
||||
prices[26] == ENTSOE_NO_VALUE ? "null" : String(prices[26], 4).c_str(),
|
||||
prices[27] == ENTSOE_NO_VALUE ? "null" : String(prices[27], 4).c_str(),
|
||||
prices[28] == ENTSOE_NO_VALUE ? "null" : String(prices[28], 4).c_str(),
|
||||
prices[29] == ENTSOE_NO_VALUE ? "null" : String(prices[29], 4).c_str(),
|
||||
prices[30] == ENTSOE_NO_VALUE ? "null" : String(prices[30], 4).c_str(),
|
||||
prices[31] == ENTSOE_NO_VALUE ? "null" : String(prices[31], 4).c_str(),
|
||||
prices[32] == ENTSOE_NO_VALUE ? "null" : String(prices[32], 4).c_str(),
|
||||
prices[33] == ENTSOE_NO_VALUE ? "null" : String(prices[33], 4).c_str(),
|
||||
prices[34] == ENTSOE_NO_VALUE ? "null" : String(prices[34], 4).c_str(),
|
||||
prices[35] == ENTSOE_NO_VALUE ? "null" : String(prices[35], 4).c_str()
|
||||
);
|
||||
|
||||
server.sendHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE);
|
||||
@@ -1036,7 +1039,7 @@ 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;
|
||||
@@ -1659,7 +1662,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,109 +1675,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/releases/download/" + version + "/ams2mqtt-esp8266-" + versionStripped + ".bin";
|
||||
/*
|
||||
t_httpUpdate_return ret = ESPhttpUpdate.update(client, url, VERSION);
|
||||
switch(ret) {
|
||||
case HTTP_UPDATE_FAILED:
|
||||
printE("[update] Update failed.");
|
||||
server.sendHeader("Location","/");
|
||||
server.send(303);
|
||||
break;
|
||||
case HTTP_UPDATE_NO_UPDATES:
|
||||
printI("[update] Update no Update.");
|
||||
server.sendHeader("Location","/");
|
||||
server.send(303);
|
||||
break;
|
||||
case HTTP_UPDATE_OK:
|
||||
printI("[update] Update ok."); // may not be called since we reboot the ESP
|
||||
performRestart = true;
|
||||
server.sendHeader("Location","/restart-wait");
|
||||
server.send(303);
|
||||
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() {
|
||||
@@ -1824,6 +1727,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);
|
||||
@@ -1832,7 +1743,7 @@ void AmsWebServer::restartWaitHtml() {
|
||||
server.send(200, MIME_HTML, html);
|
||||
|
||||
yield();
|
||||
if(performRestart) {
|
||||
if(performRestart || rebootForUpgrade) {
|
||||
if(ds != NULL) {
|
||||
ds->save();
|
||||
}
|
||||
@@ -1844,6 +1755,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -38,15 +38,18 @@
|
||||
"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
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -3,5 +3,5 @@
|
||||
"tPO" : %.2f,
|
||||
"tQI" : %.2f,
|
||||
"tQO" : %.2f,
|
||||
"rtc" : %llu
|
||||
"rtc" : %lu
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
"h" : %.2f,
|
||||
"d" : %.1f,
|
||||
"t" : %d,
|
||||
"x" : %.2f
|
||||
"x" : %.2f,
|
||||
"he" : %.2f,
|
||||
"de" : %.1f
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
"h" : %.2f,
|
||||
"d" : %.1f,
|
||||
"t" : %d,
|
||||
"x" : %.2f
|
||||
"x" : %.2f,
|
||||
"he" : %.2f,
|
||||
"de" : %.1f
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,8 @@
|
||||
"h" : %.2f,
|
||||
"d" : %.1f,
|
||||
"t" : %d,
|
||||
"x" : %.2f
|
||||
"x" : %.2f,
|
||||
"he" : %.2f,
|
||||
"de" : %.1f
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
"h" : %.2f,
|
||||
"d" : %.1f,
|
||||
"t" : %d,
|
||||
"x" : %.2f
|
||||
"x" : %.2f,
|
||||
"he" : %.2f,
|
||||
"de" : %.1f
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user