I have built an Arduino based humidity switch for my bathroom fan:
- Arduino1 + humidity sensor, publishing humidity value on MQTT
- Arduino2 + relay, connected to fan & subscribing to fanState ("ON"/"OFF")
- Raspberry Pi + Mosquitto + node-red
The node-red dashboard is set up with, amongst other things, a drop-down to change modes: Humidity, Off & On for 5 minutes.
I use a flow variable as a way to persist the state. I inject the default value (Humidity) once at the start, and then every time the main function node is invoked (when Arduino1 publishes Humidity value) it reads the flow variable and sets the msg.payload accordingly. It should also publish a msg on the third terminal [2] with a payload equivalent to the desired drop-down state. For Humidity and Off, it remains constant but there's a countdown timer for the Timed choice, so that it reverts the drop-down to Humidity, when the 300,000ms are up. My code keeps returning undefined on that terminal and I can't work out why?
[
{
"id": "f83e28e7.f328c8",
"type": "tab",
"label": "Flow 2",
"disabled": false,
"info": ""
},
{
"id": "92d0723a.bc29",
"type": "function",
"z": "f83e28e7.f328c8",
"name": "ThresholdCheck",
"func": "var humidity= msg.payload;\nvar FT = \"off\" //FanToggle\nvar FV = 0 //FantoggleValue\nvar H = {\"Humidity\":\"Humidity\"};\nvar msg2 = {};\nvar msg3 = {};\nvar msg4 = {};\n// fanGoal: 0=Humidity, 1=Off, 2=Timed\nvar fanGoal = flow.get(\"fanGoal\");\n// fanTimer\nvar fanTimer= flow.get(\"fanTimer\");\nvar fanCount= flow.get(\"fanCountdown\");\n\n//--------------msg1\nmsg = {\"payload\":humidity};\n\n//--------------msg2\n//console.log(humidity);\nif (parseFloat(humidity)>85){\n FT={\"payload\":\"ON\"};\n FV={\"payload\":parseInt(\"1\")};\n //console.log('A');\n}\nelse{\n FT={\"payload\":\"off\"};\n FV={\"payload\":parseInt(\"0\")};\n //console.log('B');\n}\n\n//console.log(\"Switch:\"+fanGoal);\nswitch(fanGoal){\n case 2: //timer\n if (fanTimer+fanCount >= Date.now()){\n // console.log(fanTimer+fanCount);\n // console.log( Date.now());\n console.log(\"Still on\");\n msg2 = {\"payload\":\"ON\"};\n //msg4 = {\"On for 5min\":\"Timed\"}; //will this reset the timer every time?\n }\n else{\n msg2 = {\"payload\":\"OFF\"};\n flow.set.fanGoal = 0;\n console.log('off - timed out');\n msg4 = \"a string\";\n //msg4.payload = H;\n //msg4 = \"Humidity\";\n //msg4 = \"Humidity:Humidity\";\n //msg4={\"payload\":H};\n //msg4={\"payload\":\"Humidity\"};\n }\n break;\n case 1: //turned off\n msg2 = {\"payload\":\"OFF\"};\n flow.set.fanGoal = 1;\n //console.log('turned off');\n break;\n default: //humidity\n msg2 = FT;\n flow.set.fanGoal = 0;\n //console.log('defaulted to humidity');\n}\n\n//--------------msg3\nmsg3 = FV;\n\n//--------------\n// [[humidity value][fan on/off state][0/1 fan state][reset fan timer]]\nreturn [[msg],[msg2],[msg3],[msg4]];",
"outputs": 4,
"noerr": 0,
"x": 1290,
"y": 360,
"wires": [
[
"cd5f791d.b65af",
"95815785.641cb",
"fef4d8d8.50ca5"
],
[
"d417b634.16acf8",
"d659884d.28f6b",
"6166c22b.d84904"
],
[
"92fe4d03.a2413",
"b43581f3.d24b5"
],
[
"723fcc70.7e8174",
"a9e2ccc8.48959"
]
]
},
{
"id": "49de89c7.1a8dc",
"type": "mqtt in",
"z": "f83e28e7.f328c8",
"name": "BathroomTemp",
"topic": "esp/dht/temperature",
"qos": "0",
"broker": "5e77ebef.095704",
"x": 1080,
"y": 120,
"wires": [
[
"7f5b7c1d.3cd9a4",
"207a4ff9.e2b4b",
"dd16722.376f71"
]
]
},
{
"id": "56e560da.6f66b8",
"type": "mqtt in",
"z": "f83e28e7.f328c8",
"name": "BathroomHumidity",
"topic": "esp/dht/humidity",
"qos": "0",
"broker": "5e77ebef.095704",
"x": 1070,
"y": 360,
"wires": [
[
"92d0723a.bc29"
]
]
},
{
"id": "d659884d.28f6b",
"type": "mqtt out",
"z": "f83e28e7.f328c8",
"name": "PublishFanState",
"topic": "bathroom/fanSwitch",
"qos": "0",
"retain": "",
"broker": "5e77ebef.095704",
"x": 1670,
"y": 360,
"wires": []
},
{
"id": "d417b634.16acf8",
"type": "ui_text",
"z": "f83e28e7.f328c8",
"group": "18fcadbc.52cd82",
"order": 4,
"width": 0,
"height": 0,
"name": "BRFanState-text",
"label": "Fan is: ",
"format": "{{msg.payload}}",
"layout": "row-spread",
"x": 1670,
"y": 420,
"wires": []
},
{
"id": "95815785.641cb",
"type": "ui_gauge",
"z": "f83e28e7.f328c8",
"name": "BRHumidity-gauge",
"group": "18fcadbc.52cd82",
"order": 1,
"width": 0,
"height": 0,
"gtype": "gage",
"title": "Humidity",
"label": "%",
"format": "{{value}}",
"min": 0,
"max": "100",
"colors": [
"#00b500",
"#e6e600",
"#ca3838"
],
"seg1": "50",
"seg2": "75",
"x": 1670,
"y": 240,
"wires": []
},
{
"id": "cd5f791d.b65af",
"type": "ui_chart",
"z": "f83e28e7.f328c8",
"name": "BRHumidity-graph",
"group": "4c2f5fcf.7f03d",
"order": 3,
"width": 0,
"height": 0,
"label": "Humidity (%)",
"chartType": "line",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "linear",
"nodata": "",
"dot": false,
"ymin": "0",
"ymax": "100",
"removeOlder": "2",
"removeOlderPoints": "",
"removeOlderUnit": "3600",
"cutout": 0,
"useOneColor": false,
"useUTC": false,
"colors": [
"#1f77b4",
"#aec7e8",
"#ff7f0e",
"#2ca02c",
"#98df8a",
"#d62728",
"#ff9896",
"#9467bd",
"#c5b0d5"
],
"useOldStyle": false,
"outputs": 1,
"x": 1670,
"y": 280,
"wires": [
[]
]
},
{
"id": "7f5b7c1d.3cd9a4",
"type": "ui_gauge",
"z": "f83e28e7.f328c8",
"name": "BRTemp-gauge",
"group": "18fcadbc.52cd82",
"order": 2,
"width": 0,
"height": 0,
"gtype": "gage",
"title": "Temp",
"label": "℃",
"format": "{{value}}",
"min": "15",
"max": "35",
"colors": [
"#00b500",
"#e6e600",
"#ca3838"
],
"seg1": "20",
"seg2": "25",
"x": 1660,
"y": 100,
"wires": []
},
{
"id": "207a4ff9.e2b4b",
"type": "ui_chart",
"z": "f83e28e7.f328c8",
"name": "BRTemp-graph",
"group": "4c2f5fcf.7f03d",
"order": 1,
"width": 0,
"height": 0,
"label": "Temp (℃)",
"chartType": "line",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "linear",
"nodata": "",
"dot": false,
"ymin": "15",
"ymax": "35",
"removeOlder": "2",
"removeOlderPoints": "",
"removeOlderUnit": "3600",
"cutout": 0,
"useOneColor": false,
"useUTC": false,
"colors": [
"#1f77b4",
"#aec7e8",
"#ff7f0e",
"#2ca02c",
"#98df8a",
"#d62728",
"#ff9896",
"#9467bd",
"#c5b0d5"
],
"useOldStyle": false,
"outputs": 1,
"x": 1660,
"y": 140,
"wires": [
[]
]
},
{
"id": "92fe4d03.a2413",
"type": "ui_chart",
"z": "f83e28e7.f328c8",
"name": "",
"group": "b47df44b.6d77f",
"order": 1,
"width": 0,
"height": 0,
"label": "Fan State",
"chartType": "line",
"legend": "false",
"xformat": "HH:mm:ss",
"interpolate": "linear",
"nodata": "",
"dot": false,
"ymin": "0",
"ymax": "1",
"removeOlder": "20",
"removeOlderPoints": "",
"removeOlderUnit": "60",
"cutout": 0,
"useOneColor": false,
"useUTC": false,
"colors": [
"#1f77b4",
"#aec7e8",
"#ff7f0e",
"#2ca02c",
"#98df8a",
"#d62728",
"#ff9896",
"#9467bd",
"#c5b0d5"
],
"useOldStyle": false,
"outputs": 1,
"x": 1640,
"y": 540,
"wires": [
[]
]
},
{
"id": "723fcc70.7e8174",
"type": "ui_dropdown",
"z": "f83e28e7.f328c8",
"name": "",
"label": "Control Fan",
"tooltip": "",
"place": "Select option",
"group": "b47df44b.6d77f",
"order": 3,
"width": 0,
"height": 0,
"passthru": false,
"multiple": false,
"options": [
{
"label": "Humidity",
"value": "Humidity",
"type": "str"
},
{
"label": "Off",
"value": "Disabled",
"type": "str"
},
{
"label": "On for 5min",
"value": "Timed",
"type": "str"
}
],
"payload": "",
"topic": "",
"x": 1090,
"y": 660,
"wires": [
[
"5e59a9f7.7ed9b",
"e3295cdf.5a951"
]
]
},
{
"id": "60cd317e.55201",
"type": "inject",
"z": "f83e28e7.f328c8",
"name": "Set Humidity High",
"topic": "esp/dht/humidity",
"payload": "90",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 1070,
"y": 240,
"wires": [
[
"92d0723a.bc29"
]
]
},
{
"id": "57c0efc.710e89",
"type": "inject",
"z": "f83e28e7.f328c8",
"name": "Set Humidity Low",
"topic": "esp/dht/humidity",
"payload": "10",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 1070,
"y": 280,
"wires": [
[
"92d0723a.bc29"
]
]
},
{
"id": "e3295cdf.5a951",
"type": "debug",
"z": "f83e28e7.f328c8",
"name": "",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"x": 1270,
"y": 720,
"wires": []
},
{
"id": "5e59a9f7.7ed9b",
"type": "function",
"z": "f83e28e7.f328c8",
"name": "FanControl",
"func": "var optns=['Humidity','Disabled','Timed'];\n\nswitch(optns.indexOf(msg.payload)){\n case 2:{\n flow.set(\"fanGoal\", 2); //timer\n flow.set(\"fanTimer\", Date.now());\n msg.payload = 2;\n break;\n }\n case 1:{\n flow.set(\"fanGoal\", 1); //off\n msg.payload = 1;\n break;\n }\n default:{\n flow.set(\"fanGoal\", 0); //humidity\n msg.payload = 0;\n }\n}\nconsole.log(\"fanGoal=\"+msg.payload);\nreturn msg;",
"outputs": 1,
"noerr": 0,
"x": 1270,
"y": 660,
"wires": [
[
"5a470963.dc131"
]
]
},
{
"id": "c8089a55.8a7ba",
"type": "inject",
"z": "f83e28e7.f328c8",
"name": "Countdowbn",
"topic": "countdown",
"payload": "300000",
"payloadType": "num",
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": 0.1,
"x": 130,
"y": 60,
"wires": [
[
"6cc6d839.7a838"
]
]
},
{
"id": "6cc6d839.7a838",
"type": "change",
"z": "f83e28e7.f328c8",
"name": "SetCountdownTime",
"rules": [
{
"t": "set",
"p": "fanCountdown",
"pt": "flow",
"to": "payload",
"tot": "msg"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 500,
"y": 60,
"wires": [
[]
]
},
{
"id": "5a470963.dc131",
"type": "debug",
"z": "f83e28e7.f328c8",
"name": "",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"x": 1650,
"y": 660,
"wires": []
},
{
"id": "698c5d7.aef0824",
"type": "inject",
"z": "f83e28e7.f328c8",
"name": "",
"topic": "Humidity",
"payload": "Humidity",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": true,
"onceDelay": 0.1,
"x": 150,
"y": 120,
"wires": [
[
"f97e71e6.9fc6d",
"723fcc70.7e8174"
]
]
},
{
"id": "f97e71e6.9fc6d",
"type": "change",
"z": "f83e28e7.f328c8",
"name": "",
"rules": [
{
"t": "set",
"p": "fanState",
"pt": "flow",
"to": "0",
"tot": "num"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 490,
"y": 120,
"wires": [
[]
]
},
{
"id": "dd16722.376f71",
"type": "debug",
"z": "f83e28e7.f328c8",
"name": "",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"x": 1650,
"y": 60,
"wires": []
},
{
"id": "fef4d8d8.50ca5",
"type": "debug",
"z": "f83e28e7.f328c8",
"name": "",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"x": 1650,
"y": 200,
"wires": []
},
{
"id": "6166c22b.d84904",
"type": "debug",
"z": "f83e28e7.f328c8",
"name": "",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"x": 1650,
"y": 460,
"wires": []
},
{
"id": "b43581f3.d24b5",
"type": "debug",
"z": "f83e28e7.f328c8",
"name": "",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"x": 1650,
"y": 580,
"wires": []
},
{
"id": "57b720f4.fbc9c",
"type": "inject",
"z": "f83e28e7.f328c8",
"name": "",
"topic": "Humidity",
"payload": "Humidity",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 850,
"y": 640,
"wires": [
[
"723fcc70.7e8174"
]
]
},
{
"id": "fbe0ed09.bad47",
"type": "inject",
"z": "f83e28e7.f328c8",
"name": "",
"topic": "Off",
"payload": "Disabled",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 870,
"y": 680,
"wires": [
[
"723fcc70.7e8174"
]
]
},
{
"id": "2d442d7d.7d3dea",
"type": "inject",
"z": "f83e28e7.f328c8",
"name": "",
"topic": "On for 5min",
"payload": "Timed",
"payloadType": "str",
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"x": 850,
"y": 720,
"wires": [
[
"723fcc70.7e8174"
]
]
},
{
"id": "a9e2ccc8.48959",
"type": "debug",
"z": "f83e28e7.f328c8",
"name": "",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"x": 1380,
"y": 520,
"wires": []
},
{
"id": "5e77ebef.095704",
"type": "mqtt-broker",
"z": "",
"name": "",
"broker": "192.168.7.245",
"port": "1883",
"clientid": "",
"usetls": false,
"compatmode": true,
"keepalive": "60",
"cleansession": true,
"birthTopic": "",
"birthQos": "0",
"birthPayload": "",
"closeTopic": "",
"closeQos": "0",
"closePayload": "",
"willTopic": "",
"willQos": "0",
"willPayload": ""
},
{
"id": "18fcadbc.52cd82",
"type": "ui_group",
"z": "",
"name": "Gauges",
"tab": "1bafefb3.600018",
"order": 2,
"disp": true,
"width": "6",
"collapse": true
},
{
"id": "4c2f5fcf.7f03d",
"type": "ui_group",
"z": "",
"name": "Graphs",
"tab": "1bafefb3.600018",
"order": 2,
"disp": true,
"width": "6",
"collapse": true
},
{
"id": "b47df44b.6d77f",
"type": "ui_group",
"z": "",
"name": "Fan state",
"tab": "1bafefb3.600018",
"order": 3,
"disp": true,
"width": "6",
"collapse": true
},
{
"id": "1bafefb3.600018",
"type": "ui_tab",
"z": "",
"name": "Bathroom",
"icon": "dashboard",
"disabled": false,
"hidden": false
}
]