npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

node-red-contrib-dsm

v0.14.1

Published

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

Downloads

341

Readme

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