Closed Flop2006 closed 8 years ago
See here: https://forum.pimatic.org/topic/1768/protocol-for-thermometer weather19.js:
module.exports = function(helper) { var protocolInfo, pulsesToBinaryMapping; pulsesToBinaryMapping = { '01': '0', '02': '1', '03': '' }; return protocolInfo = { name: 'weather19', type: 'weather', values: { temperature: { type: "number" }, id: { type: "number" }, channel: { type: "number" }, }, brands: ["Landmann BBQ Thermometer"], pulseLengths: [548, 1008, 1996, 3936], pulseCount: 66, decodePulses: function(pulses) { /* Pulse like: |020202010101|0101|01010101010101020101010102010201|0201010102010202|03| | 1 1 1 0 0 0| 0 0| 0 0 0 0 0 0 0 1 0 0 0 0 1 0 1 0| 1 0 0 0 1 0 1 1| | |ID | CH | Temperature |? | | |56 | 1 | 266(26.6) |? | | */ var binary, result; binary = helper.map(pulses, pulsesToBinaryMapping); return result = { id: helper.binaryToNumber(binary, 0, 5), temperature: helper.binaryToSignedNumber(binary, 8, 23) / 10, channel: helper.binaryToNumber(binary, 6, 7) + 1, }; } }; };
weather19.coffee:
module.exports = (helper) -> pulsesToBinaryMapping = { '01': '0' #binary 0 '02': '1' #binary 1 '03': '' #footer } return protocolInfo = { name: 'weather19' type: 'weather' values: temperature: type: "number" id: type: "number" channel: type: "number" brands: ["Landmann BBQ Thermometer"] pulseLengths: [548, 1008, 1996, 3936] pulseCount: 66 decodePulses: (pulses) -> # pulses is something like: '020202010101010101010101010101020101010102010201020101010201020203' # we first map the pulse sequences to binary binary = helper.map(pulses, pulsesToBinaryMapping) # binary is now something like: '11100000000000010000101010001011' # now we extract the temperature and humidity from that string #1110 0000 0000 0001 0000 1010 1000 1011 # IIII IICC TTTT TTTT TTTT TTTT xxxx xxxx #0 4 8 12 16 20 24 28 # I: Device ID, 6-bit unsigned Int # C: Channel (2 bits + 1, 00=1, 01=2, 10=3) # T: Temperature Value, 16-bit signed Int (divide decimal by 10) # x: Unused return result = { id: helper.binaryToNumber(binary, 0, 5) channel: helper.binaryToNumber(binary, 6, 7) + 1 temperature: helper.binaryToSignedNumber(binary, 8, 23) / 10 } }
lib-controller.coffee part
protocol: 'weather19' pulseLengths: [548, 1008, 1996, 3936] pulses: [ '020202010101010101010101010101020101010102010201020101010201020203' '020102020102010101010101010101020101020101020201010102020201020203' '020102020102010101010101010101020101020201010101020102010102010203' '020102020102010101010101010101020202010102020101020102010101010203' ] values: [ { id: 56, channel: 1, temperature: 26.6 } { id: 45, channel: 1, temperature: 29.4 } { id: 45, channel: 1, temperature: 30.4 } { id: 45, channel: 1, temperature: 46.0 } ] },
controller.js including changes for weather 17 and 18
var doesProtocolMatch, helper, protocols, sortIndices, __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; helper = require('./helper'); protocols = ['weather1', 'weather2', 'weather3', 'weather4', 'weather5', 'weather6', 'weather7', 'weather8', 'weather9', 'weather10', 'weather11', 'weather12', 'weather13', 'weather14', 'weather15', 'weather16', 'weather17', 'weather18', 'weather19', 'switch1', 'switch2', 'switch3', 'switch4', 'switch5', 'switch6', 'switch7', 'switch8', 'switch9', 'switch10', 'switch11', 'switch12', 'switch13', 'switch14', 'switch15', 'switch16', 'switch17', 'switch18', 'switch19', 'switch20', 'switch21', 'switch22', 'switch23', 'switch24', 'switch25', 'switch26', 'switch27', 'switch28', 'rolling1', 'dimmer1', 'dimmer2', 'pir1', 'pir2', 'pir3', 'pir4', 'pir5', 'contact1', 'contact2', 'contact3', 'generic', 'generic2', 'alarm1', 'alarm2', 'led1', 'led2', 'led3', 'led4', 'doorbell1', 'doorbell2', 'doorbell3', 'awning1', 'awning2', 'shutter1', 'shutter3', 'shutter4', 'shutter5', 'rawswitch']; protocols = protocols.map((function(_this) { return function(p) { return require("./protocols/" + p)(helper); }; })(this)); doesProtocolMatch = function(pulseLengths, pulses, protocol) { var i, maxDelta, _ref; if (protocol.pulseCounts != null) { if (_ref = pulses.length, __indexOf.call(protocol.pulseCounts, _ref) < 0) { return false; } } else { if (pulses.length !== protocol.pulseCount) { return false; } } if (pulseLengths.length !== protocol.pulseLengths.length) { return false; } i = 0; while (i < pulseLengths.length) { maxDelta = pulseLengths[i] * 0.4; if (Math.abs(pulseLengths[i] - protocol.pulseLengths[i]) > maxDelta) { return false; } i++; } return true; }; sortIndices = function(array) { var e, i, indices, j, tuple, tuples, _i, _j, _len, _len1; tuples = new Array(array.length); for (i = _i = 0, _len = array.length; _i < _len; i = ++_i) { e = array[i]; tuples[i] = [e, i]; } tuples.sort(function(left, right) { if (left[0] < right[0]) { return -1; } else { return 1; } }); indices = new Array(array.length); for (j = _j = 0, _len1 = tuples.length; _j < _len1; j = ++_j) { tuple = tuples[j]; indices[tuple[1]] = j; } return indices; }; module.exports = { debug: false, compressTimings: function(timings) { var bucket, buckets, counts, hasMatch, i, j, pulses, sums, timing, _i, _j, _k, _len, _len1, _len2; pulses = ''; buckets = []; sums = []; counts = []; for (i = _i = 0, _len = timings.length; _i < _len; i = ++_i) { timing = timings[i]; hasMatch = false; for (j = _j = 0, _len1 = buckets.length; _j < _len1; j = ++_j) { bucket = buckets[j]; if (Math.abs(bucket - timing) < bucket * 0.5) { pulses += j; sums[j] += timing; counts[j]++; hasMatch = true; } } if (!hasMatch) { pulses += buckets.length; buckets.push(timing); sums.push(timing); counts.push(1); } } for (j = _k = 0, _len2 = buckets.length; _k < _len2; j = ++_k) { bucket = buckets[j]; buckets[j] = Math.round(sums[j] / counts[j]); } return { buckets: buckets, pulses: pulses }; }, prepareCompressedPulses: function(input) { var parts, pulseLengths, pulses; parts = input.split(' '); pulseLengths = parts.slice(0, 8); pulses = parts[8]; pulseLengths = pulseLengths.filter(function(puls) { return puls !== '0'; }).map(function(puls) { return parseInt(puls, 10); }); return this.sortCompressedPulses(pulseLengths, pulses); }, sortCompressedPulses: function(pulseLengths, pulses) { var sortedIndices; sortedIndices = sortIndices(pulseLengths); pulseLengths.sort(function(l, r) { return l - r; }); pulses = helper.mapByArray(pulses, sortedIndices); return { pulseLengths: pulseLengths, pulses: pulses }; }, fixPulses: function(pulseLengths, pulses) { var i, newPulseLength, newPulseLengths, newPulses; if (pulseLengths.length <= 3) { return null; } i = 1; while (i < pulseLengths.length) { if (pulseLengths[i - 1] * 2 < pulseLengths[i]) { i++; continue; } newPulseLength = Math.floor((pulseLengths[i - 1] + pulseLengths[i]) / 2); newPulseLengths = pulseLengths.slice(); newPulseLengths.splice(i - 1, 2, newPulseLength); break; } if (i === pulseLengths.length) { return null; } newPulses = pulses; while (i < pulseLengths.length) { newPulses = newPulses.replace(new RegExp("" + i, 'g'), "" + (i - 1)); i++; } return { pulseLengths: newPulseLengths, pulses: newPulses }; }, decodePulses: function(pulseLengths, pulses) { var err, fixed, p, results, values, _i, _len; results = []; for (_i = 0, _len = protocols.length; _i < _len; _i++) { p = protocols[_i]; if (doesProtocolMatch(pulseLengths, pulses, p)) { try { values = p.decodePulses(pulses); results.push({ protocol: p.name, values: values }); } catch (_error) { err = _error; if (this.debug) { if (err instanceof helper.ParsingError) { console.log("Warning trying to parse message with protocol " + p.name + ": " + err.message); console.log("" + (err.stack.split("\n")[2])); } else { throw err; } } } } } fixed = this.fixPulses(pulseLengths, pulses); if (fixed == null) { return results; } return results.concat(this.decodePulses(fixed.pulseLengths, fixed.pulses)); }, encodeMessage: function(protocolName, message) { var p, protocol, _i, _len; protocol = null; for (_i = 0, _len = protocols.length; _i < _len; _i++) { p = protocols[_i]; if (p.name === protocolName) { protocol = p; break; } } if (protocol == null) { throw new Error("Could not find a protocol named " + protocolName); } if (protocol.encodeMessage == null) { throw new Error("The protocol has no send report."); } return { pulses: protocol.encodeMessage(message), pulseLengths: protocol.pulseLengths }; }, getAllProtocols: function() { return protocols; }, getProtocol: function(protocolName) { var p, _i, _len; for (_i = 0, _len = protocols.length; _i < _len; _i++) { p = protocols[_i]; if (p.name === protocolName) { return p; } } return null; } };
Excellent! Thank you very much for your contribution. I am going to integrate this asap.
released rfcontroljs@0.0.56, homeduino@0.0.62, pimatic-homeduino@0.9.10
See here: https://forum.pimatic.org/topic/1768/protocol-for-thermometer weather19.js:
weather19.coffee:
lib-controller.coffee part
controller.js including changes for weather 17 and 18