- Below are some stuff we need to know
+ Various permissions we need to do stuff:
diff --git a/lib/SvelteUi/app/src/lib/FileUploadComponent.svelte b/lib/SvelteUi/app/src/lib/FileUploadComponent.svelte
index 46c4dc78..eee6c877 100644
--- a/lib/SvelteUi/app/src/lib/FileUploadComponent.svelte
+++ b/lib/SvelteUi/app/src/lib/FileUploadComponent.svelte
@@ -1,14 +1,17 @@
Upload {title}
Select a suitable file and click upload
-
+
diff --git a/lib/SvelteUi/app/src/lib/Header.svelte b/lib/SvelteUi/app/src/lib/Header.svelte
index c6265dd1..bb41bf27 100644
--- a/lib/SvelteUi/app/src/lib/Header.svelte
+++ b/lib/SvelteUi/app/src/lib/Header.svelte
@@ -2,7 +2,7 @@
import { Link } from "svelte-navigator";
import { sysinfoStore, getGitHubReleases, gitHubReleaseStore } from './DataStores.js';
import { upgrade, getNextVersion } from './UpgradeHelper';
- import { boardtype } from './Helpers.js';
+ import { boardtype, hanError, mqttError } from './Helpers.js';
import GitHubLogo from './../assets/github.svg';
import Uptime from "./Uptime.svelte";
import Badge from './Badge.svelte';
@@ -13,7 +13,7 @@
import DownloadIcon from "./DownloadIcon.svelte";
export let data = {}
- export let sysinfo = {}
+ let sysinfo = {}
let nextVersion = {};
@@ -28,11 +28,16 @@
}
}
}
+ sysinfoStore.subscribe(update => {
+ sysinfo = update;
+ if(update.fwconsent === 1) {
+ getGitHubReleases();
+ }
+ });
gitHubReleaseStore.subscribe(releases => {
nextVersion = getNextVersion(sysinfo.version, releases);
});
- getGitHubReleases();
-
+
2.0 ? data.v.toFixed(2)+"V" : "ESP"} color={sysinfo.booting ? 'yellow' : data.em === 1 ? 'green' : data.em === 2 ? 'yellow' : data.em === 3 ? 'red' : 'gray'}/>
-
+ {#if data.he < 0}
+
{ 'HAN error: ' + hanError(data.he) }
+ {/if}
+ {#if data.me < 0}
+
{ 'MQTT error: ' + mqttError(data.me) }
+ {/if}
+
diff --git a/lib/SvelteUi/app/src/lib/Helpers.js b/lib/SvelteUi/app/src/lib/Helpers.js
index 14ce27c6..2cb3ea50 100644
--- a/lib/SvelteUi/app/src/lib/Helpers.js
+++ b/lib/SvelteUi/app/src/lib/Helpers.js
@@ -91,3 +91,33 @@ export function boardtype(c, b) {
return "Generic ESP8266";
}
}
+
+export function hanError(err) {
+ switch(err) {
+ case -1: return "Parse error";
+ case -2: return "Incomplete data received";
+ case -3: return "Payload boundry flag missing";
+ case -4: return "Header checksum error";
+ case -5: return "Footer checksum error";
+ case -9: return "Unknown data received, check meter config";
+ case -41: return "Frame length not equal";
+ case -51: return "Authentication failed";
+ case -52: return "Decryption failed";
+ case -53: return "Encryption key invalid";
+ }
+ if(err < 0) return "Unspecified error "+err;
+ return "";
+}
+
+export function mqttError(err) {
+ switch(err) {
+ case -3: return "Connection failed";
+ case -4: return "Network timeout";
+ case -10: return "Connection denied";
+ case -11: return "Failed to subscribe";
+ case -13: return "Connection lost";
+ }
+
+ if(err < 0) return "Unspecified error "+err;
+ return "";
+}
\ No newline at end of file
diff --git a/lib/SvelteUi/app/src/lib/StatusPage.svelte b/lib/SvelteUi/app/src/lib/StatusPage.svelte
index 18e0bfcc..5cc83797 100644
--- a/lib/SvelteUi/app/src/lib/StatusPage.svelte
+++ b/lib/SvelteUi/app/src/lib/StatusPage.svelte
@@ -4,6 +4,7 @@
import { upgrade, getNextVersion } from './UpgradeHelper';
import DownloadIcon from './DownloadIcon.svelte';
import { Link } from 'svelte-navigator';
+ import Mask from './Mask.svelte';
export let sysinfo;
@@ -45,6 +46,8 @@
}
let fileinput;
+ let files = [];
+ let uploading = false;
getSysinfo();
@@ -125,15 +128,16 @@
{/if}
-
+
diff --git a/lib/SvelteUi/app/vite.config.js b/lib/SvelteUi/app/vite.config.js
index dbfba4be..af80afb9 100644
--- a/lib/SvelteUi/app/vite.config.js
+++ b/lib/SvelteUi/app/vite.config.js
@@ -17,18 +17,17 @@ export default defineConfig({
plugins: [svelte()],
server: {
proxy: {
- "/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",
- "/firmware": "http://192.168.233.244",
- "/upgrade": "http://192.168.233.244"
+ "/data.json": "http://192.168.233.229",
+ "/energyprice.json": "http://192.168.233.229",
+ "/dayplot.json": "http://192.168.233.229",
+ "/monthplot.json": "http://192.168.233.229",
+ "/temperature.json": "http://192.168.233.229",
+ "/sysinfo.json": "http://192.168.233.229",
+ "/configuration.json": "http://192.168.233.229",
+ "/tariff.json": "http://192.168.233.229",
+ "/save": "http://192.168.233.229",
+ "/reboot": "http://192.168.233.229",
+ "/upgrade": "http://192.168.233.229"
}
}
})
diff --git a/lib/SvelteUi/include/AmsWebServer.h b/lib/SvelteUi/include/AmsWebServer.h
index 4dc01981..6ad94d36 100644
--- a/lib/SvelteUi/include/AmsWebServer.h
+++ b/lib/SvelteUi/include/AmsWebServer.h
@@ -83,7 +83,6 @@ private:
void monthplotJson();
void energyPriceJson();
void temperatureJson();
- void wifiScanJson();
void tariffJson();
void configurationJson();
diff --git a/lib/SvelteUi/json/conf_debug.json b/lib/SvelteUi/json/conf_debug.json
new file mode 100644
index 00000000..e9ec284b
--- /dev/null
+++ b/lib/SvelteUi/json/conf_debug.json
@@ -0,0 +1,5 @@
+"d": {
+ "s": %s,
+ "t": %s,
+ "l": %d
+},
diff --git a/lib/SvelteUi/json/conf_general.json b/lib/SvelteUi/json/conf_general.json
new file mode 100644
index 00000000..b1333cef
--- /dev/null
+++ b/lib/SvelteUi/json/conf_general.json
@@ -0,0 +1,7 @@
+"g": {
+ "t": "%s",
+ "h": "%s",
+ "s": %d,
+ "u": "%s",
+ "p": "%s"
+},
\ No newline at end of file
diff --git a/lib/SvelteUi/json/conf_gpio.json b/lib/SvelteUi/json/conf_gpio.json
new file mode 100644
index 00000000..4cea40be
--- /dev/null
+++ b/lib/SvelteUi/json/conf_gpio.json
@@ -0,0 +1,28 @@
+"i": {
+ "h": %s,
+ "a": %s,
+ "l": {
+ "p": %s,
+ "i": %s
+ },
+ "r": {
+ "r": %s,
+ "g": %s,
+ "b": %s,
+ "i": %s
+ },
+ "t": {
+ "d": %s,
+ "a": %s
+ },
+ "v": {
+ "p": %s,
+ "o": %.2f,
+ "m": %.3f,
+ "d": {
+ "v": %d,
+ "g": %d
+ },
+ "b": %.1f
+ }
+}
diff --git a/lib/SvelteUi/json/conf_meter.json b/lib/SvelteUi/json/conf_meter.json
new file mode 100644
index 00000000..b31d753f
--- /dev/null
+++ b/lib/SvelteUi/json/conf_meter.json
@@ -0,0 +1,20 @@
+"m": {
+ "b": %d,
+ "p": %d,
+ "i": %s,
+ "d": %d,
+ "f": %d,
+ "r": %d,
+ "e": {
+ "e": %s,
+ "k": "%s",
+ "a": "%s"
+ },
+ "m": {
+ "e": %s,
+ "w": %.3f,
+ "v": %.3f,
+ "a": %.3f,
+ "c": %.3f
+ }
+},
\ No newline at end of file
diff --git a/lib/SvelteUi/json/conf_mqtt.json b/lib/SvelteUi/json/conf_mqtt.json
new file mode 100644
index 00000000..c0030dbb
--- /dev/null
+++ b/lib/SvelteUi/json/conf_mqtt.json
@@ -0,0 +1,15 @@
+"q": {
+ "h": "%s",
+ "p": %d,
+ "u": "%s",
+ "a": "%s",
+ "c": "%s",
+ "b": "%s",
+ "m": %d,
+ "s": {
+ "e": %s,
+ "c": %s,
+ "r": %s,
+ "k": %s
+ }
+},
diff --git a/lib/SvelteUi/json/conf_net.json b/lib/SvelteUi/json/conf_net.json
new file mode 100644
index 00000000..4eaa1141
--- /dev/null
+++ b/lib/SvelteUi/json/conf_net.json
@@ -0,0 +1,11 @@
+"n": {
+ "m": "%s",
+ "i": "%s",
+ "s": "%s",
+ "g": "%s",
+ "d1": "%s",
+ "d2": "%s",
+ "d": %s,
+ "n1": "%s",
+ "h": %s
+},
diff --git a/lib/SvelteUi/json/conf_price.json b/lib/SvelteUi/json/conf_price.json
new file mode 100644
index 00000000..124b4697
--- /dev/null
+++ b/lib/SvelteUi/json/conf_price.json
@@ -0,0 +1,7 @@
+"p": {
+ "e": %s,
+ "t": "%s",
+ "r": "%s",
+ "c": "%s",
+ "m": %.3f
+},
diff --git a/lib/SvelteUi/json/conf_thresholds.json b/lib/SvelteUi/json/conf_thresholds.json
new file mode 100644
index 00000000..fd911368
--- /dev/null
+++ b/lib/SvelteUi/json/conf_thresholds.json
@@ -0,0 +1,15 @@
+"t": {
+ "t": [
+ %d,
+ %d,
+ %d,
+ %d,
+ %d,
+ %d,
+ %d,
+ %d,
+ %d,
+ %d
+ ],
+ "h": %d
+},
\ No newline at end of file
diff --git a/lib/SvelteUi/json/conf_wifi.json b/lib/SvelteUi/json/conf_wifi.json
new file mode 100644
index 00000000..9071e9b7
--- /dev/null
+++ b/lib/SvelteUi/json/conf_wifi.json
@@ -0,0 +1,6 @@
+"w": {
+ "s": "%s",
+ "p": "%s",
+ "w": %.1f,
+ "z": %d
+},
diff --git a/lib/SvelteUi/json/data.json b/lib/SvelteUi/json/data.json
index eefea149..173c115f 100644
--- a/lib/SvelteUi/json/data.json
+++ b/lib/SvelteUi/json/data.json
@@ -40,19 +40,23 @@
"h" : {
"u" : %.2f,
"c" : %.2f,
- "p" : %.2f
+ "p" : %.2f,
+ "i" : %.2f
},
"d" : {
"u" : %.2f,
"c" : %.2f,
- "p" : %.2f
+ "p" : %.2f,
+ "i" : %.2f
},
"m" : {
"u" : %.2f,
"c" : %.2f,
- "p" : %.2f
+ "p" : %.2f,
+ "i" : %.2f
}
},
"pr" : "%s",
+ "he" : %d,
"c" : %lu
}
\ No newline at end of file
diff --git a/lib/SvelteUi/json/peak.json b/lib/SvelteUi/json/peak.json
new file mode 100644
index 00000000..7f58d14c
--- /dev/null
+++ b/lib/SvelteUi/json/peak.json
@@ -0,0 +1,4 @@
+{
+ "d": %d,
+ "v": %.2f
+}
\ No newline at end of file
diff --git a/lib/SvelteUi/json/sysinfo.json b/lib/SvelteUi/json/sysinfo.json
new file mode 100644
index 00000000..7844d7ee
--- /dev/null
+++ b/lib/SvelteUi/json/sysinfo.json
@@ -0,0 +1,25 @@
+{
+ "version": "%s",
+ "chip": "%s",
+ "chipId": "%s",
+ "mac": "%s",
+ "board": %d,
+ "vndcfg": %s,
+ "usrcfg": %s,
+ "fwconsent": %d,
+ "hostname": "%s",
+ "booting": %s,
+ "upgrading": %s,
+ "net": {
+ "ip": "%s",
+ "mask": "%s",
+ "gw": "%s",
+ "dns1": "%s",
+ "dns2": "%s"
+ },
+ "meter": {
+ "mfg": %d,
+ "model": "%s",
+ "id": "%s"
+ }
+}
\ No newline at end of file
diff --git a/lib/SvelteUi/json/tariff.json b/lib/SvelteUi/json/tariff.json
new file mode 100644
index 00000000..e832ff11
--- /dev/null
+++ b/lib/SvelteUi/json/tariff.json
@@ -0,0 +1,17 @@
+{
+ "t": [
+ %d,
+ %d,
+ %d,
+ %d,
+ %d,
+ %d,
+ %d,
+ %d,
+ %d,
+ %d
+ ],
+ "p": [ %s ],
+ "c": %d,
+ "m": %.2f
+}
\ No newline at end of file
diff --git a/lib/SvelteUi/src/AmsWebServer.cpp b/lib/SvelteUi/src/AmsWebServer.cpp
index a691c74a..003423cc 100644
--- a/lib/SvelteUi/src/AmsWebServer.cpp
+++ b/lib/SvelteUi/src/AmsWebServer.cpp
@@ -3,8 +3,6 @@
#include "base64.h"
#include "hexutils.h"
-#include
-
#include "html/index_html.h"
#include "html/index_css.h"
#include "html/index_js.h"
@@ -15,6 +13,18 @@
#include "html/energyprice_json.h"
#include "html/tempsensor_json.h"
#include "html/response_json.h"
+#include "html/sysinfo_json.h"
+#include "html/tariff_json.h"
+#include "html/peak_json.h"
+#include "html/conf_general_json.h"
+#include "html/conf_meter_json.h"
+#include "html/conf_wifi_json.h"
+#include "html/conf_net_json.h"
+#include "html/conf_mqtt_json.h"
+#include "html/conf_price_json.h"
+#include "html/conf_thresholds_json.h"
+#include "html/conf_debug_json.h"
+#include "html/conf_gpio_json.h"
#include "version.h"
@@ -60,8 +70,6 @@ void AmsWebServer::setup(AmsConfiguration* config, GpioConfig* gpioConfig, Meter
server.on(F("/temperature.json"), HTTP_GET, std::bind(&AmsWebServer::temperatureJson, this));
server.on(F("/tariff.json"), HTTP_GET, std::bind(&AmsWebServer::tariffJson, this));
- server.on(F("/wifiscan.json"), HTTP_GET, std::bind(&AmsWebServer::wifiScanJson, this));
-
server.on(F("/configuration.json"), HTTP_GET, std::bind(&AmsWebServer::configurationJson, this));
server.on(F("/save"), HTTP_POST, std::bind(&AmsWebServer::handleSave, this));
server.on(F("/reboot"), HTTP_POST, std::bind(&AmsWebServer::reboot, this));
@@ -169,17 +177,8 @@ void AmsWebServer::faviconIco() {
void AmsWebServer::sysinfoJson() {
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /sysinfo.json over http...\n");
- DynamicJsonDocument doc(1024);
- doc[F("version")] = VERSION;
- #if defined(CONFIG_IDF_TARGET_ESP32S2)
- doc[F("chip")] = "esp32s2";
- #elif defined(CONFIG_IDF_TARGET_ESP32C3)
- doc[F("chip")] = "esp32c3";
- #elif defined(ESP32)
- doc[F("chip")] = "esp32";
- #elif defined(ESP8266)
- doc[F("chip")] = "esp8266";
- #endif
+ SystemConfig sys;
+ config->getSystemConfig(sys);
uint32_t chipId;
#if defined(ESP32)
@@ -188,39 +187,54 @@ void AmsWebServer::sysinfoJson() {
chipId = ESP.getChipId();
#endif
String chipIdStr = String(chipId, HEX);
- doc[F("chipId")] = chipIdStr;
- doc[F("mac")] = WiFi.macAddress();
-
- SystemConfig sys;
- config->getSystemConfig(sys);
- doc[F("board")] = sys.boardType;
- doc[F("vndcfg")] = sys.vendorConfigured;
- doc[F("usrcfg")] = sys.userConfigured;
- doc[F("fwconsent")] = sys.dataCollectionConsent;
- doc[F("country")] = sys.country;
+ String hostname;
if(sys.userConfigured) {
WiFiConfig wifiConfig;
config->getWiFiConfig(wifiConfig);
- doc[F("hostname")] = wifiConfig.hostname;
+ hostname = String(wifiConfig.hostname);
} else {
- doc[F("hostname")] = "ams-"+chipIdStr;
+ hostname = "ams-"+chipIdStr;
}
- doc[F("booting")] = performRestart;
- doc[F("upgrading")] = rebootForUpgrade;
+ IPAddress dns1 = WiFi.dnsIP(0);
+ IPAddress dns2 = WiFi.dnsIP(1);
- doc[F("net")][F("ip")] = WiFi.localIP().toString();
- doc[F("net")][F("mask")] = WiFi.subnetMask().toString();
- doc[F("net")][F("gw")] = WiFi.gatewayIP().toString();
- doc[F("net")][F("dns1")] = WiFi.dnsIP(0).toString();
- doc[F("net")][F("dns2")] = WiFi.dnsIP(1).toString();
+ snprintf_P(buf, BufferSize, SYSINFO_JSON,
+ VERSION,
+ #if defined(CONFIG_IDF_TARGET_ESP32S2)
+ "esp32s2",
+ #elif defined(CONFIG_IDF_TARGET_ESP32C3)
+ "esp32c3",
+ #elif defined(ESP32)
+ "esp32",
+ #elif defined(ESP8266)
+ "esp8266",
+ #endif
+ chipIdStr.c_str(),
+ WiFi.macAddress().c_str(),
+ sys.boardType,
+ sys.vendorConfigured ? "true" : "false",
+ sys.userConfigured ? "true" : "false",
+ sys.dataCollectionConsent,
+ hostname.c_str(),
+ performRestart ? "true" : "false",
+ rebootForUpgrade ? "true" : "false",
+ WiFi.localIP().toString().c_str(),
+ WiFi.subnetMask().toString().c_str(),
+ WiFi.gatewayIP().toString().c_str(),
+ dns1.isSet() ? dns1.toString().c_str() : "",
+ dns2.isSet() ? dns2.toString().c_str() : "",
+ meterState->getMeterType(),
+ meterState->getMeterModel().c_str(),
+ meterState->getMeterId().c_str()
+ );
- doc[F("meter")][F("mfg")] = meterState->getMeterType();
- doc[F("meter")][F("model")] = meterState->getMeterModel();
- doc[F("meter")][F("id")] = meterState->getMeterId();
+ server.sendHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE);
+ server.sendHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE);
+ server.sendHeader(HEADER_EXPIRES, EXPIRES_OFF);
- serializeJson(doc, buf, BufferSize);
+ server.setContentLength(strlen(buf));
server.send(200, MIME_JSON, buf);
server.handleClient();
@@ -276,7 +290,9 @@ void AmsWebServer::dataJson() {
uint8_t hanStatus;
- if(meterConfig->baud == 0 || meterState->getLastUpdateMillis() == 0) {
+ if(meterState->getLastError() < 0) {
+ hanStatus = 3;
+ } else if((meterConfig->baud == 0 || meterState->getLastUpdateMillis() == 0) && now < 15000) {
hanStatus = 0;
} else if(now - meterState->getLastUpdateMillis() < 15000) {
hanStatus = 1;
@@ -313,7 +329,7 @@ void AmsWebServer::dataJson() {
String peaks = "";
for(uint8_t i = 1; i <= ea->getConfig()->hours; i++) {
if(!peaks.isEmpty()) peaks += ",";
- peaks += String(ea->getPeak(i).value);
+ peaks += String(ea->getPeak(i).value / 100.0);
}
snprintf_P(buf, BufferSize, DATA_JSON,
@@ -357,13 +373,17 @@ void AmsWebServer::dataJson() {
ea->getUseThisHour(),
ea->getCostThisHour(),
ea->getProducedThisHour(),
+ ea->getIncomeThisHour(),
ea->getUseToday(),
ea->getCostToday(),
ea->getProducedToday(),
+ ea->getIncomeToday(),
ea->getUseThisMonth(),
ea->getCostThisMonth(),
ea->getProducedThisMonth(),
+ ea->getIncomeThisMonth(),
eapi == NULL ? "" : eapi->getArea(),
+ meterState->getLastError(),
(uint32_t) time(nullptr)
);
@@ -665,28 +685,13 @@ void AmsWebServer::indexJs() {
void AmsWebServer::configurationJson() {
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /configuration.json over http...\n");
- server.sendHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE);
- server.sendHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE);
- server.sendHeader(HEADER_EXPIRES, EXPIRES_OFF);
-
if(!checkSecurity(1))
return;
- DynamicJsonDocument doc(2048);
- doc[F("version")] = VERSION;
-
NtpConfig ntpConfig;
config->getNtpConfig(ntpConfig);
WiFiConfig wifiConfig;
config->getWiFiConfig(wifiConfig);
- WebConfig webConfig;
- config->getWebConfig(webConfig);
-
- doc[F("g")][F("t")] = ntpConfig.timezone;
- doc[F("g")][F("h")] = wifiConfig.hostname;
- doc[F("g")][F("s")] = webConfig.security;
- doc[F("g")][F("u")] = webConfig.username;
- doc[F("g")][F("p")] = strlen(webConfig.password) > 0 ? "***" : "";
bool encen = false;
for(uint8_t i = 0; i < 16; i++) {
@@ -695,166 +700,143 @@ void AmsWebServer::configurationJson() {
}
}
- config->getMeterConfig(*meterConfig);
- doc[F("m")][F("b")] = meterConfig->baud;
- doc[F("m")][F("p")] = meterConfig->parity;
- doc[F("m")][F("i")] = meterConfig->invert;
- doc[F("m")][F("d")] = meterConfig->distributionSystem;
- doc[F("m")][F("f")] = meterConfig->mainFuse;
- doc[F("m")][F("r")] = meterConfig->productionCapacity;
- doc[F("m")][F("e")][F("e")] = encen;
- doc[F("m")][F("e")][F("k")] = toHex(meterConfig->encryptionKey, 16);
- doc[F("m")][F("e")][F("a")] = toHex(meterConfig->authenticationKey, 16);
- doc[F("m")][F("m")][F("e")] = meterConfig->wattageMultiplier > 1 || meterConfig->voltageMultiplier > 1 || meterConfig->amperageMultiplier > 1 || meterConfig->accumulatedMultiplier > 1;
- doc[F("m")][F("m")][F("w")] = meterConfig->wattageMultiplier / 1000.0;
- doc[F("m")][F("m")][F("v")] = meterConfig->voltageMultiplier / 1000.0;
- doc[F("m")][F("m")][F("a")] = meterConfig->amperageMultiplier / 1000.0;
- doc[F("m")][F("m")][F("c")] = meterConfig->accumulatedMultiplier / 1000.0;
-
- EnergyAccountingConfig eac;
- config->getEnergyAccountingConfig(eac);
- doc[F("t")][F("t")][0] = eac.thresholds[0];
- doc[F("t")][F("t")][1] = eac.thresholds[1];
- doc[F("t")][F("t")][2] = eac.thresholds[2];
- doc[F("t")][F("t")][3] = eac.thresholds[3];
- doc[F("t")][F("t")][4] = eac.thresholds[4];
- doc[F("t")][F("t")][5] = eac.thresholds[5];
- doc[F("t")][F("t")][6] = eac.thresholds[6];
- doc[F("t")][F("t")][7] = eac.thresholds[7];
- doc[F("t")][F("t")][8] = eac.thresholds[8];
- doc[F("t")][F("t")][9] = eac.thresholds[9];
- doc[F("t")][F("h")] = eac.hours;
-
- doc[F("w")][F("s")] = wifiConfig.ssid;
- doc[F("w")][F("p")] = strlen(wifiConfig.psk) > 0 ? "***" : "";
- doc[F("w")][F("w")] = wifiConfig.power / 10.0;
- doc[F("w")][F("z")] = wifiConfig.sleep;
-
- doc[F("n")][F("m")] = strlen(wifiConfig.ip) > 0 ? "static" : "dhcp";
- doc[F("n")][F("i")] = wifiConfig.ip;
- doc[F("n")][F("s")] = wifiConfig.subnet;
- doc[F("n")][F("g")] = wifiConfig.gateway;
- doc[F("n")][F("d1")] = wifiConfig.dns1;
- doc[F("n")][F("d2")] = wifiConfig.dns2;
- doc[F("n")][F("d")] = wifiConfig.mdns;
- doc[F("n")][F("n1")] = ntpConfig.server;
- doc[F("n")][F("h")] = ntpConfig.dhcp;
-
+ EnergyAccountingConfig* eac = ea->getConfig();
MqttConfig mqttConfig;
config->getMqttConfig(mqttConfig);
- doc[F("q")][F("h")] = mqttConfig.host;
- doc[F("q")][F("p")] = mqttConfig.port;
- doc[F("q")][F("u")] = mqttConfig.username;
- doc[F("q")][F("a")] = strlen(mqttConfig.password) > 0 ? "***" : "";
- doc[F("q")][F("c")] = mqttConfig.clientId;
- doc[F("q")][F("b")] = mqttConfig.publishTopic;
- doc[F("q")][F("m")] = mqttConfig.payloadFormat;
- doc[F("q")][F("s")][F("e")] = mqttConfig.ssl;
-
- if(LittleFS.begin()) {
- doc[F("q")][F("s")][F("c")] = LittleFS.exists(FILE_MQTT_CA);
- doc[F("q")][F("s")][F("r")] = LittleFS.exists(FILE_MQTT_CERT);
- doc[F("q")][F("s")][F("k")] = LittleFS.exists(FILE_MQTT_KEY);
- LittleFS.end();
- } else {
- doc[F("q")][F("s")][F("c")] = false;
- doc[F("q")][F("s")][F("r")] = false;
- doc[F("q")][F("s")][F("k")] = false;
- }
EntsoeConfig entsoe;
config->getEntsoeConfig(entsoe);
- doc[F("p")][F("e")] = strlen(entsoe.token) > 0;
- doc[F("p")][F("t")] = entsoe.token;
- doc[F("p")][F("r")] = entsoe.area;
- doc[F("p")][F("c")] = entsoe.currency;
- doc[F("p")][F("m")] = entsoe.multiplier / 1000.0;
-
DebugConfig debugConfig;
config->getDebugConfig(debugConfig);
- doc[F("d")][F("s")] = debugConfig.serial;
- doc[F("d")][F("t")] = debugConfig.telnet;
- doc[F("d")][F("l")] = debugConfig.level;
- GpioConfig gpioConfig;
- config->getGpioConfig(gpioConfig);
- if(gpioConfig.hanPin == 0xff)
- doc[F("i")][F("h")] = nullptr;
- else
- doc[F("i")][F("h")] = gpioConfig.hanPin;
-
- if(gpioConfig.apPin == 0xff)
- doc[F("i")][F("a")] = nullptr;
- else
- doc[F("i")][F("a")] = gpioConfig.apPin;
-
- if(gpioConfig.ledPin == 0xff)
- doc[F("i")][F("l")][F("p")] = nullptr;
- else
- doc[F("i")][F("l")][F("p")] = gpioConfig.ledPin;
-
- doc[F("i")][F("l")][F("i")] = gpioConfig.ledInverted;
-
- if(gpioConfig.ledPinRed == 0xff)
- doc[F("i")][F("r")][F("r")] = nullptr;
- else
- doc[F("i")][F("r")][F("r")] = gpioConfig.ledPinRed;
+ bool qsc = false;
+ bool qsr = false;
+ bool qsk = false;
- if(gpioConfig.ledPinGreen == 0xff)
- doc[F("i")][F("r")][F("g")] = nullptr;
- else
- doc[F("i")][F("r")][F("g")] = gpioConfig.ledPinGreen;
+ if(LittleFS.begin()) {
+ qsc = LittleFS.exists(FILE_MQTT_CA);
+ qsr = LittleFS.exists(FILE_MQTT_CERT);
+ qsk = LittleFS.exists(FILE_MQTT_KEY);
+ LittleFS.end();
+ }
- if(gpioConfig.ledPinBlue == 0xff)
- doc[F("i")][F("r")][F("b")] = nullptr;
- else
- doc[F("i")][F("r")][F("b")] = gpioConfig.ledPinBlue;
+ server.sendHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE);
+ server.sendHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE);
+ server.sendHeader(HEADER_EXPIRES, EXPIRES_OFF);
- doc[F("i")][F("r")][F("i")] = gpioConfig.ledRgbInverted;
+ server.setContentLength(CONTENT_LENGTH_UNKNOWN);
+ server.send_P(200, MIME_JSON, PSTR("{\"version\":\""));
+ server.sendContent_P(VERSION);
+ server.sendContent_P(PSTR("\","));
+ snprintf_P(buf, BufferSize, CONF_GENERAL_JSON,
+ ntpConfig.timezone,
+ wifiConfig.hostname,
+ webConfig.security,
+ webConfig.username,
+ strlen(webConfig.password) > 0 ? "***" : ""
+ );
+ server.sendContent(buf);
+ snprintf_P(buf, BufferSize, CONF_METER_JSON,
+ meterConfig->baud,
+ meterConfig->parity,
+ meterConfig->invert ? "true" : "false",
+ meterConfig->distributionSystem,
+ meterConfig->mainFuse,
+ meterConfig->productionCapacity,
+ encen ? "true" : "false",
+ toHex(meterConfig->encryptionKey, 16).c_str(),
+ toHex(meterConfig->authenticationKey, 16).c_str(),
+ meterConfig->wattageMultiplier > 1 || meterConfig->voltageMultiplier > 1 || meterConfig->amperageMultiplier > 1 || meterConfig->accumulatedMultiplier > 1 ? "true" : "false",
+ meterConfig->wattageMultiplier / 1000.0,
+ meterConfig->voltageMultiplier / 1000.0,
+ meterConfig->amperageMultiplier / 1000.0,
+ meterConfig->accumulatedMultiplier / 1000.0
+ );
+ server.sendContent(buf);
- if(gpioConfig.tempSensorPin == 0xff)
- doc[F("i")][F("t")][F("d")] = nullptr;
- else
- doc[F("i")][F("t")][F("d")] = gpioConfig.tempSensorPin;
-
- if(gpioConfig.tempAnalogSensorPin == 0xff)
- doc[F("i")][F("t")][F("a")] = nullptr;
- else
- doc[F("i")][F("t")][F("a")] = gpioConfig.tempAnalogSensorPin;
-
- if(gpioConfig.vccPin == 0xff)
- doc[F("i")][F("v")][F("p")] = nullptr;
- else
- doc[F("i")][F("v")][F("p")] = gpioConfig.vccPin;
-
- if(gpioConfig.vccOffset == 0)
- doc[F("i")][F("v")][F("o")] = nullptr;
- else
- doc[F("i")][F("v")][F("o")] = gpioConfig.vccOffset / 100.0;
-
- if(gpioConfig.vccMultiplier == 0)
- doc[F("i")][F("v")][F("m")] = nullptr;
- else
- doc[F("i")][F("v")][F("m")] = gpioConfig.vccMultiplier / 1000.0;
-
- if(gpioConfig.vccResistorVcc == 0)
- doc[F("i")][F("v")][F("d")][F("v")] = nullptr;
- else
- doc[F("i")][F("v")][F("d")][F("v")] = gpioConfig.vccResistorVcc;
-
- if(gpioConfig.vccResistorGnd == 0)
- doc[F("i")][F("v")][F("d")][F("g")] = nullptr;
- else
- doc[F("i")][F("v")][F("d")][F("g")] = gpioConfig.vccResistorGnd;
-
- if(gpioConfig.vccBootLimit == 0)
- doc[F("i")][F("v")][F("b")] = nullptr;
- else
- doc[F("i")][F("v")][F("b")] = gpioConfig.vccBootLimit / 10.0;
-
- serializeJson(doc, buf, BufferSize);
- server.send(200, MIME_JSON, buf);
+ snprintf_P(buf, BufferSize, CONF_THRESHOLDS_JSON,
+ eac->thresholds[0],
+ eac->thresholds[1],
+ eac->thresholds[2],
+ eac->thresholds[3],
+ eac->thresholds[4],
+ eac->thresholds[5],
+ eac->thresholds[6],
+ eac->thresholds[7],
+ eac->thresholds[8],
+ eac->thresholds[9],
+ eac->hours
+ );
+ server.sendContent(buf);
+ snprintf_P(buf, BufferSize, CONF_WIFI_JSON,
+ wifiConfig.ssid,
+ strlen(wifiConfig.psk) > 0 ? "***" : "",
+ wifiConfig.power / 10.0,
+ wifiConfig.sleep
+ );
+ server.sendContent(buf);
+ snprintf_P(buf, BufferSize, CONF_NET_JSON,
+ strlen(wifiConfig.ip) > 0 ? "static" : "dhcp",
+ wifiConfig.ip,
+ wifiConfig.subnet,
+ wifiConfig.gateway,
+ wifiConfig.dns1,
+ wifiConfig.dns2,
+ wifiConfig.mdns ? "true" : "false",
+ ntpConfig.server,
+ ntpConfig.dhcp ? "true" : "false"
+ );
+ server.sendContent(buf);
+ snprintf_P(buf, BufferSize, CONF_MQTT_JSON,
+ mqttConfig.host,
+ mqttConfig.port,
+ mqttConfig.username,
+ strlen(mqttConfig.password) > 0 ? "***" : "",
+ mqttConfig.clientId,
+ mqttConfig.publishTopic,
+ mqttConfig.payloadFormat,
+ mqttConfig.ssl ? "true" : "false",
+ qsc ? "true" : "false",
+ qsr ? "true" : "false",
+ qsk ? "true" : "false"
+ );
+ server.sendContent(buf);
+ snprintf_P(buf, BufferSize, CONF_PRICE_JSON,
+ strlen(entsoe.token) > 0 ? "true" : "false",
+ entsoe.token,
+ entsoe.area,
+ entsoe.currency,
+ entsoe.multiplier / 1000.0
+ );
+ server.sendContent(buf);
+ snprintf_P(buf, BufferSize, CONF_DEBUG_JSON,
+ debugConfig.serial ? "true" : "false",
+ debugConfig.telnet ? "true" : "false",
+ debugConfig.level
+ );
+ server.sendContent(buf);
+ snprintf_P(buf, BufferSize, CONF_GPIO_JSON,
+ gpioConfig->hanPin == 0xff ? "null" : String(gpioConfig->hanPin, 10).c_str(),
+ gpioConfig->apPin == 0xff ? "null" : String(gpioConfig->apPin, 10).c_str(),
+ gpioConfig->hanPin == 0xff ? "null" : String(gpioConfig->hanPin, 10).c_str(),
+ gpioConfig->ledInverted ? "true" : "false",
+ gpioConfig->ledPinRed == 0xff ? "null" : String(gpioConfig->ledPinRed, 10).c_str(),
+ gpioConfig->ledPinGreen == 0xff ? "null" : String(gpioConfig->ledPinGreen, 10).c_str(),
+ gpioConfig->ledPinBlue == 0xff ? "null" : String(gpioConfig->ledPinBlue, 10).c_str(),
+ gpioConfig->ledRgbInverted ? "true" : "false",
+ gpioConfig->tempSensorPin == 0xff ? "null" : String(gpioConfig->tempSensorPin, 10).c_str(),
+ gpioConfig->tempAnalogSensorPin == 0xff ? "null" : String(gpioConfig->tempAnalogSensorPin, 10).c_str(),
+ gpioConfig->vccPin == 0xff ? "null" : String(gpioConfig->vccPin, 10).c_str(),
+ gpioConfig->vccOffset / 100.0,
+ gpioConfig->vccMultiplier / 1000.0,
+ gpioConfig->vccResistorVcc,
+ gpioConfig->vccResistorGnd,
+ gpioConfig->vccBootLimit / 10.0
+ );
+ server.sendContent(buf);
+ server.sendContent("}");
}
+
void AmsWebServer::handleSave() {
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf(PSTR("Handling save method from http"));
if(!checkSecurity(1))
@@ -1300,23 +1282,10 @@ void AmsWebServer::handleSave() {
}
}
-void AmsWebServer::wifiScanJson() {
- if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /wifiscan.json over http...\n");
-
- DynamicJsonDocument doc(512);
-
- serializeJson(doc, buf, BufferSize);
- server.send(200, MIME_JSON, buf);
-}
-
void AmsWebServer::reboot() {
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /reboot over http...\n");
- DynamicJsonDocument doc(128);
- doc[F("reboot")] = true;
-
- serializeJson(doc, buf, BufferSize);
- server.send(200, MIME_JSON, buf);
+ server.send(200, MIME_JSON, "{\"reboot\":true}");
server.handleClient();
delay(250);
@@ -1601,32 +1570,43 @@ void AmsWebServer::mqttKeyUpload() {
void AmsWebServer::tariffJson() {
if(debugger->isActive(RemoteDebug::DEBUG)) debugger->printf("Serving /tariff.json over http...\n");
- server.sendHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE);
- server.sendHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE);
- server.sendHeader(HEADER_EXPIRES, EXPIRES_OFF);
-
if(!checkSecurity(1))
return;
EnergyAccountingConfig* eac = ea->getConfig();
- EnergyAccountingData data = ea->getData();
- DynamicJsonDocument doc(512);
- JsonArray thresholds = doc.createNestedArray(F("t"));
- for(uint8_t x = 0;x < 10; x++) {
- thresholds.add(eac->thresholds[x]);
- }
- JsonArray peaks = doc.createNestedArray(F("p"));
+ String peaks;
for(uint8_t x = 0;x < min((uint8_t) 5, eac->hours); x++) {
- JsonObject p = peaks.createNestedObject();
EnergyAccountingPeak peak = ea->getPeak(x+1);
- p["d"] = peak.day;
- p["v"] = peak.value / 100.0;
+ int len = snprintf_P(buf, BufferSize, PEAK_JSON,
+ peak.day,
+ peak.value / 100.0
+ );
+ buf[len] = '\0';
+ if(!peaks.isEmpty()) peaks += ",";
+ peaks += String(buf);
}
- doc["c"] = ea->getCurrentThreshold();
- doc["m"] = ea->getMonthMax();
- serializeJson(doc, buf, BufferSize);
+ snprintf_P(buf, BufferSize, TARIFF_JSON,
+ eac->thresholds[0],
+ eac->thresholds[1],
+ eac->thresholds[2],
+ eac->thresholds[3],
+ eac->thresholds[4],
+ eac->thresholds[5],
+ eac->thresholds[6],
+ eac->thresholds[7],
+ eac->thresholds[8],
+ eac->thresholds[9],
+ peaks.c_str(),
+ ea->getCurrentThreshold(),
+ ea->getMonthMax()
+ );
+
+ server.sendHeader(HEADER_CACHE_CONTROL, CACHE_CONTROL_NO_CACHE);
+ server.sendHeader(HEADER_PRAGMA, PRAGMA_NO_CACHE);
+ server.sendHeader(HEADER_EXPIRES, EXPIRES_OFF);
+
+ server.setContentLength(strlen(buf));
server.send(200, MIME_JSON, buf);
-
}
\ No newline at end of file
diff --git a/platformio.ini b/platformio.ini
index c11e0b3e..9f61cd4f 100755
--- a/platformio.ini
+++ b/platformio.ini
@@ -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, EntsoePriceApi, EnergyAccounting, AmsMqttHandler, RawMqttHandler, JsonMqttHandler, DomoticzMqttHandler, HomeAssistantMqttHandler, ArduinoJson, SvelteUi
+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, EntsoePriceApi, EnergyAccounting, AmsMqttHandler, RawMqttHandler, JsonMqttHandler, DomoticzMqttHandler, HomeAssistantMqttHandler, SvelteUi
lib_ignore = OneWire
extra_scripts =
pre:scripts/addversion.py
diff --git a/src/AmsToMqttBridge.ino b/src/AmsToMqttBridge.ino
index d738c585..0a3e9480 100644
--- a/src/AmsToMqttBridge.ino
+++ b/src/AmsToMqttBridge.ino
@@ -826,6 +826,7 @@ bool readHanPort() {
if(pos == DATA_PARSE_INCOMPLETE) {
return false;
} else if(pos == DATA_PARSE_UNKNOWN_DATA) {
+ meterState.setLastError(pos);
debugV("Unknown data payload:");
len = len + hanSerial->readBytes(hanBuffer+len, BUF_SIZE_HAN-len);
debugPrint(hanBuffer, 0, len);
@@ -837,6 +838,7 @@ bool readHanPort() {
len = 0;
return false;
} else if(pos < 0) {
+ meterState.setLastError(pos);
printHanReadError(pos);
len += hanSerial->readBytes(hanBuffer+len, BUF_SIZE_HAN-len);
if(mqttEnabled && mqtt != NULL && mqttHandler == NULL) {
@@ -852,6 +854,7 @@ bool readHanPort() {
for(int i = pos+ctx.length; i 0.0) {
- ead.peaks[0] = { 1, (uint16_t) (val*100) };
- }
- } else if(i == 3) {
- double val = String(pch).toDouble();
- ead.costYesterday = val * 10;
- } else if(i == 4) {
- double val = String(pch).toDouble();
- ead.costThisMonth = val;
- } else if(i == 5) {
- double val = String(pch).toDouble();
- ead.costLastMonth = val;
- } else if(i >= 6 && i < 18) {
- uint8_t hour = i-6;
- if(hour%2 == 0) {
+ if(ead.version < 5) {
+ if(i == 0) {
long val = String(pch).toInt();
- ead.peaks[hour/2].day = val;
- } else {
+ ead.version = val;
+ } else if(i == 1) {
+ long val = String(pch).toInt();
+ ead.month = val;
+ } else if(i == 2) {
double val = String(pch).toDouble();
- ead.peaks[hour/2].value = val * 100;
+ if(val > 0.0) {
+ ead.peaks[0] = { 1, (uint16_t) (val*100) };
+ }
+ } else if(i == 3) {
+ double val = String(pch).toDouble();
+ ead.costYesterday = val * 10;
+ } else if(i == 4) {
+ double val = String(pch).toDouble();
+ ead.costThisMonth = val;
+ } else if(i == 5) {
+ double val = String(pch).toDouble();
+ ead.costLastMonth = val;
+ } else if(i >= 6 && i < 18) {
+ uint8_t hour = i-6;
+ if(hour%2 == 0) {
+ long val = String(pch).toInt();
+ ead.peaks[hour/2].day = val;
+ } else {
+ double val = String(pch).toDouble();
+ ead.peaks[hour/2].value = val * 100;
+ }
+ }
+ } else {
+ if(i == 1) {
+ long val = String(pch).toInt();
+ ead.month = val;
+ } else if(i == 2) {
+ double val = String(pch).toDouble();
+ if(val > 0.0) {
+ ead.peaks[0] = { 1, (uint16_t) (val*100) };
+ }
+ } else if(i == 3) {
+ double val = String(pch).toDouble();
+ ead.costYesterday = val * 10;
+ } else if(i == 4) {
+ double val = String(pch).toDouble();
+ ead.costThisMonth = val;
+ } else if(i == 5) {
+ double val = String(pch).toDouble();
+ ead.costLastMonth = val;
+ } else if(i == 6) {
+ double val = String(pch).toDouble();
+ ead.incomeYesterday= val * 10;
+ } else if(i == 7) {
+ double val = String(pch).toDouble();
+ ead.incomeThisMonth = val;
+ } else if(i == 8) {
+ double val = String(pch).toDouble();
+ ead.incomeLastMonth = val;
+ } else if(i >= 9 && i < 21) {
+ uint8_t hour = i-9;
+ if(hour%2 == 0) {
+ long val = String(pch).toInt();
+ ead.peaks[hour/2].day = val;
+ } else {
+ double val = String(pch).toDouble();
+ ead.peaks[hour/2].value = val * 100;
+ }
}
}
pch = strtok (NULL, " ");