Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
klaxsensor [2021/06/12 12:21] – angelegt Fabian Horst | klaxsensor [2021/12/04 12:53] (aktuell) – Fabian Horst | ||
---|---|---|---|
Zeile 3: | Zeile 3: | ||
* Hardware: [[https:// | * Hardware: [[https:// | ||
* Software: [[https:// | * Software: [[https:// | ||
+ | * Software Backup: [[https:// | ||
+ | * Grafana: [[http:// | ||
+ | * 28.09.2019 Mail von IoT Shop mit den Keys | ||
+ | * [[intern: | ||
+ | |||
+ | "Alter eigentlicher funktionierender Code": | ||
+ | < | ||
+ | 'use strict'; | ||
+ | |||
+ | /* | ||
+ | TTN decoder for KLAX LoRaWAN electricity meter sensors | ||
+ | © Tobias Schramm 2019 (tobias.schramm@t-sys.eu) (licensed under CC BY-NC-SA 4.0) | ||
+ | */ | ||
+ | |||
+ | var REGISTER_RAW = false; | ||
+ | var DEBUG = true; | ||
+ | |||
+ | function debug(msg) { | ||
+ | if(DEBUG) { | ||
+ | console.log(' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | function warning(msg) { | ||
+ | console.log(' | ||
+ | } | ||
+ | |||
+ | function error(msg) { | ||
+ | console.log(' | ||
+ | } | ||
+ | |||
+ | var METER_TYPES = [ | ||
+ | ' | ||
+ | 'IEC 62056-21 Mode B', | ||
+ | 'IEC 62056-21 Mode C', | ||
+ | ' | ||
+ | ]; | ||
+ | |||
+ | function parseHeader(data) { | ||
+ | var version = data[0]; | ||
+ | var batteryPerc = (data[1] & 0xf) * 10; | ||
+ | var meterType = METER_TYPES[(data[1] & 0x30) >> 4]; | ||
+ | var configured = (data[1] & 0x40) > 0; | ||
+ | var connTest = (data[1] & 0x80) > 0; | ||
+ | return { ' | ||
+ | } | ||
+ | |||
+ | var REGISTER_UNITS = [ | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ' | ||
+ | ]; | ||
+ | |||
+ | function exp2(power) { | ||
+ | return Math.pow(2, power); | ||
+ | } | ||
+ | |||
+ | function decodeUintN(data, | ||
+ | var val = 0; | ||
+ | var bytes = bits / 8; | ||
+ | for(var i = 0; i < bytes; i++) { | ||
+ | val += data[be ? bytes - 1 - i : i] * exp2(i * 8); | ||
+ | } | ||
+ | return val; | ||
+ | } | ||
+ | |||
+ | function decodeUint16BE(data) { | ||
+ | return decodeUintN(data, | ||
+ | } | ||
+ | |||
+ | function decodeIntN(data, | ||
+ | var val = 0; | ||
+ | var bytes = bits / 8; | ||
+ | for(var i = 0; i < bytes; i++) { | ||
+ | val += data[i] << ((be ? (bytes - 1 - i) : i) * 8); | ||
+ | } | ||
+ | return val; | ||
+ | } | ||
+ | |||
+ | function decodeInt32BE(data) { | ||
+ | return decodeIntN(data, | ||
+ | } | ||
+ | |||
+ | function mkRegister(data, | ||
+ | var unit = unitId < REGISTER_UNITS.length ? REGISTER_UNITS[unitId] : null; | ||
+ | var dataValid = false; | ||
+ | var values = [ ]; | ||
+ | while(data.length >= 4) { | ||
+ | if(REGISTER_RAW) { | ||
+ | var raw = data.slice(0, | ||
+ | var bytes = [ ]; | ||
+ | for(var i = 0; i < raw.length; i++) { | ||
+ | var val = raw[i]; | ||
+ | if(val !== 0) { | ||
+ | dataValid = true; | ||
+ | } | ||
+ | bytes.push(parseInt(val)); | ||
+ | } | ||
+ | values.push(bytes); | ||
+ | } else { | ||
+ | var val1 = decodeInt32BE(data); | ||
+ | if(val1 !== 0) { | ||
+ | dataValid = true; | ||
+ | } | ||
+ | values.push(val1); | ||
+ | } | ||
+ | data = data.slice(4); | ||
+ | } | ||
+ | dataValid = dataValid || lastValid; | ||
+ | return { ' | ||
+ | } | ||
+ | |||
+ | function decodeHistoric(data) { | ||
+ | var regmask = data[0]; | ||
+ | var reg1Active = (regmask & 0x01) > 0; | ||
+ | var reg1Filter = (regmask & 0x06) >> 1; | ||
+ | var reg1Valid = (regmask & 0x08) > 0; | ||
+ | var reg2Active = (regmask & 0x10) > 0; | ||
+ | var reg2Filter = (regmask & 0x60) >> 5; | ||
+ | var reg2Valid = (regmask & 0x80) > 0; | ||
+ | var units = data[1]; | ||
+ | var reg1Unit = units & 0x0f; | ||
+ | var reg2Unit = (units & 0xf0) >> 4; | ||
+ | data = data.slice(2); | ||
+ | var registers = [ ]; | ||
+ | if(reg1Active) { | ||
+ | var reg = mkRegister(data.slice(0, | ||
+ | reg.filterId = reg1Filter; | ||
+ | registers.push(reg); | ||
+ | } | ||
+ | data = data.slice(16); | ||
+ | if(reg2Active) { | ||
+ | var reg1 = mkRegister(data.slice(0, | ||
+ | reg1.filterId = reg2Filter; | ||
+ | registers.push(reg1); | ||
+ | } | ||
+ | return { ' | ||
+ | } | ||
+ | |||
+ | function decodeNow(data) { | ||
+ | var registers = [ ]; | ||
+ | for(var i = 0; i < 4; i++) { | ||
+ | var filterSet = (data[0] & (1<< | ||
+ | var filterValid = (data[0] & (1<< | ||
+ | var unitReg = data[i >= 2 ? 2 : 1]; | ||
+ | var unitId = (unitReg & (i % 2 === 0 ? 0x0f : 0xf0)) << ((i % 2) * 4); | ||
+ | var reg2 = mkRegister(data.slice(3 + (4 * i), 3 + (4 * (i + 1))), filterValid, | ||
+ | reg2.filterSet = filterSet; | ||
+ | reg2.filterValid = filterValid; | ||
+ | registers.push(reg2); | ||
+ | } | ||
+ | return { ' | ||
+ | } | ||
+ | |||
+ | function uint8ToHex(val) { | ||
+ | var hex = val.toString(16); | ||
+ | if(hex.length < 2) { | ||
+ | hex = ' | ||
+ | } | ||
+ | return hex; | ||
+ | } | ||
+ | |||
+ | function decodeServerID(data) { | ||
+ | var id = ''; | ||
+ | for(var i = 0; i < data.length; | ||
+ | id = id + uint8ToHex(data[i]); | ||
+ | } | ||
+ | return { ' | ||
+ | } | ||
+ | |||
+ | var PAYLOAD_HANDLERS = [ | ||
+ | { ' | ||
+ | { ' | ||
+ | { ' | ||
+ | ]; | ||
+ | |||
+ | function getHandler(data) { | ||
+ | var id = data[0]; | ||
+ | for(var i = 0; i < PAYLOAD_HANDLERS.length; | ||
+ | var handler = PAYLOAD_HANDLERS[i]; | ||
+ | if(handler.id == id) { | ||
+ | return handler; | ||
+ | } | ||
+ | } | ||
+ | return null; | ||
+ | } | ||
+ | |||
+ | function parsePayload(handler, | ||
+ | return handler.decode(data.slice(0, | ||
+ | } | ||
+ | |||
+ | function parseMsgInfo(data) { | ||
+ | var msgIdx = data[0]; | ||
+ | var msgCnt = data[1] & 0x0f; | ||
+ | var msgNum = (data[1] & 0xf0) >> 4; | ||
+ | return { ' | ||
+ | } | ||
+ | |||
+ | function parseApp(data) { | ||
+ | var header = parseHeader(data); | ||
+ | data = data.slice(2); | ||
+ | var msgInfo = parseMsgInfo(data); | ||
+ | data = data.slice(2); | ||
+ | debug(' | ||
+ | var payloads = [ ]; | ||
+ | while(data.length > 0) { | ||
+ | var handler = getHandler(data); | ||
+ | if(!handler) { | ||
+ | debug(' | ||
+ | break; | ||
+ | } | ||
+ | data = data.slice(1); | ||
+ | debug(' | ||
+ | payloads.push(parsePayload(handler, | ||
+ | data = data.slice(handler.len); | ||
+ | } | ||
+ | var appData = { ' | ||
+ | return appData; | ||
+ | } | ||
+ | |||
+ | function parseConfig(data) { | ||
+ | var header = parseHeader(data); | ||
+ | data = data.slice(2); | ||
+ | var measureInterval = decodeUint16BE(data); | ||
+ | return { ' | ||
+ | } | ||
+ | |||
+ | function parseInfo(data) { | ||
+ | var header = parseHeader(data); | ||
+ | data = data.slice(2); | ||
+ | var appMajorVersion = data[0]; | ||
+ | var appMinorVersion = data[1]; | ||
+ | return { ' | ||
+ | } | ||
+ | |||
+ | function parseRegisterDefs(data) { | ||
+ | var registers = [ ]; | ||
+ | while(data.length >= 3) { | ||
+ | var main = data[0]; | ||
+ | var major = data[1]; | ||
+ | var minor = data[2]; | ||
+ | registers.push({ ' | ||
+ | data = data.slice(3); | ||
+ | } | ||
+ | return registers; | ||
+ | } | ||
+ | |||
+ | function parseRegisterSearch(data) { | ||
+ | var header = parseHeader(data); | ||
+ | data = data.slice(2); | ||
+ | var msgInfo = parseMsgInfo(data); | ||
+ | data = data.slice(2); | ||
+ | return { ' | ||
+ | } | ||
+ | |||
+ | function parseRegisterSet(data) { | ||
+ | var header = parseHeader(data); | ||
+ | data = data.slice(2); | ||
+ | var activeFilters = data[0] & 0x0f; | ||
+ | data = data.slice(1); | ||
+ | var filters = parseRegisterDefs(data.slice(0, | ||
+ | for(var i = 0; i < filters.length; | ||
+ | filters[i].active = ((activeFilters & (1<< | ||
+ | } | ||
+ | return { ' | ||
+ | } | ||
+ | |||
+ | var DECODERS = [ | ||
+ | { ' | ||
+ | { ' | ||
+ | { ' | ||
+ | { ' | ||
+ | { ' | ||
+ | ]; | ||
+ | |||
+ | function getDecoder(port) { | ||
+ | for(var i = 0; i < DECODERS.length; | ||
+ | var decoder = DECODERS[i]; | ||
+ | if(decoder.port == port) { | ||
+ | return decoder; | ||
+ | } | ||
+ | } | ||
+ | return null; | ||
+ | } | ||
+ | |||
+ | function Decoder(bytes, | ||
+ | var decoder = getDecoder(port); | ||
+ | if(!decoder) { | ||
+ | warning(' | ||
+ | return { ' | ||
+ | } | ||
+ | if(bytes.len < decoder.minLen) { | ||
+ | warning(' | ||
+ | return { ' | ||
+ | } | ||
+ | return decoder.decode(bytes); | ||
+ | } | ||
+ | </ |