Two input function IF &&

1,553 views
Skip to first unread message

Dave

unread,
Dec 7, 2017, 11:54:31 AM12/7/17
to Node-RED
Hello,

I'm trying to make a function with two inputs, one the sun's altitude and the other the light level in a room.  The altitude comes from sunpos node and light level possibly from a ESP8266 via MQTT. Basically turning on a light if it's cloudy before sunset - What I have so far is this

var altitude = {payload: msg.payload.altitude};
var light    = {payload: msg.payload.light};

if (altitude <5 && light <5)

{msg.payload.lamp = 1;
}else{
 msg.payload.lamp = 0;}
 
return msg.payload.lamp;


I simulate msg.payload.light via an inject node

Any tips please ?

Dave.

[{"id":"6451506e.102dd","type":"sunpos","z":"940a6fc7.c59bf","name":"","lon":"-5","lat":"50.","start":"sunriseEnd","startoffset":0,"end":"sunsetStart","endoffset":0,"x":353,"y":381,"wires":[["1de11181.11a6be"]]},{"id":"ce605dfa.357ef","type":"debug","z":"940a6fc7.c59bf","name":"","active":true,"console":"false","complete":"true","x":669,"y":402,"wires":[]},{"id":"1de11181.11a6be","type":"function","z":"940a6fc7.c59bf","name":"alt & light","func":"var altitude = {payload: msg.payload.altitude};\nvar light    = {payload: msg.payload};\n\nif (altitude <5 && light <5)\n\n{msg.payload.lamp = 1;\n}else{\n msg.payload.lamp = 0;}\n \nreturn msg.payload.lamp;","outputs":1,"noerr":0,"x":525,"y":371,"wires":[["36a505c3.7caf5a","ce605dfa.357ef"]]},{"id":"36a505c3.7caf5a","type":"mqtt out","z":"940a6fc7.c59bf","name":"","topic":"","qos":"","retain":"","broker":"f2bcedec.c204e","x":735,"y":322,"wires":[]},{"id":"2f72955e.0e280a","type":"inject","z":"940a6fc7.c59bf","name":"","topic":"light","payload":"4","payloadType":"num","repeat":"","crontab":"","once":false,"x":149,"y":418,"wires":[["6451506e.102dd"]]},{"id":"f2bcedec.c204e","type":"mqtt-broker","z":"","broker":"192.168.1.40","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"willTopic":"","willQos":"0","willPayload":"","birthTopic":"","birthQos":"0","birthPayload":""}]

Colin Law

unread,
Dec 7, 2017, 12:27:41 PM12/7/17
to node...@googlegroups.com
You must return a message object, not just the answer, so you probably want
if (altitude <5 && light <5) {
msg.payload = 1;
}else{
msg.payload = 0;}
}
return msg;

or if you want the answer in msg.payload.lamp then keep it as you have
but return msg not msg.payload.lamp

Colin
> --
> http://nodered.org
>
> Join us on Slack to continue the conversation: http://nodered.org/slack
> ---
> 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.
> To post to this group, send email to node...@googlegroups.com.
> Visit this group at https://groups.google.com/group/node-red.
> To view this discussion on the web, visit
> https://groups.google.com/d/msgid/node-red/791255ff-bf69-44a3-ba4b-2a15b2e9f590%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Leif Neland

unread,
Dec 7, 2017, 12:36:07 PM12/7/17
to Node-RED
You shouldn't return msg.payload.light; this is an integer.
You should just return msg.

Colin Law

unread,
Dec 7, 2017, 12:38:38 PM12/7/17
to node...@googlegroups.com
Also that flow does rely on both values coming from the same message
(so one message with both payload.altitude and payload.light set. If
that is not the case you can use a Join node to combine two messages
into one.

Colin

Dave

unread,
Dec 7, 2017, 1:05:28 PM12/7/17
to Node-RED
Still not working as I expected, it might be better for me to wait until I actually have some hardware (ESP8266 with ESPeasy? +MQTT) returning light level from a sensor rather than trying to simulate it with an inject node. I think sunpos node is the correct way of judging when it's near being dark, with the sun less than 5 degrees above the horizon    Thanks for the replies I'm still very new to NR but every time I learn something new !. It feels like I'm cheating using too many nodes instead of writing a function !

Dave.

steve rickus

unread,
Dec 7, 2017, 1:32:01 PM12/7/17
to Node-RED
I disagree -- it's usually best to get a simulated flow working, and then swap in your actual sensor inputs...

I see you are passing the light level as msg.payload = 4 from the inject node. When you pass this msg into the Sunpos node, what happens to that payload? What inputs does it expect (if any), and what is the format of the output msg? Is suspect the Sunpos node is wiping out your light level value, which means your function is not going to get the inputs you are expecting. Best to wire a debug node to the Sunpos node output next to the function node, so you can see exactly what you have to work with.

When you want to pass one sensor payload into another output node, it's best to use a change node to move msg.payload to msg.lightlevel (or instance). Then the next node is free to create a whole new payload without overwriting your incoming value.
--
Steve

Dave

unread,
Dec 7, 2017, 1:46:47 PM12/7/17
to Node-RED
Your right, I put a debug on each output and found the 'light level' will never go through the sunpos node therefore, the function will never work. I assumed it would just a pass it on and add the other details on the suns position - I miss understood again. I'll have a rethink on how to do this with the advise I've been given.

steve rickus

unread,
Dec 7, 2017, 2:31:22 PM12/7/17
to Node-RED
After making many of the same mistakes myself, it helps me to think about what event will be triggering the light being turned on... In this case, you have two inputs: light level and sun position. So the trigger could be on a timer that checks every 10 minutes (polling loop), or the sensor could push a new value every time the light level changes (push event).

For the polling loop, I would use that timed event to kick off a flow that checks both inputs, just like you have simulated with the inject node. The goal is to pass the initial msg along a single flow, augmenting the msg with all the data you will need to decide the state of the lamp. As you found out, most nodes expect to output their own msg.payload field, not add to it. Using fields (other than payload) to hold data you want to keep is a common way to get around that, while keeping the data all in one nice package.

For async push events, you may just want to save the last received value into a flow or global variable, which can be checked later by another flow. Or if you have lots of sensor msgs being generated (like a temp sensor showing the same value every second), just pass them to an RBE node that will only output a msg when a significant change is detected -- effectively dropping duplicate readings. This reduces the volume of sun position calculations that would need to be made.

Just to say that this is the fun of working with node-red... so many ways to solve your particular problems, without having to know much programming. Enjoy!

Dave

unread,
Dec 8, 2017, 4:34:45 AM12/8/17
to Node-RED
Hi Steve, Thanks for the tips very helpful. Indeed I find it really interesting to figure out tasks I set myself. The idea of the light level and sun position came from a darker cloudy evening, having found earlier the sunpos node. I don't have any hardware at the moment but planning on get a Sonoff switch and a couple a ESP8266's running ESPeasy. I have a good electrical and electronic knowledge and a logical mind  - most of the time ... I like Node-red for that reason, a good mix a basic blocks (nodes) and programming when nothing else will fit a task. Also it's can be interfaced to many other external systems and devices. With this group I try to spread what little knowledge I have to help other as well. 

And as you say it's fun figuring out how to do something - even more so when it works !

Dave.

erwin....@gmail.com

unread,
Dec 8, 2017, 5:05:43 AM12/8/17
to Node-RED

var altitude = {payload: msg.payload.altitude};
var light    = {payload: msg.payload.light};

if (altitude <5 && light <5)


You are constructing objects and comparing them with integers. This will not work as you expect. I think you mean:
var altitude = msg.payload.altitude;
var light = msg.payload.light;

With all the other suggestions that are given, I think that should begin to work.

Julian Knight

unread,
Dec 8, 2017, 7:52:59 AM12/8/17
to Node-RED
Do note that if you are switching based on light levels ...
  1. You need to make sure the light sensor is sensibly positioned! Yes, I found that out the hard way - doh! Away from the light that it will turn on.
  2. You need to allow for some hysteresis in the values - otherwise you get edge conditions where the light will constantly turn on and off as the light level hovers around your critical value. The node node-red-contrib-edge-trigger has this built in.

On Thursday, 7 December 2017 19:31:22 UTC, steve rickus wrote:

Julian Knight

unread,
Dec 8, 2017, 7:55:06 AM12/8/17
to Node-RED
Sorry, forgot a 3rd thing. You might want to consider smoothing the data from the light sensor though if you set a suitable hysteresis level, this might not be needed.

Dave

unread,
Dec 8, 2017, 10:49:50 AM12/8/17
to Node-RED
Almost there, The only problem is the light level 'payload' needs to come in as msg.payload.light rather than just a number as I have it, then it can be filtered of in the function.
Good point on hysteresis, smoothing would soft that hopefully or a bracketed range <3   >5 soft of thing.

Dave.

[{"id":"6451506e.102dd","type":"sunpos","z":"940a6fc7.c59bf","name":"","lon":"-5","lat":"50.","start":"sunriseEnd","startoffset":0,"end":"sunsetStart","endoffset":0,"x":279,"y":353,"wires":[["33ad6f00.05b282","83e28cea.27666"]]},{"id":"ce605dfa.357ef","type":"debug","z":"940a6fc7.c59bf","name":"","active":true,"console":"false","complete":"true","x":515,"y":426,"wires":[]},{"id":"2f72955e.0e280a","type":"inject","z":"940a6fc7.c59bf","name":"","topic":"","payload":"3","payloadType":"num","repeat":"","crontab":"","once":false,"x":101,"y":453,"wires":[["eb6e1401.767408"]]},{"id":"c7bb17be.e9ae58","type":"mqtt in","z":"940a6fc7.c59bf","name":"","topic":"light","qos":"2","broker":"f2bcedec.c204e","x":81,"y":383,"wires":[["33ad6f00.05b282","6451506e.102dd"]]},{"id":"eb6e1401.767408","type":"mqtt out","z":"940a6fc7.c59bf","name":"","topic":"light","qos":"","retain":"","broker":"f2bcedec.c204e","x":222,"y":454,"wires":[]},{"id":"33ad6f00.05b282","type":"function","z":"940a6fc7.c59bf","name":"test with light at 3","func":"var altitude =  msg.payload.altitude;\nvar light    =  3\nif (altitude <4 && light <5)\n\n{msg.payload.lamp = 1;\n}else{\n msg.payload.lamp = 0;}\n \nreturn msg;\n","outputs":1,"noerr":0,"x":288,"y":407,"wires":[["ce605dfa.357ef"]]},{"id":"83e28cea.27666","type":"function","z":"940a6fc7.c59bf","name":"Sanity check","func":"if (msg.payload.altitude < 4){\n    msg.payload.less = 1;\n}else{ msg.payload.less = 0;}\nreturn msg;","outputs":1,"noerr":0,"x":474,"y":344,"wires":[["b5dd636e.27d3c"]]},{"id":"b5dd636e.27d3c","type":"debug","z":"940a6fc7.c59bf","name":"","active":true,"console":"false","complete":"true","x":516,"y":389,"wires":[]},{"id":"f2bcedec.c204e","type":"mqtt-broker","z":"","broker":"192.168.1.40","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"willTopic":"","willQos":"0","willPayload":"","birthTopic":"","birthQos":"0","birthPayload":""}]
Reply all
Reply to author
Forward
0 new messages