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

**URL:** <https://discourse.nodered.org/t/looking-for-finite-state-machine-fsm-library-to-manage-multiple-devices/37940>\
**Category:** General\
**Created:** [23 December 2020 18:25 UTC](https://discourse.nodered.org/t/looking-for-finite-state-machine-fsm-library-to-manage-multiple-devices/37940 "2020-12-23T18:25:12Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![RGNagel](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/rgnagel/32/33495_2.png) [@RGNagel](https://discourse.nodered.org/u/RGNagel)\
**Post date:** [23 December 2020 18:25 UTC](https://discourse.nodered.org/t/looking-for-finite-state-machine-fsm-library-to-manage-multiple-devices/37940/1 "2020-12-23T18:25:12Z")

</div>

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:

```auto
// [...]
// 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.

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [23 December 2020 18:42 UTC](https://discourse.nodered.org/t/looking-for-finite-state-machine-fsm-library-to-manage-multiple-devices/37940/2 "2020-12-23T18:42:08Z")

</div>

> [@RGNagel](#):
>
> I need to keep a bunch of state information for every device separately

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

> [@RGNagel](#):
>
> Also, the built-in nodes like Switch and Change don't allow the usage of a variable (msg.devID) within the expressions

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

> [@RGNagel](#):
>
> I appreciate any suggestions

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

---

<div class="post-metadata">

**Author:** ![RGNagel](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/rgnagel/32/33495_2.png) [@RGNagel](https://discourse.nodered.org/u/RGNagel)\
**Post date:** [23 December 2020 19:11 UTC](https://discourse.nodered.org/t/looking-for-finite-state-machine-fsm-library-to-manage-multiple-devices/37940/4 "2020-12-23T19:11:43Z")

</div>

> 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:

```auto
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](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/6/b/6b8dddd56ec1ec7620bd25c65f0224cd6385605c.png)

> 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!

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [23 December 2020 20:14 UTC](https://discourse.nodered.org/t/looking-for-finite-state-machine-fsm-library-to-manage-multiple-devices/37940/5 "2020-12-23T20:14:28Z")

</div>

> [@RGNagel](#):
>
> I meant something like this: Given a variable ( `devID` ), I would like to get a global object based on that variable.

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/c/7/c792eafca8f90e70b11e2e4e5eed8e987390a6ea.png)

You can with JSONata (or a function node or the subroutine nodes)...  
 ![1Ck0hX9qBi](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/f/c/fcf27a81d21f7058e2fe8e87b7eb0995256de5e6.gif)

```auto
[{"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"]]}]

```

---

<div class="post-metadata">

**Author:** ![RGNagel](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/rgnagel/32/33495_2.png) [@RGNagel](https://discourse.nodered.org/u/RGNagel)\
**Post date:** [23 December 2020 21:33 UTC](https://discourse.nodered.org/t/looking-for-finite-state-machine-fsm-library-to-manage-multiple-devices/37940/6 "2020-12-23T21:33:39Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)\
**Post date:** [21 February 2021 21:33 UTC](https://discourse.nodered.org/t/looking-for-finite-state-machine-fsm-library-to-manage-multiple-devices/37940/7 "2021-02-21T21:33:50Z")

</div>

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.
