gistfile1.txt
[{"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\"}}","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 eq3 = global.get('eq3');\nvar eq3info = global.get('eq3info');\n\nif (!eq3){\n eq3 = require('/home/pi/.node-red/node_modules/node-red-contrib-eq3-bluetooth/lib/eq3device.js');\n global.set('eq3', eq3);\n eq3info = {\n devices: {},\n names:{},\n info:{}\n };\n \n global.set('eq3info', eq3info);\n node.warn(\"new global eq3\");\n} else {\n node.warn(\"existing global eq3\");\n}\n\nif (msg.payload.names){\n eq3info.names = msg.payload.names;\n}\n\neq3.prototype.SCAN_DUPLICATES = true;\n\n\nvar eq3info = global.get('eq3info');\n\nif (eq3info.discovercallback){\n 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 var eq3info = global.get('eq3info');\n\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);\nglobal.set('eq3info', eq3info);\n\neq3.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 eq3 = global.get('eq3');\nvar eq3info = global.get('eq3info');\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 eq3 = global.get('eq3');\nvar eq3info = global.get('eq3info');\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 eq3 = global.get('eq3');\nvar eq3info = global.get('eq3info');\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 eq3 = global.get('eq3');\nvar eq3info = global.get('eq3info');\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 eq3 = global.get('eq3');\nvar eq3info = global.get('eq3info');\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 eq3 = global.get('eq3');\nvar eq3info = global.get('eq3info');\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 eq3 = global.get('eq3');\nvar eq3info = global.get('eq3info');\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 eq3 = global.get('eq3');\nvar eq3info = global.get('eq3info');\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 eq3 = global.get('eq3');\nvar eq3info = global.get('eq3info');\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":"\nvar eq3 = global.get('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 eq3 = global.get('eq3');\nvar eq3info = global.get('eq3info');\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":"\n\nvar eq3 = global.get('eq3');\nvar eq3info = global.get('eq3info');\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":"\n\nvar eq3 = global.get('eq3');\nvar eq3info = global.get('eq3info');\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 eq3 = global.get('eq3');\nvar eq3info = global.get('eq3info');\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":"\n\nvar eq3 = global.get('eq3');\nvar eq3info = global.get('eq3info');\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":"\n\nvar eq3 = global.get('eq3');\nvar eq3info = global.get('eq3info');\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":"\n\nvar eq3 = global.get('eq3');\nvar eq3info = global.get('eq3info');\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":"\n\nvar eq3 = global.get('eq3');\nvar eq3info = global.get('eq3info');\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":"\n\nvar eq3 = global.get('eq3');\nvar eq3info = global.get('eq3info');\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":"\n\nvar eq3 = global.get('eq3');\nvar eq3info = global.get('eq3info');\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":"\n\nvar eq3 = global.get('eq3');\nvar eq3info = global.get('eq3info');\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":"\n\nvar eq3 = global.get('eq3');\nvar eq3info = global.get('eq3info');\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 eq3info = global.get('eq3info');\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 eq3info = global.get('eq3info');\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"}]