"Art" of the sequence, a Node-RED retrospective

I needed a motion lighting flow that respected manually controlling the lights. Along with usual time of day, illuminance filters. I wasn't being very successful, so Googling around I found an example from a HA user. It uses a node called a finite state machine. It takes a little bit to understand if you are not a programmer, but it's not that conceptually difficult. Basically the flow chooses a path based on triggers, current state, and future state. There's a lot more at the original reddit post.

Flow JSON:

Summary
[
{
    "id": "cd2e24c3.24164",
    "type": "state-machine",
    "z": "32054f7b.6f13c",
    "name": "",
    "triggerProperty": "payload",
    "triggerPropertyType": "msg",
    "stateProperty": "payload",
    "statePropertyType": "msg",
    "outputStateChangeOnly": true,
    "throwException": false,
    "states": [
        "switch",
        "motion-detected",
        "motion-on",
        "motion-off",
        "off",
        "on"
    ],
    "transitions": [
        {
            "name": "motion",
            "from": "off",
            "to": "motion-detected"
        },
        {
            "name": "motion",
            "from": "motion-on",
            "to": "motion-on"
        },
        {
            "name": "off",
            "from": "*",
            "to": "off"
        },
        {
            "name": "on",
            "from": "*",
            "to": "on"
        },
        {
            "name": "switch",
            "from": "off",
            "to": "switch"
        },
        {
            "name": "switch",
            "from": "on",
            "to": "switch"
        },
        {
            "name": "switch",
            "from": "switch",
            "to": "switch"
        },
        {
            "name": "switch",
            "from": "motion-on",
            "to": "switch"
        },
        {
            "name": "motion-on",
            "from": "motion-detected",
            "to": "motion-on"
        },
        {
            "name": "motion-off",
            "from": "motion-on",
            "to": "motion-off"
        }
    ],
    "x": 460,
    "y": 360,
    "wires": [
        [
            "e4bc4a4c.a41c88",
            "360cbf98.e378a8",
            "56259156.cacac",
            "3abe544f.9780ec"
        ]
    ]
},
{
    "id": "2e7249fe.b79626",
    "type": "change",
    "z": "32054f7b.6f13c",
    "name": "switch",
    "rules": [
        {
            "t": "set",
            "p": "payload",
            "pt": "msg",
            "to": "switch",
            "tot": "str"
        }
    ],
    "action": "",
    "property": "",
    "from": "",
    "to": "",
    "reg": false,
    "x": 270,
    "y": 400,
    "wires": [
        [
            "cd2e24c3.24164"
        ]
    ]
},
{
    "id": "81b55db6.ac465",
    "type": "change",
    "z": "32054f7b.6f13c",
    "name": "motion",
    "rules": [
        {
            "t": "set",
            "p": "payload",
            "pt": "msg",
            "to": "motion",
            "tot": "str"
        }
    ],
    "action": "",
    "property": "",
    "from": "",
    "to": "",
    "reg": false,
    "x": 270,
    "y": 360,
    "wires": [
        [
            "cd2e24c3.24164"
        ]
    ]
},
{
    "id": "e0147903.1a0668",
    "type": "stoptimer",
    "z": "32054f7b.6f13c",
    "duration": "2",
    "units": "Minute",
    "payloadtype": "num",
    "payloadval": "0",
    "name": "pause detection",
    "x": 860,
    "y": 540,
    "wires": [
        [
            "9d1eb16.c4c095"
        ],
        []
    ]
},
{
    "id": "18468b2f.edbca5",
    "type": "change",
    "z": "32054f7b.6f13c",
    "name": "stop",
    "rules": [
        {
            "t": "set",
            "p": "payload",
            "pt": "msg",
            "to": "stop",
            "tot": "str"
        }
    ],
    "action": "",
    "property": "",
    "from": "",
    "to": "",
    "reg": false,
    "x": 830,
    "y": 480,
    "wires": [
        [
            "786d7e71.4c4598"
        ]
    ]
},
{
    "id": "70df8219.d66544",
    "type": "change",
    "z": "32054f7b.6f13c",
    "name": "motion-on",
    "rules": [
        {
            "t": "set",
            "p": "payload",
            "pt": "msg",
            "to": "motion-on",
            "tot": "str"
        }
    ],
    "action": "",
    "property": "",
    "from": "",
    "to": "",
    "reg": false,
    "x": 1250,
    "y": 300,
    "wires": [
        [
            "81434535.f6326"
        ]
    ]
},
{
    "id": "9fdf23ab.1043a8",
    "type": "change",
    "z": "32054f7b.6f13c",
    "name": "motion-off",
    "rules": [
        {
            "t": "set",
            "p": "payload",
            "pt": "msg",
            "to": "motion-off",
            "tot": "str"
        }
    ],
    "action": "",
    "property": "",
    "from": "",
    "to": "",
    "reg": false,
    "x": 1250,
    "y": 360,
    "wires": [
        [
            "81434535.f6326"
        ]
    ]
},
{
    "id": "b0621693.6aa238",
    "type": "stoptimer",
    "z": "32054f7b.6f13c",
    "duration": "1",
    "units": "Second",
    "payloadtype": "num",
    "payloadval": "0",
    "name": "pause",
    "x": 1030,
    "y": 420,
    "wires": [
        [
            "9d1eb16.c4c095"
        ],
        []
    ]
},
{
    "id": "da08aec3.d749a",
    "type": "stoptimer",
    "z": "32054f7b.6f13c",
    "duration": "1",
    "units": "Second",
    "payloadtype": "num",
    "payloadval": "0",
    "name": "pause",
    "x": 1030,
    "y": 300,
    "wires": [
        [
            "70df8219.d66544"
        ],
        []
    ]
},
{
    "id": "1f3745d7.2e5fa2",
    "type": "inject",
    "z": "32054f7b.6f13c",
    "name": "steady-state",
    "topic": "",
    "payload": "stop",
    "payloadType": "str",
    "repeat": "",
    "crontab": "",
    "once": true,
    "onceDelay": 0.1,
    "x": 1070,
    "y": 620,
    "wires": [
        [
            "e0147903.1a0668",
            "9d1eb16.c4c095"
        ]
    ]
},
{
    "id": "e7869b10.0f8bf",
    "type": "inject",
    "z": "32054f7b.6f13c",
    "name": "",
    "topic": "",
    "payload": "simulate",
    "payloadType": "str",
    "repeat": "",
    "crontab": "",
    "once": false,
    "onceDelay": 0.1,
    "x": 100,
    "y": 340,
    "wires": [
        [
            "81b55db6.ac465"
        ]
    ]
},
{
    "id": "e4bc4a4c.a41c88",
    "type": "switch",
    "z": "32054f7b.6f13c",
    "name": "motion-detected",
    "property": "payload",
    "propertyType": "msg",
    "rules": [
        {
            "t": "eq",
            "v": "motion-detected",
            "vt": "str"
        }
    ],
    "checkall": "true",
    "repair": false,
    "outputs": 1,
    "x": 690,
    "y": 300,
    "wires": [
        [
            "76ef38e1.e0c138"
        ]
    ]
},
{
    "id": "360cbf98.e378a8",
    "type": "switch",
    "z": "32054f7b.6f13c",
    "name": "motion-on",
    "property": "payload",
    "propertyType": "msg",
    "rules": [
        {
            "t": "eq",
            "v": "motion-on",
            "vt": "str"
        }
    ],
    "checkall": "true",
    "repair": false,
    "outputs": 1,
    "x": 670,
    "y": 360,
    "wires": [
        [
            "786d7e71.4c4598"
        ]
    ]
},
{
    "id": "b1cbc49a.9cd008",
    "type": "link in",
    "z": "32054f7b.6f13c",
    "name": "kitchen state machine",
    "links": [
        "81434535.f6326"
    ],
    "x": 355,
    "y": 300,
    "wires": [
        [
            "cd2e24c3.24164"
        ]
    ]
},
{
    "id": "81434535.f6326",
    "type": "link out",
    "z": "32054f7b.6f13c",
    "name": "kitchen state machine",
    "links": [
        "b1cbc49a.9cd008"
    ],
    "x": 1455,
    "y": 320,
    "wires": []
},
{
    "id": "56259156.cacac",
    "type": "switch",
    "z": "32054f7b.6f13c",
    "name": "switch",
    "property": "payload",
    "propertyType": "msg",
    "rules": [
        {
            "t": "eq",
            "v": "switch",
            "vt": "str"
        }
    ],
    "checkall": "true",
    "repair": false,
    "outputs": 1,
    "x": 650,
    "y": 480,
    "wires": [
        [
            "18468b2f.edbca5",
            "e0147903.1a0668"
        ]
    ]
},
{
    "id": "3abe544f.9780ec",
    "type": "switch",
    "z": "32054f7b.6f13c",
    "name": "motion-off",
    "property": "payload",
    "propertyType": "msg",
    "rules": [
        {
            "t": "eq",
            "v": "motion-off",
            "vt": "str"
        }
    ],
    "checkall": "true",
    "repair": false,
    "outputs": 1,
    "x": 670,
    "y": 420,
    "wires": [
        [
            "e4033469.c56598"
        ]
    ]
},
{
    "id": "786d7e71.4c4598",
    "type": "stoptimer",
    "z": "32054f7b.6f13c",
    "duration": "2",
    "units": "Minute",
    "payloadtype": "num",
    "payloadval": "0",
    "name": "",
    "x": 1060,
    "y": 360,
    "wires": [
        [
            "9fdf23ab.1043a8"
        ],
        []
    ]
},
{
    "id": "b7009f7c.1475a8",
    "type": "hubitat device",
    "z": "32054f7b.6f13c",
    "name": "Motion Sensor",
    "server": "d0c8b8e.6894848",
    "deviceId": "2695",
    "attribute": "motion",
    "sendEvent": true,
    "x": 100,
    "y": 40,
    "wires": [
        [
            "a10c31d7.2a55a8"
        ]
    ]
},
{
    "id": "8b7bf52b.866948",
    "type": "hubitat device",
    "z": "32054f7b.6f13c",
    "name": "DR Lights",
    "server": "d0c8b8e.6894848",
    "deviceId": "7",
    "attribute": "switch",
    "sendEvent": true,
    "x": 80,
    "y": 420,
    "wires": [
        [
            "2e7249fe.b79626"
        ]
    ]
},
{
    "id": "76ef38e1.e0c138",
    "type": "hubitat command",
    "z": "32054f7b.6f13c",
    "name": "DR Lights On",
    "server": "d0c8b8e.6894848",
    "deviceId": "7",
    "command": "on",
    "commandArgs": "",
    "x": 880,
    "y": 300,
    "wires": [
        [
            "da08aec3.d749a"
        ]
    ]
},
{
    "id": "e4033469.c56598",
    "type": "hubitat command",
    "z": "32054f7b.6f13c",
    "name": "DR Lights Off",
    "server": "d0c8b8e.6894848",
    "deviceId": "7",
    "command": "off",
    "commandArgs": "",
    "x": 880,
    "y": 420,
    "wires": [
        [
            "b0621693.6aa238"
        ]
    ]
},
{
    "id": "9d1eb16.c4c095",
    "type": "hubitat device",
    "z": "32054f7b.6f13c",
    "name": "DR Lights",
    "server": "d0c8b8e.6894848",
    "deviceId": "7",
    "attribute": "switch",
    "sendEvent": false,
    "x": 1240,
    "y": 440,
    "wires": [
        [
            "e12d195c.ce2e9"
        ]
    ]
},
{
    "id": "e12d195c.ce2e9",
    "type": "change",
    "z": "32054f7b.6f13c",
    "name": "DR Lights State",
    "rules": [
        {
            "t": "set",
            "p": "payload",
            "pt": "msg",
            "to": "payload.value",
            "tot": "msg"
        }
    ],
    "action": "",
    "property": "",
    "from": "",
    "to": "",
    "reg": false,
    "x": 1340,
    "y": 500,
    "wires": [
        [
            "81434535.f6326"
        ]
    ]
},
{
    "id": "e64c4e31.36aaf8",
    "type": "time-range-switch",
    "z": "32054f7b.6f13c",
    "name": "",
    "lat": "",
    "lon": "",
    "startTime": "06:00",
    "endTime": "22:00",
    "startOffset": 0,
    "endOffset": 0,
    "x": 300,
    "y": 140,
    "wires": [
        [
            "aec70c57.f1e2d8"
        ],
        []
    ]
},
{
    "id": "afbbd0dd.bb8b38",
    "type": "hubitat device",
    "z": "32054f7b.6f13c",
    "name": "Lux - Back Entrance",
    "server": "d0c8b8e.6894848",
    "deviceId": "1579",
    "attribute": "illuminance",
    "sendEvent": false,
    "x": 320,
    "y": 200,
    "wires": [
        [
            "ec312867.891898"
        ]
    ]
},
{
    "id": "3b7e53e0.d21554",
    "type": "change",
    "z": "32054f7b.6f13c",
    "name": "Lux Blocked?",
    "rules": [
        {
            "t": "set",
            "p": "lux_block",
            "pt": "flow",
            "to": "0",
            "tot": "num"
        }
    ],
    "action": "",
    "property": "",
    "from": "",
    "to": "",
    "reg": false,
    "x": 660,
    "y": 200,
    "wires": [
        [
            "d768f4ca.32357"
        ]
    ]
},
{
    "id": "aec70c57.f1e2d8",
    "type": "switch",
    "z": "32054f7b.6f13c",
    "name": "",
    "property": "payload",
    "propertyType": "msg",
    "rules": [
        {
            "t": "nempty"
        }
    ],
    "checkall": "true",
    "repair": false,
    "outputs": 1,
    "x": 490,
    "y": 140,
    "wires": [
        [
            "aa9f4f85.57da7"
        ]
    ]
},
{
    "id": "aa9f4f85.57da7",
    "type": "change",
    "z": "32054f7b.6f13c",
    "name": "Time Blocked?",
    "rules": [
        {
            "t": "set",
            "p": "time_block",
            "pt": "flow",
            "to": "0",
            "tot": "num"
        }
    ],
    "action": "",
    "property": "",
    "from": "",
    "to": "",
    "reg": false,
    "x": 660,
    "y": 140,
    "wires": [
        [
            "d768f4ca.32357"
        ]
    ]
},
{
    "id": "ec312867.891898",
    "type": "switch",
    "z": "32054f7b.6f13c",
    "name": "",
    "property": "payload.value",
    "propertyType": "msg",
    "rules": [
        {
            "t": "lt",
            "v": "43",
            "vt": "num"
        }
    ],
    "checkall": "true",
    "repair": false,
    "outputs": 1,
    "x": 490,
    "y": 200,
    "wires": [
        [
            "3b7e53e0.d21554"
        ]
    ]
},
{
    "id": "d768f4ca.32357",
    "type": "function",
    "z": "32054f7b.6f13c",
    "name": "Blocked?",
    "func": "var a= flow.get('time_block')\nvar b= flow.get('lux_block')\nmsg.payload = a+b\nreturn msg;",
    "outputs": 1,
    "noerr": 0,
    "x": 860,
    "y": 160,
    "wires": [
        [
            "1c635c36.ad33ec"
        ]
    ]
},
{
    "id": "a10c31d7.2a55a8",
    "type": "switch",
    "z": "32054f7b.6f13c",
    "name": "Active?",
    "property": "payload.value",
    "propertyType": "msg",
    "rules": [
        {
            "t": "eq",
            "v": "active",
            "vt": "str"
        }
    ],
    "checkall": "true",
    "repair": false,
    "outputs": 1,
    "x": 280,
    "y": 40,
    "wires": [
        [
            "e64c4e31.36aaf8",
            "afbbd0dd.bb8b38"
        ]
    ]
},
{
    "id": "1c635c36.ad33ec",
    "type": "switch",
    "z": "32054f7b.6f13c",
    "name": "Blocked =0",
    "property": "payload",
    "propertyType": "msg",
    "rules": [
        {
            "t": "eq",
            "v": "0",
            "vt": "num"
        }
    ],
    "checkall": "true",
    "repair": false,
    "outputs": 1,
    "x": 1010,
    "y": 160,
    "wires": [
        [
            "81b55db6.ac465"
        ]
    ]
},
{
    "id": "4ccc06b2.f00188",
    "type": "comment",
    "z": "32054f7b.6f13c",
    "name": "Check filters",
    "info": "",
    "x": 90,
    "y": 120,
    "wires": []
},
{
    "id": "1578ab31.0d2b6d",
    "type": "comment",
    "z": "32054f7b.6f13c",
    "name": "Control the lights",
    "info": "",
    "x": 100,
    "y": 280,
    "wires": []
},
{
    "id": "d0c8b8e.6894848",
    "type": "hubitat config",
    "z": "",
    "name": "Hubitat",
    "usetls": false,
    "host": "192.168.1.17",
    "port": "80",
    "token": "e5653e7e-56a0-43fc-8e19-96a6d9f22711",
    "appId": "2834",
    "nodeRedServer": "http://192.168.1.10:1882",
    "webhookPath": "/hubitat/webhook"
}]
2 Likes