Problem with XML string for an EDIMAX smartplug

404 views
Skip to first unread message

Brian Orpin

unread,
Jan 3, 2016, 8:49:01 AM1/3/16
to Node-RED
So, new to node-red to be gentle please.

I'm trying to send an XML control string to an Edimax SmartPlug.  I have used this python script to do it successfully from my Pi, but was trying to see if I could just do it in Node-RED.

I am using the http-request node with an https:// url and basic auth.  I get a DEPTH_ZERO_SELF_SIGNED_CERT error.

I have tried using a function to insert a rejectUnauthorised (as suggested elsewhere);

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;

The debug output from the Python script is;

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>

Which shows that the connection seems to be an http connection. However when I try that I get the following message;

{
 
"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
}

Any suggestions to get this to work?

Cheers.

Mark Setrem

unread,
Jan 3, 2016, 9:07:53 AM1/3/16
to Node-RED

The easiest solution might be to use the http://flows.nodered.org/node/node-red-contrib-smartplug node ;-)

Not used it myself but it would appear to do what you are trying to do...

Brian Orpin

unread,
Jan 3, 2016, 10:29:14 AM1/3/16
to Node-RED
Ok Thanks.  Numerous searches failed to throw that one up :(

OT but how do I install a node without npm?  the docs refer to a 'nodes' directory but I have not found a step by step guide.

Cheers

Brian Orpin

unread,
Jan 3, 2016, 10:56:31 AM1/3/16
to Node-RED
Ok installed npm and installed the node but I get a 'ReferenceError: Promise is not defined'.  Am I right that, as I am running the default Raspian nod-red, that this node requires a later version of node.js?

Is there a workaround?  I really do not want to install the later version.

if not I'm back to my original question :)


Cheers

On Sunday, 3 January 2016 14:07:53 UTC, Mark Setrem wrote:

Dave C-J

unread,
Jan 3, 2016, 10:56:36 AM1/3/16
to node...@googlegroups.com
Easiest is to install npm as per the docs...

Mark Setrem

unread,
Jan 3, 2016, 11:01:33 AM1/3/16
to Node-RED
The easiest answer is if the node-red-node suggests you install it with npm you should install npm.  

A lot of node-red nodes are wrappers around npm packages.  So when you install a node with npm you also install all the npm packages the node-red-node requires.

There are instruction as to how to install npm here: http://nodered.org/docs/hardware/raspberrypi.html


As shown in those instructions you should also be in the .node-red directory when you install them. This is within the home account of the user you are using to run node-red.
So if you are running it as the default user on a raspberry pi it is as shown.


But you can install nodes with the nodes directory within the .node-red directory.  If its not there just create it.

Mark Setrem

unread,
Jan 3, 2016, 4:29:58 PM1/3/16
to Node-RED

You don't need a newer version of nodejs to install that node.

I've just started with a new jessie install followed the commands below

1  sudo apt-get install npm
2  sudo npm install -g npm@2.x
3  cd ~/.node-red
4  npm install node-red-contrib-smartplug
5  node-red-start 

and nodered launches with the smart plug node installed.   

When do you get the error?


Dave C-J

unread,
Jan 3, 2016, 4:35:32 PM1/3/16
to node...@googlegroups.com
likewise for me also... I created a dummy flow (as I don't have the hardware)... and it deployed and didn't error there either...

Brian Orpin

unread,
Jan 4, 2016, 11:36:57 AM1/4/16
to Node-RED
Hi, I retried installing the 2.x npm as it has not installed first time (and I'd skipped over it).  I uninstalled the node and reinstalled it.

I'm running node-red as a service so not using 'node-red-start'

I get the error as soon as the flows are deployed.

Error messages from the service;

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


The last stopped/starting are when the flow is deployed.

I have tried deleting and recreating the flows.

Anywhere else to look for error messages?

Can you just test the node?

Brian Orpin

unread,
Jan 4, 2016, 11:45:39 AM1/4/16
to Node-RED
A bit more info from the logs (as I think it may be relevant).  There is just one flow, a smartswitch input node and a debug node on the output.

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
...


Sequence of events is - start node-red service.  No error in debug panel.  Edit smartplug node.  Redeploy flows. Reference error.

Cheers

Nicholas O'Leary

unread,
Jan 4, 2016, 11:51:59 AM1/4/16
to Node-RED Mailing List
Hmm, that is odd. The message:

Jan  4 16:38:43 server-pi Node-RED[18958]: 4 Jan 16:38:43 - [warn] [smartplug] Error: Cannot find module 'edimax-smartplug'

indicates the the smartplug node cannot find the edimax-smartplug module it depends on. So something has gone wrong in the install of the node. And it is doubly odd that it should then continue and allow you to use the smartplug-in node as it was missing a dependency.

The former issue is one for you to look at - when you ran the npm install of node-red-contrib-smartplug were there any error messages?
The latter issue (why it then continued to try to use the smartplug-in node) is one for us to look at.

Nick


--
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.

Dave C-J

unread,
Jan 4, 2016, 11:53:22 AM1/4/16
to node...@googlegroups.com
The line
[warn] [smartplug] Error: Cannot find module 'edimax-smartplug'
is not good...
it means it can't find the npm that that node pre-reqs... 
you should install the nodes from your user directory - usually
cd ~/.node-red
npm install node-red-contrib-smartplug

however.... you may now have similar files in the wrong place due to either starting in the wrong directory, trying to install as root (sudo)  - or the old version of npm... so you may need to tidy up first...


Brian Orpin

unread,
Jan 4, 2016, 12:13:58 PM1/4/16
to Node-RED
Ok so how do I clean this mess up :(

I tried installing the edimax-smartplug node separately but that just gave different errors.

So I have now uninstalled both the node-red-contrib-smartplug and the  edimax-smartplug nodes.

On startup I get the following log entries;

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


It maybe because I have a configuration node kicking about that I don't know how to delete :(

Julian Knight

unread,
Jan 4, 2016, 12:23:48 PM1/4/16
to Node-RED
Just ordered one to pick up from Maplin so I'm going to have a play as soon as I can.

Mark Setrem

unread,
Jan 4, 2016, 12:33:21 PM1/4/16
to Node-RED
If you want to get rid of the config node warning (its usually just a warning so I'm doubt its causing your problems).
Go to the hamburger menu in Node-red (top right) -> Sidebar -> Configuration Nodes

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.

Mark Setrem

unread,
Jan 4, 2016, 12:38:13 PM1/4/16
to Node-RED
I also noticed that you are running node-red as root (either directly or through using the sudo command)

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.

Brian Orpin

unread,
Jan 4, 2016, 2:25:53 PM1/4/16
to Node-RED
Thanks for that.  Hadn't tried the double click.

Brian Orpin

unread,
Jan 4, 2016, 2:31:25 PM1/4/16
to Node-RED
Yes it runs as root as it was a ua-netinst version of rasbian - minimal with just what I need plus it installs straight to a HDD with fixed IP :) (https://github.com/debian-pi/raspbian-ua-netinst)

So I have removed the config node but on restarting node-red it still gives this message
Jan  4 19:24:45 server-pi Node-RED[19342]: 4 Jan 19:24:45 - [warn] [smartplug] Error: Cannot find module 'edimax-smartplug'


Which seems to indicate node-red still thinks the node is there somewhere or there is a reference to it.  There are no flows at all.

Cheers

Julian Knight

unread,
Jan 4, 2016, 4:05:41 PM1/4/16
to Node-RED
I've just installed it without issue on my Pi2 Rasbian Jessie installation. The module referred to is a dependency and should be installed in the node-modules folder of the node-red-contrib-smartplug module - assuming you are using npm <v3

My problem is different. The config node seems to have far too many settings! I don't have a "username" for the plug and the iOS software for configuring the plug doesn't tell me the IP address! My router is playing up as well and wont tell me the details of the DHCP allocations - grrr.

OK, so I guessed the settings, deployed and of course I now get the error:

04/01/2016, 20:57:0235cf99d2.ca3066msg : errorReferenceError: Promise is not definedI'll dig into the underlying edimax-smartplug module to see if that works.

Julian Knight

unread,
Jan 4, 2016, 4:07:45 PM1/4/16
to Node-RED
Ah, missed the console output first time around:

Jan 04 21:02:31 pi2 NR-Live2[5310]: Unhandled rejection Error: Request timeout occurred - request aborted
Jan 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)

Brian Orpin

unread,
Jan 4, 2016, 5:40:15 PM1/4/16
to Node-RED
The username is default admin and password 1234.  There are some c and python scripts out there that will search for the devices.  I have used the python script from https://github.com/wendlers/ediplug-py which works nicely.

I use an Android app called Fing that will find all devices on the local network (not that is helps on IOS <grin>)

Yes I used npm 2.x


On Monday, 4 January 2016 21:05:41 UTC, Julian Knight wrote:

Julian Knight

unread,
Jan 4, 2016, 5:43:20 PM1/4/16
to Node-RED
OK, I've tested with the edimax-smartplug node.js module and that works fine. Not hardly finished but it does work.

Some hints:
  • The MAC address is on the back of the unit, I used that with the ARP table display on the router to track down the IP address.
  • You should probably use your DHCP servers fixed IP settings to ensure that the device always gets the same IP address
  • The username is "admin"
  • The example code in the edimax-smartplug module is confusing and I don't think it would work for a standard installation like I've done. My example below does work though.
If you want to test your own unit, put the following two files into a folder, adjust the IP address, name & password in index.js then from the command line in that folder, "npm install" then "npm start".

package.json
{
  "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"
  }
}

index.js
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 ON
edimax.setSwitchState(true, options).catch(function(e) {console.log(e)})

// get switch status
edimax.getSwitchState(options).then(function (state) {
    console.log("Switch is", state?"ON":"OFF")
}).catch(function(e) {console.log(e)})

// get switch power
edimax.getSwitchPower(options).then(function (power) {
    console.log("Current switch power", power, "Watts")
}).catch(function(e) {console.log(e)})

// get switch energy reading
edimax.getSwitchEnergy(options).then(function (energy) {
    console.log(energy)
}).catch(function(e) {console.log(e)})

// get switch energy reading
edimax.getStatusValues(true, options).then(function (data) {
    console.log(data)
}).catch(function(e) {console.log(e)})


Running that gives the following output (with a USB dual charge and my phone plugged in to it):
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 ON
Current 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) }



The following functions are defined: getSwitchState, setSwitchState, getSwitchPower, getSwitchEnergy, getStatusValues, getSchedule, getDeviceInfo.


Clearly there is something wrong with the node-red-contrib-smartplug module - I can't be bothered to work it out tonight I'm afraid.


On Monday, 4 January 2016 21:07:45 UTC, Julian Knight wrote:
...

Julian Knight

unread,
Jan 4, 2016, 5:45:10 PM1/4/16
to Node-RED
Thanks Brian. I got the username from the edimax-smartplug code in the end and my other post which crossed yours says how I got the IP address.

So the basic node.js module works fine but the node-red one doesn't.

Nicholas O'Leary

unread,
Jan 4, 2016, 5:47:47 PM1/4/16
to Node-RED Mailing List
Don't forget you can raise issues against the node on its github repository. That'll get the authors attention in case they aren't active on this list.

Nick

--

Julian Knight

unread,
Jan 4, 2016, 6:11:31 PM1/4/16
to Node-RED
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".

Julian Knight

unread,
Jan 4, 2016, 6:22:03 PM1/4/16
to Node-RED
A really quick and dirty test by installing bluebird and adding
var Promise = require("bluebird");

at the top of smartplug.js proved the point as it now works.

However, it constantly loops outputting a message every second or so on my Pi2 which is really not terribly useful. Still, it steers the way.

I've updated the issue.



On Monday, 4 January 2016 23:11:31 UTC, Julian Knight wrote:
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".
...

Julian Knight

unread,
Jan 4, 2016, 6:24:03 PM1/4/16
to Node-RED
Oops, take some of that back. There is an interval setting! OK, so maybe it is OK now.

Brian Orpin

unread,
Jan 5, 2016, 3:10:45 AM1/5/16
to node...@googlegroups.com

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.

Julian Knight

unread,
Jan 5, 2016, 4:43:09 AM1/5/16
to Node-RED
Hi Brian, no problem. I use EmonCMS as well. I now have the node set to poll every 30s, I'll probably reduce to 60s in line with my other sensors.

Following my standard pattern, I listen for the input, normalise/enrich it and send out to MQTT with a topic starting HARDWARE-IN/WIFI/#
I have a 2nd flow that listens to the hardware-in messages and updates online/offline MQTT heatbeats, writes a record to MongoDB, splits out specific sensor types to dedicated MQTT topics (e.g. TEMPERATURE/#, HUMIDITY/#, etc). Also, if the incoming message is from a controller (previously one of my lighting remotes but now also the Smartplug) I pass the info through a function that associates controls with switches. That changes the switch and records the new status both to MQTT and MongoDB.

The output to EmonCMS is via yet another flow.

Brian Orpin

unread,
Jan 5, 2016, 4:57:09 AM1/5/16
to node...@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.

Julian Knight

unread,
Jan 5, 2016, 4:34:19 PM1/5/16
to Node-RED
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.

OK, here is a part of the flow the listens to various bits of hardware, normalises and enriches the data and writes it to MQTT:
[{"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":[]}]
That's the old part so it doesn;t show the new Smartplug. Here is the equivalent from the new flows and is currently only for the Smartplug:
[{"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"]]}]

