def test_state_machine(): idle = State('idle') active = State('active') d1cl = Event('D1CL', 'Door 1 closed') idle.add_transition(d1cl, active) sm = StateMachine(idle) assert sm.start == sm.current_state == idle assert sm.all_states() == set([idle, active]) sm.handle('D1CL') assert sm.current_state == active
def __init__(self): super(SimulatedBearings, self).__init__() self._csm = StateMachine({ 'initial': 'resting', 'transitions': { ('resting', 'levitating'): lambda: self._levitate, ('levitating', 'levitated'): self.levitationComplete, ('levitated', 'delevitating'): lambda: not self._levitate, ('delevitating', 'resting'): self.delevitationComplete, } }) self._levitate = False
def add_state(self, state_name): s = State(state_name) if not self.states: self.states = [s] self.state_machine = StateMachine(s) else: self.states.append(s)
def state_machine(request): idle = State('Idle') a = State('A') b = State('B') idle.add_transition(Event('EVT1', 'Primer evento'), a) a.add_transition(Event('EVT2', 'Segundo evento'), b) sm = StateMachine(idle) return sm
class SimulatedBearings(CanProcess, MagneticBearings): def __init__(self): super(SimulatedBearings, self).__init__() self._csm = StateMachine({ 'initial': 'resting', 'transitions': { ('resting', 'levitating'): lambda: self._levitate, ('levitating', 'levitated'): self.levitationComplete, ('levitated', 'delevitating'): lambda: not self._levitate, ('delevitating', 'resting'): self.delevitationComplete, } }) self._levitate = False def engage(self): self.levitate() def disengage(self): self.delevitate() def levitate(self): self._levitate = True def delevitate(self): self._levitate = False def levitationComplete(self): return True def delevitationComplete(self): return True def doProcess(self, dt): self._csm.process(dt) @property def ready(self): return self._csm.state == 'levitated' and self._levitate @property def idle(self): return self._csm.state == 'resting' and not self._levitate
def __init__(self, override_states=None, override_transitions=None, override_initial_state=None, override_initial_data=None): """ This class is intended to be sub-classed to implement devices using a finite state machine internally. Implementing such a device is straightforward, there are three methods that *must* be overriden: `_get_state_handlers` `_get_initial_state` `_get_transition_handlers` The first method is supposed to return a dictionary with state handlers for each state of the state machine, the second method must return the name of the initial state. The third method must return a dict-like object (often an OrderedDict from collections) that defines the conditions for transitions between the states of the state machine. They are implemented as methods and not as plain class member variables, because often they use the `self`-variable, which does not exist at the class level. From these three methods, a `StateMachine`-instance is constructed, it's available as the device's `_csm`-member. CSM is short for "cycle-based state machine". Most device implementation will also want to override this method: `_initialize_data` This method should initialise device state variables (such as temperature, speed, etc.). Having this in a separate method from `__init__` has the advantage that it can be used to reset those variables at a later stage, without having to write the same code again. Following this scheme, inheriting from `StateMachineDevice` also provides the possibility for users of the class to override the states, the transitions, the initial state and even the data. For states, transitions and data, dicts need to be passed to the constructor, for the initial state that should be a string. All these overrides can be used to define device setups to describe certain scenarios more easily. :param override_states: Dict with one entry per state. Only states defined in the state machine are allowed. :param override_transitions: Dict with (state, state) tuples as keys and callables as values. :param override_initial_state: The initial state. :param override_initial_data: A dict that contains data members that should be overwritten on construction. """ super(StateMachineDevice, self).__init__() self._initialize_data() self._override_data(override_initial_data) state_handlers = self._get_final_state_handlers(override_states) initial = self._get_initial_state( ) if override_initial_state is None else override_initial_state if not initial in state_handlers: raise RuntimeError( 'Initial state \'{}\' is not a valid state.'.format(initial)) self._csm = StateMachine( { 'initial': initial, 'states': state_handlers, 'transitions': self._get_final_transition_handlers(override_transitions) }, context=self) self.add_processor(self._csm)
key2 = State('k2', 'keyboard key 2 pressed') # Events door_closed = Event('D1CL', 'Door closed') key_one_pressed = Event('KEY1', 'Key 1 pressed') key_two_pressed = Event('KEY2', 'Key 2 pressed') open_batcave = Event('OPEN', 'Open batcave') # Transitions idle.add_transition(door_closed, active) active.add_transition(key_one_pressed, key1) key1.add_transition(key_two_pressed, key2) key2.add_action(open_batcave) key2.add_transition(open_batcave, idle) sm = StateMachine(idle) print('All states:', ', '.join([_.name for _ in sm.all_states()])) bus = NetworkBus() bus.subscribe(sm) bus.send('D1CL') bus.send('KEY1') bus.send('KEY2')
def state_machine(self): return StateMachine(self.initial_state)