UNPKG

@1st-setup/cul

Version:

Module to interact with Busware CUL / culfw

298 lines (257 loc) 7.14 kB
'use strict'; /** * * FHT parse and cmd * * 11'2017 timroemisch https://github.com/timroemisch * GPL v2 * * based on * https://svn.fhem.de/trac/browser/trunk/fhem/FHEM/11_FHT.pm * */ var codes = { "00": "actuator", "01": "actuator1", "02": "actuator2", "03": "actuator3", "04": "actuator4", "05": "actuator5", "06": "actuator6", "07": "actuator7", "08": "actuator8", "14": "mon-from1", "15": "mon-to1", "16": "mon-from2", "17": "mon-to2", "18": "tue-from1", "19": "tue-to1", "1a": "tue-from2", "1b": "tue-to2", "1c": "wed-from1", "1d": "wed-to1", "1e": "wed-from2", "1f": "wed-to2", "20": "thu-from1", "21": "thu-to1", "22": "thu-from2", "23": "thu-to2", "24": "fri-from1", "25": "fri-to1", "26": "fri-from2", "27": "fri-to2", "28": "sat-from1", "29": "sat-to1", "2a": "sat-from2", "2b": "sat-to2", "2c": "sun-from1", "2d": "sun-to1", "2e": "sun-from2", "2f": "sun-to2", "3e": "mode", "3f": "holiday1", // Not verified "40": "holiday2", // Not verified "41": "desired-temp", "42": "measured-low", "43": "measured-high", "44": "warnings", "45": "manu-temp", // No clue what it does. "4b": "ack", "53": "can-xmit", "54": "can-rcv", "60": "year", "61": "month", "62": "day", "63": "hour", "64": "minute", "65": "report1", "66": "report2", "69": "ack2", "7d": "start-xmit", "7e": "end-xmit", "82": "day-temp", "84": "night-temp", "85": "lowtemp-offset", // Alarm-Temp.-Differenz "8a": "windowopen-temp" }; var warnings = [ 'OK', 'BATT LOW', 'TEMP LOW', 'WINDOW OPEN', 'WINDOW ERR' ]; var readonly = [ "actuator", "actuator1", "actuator2", "actuator3", "actuator4", "actuator5", "actuator6", "actuator7", "actuator8", "ack", "ack2", "battery", "can-xmit", "can-rcv", "start-xmit", "end-xmit", "lowtemp", "measured-temp", "measured-high", "measured-low", "warnings", "window", "windowsensor" ]; module.exports.parse = function(raw) { var message = {} message.protocol = 'FHT'; raw = raw.toLowerCase(); message.address = raw.slice(1, 5); message.data = {}; message.data.cmdRaw = raw.slice(5, 7); message.data.addressCode = parseInt(message.address.slice(0, 2), 16) * 100 + parseInt(message.address.slice(2, 4), 16); message.data.cmd = codes[message.data.cmdRaw] ? codes[message.data.cmdRaw] : "UNKNOWN"; message.data.valueRaw = raw.slice(9, 11); // convert hex String to int var intCmd = parseInt(message.data.cmdRaw, 16); var intVal = parseInt(message.data.valueRaw, 16); // message.data.valueRawInt = intVal; // convert some known cmd´s // and save it in value switch (message.data.cmd) { case 'night-temp': case 'day-temp': case 'windowopen-temp': case 'desired-temp': message.data.value = intVal / 2; break; case 'measured-low': message.data.value = intVal * 0.1; break; case 'measured-high': message.data.value = intVal * 25.5; break; case 'warnings': message.data.value = warnings[intVal] ? warnings[intVal] : "UNKNOWN"; break; case 'mode': message.data.value = intVal == 0 ? "AUTO" : "MANU"; break; } // check if the weekly program is send if (intCmd >= 20 && intCmd <= 47) { var hour = Math.floor(intVal / 6); var minute = intVal - (hour * 6); message.data.value = hour + ':' + minute + '0'; // add everything together } // make every value to string if (message.data.value) { message.data.value = message.data.value.toString(); } return message; }; /** * * fht.cmd * * @param centralCode string, the 'central code' - 4 digits hex string * @param device string, the 'device code' - 4 digits elv-notation string * @param command string, cmd text or 2 digits hex string * @param value string, if command is a text then you can write formatted values * like '21.5', 'AUTO' etc... (just like the parse function is outputting), * but if the command is not found you have to write it in a 2 digit hex string * @returns object string (the raw message) or boolean false (on error) * */ module.exports.cmd = function(centralCode, device, command, value) { var setCC = "T01" + centralCode.toUpperCase() + "\n"; // command for setting the cc // parts of the output string var deviceCode, cmd, cmdIsKnown, val; device = device.toUpperCase(); // convert to hex deviceCode = [device.slice(0, 2), device.slice(2, 4)]; deviceCode[0] = parseInt(deviceCode[0]).toString(16); deviceCode[1] = parseInt(deviceCode[1]).toString(16); // check if command is hex if (command.length == 2 && !isNaN(parseInt(command, 16))) { cmdIsKnown = codes[command.toLowerCase()] ? true : false; cmd = command.toUpperCase(); // save the given hex code } // check if command exists else if (codes.getKeyByValue(command) != undefined) { var strCode = codes.getKeyByValue(command); // and if it exists, check if it doesn´t exists in the readonly array if (readonly.indexOf(command) == -1) { cmd = strCode.toUpperCase(); // and save in cmd the hex code cmdIsKnown = true; } // if anything has an error -> exit else return false; } else return false; // check if command is hex if (value.length == 2 && !isNaN(parseInt(value, 16))) { val = value.toUpperCase(); } // when we know the command we can format the value else if (cmdIsKnown) { var strCmd = codes[cmd.toLowerCase()]; // save command string in strCmd switch (strCmd) { case 'night-temp': case 'day-temp': case 'windowopen-temp': case 'desired-temp': val = (roundHalf(parseFloat(value)) * 2).toString(16).toUpperCase(); break; case 'mode': if (value == 'AUTO') val = '00'; else if (value == 'MANU') val = '01'; else return false; break; default: var intCmd = parseInt(cmd, 16); // weekly program if (intCmd >= 20 && intCmd <= 47) { var time = value.split(":"); time[0] = parseInt(time[0]); time[1] = parseInt(time[1]); // check for correctness of the time format if (time.length != 2 || isNaN(time[0]) || isNaN(time[1]) ||   !(time[0] < 23 && time[0] > 0 && time[1] < 60 && time[1] > 0)) return false; time[1] = Math.floor(time[1] / 10); // keep only the tens of the minutes // convert hour and minutes to convTime var convTime = Math.floor(time[0] * 6); convTime += time[1]; val = convTime.toString(16).toUpperCase(); } // no other cmd is found -> error else { console.log("the command '" + strCmd + "' can´t be converted, please write the value in a hexadecimal form"); return false; } } } // we dont know how the value is formatted else { console.log("couldn´t format the value"); return false; } // put the string together var sendString = 'T' + deviceCode[0] + deviceCode[1] + cmd + val; // return the cmd to change the Central Code and the actual cmd return setCC + sendString; }; Object.prototype.getKeyByValue = function(value) { for (var prop in this) { if (this.hasOwnProperty(prop)) { if (this[prop] === value) return prop; } } } var roundHalf = function(n) { return (Math.round(n * 2) / 2).toFixed(1); };