Here is a section from the new flows that listens for those hardware inputs, sends out the online/offline messages and translates control buttons into command messages that are processed elsewhere (e.g. sent out to turn remote switches on/off). It also records events to MongoDB.
[{"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":[]}]

There is a lot more but that hopefully gives you a feel. One more - this snippet (from the old flows) is a couple of examples of timers operating lights via remote switches using a few different scheduling nodes. Note that the control is indirect. The schedule nodes send a COMMAND message like the example above. There is a separate flow that listens to COMMAND messages and translates them to the correct remote switch ID's and sends via the appropriate wireless controller.

[{"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"]]}]

Julian Knight

unread,
Jan 5, 2016, 4:36:24 PM1/5/16
to Node-RED
Do you have a link for the OEM forum? Always interested in alternate ways of doing things. I'm aware that my older code in particular is quite often over complex.

Also, have you tried running your own copy of EmonCMS?


On Tuesday, 5 January 2016 09:57:09 UTC, Brian Orpin wrote:

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.

...

Julian Knight

unread,
Jan 5, 2016, 4:38:09 PM1/5/16
to Node-RED
Looks like this got truncated! Let me know if it did, I'll have to send you a PM.


On Tuesday, 5 January 2016 21:34:19 UTC, Julian Knight wrote:
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.
...

