Created
December 10, 2018 17:46
-
-
Save btsimonh/f8f8227d8fa53ec9eb3a2d9bd6512192 to your computer and use it in GitHub Desktop.
fixed dev flow for EQ3 TRV
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| [{"id":"d9611430.c0dd78","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"f13a5e82.66c6","type":"inject","z":"d9611430.c0dd78","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":100,"y":100,"wires":[["81d1f125.7392"]]},{"id":"869cb11a.bc68e","type":"inject","z":"d9611430.c0dd78","name":"","topic":"","payload":"{\"names\":{\"00:1a:22:09:2c:db\":\"Living Room 1\",\"00:1a:22:09:2c:9a\":\"Living Room 2\",\"00:1a:22:09:2c:df\":\"Conservatory\",\"00:1a:22:09:08:37\":\"Office\",\"00:1a:22:09:2f:b7\":\"Dining\",\"00:1a:22:09:2f:06\":\"Utility\",\"00:1a:22:09:2f:ab\":\"Kathryn\",\"00:1a:22:09:2e:e0\":\"Jess\",\"00:1a:22:08:5b:1e\":\"MasterBed\"}}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":40,"wires":[["f77a8453.c541d8"]]},{"id":"f77a8453.c541d8","type":"function","z":"d9611430.c0dd78","name":"start","func":"var require = global.get('require');\n\nvar eq3interface = require('/home/pi/.node-red/node_modules/node-red-contrib-eq3-bluetooth/lib/eq3interface.js');\nvar noble = require('noble');\n//NobleDevice.prototype.SCAN_DUPLICATES = true;\n\nvar eq = global.get('eq');\n\nif (!eq){\n e = function() {\n \n var eq3 = require('/home/pi/.node-red/node_modules/node-red-contrib-eq3-bluetooth/lib/eq3device.js');\n eq3info = {\n eq3: eq3,\n devices: {},\n names:{},\n info:{}\n };\n \n var geteq3info = function() {\n return eq3info; \n };\n return geteq3info;\n };\n \n eq = e();\n global.set('eq', eq);\n \n node.warn(\"new global eq\");\n} else {\n node.warn(\"existing global eq\");\n}\n\nvar eq3info = eq();\nvar eq3 = eq3info.eq3;\n\nif (msg.payload.names){\n eq3info.names = msg.payload.names;\n}\n\neq3info.eq3.prototype.SCAN_DUPLICATES = true;\n\n\n\nif (eq3info.discovercallback){\n eq3info.eq3.stopDiscover(eq3info.discovercallback);\n delete eq3info.discovercallback;\n}\n\n\nif (eq3info.anyDiscovery){\n noble.removeListener('discover', eq3info.anyDiscovery);\n}\neq3info.anyDiscovery = function(peripheral){\n try{\n if (peripheral.connectable === false){\n return;\n }\n var name = 'unknown';\n if (eq3info.names && eq3info.names[peripheral.address]){\n name = eq3info.names[peripheral.address];\n }\n \n eq3info.peripherals = eq3info.peripherals || [];\n eq3info.peripherals[peripheral.id] = eq3info.peripherals[peripheral.id] || {};\n eq3info.peripherals[peripheral.id].peripheral = peripheral;\n\n if (peripheral.advertisement){\n if (peripheral.advertisement.localName !== \"CC-RT-M-BLE\"){\n //node.warn(peripheral);\n }\n var newmsg = {\n topic: \"blediscover/\"+peripheral.id.toLowerCase(),\n payload:{\n rssi: peripheral.rssi,\n txPowerLevel: peripheral.advertisement.txPowerLevel,\n serviceUuids: peripheral.advertisement.serviceUuids,\n serviceData: {},\n localName: peripheral.advertisement.localName,\n name: name\n }\n }\n if (peripheral.advertisement.serviceData){\n for (var i = 0; i < peripheral.advertisement.serviceData.length; i++){\n newmsg.payload.serviceData[peripheral.advertisement.serviceData[i].uuid] = \n peripheral.advertisement.serviceData[i].data.toString('hex');\n }\n }\n \n setTimeout(function(){\n node.send(newmsg);\n }, 1);\n }\n } catch (e){\n node.error(e);\n }\n};\n\nnoble.on('discover', eq3info.anyDiscovery);\n\n\n\n\neq3info.disconnectCallback = function(device) {\n try{\n if (!device){\n node.error(\"disconnect: no device\")\n } else {\n clearTimeout(device.disconnecttimer);\n device.disconnecttimer = null;\n //node.warn( \"got disconnected\"+ device.address );\n if (eq3info.info[device.address]){\n eq3info.info[device.address].my_state = 'disconnected';\n } else {\n node.error(\"disconnect: no info for \"+device.address);\n }\n }\n } catch(e){\n node.error(e);\n }\n};\n\neq3info.discovercallback = function(device){\n eq3info.info[device.address] = eq3info.info[device.address] || {};\n eq3info.info[device.address].rssi = device._peripheral.rssi;\n //node.warn(eq3info.devices[device.address]);\n if (eq3info.devices[device.address]){\n eq3info.info[device.address].discoverycount = (eq3info.info[device.address].discoverycount || 0)+1;\n //node.warn( \"re-discovered \"+ device.address+ ' rssi:' + device._peripheral.rssi);\n eq3info.info[device.address].last_seen = (new Date()).valueOf();\n \n // always re-add disconnect listener, just in case\n if (device.disconnectFn){\n device.removeListener('disconnect', device.disconnectFn);\n }\n device.disconnectFn = function(){\n eq3info.disconnectCallback(device);\n };\n device.on('disconnect', device.disconnectFn );\n \n } else {\n eq3info.info[device.address].last_seen = (new Date()).valueOf();\n eq3info.devices[device.address] = device;\n //node.warn(eq3info.devices[device.address]);\n node.warn( \"discovered new \"+ device.address+ ' rssi:' + device._peripheral.rssi);\n // always remove and re-add disconnect listener, just in case\n if (device.disconnectFn){\n device.removeListener('disconnect', device.disconnectFn);\n }\n device.disconnectFn = function(){\n eq3info.disconnectCallback(device);\n };\n device.on('disconnect', device.disconnectFn );\n }\n};\n\n\nnode.warn(\"starting discovery\");\n\nif (eq3){\n var keys = Object.keys(eq3info.devices);\n\n // we want to remove all devices.\n for (var i = 0; i < keys.length; i++) {\n var device = eq3info.devices[keys[i]];\n node.warn( 'disconnect:'+ device.address+ ' rssi:' + device._peripheral.rssi);\n if (device.disconnectFn){\n device.removeListener('disconnect', device.disconnectFn);\n }\n device.disconnect();\n }\n}\n\neq3info.devices = {};\neq3info.info = {};\n//node.warn(eq3info.devices);\n\neq3info.eq3.discoverAll(eq3info.discovercallback);\nnoble.startScanning([], true);\n\n\nreturn msg;","outputs":1,"noerr":0,"x":310,"y":40,"wires":[["aaa501f8.d744e","4ab8a582.5327fc"]]},{"id":"81d1f125.7392","type":"function","z":"d9611430.c0dd78","name":"stopdiscovery","func":"var eq = global.get('eq');\n\nif (!eq) return;\n\nvar eq3info = eq();\nvar eq3 = eq3info.eq3;\n\n\nif (eq3){\n if (eq3info.discovercallback){\n node.warn(\"stop discovery\");\n eq3.stopDiscoverAll(eq3info.discovercallback);\n delete eq3info.discovercallback;\n }\n}\n\n\nreturn msg;","outputs":1,"noerr":0,"x":335,"y":101,"wires":[[]]},{"id":"b20be09f.80fd3","type":"inject","z":"d9611430.c0dd78","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":100,"y":180,"wires":[["77447862.1e2eb8"]]},{"id":"77447862.1e2eb8","type":"function","z":"d9611430.c0dd78","name":"disconnectall","func":"var eq = global.get('eq');\n\nif (!eq) return;\n\nvar eq3info = eq();\nvar eq3 = eq3info.eq3;\n\nif (eq3){\n var keys = Object.keys(eq3info.devices);\n\n for (var i = 0; i < keys.length; i++) {\n var device = eq3info.devices[keys[i]];\n node.warn( 'fromglobal:'+ device.address+ ' rssi:' + device._peripheral.rssi);\n device.disconnect();\n }\n}\n\n\nreturn msg;","outputs":1,"noerr":0,"x":330,"y":180,"wires":[[]]},{"id":"235452f8.32841e","type":"inject","z":"d9611430.c0dd78","name":"","topic":"","payload":"","payloadType":"date","repeat":"30","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":240,"wires":[["2502a69.7e60a5a"]]},{"id":"2502a69.7e60a5a","type":"function","z":"d9611430.c0dd78","name":"rssi","func":"var eq = global.get('eq');\n\nif (!eq) return;\n\nvar eq3info = eq();\nvar eq3 = eq3info.eq3;\n\nif (eq3 && eq3info.info){\n \n var keys = Object.keys(eq3info.info);\n\n var points = [];\n var now = new Date();\n\n for (var i = 0; i < keys.length; i++) {\n var info = eq3info.info[keys[i]];\n var newmsg = {\n topic:'rssi-'+info.name,\n payload:info.rssi\n };\n node.send(newmsg);\n }\n}\n\n","outputs":1,"noerr":0,"x":310,"y":240,"wires":[["b3f5608f.f8475"]]},{"id":"b3f5608f.f8475","type":"ui_chart","z":"d9611430.c0dd78","name":"","group":"34dcf9c9.e64796","order":0,"width":0,"height":0,"label":"chart","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"-150","ymax":"-40","removeOlder":"24","removeOlderPoints":"1000","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":490,"y":240,"wires":[[],[]]},{"id":"93597422.104a78","type":"ui_chart","z":"d9611430.c0dd78","name":"","group":"34dcf9c9.e64796","order":0,"width":0,"height":0,"label":"chart","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"0","ymax":"100","removeOlder":"24","removeOlderPoints":"1000","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":950,"y":640,"wires":[[],[]]},{"id":"88321dc7.cc57","type":"ui_chart","z":"d9611430.c0dd78","name":"","group":"34dcf9c9.e64796","order":0,"width":0,"height":0,"label":"chart","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"0","ymax":"30","removeOlder":"24","removeOlderPoints":"1000","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":950,"y":700,"wires":[[],[]]},{"id":"a7768e04.0d9d9","type":"ui_template","z":"d9611430.c0dd78","group":"24fd5e57.122362","name":"","order":0,"width":"6","height":"12","format":"\n<div ng-repeat=\"(key, value) in msg.payload\">\n <p>{{key}} - {{value.name}} - {{value.my_state}}</p>\n <p>Target:{{value.info.targetTemperature}} Valve:{{value.info.valvePosition}}</p>\n <p>last:{{value.last_response}}</p>\n <div ng-repeat=\"day in value.days\">\n day: {{day.day}}:\n <span ng-repeat=\"sched in day.segments\">\n {{sched.temp}} to {{sched.endtime.hour}}:{{sched.endtime.min}},\n </span>\n </div>\n \n \n</div>\n","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":680,"y":960,"wires":[[]]},{"id":"3ea3ece4.4a4a34","type":"ui_button","z":"d9611430.c0dd78","name":"clear","group":"34dcf9c9.e64796","order":0,"width":0,"height":0,"passthru":false,"label":"Clear","color":"","bgcolor":"","icon":"","payload":"[]","payloadType":"json","topic":"","x":120,"y":400,"wires":[["b3f5608f.f8475","93597422.104a78","88321dc7.cc57","7526a157.fbd93"]]},{"id":"7526a157.fbd93","type":"delay","z":"d9611430.c0dd78","name":"","pauseType":"delay","timeout":"0.2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":210,"y":460,"wires":[["fe80ba30.a06448","bf2fbe23.b741f"]]},{"id":"fe80ba30.a06448","type":"delay","z":"d9611430.c0dd78","name":"","pauseType":"delay","timeout":"0.2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":210,"y":520,"wires":[["bf2fbe23.b741f"]]},{"id":"bf2fbe23.b741f","type":"function","z":"d9611430.c0dd78","name":"","func":"\nreturn msg;","outputs":1,"noerr":0,"x":380,"y":500,"wires":[["448cbf8c.ea7a1","2502a69.7e60a5a"]]},{"id":"448cbf8c.ea7a1","type":"function","z":"d9611430.c0dd78","name":"loop devices","func":"var eq = global.get('eq');\n\nif (!eq) return;\n\nvar eq3info = eq();\nvar eq3 = eq3info.eq3;\n\ncontext.dev = context.dev || 0;\n\nif (!eq3)\n return;\n\nvar now = (new Date()).valueOf();\n\nvar keys = Object.keys(eq3info.devices);\n//node.warn(keys);\n\ncontext.dev = (context.dev+1) % keys.length;\n\n//for (var i = 0; i < keys.length; i++) {\nvar i = context.dev;\n\n var device = eq3info.devices[keys[i]];\n var info = eq3info.info[keys[i]];\n \n // only if seen in last 60 seconds\n if (info && info.last_seen + 60000 > now){\n var sendaddr = function(a){\n var newmsg1 = {\n device_address: keys[i],\n };\n node.send(newmsg1);\n };\n sendaddr(keys[i]);\n }\n \n//}\n\n","outputs":1,"noerr":0,"x":330,"y":600,"wires":[["98856bc5.4acfe8"]]},{"id":"93a9aa.05577658","type":"inject","z":"d9611430.c0dd78","name":"","topic":"","payload":"","payloadType":"date","repeat":"10","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":600,"wires":[["448cbf8c.ea7a1"]]},{"id":"bd1fae1e.f2472","type":"inject","z":"d9611430.c0dd78","name":"","topic":"","payload":"","payloadType":"date","repeat":"5","crontab":"","once":false,"onceDelay":0.1,"x":690,"y":880,"wires":[["8cb9965.2a0c768"]]},{"id":"8cb9965.2a0c768","type":"function","z":"d9611430.c0dd78","name":"loop devices","func":"var eq = global.get('eq');\n\nif (!eq) return;\n\nvar eq3info = eq();\nvar eq3 = eq3info.eq3;\n\n\nif (!eq3)\n return;\n\n\nvar newinfo = JSON.stringify(eq3info.info);\n\nvar keys = Object.keys(eq3info.info);\n\nfor (var i = 0; i < keys.length; i++){\n eq3info.info[keys[i]].days = eq3info.info[keys[i]].days || [];\n //node.warn(util.inspect(eq3info.devices[keys[i]], {depth:null}));\n}\n\n//node.warn(eq3info.info);\n\nif ( newinfo !== context.lastinfo ){\n context.lastinfo = newinfo;\n var newmsg = {\n payload:eq3info.info\n };\n \n return newmsg;\n}\n\n","outputs":1,"noerr":0,"x":690,"y":920,"wires":[["a7768e04.0d9d9"]]},{"id":"bc50f8f3.c83668","type":"function","z":"d9611430.c0dd78","name":"extract valve","func":"var eq = global.get('eq');\n\nif (!eq) return;\n\nvar eq3info = eq();\nvar eq3 = eq3info.eq3;\n\n\nif (!eq3)\n return;\n\nvar device = eq3info.devices[msg.device_address];\nvar info = eq3info.info[msg.device_address];\n\ntry{\n switch(msg.cmd){\n case 'setBoost':\n case 'setDateTime':\n case 'getInfo':\n case 'automaticMode':\n case 'ecoMode':\n case 'manualMode':\n if (!msg.payload){\n node.error(\"no payload?\"+util.inspect(msg));\n return;\n }\n if (!msg.payload.status){\n node.error(\"no payload?\"+util.inspect(msg));\n return;\n }\n \n msg.payload.status.readtime = (new Date()).valueOf();\n\n info.info = msg.payload.status;\n info.deviceaddress = msg.device_address;\n \n var newmsg = {\n topic:'valve-'+info.name,\n payload:info.info.valvePosition\n };\n node.send(newmsg);\n \n var newmsg2 = {\n topic:'temp-'+info.name,\n payload:info.info.targetTemperature\n };\n node.send([null, newmsg2]);\n \n break;\n default:\n break;\n }\n} catch(e){\n node.error(e);\n}\n\n","outputs":2,"noerr":0,"x":810,"y":660,"wires":[["93597422.104a78"],["88321dc7.cc57"]]},{"id":"385d4c9.8bc79b4","type":"debug","z":"d9611430.c0dd78","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":610,"y":820,"wires":[]},{"id":"9e0b8b90.df8918","type":"function","z":"d9611430.c0dd78","name":"Connect","func":"var eq = global.get('eq');\n\nif (!eq) return;\n\nvar eq3info = eq();\nvar eq3 = eq3info.eq3;\n\nvar require = global.get('require');\nvar noble = require('noble');\n\nif (!eq3){\n return;\n}\n\n// device_address: keys[i],\n// cmd: 'getInfo' // msg.payload = addrss\n\n\nvar device = eq3info.devices[msg.device_address];\nvar info = eq3info.info[msg.device_address];\n\nswitch(info.my_state){\n case 'connected': \n //node.warn( device.address+ ' already connected' );\n //if already connected, stay connected another 10s\n clearTimeout(device.disconnecttimer);\n device.disconnecttimer = setTimeout(function(){\n device.disconnect();\n }, 1000);\n node.send(msg);\n break;\n case undefined:\n case 'disconnected':\n case 'connectfailed':\n case 'connecttimeout':\n //node.warn( device.address+ ' try to connect' );\n info.my_state = 'connecting';\n device.connectAndSetup().then(\n (ok)=>{\n clearTimeout(device.connecttimer);\n noble.startScanning([], true);\n eq3info.info[device.address] = eq3info.info[device.address] || {};\n if (eq3info.names[device.address]){\n eq3info.info[device.address].name = eq3info.names[device.address];\n } else {\n eq3info.info[device.address].name = device.address;\n }\n \n //node.warn( device.address+ ' connected' );\n /*\n device._peripheral.updateRssi(function(error, rssi){\n //node.warn( \"rssi update:\"+ device.address+ ' rssi:' + device._peripheral.rssi);\n if (eq3info.info[device.address]){\n eq3info.info[device.address].rssi = device._peripheral.rssi;\n if (eq3info.names[device.address]){\n eq3info.info[device.address].name = eq3info.names[device.address];\n } else {\n eq3info.info[device.address].name = device.address;\n }\n }\n });\n */\n info.isconnected = true;\n \n clearTimeout(device.disconnecttimer);\n device.disconnecttimer = setTimeout(function(){\n device.disconnect();\n }, 1000);\n \n //node.warn( device.address+ ' connected' );\n info.my_state = 'connected';\n setTimeout(function(){\n node.send(msg);\n }, 1);\n },\n (err)=>{\n noble.startScanning([], true);\n node.error( device.address+ ' connect unsuccessful:'+err.toString() );\n info.my_state = 'connectfailed';\n \n setTimeout(function(){\n node.error('Retry from fail '+device.address);\n node.send([null, msg]);\n }, 2000);\n }\n );\n\n // if we timeout on connection\n clearTimeout(device.connecttimer);\n device.connecttimer = setTimeout(function(){\n // then disconnect\n if (eq3info.info[device.address]){\n eq3info.info[device.address].my_state = 'connecttimeout';\n device.disconnect();\n }\n //node.warn('connect timeout '+device.address);\n setTimeout(function(){\n node.error('Retry from timeout '+device.address);\n node.send([null, msg]);\n }, 2000);\n }, 15000);\n \n break;\n case 'connecting':\n // do nothing, we're already on it\n break;\n}\n\n\n","outputs":2,"noerr":0,"x":540,"y":700,"wires":[["74b17db7.d7d5b4"],["97f7e5e9.0866f8"]],"outputLabels":["","retry"]},{"id":"74b17db7.d7d5b4","type":"function","z":"d9611430.c0dd78","name":"readinfo","func":"var eq = global.get('eq');\n\nif (!eq) return;\n\nvar eq3info = eq();\nvar eq3 = eq3info.eq3;\n\nif (!eq3)\n return;\n\n// device_address: keys[i],\n// cmd: 'getInfo' // msg.payload = addrss\n\nif (!msg.device_address){\n node.error(\"no device address\");\n return;\n}\n\n// nothing to do\nif (!msg.cmd){\n return;\n}\n\n\nvar device = eq3info.devices[msg.device_address];\nvar info = eq3info.info[msg.device_address];\n\nif (!device){\n node.error(\"no device for \"+msg.device_address);\n return;\n} else {\n}\n\nif (!device[msg.cmd]){\n node.error(\"invalid command \"+msg.cmd)\n return;\n}\n\nvar newmsg = {\n device_address: msg.device_address,\n cmd: msg.cmd\n};\n\nvar param1 = msg.payload;\nvar param2 = null;\n\n// functions with two parameters: \nswitch(msg.cmd){\n case 'ecoMode':\n param1 = msg.payload.temp;\n param2 = msg.payload.date;\n break;\n \n case 'updateOpenWindowConfiguration':\n param1 = msg.payload.temp;\n param2 = msg.payload.duration;\n break;\n \n case 'setComfortTemps':\n param1 = msg.payload.night;\n param2 = msg.payload.day;\n break;\n \n}\n\n//node.warn(\"cmd \"+msg.cmd+\" send \"+msg.payload);\ndevice[msg.cmd](param1, param2).then(\n a => {\n info.last_response = (new Date()).valueOf();\n newmsg.payload = a;\n setTimeout(function(){\n node.send(newmsg);\n if (info.commands && info.commands.length){\n info.commands.shift();\n if (info.commands.length){\n node.send([null, info.commands[0]]);\n }\n }\n }, 1);\n },\n err => {\n node.error(\"can't read from device \"+device.address+\" error \"+err);\n if (info.commands && info.commands.length){\n info.commands.shift();\n if (info.commands.length){\n node.send([null, info.commands[0]]);\n }\n }\n }\n);\n\n","outputs":2,"noerr":0,"x":540,"y":740,"wires":[["bc50f8f3.c83668","385d4c9.8bc79b4","ea3c271.5cb59d8","169bc4f2.ca11ab"],["9e0b8b90.df8918"]]},{"id":"36a1b3e4.5c18dc","type":"function","z":"d9611430.c0dd78","name":"queuemessage","func":"var eq = global.get('eq');\n\nif (!eq) return;\n\nvar eq3info = eq();\nvar eq3 = eq3info.eq3;\n\nif (!eq3)\n return;\n\n// device_address: keys[i],\n// cmd: 'getInfo' // msg.payload = addrss\n\nif (!msg.device_address){\n node.warn(\"no device address\");\n return;\n}\n\n// nothing to do\nif (!msg.cmd){\n return;\n}\n\n\nvar device = eq3info.devices[msg.device_address];\nvar info = eq3info.info[msg.device_address];\n\n\nif (!device[msg.cmd]){\n node.warn(\"invalid command \"+msg.cmd)\n return;\n}\n\nif (!device){\n node.warn(\"no device for \"+msg.device_address);\n return;\n} else {\n}\n\nvar newmsg = {\n device_address: msg.device_address,\n cmd: msg.cmd,\n payload: msg.payload,\n};\n\ninfo.commands = info.commands || [];\n\ninfo.commands.push(newmsg);\n//node.warn(info.commands);\nif (info.commands.length === 1){\n return newmsg; \n}\n\n","outputs":1,"noerr":0,"x":360,"y":700,"wires":[["9e0b8b90.df8918"]]},{"id":"1cbbc812.bf41a8","type":"inject","z":"d9611430.c0dd78","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":100,"y":800,"wires":[["be5df164.cf5a2"]]},{"id":"be5df164.cf5a2","type":"function","z":"d9611430.c0dd78","name":"Add Functions","func":"var eq = global.get('eq');\n\nif (!eq) return;\n\nvar eq3info = eq();\nvar eq3 = eq3info.eq3;\n\nvar require = global.get('require');\nvar eq3interface = require('/home/pi/.node-red/node_modules/node-red-contrib-eq3-bluetooth/lib/eq3interface.js');\n\nif (!eq3)\n return;\n\n\nconst status = {\n manual: 1,\n holiday: 2,\n boost: 4,\n dst: 8,\n openWindow: 16,\n lock: 32,\n unknown2: 64,\n lowBattery: 128,\n};\n\n\n \neq3interface.parseInfo = function(info){\n try{\n switch(info[0]){\n case 0: // ??\n node.warn(info);\n return { \n unknown:true,\n raw: info,\n };\n break;\n\n case 1: // sysinfo\n node.warn(info);\n return {\n sysinfo:{\n ver: info[1],\n type: info[2],\n },\n raw: info,\n };\n break;\n\n case 2:\n node.warn(info);\n switch(info[1] & 0xf){\n case 1: // normal info\n const statusMask = info[2];\n const valvePosition = info[3];\n const targetTemperature = info[5] / 2;\n \n node.warn(info);\n \n var ecotime = undefined; \n node.warn(statusMask+\" \"+status.holiday+\" \"+info.length)\n if (((statusMask & status.holiday) === status.holiday) && (info.length >= 10)) {\n // parse extra bytes\n ecotime = {\n day:info[6],\n year: info[7]+2000,\n hour: (info[8]/2)>>0,\n min: (info[8] & 1)? 30:0,\n month: info[9],\n };\n ecotime.date = new Date(ecotime.year, ecotime.month-1, ecotime.day, ecotime.hour, ecotime.min, 0, 0);\n }\n \n return {\n raw:info,\n status: {\n manual: (statusMask & status.manual) === status.manual,\n holiday: (statusMask & status.holiday) === status.holiday,\n boost: (statusMask & status.boost) === status.boost,\n lock: (statusMask & status.lock) === status.lock,\n dst: (statusMask & status.dst) === status.dst,\n openWindow: (statusMask & status.openWindow) === status.openWindow,\n lowBattery: (statusMask & status.lowBattery) === status.lowBattery,\n valvePosition,\n targetTemperature,\n ecotime: ecotime,\n },\n };\n break;\n \n case 2: // schedule set response, returns day set\n var res = {\n raw:info,\n dayresponse:{\n day: info[2]\n } \n }\n return res;\n break;\n \n case 0x80: // return from setTempOffset \n var res = {\n ok: true,\n raw:info,\n }\n return res;\n break;\n }\n break;\n\n case 4: // time request?\n node.warn(info);\n return {\n timerequest:true,\n raw:info,\n };\n break;\n\n case 0x21:\n node.warn(info);\n var day = {\n day: info[1],\n segments: [],\n };\n for (var i = 2; i < info.length; i += 2){\n var segment = {\n temp: info[i]/2,\n endtime:{\n hour: ((info[i+1]*10)/60)>>0,\n min: ((info[i+1]*10)%60)>>0,\n }\n };\n day.segments.push(segment);\n }\n return {\n raw:info,\n dayschedule: day\n }\n break;\n \n case 0xa0:\n node.warn(info);\n // start firmware update\n break;\n \n case 0xa1:\n node.warn(info);\n switch(info[1]){\n default:\n break;\n case 0x11: // start next firmware package\n break;\n case 0x22: // send next frame\n break\n case 0x33: // restart frame transmission\n break;\n case 0x44: // update finished\n break;\n }\n // start firmware update\n break;\n default:\n node.warn(info);\n return {\n unknown:true,\n raw:info,\n };\n break;\n }\n \n } catch(e){\n return{ error: e.toString() };\n }\n};\n \n \neq3.prototype.automaticMode = function() {\n return this.writeAndGetNotification(eq3interface.payload.setAutomaticMode())\n .then(info => eq3interface.parseInfo(info), err => {return { error: err }});\n}\n\neq3.prototype.manualMode = function() {\n return this.writeAndGetNotification(eq3interface.payload.setManualMode())\n .then(info => eq3interface.parseInfo(info), err => {return { error: err }});\n}\n\n\n// sending ecoMode empty just turns on holiday mode.\neq3.prototype.holidayMode = function() {\n return this.ecoMode();\n}\n\n// sending ecoMode empty just turns on holiday mode (holiday+manual).\n// sending with just temp turns on holiday mode, returns a time? (now+1day?)\n// sending with empty temp and date turns on holiday mode (holiday+manual), but does not return a date\n// I think if the command is 'short', it can use bytes from the last command instead!!!\neq3.prototype.ecoMode = function(temp, date) {\n var tempstr = '00';\n if (!temp){\n tempstr = 'FF'; // 'vacation mode'\n } else {\n tempstr = ('0'+(0x80 | ((temp*2)>>0)).toString(16)).slice(-2);\n }\n if (date)\n node.warn(\"set eco @ \"+temp+\" until \"+date.toString());\n else \n node.warn(\"set eco @ \"+temp+\" no date\");\n \n const prefix = '40';\n var out = undefined;\n if (date){\n const year = ('0'+((date.getFullYear() - 2000)).toString(16)).slice(-2);\n const month = ('0'+(date.getMonth() + 1).toString(16)).slice(-2);\n const day = ('0'+date.getDate().toString(16)).slice(-2);\n var hour = date.getHours();\n const minute = date.getMinutes();\n hour *=2;\n if (minute >= 30){\n hour++;\n }\n hour = ('0'+hour.toString(16)).slice(-2);\n out = new Buffer(prefix+ tempstr + day+year + hour + month, 'hex');\n } else {\n out = new Buffer(prefix+ tempstr, 'hex');\n }\n\n node.warn(out);\n\n return this.writeAndGetNotification(out)\n .then(info => eq3interface.parseInfo(info), err => {return { error: err }});\n};\n \n \neq3.prototype.updateOpenWindowConfiguration = function(temperature, minDuration) {\n const temp = ('0'+(2 * temperature).toString(16)).slice(-2);\n const dur = ('0'+(minDuration / 5).toString(16)).slice(-2);\n var out =new Buffer(`14${temp}${dur}`, 'hex')\n\n return this.writeAndGetNotification(out)\n .then(info => eq3interface.parseInfo(info), err => {return { error: err }});\n};\n\neq3.prototype.setComfortTemps = function(night, day) {\n const tempNight = ('0'+(2 * night).toString(16)).slice(-2);\n const tempDay = ('0'+(2 * day).toString(16)).slice(-2);\n var out = new Buffer(`11${tempDay}${tempNight}`, 'hex')\n return this.writeAndGetNotification(out)\n .then(info => eq3interface.parseInfo(info), err => {return { error: err }});\n}\n\n \neq3.prototype.setDateTime = function(date) {\n var out = new Buffer(7);\n out[0] = 3;\n out[1] = date.getFullYear() - 2000;\n out[2] = (date.getMonth() + 1);\n out[3] = date.getDate();\n out[4] = date.getHours();\n out[5] = date.getMinutes();\n out[6] = date.getSeconds();\n\n return this.writeAndGetNotification(out)\n .then(info => eq3interface.parseInfo(info), err => {return { error: err }});\n}\n\neq3.prototype.getSysInfo = function() {\n var out = new Buffer(1);\n out[0] = 0;\n\n return this.writeAndGetNotification(out)\n .then(info => eq3interface.parseInfo(info), err => {return { error: err }});\n}\n\n \neq3.prototype.setBoost = function(enable) {\n if (enable) {\n return this.writeAndGetNotification(eq3interface.payload.activateBoostmode())\n .then(info => eq3interface.parseInfo(info), err => {return { error: err }});\n }\n return this.writeAndGetNotification(eq3interface.payload.deactivateBoostmode())\n .then(info => eq3interface.parseInfo(info), err => {return { error: err }});\n}\n\n\neq3.prototype.getDay = function(day){\n return this.writeAndGetNotification(new Buffer('200'+day, 'hex'))\n .then(info => eq3interface.parseInfo(info), err => {return { error: err }});\n/* \n .then(\n info => {\n if (info[0] != 0x21) return { error: 'incorrect return' };\n var day = {\n day: info[1],\n segments: [],\n raw:info,\n };\n for (var i = 2; i < info.length; i += 2){\n var segment = {\n temp: info[i]/2,\n hh: ((info[i+1]*10)/60)>>0,\n mm: ((info[i+1]*10)%60)>>0,\n };\n day.segments.push(segment);\n }\n return day;\n }, \n err => console.log(\"error in getInfo \"+err));\n*/ \n};\n\neq3.prototype.setDay = function(day){\n var out = new Buffer(16);\n out[0] = 0x10;\n out[1] = day.day;\n\n // zero all first\n for (var i = 0; i < 7; i++){\n out[(i*2)+2] = 0;\n out[(i*2)+3] = 0;\n }\n\n \n for (var i = 0; i < 7; i++){\n out[(i*2)+2] = 0;\n out[(i*2)+3] = 0;\n \n if (day.segments[i].temp && day.segments[i].endtime && day.segments[i].endtime.hour && day.segments[i].endtime.min ){\n out[(i*2)+2] = (day.segments[i].temp * 2)>>0;\n out[(i*2)+3] = (((day.segments[i].endtime.hour * 60) + day.segments[i].endtime.min)/10)>>0;\n } else {\n break; // stop at first non-temp\n }\n }\n \n \n return this.writeAndGetNotification(out)\n .then(info => eq3interface.parseInfo(info), err => {return { error: err }});\n/* .then(\n info => {\n if (info[0] !== 0x02) return { error: 'incorrect return' };\n if ((info[1] & 0xf) != 0x02) return { error: 'incorrect return' };\n var res = {\n day: info[2],\n raw:info,\n };\n return res;\n }, \n err => console.log(\"error in getInfo \"+err));\n */\n};\n\n\n\neq3.prototype.setComfortTemp = function() {\n var out =new Buffer(1);\n out[0] = 0x43;\n\n return this.writeAndGetNotification(out)\n .then(info => eq3interface.parseInfo(info), err => {return { error: err }});\n};\n\neq3.prototype.setEcoTemp = function() {\n var out =new Buffer(1);\n out[0] = 0x44;\n\n return this.writeAndGetNotification(out)\n .then(info => eq3interface.parseInfo(info), err => {return { error: err }});\n};\n\neq3.prototype.setTemperature = function(temp) {\n return this.writeAndGetNotification(eq3interface.payload.setTemperature(temp))\n .then(info => eq3interface.parseInfo(info), err => {return { error: err }});\n};\n\neq3.prototype.setLock = function(enable) {\n if (enable) {\n return this.writeAndGetNotification(eq3interface.payload.lockThermostat())\n .then(info => eq3interface.parseInfo(info), err => {return { error: err }});\n }\n return this.writeAndGetNotification(eq3interface.payload.unlockThermostat())\n .then(info => eq3interface.parseInfo(info), err => {return { error: err }});\n}\n\n\nreturn msg;\n","outputs":1,"noerr":0,"x":280,"y":800,"wires":[[]]},{"id":"ea3c271.5cb59d8","type":"function","z":"d9611430.c0dd78","name":"extract day","func":"var eq = global.get('eq');\n\nif (!eq) return;\n\nvar eq3info = eq();\nvar eq3 = eq3info.eq3;\n\n\nif (!eq3)\n return;\n\nvar device = eq3info.devices[msg.device_address];\nvar info = eq3info.info[msg.device_address];\n\n\nswitch(msg.cmd){\n case 'getDay':\n if (!msg.payload){\n node.error(\"no payload?\"+util.inspect(msg));\n return;\n }\n if (msg.payload.dayschedule !== undefined){\n if (msg.payload.dayschedule.day !== undefined){\n info.days = info.days || {};\n info.days[msg.payload.dayschedule.day] = msg.payload.dayschedule;\n info.days[msg.payload.dayschedule.day].readtime = (new Date()).valueOf();\n }\n }\n \n //node.warn(info);\n break;\n default:\n break;\n}\n\n","outputs":1,"noerr":0,"x":810,"y":720,"wires":[[]]},{"id":"f5533844.9a85a8","type":"function","z":"d9611430.c0dd78","name":"GetAllDays","func":"var eq = global.get('eq');\n\nif (!eq) return;\n\nvar eq3info = eq();\nvar eq3 = eq3info.eq3;\n\nif (!eq3)\n return;\n\n\nmsg.device_address = \"00:1a:22:09:2c:df\";\n\nif (!msg.device_address){\n node.warn(\"no device address\");\n return;\n}\n\n\n\nvar device = eq3info.devices[msg.device_address];\nvar info = eq3info.info[msg.device_address];\n\n\nif (!device || !info){\n return;\n}\n\nvar get = function(address, day){\n var newmsg = {\n cmd: 'getDay',\n device_address: address,\n payload: day,\n };\n \n node.send(newmsg);\n}\n\n\nfor (var i = 0; i < 7; i++){\n get(msg.device_address, i);\n}\n\n//return msg;","outputs":1,"noerr":0,"x":150,"y":720,"wires":[["36a1b3e4.5c18dc"]]},{"id":"df2dd332.4d96b","type":"inject","z":"d9611430.c0dd78","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":80,"y":840,"wires":[["f5533844.9a85a8"]]},{"id":"4d5cfbb5.6117f4","type":"function","z":"d9611430.c0dd78","name":"Set Day","func":"var eq = global.get('eq');\n\nif (!eq) return;\n\nvar eq3info = eq();\nvar eq3 = eq3info.eq3;\n\nif (!eq3)\n return;\n\nmsg.device_address = \"00:1a:22:09:2c:df\";\n\nif (!msg.device_address){\n node.warn(\"no device address\");\n return;\n}\n\n\nvar device = eq3info.devices[msg.device_address];\nvar info = eq3info.info[msg.device_address];\n\n\nif (!device || !info){\n return;\n}\n\n\n\nvar set = function(address, day){\n var newmsg = {\n cmd: 'setDay',\n device_address: address,\n payload: day,\n };\n \n node.send(newmsg);\n}\n\nvar day = JSON.parse(JSON.stringify(info.days[0]));\nday.day = 1;\n\nset(msg.device_address, day);\n\n\n//return msg;","outputs":1,"noerr":0,"x":260,"y":880,"wires":[["36a1b3e4.5c18dc"]]},{"id":"8a041cda.8d52a","type":"inject","z":"d9611430.c0dd78","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":80,"y":880,"wires":[["4d5cfbb5.6117f4"]]},{"id":"169bc4f2.ca11ab","type":"function","z":"d9611430.c0dd78","name":"extract set day resp","func":"var eq = global.get('eq');\n\nif (!eq) return;\n\nvar eq3info = eq();\nvar eq3 = eq3info.eq3;\n\n\nif (!eq3)\n return;\n\nvar device = eq3info.devices[msg.device_address];\nvar info = eq3info.info[msg.device_address];\n\n\nswitch(msg.cmd){\n case 'setDay':\n if (!msg.payload){\n node.error(\"no payload?\"+util.inspect(msg));\n return;\n }\n \n if (msg.payload.dayresponse !== undefined){\n if (msg.payload.dayresponse.day !== undefined){\n info.days = info.days || {};\n info.dayswritten = info.dayswritten || {};\n if (info.dayswritten[msg.payload.dayresponse.day]){\n info.days[msg.payload.dayresponse.day] = info.dayswritten[msg.payload.dayresponse.day]\n }\n info.days[msg.payload.dayresponse.day].writetime = (new Date()).valueOf();\n }\n }\n \n //node.warn(info);\n break;\n default:\n break;\n}\n\n","outputs":1,"noerr":0,"x":830,"y":760,"wires":[[]]},{"id":"832b8035.59c06","type":"inject","z":"d9611430.c0dd78","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":80,"y":920,"wires":[["98856bc5.4acfe8"]]},{"id":"98856bc5.4acfe8","type":"function","z":"d9611430.c0dd78","name":"Set DateTime","func":"var eq = global.get('eq');\n\nif (!eq) return;\n\nvar eq3info = eq();\nvar eq3 = eq3info.eq3;\n\nif (!eq3)\n return;\n\nif (!msg.device_address){\n node.warn(\"no device address\");\n return;\n}\n\n\nvar device = eq3info.devices[msg.device_address];\nvar info = eq3info.info[msg.device_address];\n\n\nif (!device || !info){\n return;\n}\n\n var newmsg = {\n cmd: 'setDateTime',\n device_address: msg.device_address,\n payload: new Date(),\n };\n \n node.send(newmsg);\n","outputs":1,"noerr":0,"x":280,"y":920,"wires":[["36a1b3e4.5c18dc"]]},{"id":"96a11b8.1e1e7e8","type":"inject","z":"d9611430.c0dd78","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":80,"y":960,"wires":[["d45b5125.a9707"]]},{"id":"d45b5125.a9707","type":"function","z":"d9611430.c0dd78","name":"setTemperatureOffset","func":"var eq = global.get('eq');\n\nif (!eq) return;\n\nvar eq3info = eq();\nvar eq3 = eq3info.eq3;\n\nif (!eq3)\n return;\n\nmsg.device_address = \"00:1a:22:09:2c:df\";\n\nif (!msg.device_address){\n node.warn(\"no device address\");\n return;\n}\n\n\nvar device = eq3info.devices[msg.device_address];\nvar info = eq3info.info[msg.device_address];\n\n\nif (!device || !info){\n return;\n}\n\n var newmsg = {\n cmd: 'setTemperatureOffset',\n device_address: msg.device_address,\n payload: 0,\n };\n \n node.send(newmsg);\n","outputs":1,"noerr":0,"x":300,"y":960,"wires":[["50d15325.61df5c"]]},{"id":"50d15325.61df5c","type":"function","z":"d9611430.c0dd78","name":"","func":"\nreturn msg;","outputs":1,"noerr":0,"x":470,"y":1000,"wires":[["36a1b3e4.5c18dc"]]},{"id":"8ecd0a2b.f41b08","type":"inject","z":"d9611430.c0dd78","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":80,"y":1000,"wires":[["a4e0bfc9.09cb4"]]},{"id":"a4e0bfc9.09cb4","type":"function","z":"d9611430.c0dd78","name":"setBoost0","func":"var eq = global.get('eq');\n\nif (!eq) return;\n\nvar eq3info = eq();\nvar eq3 = eq3info.eq3;\n\n\nif (!eq3)\n return;\n\nmsg.device_address = \"00:1a:22:09:2c:df\";\n\nif (!msg.device_address){\n node.warn(\"no device address\");\n return;\n}\n\n\nvar device = eq3info.devices[msg.device_address];\nvar info = eq3info.info[msg.device_address];\n\n\nif (!device || !info){\n return;\n}\n\n var newmsg = {\n cmd: 'setBoost',\n device_address: msg.device_address,\n payload: false,\n };\n \n node.send(newmsg);\n","outputs":1,"noerr":0,"x":260,"y":1000,"wires":[["50d15325.61df5c"]]},{"id":"b002d3d6.52194","type":"function","z":"d9611430.c0dd78","name":"setBoost1","func":"var eq = global.get('eq');\n\nif (!eq) return;\n\nvar eq3info = eq();\nvar eq3 = eq3info.eq3;\n\n\nif (!eq3)\n return;\n\nmsg.device_address = \"00:1a:22:09:2c:df\";\n\nif (!msg.device_address){\n node.warn(\"no device address\");\n return;\n}\n\n\nvar device = eq3info.devices[msg.device_address];\nvar info = eq3info.info[msg.device_address];\n\n\nif (!device || !info){\n return;\n}\n\n var newmsg = {\n cmd: 'setBoost',\n device_address: msg.device_address,\n payload: 1,\n };\n \n node.send(newmsg);\n","outputs":1,"noerr":0,"x":260,"y":1040,"wires":[["50d15325.61df5c"]]},{"id":"e88f3852.241568","type":"inject","z":"d9611430.c0dd78","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":80,"y":1040,"wires":[["96313a3a.ccb3b8"]]},{"id":"96313a3a.ccb3b8","type":"function","z":"d9611430.c0dd78","name":"testCommands","func":"var eq = global.get('eq');\n\nif (!eq) return;\n\nvar eq3info = eq();\nvar eq3 = eq3info.eq3;\n\n\nif (!eq3)\n return;\n\nmsg.device_address = \"00:1a:22:09:2c:df\";\n\nif (!msg.device_address){\n node.warn(\"no device address\");\n return;\n}\n\n\nvar device = eq3info.devices[msg.device_address];\nvar info = eq3info.info[msg.device_address];\n\n\nif (!device || !info){\n return;\n}\n\n var newmsg2 = {\n cmd: 'manualMode',\n device_address: msg.device_address,\n payload: null,\n };\n node.send(newmsg2);\n\n var newmsg3 = {\n cmd: 'ecoMode',\n device_address: msg.device_address,\n payload: {temp:0, date:(new Date((new Date()).valueOf()+ 1000*60*60*24))},\n };\n //node.send(newmsg3);\n\n\n var newmsg = {\n cmd: 'ecoMode',\n device_address: msg.device_address,\n payload: {},\n };\n //node.send(newmsg);\n\n\n var newmsg4 = {\n cmd: 'ecoMode',\n device_address: msg.device_address,\n payload: {temp:13, date:(new Date((new Date()).valueOf()+ 1000*60*60*24))},\n };\n node.send(newmsg4);\n\n var newmsg2 = {\n cmd: 'automaticMode',\n device_address: msg.device_address,\n payload: null,\n };\n node.send(newmsg2);\n","outputs":1,"noerr":0,"x":280,"y":1080,"wires":[["50d15325.61df5c"]]},{"id":"ceae85fd.4c5c58","type":"function","z":"d9611430.c0dd78","name":"testCommands","func":"var eq = global.get('eq');\n\nif (!eq) return;\n\nvar eq3info = eq();\nvar eq3 = eq3info.eq3;\n\n\nif (!eq3)\n return;\n\nmsg.device_address = \"00:1a:22:09:2c:df\";\n\nif (!msg.device_address){\n node.warn(\"no device address\");\n return;\n}\n\n\nvar device = eq3info.devices[msg.device_address];\nvar info = eq3info.info[msg.device_address];\n\n\nif (!device || !info){\n return;\n}\n\n var newmsg2 = {\n cmd: 'manualMode',\n device_address: msg.device_address,\n payload: null,\n };\n node.send(newmsg2);\n\n var newmsg4 = {\n cmd: 'setTemperature',\n device_address: msg.device_address,\n payload: 10,\n };\n node.send(newmsg4);\n\n \nreturn;\n\n var newmsg3 = {\n cmd: 'ecoMode',\n device_address: msg.device_address,\n payload: {temp:18, date:(new Date((new Date()).valueOf()+ 1000*60*60))},\n };\n// node.send(newmsg3);\n\n var newmsg = {\n cmd: 'setLock',\n device_address: msg.device_address,\n payload: 1,\n };\n node.send(newmsg);\n\n var newmsg4 = {\n cmd: 'setLock',\n device_address: msg.device_address,\n payload: 0,\n };\n node.send(newmsg4);\n\n\n\n","outputs":1,"noerr":0,"x":280,"y":1120,"wires":[["50d15325.61df5c"]]},{"id":"33975019.ed20b","type":"inject","z":"d9611430.c0dd78","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":80,"y":1100,"wires":[["ceae85fd.4c5c58"]]},{"id":"4d7e0649.4b1228","type":"inject","z":"d9611430.c0dd78","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":80,"y":1160,"wires":[["41363ada.16b1b4"]]},{"id":"41363ada.16b1b4","type":"function","z":"d9611430.c0dd78","name":"testCommands","func":"var eq = global.get('eq');\n\nif (!eq) return;\n\nvar eq3info = eq();\nvar eq3 = eq3info.eq3;\n\n\nif (!eq3)\n return;\n\nmsg.device_address = \"00:1a:22:09:2c:df\";\n\nif (!msg.device_address){\n node.warn(\"no device address\");\n return;\n}\n\n\nvar device = eq3info.devices[msg.device_address];\nvar info = eq3info.info[msg.device_address];\n\n\nif (!device || !info){\n return;\n}\n\nvar s = function(b){\n var newmsg3 = {\n cmd: 'sendRaw',\n device_address: msg.device_address,\n payload: new Buffer(b, 'hex'),\n };\n node.send(newmsg3);\n \n}\n\ns('b0');\ns('c0');\ns('d0');\ns('e0');\n\nreturn;\n\n\n\n\n\n var newmsg2 = {\n cmd: 'manualMode',\n device_address: msg.device_address,\n payload: null,\n };\n node.send(newmsg2);\n\n var newmsg4 = {\n cmd: 'setTemperature',\n device_address: msg.device_address,\n payload: 10,\n };\n node.send(newmsg4);\n\n \nreturn;\n\n\n var newmsg = {\n cmd: 'setLock',\n device_address: msg.device_address,\n payload: 1,\n };\n node.send(newmsg);\n\n var newmsg4 = {\n cmd: 'setLock',\n device_address: msg.device_address,\n payload: 0,\n };\n node.send(newmsg4);\n\n\n\n","outputs":1,"noerr":0,"x":280,"y":1180,"wires":[["50d15325.61df5c"]]},{"id":"7c1d2c4d.b03194","type":"function","z":"d9611430.c0dd78","name":"testCommands","func":"var eq = global.get('eq');\n\nif (!eq) return;\n\nvar eq3info = eq();\nvar eq3 = eq3info.eq3;\n\n\nif (!eq3)\n return;\n\nmsg.device_address = \"00:1a:22:09:2c:db\";\n\nif (!msg.device_address){\n node.warn(\"no device address\");\n return;\n}\n\n\nvar device = eq3info.devices[msg.device_address];\n\nnode.warn(util.inspect(device));\nmsg.payload = device._characteristics;\n\nreturn msg;","outputs":1,"noerr":0,"x":280,"y":1340,"wires":[["ff3eead8.073548"]]},{"id":"14830a0f.c1dad6","type":"inject","z":"d9611430.c0dd78","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":100,"y":1340,"wires":[["7c1d2c4d.b03194"]]},{"id":"ff3eead8.073548","type":"debug","z":"d9611430.c0dd78","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":480,"y":1360,"wires":[]},{"id":"97f7e5e9.0866f8","type":"function","z":"d9611430.c0dd78","name":"Retry connect loop","func":"\nreturn msg;","outputs":1,"noerr":0,"x":550,"y":660,"wires":[["9e0b8b90.df8918"]]},{"id":"aaa501f8.d744e","type":"mqtt out","z":"d9611430.c0dd78","name":"","topic":"","qos":"0","retain":"false","broker":"2d9e7c35.a76844","x":870,"y":40,"wires":[]},{"id":"4ab8a582.5327fc","type":"debug","z":"d9611430.c0dd78","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":520,"y":80,"wires":[]},{"id":"54b66c60.4141f4","type":"mqtt in","z":"d9611430.c0dd78","name":"","topic":"blectl/+","qos":"2","broker":"2d9e7c35.a76844","x":500,"y":140,"wires":[["215868a1.824d98"]]},{"id":"42cdfd1a.281824","type":"debug","z":"d9611430.c0dd78","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":690,"y":220,"wires":[]},{"id":"215868a1.824d98","type":"function","z":"d9611430.c0dd78","name":"getservices","func":"var eq = global.get('eq');\n\nif (!eq) return;\n\nvar eq3info = eq();\nvar eq3 = eq3info.eq3;\n\nvar t = msg.topic.split('/');\nvar deviceuuid = t[t.length-1];\n\n\nif (eq3info.peripherals){\n if (eq3info.peripherals[deviceuuid] && eq3info.peripherals[deviceuuid].peripheral){\n var id = deviceuuid;\n \n if (eq3info.peripherals[deviceuuid].peripheral.connectable){\n var c = function(error){\n try{\n node.warn(\"connected\");\n node.warn(error);\n var cb = function(error, services, characteristics){\n var newmsg = {\n topic: \"blediscover/\"+id+\"/services\", \n };\n if (error){\n newmsg.payload = {\n error: error.toString()\n };\n } else {\n eq3info.peripherals[deviceuuid].services = services;\n \n newmsg.payload = {\n services:[]\n }\n for (var i = 0; i < services.length; i++){\n var service = {\n uuid: services[i].uuid,\n characteristics:[]\n };\n \n for (var c = 0; c < services[i].characteristics.length; c++){\n var characteristic = {\n uuid: services[i].characteristics[c].uuid,\n properties: services[i].characteristics[c].properties,\n \n \n };\n service.characteristics.push(characteristic);\n }\n \n newmsg.payload.services.push(service);\n }\n //node.warn(services);\n }\n eq3info.peripherals[deviceuuid].peripheral.disconnect();\n node.send(newmsg);\n }\n node.warn(\"request all services for \"+deviceuuid);\n eq3info.peripherals[deviceuuid].peripheral.discoverAllServicesAndCharacteristics(cb);\n } catch(e){\n node.warn(e);\n }\n }\n try{\n eq3info.peripherals[deviceuuid].peripheral.connect(c)\n } catch(e){\n node.warn(e);\n }\n } else {\n node.warn(\"not connectable\");\n }\n \n }\n}\n\n","outputs":1,"noerr":0,"x":610,"y":180,"wires":[["42cdfd1a.281824","aaa501f8.d744e"]]},{"id":"b03aed81.005c2","type":"mqtt in","z":"d9611430.c0dd78","name":"","topic":"blectl/+/+/+","qos":"2","broker":"2d9e7c35.a76844","x":500,"y":320,"wires":[["c3fdff55.1b8f7"]]},{"id":"c3fdff55.1b8f7","type":"function","z":"d9611430.c0dd78","name":"characteristic","func":"var eq = global.get('eq');\n\nif (!eq) return;\n\nvar eq3info = eq();\nvar eq3 = eq3info.eq3;\n\nvar t = msg.topic.split('/');\nvar deviceuuid = t[t.length-3];\nvar serviceuuid = t[t.length-2];\nvar characteristicuuid = t[t.length-1];\n\n\nif (eq3info.peripherals){\n if (eq3info.peripherals[deviceuuid] && eq3info.peripherals[deviceuuid].services){\n \n// return;\n \n var services = eq3info.peripherals[deviceuuid].services;\n \n for (var s = 0; s < services.length; s++){\n if (services[s].uuid === serviceuuid){\n var service = services[s];\n for (var c = 0; c < service.characteristics.length; c++){\n if (service.characteristics[c].uuid === characteristicuuid){\n char = service.characteristics[c];\n var cb = function(error, data){\n try{\n node.warn('read cb');\n node.warn(data);\n \n var newmsg = {\n topic: \"blediscover/\"+deviceuuid+\"/\"+serviceuuid+\"/\"+characteristicuuid, \n };\n if (error){\n newmsg.payload = {\n error: error.toString()\n };\n } else {\n newmsg.payload = { data:data.toString('hex') };\n }\n node.send(newmsg);\n } catch(e){\n node.warn(e);\n }\n }\n \n \n if (eq3info.peripherals[deviceuuid].peripheral.state === 'connected'){\n node.warn(\"reading connected\");\n try{\n char.read(cb);\n } catch(e){\n node.warn(e);\n }\n } else {\n node.warn(\"calling connect\");\n //node.warn(eq3info.peripherals[deviceuuid]);\n if (eq3info.peripherals[deviceuuid].peripheral.connectable){\n var c = function(error){\n try{\n node.warn(\"connected\");\n node.warn(error);\n char.read(cb);\n } catch(e){\n node.warn(e);\n }\n }\n try{\n eq3info.peripherals[deviceuuid].peripheral.connect(c)\n } catch(e){\n node.warn(e);\n }\n } else {\n node.warn(\"not connectable\");\n }\n }\n break;\n }\n }\n break;\n }\n }\n } else {\n node.warn(\"no services\");\n }\n}\n\n","outputs":1,"noerr":0,"x":650,"y":320,"wires":[["aaa501f8.d744e"]]},{"id":"34dcf9c9.e64796","type":"ui_group","z":"","name":"heating","tab":"95e3af4d.5dfb5","disp":true,"width":"6","collapse":false},{"id":"24fd5e57.122362","type":"ui_group","z":"","name":"Default","tab":"95e3af4d.5dfb5","disp":true,"width":"6","collapse":false},{"id":"2d9e7c35.a76844","type":"mqtt-broker","z":"","name":"","broker":"192.168.1.210","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"95e3af4d.5dfb5","type":"ui_tab","z":"","name":"Home","icon":"dashboard"}] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment