//Parser version 1.0.0 /* Parser can used for Stella Pro devices Supported Software Versions: Base Software 1.33 (and older) Radio software 0.2.0 (and older) */ /* Changelog: 15-08-2025 First version of the parser */ const OFFSET_LOOKUP_TABLE = { "-5.0" : 0xf6, "-4.5" : 0xf7, "-4.0" : 0xf8, "-3.5" : 0xf9, "-3.0" : 0xfa, "-2.5" : 0xfb, "-2.0" : 0xfc, "-1.5" : 0xfd, "-1.0" : 0xfe, "-0.5" : 0xff, "0.0" : 0x00, "0.5" : 0x01, "1.0" : 0x02, "1.5" : 0x03, "2.0" : 0x04, "2.5" : 0x05, "3.0" : 0x06, "3.5" : 0x07, "4.0" : 0x08, "4.5" : 0x09, "5.0" : 0x0a, }; function setExternalTemperature(input){ let externalTempData = input.externalTemperatureValue; let output = []; if(externalTempData !== null){ output.push(0xe4); if(externalTempData=='disabled' || externalTempData == 0xff){ output.push(0xff); } else if(externalTempData != 0xff){ if(externalTempData >= 0 && externalTempData <= 50 ){ externalTempData = Math.floor(externalTempData*2); output.push(externalTempData); } else{ output.push(0xff); } } } return output; } function setValvePosition(input){ let currentPosition = input.currentValvePosition; let output = []; if(currentPosition !== null && currentPosition !== undefined && !isNaN(currentPosition)){ output.push(0xff); if(currentPosition > 0 && currentPosition < 256){ output.push(currentPosition.toString(16)); } else{ output.push(0x00); } output.push(0x00); } return output; } function setTemperature(input){ let output = []; output.push(0xf5); output.push(0x80); output.push(0x80); let heatingTemperature = Math.floor(input.heatingTemperature*2); if(heatingTemperature == null || heatingTemperature === undefined || heatingTemperature < 14 || heatingTemperature > 57){ heatingTemperature = 0x80; } output.push(heatingTemperature); let temperatureOffset = OFFSET_LOOKUP_TABLE[input.temperatureOffset]; if(input.temperatureOffset === undefined || input.temperatureOffset === null){ temperatureOffset = 0x80; } output.push(temperatureOffset); let windowOpenDetectionThreshold = Math.floor(input.windowDetectionThreshold); if(windowOpenDetectionThreshold === null || windowOpenDetectionThreshold === undefined || isNaN(windowOpenDetectionThreshold)){ windowOpenDetectionThreshold = 0x80; }else { if(windowOpenDetectionThreshold != 0xff && (windowOpenDetectionThreshold < 4 || windowOpenDetectionThreshold> 12)){ windowOpenDetectionThreshold = 0x80; } } output.push(windowOpenDetectionThreshold); let windowOpenDetectionDuration = input.windowDetectionDuration; if(windowOpenDetectionDuration=== null || windowOpenDetectionDuration === undefined || windowOpenDetectionDuration < 1 || windowOpenDetectionDuration > 30){ windowOpenDetectionDuration = 0x80; } output.push(windowOpenDetectionDuration); output.push(0x80); return output; } function setMaxValvePosition(input){ let output = []; let value = input.maxValvePositionLimitInPercent; output.push(0xE1); if(value >= 0 && value <= 100 && value !== null && !isNaN(value) && value !== undefined){ output.push(value); } else{ output.push(0x80); } return output; } function setWakeupInterval(input){ let intervall = input.wakeupIntervalInSeconds; let output = []; if(intervall >= 60 && intervall <= 7200 && intervall !== null && !isNaN(intervall) && intervall !== undefined){ output.push(0xA3); let lsb = (parseInt(intervall.toString(16),16) & 0xFF); let msb = (parseInt(intervall.toString(16),16) & 0xFF00) >> 8; output.push(lsb); output.push(msb); } return output; } function encodeDownlink(input) { let bytes = []; for(let key of Object.keys(input.data)){ switch(key){ case "getRadioSoftwareVersion": bytes.push(0xa0); break; case "getWakeupInterval": bytes.push(0xa4); break; case "setWakeupInterval": bytes = setWakeupInterval(input.data.setWakeupInterval); break; case "getMaxValvePositionLimit": bytes.push(0xe2); break; case "maxValvePositionLimit": bytes = setMaxValvePosition(input.data.maxValvePositionLimit); break; case "getExternalTemperatureValue": bytes.push(0xe3); break; case "externalTemperatureValue": bytes = setExternalTemperature(input.data); break; case "getSummary": bytes.push(0xe9); break; case "getBaseSoftwareVersion": bytes.push(0xef); break; case "getBatteryValue": bytes.push(0xf3); break; case "getTemperature": bytes.push(0xf4); break; case "temperature": bytes = setTemperature(input.data.temperature); break; case "getFlags": bytes.push(0xf6); break; case "getValvePosition": bytes.push(0xfe); break; case "valvePosition": bytes = setValvePosition(input.data.valvePosition); break; default: break; } } return { bytes: bytes, fPort: 2, warnings: [], errors: [] }; } function decodeDownlink(input) { return { data: { bytes: input.bytes }, warnings: [], errors: [] } }