If you enjoy state machines I would encourage you to also have a look at this contribution:
1 Like
This is great work!
This could handle a lot of things I’m doing now in a different way. And probably better.
Question, as I try to wrap my head around it… your example code shows a third state for “Alarm disarmed” with an enter_programs of “self.siren_on”. That shoudl be “self.siren_off”, right? Assuming I don’t want the siren going off when the alarm is disarmed.
Thank you. I want to give credit to PeWu as well as his code was my inspiration.
The example code is written without testing it. Yes, you are correct, siren should be off in this state
(git hub documentation is now corrected)
1 Like
In an attempt to solve the same problem, I wrote something simple like this, does not have too many bells and whistles, but works very efficiently.
import appdaemon.plugins.hass.hassapi as hass
class StateListener(hass.Hass):
def initialize(self):
self.state_sensor = self.args.get("stateSensor")
self.state_listen_handle = self.listen_state(self.state_change, self.state_sensor)
self.notifier = self.get_app("notifier")
self.state_update()
def get_state_obj(self, state):
for cls in State.__subclasses__():
if cls.check(state):
return cls(self)
def state_change(self, entity, attribute, old, new, kwargs):
if old == new:
return
newState = self.get_state_obj(new)
oldState = self.get_state_obj(old)
self.log("Transition: {}-{}".format(old,new))
self.run_in(newState.enter, 5)
self.run_once(oldState.exit, self.time(), new=new)
self.state_update()
def state_update(self):
self.current_state = self.get_state(self.state_sensor)
self.current_state_obj = self.get_state_obj(state=self.current_state)
self.notifier.notify_join("hass=:=state=:={}".format(self.current_state))
class State():
name = 'State'
allowed = []
def __init__(self, hass):
self.hass = hass
self.timer_list = {}
def initialize(self):
pass
def on_enter(self):
pass
def on_exit(self):
pass
@classmethod
def check(self, state):
return state == self.name
class Home(State):
name = "Home"
allowed = ['NearHome']
def enter(self, kwargs):
self.check_timer()
self.turn_on_bedroom_lights()
def exit(self, kwargs):
self.timer_list["turn_off_bedroom"] = self.hass.run_in(self.turn_off_bedroom,5*60)
def turn_off_bedroom(self, kwargs):
self.hass.turn_off("group.all_lights")
self.hass.turn_off("switch.fan")
def turn_on_bedroom_lights(self):
self.hass.log(self.hass.time())
if self.hass.now_is_between("sunset-00:40:00","21:00:00"):
self.hass.turn_on("light.main_light")
if self.hass.now_is_between("21:00:00","sunrise-00:30:00"):
self.hass.turn_on("light.table_lamp")
def check_timer(self):
if "turn_off_bedroom" in self.timer_list:
self.hass.log("Cancelling bedroom timer")
self.hass.cancel_timer(self.timer_list["turn_off_bedroom"])
class NearHome(State):
name = "NearHome"
allowed = ['Home', 'Outside', 'Car']
def enter(self, kwargs):
pass
def exit(self, kwargs):
pass
class Outside(State):
name = "Outside"
allowed = ['NearHome', 'Car', 'Work']
def enter(self,kwargs):
pass
def exit(self,kwargs):
pass
class Work(State):
name = "Work"
allowed = ['Car', 'Outside']
def enter(self,kwargs):
pass
def exit(self,kwargs):
pass
class Car(State):
name = "Car"
allowed = ['NearHome', 'Outside', 'Work']
def enter(self,kwargs):
pass
def exit(self,kwargs):
pass