Skip to content

Instantly share code, notes, and snippets.

@fasmide
Last active December 19, 2015 08:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fasmide/96592c5cc690cd06c831 to your computer and use it in GitHub Desktop.
Save fasmide/96592c5cc690cd06c831 to your computer and use it in GitHub Desktop.
local units = ["", "Wh", "kWh", "MWh", "GWh", "j", "kj", "Mj",
"Gj", "Cal", "kCal", "Mcal", "Gcal", "varh",
"kvarh", "Mvarh", "Gvarh", "VAh", "kVAh",
"MVAh", "GVAh", "kW", "kW", "MW", "GW",
"kvar", "kvar", "Mvar", "Gvar", "VA", "kVA",
"MVA", "GVA", "V", "A", "kV", "kA", "C",
"K", "l", "m3", "l/h", "m3/h", "m3xC",
"ton", "ton/h", "h", "hh:mm:ss", "yy:mm:dd",
"yyyy:mm:dd", "mm:dd", "", "bar", "RTC",
"ASCII", "m3 x 10", "ton x 10", "GJ x 10",
"minutes", "Bitfield", "s", "ms", "days",
"RTC-Q", "Datetime"
]
local thingsToReceive = [
{
var = 0x000d,
name = "Energy in hi-res"
},
{
var = 0x041e,
name = "Voltage p1"
},
{
var = 0x041f,
name = "Voltage p2"
},
{
var = 0x0434,
name = "Current p1"
},
{
var = 0x0435,
name = "Current p2"
},
{
var = 0x0438,
name = "Power p1"
},
{
var = 0x0439,
name = "Power p2"
}
];
function isEscape(x) {
if(x == 0x06) {
return true;
}
if(x == 0x0d) {
return true;
}
if(x == 0x1b) {
return true;
}
if(x == 0x40) {
return true;
}
if(x == 0x80) {
return true;
}
return false;
}
function crc_1021(message) {
local poly = 0x1021;
local reg = 0x0000;
foreach(byte in message) {
local mask = 0x80;
while(mask > 0) {
//server.log(format("mask: %d",mask));
reg = reg << 1;
if(byte & mask) {
reg = reg | 1;
}
mask = mask >> 1
if(reg & 0x10000) {
reg = reg & 0xffff;
reg = reg ^ poly;
}
}
}
return reg;
}
function sendToKamstrup(pfx, msg) {
local b = msg;
b.append(0)
b.append(0)
local c = crc_1021(b)
b[b.len()-2] = c >> 8;
b[b.len()-1] = c & 0xff;
c = [];
c.append(pfx)
foreach(i in b) {
if(isEscape(i)) {
c.append(0x1b)
c.append(i ^ 0xff)
} else {
c.append(i);
}
}
c.append(0x0d);
foreach(send in c) {
hardware.uart57.write(send);
//server.log(send);
}
}
function recvKam() {
hardware.uart57.flush();
local b = [];
local readErrors = 0;
while(true) {
local d = hardware.uart57.read();
if(d == -1) {
readErrors++;
if(readErrors > 10) {
return null;
}
imp.sleep(0.02);
continue;
}
if(d == 0x40) {
b = [];
}
//server.log(format("in: %d", d));
b.append(d);
if(d == 0x0d) {
break;
}
}
local c = [];
local i = 1;
while(i < b.len() - 1) {
if(b[i] == 0x1b) {
local v = b[i + 1] ^ 0xff;
if(!isEscape(v)) {
server.log(format("Missing Escape %02x" % v));
}
c.append(v);
i += 2;
} else {
c.append(b[i]);
i += 1;
}
}
if(crc_1021(c)) {
server.log("CRC error");
}
return c;
}
function readvar(var) {
sendToKamstrup(0x80,[0x3f, 0x10, 0x01, (var >> 8), (var & 0xff)]);
local b = recvKam();
if(b == null) {
return {value = "TO", unit = "NA"};
}
if(b[0] != 0x3f || b[1] != 0x10) {
return {value = "NA", unit = "NA"};
}
if(b[2] != (var >> 8) || b[3] != (var & 0xff)) {
return {value = "NA", unit = "NA"};
}
local u = "None";
if(units[b[4]]) {
u = units[b[4]]
}
//Decode the mantissa
local x = 0
for (local i = 0; i < b[5]; i++) {
x = x << 8;
x = x | b[i + 7];
}
// Decode the exponent
local i = b[6] & 0x3f;
if(b[6] & 0x40) {
i = -i;
}
i = math.pow(10,i);
if(b[6] & 0x80) {
i = -i
}
x *= i
//return format("%g %s", x, u);
return {value = format("%g", x), unit = u};
}
function readEverything() {
nv.data = nv.data + format("%d,", time());
foreach(x in thingsToReceive) {
local response = readvar(x.var);
nv.data = nv.data + format("%s,", response.value);
imp.sleep(0.1) //give kamstrup time to recover..
}
nv.data = nv.data + "\n";
}
// configure a pin pair for UART TX/RX
hardware.uart57.configure(9600, 8, PARITY_NONE, 1, NO_CTSRTS);
t <- time();
function hourly() {
if(nv.data != "") {
local output = OutputPort("data", "string");
imp.configure("Kamstrup", [], [output]);
server.log("Sending data...");
local responseCode = output.set(nv.data);
if(responseCode != 0) {
if(responseCode == SEND_ERROR_NOT_CONNECTED) {
server.log("Send error not connected");
}
if(responseCode == SEND_ERROR_TIMEOUT) {
server.log("Send error timeout");
}
if(responseCode == SEND_ERROR_DISCONNECTED) {
server.log("The connection was disconnected before all data was sent to the server.");
}
}
server.log("Data sent... ");
if(server.flush(20)) {
server.log("Flush timed out");
}
} else {
server.log("Nothing to send, first boot?");
}
nv.data = "";
server.expectonlinein(3600);
//server.expectonlinein(120);
}
function log() {
if (!("nv" in getroottable())) {
nv <- { data = "" };
hourly();
}
local min = (t/60) % 60;
readEverything();
if (min == 59) {
hourly();
}
imp.onidle(function() { imp.deepsleepfor(60 - (time() % 60)); });
}
log();
/*local dog = 0;
function watchdog() {
server.show("Watchdog: " + dog.tostring());
dog++;
imp.wakeup(20, watchdog);
}
watchdog();*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment