Making a AND function

Hi, This is second time im using node-red so im still a rookie :smiley:

Im having trouble getting my function to work. Need to sends out a 1 or 0 in debug node.

Im using rasberry pi 4b with PIR and ultra sonic sensor. I want to make a AND function:
if their is movement and sonic sensor is in a certain range the function will send a 1 else its a 0

im getting errors: "Cannot set property of non-object type: payload.uss,
same with payload.pir

Do I need to use a join node before a function or is their a better or smarter way?

-ultra sonic sensor sends a string (xxx in cm)and I change that to number
-pir sensor sends in numberic 1 or 0

Here is my code:

[{"id":"3111490beaa533a8","type":"tab","label":"Flow 3","disabled":true,"info":"","env":[]},{"id":"5866be3c574cc7ff","type":"rpi-gpio in","z":"3111490beaa533a8","name":"PIR_Sensor_GPIO26","pin":"26","intype":"tri","debounce":"25","read":false,"bcm":true,"x":200,"y":200,"wires":[["09c2e1dc101cfde2"]]},{"id":"181ad8db249dc7ac","type":"rpi-srf","z":"3111490beaa533a8","name":"","topic":"SRF","pulse":"2","pins":"38,40","precision":"0","x":150,"y":100,"wires":[["f0b6656bb04a1599"]]},{"id":"ed7471ed04b0e870","type":"change","z":"3111490beaa533a8","name":"","rules":[{"t":"set","p":"payload.uss","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":820,"y":80,"wires":[["e6ab834867e6bbcb"]]},{"id":"09c2e1dc101cfde2","type":"change","z":"3111490beaa533a8","name":"","rules":[{"t":"set","p":"payload.pir","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":710,"y":200,"wires":[["e6ab834867e6bbcb"]]},{"id":"e6ab834867e6bbcb","type":"function","z":"3111490beaa533a8","name":"","func":"//detection and correct distance\nif(msg.payload.pir === 1 & msg.payload.uss === 1) \n{\n    msg.payload=1;\n}\n\n//No detection and wrong distance\nelse \n{\n    msg.payload=0;\n}\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1040,"y":80,"wires":[["a354b46e67748d63"]]},{"id":"a354b46e67748d63","type":"debug","z":"3111490beaa533a8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1210,"y":80,"wires":[]},{"id":"f0b6656bb04a1599","type":"switch","z":"3111490beaa533a8","name":"","property":"payload","propertyType":"msg","rules":[{"t":"btwn","v":"15","vt":"str","v2":"20","v2t":"str"},{"t":"gt","v":"15","vt":"str"},{"t":"lt","v":"20","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":370,"y":80,"wires":[["2e398ab9a7348453"],["91f2c51ed301826b"],["d6009968df9dfc81"]]},{"id":"2e398ab9a7348453","type":"change","z":"3111490beaa533a8","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"1","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":580,"y":60,"wires":[["ed7471ed04b0e870"]]},{"id":"91f2c51ed301826b","type":"change","z":"3111490beaa533a8","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":580,"y":100,"wires":[["ed7471ed04b0e870"]]},{"id":"d6009968df9dfc81","type":"change","z":"3111490beaa533a8","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":580,"y":140,"wires":[["ed7471ed04b0e870"]]}]

You need always either a JOIN Node or you can use a context (function node or flow variable). To compare 2 different values in 2 different messages. It is always necessary to store at least one value somewhere. You should be aware that messages do not wait for each other, that they can be compared.

1 Like

@Naz - You are much more likely to get support if you could post your flow without including the non-standard nodes (Rpi nodes), because other users trying your flow would need to install and setup those nodes in their own own system.
You can always replace those nodes with inject nodes to simulate the rpi nodes.

I assume that both PIR data & ultrasonic data must arrive together within a certain timeframe, so just using a Join node or context data may not meet your needs without further processing.
That timeframe in commercial devices is usually about 1 second.

Looking at your Switch node:

Firstly, if msg.payload is between "15 and "20" the message goes to output 1.
The next line (if msg.payload > "15") sends the message to output 2 but because of the first test, only if payload > "20"
Similarly with line 3 (if msg.payload < "20") the message goes to output 3 only if msg.payload < "15"
At the very least, this is confusing and badly written.

Worse still, you are comparing numeric values in string form which gives rise to such surprising truths as "8" > "20".
The very first thing you should do is convert the input to a number, then process it as a number.

Do you know if a payload value of exactly "15" or "20" will be caught by the first test?

You really need to clarify the precise circumstances in which outputs 1, 2 or 3 are chosen.

The idea was if ultra sonic sensor was between 15cm and 20 cm, it sends out 1, if it is under 15cm or over 20cm its sends out 0 with the two other outputs.

I think the motion sensor sends a value every 4-5 seconds.
The ultra sonic sensor I can control how often with the node. atm its every 2 sec

anyway i made inject nodes and converted it to number but im not sure if this will work. Am I on the right path? Here is the code:

[{"id":"60a12d043447c535","type":"tab","label":"Flow 4","disabled":false,"info":"","env":[]},{"id":"31f67ad42d56e0c7","type":"change","z":"60a12d043447c535","name":"","rules":[{"t":"set","p":"distance_sensor","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":560,"y":220,"wires":[["072efbd12d92d47a"]]},{"id":"275ff620ebd6b18d","type":"change","z":"60a12d043447c535","name":"","rules":[{"t":"set","p":"motion_sensor","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":530,"y":100,"wires":[["ba3ddf985951a34b"]]},{"id":"072efbd12d92d47a","type":"function","z":"60a12d043447c535","name":"","func":"if (global.distance_sensor < 25 && Global.motion_sensor == 1)\n{\n    msg.payload=1;\n}\n\n//No detection and wrong distance\nelse \n{\n    msg.payload=0;\n}\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":820,"y":220,"wires":[["1cb0012afcd4599b"]]},{"id":"4aa30dfedbcb0928","type":"function","z":"60a12d043447c535","name":"","func":"msg.payload = Number(msg.payload);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":320,"y":220,"wires":[["31f67ad42d56e0c7","22691a96c773e26e"]]},{"id":"1cb0012afcd4599b","type":"debug","z":"60a12d043447c535","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1030,"y":220,"wires":[]},{"id":"ba3ddf985951a34b","type":"debug","z":"60a12d043447c535","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":770,"y":100,"wires":[]},{"id":"22691a96c773e26e","type":"debug","z":"60a12d043447c535","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":210,"y":320,"wires":[]},{"id":"c2f437b8483ae3b5","type":"inject","z":"60a12d043447c535","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":130,"y":100,"wires":[["275ff620ebd6b18d"]]},{"id":"d6a189e0f34e5a30","type":"inject","z":"60a12d043447c535","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"20","payloadType":"str","x":130,"y":220,"wires":[["4aa30dfedbcb0928"]]},{"id":"7f62bf345e27178a","type":"comment","z":"60a12d043447c535","name":"Motion_sensor sends 1 or 0 (number)","info":"Motion_sensor sends 1 or 0 (number)","x":190,"y":40,"wires":[]},{"id":"b7e72f57e7e47f49","type":"comment","z":"60a12d043447c535","name":"Ultra sonic sensor sends value between 0 to 300 (string)","info":"","x":220,"y":180,"wires":[]},{"id":"bb15ccb6e7a57135","type":"comment","z":"60a12d043447c535","name":"if ultra sonic sensor is under 20 and motion sensor is 1 then payload = 1  else payload = 0","info":"if ultra sonic sensor is under 20 and motion sensor is 1 then payload = 1 \nelse\npayload 0","x":1030,"y":280,"wires":[]}]

Thanks for your simplified flow @Naz.

There are different methods available to compare messages from two or more sources.
One is to save one of the values in context storage.
This may be the right approach in your system where they arrive at different frequency.

However, with just two messages, you only need to save one of them in context storage, and you should try not to use global context if the stored value is only relevant in the current flow. Instead use flow.distance_sensor.

Looking at your comparison code:

if (global.distance_sensor < 25 && Global.motion_sensor == 1)
{
    msg.payload=1;
} 
etc

I might be wrong but I don't think you can access the value of a context variable like that.
I think it should be something like this...

const distancesensor = flow.get('distance_sensor') || 0;   // A default value for if variable not yet set.
if (distancesensor < 25 && msg.payload == 1) {
   msg.payload = 1;
}
else (
   msg.payload = 0;
}

ps I don't think "Global.blah" and "global,blah" are equivalent. Not sure because I try to always use lower case to avoid problems with case sensitive languages.

@jbudd - I assume that the OP is confirming a physical presence by receiving 2 different alerts (commonly called dualtech);

  1. PIR - to detect changes in the infrared footprint, and
  2. Ultrasonic - to detect a change in the distance of a moving object

This is usually a double-check, to prevent false alerts, so both have to activate at almost the same time, usually within a second apart.

An example would be when a ray of sunshine hits the PIR it would activate (and indicate an intruder), but because there is no Ultrasonic activity, it would be disregarded.
However, if a person was approaching, the PIR would again see a change in it's footprint, and also the Ultrasonic (doppler) would also see a change and therefore would result in a positive detection.

Using saved context has no understanding of the activation times, so for example, the PIR could activate at 10am when a fan heater switches on, and the Ultrasonic device activates an hour later at 11am when a gust of wind moves a curtain. This would be a false alarm.

Both alerts need to coincide, in whatever order, within a small timeframe.

@Naz if this is not your case, please say so!

I'm sure you are right. I don't think that the description we have is sufficient to define a robust algorithm. but it's a good first step.

@Paul-Reed You hit jackpot :smiley: Im working on a anpr system with a free clouding service with limited uploads. To avoid using unnecessary uploads everytime the PIR motion sensor triggers, I would have a other type of sensor helping out with false triggers. I think the problem could be how they both need to activate in a small timeframe. In my head I figured it would be easy but I guees not :smiley:

You can shorten the lifespan of a context variable with a trigger node.
Eg send msg.payload first, after n seconds send 0

3 Likes

Just be aware that either sensor could trigger first, so maybe need to treat them identically. ie, both sensors will need to create a context variable.

1 Like

Thank you very much for your time @jbudd and @Paul-Reed

I read and saw a video about how context works and got a better understanding.

So what I did was , the motion sensor need to save the data in context for 3 secs then it reset before the motion sensor triggers again(every 4-5 secs).
The distance sensor keeps sending msgs every 1 sec and if its between 15-25 cm and there was motion in certain time frame(gets context data) then it sends payload= 1 else = 0

here the code if anyone would like to learn from it or use it:

[{"id":"60a12d043447c535","type":"tab","label":"Flow 4","disabled":false,"info":"","env":[]},{"id":"072efbd12d92d47a","type":"function","z":"60a12d043447c535","name":"","func":"const motionsensor = flow.get('motion_sensor') || 0;   // A default value for if variable not yet set.\n\nif (msg.distance_sensor >= 15 && msg.distance_sensor <= 25 && motionsensor == 1)\n{\n    msg.payload=1;\n}\n\n//No detection or wrong distance\nelse \n\n{\n    msg.payload=0;\n}\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":820,"y":220,"wires":[["1cb0012afcd4599b"]]},{"id":"4aa30dfedbcb0928","type":"function","z":"60a12d043447c535","name":"","func":"msg.payload = Number(msg.payload);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":320,"y":220,"wires":[["9d2427f7c9583653"]]},{"id":"1cb0012afcd4599b","type":"debug","z":"60a12d043447c535","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1030,"y":220,"wires":[]},{"id":"ba3ddf985951a34b","type":"debug","z":"60a12d043447c535","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":770,"y":100,"wires":[]},{"id":"c2f437b8483ae3b5","type":"inject","z":"60a12d043447c535","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":130,"y":100,"wires":[["577a3f841921bc1d"]]},{"id":"d6a189e0f34e5a30","type":"inject","z":"60a12d043447c535","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"20","payloadType":"str","x":130,"y":220,"wires":[["4aa30dfedbcb0928"]]},{"id":"7f62bf345e27178a","type":"comment","z":"60a12d043447c535","name":"Motion_sensor sends 1 or 0 (number)","info":"Motion_sensor sends 1 or 0 (number)","x":190,"y":40,"wires":[]},{"id":"b7e72f57e7e47f49","type":"comment","z":"60a12d043447c535","name":"Ultra sonic sensor sends value between 0 to 300 (string)","info":"","x":220,"y":180,"wires":[]},{"id":"bb15ccb6e7a57135","type":"comment","z":"60a12d043447c535","name":"if ultra sonic sensor is between 15-25 and motion sensor is 1 then payload = 1  else payload 0","info":"if ultra sonic sensor is between 15-25 and motion sensor is 1 then payload = 1 \nelse\npayload 0","x":1040,"y":280,"wires":[]},{"id":"9d2427f7c9583653","type":"change","z":"60a12d043447c535","name":"","rules":[{"t":"set","p":"distance_sensor","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":550,"y":220,"wires":[["072efbd12d92d47a"]]},{"id":"bad434abd9a9a616","type":"change","z":"60a12d043447c535","name":"","rules":[{"t":"set","p":"motion_sensor","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":500,"y":100,"wires":[["ba3ddf985951a34b"]]},{"id":"577a3f841921bc1d","type":"trigger","z":"60a12d043447c535","name":"","op1":"","op2":"0","op1type":"pay","op2type":"num","duration":"3","extend":false,"overrideDelay":false,"units":"s","reset":"","bytopic":"all","topic":"topic","outputs":1,"x":280,"y":100,"wires":[["bad434abd9a9a616"]]},{"id":"ee16bb0548e16cf2","type":"comment","z":"60a12d043447c535","name":"Keep that value in context and gets reset after 3 sec by the trigger node","info":"","x":650,"y":40,"wires":[]},{"id":"0e2786743573d1b4","type":"comment","z":"60a12d043447c535","name":"convert to number","info":"","x":330,"y":260,"wires":[]}]
1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.