Looking for: Finite State Machine (FSM) library to manage multiple devices

Hi,

I have multiple devices that can connect via MQTT into my node-red application. Every device has a unique ID (let's name it devID). I need to keep a bunch of state information for every device separately, and the states are the same for all devices. State examples: IDLE, TXING_DATA, RXING_DATA, etc.

I have been using global context to manage those instances, for example:

// [...]
// msg.devID contains the device ID that came from MQTT.

var state;
var devObject;

// get device global state
devObject = global.get(msg.devID);

if (devObject.state)
   state = devObject.state;
else
   state = IDLE; // default state

// do something with device state
// [...]

// save device global state
devObject.state = state;
global.set(msg.devID, devObject);

// [...]

However, it's getting difficult for me to organize my flows and nodes as the application grows. Also, the built-in nodes like Switch and Change don't allow the usage of a variable (msg.devID) within the expressions.

In my search for node-red FSM libraries, I haven't found any that would allow me to use multiple separate instances of the same FSM for every device.

I appreciate any suggestions,
Thank you very much.

By the looks of your code you are storing each value separately. By not store 1 object with all values?

What do you mean by this? Can you provide an example?

Subflows or a Subroutine might help (node-red-contrib-components is effectively works like a subroutine)

By the looks of your code you are storing each value separately. By not store 1 object with all values?

I could store one object to hold all devices' states, something like:

globalObj = {
    dev1: {state: 'IDLE'},
    dev2: {state: 'TXING_DATA'},
    dev3: {state: "RXING_DATA'},
    // ...
};
// or
globalArr = [
    {devID: 14327472, state: 'IDLE'},
    {devID: 48239024, state: 'TXING_DATA'},
    {devID: 74234893, state: 'RXING_DATA'},
    // ...
];

But for me it looks like it does not make any difference.

What do you mean by this? Can you provide an example?

I meant something like this: Given a variable (devID), I would like to get a global object based on that variable. See the following example of something I would like to do, but it is not possible:
image

Subflows or a Subroutine might help (node-red-contrib-components is effectively works like a subroutine)

I am taking a look on node-red-contrib-components. Looks very interesting. Thank you!

image

You can with JSONata (or a function node or the subroutine nodes)...

[{"id":"400bd21a.2b524c","type":"inject","z":"64ce1d00.d049e4","name":"init","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":330,"y":660,"wires":[["faa4487d.4c3398"]]},{"id":"faa4487d.4c3398","type":"change","z":"64ce1d00.d049e4","name":"","rules":[{"t":"set","p":"devices","pt":"global","to":"{\"dev1\":{\"state\":\"IDLE\"},\"dev2\":{\"state\":\"TXING_DATA\"},\"dev3\":{\"state\":\"RXING_DATA\"}}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":590,"y":660,"wires":[[]]},{"id":"fce4a5a3.dd0288","type":"inject","z":"64ce1d00.d049e4","name":"msg.devID = \"dev1\"","props":[{"p":"devID","v":"dev1","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":370,"y":700,"wires":[["489dc74b.95df38"]]},{"id":"489dc74b.95df38","type":"change","z":"64ce1d00.d049e4","name":"$globalContext(\"devices.\" & devID)","rules":[{"t":"set","p":"payload","pt":"msg","to":"$globalContext(\"devices.\" & devID)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":640,"y":700,"wires":[["c0e8ce13.f4abe"]]},{"id":"c0e8ce13.f4abe","type":"debug","z":"64ce1d00.d049e4","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":890,"y":700,"wires":[]},{"id":"10fc7064.cefd1","type":"inject","z":"64ce1d00.d049e4","name":"msg.devID = \"dev2\"","props":[{"p":"devID","v":"dev2","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":370,"y":740,"wires":[["489dc74b.95df38"]]}]
1 Like

This is awesome! Thank you, Steve. I know nothing about JSONata expressions :smiley: