mirror of
https://github.com/UtilitechAS/amsreader-firmware.git
synced 2026-02-10 02:10:47 +00:00
Changes in user interface
This commit is contained in:
@@ -287,6 +287,30 @@ void AmsData::extractFromOmnipower(HanReader& hanReader, int listSize) {
|
||||
}
|
||||
|
||||
void AmsData::apply(AmsData& other) {
|
||||
if(other.getListType() < 3) {
|
||||
unsigned long ms = this->lastUpdateMillis > other.getLastUpdateMillis() ? 0 : other.getLastUpdateMillis() - this->lastUpdateMillis;
|
||||
|
||||
if(ms > 0) {
|
||||
if(other.getActiveImportPower() > 0)
|
||||
activeImportCounter += (((double) ms) * other.getActiveImportPower()) / 3600000000;
|
||||
counterEstimated = true;
|
||||
}
|
||||
|
||||
if(other.getListType() > 1) {
|
||||
unsigned long ms2 = this->lastList2UpdateMillis > other.getLastUpdateMillis() ? 0 : other.getLastUpdateMillis() - this->lastList2UpdateMillis;
|
||||
if(ms2 > 0) {
|
||||
// Not sure why, but I cannot make these numbers correct. It seems to be double of what it should, so dividing it by two...
|
||||
if(other.getActiveExportPower() > 0)
|
||||
activeExportCounter += (((double) ms2/2) * other.getActiveExportPower()) / 3600000000;
|
||||
if(other.getReactiveImportPower() > 0)
|
||||
reactiveImportCounter += (((double) ms2/2) * other.getReactiveImportPower()) / 3600000000;
|
||||
if(other.getReactiveExportPower() > 0)
|
||||
reactiveExportCounter += (((double) ms2/2) * other.getReactiveExportPower()) / 3600000000;
|
||||
counterEstimated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->lastUpdateMillis = other.getLastUpdateMillis();
|
||||
this->packageTimestamp = other.getPackageTimestamp();
|
||||
this->listType = max(this->listType, other.getListType());
|
||||
@@ -297,6 +321,7 @@ void AmsData::apply(AmsData& other) {
|
||||
this->activeExportCounter = other.getActiveExportCounter();
|
||||
this->reactiveImportCounter = other.getReactiveImportCounter();
|
||||
this->reactiveExportCounter = other.getReactiveExportCounter();
|
||||
this->counterEstimated = false;
|
||||
case 2:
|
||||
this->listId = other.getListId();
|
||||
this->meterId = other.getMeterId();
|
||||
@@ -311,6 +336,7 @@ void AmsData::apply(AmsData& other) {
|
||||
this->l2voltage = other.getL2Voltage();
|
||||
this->l3voltage = other.getL3Voltage();
|
||||
this->threePhase = other.isThreePhase();
|
||||
this->lastList2UpdateMillis = other.getLastUpdateMillis();
|
||||
case 1:
|
||||
this->activeImportPower = other.getActiveImportPower();
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ public:
|
||||
|
||||
private:
|
||||
unsigned long lastUpdateMillis = 0;
|
||||
unsigned long lastList2UpdateMillis = 0;
|
||||
int listType = 0;
|
||||
unsigned long packageTimestamp = 0;
|
||||
String listId, meterId, meterType;
|
||||
@@ -58,7 +59,7 @@ private:
|
||||
int activeImportPower = 0, reactiveImportPower = 0, activeExportPower = 0, reactiveExportPower = 0;
|
||||
double l1voltage = 0, l2voltage = 0, l3voltage = 0, l1current = 0, l2current = 0, l3current = 0;
|
||||
double activeImportCounter = 0, reactiveImportCounter = 0, activeExportCounter = 0, reactiveExportCounter = 0;
|
||||
bool threePhase = false;
|
||||
bool threePhase = false, counterEstimated = false;
|
||||
|
||||
void extractFromKaifa(HanReader& hanReader, int listSize);
|
||||
void extractFromAidon(HanReader& hanReader, int listSize, bool substituteMissing);
|
||||
|
||||
@@ -459,11 +459,11 @@ void loop() {
|
||||
delay(1);
|
||||
readHanPort();
|
||||
if(WiFi.status() == WL_CONNECTED) {
|
||||
ws.loop();
|
||||
if(eapi.loop()) {
|
||||
sendPricesToMqtt();
|
||||
}
|
||||
//if(eapi.loop()) {
|
||||
// sendPricesToMqtt();
|
||||
//}
|
||||
}
|
||||
ws.loop();
|
||||
delay(1); // Needed for auto modem sleep
|
||||
}
|
||||
|
||||
@@ -611,62 +611,77 @@ void mqttMessageReceived(String &topic, String &payload)
|
||||
}
|
||||
|
||||
void sendPricesToMqtt() {
|
||||
if(strlen(config.getMqttHost()) == 0 || strlen(config.getMqttPublishTopic()) == 0)
|
||||
return;
|
||||
if(strcmp(config.getEntsoeApiToken(), "") != 0)
|
||||
return;
|
||||
|
||||
time_t now = time(nullptr);
|
||||
|
||||
double min1hr, min3hr, min6hr;
|
||||
int min1hrIdx = -1, min3hrIdx = -1, min6hrIdx = -1;
|
||||
double min = INT16_MAX, max = INT16_MIN;
|
||||
double values[48];
|
||||
for(int i = 0; i < 48; i++) {
|
||||
double val1 = eapi.getValueForHour(i);
|
||||
values[i] = val1;
|
||||
double values[24] = {0};
|
||||
for(int i = 0; i < 24; i++) {
|
||||
double val = eapi.getValueForHour(now, i);
|
||||
values[i] = val;
|
||||
|
||||
if(val1 == ENTSOE_NO_VALUE) break;
|
||||
if(val == ENTSOE_NO_VALUE) break;
|
||||
|
||||
if(val1 < min) min = val1;
|
||||
if(val1 > max) max = val1;
|
||||
if(val < min) min = val;
|
||||
if(val > max) max = val;
|
||||
|
||||
if(i >= 24) continue; // Only estimate 1hr, 3hr and 6hr cheapest interval for next 24 hrs
|
||||
|
||||
if(min1hrIdx == -1 || min1hr > val1) {
|
||||
min1hr = val1;
|
||||
if(min1hrIdx == -1 || min1hr > val) {
|
||||
min1hr = val;
|
||||
min1hrIdx = i;
|
||||
}
|
||||
|
||||
double val2 = eapi.getValueForHour(i+1);
|
||||
double val3 = eapi.getValueForHour(i+2);
|
||||
if(val2 == ENTSOE_NO_VALUE || val3 == ENTSOE_NO_VALUE) continue;
|
||||
double val3hr = val1+val2+val3;
|
||||
if(min3hrIdx == -1 || min3hr > val3hr) {
|
||||
min3hr = val3hr;
|
||||
min3hrIdx = i;
|
||||
if(i >= 2) {
|
||||
double val1 = values[i-2];
|
||||
double val2 = values[i-1];
|
||||
double val3 = val;
|
||||
if(val1 == ENTSOE_NO_VALUE || val2 == ENTSOE_NO_VALUE || val3 == ENTSOE_NO_VALUE) continue;
|
||||
double val3hr = val1+val2+val3;
|
||||
if(min3hrIdx == -1 || min3hr > val3hr) {
|
||||
min3hr = val3hr;
|
||||
min3hrIdx = i-2;
|
||||
}
|
||||
}
|
||||
|
||||
double val4 = eapi.getValueForHour(i+3);
|
||||
double val5 = eapi.getValueForHour(i+4);
|
||||
double val6 = eapi.getValueForHour(i+5);
|
||||
if(val4 == ENTSOE_NO_VALUE || val5 == ENTSOE_NO_VALUE || val6 == ENTSOE_NO_VALUE) continue;
|
||||
double val6hr = val1+val2+val3+val4+val5+val6;
|
||||
if(min6hrIdx == -1 || min6hr > val6hr) {
|
||||
min6hr = val6hr;
|
||||
min6hrIdx = i;
|
||||
|
||||
if(i >= 5) {
|
||||
double val1 = values[i-5];
|
||||
double val2 = values[i-4];
|
||||
double val3 = values[i-3];
|
||||
double val4 = values[i-2];
|
||||
double val5 = values[i-1];
|
||||
double val6 = val;
|
||||
if(val1 == ENTSOE_NO_VALUE || val2 == ENTSOE_NO_VALUE || val3 == ENTSOE_NO_VALUE || val4 == ENTSOE_NO_VALUE || val5 == ENTSOE_NO_VALUE || val6 == ENTSOE_NO_VALUE) continue;
|
||||
double val6hr = val1+val2+val3+val4+val5+val6;
|
||||
if(min6hrIdx == -1 || min6hr > val6hr) {
|
||||
min6hr = val6hr;
|
||||
min6hrIdx = i-5;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
char ts1hr[21];
|
||||
if(min1hrIdx != -1) {
|
||||
tmElements_t tm;
|
||||
breakTime(time(nullptr) + (SECS_PER_HOUR * min1hrIdx), tm);
|
||||
breakTime(now + (SECS_PER_HOUR * min1hrIdx), tm);
|
||||
sprintf(ts1hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
}
|
||||
char ts3hr[21];
|
||||
if(min3hrIdx != -1) {
|
||||
tmElements_t tm;
|
||||
breakTime(time(nullptr) + (SECS_PER_HOUR * min3hrIdx), tm);
|
||||
breakTime(now + (SECS_PER_HOUR * min3hrIdx), tm);
|
||||
sprintf(ts3hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
}
|
||||
char ts6hr[21];
|
||||
if(min6hrIdx != -1) {
|
||||
tmElements_t tm;
|
||||
breakTime(time(nullptr) + (SECS_PER_HOUR * min6hrIdx), tm);
|
||||
breakTime(now + (SECS_PER_HOUR * min6hrIdx), tm);
|
||||
sprintf(ts6hr, "%04d-%02d-%02dT%02d:00:00Z", tm.Year+1970, tm.Month, tm.Day, tm.Hour);
|
||||
}
|
||||
|
||||
@@ -678,33 +693,37 @@ void sendPricesToMqtt() {
|
||||
json["name"] = config.getMqttClientId();
|
||||
json["up"] = millis();
|
||||
JsonObject jp = json.createNestedObject("prices");
|
||||
for(int i = 0; i < 48; i++) {
|
||||
double val = values[i];
|
||||
if(val == ENTSOE_NO_VALUE) break;
|
||||
jp[String(i)] = serialized(String(val, 4));
|
||||
}
|
||||
if(min != INT16_MAX) {
|
||||
jp["min"] = serialized(String(min, 4));
|
||||
}
|
||||
if(max != INT16_MIN) {
|
||||
jp["max"] = serialized(String(max, 4));
|
||||
}
|
||||
if(min1hrIdx != -1) {
|
||||
jp["cheapest1hr"] = String(ts1hr);
|
||||
}
|
||||
if(min3hrIdx != -1) {
|
||||
jp["cheapest3hr"] = String(ts1hr);
|
||||
}
|
||||
if(min6hrIdx != -1) {
|
||||
jp["cheapest6hr"] = String(ts1hr);
|
||||
}
|
||||
for(int i = 0; i < 24; i++) {
|
||||
double val = values[i];
|
||||
if(val == ENTSOE_NO_VALUE) break;
|
||||
jp[String(i)] = serialized(String(val, 4));
|
||||
}
|
||||
if(min != INT16_MAX) {
|
||||
jp["min"] = serialized(String(min, 4));
|
||||
}
|
||||
if(max != INT16_MIN) {
|
||||
jp["max"] = serialized(String(max, 4));
|
||||
}
|
||||
|
||||
if(min1hrIdx != -1) {
|
||||
jp["cheapest1hr"] = String(ts1hr);
|
||||
}
|
||||
if(min3hrIdx != -1) {
|
||||
jp["cheapest3hr"] = String(ts3hr);
|
||||
}
|
||||
if(min6hrIdx != -1) {
|
||||
jp["cheapest6hr"] = String(ts6hr);
|
||||
}
|
||||
|
||||
String msg;
|
||||
serializeJson(json, msg);
|
||||
mqtt.publish(config.getMqttPublishTopic(), msg.c_str());
|
||||
break;
|
||||
}
|
||||
case 1: // RAW
|
||||
case 2:
|
||||
// Send updated prices if we have them
|
||||
if(strcmp(config.getEntsoeApiToken(), "") != 0) {
|
||||
for(int i = 0; i < 48; i++) {
|
||||
{
|
||||
for(int i = 0; i < 24; i++) {
|
||||
double val = values[i];
|
||||
if(val == ENTSOE_NO_VALUE) {
|
||||
mqtt.publish(String(config.getMqttPublishTopic()) + "/price/" + String(i), "");
|
||||
@@ -712,6 +731,8 @@ void sendPricesToMqtt() {
|
||||
} else {
|
||||
mqtt.publish(String(config.getMqttPublishTopic()) + "/price/" + String(i), String(val, 4));
|
||||
}
|
||||
mqtt.loop();
|
||||
delay(10);
|
||||
}
|
||||
if(min != INT16_MAX) {
|
||||
mqtt.publish(String(config.getMqttPublishTopic()) + "/price/min", String(min, 4));
|
||||
@@ -719,6 +740,7 @@ void sendPricesToMqtt() {
|
||||
if(max != INT16_MIN) {
|
||||
mqtt.publish(String(config.getMqttPublishTopic()) + "/price/max", String(max, 4));
|
||||
}
|
||||
|
||||
if(min1hrIdx != -1) {
|
||||
mqtt.publish(String(config.getMqttPublishTopic()) + "/price/cheapest/1hr", String(ts1hr));
|
||||
}
|
||||
@@ -910,7 +932,6 @@ void readHanPort() {
|
||||
mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/import/active/accumulated", String(data.getActiveImportCounter(), 2));
|
||||
mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/export/reactive/accumulated", String(data.getReactiveExportCounter(), 2));
|
||||
mqtt.publish(String(config.getMqttPublishTopic()) + "/meter/export/active/accumulated", String(data.getActiveExportCounter(), 2));
|
||||
|
||||
sendPricesToMqtt();
|
||||
case 2:
|
||||
// Only send data if changed. ID and Type is sent on the 10s interval only if changed
|
||||
|
||||
@@ -40,10 +40,13 @@ void EntsoeApi::setMultiplier(double multiplier) {
|
||||
char* EntsoeApi::getCurrency() {
|
||||
return currency;
|
||||
}
|
||||
|
||||
double EntsoeApi::getValueForHour(int hour) {
|
||||
tmElements_t tm;
|
||||
time_t cur = time(nullptr);
|
||||
return getValueForHour(cur, hour);
|
||||
}
|
||||
|
||||
double EntsoeApi::getValueForHour(time_t cur, int hour) {
|
||||
tmElements_t tm;
|
||||
if(tz != NULL)
|
||||
cur = tz->toLocal(cur);
|
||||
breakTime(cur, tm);
|
||||
|
||||
@@ -15,6 +15,7 @@ public:
|
||||
bool loop();
|
||||
|
||||
double getValueForHour(int hour);
|
||||
double getValueForHour(time_t now, int hour);
|
||||
char* getCurrency();
|
||||
|
||||
void setToken(const char* token);
|
||||
|
||||
@@ -295,19 +295,18 @@ void AmsWebServer::indexHtml() {
|
||||
html.replace("${data.P}", String(data.getActiveImportPower()));
|
||||
html.replace("${data.PO}", String(data.getActiveExportPower()));
|
||||
html.replace("${display.export}", config->getProductionCapacity() > 0 ? "" : "none");
|
||||
html.replace("${text.import}", config->getProductionCapacity() > 0 ? "Import" : "Consumption");
|
||||
html.replace("${display.nonexport}", config->getProductionCapacity() > 0 ? "none" : "");
|
||||
html.replace("${text.import}", config->getProductionCapacity() > 0 ? "Import" : "Use");
|
||||
html.replace("${display.3p}", data.isThreePhase() ? "" : "none");
|
||||
|
||||
html.replace("${data.U1}", u1 > 0 ? String(u1, 1) : "");
|
||||
html.replace("${data.I1}", u1 > 0 ? String(i1, 1) : "");
|
||||
html.replace("${display.P1}", u1 > 0 ? "" : "none");
|
||||
|
||||
html.replace("${data.U2}", u2 > 0 ? String(u2, 1) : "");
|
||||
html.replace("${data.I2}", u2 > 0 ? String(i2, 1) : "");
|
||||
html.replace("${display.P2}", u2 > 0 ? "" : "none");
|
||||
|
||||
html.replace("${data.U3}", u3 > 0 ? String(u3, 1) : "");
|
||||
html.replace("${data.I3}", u3 > 0 ? String(i3, 1) : "");
|
||||
html.replace("${display.P3}", u3 > 0 ? "" : "none");
|
||||
|
||||
html.replace("${data.tPI}", tpi > 0 ? String(tpi, 1) : "");
|
||||
html.replace("${data.tPO}", tpi > 0 ? String(tpo, 1) : "");
|
||||
@@ -327,6 +326,8 @@ void AmsWebServer::indexHtml() {
|
||||
html.replace("${wifi.channel}", WiFi.channel() > 0 ? String(WiFi.channel()) : "");
|
||||
html.replace("${wifi.ssid}", !WiFi.SSID().isEmpty() ? String(WiFi.SSID()) : "");
|
||||
|
||||
html.replace("${currentSeconds}", String((uint32_t)(millis64()/1000), 10));
|
||||
|
||||
server.setContentLength(html.length() + HEAD_HTML_LEN + FOOT_HTML_LEN);
|
||||
server.send_P(200, "text/html", HEAD_HTML);
|
||||
server.sendContent(html);
|
||||
@@ -628,6 +629,9 @@ void AmsWebServer::dataJson() {
|
||||
double tqi = data.getReactiveImportCounter();
|
||||
double tqo = data.getReactiveExportCounter();
|
||||
|
||||
double volt = u1;
|
||||
double amp = i1;
|
||||
|
||||
if(u1 > 0) {
|
||||
json["data"]["U1"] = u1;
|
||||
json["data"]["I1"] = i1;
|
||||
@@ -635,10 +639,13 @@ void AmsWebServer::dataJson() {
|
||||
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) {
|
||||
@@ -650,6 +657,14 @@ void AmsWebServer::dataJson() {
|
||||
|
||||
json["p_pct"] = min(data.getActiveImportPower()*100/maxPwr, 100);
|
||||
|
||||
json["v"] = volt;
|
||||
json["v_pct"] = (max((int)volt-207, 1)*100/46);
|
||||
|
||||
int maxAmp = config->getMainFuse() == 0 ? 32 : config->getMainFuse();
|
||||
|
||||
json["a"] = amp;
|
||||
json["a_pct"] = amp * 100 / maxAmp;
|
||||
|
||||
if(config->getProductionCapacity() > 0) {
|
||||
int maxPrd = config->getProductionCapacity() * 1000;
|
||||
json["po_pct"] = min(data.getActiveExportPower()*100/maxPrd, 100);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
var nextVersion;
|
||||
var im, em;
|
||||
var im, em, vm, am;
|
||||
$(function() {
|
||||
im = $("#importMeter");
|
||||
if(im && im.gaugeMeter) {
|
||||
@@ -18,6 +18,24 @@ $(function() {
|
||||
append: "W"
|
||||
});
|
||||
}
|
||||
|
||||
vm = $("#voltMeter");
|
||||
if(vm && vm.gaugeMeter) {
|
||||
vm.gaugeMeter({
|
||||
percent: 0,
|
||||
text: "-",
|
||||
append: "V"
|
||||
});
|
||||
}
|
||||
|
||||
am = $("#ampMeter");
|
||||
if(am && am.gaugeMeter) {
|
||||
am.gaugeMeter({
|
||||
percent: 0,
|
||||
text: "-",
|
||||
append: "A"
|
||||
});
|
||||
}
|
||||
|
||||
var meters = $('.SimpleMeter');
|
||||
|
||||
@@ -217,10 +235,12 @@ var fetch = function() {
|
||||
timeout: 10000,
|
||||
dataType: 'json',
|
||||
}).done(function(json) {
|
||||
if(im && em) {
|
||||
if(im) {
|
||||
$(".SimpleMeter").hide();
|
||||
im.show();
|
||||
em.show();
|
||||
vm.show();
|
||||
am.show();
|
||||
}
|
||||
|
||||
for(var id in json) {
|
||||
@@ -237,8 +257,8 @@ var fetch = function() {
|
||||
}
|
||||
|
||||
if(window.moment) {
|
||||
$('#currentMillis').html(moment.duration(parseInt(json.uptime_seconds), 'seconds').humanize());
|
||||
$('#currentMillis').closest('.row').show();
|
||||
$('.currentSeconds').html(moment.duration(parseInt(json.uptime_seconds), 'seconds').humanize());
|
||||
$('.currentSeconds').closest('.row').show();
|
||||
}
|
||||
|
||||
if(json.status) {
|
||||
@@ -304,16 +324,46 @@ var fetch = function() {
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
$('.'+id).html(str);
|
||||
} else {
|
||||
var num = parseFloat(str);
|
||||
$('#'+id).html(num.toFixed(1));
|
||||
$('.'+id).html(num.toFixed(1));
|
||||
$('#'+id+'-row').show();
|
||||
$('.'+id+'-row').show();
|
||||
}
|
||||
}
|
||||
|
||||
var temp = parseInt(json.temp);
|
||||
if(temp == -127) {
|
||||
$('.temp').html("N/A");
|
||||
}
|
||||
} else {
|
||||
if(im && im.gaugeMeter) {
|
||||
im.gaugeMeter({
|
||||
@@ -330,26 +380,25 @@ var fetch = function() {
|
||||
append: "W"
|
||||
});
|
||||
}
|
||||
|
||||
if(vm && vm.gaugeMeter) {
|
||||
vm.gaugeMeter({
|
||||
percent: 0,
|
||||
text: "-"
|
||||
});
|
||||
}
|
||||
|
||||
if(am && am.gaugeMeter) {
|
||||
am.gaugeMeter({
|
||||
percent: 0,
|
||||
text: "-"
|
||||
});
|
||||
}
|
||||
}
|
||||
setTimeout(fetch, interval);
|
||||
}).fail(function() {
|
||||
setTimeout(fetch, interval*4);
|
||||
|
||||
if(im && im.gaugeMeter) {
|
||||
im.gaugeMeter({
|
||||
percent: 0,
|
||||
text: "-",
|
||||
append: "W"
|
||||
});
|
||||
}
|
||||
|
||||
if(em && em.gaugeMeter) {
|
||||
em.gaugeMeter({
|
||||
percent: 0,
|
||||
text: "-",
|
||||
append: "W"
|
||||
});
|
||||
}
|
||||
setStatus("mqtt", "secondary");
|
||||
setStatus("wifi", "secondary");
|
||||
setStatus("han", "secondary");
|
||||
|
||||
@@ -55,6 +55,18 @@
|
||||
"LightGreen-DarkGreen" === option.theme && (e > 0 && (t = "#3afc00"), e > 10 && (t = "#39f900"), e > 20 && (t = "#38f600"), e > 30 && (t = "#38f100"), e > 40 && (t = "#37ec00"), e > 50 && (t = "#36e700"), e > 60 && (t = "#34e200"), e > 70 && (t = "#34df00"), e > 80 && (t = "#33db00"), e > 90 && (t = "#32d900")),
|
||||
"DarkGold-LightGold" === option.theme && (e > 0 && (t = "#ffb800"), e > 10 && (t = "#ffba00"), e > 20 && (t = "#ffbd00"), e > 30 && (t = "#ffc200"), e > 40 && (t = "#ffc600"), e > 50 && (t = "#ffcb00"), e > 60 && (t = "#ffcf00"), e > 70 && (t = "#ffd400"), e > 80 && (t = "#ffd600"), e > 90 && (t = "#ffd900")),
|
||||
"LightGold-DarkGold" === option.theme && (e > 0 && (t = "#ffd900"), e > 10 && (t = "#ffd600"), e > 20 && (t = "#ffd400"), e > 30 && (t = "#ffcf00"), e > 40 && (t = "#ffcb00"), e > 50 && (t = "#ffc600"), e > 60 && (t = "#ffc200"), e > 70 && (t = "#ffbd00"), e > 80 && (t = "#ffba00"), e > 90 && (t = "#ffb800")),
|
||||
"Voltage" === option.theme && (
|
||||
e > 0 && (t = "#d90000"),
|
||||
e > 10 && (t = "#f35100"),
|
||||
e > 20 && (t = "#ffb800"),
|
||||
e > 30 && (t = "#a6d900"),
|
||||
e > 40 && (t = "#32d900"),
|
||||
e > 50 && (t = "#32d900"),
|
||||
e > 60 && (t = "#a6d900"),
|
||||
e > 70 && (t = "#ffb800"),
|
||||
e > 80 && (t = "#f35100"),
|
||||
e > 90 && (t = "#d90000")
|
||||
),
|
||||
"White" === option.theme && (t = "#fff"),
|
||||
"Black" === option.theme && (t = "#000"),
|
||||
t;
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<main role="main" class="container">
|
||||
<header class="navbar navbar-expand navbar-dark flex-column flex-lg-row rounded mt-2 mb-4" style="background-color: var(--purple);">
|
||||
<header class="navbar navbar-expand navbar-dark flex-column flex-lg-row rounded mt-2 mb-3" style="background-color: var(--purple);">
|
||||
<a href="/" class=""><h6 class="navbar-brand">AMS reader <small id="swVersion" data-url="https://api.github.com/repos/gskjold/AmsToMqttBridge/releases">${version}</small></h6></a>
|
||||
<div class="navbar-nav-scroll">
|
||||
<ul class="navbar-nav bd-navbar-nav flex-row">
|
||||
|
||||
217
web/index.html
217
web/index.html
@@ -1,107 +1,138 @@
|
||||
<div class="my-3 p-3 bg-white rounded shadow">
|
||||
<div class="bg-white rounded shadow p-1">
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-lg-3">
|
||||
<div class="text-center">
|
||||
<div id="P" class="SimpleMeter" style="display: inline;">
|
||||
${data.P} W
|
||||
<div class="col-md-3 col-6">
|
||||
<div class="text-center">Up <span class="currentSeconds">${currentSeconds}</span></div>
|
||||
</div>
|
||||
<div class="col-md-3 col-6">
|
||||
<div class="text-center">Temperature: <span class="temp">${temp}</span>°C</div>
|
||||
</div>
|
||||
<div class="col-md-3 col-6">
|
||||
<div class="text-center">ESP volt: <span class="vcc">${vcc}</span>V</div>
|
||||
</div>
|
||||
<div class="col-md-3 col-6">
|
||||
<div class="text-center">WiFi RSSI: <span class="rssi">${wifi.rssi}</span>dBm</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6">
|
||||
<div class="row">
|
||||
<div class="col-sm-6 mt-3">
|
||||
<div class="bg-white rounded shadow p-3">
|
||||
<div class="text-center">
|
||||
<div id="P" class="SimpleMeter" style="display: inline;">
|
||||
${data.P} W
|
||||
</div>
|
||||
<div id="importMeter" class="GaugeMeter rounded"
|
||||
style="display: none;"
|
||||
data-size="180px"
|
||||
data-text_size="0.15"
|
||||
data-width="25"
|
||||
data-style="Arch"
|
||||
data-theme="Green-Gold-Red"
|
||||
data-animationstep="0"
|
||||
data-label="${text.import}"
|
||||
></div>
|
||||
</div>
|
||||
<div id="tPI-row" class="row" style="display: ${display.accumulative};">
|
||||
<div class="col-12 text-right"><span class="tPI">${data.tPI}</span> kWh</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="importMeter" class="GaugeMeter rounded"
|
||||
</div>
|
||||
<div class="col-sm-6 mt-3" style="display: ${display.export};">
|
||||
<div class="bg-white rounded shadow p-3">
|
||||
<div class="text-center">
|
||||
<div id="P" class="SimpleMeter" style="display: inline;">
|
||||
${data.PO} W
|
||||
</div>
|
||||
<div id="exportMeter" class="GaugeMeter rounded"
|
||||
style="display: none;"
|
||||
data-size="180px"
|
||||
data-text_size="0.15"
|
||||
data-width="25"
|
||||
data-style="Arch"
|
||||
data-theme="DarkGreen-LightGreen"
|
||||
data-animationstep="0"
|
||||
data-label="Export"
|
||||
></div>
|
||||
</div>
|
||||
<div id="tPO-row" class="row" style="display: ${display.accumulative};">
|
||||
<div class="col-12 text-right"><span class="tPO">${data.tPO}</span> kWh</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 mt-3" style="display: ${display.nonexport};">
|
||||
<div class="bg-white rounded shadow p-3" style="display: ${display.accumulative};">
|
||||
<h5 class="text-center">Reactive</h5>
|
||||
<div id="tQI-row" class="row">
|
||||
<div class="col-4">Import</div>
|
||||
<div class="col-8 text-right"><span class="tQI">${data.tQI}</span> kvarh</div>
|
||||
<div class="col-4">Export</div>
|
||||
<div class="col-8 text-right"><span class="tQO">${data.tQO}</span> kvarh</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12 mt-3" style="display: ${display.export};">
|
||||
<div class="bg-white rounded shadow p-3" style="display: ${display.accumulative};">
|
||||
<div id="tQO-row" class="row">
|
||||
<div class="col-4">Import</div>
|
||||
<div class="col-8 text-right"><span class="tQI">${data.tQI}</span> kvarh</div>
|
||||
<div class="col-4">Export</div>
|
||||
<div class="col-8 text-right"><span class="tQO">${data.tQO}</span> kvarh</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-sm-6 mt-3">
|
||||
<div class="bg-white rounded shadow p-3">
|
||||
<div class="text-center">
|
||||
<div id="voltMeter" class="GaugeMeter rounded"
|
||||
style="display: none;"
|
||||
data-size="200px"
|
||||
data-text_size="0.11"
|
||||
data-size="180px"
|
||||
data-text_size="0.15"
|
||||
data-width="25"
|
||||
data-style="Arch"
|
||||
data-theme="Voltage"
|
||||
data-animationstep="0"
|
||||
data-label="Volt"
|
||||
></div>
|
||||
</div>
|
||||
<div id="U2-row" class="row" style="display: ${display.3p};">
|
||||
<div class="col-4" title="L1"><span class="U1">${data.U1}</span>V</div>
|
||||
<div class="col-4 text-center" title="L2"><span class="U2">${data.U2}</span>V</div>
|
||||
<div class="col-4 text-right" title="L3"><span class="U3">${data.U3}</span>V</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-sm-6 mb-3 mt-3">
|
||||
<div class="bg-white rounded shadow p-3">
|
||||
<div class="text-center">
|
||||
<div id="ampMeter" class="GaugeMeter rounded"
|
||||
style="display: none;"
|
||||
data-size="180px"
|
||||
data-text_size="0.15"
|
||||
data-width="25"
|
||||
data-style="Arch"
|
||||
data-theme="Green-Gold-Red"
|
||||
data-animationstep="0"
|
||||
data-label="${text.import}"
|
||||
data-label="Ampere"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-lg-3">
|
||||
<div id="U1-row" class="row" style="display: ${display.P1};">
|
||||
<div class="col-2">L1</div>
|
||||
<div class="col-5 text-right"><span id="U1">${data.U1}</span> V</div>
|
||||
<div class="col-5 text-right"><span id="I1">${data.I1}</span> A</div>
|
||||
</div>
|
||||
<div id="U2-row" class="row" style="display: ${display.P2};">
|
||||
<div class="col-2">L2</div>
|
||||
<div class="col-5 text-right"><span id="U2">${data.U2}</span> V</div>
|
||||
<div class="col-5 text-right"><span id="I2">${data.I2}</span> A</div>
|
||||
</div>
|
||||
<div id="U3-row" class="row" style="display: ${display.P3};">
|
||||
<div class="col-2">L3</div>
|
||||
<div class="col-5 text-right"><span id="U3">${data.U3}</span> V</div>
|
||||
<div class="col-5 text-right"><span id="I3">${data.I3}</span> A</div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div id="tPI-row" class="row" style="display: ${display.accumulative};">
|
||||
<div class="col-6">Active in</div>
|
||||
<div class="col-6 text-right"><span id="tPI">${data.tPI}</span> kWh</div>
|
||||
</div>
|
||||
<div id="tPO-row" class="row" style="display: ${display.accumulative};">
|
||||
<div class="col-6">Active out</div>
|
||||
<div class="col-6 text-right"><span id="tPO">${data.tPO}</span> kWh</div>
|
||||
</div>
|
||||
<div id="tQI-row" class="row" style="display: ${display.accumulative};">
|
||||
<div class="col-6">Reactive in</div>
|
||||
<div class="col-6 text-right"><span id="tQI">${data.tQI}</span> kvarh</div>
|
||||
</div>
|
||||
<div id="tQO-row" class="row" style="display: ${display.accumulative};">
|
||||
<div class="col-6">Reactive out</div>
|
||||
<div class="col-6 text-right"><span id="tQO">${data.tQO}</span> kvarh</div>
|
||||
<div id="I2-row" class="row" style="display: ${display.3p};">
|
||||
<div class="col-4" title="L1"><span class="I1">${data.I1}</span>A</div>
|
||||
<div class="col-4 text-center" title="L2"><span class="I2">${data.I2}</span>A</div>
|
||||
<div class="col-4 text-right" title="L3"><span class="I3">${data.I3}</span>A</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-lg-3">
|
||||
<div class="text-center" style="display: ${display.export};">
|
||||
<div id="P" class="SimpleMeter" style="display: inline;">
|
||||
${data.PO} W
|
||||
</div>
|
||||
<div id="exportMeter" class="GaugeMeter rounded"
|
||||
style="display: none;"
|
||||
data-size="200px"
|
||||
data-text_size="0.11"
|
||||
data-width="25"
|
||||
data-style="Arch"
|
||||
data-theme="DarkGreen-LightGreen"
|
||||
data-animationstep="0"
|
||||
data-label="Export"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-lg-3">
|
||||
<hr class="d-md-inline"/>
|
||||
<div class="row">
|
||||
<div class="col-6">Vcc</div>
|
||||
<div class="col-6 text-right"><span id="vcc">${vcc}</span> V</div>
|
||||
</div>
|
||||
<div class="row" style="display: ${display.temp};">
|
||||
<div class="col-6">Temperature</div>
|
||||
<div class="col-6 text-right"><span id="temp">${temp}</span> °C</div>
|
||||
</div>
|
||||
<div class="row" style="display: none;">
|
||||
<div class="col-6">Uptime</div>
|
||||
<div class="col-6 text-right"><span id="currentMillis">${currentMillis}</span></div>
|
||||
</div>
|
||||
<hr/>
|
||||
<div class="row">
|
||||
<div class="col-6">SSID</div>
|
||||
<div class="col-6 text-right"><span id="ssid">${wifi.ssid}</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6">Channel</div>
|
||||
<div class="col-6 text-right"><span id="channel">${wifi.channel}</span></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-6">RSSI</div>
|
||||
<div class="col-6 text-right"><span id="rssi">${wifi.rssi}</span> dBm</div>
|
||||
</div>
|
||||
<hr class="d-none mqtt-error mqtt-error-1 mqtt-error-2 mqtt-error-3 mqtt-error-4 mqtt-error-5 mqtt-error-6 mqtt-error-7 mqtt-error-8 mqtt-error-9 mqtt-error-10 mqtt-error-11 mqtt-error-12 mqtt-error-13"/>
|
||||
<div class="d-none badge badge-danger mqtt-error mqtt-error-1 mqtt-error-2 mqtt-error-5 mqtt-error-6 mqtt-error-7 mqtt-error-8 mqtt-error-9 mqtt-error-12">MQTT communication error (<span id="mqtt-lastError">-</span>)</div>
|
||||
<div class="d-none badge badge-danger mqtt-error mqtt-error-3">MQTT failed to connect</div>
|
||||
<div class="d-none badge badge-danger mqtt-error mqtt-error-4">MQTT network timeout</div>
|
||||
<div class="d-none badge badge-danger mqtt-error mqtt-error-10">MQTT connection denied</div>
|
||||
<div class="d-none badge badge-danger mqtt-error mqtt-error-11">MQTT failed to subscribe</div>
|
||||
<div class="d-none badge badge-danger mqtt-error mqtt-error-13">MQTT lost connection</div>
|
||||
</div>
|
||||
<div class="col-lg-3 col-sm-6 mb-3 d-none mqtt-error mqtt-error-1 mqtt-error-2 mqtt-error-3 mqtt-error-4 mqtt-error-5 mqtt-error-6 mqtt-error-7 mqtt-error-8 mqtt-error-9 mqtt-error-10 mqtt-error-11 mqtt-error-12 mqtt-error-13">
|
||||
<div class="d-none badge badge-danger mqtt-error mqtt-error-1 mqtt-error-2 mqtt-error-5 mqtt-error-6 mqtt-error-7 mqtt-error-8 mqtt-error-9 mqtt-error-12">MQTT communication error (<span id="mqtt-lastError">-</span>)</div>
|
||||
<div class="d-none badge badge-danger mqtt-error mqtt-error-3">MQTT failed to connect</div>
|
||||
<div class="d-none badge badge-danger mqtt-error mqtt-error-4">MQTT network timeout</div>
|
||||
<div class="d-none badge badge-danger mqtt-error mqtt-error-10">MQTT connection denied</div>
|
||||
<div class="d-none badge badge-danger mqtt-error mqtt-error-11">MQTT failed to subscribe</div>
|
||||
<div class="d-none badge badge-danger mqtt-error mqtt-error-13">MQTT lost connection</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<div id="sensors" class="my-3 p-3 bg-white rounded shadow">
|
||||
<p>Price retrieval requires ENTSO-E API and NTP to be configured and working</p>
|
||||
<div class="row">
|
||||
<div class="col-lg-2 col-md-3 col-sm-4">
|
||||
<div class="row">
|
||||
|
||||
Reference in New Issue
Block a user