How to build a modal switch

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
    }
]