Help controlling water tank level

Hi,

Im trying to control the level in a tank with node red on the raspberry pi 3. I have a low and high switch at the bottem and top of the tank and a solenooid to let in water. Im very new to coding and node red so i need some help. Ive done up a flow (I know its ugly) and it kind of works but, if the high switch is open before the low switch opens the solenoid still fills the tank.

[{“id”:“8757536f.2115c8”,“type”:“rpi-gpio in”,“z”:“e4167a44.5763d8”,“name”:“Low Level SW”,“pin”:“40”,“intype”:“up”,“debounce”:“25”,“read”:true,“x”:130,“y”:580,“wires”:[[“26fd1d82.81ceb2”,“580f2422.bc118c”,“42c5da7c.9a4054”,“a1c56cf5.c4674”,“e0876d8c.a7238”]]},{“id”:“ca05192d.5c77b8”,“type”:“rpi-gpio in”,“z”:“e4167a44.5763d8”,“name”:“High level SW”,“pin”:“38”,“intype”:“up”,“debounce”:“25”,“read”:true,“x”:130,“y”:520,“wires”:[[“39d1f00e.2be2b”]]},{“id”:“ec6b2cda.ba1df”,“type”:“rpi-gpio out”,“z”:“e4167a44.5763d8”,“name”:“Solenoid”,“pin”:“37”,“set”:true,“level”:“1”,“freq”:"",“out”:“out”,“x”:800,“y”:580,“wires”:},{“id”:“9138080f.2f1f28”,“type”:“change”,“z”:“e4167a44.5763d8”,“name”:“AND”,“rules”:[{“t”:“change”,“p”:“payload”,“pt”:“msg”,“from”:“0”,“fromt”:“num”,“to”:“0”,“tot”:“num”}],“action”:"",“property”:"",“from”:"",“to”:"",“reg”:false,“x”:610,“y”:580,“wires”:[[“ec6b2cda.ba1df”]]},{“id”:“e0876d8c.a7238”,“type”:“trigger”,“z”:“e4167a44.5763d8”,“op1”:“1”,“op2”:“1”,“op1type”:“num”,“op2type”:“num”,“duration”:“250”,“extend”:false,“units”:“ms”,“reset”:"",“bytopic”:“all”,“name”:"",“x”:420,“y”:580,“wires”:[[“9138080f.2f1f28”]]},{“id”:“39d1f00e.2be2b”,“type”:“change”,“z”:“e4167a44.5763d8”,“name”:“Invert output”,“rules”:[{“t”:“change”,“p”:“payload”,“pt”:“msg”,“from”:“1”,“fromt”:“num”,“to”:“0”,“tot”:“num”}],“action”:"",“property”:"",“from”:"",“to”:"",“reg”:false,“x”:410,“y”:520,“wires”:[[“9138080f.2f1f28”]]}]

This is what i need it to do,
if high switch = 0 & low switch = 0
send = 0
if high switch = 1 & low switch = 0
send = 0
if high switch = 1 & low switch = 1
send = 0
if high switch = 0 & low switch = 1
send = 1, untill high switch = 1

Ive used the trigger node to latch the low switch output to 1 untill the high switch sends 0. I think it can be done in a function node but i dont know how to seperate the 2 switch payloads coming in to the function node

Any help wil be appreciated
Jeremy

