UNPKG

node-red-contrib-knx-ultimate

Version:

Control your KNX intallation via Node-Red! Single Node KNX IN/OUT with optional ETS group address importer. Easy to use and highly configurable.

213 lines (184 loc) 6.11 kB
/** * KNXEngine - a KNX protocol stack in Javascript * (C) 2020-2022 Supergiovane */ const knxLog = require('./../KnxLog'); // // DPT9.*: 2-byte floating point value // const util = require('util'); // kudos to http://croquetweak.blogspot.gr/2014/08/deconstructing-floats-frexp-and-ldexp.html function ldexp(mantissa, exponent) { return exponent > 1023 // avoid multiplying by infinity ? mantissa * Math.pow(2, 1023) * Math.pow(2, exponent - 1023) : exponent < -1074 // avoid multiplying by zero ? mantissa * Math.pow(2, -1074) * Math.pow(2, exponent + 1074) : mantissa * Math.pow(2, exponent); } function frexp(value) { if (value === 0) return [value, 0]; var data = new DataView(new ArrayBuffer(8)); data.setFloat64(0, value); var bits = (data.getUint32(0) >>> 20) & 0x7FF; if (bits === 0) { data.setFloat64(0, value * Math.pow(2, 64)); bits = ((data.getUint32(0) >>> 20) & 0x7FF) - 64; } var exponent = bits - 1022, mantissa = ldexp(value, -exponent); return [mantissa, exponent]; } exports.formatAPDU = function (value) { var apdu_data = Buffer.alloc(2); if (!isFinite(value)) { knxLog.get().warn("DPT9: cannot write non-numeric or undefined value"); } else { var arr = frexp(value); var mantissa = arr[0], exponent = arr[1]; // find the minimum exponent that will upsize the normalized mantissa (0,5 to 1 range) // in order to fit in 11 bits ([-2048, 2047]) max_mantissa = 0; for (e = exponent; e >= -15; e--) { max_mantissa = ldexp(100 * mantissa, e); if (max_mantissa > -2048 && max_mantissa < 2047) break; } var sign = (mantissa < 0) ? 1 : 0 var mant = (mantissa < 0) ? ~(max_mantissa ^ 2047) : max_mantissa var exp = exponent - e; // yucks apdu_data[0] = (sign << 7) + (exp << 3) + (mant >> 8); apdu_data[1] = mant % 256; } return apdu_data; } exports.fromBuffer = function (buf) { if (buf.length != 2) { knxLog.get().warn("DPT9.fromBuffer: buf should be 2 bytes long (got %d bytes)", buf.length); return null; } else { var sign = buf[0] >> 7; var exponent = (buf[0] & 0b01111000) >> 3; var mantissa = 256 * (buf[0] & 0b00000111) + buf[1]; mantissa = (sign == 1) ? ~(mantissa ^ 2047) : mantissa; return parseFloat(ldexp((0.01 * mantissa), exponent).toPrecision(15)); } } // DPT9 basetype info exports.basetype = { "bitlength": 16, "valuetype": "basic", "desc": "16-bit floating point value", "help": `// Send 16-bit floating point value. msg.payload = 25; return msg;` } // DPT9 subtypes exports.subtypes = { // 9.001 temperature (oC) "001": { "name": "Temperature (°C)", "desc": "temperature", "unit": "°C", "range": [-273, 670760] }, // 9.002 temperature difference (oC) "002": { "name": "Temperature difference (°C)", "desc": "temperature difference", "unit": "°C", "range": [-670760, 670760] }, // 9.003 kelvin/hour (K/h) "003": { "name": "Kelvin/hour (K/h)", "desc": "kelvin/hour", "unit": "°K/h", "range": [-670760, 670760] }, // 9.004 lux (Lux) "004": { "name": "Lux (lux)", "desc": "lux", "unit": "lux", "range": [0, 670760] }, // 9.005 speed (m/s) "005": { "name": "Speed (m/s)", "desc": "wind speed", "unit": "m/s", "range": [0, 670760] }, // 9.006 pressure (Pa) "006": { "name": "Pressure (Pa)", "desc": "pressure", "unit": "Pa", "range": [0, 670760] }, // 9.007 humidity (%) "007": { "name": "Humidity (%)", "desc": "humidity", "unit": "%", "range": [0, 670760] }, // 9.008 parts/million (ppm) "008": { "name": "Parts/million (ppm)", "desc": "air quality", "unit": "ppm", "range": [0, 670760] }, // 9.010 time (s) "010": { "name": "Time (s)", "desc": "time(sec)", "unit": "s", "range": [-670760, 670760] }, // 9.011 time (ms) "011": { "name": "Time (ms)", "desc": "time(msec)", "unit": "ms", "range": [-670760, 670760] }, // 9.020 voltage (mV) "020": { "name": "Voltage (mV)", "desc": "voltage", "unit": "mV", "range": [-670760, 670760] }, // 9.021 current (mA) "021": { "name": "Current (mA)", "desc": "current", "unit": "mA", "range": [-670760, 670760] }, // 9.022 power density (W/m2) "022": { "name": "Power density (W/m²)", "desc": "power density", "unit": "W/m²", "range": [-670760, 670760] }, // 9.023 kelvin/percent (K/%) "023": { "name": "Kelvin/percent (K/%)", "desc": "Kelvin / %", "unit": "K/%", "range": [-670760, 670760] }, // 9.024 power (kW) "024": { "name": "Power (kW)", "desc": "power (kW)", "unit": "kW", "range": [-670760, 670760] }, // 9.025 volume flow (l/h) "025": { "name": "Volume flow (l/h)", "desc": "volume flow", "unit": "l/h", "range": [-670760, 670760] }, // 9.026 rain amount (l/m2) "026": { "name": "Rain amount (l/m²)", "desc": "rain amount", "unit": "l/m²", "range": [-670760, 670760] }, // 9.027 temperature (Fahrenheit) "027": { "name": "Temperature (Fahrenheit)", "desc": "temperature (F)", "unit": "°F", "range": -[459.6, 670760] }, // 9.028 wind speed (km/h) "028": { "name": "Wind speed (km/h)", "desc": "wind speed (km/h)", "unit": "km/h", "range": [0, 670760] }, // 9.029 wind speed (km/h) "029": { "name": "Absolute humidity (g/m3)", "desc": "absolute humidity (g/m3)", "unit": "g/m3", "range": [0, 670760] }, // 9.030 concentration (ug/m3) "030": { "name": "Concentration (ug/m3)", "desc": "concentration (ug/m3)", "unit": "ug/m3", "range": [0, 670760] } }