Julian Knight

unread,
Jan 5, 2016, 4:38:33 PM1/5/16
to Node-RED
There should have been 3 or 4 sets of code in that message.

Brian Orpin

unread,
Jan 6, 2016, 3:40:13 PM1/6/16
to Node-RED
OEM Forum - http://openenergymonitor.org/emon/forum

Yes I only run my own copy of EmonCMS on a Pi (same one NR is on).

Brian Orpin

unread,
Jan 6, 2016, 3:41:00 PM1/6/16
to Node-RED
It got truncated I think.  Can You PM?

Brian Orpin

unread,
Jan 6, 2016, 3:45:17 PM1/6/16
to Node-RED
Ok I tried that and it worked.

BUT the status does not change if the plug is switched on or off.  If I redeploy the nodes it picks up the new status but otherwise just repeats.  Do you see the same behaviour?

I also cannot work out how to use the node to switch the plug on and off.

Cheers


On Monday, 4 January 2016 23:22:03 UTC, Julian Knight wrote:
Message has been deleted

Brian Orpin

unread,
Jan 6, 2016, 4:52:20 PM1/6/16
to Node-RED
Fixed the status issue by moving the repeating function declaration to above line 41. I've raised an issue on github.

Julian Knight

unread,
Jan 6, 2016, 7:47:59 PM1/6/16
to Node-RED
I tried that, but it didn't work. It still doesn't update when turning on/off.

Tried the output node too and that didn't work either!

So I guess this node is a bust.

Brian Orpin

unread,
Jan 7, 2016, 12:56:24 AM1/7/16
to node...@googlegroups.com

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.
Message has been deleted

Julian Knight

unread,
Jan 7, 2016, 3:31:59 PM1/7/16
to Node-RED
I moved the require for bluebird into the repeating function as you suggested and it now works.

Sending is also working now. So please ignore the last post.
Reply all
Reply to author
Forward
0 new messages