const SETTINGS_HEADER = 0x3E; function bool(a) { return a[0] ? "true" : "false"; } function uint(a) { if(a.length == 1) return a[0]; if(a.length == 2) return (a[0]<<8)|a[1]; if(a.length == 4) return (a[0]<<24)|(a[1]<<16)|(a[2]<<8)|a[3]; return a; } function extcfg(a) { var cfg = a[0]; switch(cfg) { case 1: return "Analog"; case 2: return "Pulse (pulldown)"; case 3: return "Pulse (pullup)"; case 4: return "Abs pulse (pulldown)"; case 5: return "Abs pulse (pullup)"; case 6: return "1-wire temp DS18B20"; case 7: return "Switch NO"; case 8: return "Switch NC"; case 9: return "Digital"; case 10: return "SRF-01"; case 11: return "Decagon"; case 12: return "Waterleak"; case 13: return "Maxbotix ML738x"; case 14: return "GPS"; case 15: return "1-wire temp + Switch NO"; case 16: return "Analog 0-3V"; case 17: return "ADC module (pt1000)"; } return a; } function sensor(a) { var t = a[0]; switch(t) { case 0: return "Unknown"; case 1: return "ESM5k"; case 10: return "ELT1"; case 11: return "ELT1HP"; case 12: return "ELT2HP"; case 13: return "ELT Lite"; case 20: return "ERS"; case 21: return "ERS CO2"; case 22: return "ERS Lite"; case 23: return "ERS Eye"; case 24: return "ERS Desk"; case 25: return "ERS Sound"; case 30: return "EMS"; } return a; } const settings = [ {size: 16, type: 1, name: 'AppSKey', hex:true, parse: null}, {size: 16, type: 2, name: 'NwkSKey', hex:true, parse: null}, {size: 16, type: 4, name: 'AppEui', hex:true, parse: null}, {size: 4, type: 6, name: 'DevAddr', hex:true, parse: null}, {size: 1, type: 7, name: 'OTA', parse: bool}, {size: 1, type: 8, name: 'Port', parse: uint}, {size: 1, type: 9, name: 'Mode', parse: uint}, {size: 1, type: 10, name: 'ACK', parse: bool}, {size: 1, type: 11, name: 'DrDef', parse: uint}, {size: 1, type: 13, name: 'DrMin', parse: uint}, {size: 1, type: 12, name: 'DrMax', parse: uint}, {size: 1, type: 16, name: 'ExtCfg', parse: extcfg}, {size: 1, type: 17, name: 'PirCfg', parse: uint}, {size: 1, type: 18, name: 'Co2Cfg', parse: uint}, {size: 4, type: 19, name: 'AccCfg', parse: null}, {size: 4, type: 20, name: 'SplPer', parse: uint}, {size: 4, type: 21, name: 'TempPer', parse: uint}, {size: 4, type: 22, name: 'RhPer', parse: uint}, {size: 4, type: 23, name: 'LightPer', parse: uint}, {size: 4, type: 24, name: 'PirPer', parse: uint}, {size: 4, type: 25, name: 'Co2Per', parse: uint}, {size: 4, type: 26, name: 'ExtPer', parse: uint}, {size: 4, type: 27, name: 'ExtPwrTime', parse: uint}, {size: 4, type: 28, name: 'TriggTime', parse: uint}, {size: 4, type: 29, name: 'AccPer', parse: uint}, {size: 4, type: 30, name: 'VddPer', parse: uint}, {size: 4, type: 31, name: 'SendPer', parse: uint}, {size: 4, type: 32, name: 'Lock', parse: uint}, {size: 4, type: 34, name: 'Link', parse: null}, {size: 4, type: 33, name: 'KeyWdg', parse: uint}, {size: 4, type: 35, name: 'PressPer', parse: uint}, {size: 4, type: 36, name: 'SoundPer', parse: uint}, {size: 1, type: 37, name: 'Plan', parse: uint}, {size: 1, type: 38, name: 'SubBand', parse: uint}, {size: 1, type: 39, name: 'LBT', parse: bool}, {size: 1, type: 40, name: 'LedConfig', parse: uint}, {size: 4, type: 42, name: 'WaterPer', parse: uint}, {size: 4, type: 43, name: 'ReedPer', parse: uint}, {size: 4, type: 44, name: 'ReedCfg', parse: uint}, {size: 1, type: 45, name: 'PirSens', parse: uint}, {size: 1, type: 46, name: 'QSize', parse: uint}, {size: 1, type: 47, name: 'QOffset', parse: bool}, {size: 1, type: 48, name: 'QPurge', parse: bool}, {size: 4, type: 240, name: 'C1', parse: uint}, {size: 4, type: 241, name: 'C2', parse: uint}, {size: 4, type: 242, name: 'C3', parse: uint}, {size: 4, type: 243, name: 'C4', parse: uint}, {size: 1, type: 244, name: 'NFCDisable', parse: bool}, {size: 1, type: 245, name: 'Sensor', parse: sensor}, {size: 1, type: 250, name: 'External', parse: null}, {size: 2, type: 251, name: 'Version', parse: uint}, {size: 4, type: 252, name: 'Sleep', parse: null}, //{size: 0, type: 253, name: 'Generic', parse: null}, {size: 0, type: 254, name: 'Reboot', parse: null} ]; function DecodeElsysSettings(input) { var bytes = []; if (Array.isArray(input)) { if (input.length > 0 && typeof input[0] == "number") { bytes = input; } else { return makeError("unknown input type; array with non-number elements"); } } else if (typeof input == "string") { var result = []; while (input.length >= 2) { result.push(parseInt(input.substring(0, 2), 16)); input = input.substring(2, input.length); } bytes = result; } else { return makeError("unknown input type; not array nor string"); } var payload = {}; var i = 0; if(bytes[i++] != SETTINGS_HEADER) { return makeError("incorrect header"); } var size = bytes[i++]; while (i < bytes.length) { var type = bytes[i++]; var setting = settings.filter(function(s) { return s.type == type; }); if(setting.length == 0) { return makeError("unknown setting type; " + type + " at offset " + i); } setting = setting[0]; var d = bytes.slice(i, i+setting.size); console.debug("consuming [" + d + "] for setting " + setting.name); if(setting.parse == null) { payload[setting.name] = d; } else { payload[setting.name] = setting.parse(d); } i += setting.size; } return { "settings": payload }; } function makeError(desc) { return { "error": desc }; } document.getElementById("convert").onclick = function() { var res = DecodeElsysSettings(document.getElementById("inputData").value.replace(/[ _-]/g,'')); var json = JSON.stringify(res, null, 4); document.getElementById("result").innerHTML = json; };