def test_init_1(self): s1 = es.state("start") s2 = es.state("end") t1 = es.transition(s2, "next", condition=lambda: True) s1.add_transition(t1) sm = es.statemachine([s1, s2]) self.assertRaises(RuntimeError, sm.init) # test if no initial state is definied s1.initial = True sm.init() sm.step() self.assertEqual(sm.state, s2) # test if first transition works self.assertRaises(RuntimeError, sm.step) # test if final state works right
def setup(temps, thresh): s_cold = ep_statemachine.state("cold", initial=True) #1 s_heatUp1 = ep_statemachine.state("heatUp1") #2 s_heatUp2 = ep_statemachine.state("heatUp2") #3 s_hot = ep_statemachine.state("hot") #4 s_toHot = ep_statemachine.state("toHot") #5 s_muchToHot = ep_statemachine.state("muchToHot") #6 t_12 = ep_statemachine.transition( s_heatUp1, "t_12", # (T_Oven > T1) & T_Oven > T_TankU + dT1 lambda: (temps("T_Oven") > thresh("T1")) & (temps("T_Oven") > temps("T_TankU") + thresh("T1"))) t_23 = ep_statemachine.transition( s_heatUp2, "t_23", lambda: (temps("T_Oven") < temps("T_TankL") + thresh("dT1") ) # T_Oven < T_TankL + dT1 ) t_32 = ep_statemachine.transition( s_heatUp1, "t_32", lambda: (temps("T_Oven") > temps("T_TankU") + thresh("dT1") ) # T_Oven > T_TankU + dT1 ) t_cold = ep_statemachine.transition( s_cold, "t_cold", lambda: (temps("T_Oven") < thresh("T5")) # T_Oven < T5 ) t_hot = ep_statemachine.transition( s_hot, "t_hot", lambda: (temps("T_TankL") > thresh("T2")) # T_TankL > T2 ) t_42 = ep_statemachine.transition( s_heatUp1, "t_42", # T_TankL < T2 - dT1 & T_Oven > T_TankU + dT1 lambda: (temps("T_TankL") < thresh("T2") - thresh("dT1")) & (temps("T_Oven") > temps("T_TankU") + thresh("dT1"))) t_toHot = ep_statemachine.transition( s_toHot, "t_toHot", lambda: (temps("T_Oven") > thresh("T3") + thresh("dT2")) # T_Oven > T3 + dT2 ) t_54 = ep_statemachine.transition( s_hot, "t_54", lambda: (temps("T_Oven") < thresh("T3") - thresh("dT2")) # T_Oven < T3 - dT2 ) t_56 = ep_statemachine.transition( s_muchToHot, "t_56", lambda: (temps("T_Oven") > thresh("T4") + thresh("dT2")) # T_Oven > T4 + dT2 ) t_65 = ep_statemachine.transition( s_toHot, "t_65", lambda: (temps("T_Oven") < thresh("T4") - thresh("dT2")) # T_Oven < T4 - dT2 ) s_cold.add_transition(t_12) s_cold.add_transition(t_toHot) s_heatUp1.add_transition(t_23) s_heatUp1.add_transition(t_cold) s_heatUp1.add_transition(t_hot) s_heatUp1.add_transition(t_toHot) s_heatUp2.add_transition(t_32) s_heatUp2.add_transition(t_cold) s_heatUp2.add_transition(t_hot) s_heatUp2.add_transition(t_toHot) s_hot.add_transition(t_cold) s_hot.add_transition(t_toHot) s_hot.add_transition(t_42) s_toHot.add_transition(t_54) s_toHot.add_transition(t_56) s_muchToHot.add_transition(t_65) return ep_statemachine.statemachine( [s_cold, s_heatUp1, s_heatUp2, s_hot, s_toHot, s_muchToHot])
def test_coffee_machine(self): i = 0 def inc(): nonlocal i i = i + 1 workflow = [ "press coffee button", "press coffee button", "press espresso button", "press espresso button", "press off button", "press off button", ] s_sleep = es.state("sleep", initial=True, entry_action=inc) s_select_input = es.state("select_input", entry_action=inc) s_make_coffee = es.state("make coffee") s_make_espresso = es.state("make espresso") s_done = es.state("done") s_off = es.state("off") t_wake_up = es.transition( s_select_input, identifier="wake up", condition=lambda: re.match("press (coffee|espresso|off) button", workflow[i]) is not None) s_sleep.add_transition(t_wake_up) t_coffee = es.transition( s_make_coffee, identifier="coffee", condition=lambda: workflow[i] == "press coffee button") s_select_input.add_transition(t_coffee) t_espresso = es.transition( s_make_espresso, identifier="espresso", condition=lambda: workflow[i] == "press espresso button") s_select_input.add_transition(t_espresso) t_finished = es.transition(s_done, identifier="finished", condition=lambda: True) s_make_coffee.add_transition(t_finished) s_make_espresso.add_transition(t_finished) t_back_to_sleep = es.transition(s_sleep, identifier="back to sleep", condition=lambda: True) s_done.add_transition(t_back_to_sleep) t_turn_off = es.transition( s_off, identifier="turn off", condition=lambda: workflow[i] == "press off button") s_select_input.add_transition(t_turn_off) sm = es.statemachine([ s_sleep, s_select_input, s_make_coffee, s_make_espresso, s_done, s_off ]) sm.init() self.assertEqual(sm.state, s_sleep) sm.step() # press any button self.assertEqual(sm.state, s_select_input) sm.step() # press coffee button self.assertEqual(sm.state, s_make_coffee) sm.step() # wait self.assertEqual(sm.state, s_done) sm.step() # drink coffee self.assertEqual(sm.state, s_sleep) sm.step() # press any button self.assertEqual(sm.state, s_select_input) sm.step() # press espresso button self.assertEqual(sm.state, s_make_espresso) sm.step() # wait self.assertEqual(sm.state, s_done) sm.step() # drink espresso self.assertEqual(sm.state, s_sleep) sm.step() # press off button self.assertEqual(sm.state, s_select_input) sm.step() # press off button self.assertEqual(sm.state, s_off) self.assertRaises(RuntimeError, sm.step) # coffee machine is off sm.init() # reinit i = 0 self.assertEqual(sm.state, s_sleep) sm.cycle(0.01) # run all steps at once self.assertEqual(sm.state, s_off)
def test_heater_control(self): i = 0 def inc(): nonlocal i i = i + 1 s_cold = es.state("cold", initial=True, entry_action=inc, during_action=inc) # 1 s_heat_up_1 = es.state("head up 1", entry_action=inc, during_action=inc) # 2 s_heat_up_2 = es.state("head up 2", entry_action=inc, during_action=inc) # 3 s_hot = es.state("hot", entry_action=inc, during_action=inc) # 4 s_to_hot = es.state("to hot", entry_action=inc, during_action=inc) # 5 s_much_to_hot = es.state("much to hot", entry_action=inc, during_action=inc) # 6 s_cool_down = es.state("much to hot", entry_action=inc, during_action=inc) # 7 # test array: # state is state before temperatures are reached test_array = [ { "T_Oven": 40, "T_Tank_Upper": 30, "T_Tank_Lower": 25, "state": s_cold }, { "T_Oven": 50, "T_Tank_Upper": 30, "T_Tank_Lower": 25, "state": s_cold }, { "T_Oven": 60, "T_Tank_Upper": 30, "T_Tank_Lower": 25, "state": s_cold }, { "T_Oven": 70, "T_Tank_Upper": 30, "T_Tank_Lower": 25, "state": s_cold }, { "T_Oven": 70, "T_Tank_Upper": 40, "T_Tank_Lower": 25, "state": s_heat_up_1 }, { "T_Oven": 70, "T_Tank_Upper": 50, "T_Tank_Lower": 30, "state": s_heat_up_1 }, { "T_Oven": 70, "T_Tank_Upper": 50, "T_Tank_Lower": 40, "state": s_heat_up_1 }, { "T_Oven": 60, "T_Tank_Upper": 60, "T_Tank_Lower": 50, "state": s_heat_up_1 }, { "T_Oven": 55, "T_Tank_Upper": 60, "T_Tank_Lower": 50, "state": s_heat_up_1 }, { "T_Oven": 55, "T_Tank_Upper": 60, "T_Tank_Lower": 55, "state": s_heat_up_2 }, { "T_Oven": 60, "T_Tank_Upper": 60, "T_Tank_Lower": 55, "state": s_heat_up_2 }, { "T_Oven": 70, "T_Tank_Upper": 60, "T_Tank_Lower": 55, "state": s_heat_up_2 }, { "T_Oven": 75, "T_Tank_Upper": 60, "T_Tank_Lower": 55, "state": s_heat_up_1 }, { "T_Oven": 85, "T_Tank_Upper": 80, "T_Tank_Lower": 70, "state": s_heat_up_1 }, { "T_Oven": 85, "T_Tank_Upper": 80, "T_Tank_Lower": 70, "state": s_hot }, { "T_Oven": 90, "T_Tank_Upper": 80, "T_Tank_Lower": 70, "state": s_hot }, { "T_Oven": 97, "T_Tank_Upper": 80, "T_Tank_Lower": 70, "state": s_hot }, { "T_Oven": 97, "T_Tank_Upper": 80, "T_Tank_Lower": 70, "state": s_to_hot }, { "T_Oven": 90, "T_Tank_Upper": 80, "T_Tank_Lower": 75, "state": s_to_hot }, { "T_Oven": 90, "T_Tank_Upper": 80, "T_Tank_Lower": 75, "state": s_hot }, { "T_Oven": 97, "T_Tank_Upper": 80, "T_Tank_Lower": 75, "state": s_hot }, { "T_Oven": 97, "T_Tank_Upper": 85, "T_Tank_Lower": 80, "state": s_to_hot }, { "T_Oven": 101, "T_Tank_Upper": 85, "T_Tank_Lower": 80, "state": s_to_hot }, { "T_Oven": 101, "T_Tank_Upper": 85, "T_Tank_Lower": 80, "state": s_much_to_hot }, { "T_Oven": 101, "T_Tank_Upper": 85, "T_Tank_Lower": 80, "state": s_much_to_hot }, { "T_Oven": 97, "T_Tank_Upper": 85, "T_Tank_Lower": 80, "state": s_much_to_hot }, { "T_Oven": 97, "T_Tank_Upper": 85, "T_Tank_Lower": 80, "state": s_to_hot }, { "T_Oven": 90, "T_Tank_Upper": 85, "T_Tank_Lower": 80, "state": s_to_hot }, { "T_Oven": 90, "T_Tank_Upper": 85, "T_Tank_Lower": 80, "state": s_hot }, { "T_Oven": 80, "T_Tank_Upper": 85, "T_Tank_Lower": 80, "state": s_hot }, { "T_Oven": 70, "T_Tank_Upper": 85, "T_Tank_Lower": 80, "state": s_hot }, { "T_Oven": 60, "T_Tank_Upper": 85, "T_Tank_Lower": 80, "state": s_hot }, { "T_Oven": 55, "T_Tank_Upper": 85, "T_Tank_Lower": 80, "state": s_hot }, { "T_Oven": 55, "T_Tank_Upper": 85, "T_Tank_Lower": 80, "state": s_cool_down }, ] t_12 = es.transition( s_heat_up_1, identifier="t_12", condition=lambda: (test_array[i]["T_Oven"] > 65) & (test_array[i]["T_Oven"] > test_array[i]["T_Tank_Lower"])) s_cold.add_transition(t_12) t_23 = es.transition( s_heat_up_2, identifier="t_23", condition=lambda: (test_array[i]["T_Oven"] < 60) | (test_array[i]["T_Tank_Lower"] > test_array[i]["T_Oven"])) s_heat_up_1.add_transition(t_23) t_32 = es.transition( s_heat_up_1, identifier="t_32", condition=lambda: (test_array[i]["T_Oven"] > test_array[i]["T_Tank_Lower"] + 5)) s_heat_up_2.add_transition(t_32) t_24 = t_34 = es.transition(s_hot, identifier="t_x4", condition=lambda: (test_array[i]["T_Oven"] > 80)) s_heat_up_1.add_transition(t_24) s_heat_up_2.add_transition(t_34) t_45 = es.transition(s_to_hot, identifier="t_45", condition=lambda: (test_array[i]["T_Oven"] > 96)) t_54 = es.transition(s_hot, identifier="t_54", condition=lambda: (test_array[i]["T_Oven"] < 94)) s_hot.add_transition(t_45) s_to_hot.add_transition(t_54) t_56 = es.transition(s_much_to_hot, identifier="t_56", condition=lambda: (test_array[i]["T_Oven"] > 100)) t_65 = es.transition(s_to_hot, identifier="t_65", condition=lambda: (test_array[i]["T_Oven"] < 98)) s_to_hot.add_transition(t_56) s_much_to_hot.add_transition(t_65) t_47 = es.transition(s_cool_down, identifier="t_47", condition=lambda: (test_array[i]["T_Oven"] < 60)) s_hot.add_transition(t_47) t_71 = es.transition(s_cold, identifier="t_71", condition=lambda: (test_array[i]["T_Oven"] < 50)) s_cool_down.add_transition(t_71) t_72 = es.transition( s_heat_up_1, identifier="t_72", condition=lambda: (test_array[i]["T_Oven"] > 60) & (test_array[i]["T_Oven"] > test_array[i]["T_Tank_Lower"])) s_cool_down.add_transition(t_72) t_37 = es.transition(s_cool_down, identifier="t_37", condition=lambda: (test_array[i]["T_Oven"] < 60)) s_cool_down.add_transition(t_37) sm = es.statemachine([ s_cold, s_heat_up_1, s_heat_up_2, s_hot, s_to_hot, s_much_to_hot, s_cool_down ]) sm.init() while i < len(test_array): self.assertEqual(sm.state, test_array[i]["state"]) sm.step()
def test_coffee_machine_event(self): s_sleep = es.state("sleep", initial=True) s_select_input = es.state("select_input") s_make_coffee = es.state("make coffee") s_make_espresso = es.state("make espresso") s_done = es.state("done") s_off = es.state("off") e_press_coffee_button = es.event("coffee button pressed") e_press_espresso_button = es.event("espresso button pressed") e_press_off_button = es.event("off button pressed") t_wake_up = es.transition(s_select_input, identifier="wake up", events=[ e_press_coffee_button, e_press_espresso_button, e_press_off_button ]) s_sleep.add_transition(t_wake_up) t_coffee = es.transition(s_make_coffee, identifier="coffee", events=[e_press_coffee_button]) s_select_input.add_transition(t_coffee) t_espresso = es.transition(s_make_espresso, identifier="espresso", events=[e_press_espresso_button]) s_select_input.add_transition(t_espresso) t_finished = es.transition(s_done, identifier="finished", condition=lambda: True) s_make_coffee.add_transition(t_finished) s_make_espresso.add_transition(t_finished) t_back_to_sleep = es.transition(s_sleep, identifier="back to sleep", condition=lambda: True) s_done.add_transition(t_back_to_sleep) t_turn_off = es.transition(s_off, identifier="turn off", events=[e_press_off_button]) s_select_input.add_transition(t_turn_off) sm = es.statemachine([ s_sleep, s_select_input, s_make_coffee, s_make_espresso, s_done, s_off ]) sm.init() self.assertEqual(sm.state, s_sleep) sm.action(e_press_coffee_button) self.assertEqual(sm.state, s_select_input) sm.action(e_press_coffee_button) self.assertEqual(sm.state, s_make_coffee) sm.step() self.assertEqual(sm.state, s_done) sm.step() self.assertEqual(sm.state, s_sleep) sm.action(e_press_coffee_button) self.assertEqual(sm.state, s_select_input) sm.action(e_press_espresso_button) self.assertEqual(sm.state, s_make_espresso) sm.step() self.assertEqual(sm.state, s_done) sm.step() self.assertEqual(sm.state, s_sleep) sm.action(e_press_off_button) self.assertEqual(sm.state, s_select_input) sm.action(e_press_off_button) self.assertEqual(sm.state, s_off)
def setup(temps, thresh): pump_pin = machine.Pin(14, machine.Pin.OUT) warn_led = machine.Pin(17, machine.Pin.OUT) pump_on = lambda: pump_pin.off() pump_off = lambda: pump_pin.on() warn_on = lambda: warn_led.off() warn_off = lambda: warn_led.on() def s_cold_enter(): pump_off() warn_off() def s_heatUp1_enter(): pump_on() warn_off() def s_heatUp2_enter(): pump_off() warn_off() def s_hot_enter(): pump_off() warn_off() def s_toHot_enter(): pump_on() warn_on() def s_muchToHot_enter(): pump_on() warn_on() s_cold = ep_statemachine.state("cold", initial=True, entry_action=s_cold_enter) #1 s_heatUp1 = ep_statemachine.state("heatUp1", entry_action=s_heatUp1_enter) #2 s_heatUp2 = ep_statemachine.state("heatUp2", entry_action=s_heatUp2_enter) #3 s_hot = ep_statemachine.state("hot", entry_action=s_hot_enter) #4 s_toHot = ep_statemachine.state("toHot", entry_action=s_toHot_enter) #5 s_muchToHot = ep_statemachine.state("muchToHot", entry_action=s_muchToHot_enter) #6 t_12 = ep_statemachine.transition( s_heatUp1, "t_12", # (T_Oven > T1) & T_Oven > T_TankU + dT1 lambda: (temps("T_Oven") > thresh("T1")) & (temps("T_Oven") > temps("T_TankU") + thresh("T1"))) t_23 = ep_statemachine.transition( s_heatUp2, "t_23", lambda: (temps("T_Oven") < temps("T_TankL") + thresh("dT1") ) # T_Oven < T_TankL + dT1 ) t_32 = ep_statemachine.transition( s_heatUp1, "t_32", lambda: (temps("T_Oven") > temps("T_TankU") + thresh("dT1") ) # T_Oven > T_TankU + dT1 ) t_cold = ep_statemachine.transition( s_cold, "t_cold", lambda: (temps("T_Oven") < thresh("T5")) # T_Oven < T5 ) t_hot = ep_statemachine.transition( s_hot, "t_hot", lambda: (temps("T_TankL") > thresh("T2")) # T_TankL > T2 ) t_42 = ep_statemachine.transition( s_heatUp1, "t_42", # T_TankL < T2 - dT1 & T_Oven > T_TankU + dT1 lambda: (temps("T_TankL") < thresh("T2") - thresh("dT1")) & (temps("T_Oven") > temps("T_TankU") + thresh("dT1"))) t_toHot = ep_statemachine.transition( s_toHot, "t_toHot", lambda: (temps("T_Oven") > thresh("T3") + thresh("dT2")) # T_Oven > T3 + dT2 ) t_54 = ep_statemachine.transition( s_hot, "t_54", lambda: (temps("T_Oven") < thresh("T3") - thresh("dT2")) # T_Oven < T3 - dT2 ) t_56 = ep_statemachine.transition( s_muchToHot, "t_56", lambda: (temps("T_Oven") > thresh("T4") + thresh("dT2")) # T_Oven > T4 + dT2 ) t_65 = ep_statemachine.transition( s_toHot, "t_65", lambda: (temps("T_Oven") < thresh("T4") - thresh("dT2")) # T_Oven < T4 - dT2 ) s_cold.add_transition(t_12) s_cold.add_transition(t_toHot) s_heatUp1.add_transition(t_23) s_heatUp1.add_transition(t_cold) s_heatUp1.add_transition(t_hot) s_heatUp1.add_transition(t_toHot) s_heatUp2.add_transition(t_32) s_heatUp2.add_transition(t_cold) s_heatUp2.add_transition(t_hot) s_heatUp2.add_transition(t_toHot) s_hot.add_transition(t_cold) s_hot.add_transition(t_toHot) s_hot.add_transition(t_42) s_toHot.add_transition(t_54) s_toHot.add_transition(t_56) s_muchToHot.add_transition(t_65) return ep_statemachine.statemachine( [s_cold, s_heatUp1, s_heatUp2, s_hot, s_toHot, s_muchToHot]), lambda: 1 - pump_pin.value()