OK when posting code - place ``` (backticks) around it so we can import the code correctly.

Explain in english (once you have fixed up your code above) - what you are trying to achieve ?

I assume

  1. Monitor Tank low level sensor = if it is triggered - then the tank needs to be filled so turn on the solenoid to let water in

  2. Monitor high level sensor = when it is triggered then turn off the solenoid to stop filling the tank

Is this logic correct (i.e. this is what you want to do ?) if so where is the problem ?

Craig

with the flow at the moment if the high level is already triggered before the low is triggered (eg: if the high switch is stuck from the last fill) the tank will start to fill once the low switch is active and continue to fill untill it overflowes

{"id":"8757536f.2115c8","type":"rpi-gpio in","z":"e4167a44.5763d8","name":"Low Level SW","pin":"40","intype":"up","debounce":"25","read":true,"x":130,"y":580,"wires":[["26fd1d82.81ceb2","580f2422.bc118c","42c5da7c.9a4054","a1c56cf5.c4674","e0876d8c.a7238"]]},{"id":"ca05192d.5c77b8","type":"rpi-gpio in","z":"e4167a44.5763d8","name":"High level SW","pin":"38","intype":"up","debounce":"25","read":true,"x":130,"y":520,"wires":[["39d1f00e.2be2b"]]},{"id":"ec6b2cda.ba1df","type":"rpi-gpio out","z":"e4167a44.5763d8","name":"Solenoid","pin":"37","set":true,"level":"1","freq":"","out":"out","x":800,"y":580,"wires":[]},{"id":"9138080f.2f1f28","type":"change","z":"e4167a44.5763d8","name":"AND","rules":[{"t":"change","p":"payload","pt":"msg","from":"0","fromt":"num","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":610,"y":580,"wires":[["ec6b2cda.ba1df"]]},{"id":"e0876d8c.a7238","type":"trigger","z":"e4167a44.5763d8","op1":"1","op2":"1","op1type":"num","op2type":"num","duration":"250","extend":false,"units":"ms","reset":"","bytopic":"all","name":"","x":420,"y":580,"wires":[["9138080f.2f1f28"]]},{"id":"39d1f00e.2be2b","type":"change","z":"e4167a44.5763d8","name":"Invert output","rules":[{"t":"change","p":"payload","pt":"msg","from":"1","fromt":"num","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":410,"y":520,"wires":[["9138080f.2f1f28"]]}

i think the easy thing to do would be use a function node but i dont know how to differentiate between the 2 variables from the 2 switches, need help with the '?'

var high switch=? //msg.payload from high switch
var low switch=? //msg.payload from low switch
var output=''
if (low switch=0 && high switch=0) {
output=false
} else
if (low switch=0 && high switch=1) {
output=false
} else
if (low switch=1 && high switch=1) {
output=false
}else
if (low switch=1 && high switch=0) {
output=true
msg.payload=0utput
return msg;

For some reason your flow is not importable (by me at least), but I think you should use a Join node in key/value mode to give you one message containing the current state of both switches. Then I think it becomes easy. See this example in the cookbook for how to do it.#https://cookbook.nodered.org/basic/join-streams

OK when you say the switch is stuck - i assume you mean the "Virtual" switch i.e. your variables you are using - rather than the physical switch being faulty ? (if it is the physical switch then you need to get that replaced, not try to code around edge use cases).

I will assume that once you receive a low level alert you want to fill the tank until you receive a high level alert and then stop filling ?

The easiest way is to use a global variable (Lets call it Tank-Needs-Filling) - this will be set to True when the Low level switch is activated and set to False when the high level switch is activated

So you will have a loop that does the following

Check Low level switch - if activated set Tank-Needs-Filling to True
Check High level switch - if activated set Tank-Needs-Filling to False

This loop would just run every minute (or whatever is appropriate based on the size of the tank and the fill rate)

A 2nd Loop would run and monitor this Global Variable - Tank-Needs-Filling - if it equals true, will turn on the solenoid, if false turn off the solenoid

Craig

Later on if you want to get fancy - you can look at doing this as a Finite State Machine - using the DSM node

(And i can not import your flow either) when pasting a flow - select the nodes and then choose the export option

When you go to paste them in here then put 3 backticks on a single line (by themselves) - then paste your code and then 3 more backticks on a line after your code and you should end up with something that looks like the below - the backtick on a standard (US) keyboard is next to the 1 key and is on the same key as the TILDE ~

{"id":"8757536f.2115c8","type":"rpi-gpio in","z":"e4167a44.5763d8","name":"Low Level SW","pin":"40","intype":"up","debounce":"25","read":true,"x":130,"y":580,"wires":[["26fd1d82.81ceb2","580f2422.bc118c","42c5da7c.9a4054","a1c56cf5.c4674","e0876d8c.a7238"]]},{"id":"ca05192d.5c77b8","type":"rpi-gpio in","z":"e4167a44.5763d8","name":"High level SW","pin":"38","intype":"up","debounce":"25","read":true,"x":130,"y":520,"wires":[["39d1f00e.2be2b"]]},{"id":"ec6b2cda.ba1df","type":"rpi-gpio out","z":"e4167a44.5763d8","name":"Solenoid","pin":"37","set":true,"level":"1","freq":"","out":"out","x":800,"y":580,"wires":[]},{"id":"9138080f.2f1f28","type":"change","z":"e4167a44.5763d8","name":"AND","rules":[{"t":"change","p":"payload","pt":"msg","from":"0","fromt":"num","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":610,"y":580,"wires":[["ec6b2cda.ba1df"]]},{"id":"e0876d8c.a7238","type":"trigger","z":"e4167a44.5763d8","op1":"1","op2":"1","op1type":"num","op2type":"num","duration":"250","extend":false,"units":"ms","reset":"","bytopic":"all","name":"","x":420,"y":580,"wires":[["9138080f.2f1f28"]]},{"id":"39d1f00e.2be2b","type":"change","z":"e4167a44.5763d8","name":"Invert output","rules":[{"t":"change","p":"payload","pt":"msg","from":"1","fromt":"num","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":410,"y":520,"wires":[["9138080f.2f1f28"]]}

Craig

[{"id":"8757536f.2115c8","type":"rpi-gpio in","z":"e4167a44.5763d8","name":"Low Level SW","pin":"40","intype":"up","debounce":"25","read":true,"x":150,"y":720,"wires":[["e0876d8c.a7238"]]},{"id":"ca05192d.5c77b8","type":"rpi-gpio in","z":"e4167a44.5763d8","name":"High level SW","pin":"38","intype":"up","debounce":"25","read":true,"x":150,"y":660,"wires":[["12edd188.79e84e"]]},{"id":"ec6b2cda.ba1df","type":"rpi-gpio out","z":"e4167a44.5763d8","name":"Solenoid","pin":"19","set":true,"level":"1","freq":"","out":"out","x":820,"y":720,"wires":[]},{"id":"9138080f.2f1f28","type":"change","z":"e4167a44.5763d8","name":"AND","rules":[{"t":"change","p":"payload","pt":"msg","from":"0","fromt":"num","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":650,"y":720,"wires":[["ec6b2cda.ba1df"]]},{"id":"e0876d8c.a7238","type":"trigger","z":"e4167a44.5763d8","op1":"1","op2":"1","op1type":"num","op2type":"num","duration":"250","extend":false,"units":"ms","reset":"","bytopic":"all","name":"","x":440,"y":720,"wires":[["9138080f.2f1f28","26fd1d82.81ceb2","580f2422.bc118c","42c5da7c.9a4054"]]},{"id":"12edd188.79e84e","type":"change","z":"e4167a44.5763d8","name":"Invert output","rules":[{"t":"change","p":"payload","pt":"msg","from":"1","fromt":"num","to":"0","tot":"num"}],"action":"","property":"","from":"","to":"","reg":false,"x":430,"y":660,"wires":[["9138080f.2f1f28"]]}]

how can i post a picture i think it would be easier to show what im trying to do

Maybe i could try somthing like this but i dont know how assign the variables from the 2 switches,

[{"id":"abfdc92b.0f7be8","type":"rpi-gpio in","z":"e4167a44.5763d8","name":"Low Level SW","pin":"40","intype":"up","debounce":"25","read":true,"x":510,"y":1100,"wires":[["c7cf5cde.303d3"]]},{"id":"d398d6cb.dc6c5","type":"rpi-gpio in","z":"e4167a44.5763d8","name":"High level SW","pin":"38","intype":"up","debounce":"25","read":true,"x":510,"y":1040,"wires":[["c7cf5cde.303d3"]]},{"id":"c7cf5cde.303d3","type":"function","z":"e4167a44.5763d8","name":"","func":"var high_switch= ? //msg.payload from high switch\nvar low_switch= ?  //msg.payload from low switch\nvar output;\n\nif (low_switch==0 && high_switch==0) {\n    output=false\n}else\nif (low_switch==0 && high_switch==1) {\n    output=false\n}else  \nif (low_switch==1 && high_switch==1) { \n    output=false\n}else\nif (low_switch==1 && high_switch==0) {\n    output=true\n}\nmsg.payload=output\nreturn msg;","outputs":1,"noerr":8,"x":730,"y":1080,"wires":[["d24cc080.e907f"]]},{"id":"d24cc080.e907f","type":"rpi-gpio out","z":"e4167a44.5763d8","name":"Solenoid","pin":"19","set":true,"level":"1","freq":"","out":"out","x":900,"y":1080,"wires":[]}]

if i use
var low_switch=msg.payload
var high_switch=msg.payload
how would the function node know which is which

Use the Change Node which can take an input value in the message body (payload) and put it into a context variable

I am not at my computer to do a flow now - but if you follow the logic from what i said above you should be able to get a solution

Craig

I think you are making this harder than it needs to be by trying to get your && working in the if statement - if you use the logic that i said before then you are not concerned about transitions of the switches (after the 1st one)

Craig

OK Try this

[{"id":"c78f696.b5cee98","type":"rpi-gpio in","z":"b68d15f7.6a1ab8","name":"Low Level SW","pin":"40","intype":"up","debounce":"25","read":true,"x":210,"y":440,"wires":[["a3253f5a.7b082"]]},{"id":"427da720.c44318","type":"change","z":"b68d15f7.6a1ab8","name":"Set Global Variable to fill tank","rules":[{"t":"set","p":"Tank_Needs_to_Be_Filled","pt":"global","to":"true","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":740,"y":440,"wires":[[]]},{"id":"a3253f5a.7b082","type":"switch","z":"b68d15f7.6a1ab8","name":"Test for low level","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"0","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":430,"y":440,"wires":[["427da720.c44318"]]},{"id":"6720f018.bed2b","type":"rpi-gpio in","z":"b68d15f7.6a1ab8","name":"High level SW","pin":"38","intype":"up","debounce":"25","read":true,"x":210,"y":500,"wires":[["78e82b4f.1b8884"]]},{"id":"78e82b4f.1b8884","type":"switch","z":"b68d15f7.6a1ab8","name":"Test for High level","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"1","vt":"num"}],"checkall":"true","repair":false,"outputs":1,"x":430,"y":500,"wires":[["31194b7d.27f9b4"]]},{"id":"31194b7d.27f9b4","type":"change","z":"b68d15f7.6a1ab8","name":"Set Global Variable to fill tank","rules":[{"t":"set","p":"Tank_Needs_to_Be_Filled","pt":"global","to":"false","tot":"bool"}],"action":"","property":"","from":"","to":"","reg":false,"x":740,"y":500,"wires":[[]]}]

This sets the global variable for you (you will need to create it first somewhere) and then manipulates its based on the switch positions (i do not know the logic of your switches in terms of 1 and 0 for open and closed)

You then just need an inject node that runs every minute (as appropriate) to check the Global variable and enable the solenoid if it is set to true

Depending on if motors (pumps) are involved you may want to build in some hysterises control but that can come later

Craig

I have a flow I was using in my son's greenhouse (the bum moved!) I had a hydroponics setup and the water tank had two float valves, one at the top and one halfway down. They were tied to two gpio pins on the pi - if the switch was up, it would report 'high', if it was low it would report low. Both switches also put the value in seperate golbal variables. A common function node would determine if the tank was 'full' - both switches on. 'low' - top swotch off and middle switch on, or 'needs water' - both switches off. The msg's were paused for 50 ms to handle any rocking state of the switch due to waves caused by water returning to the tank. The msgs were only sent outside the three times watering went on automatically.

a second flow would look at the status (full, low or needs water) and send out an email if need be.

I had plans to connect this all to an automatic valve but didn't have time before they moved (the bum :smile:)

Here is the entire flow if you want to take a look. greenhouse.json (46.2 KB)

You will note that I also sent the data to a php program running on my web host that stored the data in a mySQL database and I had some php programs to query the data allowed me to look at it from anywhere.

Hi craig,

Thanks for the help so far, I kind of understand about to concept of storing a variable but i dont really understand what i am meant to do with these nodes in your flow.

Here is picture of what i would do if i were to hard wire it.

Hi Zenofmud,

Could you please export your flow so i can import it.

Yep you are getting hardware and software mixed up and making it harder than you need to.

The nodes in my flow are to simply read the state of the input pins on the Rpi, based on them you set the global variable appopriately.

Think about it this way - once the tank goes low you want to know that from the low side valve - you do not care what that valve is doing after it tells you the tank is low - so you only have to capute one state transition - that from when the tank is adequately full to when it is approaching empty

Similarly on the high side valve - you are only interested when it signals that the tank is full - so you record it only when it tells you that the tank is full

The brains of the outfit is done by the third node that i have not given you - it polls the global variable every minute - if it says the variable is null it does nothing, if it says the tank needs filling it opens the solenoid valve, if it says the tank is full it closes the solenoid. Thats it

Craig

Sorry it was stuck in the middle of the last paragraph. I reakky have to reread my posts before pressing reply. Look again I edited my post.