[Python] How to transition multiple states in a predefined sequence in dependence of the...

Discussão em 'Python' iniciado por Stack, Outubro 24, 2024.

  1. Stack

    Stack Membro Participativo

    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()
    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()

    Output


    When I run the code I get the following output.

    Start machine.
    Turning off
    Transition: Off to standby
    Turning to standby
    Transition: Standby to on
    Turning on
    Doing work
    Transition: On to standby
    Turning to standby
    Transition: Standby to on
    Turning on
    Doing work
    Transition: On to standby
    Turning to standby
    finished work.
    State: Standby , Time: 14 , Work done: 30


    This is the expected behavior. time_counter: 1+2+1+3+2+2+3=14 work_done: 10+20=30

    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.

    Continue reading...

Compartilhe esta Página