Some changes after testing

This commit is contained in:
Gunnar Skjold 2021-11-30 08:01:20 +01:00
parent f425abb52d
commit ab101c8622
8 changed files with 106 additions and 41 deletions

View File

@ -5,12 +5,14 @@
#include <Timezone.h>
enum AmsType {
AmsTypeAutodetect = 0x00,
AmsTypeAidon = 0x01,
AmsTypeKaifa = 0x02,
AmsTypeKamstrup = 0x03,
AmsTypeIskra = 0x08,
AmsTypeLandis = 0x09,
AmsTypeSagemcom = 0x0A,
AmsTypeCustom = 0x88,
AmsTypeUnknown = 0xFF
};

View File

@ -689,6 +689,9 @@ void readHanPort() {
}
return;
}
for(int i = len; i<BUF_SIZE; i++) {
buf[i] = 0x00;
}
if(pos == HDLC_ENCRYPTION_CONFIG_MISSING) {
hc = new HDLCConfig();
memcpy(hc->encryption_key, meterConfig.encryptionKey, 16);

View File

@ -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);

View File

@ -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;
}

View File

@ -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

View File

@ -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");

View File

@ -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);

View File

@ -56,7 +56,15 @@
<div class="col-sm-6 mb-3" style="display: {dn};">
<div class="bg-white rounded shadow p-3" style="display: {da};">
<h5 class="text-center">Reactive</h5>
<div class="row rri">
<div class="col-12 font-weight-bold">Instant</div>
<div class="col-4">In</div>
<div class="col-8 text-right"><span class="jri">{Q}</span> var</div>
<div class="col-4">Out</div>
<div class="col-8 text-right"><span class="jre">{QO}</span> var</div>
</div>
<div class="row rric">
<div class="col-12 font-weight-bold">Total</div>
<div class="col-4">In</div>
<div class="col-8 text-right"><span class="jric">{tQI}</span> kvarh</div>
<div class="col-4">Out</div>
@ -64,29 +72,45 @@
</div>
</div>
</div>
<div class="col-sm-12 mb-3" style="display: {de};">
<div class="col-12 mb-3" style="display: {de};">
<div class="bg-white rounded shadow p-3" style="display: {da};">
<div class="row rrec">
<div class="col-4 col-sm-2">In</div>
<div class="col-8 col-sm-4 text-right"><span class="jric">{tQI}</span> kvarh</div>
<div class="col-4 col-sm-2">Out</div>
<div class="col-8 col-sm-4 text-right"><span class="jrec">{tQO}</span> kvarh</div>
<div class="col-sm-4 font-weight-bold">Instant reactive</div>
<div class="col-4 col-sm-1">In</div>
<div class="col-8 col-sm-3 text-right"><span class="jric">{tQI}</span> kvarh</div>
<div class="col-4 col-sm-1">Out</div>
<div class="col-8 col-sm-3 text-right"><span class="jrec">{tQO}</span> kvarh</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-3 col-sm-6 mb-3">
<div class="bg-white rounded shadow p-3">
<div class="text-center">
<div id="vp" class="plot2"></div>
<div class="col-lg-6">
<div class="row">
<div class="col-sm-6 mb-3">
<div class="bg-white rounded shadow p-3">
<div class="text-center">
<div id="vp" class="plot2"></div>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-3 col-sm-6 mb-3">
<div class="bg-white rounded shadow p-3">
<div class="text-center">
<div id="ap" class="plot2"></div>
<div class="col-sm-6 mb-3">
<div class="bg-white rounded shadow p-3">
<div class="text-center">
<div id="ap" class="plot2"></div>
</div>
</div>
</div>
<div class="col-12 mb-3" style="display: {de};">
<div class="bg-white rounded shadow p-3" style="display: {da};">
<div class="row rrec">
<div class="col-sm-4 font-weight-bold">Total reactive</div>
<div class="col-4 col-sm-1">In</div>
<div class="col-8 col-sm-3 text-right"><span class="jric">{tQI}</span> kvarh</div>
<div class="col-4 col-sm-1">Out</div>
<div class="col-8 col-sm-3 text-right"><span class="jrec">{tQO}</span> kvarh</div>
</div>
</div>
</div>
</div>
</div>