Another dsm question - same trigger different transitions

Looking for advice on the best way to accomplish something in node-red-contrib-dsm.
I have a situation where the same trigger input causes different transitions dependent on current state, which is not in itself a problem. The issue is that as well as causing different transitions I wish other aspects of the transition to be different. For example I have attached a simple flow where the trigger causes the state machine to step through states 1, 2, 3 and then back to 1. I wish to suppress the output except when going from state 3 to state 1. I have accomplished this by testing sm.currentState in the trigger method and this does work, but it is not in keeping with the philosophy of a state machine so I suspect there may be a better way. This is a very much simplified example of what I am actually trying to achieve of course.
On a side issue it is a little confusing that in the transition method sm.currentState is already on the new state, but that is a different issue.

[{"id":"a60e15e3.e62a18","type":"dsm","z":"5dfa5b0c.04132c","name":"dsm test","sm_config":"{\n    \"currentState\": \"state1\",\n    \"states\": {\n        \"state1\": {\n            \"trigger\": \"state2\"\n        },\n        \"state2\": {\n            \"trigger\": \"state3\"\n        },\n        \"state3\": {\n            \"trigger\": \"state1\"\n        }\n    },\n    \"methods\": {\n        \"trigger\": [\n            \"if (sm.currentState != 'state1')\",\n              \"output = false;\"\n        ]\n    }\n}","x":269,"y":759,"wires":[["2ffcc5d4.eced12"]]},{"id":"8b45332e.85d5e8","type":"inject","z":"5dfa5b0c.04132c","name":"trigger","topic":"trigger","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":107.5,"y":759,"wires":[["a60e15e3.e62a18"]]},{"id":"2ffcc5d4.eced12","type":"debug","z":"5dfa5b0c.04132c","name":"","active":true,"console":"false","complete":"true","x":423,"y":759,"wires":[]}]

The current version doesn't support state-methods.

Here is a workaround:

  1. the state will change before the transition method is executed. So if you want to test the actualState before the transition, you could use the onBeforeTransition method and save true/false in a sm variable (sm.out)
  2. in the trigger method use sm.out to set the output.
{
    "currentState": "state1",
    "states": {
        "state1": {
            "trigger": "state2"
        },
        "state2": {
            "trigger": "state3"
        },
        "state3": {
            "trigger": "state1"
        }
    },
    "methods": {
        "onBeforeTransition": [
            "sm.out = sm.currentState === 'state3' ? true : false;"
        ],
        "trigger": [
            "output = sm.out;",
            "/* your method code */;"
        ]
    }
}

OK, thanks. It isn't actually an issue testing the new state as (in this case anyway) that is sufficient to decide what to do. It was more the fact that it just didn't seem right to be running code based on the state. Nothing is perfect of course.

On a different subject, have you considered allowing multiple outputs. I seem to end up with a switch on the output in order to determine where to send the message and multiple outputs would save that.
output = 2
for example.

Multiple outputs is on my todo list but with a low priority.

I agree, it would avoid an additional node but In this case adding a switch node to the output is quite easy to do.

:slight_smile:

:frowning:

Though it is not a major issue I agree.

With the new version 0.13.0 you can now use preState:

{
    "stateOutput": "current",
    "preStateOutput": "previous",
    "currentState": "state1",
    "states": {
        "state1": {
            "trigger": "state2"
        },
        "state2": {
            "trigger": "state3"
        },
        "state3": {
            "trigger": "state1"
        }
    },
    "methods": {
        "trigger": [
            "output = sm.preState === 'state3' ? true : false;"
        ]
    }
}
1 Like

OK, thanks