Multiple temperatures controlling one fan

Hey there,
hopefully I posting in the right place. :thinking:

I have searched around and experimented a bit but am still struggeling with a rather simple task. I use Node-RED plus some ESPs with DS18 temp sensors plus a Shelly Plug S to control a fan for my hot air collector.

The initial flow so far ist pretty basic:
Temperatue inside the collector is measured and as soon as it is above a certain temperature the fan will start working. As soon as the temperature drops below a certain temperature, the fan stops working.


Now I have added another temp sensor monitoring the outside temperature. This way I want to disable the hotair collector as soon as the outside temperature is about lets say 15°C. who needs 60°C+ hot air in the house if it is warm outside anyway.

OK, i tried to connect my outside temperature sensor to the same switch node I used in the first simpler flow.

In order to combine the two temperature comparisons I used a logical AND to combine them. Funny enough the first comparison shows me a true and the fan stays out.

The other switch node enables the fan as soon as the temperature in the collector gets warm enough but outside temperature is still cool enough.
The second AND node report "Unknown" as status and I do not understand why.

It is a smart approach using switch plus a logical operator ? Or should I rather hack together my own fuction to combine both temperature checks to a single logical output message ?

Thanks in advance,
HolgiB

Welcome to the Forum @HolgiB

Your flow looks confusing from the screen shot. so that we can see what you are actually doing, if you postt your flow using these guidelines, it will make it easier to help you.

