diff --git a/scripts/makeweb.py b/scripts/makeweb.py index e48b8045..2d82721e 100644 --- a/scripts/makeweb.py +++ b/scripts/makeweb.py @@ -37,7 +37,7 @@ for filename in os.listdir(webroot): content = html_minify(content) elif filename.endswith(".css"): content = css_minify(content) - elif filename.endswith(".js") and filename != 'gaugemeter.js': + elif (filename.endswith(".js") and filename != 'gaugemeter.js') or filename.endswith(".json"): content = js_minify(content) except: print("WARN: Unable to minify") diff --git a/src/web/AmsWebServer.cpp b/src/web/AmsWebServer.cpp index aca5cd54..d89b5cea 100644 --- a/src/web/AmsWebServer.cpp +++ b/src/web/AmsWebServer.cpp @@ -27,6 +27,7 @@ #include "root/temperature_html.h" #include "root/price_html.h" #include "root/notfound_html.h" +#include "root/data_json.h" #include "base64.h" @@ -604,163 +605,93 @@ void AmsWebServer::githubSvg() { void AmsWebServer::dataJson() { printD("Serving /data.json over http..."); + uint64_t now = millis64(); if(!checkSecurity(2)) return; - StaticJsonDocument<768> json; + float vcc = hw->getVcc(); + int rssi = hw->getWifiRssi(); - String jsonStr; - if(meterState->getLastUpdateMillis() > 0) { - int maxPwr = this->maxPwr; - if(maxPwr == 0) { - if(meterState->isThreePhase()) { - maxPwr = 20000; - } else { - maxPwr = 10000; - } - } - - json["up"] = meterState->getLastUpdateMillis(); - json["t"] = meterState->getPackageTimestamp(); - json["freemem"] = ESP.getFreeHeap(); - json.createNestedObject("data"); - json["data"]["P"] = meterState->getActiveImportPower(); - json["data"]["PO"] = meterState->getActiveExportPower(); - - double u1 = meterState->getL1Voltage(); - double u2 = meterState->getL2Voltage(); - double u3 = meterState->getL3Voltage(); - double i1 = meterState->getL1Current(); - double i2 = meterState->getL2Current(); - double i3 = meterState->getL3Current(); - double tpi = meterState->getActiveImportCounter(); - double tpo = meterState->getActiveExportCounter(); - double tqi = meterState->getReactiveImportCounter(); - double tqo = meterState->getReactiveExportCounter(); - - double volt = u1; - double amp = i1; - - if(u1 > 0) { - json["data"]["U1"] = u1; - json["data"]["I1"] = i1; - } - if(u2 > 0) { - json["data"]["U2"] = u2; - json["data"]["I2"] = i2; - if(i2 > amp) amp = i2; - } - if(u3 > 0) { - json["data"]["U3"] = u3; - json["data"]["I3"] = i3; - volt = (u1+u2+u3)/3; - if(i3 > amp) amp = i3; - } - - if(tpi > 0) { - json["data"]["tPI"] = tpi; - json["data"]["tPO"] = tpo; - json["data"]["tQI"] = tqi; - json["data"]["tQO"] = tqo; - } - - json["p_pct"] = min(meterState->getActiveImportPower()*100/maxPwr, 100); - - json["v"] = volt; - json["v_pct"] = (max((int)volt-207, 1)*100/46); - - int maxAmp = meterConfig->mainFuse == 0 ? 32 : meterConfig->mainFuse; - - json["a"] = amp; - json["a_pct"] = amp * 100 / maxAmp; - - if(meterConfig->productionCapacity > 0) { - int maxPrd = meterConfig->productionCapacity * 1000; - json["po_pct"] = min(meterState->getActiveExportPower()*100/maxPrd, 100); - } - } else { - json["p_pct"] = -1; - json["po_pct"] = -1; - } - - json["id"] = WiFi.macAddress(); - json["maxPower"] = maxPwr; - json["meterType"] = meterConfig->type; - json["uptime_seconds"] = millis64() / 1000; - double vcc = hw->getVcc(); - json["vcc"] = serialized(String(vcc, 3)); - - double temp = hw->getTemperature(); - json["temp"] = serialized(String(temp, 2)); - - json.createNestedObject("wifi"); - float rssi = WiFi.RSSI(); - rssi = isnan(rssi) ? -100.0 : rssi; - json["wifi"]["ssid"] = WiFi.SSID(); - json["wifi"]["channel"] = (int) WiFi.channel(); - json["wifi"]["rssi"] = rssi; - - json.createNestedObject("status"); - - String espStatus; + uint8_t espStatus; if(vcc == 0) { - espStatus = "secondary"; + espStatus = 0; } else if(vcc > 3.1) { - espStatus = "success"; + espStatus = 1; } else if(vcc > 2.8) { - espStatus = "warning"; + espStatus = 2; } else { - espStatus = "danger"; + espStatus = 3; } - json["status"]["esp"] = espStatus; - unsigned long now = millis(); - String hanStatus; + uint8_t hanStatus; if(meterConfig->type == 0) { - hanStatus = "secondary"; + hanStatus = 0; } else if(now - meterState->getLastUpdateMillis() < 15000) { - hanStatus = "success"; + hanStatus = 1; } else if(now - meterState->getLastUpdateMillis() < 30000) { - hanStatus = "warning"; + hanStatus = 2; } else { - hanStatus = "danger"; + hanStatus = 3; } - json["status"]["han"] = hanStatus; - String wifiStatus; + uint8_t wifiStatus; if(rssi > -75) { - wifiStatus = "success"; + wifiStatus = 1; } else if(rssi > -95) { - wifiStatus = "warning"; + wifiStatus = 2; } else { - wifiStatus = "danger"; + wifiStatus = 3; } - json["status"]["wifi"] = wifiStatus; - String mqttStatus; + uint8_t mqttStatus; if(!mqttEnabled) { - mqttStatus = "secondary"; + mqttStatus = 0; } else if(mqtt->connected()) { - mqttStatus = "success"; + mqttStatus = 1; } else if(mqtt->lastError() == 0) { - mqttStatus = "warning"; + mqttStatus = 2; } else { - mqttStatus = "danger"; + mqttStatus = 3; } - json["status"]["mqtt"] = mqttStatus; - json.createNestedObject("mqtt"); - json["mqtt"]["lastError"] = (int) mqtt->lastError(); - - serializeJson(json, jsonStr); + char json[280]; + snprintf_P(json, sizeof(json), DATA_JSON, + maxPwr == 0 ? meterState->isThreePhase() ? 20000 : 10000 : maxPwr, + meterConfig->productionCapacity, + meterConfig->mainFuse == 0 ? 32 : meterConfig->mainFuse, + meterState->getActiveImportPower(), + meterState->getActiveExportPower(), + meterState->getReactiveImportPower(), + meterState->getReactiveExportPower(), + meterState->getActiveImportCounter(), + meterState->getReactiveExportCounter(), + meterState->getReactiveImportCounter(), + meterState->getReactiveExportCounter(), + meterState->getL1Voltage(), + meterState->getL2Voltage(), + meterState->getL3Voltage(), + meterState->getL1Current(), + meterState->getL2Current(), + meterState->getL3Current(), + vcc, + rssi, + hw->getTemperature(), + (uint32_t) (now / 1000), + ESP.getFreeHeap(), + espStatus, + hanStatus, + wifiStatus, + mqttStatus, + (int) mqtt->lastError() + ); server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server.sendHeader("Pragma", "no-cache"); server.sendHeader("Expires", "-1"); - server.setContentLength(jsonStr.length()); - server.send(200, "application/json", jsonStr); + server.setContentLength(strlen(json)); + server.send(200, "application/json", json); } void AmsWebServer::handleSetup() { diff --git a/web/application.js b/web/application.js index fc56cf3e..5a24be53 100644 --- a/web/application.js +++ b/web/application.js @@ -219,12 +219,22 @@ $(function() { } }); -var setStatus = function(id, status) { +var setStatus = function(id, sid) { var item = $('#'+id); item.removeClass('d-none'); item.removeClass (function (index, className) { return (className.match (/(^|\s)badge-\S+/g) || []).join(' '); }); + var status; + if(sid == 0) { + status = "secondary"; + } else if(sid == 1) { + status = "success"; + } else if(sid == 2) { + status = "warning"; + } else { + status = "danger"; + } item.addClass('badge badge-' + status); }; @@ -249,150 +259,90 @@ var fetch = function() { continue; } if(isNaN(str)) { - $('.'+id).html(str); + $('.j'+id).html(str); } else { var num = parseFloat(str); - $('.'+id).html(num.toFixed(num < 0 ? 0 : num < 10 ? 2 : 1)); + $('.j'+id).html(num.toFixed(num < 0 ? 0 : num < 10 ? 2 : 1)); } + $('.r'+id).show(); } if(window.moment) { - $('.cs').html(moment.duration(parseInt(json.uptime_seconds), 'seconds').humanize()); - $('.cs').closest('.row').show(); + $('.ju').html(moment.duration(parseInt(json.u), 'seconds').humanize()); } - if(json.status) { - for(var id in json.status) { - setStatus(id, json.status[id]); + setStatus("esp", json.em); + setStatus("han", json.em == 3 ? 0 : json.hm); + setStatus("wifi", json.em == 3 ? 0 : json.wm); + setStatus("mqtt", json.em == 3 ? 0 : json.mm); + + + if(im && im.gaugeMeter) { + var v = parseInt(json.i); + var pct = (v*100)/parseInt(json.im); + var append = "W"; + if(v > 1000) { + v = (v/1000).toFixed(1); + append = "kW"; } + im.gaugeMeter({ + percent: pct, + text: v, + append: append + }); } - if(json.mqtt) { + if(em && em.gaugeMeter && json.om) { + var v = parseInt(json.e); + var pct = (v*100)/(parseInt(json.om)*1000); + var append = "W"; + if(v > 1000) { + v = (v/1000).toFixed(1); + append = "kW"; + } + em.gaugeMeter({ + percent: pct, + text: v, + append: append + }); + } + + if(vm && vm.gaugeMeter && json.u1) { + var v = parseFloat(json.u1); + if(json.u2) { + v = (v+parseFloat(json.u2)+parseFloat(json.u3)) / 3; + } + var pct = (Math.max(v-207, 1)*100/46); + vm.gaugeMeter({ + percent: pct, + text: v.toFixed(1) + }); + } + + if(am && am.gaugeMeter && json.i1 && json.mf) { + var v = parseFloat(json.i1); + if(json.i2) { + v = Math.max(v, parseFloat(json.i2)); + } + if(json.i3) { + v = Math.max(v, parseFloat(json.i3)); + } + var pct = (v*100)/parseInt(json.mf); + am.gaugeMeter({ + percent: pct, + text: v.toFixed(1) + }); + } + + if(json.me) { $('.me').addClass('d-none'); - $('.me'+json.mqtt.lastError).removeClass('d-none'); - $('#ml').html(json.mqtt.lastError); + $('.me'+json.me).removeClass('d-none'); + $('#ml').html(json.me); } - if(json.wifi) { - for(var id in json.wifi) { - var str = json.wifi[id]; - dst = $('.'+id); - if(isNaN(str)) { - dst.html(str); - } else { - var num = parseFloat(str); - dst.html(num.toFixed(0)); - $('.'+id+'-row').show(); - } - } - } - - if(json.data) { - var p = 0; - var p_pct = parseInt(json.p_pct); - var p_append = "W"; - if(json.data.P) { - p = parseFloat(json.data.P); - if(p > 1000) { - p = (p/1000).toFixed(1); - p_append = "kW"; - } - } - if(im && im.gaugeMeter) { - im.gaugeMeter({ - percent: p_pct, - text: p, - append: p_append - }); - } - - var po = 0; - var po_pct = parseInt(json.po_pct); - var po_append = "W"; - if(json.data.PO) { - po = parseFloat(json.data.PO); - if(po > 1000) { - po = (po/1000).toFixed(1); - po_append = "kW"; - } - } - if(em && em.gaugeMeter) { - em.gaugeMeter({ - percent: po_pct, - text: po, - append: po_append - }); - } - - var v = parseFloat(json.v); - if(v > 0) { - var v_pct = parseInt(json.v_pct); - - if(vm && vm.gaugeMeter) { - vm.gaugeMeter({ - percent: v_pct, - text: v.toFixed(1) - }); - } - } - - var a = parseFloat(json.a); - if(a > 0) { - var a_pct = parseInt(json.a_pct); - - if(am && am.gaugeMeter) { - am.gaugeMeter({ - percent: a_pct, - text: a.toFixed(1) - }); - } - } - - for(var id in json.data) { - var str = json.data[id]; - if(isNaN(str)) { - $('.'+id).html(str); - } else { - var num = parseFloat(str); - $('.'+id).html(num.toFixed(1)); - $('.'+id+'-row').show(); - } - } - - var temp = parseInt(json.temp); - if(temp == -127) { - $('.temp').html("N/A"); - } - } else { - if(im && im.gaugeMeter) { - im.gaugeMeter({ - percent: 0, - text: "-", - append: "W" - }); - } - - if(em && em.gaugeMeter) { - em.gaugeMeter({ - percent: 0, - text: "-", - append: "W" - }); - } - - if(vm && vm.gaugeMeter) { - vm.gaugeMeter({ - percent: 0, - text: "-" - }); - } - - if(am && am.gaugeMeter) { - am.gaugeMeter({ - percent: 0, - text: "-" - }); - } + var temp = parseInt(json.t); + if(temp == -127) { + $('.jt').html("N/A"); } setTimeout(fetch, interval); }).fail(function() { diff --git a/web/data.json b/web/data.json new file mode 100644 index 00000000..346535a4 --- /dev/null +++ b/web/data.json @@ -0,0 +1,29 @@ +{ + "im" : %d, + "om" : %d, + "mf" : %d, + "i" : %d, + "e" : %d, + "ri" : %d, + "re" : %d, + "ic" : %.1f, + "ec" : %.1f, + "ric" : %.1f, + "rec" : %.1f, + "u1" : %.1f, + "u2" : %.1f, + "u3" : %.1f, + "i1" : %.2f, + "i2" : %.2f, + "i3" : %.2f, + "v" : %.2f, + "r" : %d, + "t" : %.1f, + "u" : %lu, + "m" : %lu, + "em" : %d, + "hm" : %d, + "wm" : %d, + "mm" : %d, + "me" : %d +} \ No newline at end of file diff --git a/web/index.html b/web/index.html index 48659897..b73beb81 100644 --- a/web/index.html +++ b/web/index.html @@ -1,16 +1,16 @@