Help with node-red-contrib-dsm and timeout

I am trying to get my head round node-red-contrib-dsm and in particular a case where I have a simple situation that the machine cycles through states based on incoming signals, but on one of them I want a timeout such that if the next transition does not occur within 15 seconds that it goes to another state. I have looked at the Blink example but am having difficulty seeing the wood for the trees and hope that a simple example will help me. The machine I have so far is

{
  "currentState": "Waiting",
  "states": {
      "Waiting": {
          "StartShutdown": "WaitingShutdown"
      },
      "WaitingShutdown": {
          "Offline": "Offline"
      },
      "Offline": {
          "Online": "Waiting"
    }
  }
}

and I want to add the condition that if it stays in the WaitingShutdown state for 15 seconds without the Offline signal then it goes to the Waiting state.

what does the input (or inputs) look like?

Just the usual topic based signals for the dsm, so the topic is " StartShutdown", "Offline", or "Online" to switch between the states, but if the "Offline" message does not appear while in state WaitingShutdown (which can happen due to other circumstances) then after 15 seconds I want it to transition to the Waiting state.

Is this an academic question in understanding that node or are you trying to accomplish some real world solution? In other words if it was accomplished using a function node does that suffice?

I know how to do it with a function node, this is a simplified real world example which is ideally suited to the finite state machine technique. The Blink example in the dsm wiki shows that the timeout can be done fairly easily as the example has much more complex timer features than I need. I just can't quite grasp the required incantations to get it to work. I am sure it is just a few lines of code in the dsm spec.

Hi, this should do the job:

{
    "currentState": "Waiting",
    "states": {
        "Waiting": {
            "StartShutdown": "WaitingShutdown"
        },
        "WaitingShutdown": {
            "Offline": "Offline",
            "Timeout": "Waiting"
        },
        "Offline": {
            "Online": "Waiting"
        }
    },
    "methods": {
        "StartShutdown": [
            "timeout.id = setTimeout(function() {",
                "resume('Timeout', msg)",
            "},15000);"
        ],
        "status": {
            "fill": "green",
            "shape": "dot",
            "text": {
                "get": "sm.currentState;"
            }
        }
    }
}

Ah right, I see, of course. You just need to start a timer with the same event that switches to the state and get it do the state transition when the timer runs down. If there were any danger of it getting back round to the WaitingShutdown state (via the normal route) before the timer had run down then presumably I should reset the timer on the Offline event.
Many thanks indeed.

Trying to generalise this a bit, as I want to run the timer on every state change, I have tried

 "methods": {
        "onTransition": [
            "if (timeout.id) clearTimeout(timeout.id);",
            "timeout.id = setTimeout(function() {",
                "resume('Timeout', msg)",
                "timeout.id = 0",
            "},5000);"
        ]
}

which works perfectly until I add the line timeout.id = 0 and then I get
[error] [dsm:Presence/Armed] SyntaxError: Unexpected identifier
It seemed a good idea to do that, along with the test at the start when clearing the timeout, in order to make sure timeout.id is a valid timer, but I must be missing something.

missing ;

"resume('Timeout', msg);",

Note: the function is one string! so you have to separate every statement.

Doh, of course, that's what comes from getting used to taking shortcuts.
Thanks.

Is there a way to implement a timeout on the initial state, so for instance something like

{
    "currentState": "Waiting",
    "states": {
        "Waiting": {
            "StartShutdown": "WaitingShutdown",
            "Timeout": "Offline"
        },
...
}

I can't use onTransition or a specific event method to start the timer as there is no transition or event to get to the initial state.
I have a work around using an extra state Initialising which defines a transition to Waiting and use an Inject node firing on startup to kick it into life, but it isn't pretty.

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