October 24, 2024
Chicago 12, Melborne City, USA
python

How to transition multiple states in a predefined sequence in dependence of the current state using `python-statemachine` events syntax?


Motivation

I would like to simulate a machine using the impressive python-statemachine package. It is the first time I’ve read about the concept of State Machine, so I spend about one day reading the (again) impressive package documentation. I think I have a use-case that the concept and the package is applicable to. I would like to learn how to.

Context

The machine has multiple operating states. For a minimal working example (MWE), I assume three states, namely Off, Standby, On. The machine can do work only in one state, that is On in the MWE. The machine can only transition from Off to On via Standby, which will require some time.
Once the machine is requested to to work (an event), it should transition to the On state regardless of the state it is currently in, do the work, and then transition to back Standby.

Use case minimal working example

I have currently achieved the desired behavior by using a custom method switch_on, which implements the given sequence of states. It is called in the method do_work, which handles the working part of the machine.

from statemachine import StateMachine, State


class Machine(StateMachine):
    """
    A simple machine model with three states: off, standby, and on.
    """
    # Define the states
    off = State(initial=True)
    standby = State()
    on = State()

    # Define events triggering transitions
    off_to_standby = off.to(standby, on="off_to_standby_action")
    standby_to_on = standby.to(on, on="standby_to_on_action")
    on_to_standby = on.to(standby, on="on_to_standby_action")

    def __init__(self, off_to_standby_time, standby_to_on_time, on_to_standby_time):
        # characteristics
        self.off_to_standby_time = off_to_standby_time
        self.standby_to_on_time = standby_to_on_time
        self.on_to_standby_time = on_to_standby_time
        # live variable
        self.time_counter = 0
        self.work_done = 0
        super(Machine, self).__init__()

    # Define state actions. Use decorator syntax to avoid stupid method names like `on_on`.
    @off.enter
    def turn_off(self):
        print("Turning off")

    @standby.enter
    def turn_standby(self):
        print("Turning to standby")

    @on.enter
    def turn_on(self):
        print("Turning on")

    # Define transition actions
    def off_to_standby_action(self):
        print("Transition: Off to standby")
        self.time_counter += self.off_to_standby_time
        return self.time_counter

    def standby_to_on_action(self):
        print("Transition: Standby to on")
        self.time_counter += self.standby_to_on_time
        return self.time_counter

    def on_to_standby_action(self):
        print("Transition: On to standby")
        self.time_counter += self.on_to_standby_time
        return self.time_counter

    # Define custom methods
    def switch_on(self):
        if self.off.is_active:
            self.off_to_standby()
            self.standby_to_on()
        elif self.standby.is_active:
            self.standby_to_on()

    def work_action(self, amount_of_work, time):
        print("Doing work")
        self.work_done += amount_of_work
        self.time_counter += time
        return self.work_done, self.time_counter

    def do_work(self, amount_of_work, time):
        self.switch_on()
        print("Doing work")
        w, t = self.work_action(amount_of_work, time)
        self.on_to_standby()
        return w, t


def main():
    print("Start machine.")
    machine = Machine(1, 2, 3)
    machine.do_work(10, 1)
    machine.do_work(20, 2)
    print("finished work.")
    print("State: ", machine.current_state, ", Time: ", machine.time_counter, ", Work done: ", machine.work_done)


if __name__ == '__main__':
    main()

Question

How can I avoid explicitly enforcing the sequential transition order via if-statements in a custom method, when attempting to execute work_action in the correct state On? In particular, is there a solution to respect the transtition order and execute the custom actions work_action in which I define one or multiple events like switch_on using the syntax with the overloaded OR | operator provided by the package?

Efforts

I tried to think about it a lot while reading the documentation. I also tried interacting with a chatbot. The best solution is the one I came up with in the MWE, which is why I was hoping for a conversation with real human beings.



You need to sign in to view this answers

Leave feedback about this

  • Quality
  • Price
  • Service

PROS

+
Add Field

CONS

+
Add Field
Choose Image
Choose Video