msg.headers += {
'rejectUnauthorized': 'false',
};
msg.payload += '<?xml version="1.0" ?><SMARTPLUG id="edimax"><CMD id="get"><NOW_POWER><Device.System.Power.NowPower/></NOW_POWER></CMD></SMARTPLUG>';
return msg;2016-01-03 13:35:11,450 - DEBUG [ smartplug] - Request: <?xml version="1.0" ?><SMARTPLUG id="edimax"><CMD id="get"><NOW_POWER><Device.System.Power.NowPower/></NOW_POWER></CMD></SMARTPLUG>
2016-01-03 13:35:11,582 - INFO [ connectionpool] - Starting new HTTP connection (1): 192.168.7.200
2016-01-03 13:35:11,659 - DEBUG [ connectionpool] - "POST /smartplug.cgi HTTP/1.1" 200 177
2016-01-03 13:35:11,671 - DEBUG [ smartplug] - Status code: 200
2016-01-03 13:35:11,674 - DEBUG [ smartplug] - Response: <?xml version="1.0" encoding="UTF8"?><SMARTPLUG id="edimax"><CMD id="get"><NOW_POWER><Device.System.Power.NowPower>0</Device.System.Power.NowPower></NOW_POWER></CMD></SMARTPLUG>{
"topic": "",
"payload": "<h1>Error - Document
follows</h1>\n<pre>This web server is running in SSL mode.
Try the URL <a
href='https://UNKNOWN:10000/'>https://UNKNOWN:10000/</a>
instead.<br></pre>\n",
"_msgid": "1de860f3.e2179f",
"headers": {
"server": "MiniServ/1.760",
"date": "Sun, 3 Jan 2016 13:04:35 GMT",
"content-type": "text/html; Charset=iso-8859-1",
"connection": "close"
},
"statusCode": 200
}Enter code here...● node-RED.service - Node-RED is a tool for wiring together hardware devices, APIs and online services in new and interesting ways.
Loaded: loaded (/etc/systemd/system/node-RED.service; enabled)
Active: active (running) since Mon 2016-01-04 16:23:36 UTC; 2min 16s ago
Docs: http://nodered.org/
Main PID: 18887 (node-red-pi)
CGroup: /system.slice/node-RED.service
├─18887 /bin/bash /usr/bin/node-red-pi --max-old-space-size=128 red.js -v
└─18897 node-red
Jan 04 16:24:22 server-pi Node-RED[18887]: at runContinuation1 (/usr/lib/node_modules/node-red/node_modules/when/lib/makePromise.js:804:4)
Jan 04 16:24:22 server-pi Node-RED[18887]: at Fulfilled.when (/usr/lib/node_modules/node-red/node_modules/when/lib/makePromise.js:592:4)
Jan 04 16:24:22 server-pi Node-RED[18887]: at Pending.run (/usr/lib/node_modules/node-red/node_modules/when/lib/makePromise.js:483:13)
Jan 04 16:24:22 server-pi Node-RED[18887]: at Scheduler._drain (/usr/lib/node_modules/node-red/node_modules/when/lib/Scheduler.js:62:19)
Jan 04 16:24:22 server-pi Node-RED[18887]: at Scheduler.drain (/usr/lib/node_modules/node-red/node_modules/when/lib/Scheduler.js:27:9)
Jan 04 16:24:22 server-pi Node-RED[18887]: at process._tickCallback (node.js:419:13)
Jan 04 16:25:48 server-pi Node-RED[18887]: 4 Jan 16:25:48 - [info] Stopping flows
Jan 04 16:25:48 server-pi Node-RED[18887]: 4 Jan 16:25:48 - [info] Stopped flows
Jan 04 16:25:48 server-pi Node-RED[18887]: 4 Jan 16:25:48 - [info] Starting flows
Jan 04 16:25:48 server-pi Node-RED[18887]: 4 Jan 16:25:48 - [error] [smartplug-in:309e15bb.4c5b62] ReferenceError: Promise is not defined
Enter codeJan 4 16:38:00 server-pi systemd[1]: Starting Node-RED is a tool for wiring together hardware devices, APIs and online services in new and interesting ways....
Jan 4 16:38:00 server-pi systemd[1]: Started Node-RED is a tool for wiring together hardware devices, APIs and online services in new and interesting ways..
Jan 4 16:38:13 server-pi Node-RED[18958]: Welcome to Node-RED
Jan 4 16:38:13 server-pi Node-RED[18958]: ===================
Jan 4 16:38:13 server-pi Node-RED[18958]: 4 Jan 16:38:13 - [info] Node-RED version: v0.12.1
Jan 4 16:38:13 server-pi Node-RED[18958]: 4 Jan 16:38:13 - [info] Node.js version: v0.10.29
Jan 4 16:38:13 server-pi Node-RED[18958]: 4 Jan 16:38:13 - [info] Loading palette nodes
Jan 4 16:38:18 server-pi Node-RED[18958]: 4 Jan 16:38:18 - [warn] Cannot find Pi RPi.GPIO python library
Jan 4 16:38:43 server-pi Node-RED[18958]: 4 Jan 16:38:43 - [rpi-ledborg] Info : Can't find RPi.GPIO python library.
Jan 4 16:38:43 server-pi Node-RED[18958]: 4 Jan 16:38:43 - [warn] ------------------------------------------
Jan 4 16:38:43 server-pi Node-RED[18958]: 4 Jan 16:38:43 - [warn] [rpi-gpio] Warning : Cannot find Pi RPi.GPIO python library
Jan 4 16:38:43 server-pi Node-RED[18958]: 4 Jan 16:38:43 - [warn] [smartplug] Error: Cannot find module 'edimax-smartplug'
Jan 4 16:38:43 server-pi Node-RED[18958]: 4 Jan 16:38:43 - [warn] [ledborg] Warning : Can't find RPi.GPIO python library.
Jan 4 16:38:43 server-pi Node-RED[18958]: 4 Jan 16:38:43 - [warn] ------------------------------------------
Jan 4 16:38:43 server-pi Node-RED[18958]: 4 Jan 16:38:43 - [info] Settings file : /root/.node-red/settings.js
Jan 4 16:38:43 server-pi Node-RED[18958]: 4 Jan 16:38:43 - [info] User directory : /root/.node-red
Jan 4 16:38:43 server-pi Node-RED[18958]: 4 Jan 16:38:43 - [info] Flows file : /root/.node-red/red.js
Jan 4 16:38:43 server-pi Node-RED[18958]: 4 Jan 16:38:43 - [info] Server now running at http://127.0.0.1:1880/
Jan 4 16:38:44 server-pi Node-RED[18958]: 4 Jan 16:38:44 - [info] Starting flows
Jan 4 16:38:44 server-pi Node-RED[18958]: 4 Jan 16:38:44 - [error] [smartplug-in:309e15bb.4c5b62] ReferenceError: Promise is not defined
Jan 4 16:38:44 server-pi Node-RED[18958]: Potentially unhandled rejection [1] TypeError: Cannot read property 'type' of null
Jan 4 16:38:44 server-pi Node-RED[18958]: at Flow.start (/usr/lib/node_modules/node-red/red/nodes/flows/Flow.js:81:25)
Jan 4 16:38:44 server-pi Node-RED[18958]: at start (/usr/lib/node_modules/node-red/red/nodes/flows/index.js:251:29)
Jan 4 16:38:44 server-pi Node-RED[18958]: at tryCatchReject (/usr/lib/node_modules/node-red/node_modules/when/lib/makePromise.js:845:30)
Jan 4 16:38:44 server-pi Node-RED[18958]: at runContinuation1 (/usr/lib/node_modules/node-red/node_modules/when/lib/makePromise.js:804:4)
Jan 4 16:38:44 server-pi Node-RED[18958]: at Fulfilled.when (/usr/lib/node_modules/node-red/node_modules/when/lib/makePromise.js:592:4)
Jan 4 16:38:44 server-pi Node-RED[18958]: at Pending.run (/usr/lib/node_modules/node-red/node_modules/when/lib/makePromise.js:483:13)
Jan 4 16:38:44 server-pi Node-RED[18958]: at Scheduler._drain (/usr/lib/node_modules/node-red/node_modules/when/lib/Scheduler.js:62:19)
Jan 4 16:38:44 server-pi Node-RED[18958]: at Scheduler.drain (/usr/lib/node_modules/node-red/node_modules/when/lib/Scheduler.js:27:9)
Jan 4 16:38:44 server-pi Node-RED[18958]: at process._tickCallback (node.js:419:13)
Jan 4 16:39:37 server-pi Node-RED[18958]: 4 Jan 16:39:37 - [info] Stopping flows
Jan 4 16:39:37 server-pi Node-RED[18958]: 4 Jan 16:39:37 - [info] Stopped flows
Jan 4 16:39:37 server-pi Node-RED[18958]: 4 Jan 16:39:37 - [info] Starting flows
Jan 4 16:39:37 server-pi Node-RED[18958]: 4 Jan 16:39:37 - [error] [smartplug-in:309e15bb.4c5b62] ReferenceError: Promise is not defined
here...--
http://nodered.org
---
You received this message because you are subscribed to the Google Groups "Node-RED" group.
To unsubscribe from this group and stop receiving emails from it, send an email to node-red+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Enter code here...Jan 4 17:10:30 server-pi Node-RED[19151]: 4 Jan 17:10:30 - [warn] [smartplug] Error: Cannot find module 'edimax-smartplug'
Jan 4 17:10:30 server-pi Node-RED[19151]: 4 Jan 17:10:30 - [info] Waiting for missing types to be registered:
Jan 4 17:10:30 server-pi Node-RED[19151]: 4 Jan 17:10:30 - [info] - smartplug-device
This will display the configuration nodes in the sidebar, where you will see a list and the number of nodes using that configuration.
Any that aren't being used will have a 0 by them, you can double click on them and then click delete.
Then click deploy to save that change.
So your "home" node-red directory is /root/.node-red
and thats the directory you would need to be in to install the additional nodes.
ageJan 4 19:24:45 server-pi Node-RED[19342]: 4 Jan 19:24:45 - [warn] [smartplug] Error: Cannot find module 'edimax-smartplug'
Jan 04 21:02:31 pi2 NR-Live2[5310]: Unhandled rejection Error: Request timeout occurred - request abortedJan 04 21:02:31 pi2 NR-Live2[5310]: at ClientRequest.http.request.on.on.timeoutOccurred (/home/pi/node/nr-live2/node_modules/node-red-contrib-smartplug/node_modules/edimax-smartplug/index.js:87:29)Jan 04 21:02:31 pi2 NR-Live2[5310]: at ClientRequest.EventEmitter.emit (events.js:95:17)Jan 04 21:02:31 pi2 NR-Live2[5310]: at Socket.socketCloseListener (http.js:1522:9)Jan 04 21:02:31 pi2 NR-Live2[5310]: at Socket.EventEmitter.emit (events.js:117:20)Jan 04 21:02:31 pi2 NR-Live2[5310]: at TCP.close (net.js:465:12){ "name": "editest", "version": "0.0.0", "description": "Test the edimax-smartplug module", "main": "index.js", "scripts": { "start": "node index.js", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "dependencies": { "edimax-smartplug": "0.0.10" }}var edimax = require("edimax-smartplug")//console.dir(edimax)
var options = { timeout: 10000, name:'SP01', host:'192.168.1.117', username: 'admin', password: '1234'}
edimax.getDeviceInfo(options).then(function (info) { console.log(info)}).catch(function(e) {console.log("Request failed: ", e)})
// set switch ONedimax.setSwitchState(true, options).catch(function(e) {console.log(e)})
// get switch statusedimax.getSwitchState(options).then(function (state) { console.log("Switch is", state?"ON":"OFF")}).catch(function(e) {console.log(e)})
// get switch poweredimax.getSwitchPower(options).then(function (power) { console.log("Current switch power", power, "Watts")}).catch(function(e) {console.log(e)})
// get switch energy readingedimax.getSwitchEnergy(options).then(function (energy) { console.log(energy)}).catch(function(e) {console.log(e)})
// get switch energy readingedimax.getStatusValues(true, options).then(function (data) { console.log(data)}).catch(function(e) {console.log(e)})
pi@pi2 ~/node/editest $ npm start
> edi...@0.0.0 start /home/pi/node/editest> node index.js
{ vendor: 'Edimax', model: 'SP2101W', fwVersion: '1.03', mac: '801F02FA90B7' }Switch is ONCurrent switch power 1.07 Watts{ day: 0.003, week: 0.003, month: 0.003 }{ state: true, nowPower: 1.07, nowCurrent: 0.012, day: 0.003, week: 0.003, month: 0.003, lastToggleTime: Mon Jan 04 2016 21:54:12 GMT+0000 (GMT) }
...
--
Promise.all(node.promises).then(function(result) {
var Promise = require("bluebird");
Thanks Nick. Yes, I think Brian has already done so. I'll add some comments shortly.I've found the issue actually. But I don't know the fix.Line 56 of smartplug.js references:Promise.all(node.promises).then(function(result) {But "Promise" is not defined. I rather think that is because it didn't get put into node.js natively until after v0.10.x So you actually need a new version of node to run it.
That isn't true of the underlying module though which seems quite happy because it is using the Bluebird library for promises so works fine with older versions of node. So the package.json for the node needs to reference the appropriate "engine".
...
Hi Julian,
Brilliant. I'll try it tonight when I'm home. Actually a regular feed is just what I want as I'll feed it, via MQTT, into a system called EmonCMS part of the Open Energy Monitor project.
It will allow me to monitor energy use for specific bits of equipment.
Really appreciate it.
Brian
--
http://nodered.org
---
You received this message because you are subscribed to a topic in the Google Groups "Node-RED" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/node-red/Z5FApuA_WHg/unsubscribe.
To unsubscribe from this group and all its topics, send an email to node-red+u...@googlegroups.com.
Hi Julian,
Could I trouble you for a copy of the flow please? As I say, pretty new to node-red and it would be great to see an example of how to do it.
Do you follow the OEM forums? I put some bits up about getting data into EmonCMS via MQTT.
Cheers.
[{"id":"3a35caa3.80b476","type":"mqtt-broker","broker":"localhost","port":"1883","clientid":"Pi2-NR"},{"id":"1ece064a.e131fa","type":"serial-port","serialport":"/dev/arduino","serialbaud":"9600","databits":"8","parity":"none","stopbits":"1","newline":"\\n","bin":"false","out":"char","addchar":false},{"id":"89d16e5f.bf536","type":"serial-port","serialport":"/dev/ttyAMA0","serialbaud":"9600","databits":"8","parity":"none","stopbits":"1","newline":"1000","bin":"false","out":"time","addchar":true},{"id":"42d3e5eb.858c74","type":"rfxtrx-port","port":"/dev/rfxtrx433e"},{"id":"4acf3302.73708c","type":"rfx-lights-in","name":"Listen to RFX: Lights","port":"42d3e5eb.858c74","topicSource":"all","topic":"","x":130.5833740234375,"y":333.03336334228516,"z":"32aed56e.8ec7a2","wires":[["ac818e1b.0fa2d","f8395d8f.07c6a","1d981452.e267ec"]]},{"id":"8539b916.665d08","type":"rfx-sensor","name":"Listen to RFX: Sensor","port":"42d3e5eb.858c74","topicSource":"all","topic":"","x":138.5,"y":501.30005645751953,"z":"32aed56e.8ec7a2","wires":[["2f84b877.bac218","c2ad6955.3d5298"]]},{"id":"91318d43.c08b1","type":"rfx-meter","name":"Listen to RFX: Meter","port":"42d3e5eb.858c74","topicSource":"all","topic":"","x":129.3499755859375,"y":411.30004119873047,"z":"32aed56e.8ec7a2","wires":[["d07b1259.59f778","c2ad6955.3d5298"]]},{"id":"4b33990d.f43ae8","type":"serial in","name":"SRF (Slice of Pi)","serial":"89d16e5f.bf536","x":121.5,"y":620.3000259399414,"z":"32aed56e.8ec7a2","wires":[["b556d6a4.31785","f2772d67.0d88d","11ff5bfe.ee00a4"]]},{"id":"85a18917.7a5e78","type":"serial in","name":"USB1 (Arduino Nano)","serial":"1ece064a.e131fa","x":145.8958282470703,"y":749.5555801391602,"z":"32aed56e.8ec7a2","wires":[["80187c48.7fe78","8421beba.7bde4"]]},{"id":"f2772d67.0d88d","type":"change","name":"","rules":[{"t":"set","p":"topic","to":"ARD/UNO1"},{"t":"set","p":"inputController","to":"SRF"},{"t":"set","p":"type","to":"SENSOR"}],"action":"","property":"","from":"","to":"","reg":false,"x":261.8958282470703,"y":574.9999771118164,"z":"32aed56e.8ec7a2","wires":[["5565077c.aa9af8"]]},{"id":"8421beba.7bde4","type":"change","name":"","rules":[{"t":"set","p":"topic","to":"ARD/NANO1"},{"t":"set","p":"inputController","to":"PIUSB"},{"t":"set","p":"type","to":"SENSOR"}],"action":"","property":"","from":"","to":"","reg":false,"x":280.8958282470703,"y":693.2221450805664,"z":"32aed56e.8ec7a2","wires":[["5565077c.aa9af8"]]},{"id":"c2ad6955.3d5298","type":"change","name":"","rules":[{"t":"set","p":"inputController","to":"RFX"},{"t":"set","p":"type","to":"SENSOR"}],"action":"","property":"","from":"","to":"","reg":false,"x":347.6665344238281,"y":403.66666412353516,"z":"32aed56e.8ec7a2","wires":[["5565077c.aa9af8"]]},{"id":"f8395d8f.07c6a","type":"debug","name":"","active":false,"console":"false","complete":"true","x":368.6666564941406,"y":257.6666564941406,"z":"32aed56e.8ec7a2","wires":[]},{"id":"5565077c.aa9af8","type":"function","name":"Normalise and Enrich","func":"/***\n * Normalise and enrich input from hardware prior to sending out to MQTT\n * \n * Requirements:\n * msg.topic must be set & have at least 1 '/' eg: ARD/UN1, ARD/NANO1, TH1/0x3001, AC/0x0000A9F8/2, etc\n * msg.payload must be set (but can be either a string or an object)\n * Returns:\n * msg with topic and payload ready to sent to MQTT\n ***/\n\n// If no topic, just exit\nif ( !('topic' in msg) ) {\n // If no topic, we have to drop the msg since MQTT wont know what to do with it\n node.warn( 'msg dropped - no topic, from %s', msg.inputController );\n return;\n}\n\nmsg.topic = msg.topic.replace( '+', '0' );\n\n// We want all payloads here to be JSON\nif ( typeof msg.payload == 'string' ) {\n // If str payload contains open/close braces, it should be a JSON strong\n if ( msg.payload.match( /[{}]/g ) ) {\n try {\n msg.payload = JSON.parse(msg.payload);\n } catch (err) {\n // If we cannot parse the JSON input, may as well just drop it\n node.warn( 'msg dropped, from ' + msg.inputController );\n node.warn( msg );\n return;\n }\n } else {\n // Not a JSON str so should contain a command string (from a remote, pir, etc)\n msg.payload = { 'command' : msg.payload };\n }\n}\n\n// msg.payload should now be an object\nif ( typeof msg.payload == 'string' ) {\n node.warn( 'msg dropped - payload is still a string, from %s, payload: %s', msg.inputController, msg.payload );\n return;\n}\n\n// if data contains \"info\" pass to the info output (2)\nif ( 'info' in msg.payload ) {\n return [null, msg];\n}\n\n// Track date/time\nmsg.payload.timestamp = new Date();\n\n// Keep a copy of the original topic\nmsg.payload.topic = msg.topic;\n// Keep track of the input controller (e.g. RFX, PIUSB, SRF, etc)\nmsg.payload.inputController = msg.inputController;\n\n// Split topic to payload: ARD/UN1, ARD/NANO1, TH1/0x3001, AC/0x0000A9F8/2, etc.\nvar topic = msg.topic.split('/');\n\n// Enance metadata from the topic\nif (topic.length >= 2) {\n // e.g. LIGHTWAVERF, TH1, AC, ARD (Arduino)\n\tmsg.payload.deviceFamily = topic[0];\n\tmsg.payload.id = topic[1];\n} else {\n // topic doesn't contain a / so error and exit\n node.warn( 'msg dropped - topic too short, from %s, topic: %s', msg.inputController, msg.topic );\n return;\n}\nif (topic.length == 3 ) {\n // NB: unitAddr=\"+\" for Nexa == Group (e.g. Group On)\n\tmsg.payload.unitAddr = topic[2];\n} else if ( topic.length == 4 ) {\n\tmsg.payload.unitGroup = topic[2];\n\tmsg.payload.unitAddr = topic[3];\n} else if ( topic.length >= 4 ) { // >4 entries, we are clueless!\n\ttopic.splice(0, 2); // remove 1st 2 entries\n\tmsg.payload.unitAddr = topic;\n}\n\n// RFX reports status on msg, move to payload and extract rssi/battery level if present\nif ( 'status' in msg) {\n msg.payload.status = msg.status;\n if ( 'rssi' in msg.status) {\n msg.payload.rssi = msg.status.rssi;\n }\n if ( 'battery' in msg.status) {\n msg.payload.battery = msg.status.battery;\n }\n}\n\n// Standardise main sensor readings \nif ( !('Temperature' in msg.payload) ) {\n if ( 'temperature' in msg.payload ) {\n if ( 'value' in msg.payload.temperature ) {\n msg.payload.Temperature = msg.payload.temperature.value;\n }\n }\n}\nif ( !('Humidity' in msg.payload) ) {\n if ( 'humidity' in msg.payload ) {\n if ( 'value' in msg.payload.humidity ) {\n msg.payload.Humidity = msg.payload.humidity.value;\n }\n }\n}\nif ( !('Light' in msg.payload) ) {\n if ( 'LDR' in msg.payload ) {\n msg.payload.Light = msg.payload.LDR;\n }\n}\n\n// What features/capabilities does this device have?\nmsg.payload.deviceFeatures = '';\nif ( 'Temperature' in msg.payload ) {\n msg.payload.deviceFeatures += 'T';\n}\nif ( 'Humidity' in msg.payload ) {\n msg.payload.deviceFeatures += 'H';\n}\nif ( 'Pressure' in msg.payload ) {\n msg.payload.deviceFeatures += 'P';\n}\nif ( 'Light' in msg.payload ) {\n msg.payload.deviceFeatures += 'L';\n}\n// for PIR's - they come in as controls, enrich as sensors\nif ( msg.payload.id === '0x0000A9F8' ) {\n if ( msg.payload.command === 'On' ) {\n msg.payload.Movement = true;\n } else {\n msg.payload.Movement = false;\n }\n msg.payload.deviceFeatures += 'M';\n}\nif ( msg.type === 'CONTROLLER' ) {\n msg.payload.deviceFeatures += 'C';\n}\n\n// Add sealevel pressure if not present to allow comparisons\n// with weather stations\nif ('Pressure' in msg.payload) {\n if ('Pressure_Sealevel' in msg.payload) {\n // Don't bother\n } else {\n var A = 201, //Altitude of sensor <<-- TODO: replace with lookup\n P = msg.payload.Pressure\n ;\n \tmsg.payload.Pressure_Sealevel = round( P/Math.pow( (1-(A/44330.0)), 5.255 ), 2 );\n }\n}\n\nif ( ('Temperature' in msg.payload) && ('Humidity' in msg.payload) ) {\n if ('Heat_Index' in msg.payload) {\n // Don't bother\n } else {\n //msg.payload.Heat_Index = heatIndex(msg.payload.Temperature, msg.payload.Humidity);\n msg.payload.Heat_Index = computeHeatIndex(msg.payload.Temperature, msg.payload.Humidity, false)\n }\n if ('DewPoint' in msg.payload) {\n // Don't bother\n } else {\n msg.payload.DewPoint = dewPointFast(msg.payload.Temperature, msg.payload.Humidity);\n }\n}\n\n// Add std topic header to make MQTT handing simpler\nmsg.topic = 'HARDWARE-IN/' + msg.topic;\n\nreturn [msg,null];\n\n/***\n * Output schema:\n * msg {\n topic: HARDWARE-IN/<deviceid>\n payload : {\n id : device identifier // UNO1, NANO1, 0x3001, etc\n unitAddr : n // For controllers/sensors with multiple units on one ID, can also be +\n deviceFamily : xx // e.g. LIGHTWAVERF, TH1, AC, ARD (Arduino)\n unitGroup: n\n command : command string (e.g. remote controls or PIRs, on/off/On/Off/GroupOn/Mood1/etc)\n rssi : n // signal level if available - optional\n battery : n // battery level if available - optional\n status : { rssi, battery } // Optional\n timestamp: // when msg was recieved\n }\n }\n ***/\n\nfunction round(num, decimals) {\n var n = Math.pow(10, decimals);\n return Math.round( (n * num).toFixed(decimals) ) / n;\n}\n\nfunction convertCtoF(c) {\n return c * 1.8 + 32;\n}\nfunction convertFtoC(f) {\n return (f - 32) * 0.55555;\n}\n\n// See: http://arduinotronics.blogspot.co.uk/2013/12/temp-humidity-w-dew-point-calcualtions.html\n// delta max = 0.6544 wrt dewPoint()\n// 6.9 x faster than dewPoint()\n// reference: http://en.wikipedia.org/wiki/Dew_point\nfunction dewPointFast(celsius, humidity) {\n var a = 17.271;\n var b = 237.7;\n var temp = (a * celsius) / (b + celsius) + Math.log(humidity * 0.01);\n var Td = (b * temp) / (a - temp);\n return round( Td, 1 );\n}\n\n//boolean isFahrenheit: True == Fahrenheit; False == Celcius\nfunction computeHeatIndex(temperature, percentHumidity, isFahrenheit) {\n // Using both Rothfusz and Steadman's equations\n // http://www.wpc.ncep.noaa.gov/html/heatindex_equation.shtml\n var hi;\n\n if (!isFahrenheit)\n temperature = convertCtoF(temperature);\n\n hi = 0.5 * (temperature + 61.0 + ((temperature - 68.0) * 1.2) + (percentHumidity * 0.094));\n\n if (hi > 79) {\n hi = -42.379 +\n 2.04901523 * temperature +\n 10.14333127 * percentHumidity +\n -0.22475541 * temperature * percentHumidity +\n -0.00683783 * Math.pow(temperature, 2) +\n -0.05481717 * Math.pow(percentHumidity, 2) +\n 0.00122874 * Math.pow(temperature, 2) * percentHumidity +\n 0.00085282 * temperature * Math.pow(percentHumidity, 2) +\n -0.00000199 * Math.pow(temperature, 2) * Math.pow(percentHumidity, 2);\n\n if((percentHumidity < 13) && (temperature >= 80.0) && (temperature <= 112.0))\n hi -= ((13.0 - percentHumidity) * 0.25) * Math.sqrt((17.0 - Math.abs(temperature - 95.0)) * 0.05882);\n\n else if((percentHumidity > 85.0) && (temperature >= 80.0) && (temperature <= 87.0))\n hi += ((percentHumidity - 85.0) * 0.1) * ((87.0 - temperature) * 0.2);\n }\n\n return isFahrenheit ? round( hi, 1 ) : round( convertFtoC(hi), 1 );\n}\n\nfunction heatIndex(tempC, humidity) {\n var tempF = convertCtoF(tempC);\n var c1 = -42.38, c2 = 2.049, c3 = 10.14, c4 = -0.2248, c5= -6.838e-3, c6=-5.482e-2, c7=1.228e-3, c8=8.528e-4, c9=-1.99e-6 ;\n var T = tempF;\n var R = humidity;\n \n var A = (( c5 * T) + c2) * T + c1;\n var B = ((c7 * T) + c4) * T + c3;\n var C = ((c9 * T) + c8) * T + c6;\n \n var rv = (C * R + B) * R + A;\n return round( rv, 1 );\n}\n","outputs":"2","noerr":0,"x":588.8958129882812,"y":387.8888931274414,"z":"32aed56e.8ec7a2","wires":[["93b006a3.6c4ff8"],["90e2bfdc.6f1d4"]]},{"id":"11ff5bfe.ee00a4","type":"debug","name":"","active":false,"console":"false","complete":"false","x":511.8958282470703,"y":623.222181885331,"z":"32aed56e.8ec7a2","wires":[]},{"id":"1d981452.e267ec","type":"change","name":"","rules":[{"t":"set","p":"inputController","to":"RFX"},{"t":"set","p":"type","to":"CONTROLLER"}],"action":"","property":"","from":"","to":"","reg":false,"x":345.89581298828125,"y":350.00000762939453,"z":"32aed56e.8ec7a2","wires":[["5565077c.aa9af8"]]},{"id":"90e2bfdc.6f1d4","type":"debug","name":"","active":false,"console":"false","complete":"true","x":748.895751953125,"y":427.00000762939453,"z":"32aed56e.8ec7a2","wires":[]},{"id":"93b006a3.6c4ff8","type":"mqtt out","name":"","topic":"","qos":"","retain":"","broker":"3a35caa3.80b476","x":750.8958129882812,"y":347.8888931274414,"z":"32aed56e.8ec7a2","wires":[]}]
[{"id":"3b2726f7.c4d8da","type":"mqtt-broker","z":"","broker":"localhost","port":"1883","clientid":"Pi2_NR-Live","usetls":false,"verifyservercert":true,"compatmode":false,"keepalive":"15","cleansession":true,"willTopic":"DEVICES/PI2NR-LIVE","willQos":"1","willRetain":"false","willPayload":"Offline","birthTopic":"DEVICES/PI2NR-LIVE","birthQos":"1","birthRetain":"false","birthPayload":"Online"},{"id":"ead23e97.152dc","type":"smartplug-device","z":"c919054f.36e6f8","name":"SP01","host":"192.168.1.117","timeout":"10","retry":"5"},{"id":"777c0880.8883f8","type":"smartplug-in","z":"c919054f.36e6f8","name":"Edimax SP01","topic":"WIFI/SP01","device":"ead23e97.152dc","interval":"30000","deviceinfo":false,"schedule":false,"status":true,"x":147,"y":140,"wires":[["3a37ca3.fc5c836"]]},{"id":"769b7f7f.89648","type":"debug","z":"c919054f.36e6f8","name":"","active":false,"console":"false","complete":"true","x":710,"y":100,"wires":[]},{"id":"7979bfe2.86864","type":"comment","z":"c919054f.36e6f8","name":"Wi-Fi Smartplugs","info":"","x":164.51483154296875,"y":91.54073333740234,"wires":[]},{"id":"30421ae0.cfbde6","type":"function","z":"c919054f.36e6f8","name":"Normalise and Enrich","func":"/***\n * Normalise and enrich input from hardware prior to sending out to MQTT\n * \n * Requirements:\n * msg.topic must be set & have at least 1 '/' eg: ARD/UN1, ARD/NANO1, TH1/0x3001, AC/0x0000A9F8/2, etc\n * msg.payload must be set (but can be either a string or an object)\n * Returns:\n * msg with topic and payload ready to sent to MQTT\n ***/\n\n// If no topic, just exit\nif ( !('topic' in msg) ) {\n // If no topic, we have to drop the msg since MQTT wont know what to do with it\n node.warn( 'msg dropped - no topic, from %s', msg.inputController );\n return;\n}\n\n// If the topic contains a + (e.g. Lightwave group on/off), change to a 0\nmsg.topic = msg.topic.replace( '+', '0' );\n\n// We want all payloads here to be JSON\nif ( typeof msg.payload == 'string' ) {\n // If str payload contains open/close braces, it should be a JSON strong\n if ( msg.payload.match( /[{}]/g ) ) {\n try {\n msg.payload = JSON.parse(msg.payload);\n } catch (err) {\n // If we cannot parse the JSON input, may as well just drop it\n node.warn( 'msg dropped, from ' + msg.inputController );\n node.warn( msg );\n return;\n }\n } else {\n // Not a JSON str so should contain a command string (from a remote, pir, etc)\n msg.payload = { 'command' : msg.payload };\n }\n}\n\n// msg.payload should now be an object\nif ( typeof msg.payload == 'string' ) {\n node.warn( 'msg dropped - payload is still a string, from %s, payload: %s', msg.inputController, msg.payload );\n return;\n}\n\n// if data contains \"info\" pass to the info output (2)\nif ( 'info' in msg.payload ) {\n return [null, msg];\n}\n// othewise\n\n// Track date/time\nmsg.payload.timestamp = new Date();\n\n// Keep a copy of the original topic\nmsg.payload.topic = msg.topic;\n// Keep track of the input controller (e.g. RFX, PIUSB, SRF, etc)\nmsg.payload.inputController = msg.inputController;\n\n// Split topic to payload: ARD/UN1, ARD/NANO1, TH1/0x3001, AC/0x0000A9F8/2, etc.\nvar topic = msg.topic.split('/');\n\n// Enance metadata from the topic\nif (topic.length >= 2) {\n // e.g. LIGHTWAVERF, TH1, AC, ARD (Arduino), WIFI\n\tmsg.payload.deviceFamily = topic[0];\n\tmsg.payload.id = topic[1];\n} else {\n // topic doesn't contain a / so error and exit\n node.warn( 'msg dropped - topic too short, from %s, topic: %s', msg.inputController, msg.topic );\n return;\n}\nif (topic.length == 3 ) {\n // NB: unitAddr=\"+\" for Nexa == Group (e.g. Group On)\n\tmsg.payload.unitAddr = topic[2];\n} else if ( topic.length == 4 ) {\n\tmsg.payload.unitGroup = topic[2];\n\tmsg.payload.unitAddr = topic[3];\n} else if ( topic.length >= 4 ) { // >4 entries, we are clueless!\n\ttopic.splice(0, 2); // remove 1st 2 entries\n\tmsg.payload.unitAddr = topic;\n}\n\n// RFX reports status on msg, move to payload and extract rssi/battery level if present\nif ( 'status' in msg) {\n msg.payload.status = msg.status;\n if ( 'rssi' in msg.status) {\n msg.payload.rssi = msg.status.rssi;\n }\n if ( 'battery' in msg.status) {\n msg.payload.battery = msg.status.battery;\n }\n}\n\n// Edimax Smartplug (WiFi) reports state as true/false, change to on/off to match other controllers\nif ( 'state' in msg.payload ) {\n msg.payload.state === true ? \"On\" : \"Off\";\n}\n\n// Standardise main sensor readings \nif ( !('Temperature' in msg.payload) ) {\n if ( 'temperature' in msg.payload ) {\n if ( 'value' in msg.payload.temperature ) {\n msg.payload.Temperature = msg.payload.temperature.value;\n }\n }\n}\nif ( !('Humidity' in msg.payload) ) {\n if ( 'humidity' in msg.payload ) {\n if ( 'value' in msg.payload.humidity ) {\n msg.payload.Humidity = msg.payload.humidity.value;\n }\n }\n}\nif ( !('Light' in msg.payload) ) {\n if ( 'LDR' in msg.payload ) {\n msg.payload.Light = msg.payload.LDR;\n }\n}\n\n// What features/capabilities does this device have?\nmsg.payload.deviceFeatures = '';\nif ( 'Temperature' in msg.payload ) {\n msg.payload.deviceFeatures += 'T';\n}\nif ( 'Humidity' in msg.payload ) {\n msg.payload.deviceFeatures += 'H';\n}\nif ( 'Pressure' in msg.payload ) {\n msg.payload.deviceFeatures += 'P';\n}\nif ( 'Light' in msg.payload ) {\n msg.payload.deviceFeatures += 'L';\n}\nif ( 'nowPower' in msg.payload ) {\n msg.payload.deviceFeatures += 'E'; // E = Energy (in watts)\n}\n// for PIR's - they come in as controls, enrich as sensors\nif ( msg.payload.id === '0x0000A9F8' ) {\n if ( msg.payload.command === 'On' ) {\n msg.payload.Movement = true;\n } else {\n msg.payload.Movement = false;\n }\n msg.payload.deviceFeatures += 'M';\n}\nif ( msg.type === 'CONTROLLER' ) {\n msg.payload.deviceFeatures += 'C';\n}\n\n// Add sealevel pressure if not present to allow comparisons\n// with weather stations\nif ('Pressure' in msg.payload) {\n if ('Pressure_Sealevel' in msg.payload) {\n // Don't bother\n } else {\n var A = 201, //Altitude of sensor <<-- TODO: replace with lookup\n P = msg.payload.Pressure\n ;\n \tmsg.payload.Pressure_Sealevel = round( P/Math.pow( (1-(A/44330.0)), 5.255 ), 2 );\n }\n}\n\nif ( ('Temperature' in msg.payload) && ('Humidity' in msg.payload) ) {\n if ('Heat_Index' in msg.payload) {\n // Don't bother\n } else {\n //msg.payload.Heat_Index = heatIndex(msg.payload.Temperature, msg.payload.Humidity);\n msg.payload.Heat_Index = computeHeatIndex(msg.payload.Temperature, msg.payload.Humidity, false)\n }\n if ('DewPoint' in msg.payload) {\n // Don't bother\n } else {\n msg.payload.DewPoint = dewPointFast(msg.payload.Temperature, msg.payload.Humidity);\n }\n}\n\n// Add std topic header to make MQTT handing simpler\nmsg.topic = 'HARDWARE-IN/' + msg.topic;\n\nreturn [msg,null];\n\n/***\n * Output schema:\n * msg {\n topic: HARDWARE-IN/<deviceid>\n payload : {\n id : device identifier // UNO1, NANO1, 0x3001, etc\n unitAddr : n // For controllers/sensors with multiple units on one ID, can also be +\n deviceFamily : xx // e.g. LIGHTWAVERF, TH1, AC, ARD (Arduino)\n unitGroup: n\n command : command string (e.g. remote controls or PIRs, on/off/On/Off/GroupOn/Mood1/etc)\n rssi : n // signal level if available - optional\n battery : n // battery level if available - optional\n status : { rssi, battery } // Optional\n timestamp: // when msg was recieved\n }\n }\n ***/\n\nfunction round(num, decimals) {\n var n = Math.pow(10, decimals);\n return Math.round( (n * num).toFixed(decimals) ) / n;\n}\n\nfunction convertCtoF(c) {\n return c * 1.8 + 32;\n}\nfunction convertFtoC(f) {\n return (f - 32) * 0.55555;\n}\n\n// See: http://arduinotronics.blogspot.co.uk/2013/12/temp-humidity-w-dew-point-calcualtions.html\n// delta max = 0.6544 wrt dewPoint()\n// 6.9 x faster than dewPoint()\n// reference: http://en.wikipedia.org/wiki/Dew_point\nfunction dewPointFast(celsius, humidity) {\n var a = 17.271;\n var b = 237.7;\n var temp = (a * celsius) / (b + celsius) + Math.log(humidity * 0.01);\n var Td = (b * temp) / (a - temp);\n return round( Td, 1 );\n}\n\n//boolean isFahrenheit: True == Fahrenheit; False == Celcius\nfunction computeHeatIndex(temperature, percentHumidity, isFahrenheit) {\n // Using both Rothfusz and Steadman's equations\n // http://www.wpc.ncep.noaa.gov/html/heatindex_equation.shtml\n var hi;\n\n if (!isFahrenheit)\n temperature = convertCtoF(temperature);\n\n hi = 0.5 * (temperature + 61.0 + ((temperature - 68.0) * 1.2) + (percentHumidity * 0.094));\n\n if (hi > 79) {\n hi = -42.379 +\n 2.04901523 * temperature +\n 10.14333127 * percentHumidity +\n -0.22475541 * temperature * percentHumidity +\n -0.00683783 * Math.pow(temperature, 2) +\n -0.05481717 * Math.pow(percentHumidity, 2) +\n 0.00122874 * Math.pow(temperature, 2) * percentHumidity +\n 0.00085282 * temperature * Math.pow(percentHumidity, 2) +\n -0.00000199 * Math.pow(temperature, 2) * Math.pow(percentHumidity, 2);\n\n if((percentHumidity < 13) && (temperature >= 80.0) && (temperature <= 112.0))\n hi -= ((13.0 - percentHumidity) * 0.25) * Math.sqrt((17.0 - Math.abs(temperature - 95.0)) * 0.05882);\n\n else if((percentHumidity > 85.0) && (temperature >= 80.0) && (temperature <= 87.0))\n hi += ((percentHumidity - 85.0) * 0.1) * ((87.0 - temperature) * 0.2);\n }\n\n return isFahrenheit ? round( hi, 1 ) : round( convertFtoC(hi), 1 );\n}\n\nfunction heatIndex(tempC, humidity) {\n var tempF = convertCtoF(tempC);\n var c1 = -42.38, c2 = 2.049, c3 = 10.14, c4 = -0.2248, c5= -6.838e-3, c6=-5.482e-2, c7=1.228e-3, c8=8.528e-4, c9=-1.99e-6 ;\n var T = tempF;\n var R = humidity;\n \n var A = (( c5 * T) + c2) * T + c1;\n var B = ((c7 * T) + c4) * T + c3;\n var C = ((c9 * T) + c8) * T + c6;\n \n var rv = (C * R + B) * R + A;\n return round( rv, 1 );\n}\n","outputs":"2","noerr":0,"x":515.5,"y":140,"wires":[["769b7f7f.89648","f4044933.0bfbb8"],[]]},{"id":"f4044933.0bfbb8","type":"mqtt out","z":"c919054f.36e6f8","name":"","topic":"","qos":"","retain":"","broker":"3b2726f7.c4d8da","x":710,"y":140,"wires":[]},{"id":"3a37ca3.fc5c836","type":"change","z":"c919054f.36e6f8","name":"","rules":[{"t":"set","p":"inputController","to":"WIFI"},{"t":"set","p":"payload","to":"msg.payload.status"},{"t":"set","p":"type","to":"CONTROLLER"},{"t":"change","p":"payload.state","from":"true","to":"On","re":false},{"t":"change","p":"payload.state","from":"false","to":"Off","re":false}],"action":"","property":"","from":"","to":"","reg":false,"x":316.5,"y":140,"wires":[["30421ae0.cfbde6"]]}]
[{"id":"37127811.c8ed88","type":"mongodb","z":"","hostname":"127.0.0.1","port":"27017","db":"DomoticaPi2","name":"DomoticaPi2"},{"id":"3b2726f7.c4d8da","type":"mqtt-broker","z":"","broker":"localhost","port":"1883","clientid":"Pi2_NR-Live","usetls":false,"verifyservercert":true,"compatmode":false,"keepalive":"15","cleansession":true,"willTopic":"DEVICES/PI2NR-LIVE","willQos":"1","willRetain":"false","willPayload":"Offline","birthTopic":"DEVICES/PI2NR-LIVE","birthQos":"1","birthRetain":"false","birthPayload":"Online"},{"id":"2211acd1.ddee54","type":"debug","z":"13040d87.ecfbf2","name":"","active":false,"console":"false","complete":"payload","x":868.9999694824219,"y":445,"wires":[]},{"id":"a7f89cf8.58076","type":"mqtt in","z":"13040d87.ecfbf2","name":"","topic":"HARDWARE-IN/#","broker":"3b2726f7.c4d8da","x":102,"y":265,"wires":[["da258750.25da78"]]},{"id":"47d2e22e.b82d1c","type":"mqtt out","z":"13040d87.ecfbf2","name":"COMMAND/SWITCHnn (On/Off)","topic":"","qos":"","retain":"","broker":"3b2726f7.c4d8da","x":746.9999847412109,"y":289,"wires":[]},{"id":"596aa9e5.a69558","type":"function","z":"13040d87.ecfbf2","name":"1) Controls, 2) Sensors","func":"// Process known controllers into direct commands where needed \n// Ignore inbound messages where needed\n// Ensure only On messages from PIR's are processed (as a sensor)\n// Everything is treated as sensor output\n\nif ( ! ('swCount' in context) ) context.swCount = 0;\nif ( ! ('statCount' in context) ) context.statCount = 0;\n\nfunction setStatus() {\n node.status({'text':'In: ' + context.statCount + ', Switches: ' + context.swCount });\n}\n\ncontext.statCount++; setStatus();\n\n// Send one or more command msgs to MQTT\nfunction doControl(ctrl) {\n context.swCount++; setStatus();\n \n // ctrl = [SWITCHnn], ac\n // Sent COMMAND/SWITCHnn\n // if cmd is not an array, make it one\n if ( (typeof ctrl) === 'string' ) ctrl = [ctrl];\n // loop over cmds with delay between\n ctrl.forEach( function(control, index, array) {\n // Send COMMAND/SWITCHnn to MQTT, null\n node.send( [ { \n 'topic' : 'COMMAND/' + control, // The logical output ID, Used for MQTT send\n 'payload' : msg.payload.command, // The command string (On/Off)\n 'inputHardware' : msg.topic, // Helps keep track of where the command came from\n 'collection' : 'COMMAND/' + control, // The logical output ID, used for MongoDB save\n '_id' : msg.payload.timestamp // Record ID for MongoDB (input mod date/time)\n }, null ] );\n });\n // for delay: _.delay(node.send, wait, { 'topic' : element, 'payload' : msg.payload.command }) - set the wait to 0 for initial run then something higher\n} // ---- End of doControl ---- //\n\n// Work out what to do with incoming MQTT messages from hardware inputs\nswitch ( msg.payload.topic ) {\n // ----- Anything to ignore goes here ----- //\n // Ignore - using AC not HE as signal strength is better\n case 'HOMEEASY_EU/0x00024404/3': // he dual switch\n case 'HOMEEASY_EU/0x00024404/2':\n case 'HOMEEASY_EU/0x000081C0/2': // he pir\n break;\n \n // ------- CONTROLS -->> COMMANDS (output 1) -------- //\n // known controls that directly translate to commands go here\n // NB: Can send 2 or more commands simply by returning an array on the 1st output: [ [msg1, msg2], null ]\n \n // HomeEasy Dual Switch\n case 'AC/0x000247C4/2': // Landing light\n doControl( ['SWITCH04'] );\n break;\n case 'AC/0x000247C4/3': // Both hall lights together\n doControl( ['SWITCH02', 'SWITCH03' ] );\n break;\n\n // Siemens Remote Control (LightwaveRF)\n case 'LIGHTWAVERF/0xF2D8D7/0': // All off\n case 'LIGHTWAVERF/0xF2D8D7/16': // Mood1 = All on\n if ( msg.payload.command === 'Mood1') msg.payload.command = 'On';\n doControl( ['SWITCH01', 'SWITCH03', 'SWITCH02', 'SWITCH04'] );\n break;\n // Catch the remaining remote controls - using slice emulates a wildcard - must come last of the group\n case 'LIGHTWAVERF/0xF2D8D7/' + msg.payload.topic.slice( 'LIGHTWAVERF/0xF2D8D7/'.length ):\n //node.warn( 'LWRF REMOTE unit (NOT HANDLING HERE YET): ' + msg.payload.unitAddr + ', cmd: ' + msg.payload.command );\n // Automatically set the remote control switch ID to the output switch ID\n doControl( [ 'SWITCH' + ('00' + msg.payload.unitAddr).slice(-2) ] );\n break;\n \n // ---------- SENSORS (output 2) ----------//\n \n // HE PIR on AC channel - treat as a sensor not a controller\n /*\n case 'AC/0x0000A9F8/2':\n // Only track On, not off\n if ( msg.payload.command === 'On' ) {\n return [null,msg];\n }\n break;\n */\n \n // Everything else (e.g. that does not translate to a command) is passed on to the second output channel\n default:\n return [null,msg];\n \n} // ---- End of Switch/case ---- //\n\n// ==== EOF ==== //","outputs":"2","noerr":0,"x":290.49998474121094,"y":320,"wires":[["9d5bc110.62a44"],["4e394299.b1c6bc"]]},{"id":"da258750.25da78","type":"json","z":"13040d87.ecfbf2","name":"","x":181,"y":290,"wires":[["596aa9e5.a69558","397fc7dc.c68038"]]},{"id":"4e394299.b1c6bc","type":"switch","z":"13040d87.ecfbf2","name":"","property":"payload.topic","rules":[{"t":"eq","v":"TH1/0x3001"},{"t":"else"}],"checkall":"false","outputs":2,"x":695.8958129882812,"y":428.8888854980469,"wires":[["48d695e5.b7296c"],["2211acd1.ddee54"]]},{"id":"48d695e5.b7296c","type":"debug","z":"13040d87.ecfbf2","name":"","active":false,"console":"false","complete":"payload","x":868.8957824707031,"y":405.8888854980469,"wires":[]},{"id":"634570a7.9cba9","type":"comment","z":"13040d87.ecfbf2","name":"Listen for HW in messages, convert to COMMANDs and SENSOR outputs","info":"","x":285.89581298828125,"y":155.88887786865234,"wires":[]},{"id":"397fc7dc.c68038","type":"function","z":"13040d87.ecfbf2","name":"DEVICES/# output","func":"//\n\n// Track timer functions\nif ( ! ('myTimers' in context) ) {\n context.myTimers = {};\n //node.warn( ' creating myTimers ');\n} //else node.warn( ' Timers: ' + (Object.keys( context.myTimers )).join(', ') );\n\n// ---- Support functions ---- //\n\n// Tell MQTT that a device is offline\nfunction devOffline(devId) {\n //node.warn( 'Triggering timeout for: ' + devId );\n // This gets executed unless something cancels or resets the timer\n var mqMsg = {\n 'topic' : 'DEVICES/' + devId,\n 'payload' : 'Offline'\n }; \n node.send( [ mqMsg, null ] );\n}\n\n// Msg to MQTT to tell us whether a device is online or offline\nfunction devOnOff(devId, timeout) {\n //node.warn( 'Timeout update for: ' + msg.payload.topic );\n var mqMsg = {\n 'topic' : 'DEVICES/' + devId,\n 'payload' : 'Online'\n };\n node.send( [ mqMsg, null ] )\n // Cancel a timer if one already exists & remove from tracker\n if ( devId in context.myTimers ) {\n clearTimeout( context.myTimers[devId] );\n delete context.myTimers[devId];\n }\n // Set a timer for this device & track it 5min = 5*60*1000 ms = 300,000\n // This will call the fn on timeout which sends an MQTT message saying offline\n context.myTimers[devId] = setTimeout( function() {\n devOffline(devId);\n }, timeout );\n}\n// ---- End of support functions ---- //\n\nmsg.collection = msg.topic; // Used for MongoDB save\nmsg._id = msg.payload.timestamp; // Record ID for MongoDB (input mod date/time)\n\n// Msg to MQTT to tell us that the input devices listening device is live (online) or otherwise (e.g. SRF, USB, RFX)\ndevOnOff(msg.payload.inputController, 300000);\n \n// Msg to MQTT to tell us that the input device is live (online) or othwise\nvar dt = msg.payload.deviceFeatures;\n// Ignore switches and PIR's as they only occasionally trigger\nif ( dt === 'C' || dt === 'M' || dt === 'CM' || dt === 'MC' ) {\n} else { // assume everything else triggers at least once every 5 min (300000 ms)\n devOnOff(msg.payload.topic, 300000);\n}\n\n// 1) MQTT output (not sent here, see fns), 2) MongoDB output\nreturn [ null, msg ];","outputs":"2","noerr":0,"x":336.895751953125,"y":226.88888549804688,"wires":[["bbbc563c.4443a8"],["b1082e6c.4ef7d","5340f79d.acbf08"]]},{"id":"bbbc563c.4443a8","type":"mqtt out","z":"13040d87.ecfbf2","name":"DEVICES/# On-Offline","topic":"","qos":"1","retain":"","broker":"3b2726f7.c4d8da","x":662.8957977294922,"y":184.88888549804688,"wires":[]},{"id":"3f11a592.c0ee5a","type":"bigtimer","z":"13040d87.ecfbf2","outtopic":"COMMAND/SWITCH05","outpayload1":"On","outpayload2":"Off","name":"Outside Lights","lat":"53.41239","lon":"-1.59447","start":"sunrise","end":"sunset","starttime":"900","endtime":"1425","duskoff":"0","dawnoff":"0","outtext1":"SWITCH05: On","outtext2":"SWITCH05: Off","sun":true,"mon":true,"tue":true,"wed":true,"thu":true,"fri":true,"sat":true,"jan":true,"feb":true,"mar":true,"apr":true,"may":true,"jun":true,"jul":true,"aug":true,"sep":true,"oct":true,"nov":true,"dec":true,"repeat":false,"atstart":true,"x":261.6666564941406,"y":390.6666793823242,"wires":[[],[],["78c372a3.873c8c"]]},{"id":"78c372a3.873c8c","type":"debug","z":"13040d87.ecfbf2","name":"","active":false,"console":"false","complete":"payload","x":481.66664123535156,"y":477.6666564941406,"wires":[]},{"id":"1b2bb71.fe4d449","type":"http request","z":"13040d87.ecfbf2","name":"","method":"GET","ret":"txt","url":"https://totallyinformation.bip.io/bip/http/recv_iot","x":914,"y":178,"wires":[["6a22c0dd.95dd4"]]},{"id":"6a22c0dd.95dd4","type":"debug","z":"13040d87.ecfbf2","name":"","active":false,"console":"false","complete":"payload","x":1097,"y":172,"wires":[]},{"id":"7b8c4c6.f8473b4","type":"inject","z":"13040d87.ecfbf2","name":"","topic":"COMMAND/SWITCH03","payload":"Off","payloadType":"string","repeat":"","crontab":"00 9 * * 1,2,3,4","once":false,"x":160,"y":493,"wires":[["9d5bc110.62a44"]]},{"id":"de815686.217ea8","type":"inject","z":"13040d87.ecfbf2","name":"","topic":"COMMAND/SWITCH04","payload":"Off","payloadType":"string","repeat":"","crontab":"00 9 * * 1,2,3,4","once":false,"x":160,"y":530,"wires":[["9d5bc110.62a44"]]},{"id":"e38d4bf6.1c72b8","type":"inject","z":"13040d87.ecfbf2","name":"","topic":"COMMAND/SWITCH02","payload":"Off","payloadType":"string","repeat":"","crontab":"00 9 * * 1,2,3,4","once":false,"x":156,"y":457,"wires":[["9d5bc110.62a44"]]},{"id":"73a12acf.8c5ed4","type":"inject","z":"13040d87.ecfbf2","name":"","topic":"COMMAND/SWITCH05","payload":"On","payloadType":"string","repeat":"","crontab":"00 15 * * *","once":false,"x":156.8958282470703,"y":572,"wires":[["9d5bc110.62a44"]]},{"id":"b1082e6c.4ef7d","type":"mongodb out","z":"13040d87.ecfbf2","mongodb":"37127811.c8ed88","name":"Log (each device in own collection)","collection":"","payonly":false,"upsert":false,"multi":false,"operation":"store","x":729.8957977294922,"y":243.88888549804688,"wires":[]},{"id":"9d5bc110.62a44","type":"function","z":"13040d87.ecfbf2","name":"","func":"// Make sure output message is ready to be recorded in MongoDB\n\nif ( !('topic' in msg) || msg.topic === '' ) {\n node.warn( 'No topic! Dropping output' );\n return null;\n}\n\nif ( !('collection' in msg) ) {\n msg.collection = msg.topic; \n}\n\nif ( !('_id' in msg) ) {\n msg._id = new Date();\n}\n\n// Record what triggered this command msg if we can\nif ( !('inputHardware' in msg) ) {\n msg.inputHardware = 'MANUAL_OR_NR'\n}\n\n// 2nd output is for the Current Switch status\nvar currMsg = {\n 'collection': 'CurrentSwitchStatus',\n '_id': msg.topic,\n 'state': msg.payload,\n 'lastUpdate': msg._id,\n 'inputHardware': msg.inputHardware\n};\n\n\nreturn [msg, currMsg];","outputs":"2","noerr":0,"x":520.8957366943359,"y":319.111083984375,"wires":[["47d2e22e.b82d1c","b1082e6c.4ef7d"],["56d6d8ec.a92928"]]},{"id":"56d6d8ec.a92928","type":"mongodb out","z":"13040d87.ecfbf2","mongodb":"37127811.c8ed88","name":"Current Status (single collection)","collection":"","payonly":false,"upsert":false,"multi":false,"operation":"store","x":765.8957977294922,"y":349.1111145019531,"wires":[]},{"id":"de61d897.219e28","type":"inject","z":"13040d87.ecfbf2","name":"","topic":"COMMAND/SWITCH05","payload":"Off","payloadType":"string","repeat":"","crontab":"12 01 * * *","once":false,"x":157.8958282470703,"y":617,"wires":[["9d5bc110.62a44"]]},{"id":"5340f79d.acbf08","type":"debug","z":"13040d87.ecfbf2","name":"debug for mongodb","active":false,"console":"false","complete":"true","x":1014.5148315429688,"y":283.5407409667969,"wires":[]}]
[{"id":"be8e40db.66557","type":"pushbullet-config","name":""},{"id":"3a35caa3.80b476","type":"mqtt-broker","broker":"localhost","port":"1883","clientid":"Pi2-NR"},{"id":"7147ecd7.8eca7c","type":"mqtt out","name":"Local: COMMAND/SWITCH04","topic":"COMMAND/SWITCH04","qos":"0","retain":"false","broker":"3a35caa3.80b476","x":783.5,"y":420,"z":"50bb4ad3.75448c","wires":[]},{"id":"1145cb61.6812e5","type":"mqtt out","name":"Local: COMMAND/SWITCH03","topic":"COMMAND/SWITCH03","qos":"0","retain":"false","broker":"3a35caa3.80b476","x":743.5,"y":619,"z":"50bb4ad3.75448c","wires":[]},{"id":"e9ec7a1c.160f78","type":"inject","name":"Manual On","topic":"","payload":"On","payloadType":"string","repeat":"","crontab":"","once":false,"x":119,"y":380,"z":"50bb4ad3.75448c","wires":[["294b6fea.17a648"]]},{"id":"74850327.7cb834","type":"inject","name":"Manual Off","topic":"","payload":"Off","payloadType":"string","repeat":"","crontab":"","once":false,"x":118.20001220703125,"y":418.1999816894531,"z":"50bb4ad3.75448c","wires":[["294b6fea.17a648"]]},{"id":"c07de995.69e4c8","type":"comment","name":"Switch04 = Landing Security Light (Nexa)","info":"","x":789,"y":380,"z":"50bb4ad3.75448c","wires":[]},{"id":"99064b7d.f0aa1","type":"comment","name":"Switch03 = Front Hall Light (Siemens)","info":"","x":729,"y":579,"z":"50bb4ad3.75448c","wires":[]},{"id":"294b6fea.17a648","type":"timestamp","name":"Dummy","x":571,"y":420,"z":"50bb4ad3.75448c","wires":[["7147ecd7.8eca7c","3aff1b60.c500e4"]]},{"id":"bc0cbac3.75ece8","type":"timestamp","name":"Dummy","x":531,"y":619,"z":"50bb4ad3.75448c","wires":[["1145cb61.6812e5"]]},{"id":"5d6444fd.815d5c","type":"scheduler","outtopic":"","outpayload1":"On","outpayload2":"Off","name":"On Dusk-1.5hrs -> Off Dawn","lat":"53.38899","lon":"-1.49949","start":"sunrise","end":"sunset","starttime":"6000","endtime":"5000","duskoff":"-90","dawnoff":"0","sun":true,"mon":true,"tue":true,"wed":true,"thu":true,"fri":true,"sat":true,"jan":false,"feb":true,"mar":false,"apr":false,"may":false,"jun":true,"jul":true,"aug":true,"sep":false,"oct":false,"nov":false,"dec":false,"x":185.5,"y":619,"z":"50bb4ad3.75448c","wires":[["bc0cbac3.75ece8"],[]]},{"id":"40728ba0.af756c","type":"inject","name":"Off M-Su/1am","topic":"","payload":"Off","payloadType":"string","repeat":"","crontab":"00 01 * * *","once":false,"x":132.5,"y":579,"z":"50bb4ad3.75448c","wires":[["bc0cbac3.75ece8"]]},{"id":"6f8634a9.9079cc","type":"later","name":"Mo-Fr/06am & 3pm, Sa-Su/8am","schedule":"on Mon through Fri at 06:00,15:00 also on Sat,Sun at 08:00","x":315.5,"y":480,"z":"50bb4ad3.75448c","wires":[["294b6fea.17a648"]]},{"id":"9662c398.699d4","type":"inject","name":"","topic":"","payload":"On","payloadType":"string","repeat":"","crontab":"","once":true,"x":110,"y":480,"z":"50bb4ad3.75448c","wires":[["6f8634a9.9079cc"]]},{"id":"8fe9f2a1.70161","type":"later","name":"Mo-Th/9am, Fri/12, Mo-Su/2am","schedule":"on Mon through Thu at 09:00 also on Fri at 12:00 also at 02:00","x":323.5,"y":520,"z":"50bb4ad3.75448c","wires":[["294b6fea.17a648"]]},{"id":"b57d825e.4a828","type":"inject","name":"","topic":"","payload":"Off","payloadType":"string","repeat":"","crontab":"","once":true,"x":110,"y":520,"z":"50bb4ad3.75448c","wires":[["8fe9f2a1.70161"]]},{"id":"514de16c.aeb22","type":"comment","name":"Later scheduler","info":"","x":312.50001525878906,"y":445.00000762939453,"z":"50bb4ad3.75448c","wires":[]},{"id":"3aff1b60.c500e4","type":"debug","name":"","active":false,"console":"false","complete":"true","x":736,"y":479,"z":"50bb4ad3.75448c","wires":[]},{"id":"4028a7e6.bfd758","type":"pushbullet","config":"be8e40db.66557","pushtype":"note","title":"SWITCH02","chan":"","name":"","x":749,"y":513,"z":"50bb4ad3.75448c","wires":[]},{"id":"450ddbc6.baf224","type":"scheduler","outtopic":"","outpayload1":"On","outpayload2":"Off","name":"On Dusk-2.5hrs -> Off 8:45am","lat":"53.38899","lon":"-1.49949","start":"sunrise","end":"sunset","starttime":"6000","endtime":"525","duskoff":"-180","dawnoff":"60","sun":true,"mon":true,"tue":true,"wed":true,"thu":true,"fri":true,"sat":true,"jan":true,"feb":true,"mar":true,"apr":true,"may":true,"jun":false,"jul":false,"aug":false,"sep":true,"oct":true,"nov":true,"dec":true,"x":177.8958282470703,"y":661.111083984375,"z":"50bb4ad3.75448c","wires":[["bc0cbac3.75ece8"],[]]},{"id":"5aba880f.43681","type":"inject","name":"Manual On","topic":"","payload":"On","payloadType":"string","repeat":"","crontab":"","once":false,"x":118,"y":712.0000305175781,"z":"50bb4ad3.75448c","wires":[["bc0cbac3.75ece8"]]},{"id":"ee78713a.a1d7f","type":"inject","name":"Manual Off","topic":"","payload":"Off","payloadType":"string","repeat":"","crontab":"","once":false,"x":118,"y":752.0000305175781,"z":"50bb4ad3.75448c","wires":[["bc0cbac3.75ece8"]]}]
Hi Julian,
Could I trouble you for a copy of the flow please? As I say, pretty new to node-red and it would be great to see an example of how to do it.
Do you follow the OEM forums? I put some bits up about getting data into EmonCMS via MQTT.
Cheers.
...
Not sure I can safely share the full set of flows Brian. But I can share some pictures. At the moment I am part way through migrating from an older version of NR to the latest and the old version is certainly very messy. Lets see what we can do.
...
I also put the var promise declaration inside the function tho I'm not sure it makes any difference.
--
http://nodered.org
---
You received this message because you are subscribed to a topic in the Google Groups "Node-RED" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/node-red/Z5FApuA_WHg/unsubscribe.
To unsubscribe from this group and all its topics, send an email to node-red+u...@googlegroups.com.