From ab101c862218afd84e6fe0b9df400d2ef3800585 Mon Sep 17 00:00:00 2001 From: Gunnar Skjold Date: Tue, 30 Nov 2021 08:01:20 +0100 Subject: [PATCH] Some changes after testing --- src/AmsData.h | 2 ++ src/AmsToMqttBridge.ino | 3 +++ src/IEC6205675.cpp | 5 ++-- src/ams/hdlc.cpp | 31 +++++++++++++++++++---- src/ams/hdlc.h | 2 ++ src/web/AmsWebServer.cpp | 2 ++ web/application.js | 48 +++++++++++++++++++++-------------- web/index.html | 54 +++++++++++++++++++++++++++++----------- 8 files changed, 106 insertions(+), 41 deletions(-) diff --git a/src/AmsData.h b/src/AmsData.h index e428e0b2..9c09a499 100644 --- a/src/AmsData.h +++ b/src/AmsData.h @@ -5,12 +5,14 @@ #include enum AmsType { + AmsTypeAutodetect = 0x00, AmsTypeAidon = 0x01, AmsTypeKaifa = 0x02, AmsTypeKamstrup = 0x03, AmsTypeIskra = 0x08, AmsTypeLandis = 0x09, AmsTypeSagemcom = 0x0A, + AmsTypeCustom = 0x88, AmsTypeUnknown = 0xFF }; diff --git a/src/AmsToMqttBridge.ino b/src/AmsToMqttBridge.ino index 812cb6de..b6b4a979 100644 --- a/src/AmsToMqttBridge.ino +++ b/src/AmsToMqttBridge.ino @@ -689,6 +689,9 @@ void readHanPort() { } return; } + for(int i = len; iencryption_key, meterConfig.encryptionKey, 16); diff --git a/src/IEC6205675.cpp b/src/IEC6205675.cpp index cd5c68ef..8bc2e769 100644 --- a/src/IEC6205675.cpp +++ b/src/IEC6205675.cpp @@ -271,9 +271,8 @@ IEC6205675::IEC6205675(const char* d, uint8_t useMeterType, CosemDateTime packag AmsOctetTimestamp* amst = (AmsOctetTimestamp*) meterTs; time_t ts = getTimestamp(amst->dt); if(meterType == AmsTypeKamstrup || meterType == AmsTypeAidon) { - this->packageTimestamp = tz.toUTC(ts); + this->packageTimestamp = this->packageTimestamp > 0 ? tz.toUTC(this->packageTimestamp) : 0; this->meterTimestamp = tz.toUTC(ts); - Serial.printf("\nKamstrup/Aidon time: %d\n", meterTimestamp); } else { meterTimestamp = ts; } @@ -457,7 +456,7 @@ time_t IEC6205675::getTimestamp(CosemDateTime timestamp) { tm.Minute = timestamp.minute; tm.Second = timestamp.second; - Serial.printf("\nY: %d, M: %d, D: %d, h: %d, m: %d, s: %d, deviation: 0x%2X, status: 0x%1X\n", tm.Year, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second, timestamp.deviation, timestamp.status); + //Serial.printf("\nY: %d, M: %d, D: %d, h: %d, m: %d, s: %d, deviation: 0x%2X, status: 0x%1X\n", tm.Year, tm.Month, tm.Day, tm.Hour, tm.Minute, tm.Second, timestamp.deviation, timestamp.status); time_t time = makeTime(tm); int16_t deviation = ntohs(timestamp.deviation); diff --git a/src/ams/hdlc.cpp b/src/ams/hdlc.cpp index 85e48afb..6ce12c6a 100644 --- a/src/ams/hdlc.cpp +++ b/src/ams/hdlc.cpp @@ -23,17 +23,17 @@ int HDLC_validate(const uint8_t* d, int length, HDLCConfig* config, CosemDateTim // Length field (11 lsb of format) int len = (ntohs(h->format) & 0x7FF) + 2; if(len > length) - return -4; + return HDLC_FRAME_INCOMPLETE; HDLCFooter* f = (HDLCFooter*) (d + len - sizeof *f); // First and last byte should be MBUS_HAN_TAG if(h->flag != HDLC_FLAG || f->flag != HDLC_FLAG) - return -1; + return HDLC_BOUNDRY_FLAG_MISSING; // Verify FCS if(ntohs(f->fcs) != crc16_x25(d + 1, len - sizeof *f - 1)) - return -2; + return HDLC_FCS_ERROR; int headersize = 8; int footersize = 3; @@ -60,7 +60,7 @@ int HDLC_validate(const uint8_t* d, int length, HDLCConfig* config, CosemDateTim // Verify HCS if(ntohs(t3->hcs) != crc16_x25(d + 1, ptr-d)) - return -3; + return HDLC_HCS_ERROR; ptr += sizeof *t3; } @@ -138,7 +138,28 @@ int HDLC_validate(const uint8_t* d, int length, HDLCConfig* config, CosemDateTim } mbedtls_gcm_free(&m_ctx); #endif - ptr += 36; // TODO: Come to this number in a proper way... + + ptr += 23; // TODO: Come to this number in a proper way... + + // ADPU timestamp + CosemData* dateTime = (CosemData*) ptr; + if(dateTime->base.type == CosemTypeOctetString) { + if(dateTime->base.length == 0x0C) { + memcpy(timestamp, ptr+1, dateTime->base.length); + } + ptr += 2 + dateTime->base.length; + } else if(dateTime->base.type == CosemTypeNull) { + timestamp = 0; + ptr++; + } else if(dateTime->base.type == CosemTypeDateTime) { + memcpy(timestamp, ptr, dateTime->base.length); + } else if(dateTime->base.type == 0x0C) { // Kamstrup bug... + memcpy(timestamp, ptr, 0x0C); + ptr += 13; + } else { + return -99; + } + return ptr-d; } diff --git a/src/ams/hdlc.h b/src/ams/hdlc.h index c4447450..0eb7568f 100644 --- a/src/ams/hdlc.h +++ b/src/ams/hdlc.h @@ -6,6 +6,8 @@ #define HDLC_FLAG 0x7E #define HDLC_BOUNDRY_FLAG_MISSING -1 +#define HDLC_FCS_ERROR -2 +#define HDLC_HCS_ERROR -3 #define HDLC_FRAME_INCOMPLETE -4 #define HDLC_ENCRYPTION_CONFIG_MISSING -90 diff --git a/src/web/AmsWebServer.cpp b/src/web/AmsWebServer.cpp index 467368c8..9095e914 100644 --- a/src/web/AmsWebServer.cpp +++ b/src/web/AmsWebServer.cpp @@ -349,6 +349,8 @@ void AmsWebServer::indexHtml() { html.replace("{P}", String(meterState->getActiveImportPower())); html.replace("{PO}", String(meterState->getActiveExportPower())); + html.replace("{Q}", String(meterState->getReactiveImportPower())); + html.replace("{QO}", String(meterState->getReactiveExportPower())); html.replace("{de}", meterConfig->productionCapacity > 0 ? "" : "none"); html.replace("{dn}", meterConfig->productionCapacity > 0 ? "none" : ""); html.replace("{ti}", meterConfig->productionCapacity > 0 ? "Import" : "Use"); diff --git a/web/application.js b/web/application.js index 2f399fc4..55af61ca 100644 --- a/web/application.js +++ b/web/application.js @@ -6,11 +6,17 @@ var ep; var ea; var eo = { title: 'Last 24 hours', - curveType: 'function', + titleTextStyle: { + fontSize: 14 + }, + bar: { groupWidth: '90%' }, legend: { position: 'none' }, vAxis: { + title: 'kWh', viewWindowMode: 'maximized' - } + }, + tooltip: { trigger: 'none'}, + enableInteractivity: false, }; // Month plot @@ -18,11 +24,17 @@ var mp; var ma; var mo = { title: 'Last month', - curveType: 'function', + titleTextStyle: { + fontSize: 14 + }, + bar: { groupWidth: '90%' }, legend: { position: 'none' }, vAxis: { + title: 'kWh', viewWindowMode: 'maximized' - } + }, + tooltip: { trigger: 'none'}, + enableInteractivity: false, }; // Voltage plot @@ -328,8 +340,8 @@ var zeropad = function(num) { } var setupChart = function() { - ep = new google.visualization.LineChart(document.getElementById('ep')); - mp = new google.visualization.LineChart(document.getElementById('mp')); + ep = new google.visualization.ColumnChart(document.getElementById('ep')); + mp = new google.visualization.ColumnChart(document.getElementById('mp')); vp = new google.visualization.ColumnChart(document.getElementById('vp')); ap = new google.visualization.ColumnChart(document.getElementById('ap')); ip = new google.visualization.PieChart(document.getElementById('ip')); @@ -353,19 +365,19 @@ var drawEnergy = function() { timeout: 30000, dataType: 'json', }).done(function(json) { - data = [['Hour','Value']]; + data = [['Hour','kWh', { role: 'style' }, { role: 'annotation' }]]; var r = 1; var hour = moment.utc().hours(); var offset = moment().utcOffset()/60; var min = 0; for(var i = hour; i<24; i++) { var val = json["h"+zeropad(i)]; - data[r++] = [zeropad((i+offset)%24), val]; + data[r++] = [zeropad((i+offset)%24), val, "color: #6f42c1;opacity: 0.9;", val.toFixed(1)]; Math.min(0, val); }; for(var i = 0; i < hour; i++) { var val = json["h"+zeropad(i)]; - data[r++] = [zeropad((i+offset)%24), val]; + data[r++] = [zeropad((i+offset)%24), val, "color: #6f42c1;opacity: 0.9;", val.toFixed(1)]; Math.min(0, val); }; ea = google.visualization.arrayToDataTable(data); @@ -378,19 +390,19 @@ var drawEnergy = function() { timeout: 30000, dataType: 'json', }).done(function(json) { - data = [['Day','Value']]; + data = [['Day','kWh', { role: 'style' }, { role: 'annotation' }]]; var r = 1; var day = moment().date(); var start = moment().subtract(1, 'months').endOf('month').date(); var min = 0; for(var i = day; i<=start; i++) { var val = json["d"+zeropad(i)]; - data[r++] = [zeropad((i)), val]; + data[r++] = [zeropad((i)), val, "color: #6f42c1;opacity: 0.9;", val.toFixed(0)]; Math.min(0, val); } for(var i = 1; i < day; i++) { var val = json["d"+zeropad(i)]; - data[r++] = [zeropad((i)), val]; + data[r++] = [zeropad((i)), val, "color: #6f42c1;opacity: 0.9;", val.toFixed(0)]; Math.min(0, val); } ma = google.visualization.arrayToDataTable(data); @@ -535,21 +547,21 @@ var fetch = function() { t += u1; c++; var pct = (Math.max(parseFloat(json.u1)-195.5, 1)*100/69); - arr[r++] = ['L1', u1, voltcol(pct), u1 + "V"]; + arr[r++] = ['L1', u1, "color: " + voltcol(pct) + ";opacity: 0.9;", u1 + "V"]; } if(json.u2) { var u2 = parseFloat(json.u2); t += u2; c++; var pct = (Math.max(parseFloat(json.u2)-195.5, 1)*100/69); - arr[r++] = ['L2', u2, voltcol(pct), u2 + "V"]; + arr[r++] = ['L2', u2, "color: " + voltcol(pct) + ";opacity: 0.9;", u2 + "V"]; } if(json.u3) { var u3 = parseFloat(json.u3); t += u3; c++; var pct = (Math.max(parseFloat(json.u3)-195.5, 1)*100/69); - arr[r++] = ['L3', u3, voltcol(pct), u3 + "V"]; + arr[r++] = ['L3', u3, "color: " + voltcol(pct) + ";opacity: 0.9;", u3 + "V"]; } v = t/c; if(v > 0) { @@ -566,19 +578,19 @@ var fetch = function() { var i1 = parseFloat(json.i1); a = Math.max(a, i1); var pct = (parseFloat(json.i1)/parseInt(json.mf))*100; - arr[r++] = ['L1', pct, ampcol(pct), i1 + "A"]; + arr[r++] = ['L1', pct, "color: " + ampcol(pct) + ";opacity: 0.9;", i1 + "A"]; } if(json.i2) { var i2 = parseFloat(json.i2); a = Math.max(a, i2); var pct = (parseFloat(json.i2)/parseInt(json.mf))*100; - arr[r++] = ['L2', pct, ampcol(pct), i2 + "A"]; + arr[r++] = ['L2', pct, "color: " + ampcol(pct) + ";opacity: 0.9;", i2 + "A"]; } if(json.i3) { var i3 = parseFloat(json.i3); a = Math.max(a, i3); var pct = (parseFloat(json.i3)/parseInt(json.mf))*100; - arr[r++] = ['L3', pct, ampcol(pct), i3 + "A"]; + arr[r++] = ['L3', pct, "color: " + ampcol(pct) + ";opacity: 0.9;", i3 + "A"]; } if(a > 0) { aa = google.visualization.arrayToDataTable(arr); diff --git a/web/index.html b/web/index.html index f592339a..5bb427ab 100644 --- a/web/index.html +++ b/web/index.html @@ -56,7 +56,15 @@
Reactive
+
+
Instant
+
In
+
{Q} var
+
Out
+
{QO} var
+
+
Total
In
{tQI} kvarh
Out
@@ -64,29 +72,45 @@
-
+
-
In
-
{tQI} kvarh
-
Out
-
{tQO} kvarh
+
Instant reactive
+
In
+
{tQI} kvarh
+
Out
+
{tQO} kvarh
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
Total reactive
+
In
+
{tQI} kvarh
+
Out
+
{tQO} kvarh
+
+