In order to make code readable and usable it is necessary to surround your code with three backticks (also known as a left quote or backquote ```)

``` 
   code goes here 
```

You can edit and correct your post by clicking the pencil :pencil2: icon.

See this post for more details - How to share code or flow json

1 Like

One thing you need to be aware of is the data on the output of the two MQTT-In nodes will arrive at different times. This means you need to 'store' the data in some sort of 'context' otherwise your 'switch' node will not work correctly. As @mudwalker asked, would it be possible for you to share your flow so people can help you?

Just been re-reading your post about when the fan should operate. It seems the logical condition is...
Turn fan ON if temperature insider collector is above a certain threshold AND ext temperature <= 15 deg C.

1 Like

Thanks for all the replies. I didn´t share my workflow as json code because it didn´t work in the first place anyhow.

@dynamicdave: I wasn´t really aware of the async nature of the two MQTT-in nodes but shure, the temperatures come in with some time differences. Also usually Node-RED in the standard flows simply forwards the message when a condition is meet.

What you describe is correct:
If we name outside temperature Tout and the collector temperature Tcol I am looking for somewhat of this logical equations:
(Tout < 15°C) && (Tcol > 30°C) = Fan On
(Tout >= 15°C) && (Tcol > 30°C) = Fan Off
(Tout < 15°C) && (Tcol < 20°C) = Fan Off
(Tout >= 15°C) && (Tcol < 20°C) = Fan Off

Somewhat like that. I already played around with various boolean modules for Node-RED but none of them really worked.

Sorry if I seem to miss obvious things here but I am using Node-RED only since a few weeks and mainly did workflows related to monitoring the energy production of several solar grid-tie inverters I have. This solar collector automation stuff was simply a by product. May be I should consider a different approach and do some "bash magic" getting more constant data from my InfluxDB.

TIA,
HolgiB

It should be perfectly possible to do these tests in Node-red.
On the other hand, it should be possible to do it in your database query or in Bash, whatever is easiest for you.

For some reason your flow doesn't work. OK.
If you were to post it maybe we could see why, but looking at a screen capture is less informative.

And I don't know the AND node you are using but I suspect it's intended to compare messages arriving sequentially on inputs 1 and 2. If so, this is a perfectly valid way to compare two different messages.

Ok, this is somewhat of an example flow with two temperature inputs plus temperature checks:

[
    {
        "id": "d6c1f08ec046990c",
        "type": "tab",
        "label": "Flow 2",
        "disabled": false,
        "info": "",
        "env": []
    },
    {
        "id": "7fa0e1ad4e60fcac",
        "type": "mqtt in",
        "z": "d6c1f08ec046990c",
        "name": "soluko-temp-0",
        "topic": "shellies/shellyuni-soluko/ext_temperature/0",
        "qos": "0",
        "datatype": "auto-detect",
        "broker": "c724c4775dbcf9f9",
        "nl": false,
        "rap": true,
        "rh": 0,
        "inputs": 0,
        "x": 110,
        "y": 160,
        "wires": [
            [
                "c4ef2c73096682cc"
            ]
        ]
    },
    {
        "id": "7581eac314df62cc",
        "type": "mqtt in",
        "z": "d6c1f08ec046990c",
        "name": "aussen-temp",
        "topic": "esp/esp8266-1/temp-0",
        "qos": "0",
        "datatype": "auto-detect",
        "broker": "c724c4775dbcf9f9",
        "nl": false,
        "rap": true,
        "rh": 0,
        "inputs": 0,
        "x": 110,
        "y": 340,
        "wires": [
            [
                "37fe12d739acd25e"
            ]
        ]
    },
    {
        "id": "c4ef2c73096682cc",
        "type": "switch",
        "z": "d6c1f08ec046990c",
        "name": "Temperatur >",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "gt",
                "v": "30",
                "vt": "num"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 430,
        "y": 160,
        "wires": [
            []
        ]
    },
    {
        "id": "37fe12d739acd25e",
        "type": "switch",
        "z": "d6c1f08ec046990c",
        "name": "Temperatur <",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "lt",
                "v": "15",
                "vt": "num"
            }
        ],
        "checkall": "true",
        "repair": false,
        "outputs": 1,
        "x": 430,
        "y": 340,
        "wires": [
            []
        ]
    },
    {
        "id": "01cc420a4833ccfb",
        "type": "http request",
        "z": "d6c1f08ec046990c",
        "name": "Soluko Lüfter an",
        "method": "GET",
        "ret": "txt",
        "paytoqs": "ignore",
        "url": "http://192.168.0.25/relay/0?turn=on",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "",
        "senderr": false,
        "headers": [],
        "x": 760,
        "y": 240,
        "wires": [
            []
        ]
    },
    {
        "id": "c724c4775dbcf9f9",
        "type": "mqtt-broker",
        "name": "hb-sauger",
        "broker": "192.168.0.181",
        "port": "1883",
        "clientid": "",
        "autoConnect": true,
        "usetls": false,
        "protocolVersion": "4",
        "keepalive": "60",
        "cleansession": true,
        "birthTopic": "",
        "birthQos": "0",
        "birthPayload": "",
        "birthMsg": {},
        "closeTopic": "",
        "closeQos": "0",
        "closePayload": "",
        "closeMsg": {},
        "willTopic": "",
        "willQos": "0",
        "willPayload": "",
        "willMsg": {},
        "userProps": "",
        "sessionExpiry": ""
    }
]

The question that remains open to me:
How do I "logically connect" the outputs of the two temperature checks in order to control the power state of my fan. :slight_smile:

Just had a few moments to rough-out this simple flow for you... it is untested (so may not work)

[{"id":"d6c1f08ec046990c","type":"tab","label":"check two inputs","disabled":false,"info":"","env":[]},{"id":"7fa0e1ad4e60fcac","type":"mqtt in","z":"d6c1f08ec046990c","name":"soluko-temp-0","topic":"shellies/shellyuni-soluko/ext_temperature/0","qos":"0","datatype":"auto","broker":"c724c4775dbcf9f9","nl":false,"rap":true,"rh":0,"inputs":0,"x":110,"y":160,"wires":[["54ce7c75f9fd7fd4"]]},{"id":"7581eac314df62cc","type":"mqtt in","z":"d6c1f08ec046990c","name":"OUTSIDE-temp","topic":"esp/esp8266-1/temp-0","qos":"0","datatype":"auto-detect","broker":"c724c4775dbcf9f9","nl":false,"rap":true,"rh":0,"inputs":0,"x":120,"y":240,"wires":[["bf61d0013767ea57"]]},{"id":"01cc420a4833ccfb","type":"http request","z":"d6c1f08ec046990c","name":"Soluko Lüfter an","method":"GET","ret":"txt","paytoqs":"ignore","url":"http://192.168.0.25/relay/0?turn=on","tls":"","persist":false,"proxy":"","authType":"","senderr":false,"x":770,"y":140,"wires":[[]]},{"id":"54ce7c75f9fd7fd4","type":"change","z":"d6c1f08ec046990c","name":"","rules":[{"t":"set","p":"Tcol","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":310,"y":160,"wires":[["484b63dca9a3c78a"]]},{"id":"bf61d0013767ea57","type":"change","z":"d6c1f08ec046990c","name":"","rules":[{"t":"set","p":"Tout","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":310,"y":240,"wires":[["484b63dca9a3c78a"]]},{"id":"484b63dca9a3c78a","type":"function","z":"d6c1f08ec046990c","name":"Check temperatures","func":"let Tcol = flow.get(\"Tcol\");\nlet Tout = flow.get(\"Tout\");\n\nif ( (Tout < 15) && (Tcol > 30) ) {\n    msg.payload = \"fan_ON\";\n    node.status({fill:\"red\",shape:\"ring\",text:\"Fan is ON\"});\n}\nelse {\n    msg.payload = \"fan_OFF\";\n    node.status({fill:\"green\",shape:\"ring\",text:\"Fan is OFF\"});\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":520,"y":200,"wires":[["fea9d456b1cae154"]]},{"id":"ed8d9688046c671f","type":"comment","z":"d6c1f08ec046990c","name":"Store Tcol and Tout in some flow variables","info":"","x":400,"y":120,"wires":[]},{"id":"fea9d456b1cae154","type":"debug","z":"d6c1f08ec046990c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":750,"y":200,"wires":[]},{"id":"c724c4775dbcf9f9","type":"mqtt-broker","name":"hb-sauger","broker":"192.168.0.181","port":"1883","clientid":"","autoConnect":true,"usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","birthMsg":{},"closeTopic":"","closeQos":"0","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"sessionExpiry":""}]

There are many ways the logical operation can be implemented. In my simple flow I save Tcol and Tout in a couple of flow variables. These variables are used in the 'function' node to compare the values. I've only written the ON condition check as I believe all other conditions result in the fan being OFF.
You will need to adjust the msg.payload output format to match the command to operate the Shelly Plug.

You may need to adjust the flow to handle the initial condition when only one input has been received from the MQTT node. For example, put some default values in the function node as below.

let Tcol = flow.get("Tcol") || 0;  // Insert a suitable default value
let Tout = flow.get("Tout") || 0;  // Insert a suitable default value

if ( (Tout < 15) && (Tcol > 30) ) {
    msg.payload = "on";
    node.status({fill:"red",shape:"ring",text:"Fan is ON"});
}
else {
    msg.payload = "off";
    node.status({fill:"green",shape:"ring",text:"Fan is OFF"});
}

return msg;
1 Like

Here is another example using a join node.

[{"id":"01cc420a4833ccfb","type":"http request","z":"d6c1f08ec046990c","name":"Soluko Lüfter an","method":"GET","ret":"txt","paytoqs":"ignore","url":"http://192.168.0.25/relay/0?turn={{payload}}","tls":"","persist":false,"proxy":"","insecureHTTPParser":false,"authType":"","senderr":false,"headers":[],"x":580,"y":220,"wires":[[]]},{"id":"62cb7cf883818ee6","type":"rbe","z":"d6c1f08ec046990c","name":"","func":"rbe","gap":"","start":"","inout":"out","septopics":false,"property":"payload","topi":"topic","x":610,"y":160,"wires":[["a7f357bf54591949","01cc420a4833ccfb"]]},{"id":"0a5362e3bd57ed1c","type":"function","z":"d6c1f08ec046990c","name":"function 21","func":"const Tcol = msg.payload[\"shellies/shellyuni-soluko/ext_temperature/0\"];\nconst Tout = msg.payload[\"esp/esp8266-1/temp-0\"];\nif(Tout < 15 && Tcol > 30) msg.payload = \"on\";\nelse msg.payload = \"off\";\nnode.status({fill: (msg.payload == \"on\" ? \"green\" : \"red\"),shape:\"ring\",text:\"Fan is \" + msg.payload});\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":430,"y":160,"wires":[["62cb7cf883818ee6"]]},{"id":"a7f357bf54591949","type":"debug","z":"d6c1f08ec046990c","name":"debug 238","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":570,"y":120,"wires":[]},{"id":"72007fcc0e1fb79d","type":"join","z":"d6c1f08ec046990c","name":"","mode":"custom","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":true,"timeout":"","count":"2","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":290,"y":180,"wires":[["0a5362e3bd57ed1c"]]},{"id":"384012c99ed90376","type":"inject","z":"d6c1f08ec046990c","name":"10","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"shellies/shellyuni-soluko/ext_temperature/0","payload":"10","payloadType":"num","x":150,"y":40,"wires":[["72007fcc0e1fb79d"]]},{"id":"0de8d29796fed3e0","type":"inject","z":"d6c1f08ec046990c","name":"40","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"shellies/shellyuni-soluko/ext_temperature/0","payload":"40","payloadType":"num","x":150,"y":80,"wires":[["72007fcc0e1fb79d"]]},{"id":"684f7d1553f0b8ca","type":"inject","z":"d6c1f08ec046990c","name":"10","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"esp/esp8266-1/temp-0","payload":"10","payloadType":"num","x":150,"y":260,"wires":[["72007fcc0e1fb79d"]]},{"id":"c92bf27040cf5ce1","type":"inject","z":"d6c1f08ec046990c","name":"40","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"esp/esp8266-1/temp-0","payload":"40","payloadType":"num","x":150,"y":300,"wires":[["72007fcc0e1fb79d"]]}]

[Edit] added filter node to limit multiple on's or off's in a row.

3 Likes

Thanks a lot ! I will try out and report back!

@E1cid 's solution using the Join node is really efficient as it stores the messages inside the Join node.
I always forget the Join node has this capability and end-up creating a slightly more complicated flow.

2 Likes

Hey mates, thanks for the help. :+1:

@dynamicdave: Indeed, what @E1cid posted is a great solution for my problem. It not only helps merging / buffering two timely independent MQTT message flows but also makes my flow much simpler since I only have one node controlling my fan. I also like the filter node a lot since it keeps the flow from sending multiple on / off commands to the Shelly S plug. It seems to me that I have still a long way to go prior I get even close to what is possible in Node-RED.

2 Likes

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