appd - Completed redesign of entity manager
This commit is contained in:
parent
301ea0304d
commit
a070dc679f
@ -1,168 +0,0 @@
|
|||||||
import appdaemon.plugins.hass.hassapi as hass
|
|
||||||
|
|
||||||
class Base(hass.Hass):
|
|
||||||
def initialize(self):
|
|
||||||
if(getattr(super(), 'initialize', False)):
|
|
||||||
super().initialize()
|
|
||||||
|
|
||||||
class Timers(Base):
|
|
||||||
def initialize(self):
|
|
||||||
if(getattr(super(), 'initialize', False)):
|
|
||||||
super().initialize()
|
|
||||||
self._timers = {}
|
|
||||||
|
|
||||||
functions = [
|
|
||||||
'run_in',
|
|
||||||
'run_once',
|
|
||||||
'run_at',
|
|
||||||
'run_daily',
|
|
||||||
'run_hourly',
|
|
||||||
'run_minutely',
|
|
||||||
'run_every',
|
|
||||||
'run_at_sunrise',
|
|
||||||
'run_at_sunset',
|
|
||||||
]
|
|
||||||
for f in functions:
|
|
||||||
self._override(f)
|
|
||||||
|
|
||||||
setattr(self, '_cancel_timer', super().cancel_timer)
|
|
||||||
|
|
||||||
def cancel_timer(self, name, *args, **kwargs):
|
|
||||||
if type(name) is str:
|
|
||||||
if name in self._timers:
|
|
||||||
return super().cancel_timer(self._timers[name])
|
|
||||||
else:
|
|
||||||
return super().cancel_timer(*args, **kwargs)
|
|
||||||
|
|
||||||
def _override(self, f):
|
|
||||||
setattr(self, f'_{f}', getattr(self, f))
|
|
||||||
def fn(name, *args, **kwargs):
|
|
||||||
if type(name) is str:
|
|
||||||
if name in self._timers:
|
|
||||||
super().cancel_timer(self._timers[name])
|
|
||||||
self._timers[name] = getattr(self, f'_{f}')(*args, **kwargs)
|
|
||||||
return self._timers[name]
|
|
||||||
else:
|
|
||||||
return getattr(self, f'_{f}')(name, *args, **kwargs)
|
|
||||||
setattr(self, f, fn)
|
|
||||||
|
|
||||||
class Entities(Base):
|
|
||||||
def initialize(self):
|
|
||||||
if(getattr(super(), 'initialize', False)):
|
|
||||||
super().initialize()
|
|
||||||
|
|
||||||
self.e = {}
|
|
||||||
|
|
||||||
def register_entity(self, name, entity, managed=False, default=None, attributes=None):
|
|
||||||
domain, _ = entity.split('.')
|
|
||||||
controller = {
|
|
||||||
'light': Entities.LightEntity,
|
|
||||||
'input_datetime': Entities.InputDateTimeEntity,
|
|
||||||
'input_number': Entities.InputNumberEntity,
|
|
||||||
}.get(domain, Entities.Entity)
|
|
||||||
self.e[name] = controller(self, entity, managed, default, attributes)
|
|
||||||
|
|
||||||
class Entity:
|
|
||||||
def __init__(self, hass, entity, managed = False, default = None, attributes = None):
|
|
||||||
self._entity = entity
|
|
||||||
self._hass = hass
|
|
||||||
self._hass.listen_state(self._listener, entity=entity, attributes='all')
|
|
||||||
self._listeners = []
|
|
||||||
if managed:
|
|
||||||
if default:
|
|
||||||
self.state = default
|
|
||||||
self.update(attributes)
|
|
||||||
|
|
||||||
def listen(self, callback, kwarg=None):
|
|
||||||
""" Listen to changes to entity state """
|
|
||||||
self._listeners.append({
|
|
||||||
'callback': callback,
|
|
||||||
'kwarg': kwarg,
|
|
||||||
})
|
|
||||||
return self._listeners[-1]
|
|
||||||
def unlisten(self, handle):
|
|
||||||
""" Remove state change listener """
|
|
||||||
if handle in self._listeners:
|
|
||||||
self._listeners.remove(handle)
|
|
||||||
def _listener(self, entity, attribute, old, new, kwargs):
|
|
||||||
for l in self._listeners:
|
|
||||||
l['callback'](l['kwarg'])
|
|
||||||
|
|
||||||
def __getattr__(self, key):
|
|
||||||
if key == 'state':
|
|
||||||
if self.get_state:
|
|
||||||
return self.get_state()
|
|
||||||
return self._hass.get_state(self._entity)
|
|
||||||
return self._hass.get_state(self._entity,
|
|
||||||
attribute=key)
|
|
||||||
def __setattr__(self, key, value):
|
|
||||||
if key.startswith('_'):
|
|
||||||
self.__dict__[key] = value
|
|
||||||
return
|
|
||||||
if key == 'state':
|
|
||||||
if self.set_state:
|
|
||||||
self.set_state(value)
|
|
||||||
return self._hass.set_state(self._entity, state=value)
|
|
||||||
attr = self._hass.get_state(self._entity,
|
|
||||||
attribute='all')
|
|
||||||
attr = attr.get('attributes', {}) if attr else {}
|
|
||||||
attr[key] = value
|
|
||||||
self._hass.set_state(self._entity, attributes=attr)
|
|
||||||
def __delattr__(self, key):
|
|
||||||
if key.startswith('_'):
|
|
||||||
del self.__dict__[key]
|
|
||||||
return
|
|
||||||
attr = self._hass.get_state(self._entity,
|
|
||||||
attribute='all').get('attributes', {})
|
|
||||||
attr[key] = ''
|
|
||||||
self._hass.set_state(self._entity, attributes=attr)
|
|
||||||
|
|
||||||
def update(self, new):
|
|
||||||
attr = self._hass.get_state(self._entity, attribute='all').get('attributes', {})
|
|
||||||
attr.update(new)
|
|
||||||
self._hass.set_state(self._entity, attributes=attr)
|
|
||||||
|
|
||||||
class LightEntity(Entities.Entity):
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def set_state(self, state):
|
|
||||||
if state == 'on':
|
|
||||||
self._hass.call_service('light/turn_on', entity_id =
|
|
||||||
self._entity)
|
|
||||||
elif state == 'off':
|
|
||||||
self._hass.call_service('light/turn_off', entity_id =
|
|
||||||
self._entity)
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
|
|
||||||
class InputNumberEntity(Entities.Entity):
|
|
||||||
def __init__(self, hass, entity, managed = False, default = None, attributes = None):
|
|
||||||
super().__init__(hass, entity, managed, default, attributes)
|
|
||||||
if managed:
|
|
||||||
hass.listen_event(self.service_callback, event = 'call_service')
|
|
||||||
|
|
||||||
def service_callback(self, event, data, kwargs):
|
|
||||||
if data['service_data'].get('entity_id', '') == self._entity and data['service'] == 'set_value':
|
|
||||||
self._hass.log("Value changed!")
|
|
||||||
|
|
||||||
|
|
||||||
class InputDateTimeEntity(Entities.Entity):
|
|
||||||
def __init__(self, hass, entity, managed = False, default = None, attributes = None):
|
|
||||||
super().__init__(hass, entity, managed, default, attributes)
|
|
||||||
if managed:
|
|
||||||
hass.listen_event(self.service_callback, event = 'call_service')
|
|
||||||
|
|
||||||
def service_callback(self, event, data, kwargs):
|
|
||||||
if data['service_data'].get('entity_id', '') == self._entity and data['service'] == 'set_datetime':
|
|
||||||
self._hass.log("Datetime changed!")
|
|
||||||
|
|
||||||
def set_state(self, state):
|
|
||||||
time = state.split(':')
|
|
||||||
time += ['00'] * (3 - len(time))
|
|
||||||
self._hass.set_state(self._entity, state=':'.join(time))
|
|
||||||
self.update({
|
|
||||||
'hour': int(time[0], base=10),
|
|
||||||
'minute': int(time[1], base=10),
|
|
||||||
'second': int(time[2], base=10),
|
|
||||||
})
|
|
@ -1,7 +1,3 @@
|
|||||||
global_modules:
|
|
||||||
- base
|
|
||||||
- entities
|
|
||||||
|
|
||||||
hello_world:
|
hello_world:
|
||||||
global_dependencies:
|
global_dependencies:
|
||||||
- base
|
- base
|
||||||
|
6
appdaemon/apps/helpers/base.py
Normal file
6
appdaemon/apps/helpers/base.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import appdaemon.plugins.hass.hassapi as hass
|
||||||
|
|
||||||
|
class Base(hass.Hass):
|
||||||
|
def initialize(self):
|
||||||
|
if(getattr(super(), 'initialize', False)):
|
||||||
|
super().initialize()
|
@ -1,10 +1,10 @@
|
|||||||
import base
|
import base
|
||||||
|
|
||||||
class Entities(base.Base):
|
class Entities(base.Base):
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
if(getattr(super(), 'initialize', False)):
|
if(getattr(super(), 'initialize', False)):
|
||||||
super().initialize()
|
super().initialize()
|
||||||
|
|
||||||
self.e = {}
|
self.e = {}
|
||||||
|
|
||||||
def register_entity(self, name, entity, managed=False, default=None, attributes=None):
|
def register_entity(self, name, entity, managed=False, default=None, attributes=None):
|
||||||
@ -12,10 +12,15 @@ class Entities(base.Base):
|
|||||||
controller = {
|
controller = {
|
||||||
'light': LightEntity,
|
'light': LightEntity,
|
||||||
'switch': SwitchEntity,
|
'switch': SwitchEntity,
|
||||||
|
'input_number': InputNumberEntity,
|
||||||
|
'input_datetime': InputDateTimeEntity,
|
||||||
|
'input_select': InputSelectEntity,
|
||||||
}.get(domain, Entity)
|
}.get(domain, Entity)
|
||||||
self.e[name] = controller(self, entity, managed, default, attributes)
|
self.e[name] = controller(self, entity, managed, default, attributes)
|
||||||
|
|
||||||
|
|
||||||
class Entity:
|
class Entity:
|
||||||
|
|
||||||
def __init__(self, hass, entity, managed=False, state=None, attributes=None):
|
def __init__(self, hass, entity, managed=False, state=None, attributes=None):
|
||||||
self._hass = hass
|
self._hass = hass
|
||||||
self._entity = entity
|
self._entity = entity
|
||||||
@ -33,15 +38,18 @@ class Entity:
|
|||||||
else:
|
else:
|
||||||
self.pull()
|
self.pull()
|
||||||
|
|
||||||
|
# State change listeners
|
||||||
def listen(self, callback, kwarg=None):
|
def listen(self, callback, kwarg=None):
|
||||||
self._listeners.append({
|
self._listeners.append({
|
||||||
'callback': callback,
|
'callback': callback,
|
||||||
'kwarg': kwarg,
|
'kwarg': kwarg,
|
||||||
})
|
})
|
||||||
return self._listeners[-1]
|
return self._listeners[-1]
|
||||||
|
|
||||||
def unlisten(self, handle):
|
def unlisten(self, handle):
|
||||||
if handle in self._listeners:
|
if handle in self._listeners:
|
||||||
self._listeners.remove(handle)
|
self._listeners.remove(handle)
|
||||||
|
|
||||||
def _listener(self, entity, attribute, old, new, kwargs):
|
def _listener(self, entity, attribute, old, new, kwargs):
|
||||||
self._state = new['state']
|
self._state = new['state']
|
||||||
self._attributes = new['attributes']
|
self._attributes = new['attributes']
|
||||||
@ -49,13 +57,13 @@ class Entity:
|
|||||||
if old != new:
|
if old != new:
|
||||||
self._laststate = new
|
self._laststate = new
|
||||||
self._callback(old, new)
|
self._callback(old, new)
|
||||||
|
|
||||||
def _callback(self, old, new):
|
def _callback(self, old, new):
|
||||||
for l in self._listeners:
|
for l in self._listeners:
|
||||||
l['callback'](old, new, l['kwarg'])
|
l['callback'](old, new, l['kwarg'])
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Updating state
|
||||||
|
|
||||||
def pull(self):
|
def pull(self):
|
||||||
d = self._hass.get_state(self._entity, attribute='all')
|
d = self._hass.get_state(self._entity, attribute='all')
|
||||||
self._state = d['state']
|
self._state = d['state']
|
||||||
@ -74,12 +82,15 @@ class Entity:
|
|||||||
def set_state(self, old, new):
|
def set_state(self, old, new):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# If the entity is controller by appd, changes made in the GUI will be communicated via service calls
|
||||||
def _service_listener(self, event, data, kwarg):
|
def _service_listener(self, event, data, kwarg):
|
||||||
if data['service_data'].get('entity_id', '') == self._entity:
|
if data['service_data'].get('entity_id', '') == self._entity:
|
||||||
self.service_callback(data)
|
self.service_callback(data)
|
||||||
|
|
||||||
def service_callback(self, data):
|
def service_callback(self, data):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
#
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
return self._state
|
return self._state
|
||||||
@ -91,17 +102,51 @@ class Entity:
|
|||||||
def attr(self):
|
def attr(self):
|
||||||
return self._attributes
|
return self._attributes
|
||||||
|
|
||||||
|
|
||||||
class LightEntity(Entity):
|
class LightEntity(Entity):
|
||||||
|
|
||||||
def set_state(self, old, new):
|
def set_state(self, old, new):
|
||||||
if new == "on":
|
if new == "on":
|
||||||
self._hass.call_service("light/turn_on", entity_id = self._entity)
|
self._hass.call_service("light/turn_on", entity_id = self._entity)
|
||||||
elif new == "off":
|
elif new == "off":
|
||||||
self._hass.call_service("light/turn_off", entity_id = self._entity)
|
self._hass.call_service("light/turn_off", entity_id = self._entity)
|
||||||
|
|
||||||
|
|
||||||
class SwitchEntity(Entity):
|
class SwitchEntity(Entity):
|
||||||
|
|
||||||
def service_callback(self, data):
|
def service_callback(self, data):
|
||||||
if data['service'] == 'turn_on':
|
if data['service'] == 'turn_on':
|
||||||
self._state = "on"
|
self._state = "on"
|
||||||
if data['service'] == 'turn_off':
|
if data['service'] == 'turn_off':
|
||||||
self._state = "off"
|
self._state = "off"
|
||||||
self.push()
|
self.push()
|
||||||
|
|
||||||
|
|
||||||
|
class InputNumberEntity(Entity):
|
||||||
|
|
||||||
|
def service_callback(self, data):
|
||||||
|
if data['domain'] == 'input_number' and data['service'] == 'set_value':
|
||||||
|
self._state = data['service_data']['value']
|
||||||
|
self.push()
|
||||||
|
|
||||||
|
class InputDateTimeEntity(Entity):
|
||||||
|
|
||||||
|
def set_state(self, old, new):
|
||||||
|
time = new.split(':')
|
||||||
|
time += ["00"] * (3 - len(time))
|
||||||
|
self._state = ':'.join(time)
|
||||||
|
self.attr['hour'] = int(time[0], base=10)
|
||||||
|
self.attr['minute'] = int(time[1], base=10)
|
||||||
|
self.attr['seconf'] = int(time[2], base=10)
|
||||||
|
|
||||||
|
def service_callback(self, data):
|
||||||
|
if data['service'] == 'set_datetime':
|
||||||
|
self._state = data['service_data'].get('time', "00:00:00")
|
||||||
|
self.push()
|
||||||
|
|
||||||
|
class InputSelectEntity(Entity):
|
||||||
|
|
||||||
|
def service_callback(self, data):
|
||||||
|
if data['service'] == 'select_option':
|
||||||
|
self._state = data['service_data'].get('option', None)
|
||||||
|
self.push()
|
4
appdaemon/apps/helpers/helpers.yaml
Normal file
4
appdaemon/apps/helpers/helpers.yaml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
global_modules:
|
||||||
|
- base
|
||||||
|
- entities
|
||||||
|
- timers
|
42
appdaemon/apps/helpers/timers.py
Normal file
42
appdaemon/apps/helpers/timers.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import base
|
||||||
|
|
||||||
|
class Timers(base.Base):
|
||||||
|
def initialize(self):
|
||||||
|
if(getattr(super(), 'initialize', False)):
|
||||||
|
super().initialize()
|
||||||
|
self._timers = {}
|
||||||
|
|
||||||
|
functions = [
|
||||||
|
'run_in',
|
||||||
|
'run_once',
|
||||||
|
'run_at',
|
||||||
|
'run_daily',
|
||||||
|
'run_hourly',
|
||||||
|
'run_minutely',
|
||||||
|
'run_every',
|
||||||
|
'run_at_sunrise',
|
||||||
|
'run_at_sunset',
|
||||||
|
]
|
||||||
|
for f in functions:
|
||||||
|
self._override(f)
|
||||||
|
|
||||||
|
setattr(self, '_cancel_timer', super().cancel_timer)
|
||||||
|
|
||||||
|
def cancel_timer(self, name, *args, **kwargs):
|
||||||
|
if type(name) is str:
|
||||||
|
if name in self._timers:
|
||||||
|
return super().cancel_timer(self._timers[name])
|
||||||
|
else:
|
||||||
|
return super().cancel_timer(*args, **kwargs)
|
||||||
|
|
||||||
|
def _override(self, f):
|
||||||
|
setattr(self, f'_{f}', getattr(self, f))
|
||||||
|
def fn(name, *args, **kwargs):
|
||||||
|
if type(name) is str:
|
||||||
|
if name in self._timers:
|
||||||
|
super().cancel_timer(self._timers[name])
|
||||||
|
self._timers[name] = getattr(self, f'_{f}')(*args, **kwargs)
|
||||||
|
return self._timers[name]
|
||||||
|
else:
|
||||||
|
return getattr(self, f'_{f}')(name, *args, **kwargs)
|
||||||
|
setattr(self, f, fn)
|
@ -1,5 +1,6 @@
|
|||||||
import base
|
import base
|
||||||
class TimeOfDay(base.Entities):
|
import entities
|
||||||
|
class TimeOfDay(entities.Entities):
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
super().initialize()
|
super().initialize()
|
||||||
|
|
||||||
@ -18,5 +19,5 @@ class TimeOfDay(base.Entities):
|
|||||||
self.e['sunrise'].listen(self.input_listener, {'changed': "sunrise"})
|
self.e['sunrise'].listen(self.input_listener, {'changed': "sunrise"})
|
||||||
|
|
||||||
|
|
||||||
def input_listener(self, kwargs):
|
def input_listener(self, old, new, kwargs):
|
||||||
self.log(kwargs)
|
self.log(kwargs)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user