node-red-contrib-dsm

    0.14.1 • Public • Published

    node-red-contrib-dsm

    A dynamic state machine node based on the Finite state machine model.

    The dsm node is a pure Node.js package for Node Red, it doesn't use any external libraries. The dsm behaviour is defined in a JSON format and can be optianally set/modified programmatically e.g. using an inject node.

    Principle of operation [Wikipedia]

    A finite-state machine (FSM) is an abstract machine that can be in exactly one of a finite number of states at any given time. The FSM can change from one state to another in response to some external inputs; the change from one state to another is called a transition. A FSM is defined by a list of its states, its initial state, and the conditions for each transition.

    Usage

    The dsm properties can be defined in the edit dsm node window or by an input JSON object:

    dsmconf

    JSON object:

    topic: "set"
    payload:
    {
        "triggerInput": "topic",
        "stateOutput": "current",
        "preStateOutput": "previous",
        "globalOutput": "my_global_var",
        "flowOutput": "my_flow_var",
        "preState": null,
        "currentState": "state1",
        "states": {
            "state1": {
                "transition2": "state2"
            },
            "state2": {
                "transition1": "state1",
                "transition3": "state3"
            },
            "state3": {
                "transition1": "state1",
                "transition2": "state2"
            }
        }
    }
    

    triggerInput, stateOutput, preStateOutput, globalOutput and flowOutput can be omitted.

    triggerInput and stateOutput default topic.

    preStateOutput default preState

    globalOutput and flowOutput default false.

    If globalOutput or flowlOutput is defined, the corresponding variable is additionally set.

    When the node receives a trigger with a transition it will change from one state to another:

    topic: "transition"
    payload: any
    

    Data and methods

    In addition to states and transitions a dsm can also contain arbitrary data and methods.

    Example:

    {
        "stateOutput": "payload",
        "currentState": "one_state",
        "states": {
            "recursive": "one_state"
        },
        "data": {
            "delay": 2000
        },
        "methods": {
            "setDelay": "sm.data.delay = msg.payload;",
            "getDelay": "msg.delay = sm.data.delay;",
            "default": "msg.payload = 'method undefined'"
        }
    }
    

    Methods can be any valid javascript statements. If the method name is the same as the transition name, both the transition and the method are processed.

    The method default is executed when no method is found in the methods list.

    To simplify editing methods can be defined as an array of comma separated strings:

    "onTransition" : [
        "if (sm.data.indoor > sm.data.outdoor) {",
            "msg.payload = 'indoor > outdoor';",
        "} else if (sm.data.indoor < sm.data.outdoor) {",
            "msg.payload = 'indoor < outdoor';",
        "} else {",
            "msg.payload = 'indoor = outdoor';",
        "}"
    ]
    

    General purpose methods

    • init
    • onBeforeTransition
    • onTransition
    • onAfterTransition
    • status defines an arbitrary status

    The general purpose methods are executed independently even without states. The init method is executed when the dsm is deployed respectively when the dsm is set. init can be used to initialize values.

    Example:

    }
        "methods": {
            "onTransition": "msg.payload = {'sid': global.get('xiaomi_name')[msg.payload]};",
            "status": {
                "fill": "green",
                "shape": "ring",
                "text": {
                    "get": "JSON.stringify(msg.payload)"
                }
            }
        }
    }
    

    Build-in methods

    To simplify the configuration build-in methods are available.

    • setData
    • getData
    • timer
    • resetTimer
    • watchdog

    Configuration Examples

    setData and getData

    {
        "data": {
            "temperature": 0,
            "humidity": 0,
            "pressure": 0,
            "co2": 0
        },
        "methods": {
            "temperature": {
                "name": "setData"
            },
            "humidity": {
                "name": "setData"
            },
            "pressure": {
                "name": "setData"
            },
            "co2": {
                "name": "setData"
            },
            "getData": {
                "name": "getData"
            }
        }
    }
    

    timer and watchdog

    {
        "data": {
            "delay1": 2000,
            "delay2": 3000
        },
        "methods": {
            "timer1": {
                "name": "timer",
                "param": "delay1"
            },
            "timer2": {
                "name": "timer",
                "param": "delay2",
                "do": "node.status({});"
            },
            "timer3": {
                "name": "timer",
                "param": 5000,
                "send": "toilet window timeout"
            },
            "resetTimer3": {
                "name": "resetTimer",
                "param": "timer3"
            },
            "watchdog1": {
                "name": "watchdog",
                "param": 5000,
                "send": {
                    "get": "msg.payload.name+' timeout';"
                }
            }
        }
    }
    

    timerand watchdog param in milliseconds.

    do executes a statement.

    send sets msg.payload - either to a string or when using get to the result of a statement - and send the msg.

    Examples

    Door

    door-7 2

    Configuration

    {
        "currentState": "closed",
        "states": {
            "opened": {
                "close": "closed",
                "stop": "stopped"
            },
            "closed": {
                "open": "opened",
                "stop": "stopped"
            },
            "stopped": {
                "open": "opened",
                "close": "closed"
            }
        }
    }
    

    Flow

    [{"id":"8b02669f.7ddd98","type":"debug","z":"57ef434a.058a6c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":430,"y":1680,"wires":[]},{"id":"68c0e2d5.3b798c","type":"inject","z":"57ef434a.058a6c","name":"open","topic":"open","payload":"your open payload","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":1640,"wires":[["3b0c292.2da33d6"]]},{"id":"fae17b11.e48a88","type":"inject","z":"57ef434a.058a6c","name":"close","topic":"close","payload":"your close payload","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":1680,"wires":[["3b0c292.2da33d6"]]},{"id":"3b0c292.2da33d6","type":"dsm","z":"57ef434a.058a6c","name":"door","sm_config":"{\n    \"currentState\": \"closed\",\n    \"states\": {\n        \"opened\": {\n            \"close\": \"closed\",\n            \"stop\": \"stopped\"\n        },\n        \"closed\": {\n            \"open\": \"opened\",\n            \"stop\": \"stopped\"\n        },\n        \"stopped\": {\n            \"open\": \"opened\",\n            \"close\": \"closed\"\n        }\n    }\n}","x":260,"y":1680,"wires":[["8b02669f.7ddd98"]]},{"id":"caac460e.2942c8","type":"inject","z":"57ef434a.058a6c","name":"stop","topic":"stop","payload":"your stop payload","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":1720,"wires":[["3b0c292.2da33d6"]]}]
    

    Garage door

    garade_door-7 2

    Configuration

    {
        "stateOutput": "payload",
        "currentState": "closed",
        "states": {
            "opened": {
                "click": "closing"
            },
            "closed": {
                "click": "opening"
            },
            "opening": {
                "limit_switch": "opened",
                "click": "opening_stopped"
            },
            "closing": {
                "limit_switch": "closed",
                "click": "closing_stopped"
            },
            "opening_stopped": {
                "click": "closing"
            },
            "closing_stopped": {
                "click": "opening"
            }
        }
    }
    

    Flow

    [{"id":"1501e603.fdbeba","type":"dsm","z":"57ef434a.058a6c","name":"garage door","sm_config":"{\n    \"stateOutput\": \"payload\",\n    \"globalOutput\": \"garage_door_state\",\n    \"currentState\": \"closed\",\n    \"states\": {\n        \"opened\": {\n            \"click\": \"closing\"\n        },\n        \"closed\": {\n            \"click\": \"opening\"\n        },\n        \"opening\": {\n            \"limit_switch\": \"opened\",\n            \"click\": \"opening_stopped\"\n        },\n        \"closing\": {\n            \"limit_switch\": \"closed\",\n            \"click\": \"closing_stopped\"\n        },\n        \"opening_stopped\": {\n            \"click\": \"closing\"\n        },\n        \"closing_stopped\": {\n            \"click\": \"opening\"\n        }\n    }\n}","x":260,"y":1240,"wires":[["2125cea7.329542"]]},{"id":"4744a8a3.28aec8","type":"inject","z":"57ef434a.058a6c","name":"click","topic":"click","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":90,"y":1240,"wires":[["1501e603.fdbeba"]]},{"id":"379cd28e.34076e","type":"link in","z":"57ef434a.058a6c","name":"to timer","links":["4c183a20.342304"],"x":115,"y":1280,"wires":[["1501e603.fdbeba"]]},{"id":"4c183a20.342304","type":"link out","z":"57ef434a.058a6c","name":"from dsm","links":["379cd28e.34076e"],"x":535,"y":1340,"wires":[]},{"id":"5a467385.1c0bcc","type":"comment","z":"57ef434a.058a6c","name":"motor simulation","info":"","x":440,"y":1200,"wires":[]},{"id":"2125cea7.329542","type":"change","z":"57ef434a.058a6c","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload = \"opening\" or payload = \"closing\" ? payload : \"reset\"","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":440,"y":1240,"wires":[["23d5eb3e.3f4fa4"]]},{"id":"23d5eb3e.3f4fa4","type":"trigger","z":"57ef434a.058a6c","op1":"","op2":"limit_switch","op1type":"nul","op2type":"str","duration":"3","extend":false,"units":"s","reset":"reset","bytopic":"topic","name":"","x":320,"y":1340,"wires":[["77a5a197.e301e"]]},{"id":"77a5a197.e301e","type":"change","z":"57ef434a.058a6c","name":"topic","rules":[{"t":"set","p":"topic","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":450,"y":1340,"wires":[["4c183a20.342304"]]}]
    

    For more examples have a look at the Wiki

    Install

    npm i node-red-contrib-dsm

    DownloadsWeekly Downloads

    1,923

    Version

    0.14.1

    License

    Apache-2.0

    Unpacked Size

    41.8 kB

    Total Files

    7

    Last publish

    Collaborators

    • cflurin