Skip to content
Snippets Groups Projects
Commit 91ab1a60 authored by jkerdreu's avatar jkerdreu
Browse files

- Major rework on startup, no more waiting to xAAL monitor to boot

- Fix HASS native units
- Fix bug that cause HASS to hang in monitor_event with a newly created entity
- Added filtering

git-svn-id: https://redmine.imt-atlantique.fr/svn/xaal/code/Python/branches/0.7@2985 b32b6428-25c9-4566-ad07-03861ab6144f
parent 3d88d282
Branches
No related tags found
No related merge requests found
......@@ -17,8 +17,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
bridge = Bridge(hass)
hass.data.setdefault(DOMAIN, {})[entry.entry_id] = bridge
await bridge.wait_is_ready()
_LOGGER.debug("xAAL Bridge READY")
#await bridge.wait_is_ready()
# _LOGGER.debug("xAAL Bridge READY")
hass.config_entries.async_setup_platforms(entry, PLATFORMS)
return True
......
......@@ -6,12 +6,12 @@ from homeassistant.components.binary_sensor import BinarySensorEntity, BinarySen
from homeassistant.const import STATE_ON, STATE_OFF
from .const import DOMAIN
from .core import XAALEntity, EntryHandler
from .core import XAALEntity, EntityFactory
_LOGGER = logging.getLogger(__name__)
class Handler(EntryHandler):
class Factory(EntityFactory):
def new_entity(self, device):
entity = None
......@@ -36,9 +36,10 @@ class Handler(EntryHandler):
async def async_setup_entry(hass, config_entry, async_add_entities):
bridge = hass.data[DOMAIN][config_entry.entry_id]
handler = Handler(bridge, async_add_entities)
factory = Factory(bridge, async_add_entities)
for dev in bridge._mon.devices:
handler.new_entity(dev)
if dev.is_ready():
factory.new_entity(dev)
class Motion(XAALEntity, BinarySensorEntity):
......
......@@ -11,24 +11,15 @@ _LOGGER = logging.getLogger(__name__)
#DB_SERVER = tools.get_uuid('d28fbc27-190f-4ee5-815a-fe05233400a2')
DB_SERVER = tools.get_uuid('9064ccbc-84ea-11e8-80cc-82ed25e6aaaa')
# DB_SERVER = tools.get_uuid('d28fbc27-190f-4ee5-815a-fe05233400a2')
UNSUPPORTED_TYPES = ['cli','hmi','windgauge','barometer','co2meter','soundmeter']
def filter_msg(msg):
if msg.source == DB_SERVER:
return True
if msg.dev_type.startswith('lamp.'):
return True
if msg.dev_type.startswith('powerrelay.'):
return True
if msg.dev_type.startswith('thermometer.'):
return True
if msg.dev_type.startswith('hygrometer.'):
return True
if msg.dev_type.startswith('battery.'):
return True
def filter_msg(msg):
m_type = msg.dev_type.split('.')[0]
if m_type in UNSUPPORTED_TYPES:
return False
return True
class Bridge(object):
......@@ -38,12 +29,12 @@ class Bridge(object):
self._hass = hass
self._eng = AsyncEngine()
self._dev = self.setup_device()
self._mon = Monitor(self._dev, db_server=DB_SERVER)
self._eng.start()
self._mon = Monitor(self._dev, filter_msg, db_server=DB_SERVER)
self._eng.on_start(self.on_start)
self._eng.on_stop(self.on_stop)
self._eng.start()
self._entities = {}
self._handlers = []
self._factories = []
@property
def engine(self):
......@@ -51,15 +42,16 @@ class Bridge(object):
async def on_start(self):
_LOGGER.warning(f"{self._eng} started")
await self.wait_is_ready()
#await self.wait_is_ready()
print("Subscribing..")
self._mon.subscribe(self.monitor_event)
self._eng.subscribe(self.notification_handler)
self._eng.subscribe(self.monitor_notification)
def on_stop(self):
_LOGGER.warning(f"{self._eng} stopped")
def add_entity(self, addr, entity):
_LOGGER.warning(f"new Entity {addr} {entity}")
self._entities.update({addr: entity})
def remove_entity(self, addr):
......@@ -68,18 +60,19 @@ class Bridge(object):
def get_entity(self, addr):
return self._entities.get(addr, None)
def add_handler(self,handler):
print(handler)
self._handlers.append(handler)
def add_factory(self, klass):
self._factories.append(klass)
def remove_handler(self,handler):
self._handlers.remove(handler)
def remove_factory(self, klass):
self._factories.remove(klass)
def setup_device(self):
dev = schemas.hmi()
dev.dev_type = 'hmi.hass'
dev.vendor_id = 'IMT Atlantique'
dev.product_id = 'xAAL to HASS Brigde'
# never use this terrible hack to gain access to brigde throught aioconsole
#dev.new_attribute('bridge',self)
self._eng.add_device(dev)
return dev
......@@ -90,27 +83,29 @@ class Bridge(object):
while 1:
if self._mon.boot_finished:
return True
await asyncio.sleep(1)
await asyncio.sleep(0.5)
return False
def monitor_event(self, event, dev):
entity = self.get_entity(dev.address)
#_LOGGER.debug(f"{event} {dev.address} {dev.is_ready()} => {entity}")
# WARNING, never call ha_state update on a newly created entity,
# hass will block on this task (tricks: asyncio.sleep can fix that)
if entity and (event == Notification.attribute_change):
_LOGGER.debug(f"{event} {dev.address} => {entity}")
entity.schedule_update_ha_state()
return
if entity is None:
for h in self._handlers:
if entity is None and dev.is_ready():
for h in self._factories:
r = h.new_entity(dev)
if r:
_LOGGER.debug(f"New entity for {dev.address}")
return
_LOGGER.warning(f"Unable to find handler for {dev.address}")
return
self.get_entity(dev.address)
_LOGGER.info(f"New entity for {dev.address}")
if event in [Notification.attribute_change, Notification.metadata_change]:
_LOGGER.debug(f"{event} {entity}")
entity.async_write_ha_state()
return
def notification_handler(self, msg):
def monitor_notification(self, msg):
# right now the monitor doesn't send event on notification, so the bridge deals w/
# both monitor events & messages.
if (not msg.is_notify()) or msg.is_alive() or msg.is_attributes_change():
......@@ -119,4 +114,3 @@ class Bridge(object):
if entity and hasattr(entity, 'handle_notification'):
msg.dump()
entity.handle_notification(msg)
......@@ -29,7 +29,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
# if we have some user_input let's start
if user_input is not None:
try:
return self.async_create_entry(title="Bridge", data=user_input)
return self.async_create_entry(title="xAAL Bridge", data=user_input)
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
......
......@@ -16,7 +16,7 @@ class XAALEntity(Entity):
@property
def device_info(self):
print(f"DB: {self.unique_id} {self._dev.db}")
#print(f"DB: {self.unique_id} {self._dev.db}")
dev = self._dev
ident = "dev:" + str(dev.address)
......@@ -24,7 +24,7 @@ class XAALEntity(Entity):
if group_id:
ident = "grp:" + str(group_id)
_LOGGER.warning(ident)
#_LOGGER.warning(ident)
return {
"identifiers": {(DOMAIN, ident)},
......@@ -65,22 +65,13 @@ class XAALEntity(Entity):
addr = str(self._dev.address).replace('-', '_')
return f"xaal.{addr}"
# @property
# def entity_id(self) -> str | None:
# return self.unique_id
# @entity_id.setter
# def entity_id(self, value):
# _LOGGER.warning(f"entity_id setter {value}")
class EntryHandler(object):
class EntityFactory(object):
def __init__(self, bridge, async_add_entitites):
self._bridge = bridge
self._async_add_entitites = async_add_entitites
self._bridge.add_handler(self)
self._bridge.add_factory(self)
def add_entity(self, entity, address):
......
......@@ -5,12 +5,12 @@ from homeassistant.components.light import (
from homeassistant.util import color as color_util
from .const import DOMAIN
from .core import XAALEntity, EntryHandler
from .core import XAALEntity, EntityFactory
_LOGGER = logging.getLogger(__name__)
class Handler(EntryHandler):
class Factory(EntityFactory):
def new_entity(self, device):
if device.dev_type.startswith('lamp.'):
......@@ -22,9 +22,10 @@ class Handler(EntryHandler):
async def async_setup_entry(hass, config_entry, async_add_entities):
bridge = hass.data[DOMAIN][config_entry.entry_id]
handler = Handler(bridge, async_add_entities)
factory = Factory(bridge, async_add_entities)
for dev in bridge._mon.devices:
handler.new_entity(dev)
if dev.is_ready():
factory.new_entity(dev)
class Lamp(XAALEntity, LightEntity):
......@@ -37,10 +38,6 @@ class Lamp(XAALEntity, LightEntity):
if dev_type in ['lamp.dimmer']:
return {"brightness"}
# @property
# def unique_id(self) -> str:
# return f'light.{str(self._dev.address)}'
@property
def color_mode(self):
mode = self._dev.attributes.get('mode', None)
......
......@@ -8,17 +8,14 @@ from homeassistant.const import (
POWER_WATT,
)
from .const import DOMAIN
from .core import XAALEntity, EntryHandler
from .core import XAALEntity, EntityFactory
_LOGGER = logging.getLogger(__name__)
class Handler(EntryHandler):
class Factory(EntityFactory):
def new_entity(self, device):
entity = None
......@@ -45,14 +42,15 @@ class Handler(EntryHandler):
async def async_setup_entry(hass, config_entry, async_add_entities):
bridge = hass.data[DOMAIN][config_entry.entry_id]
handler = Handler(bridge, async_add_entities)
factory = Factory(bridge, async_add_entities)
for dev in bridge._mon.devices:
handler.new_entity(dev)
if dev.is_ready():
factory.new_entity(dev)
class Thermometer(XAALEntity, SensorEntity):
_attr_device_class = SensorDeviceClass.TEMPERATURE
_attr_unit_of_measurement = TEMP_CELSIUS
_attr_native_unit_of_measurement = TEMP_CELSIUS
@property
def state(self):
......@@ -61,7 +59,7 @@ class Thermometer(XAALEntity, SensorEntity):
class Hygrometer(XAALEntity, SensorEntity):
_attr_device_class = SensorDeviceClass.HUMIDITY
_attr_unit_of_measurement = PERCENTAGE
_attr_native_unit_of_measurement = PERCENTAGE
@property
def state(self):
......@@ -79,7 +77,7 @@ class Battery(XAALEntity, SensorEntity):
class PowerMeter(XAALEntity, SensorEntity):
_attr_device_class = SensorDeviceClass.POWER
_attr_unit_of_measurement = POWER_WATT
_attr_native_unit_of_measurement = POWER_WATT
@property
def state(self):
......
......@@ -3,12 +3,12 @@ from homeassistant.components.switch import SwitchEntity, DEVICE_CLASS_OUTLET
from .const import DOMAIN
from .core import XAALEntity, EntryHandler
from .core import EntityFactory, XAALEntity
_LOGGER = logging.getLogger(__name__)
class Handler(EntryHandler):
class Factory(EntityFactory):
def new_entity(self, device):
if device.dev_type.startswith('powerrelay.'):
......@@ -19,9 +19,10 @@ class Handler(EntryHandler):
async def async_setup_entry(hass, config_entry, async_add_entities):
bridge = hass.data[DOMAIN][config_entry.entry_id]
handler = Handler(bridge, async_add_entities)
factory = Factory(bridge, async_add_entities)
for dev in bridge._mon.devices:
handler.new_entity(dev)
if dev.is_ready():
factory.new_entity(dev)
class PowerRelay(XAALEntity, SwitchEntity):
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment