core/homeassistant/components/upb/__init__.py

151 lines
4.1 KiB
Python

"""Support the UPB PIM."""
import asyncio
import upb_lib
from homeassistant.const import CONF_FILE_PATH, CONF_HOST
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.typing import ConfigType
from .const import (
ATTR_ADDRESS,
ATTR_BRIGHTNESS_PCT,
ATTR_COMMAND,
ATTR_RATE,
DOMAIN,
EVENT_UPB_SCENE_CHANGED,
)
UPB_PLATFORMS = ["light", "scene"]
async def async_setup(hass: HomeAssistant, hass_config: ConfigType) -> bool:
"""Set up the UPB platform."""
return True
async def async_setup_entry(hass, config_entry):
"""Set up a new config_entry for UPB PIM."""
url = config_entry.data[CONF_HOST]
file = config_entry.data[CONF_FILE_PATH]
upb = upb_lib.UpbPim({"url": url, "UPStartExportFile": file})
upb.connect()
hass.data.setdefault(DOMAIN, {})
hass.data[DOMAIN][config_entry.entry_id] = {"upb": upb}
for component in UPB_PLATFORMS:
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(config_entry, component)
)
def _element_changed(element, changeset):
change = changeset.get("last_change")
if change is None:
return
if change.get("command") is None:
return
hass.bus.async_fire(
EVENT_UPB_SCENE_CHANGED,
{
ATTR_COMMAND: change["command"],
ATTR_ADDRESS: element.addr.index,
ATTR_BRIGHTNESS_PCT: change.get("level", -1),
ATTR_RATE: change.get("rate", -1),
},
)
for link in upb.links:
element = upb.links[link]
element.add_callback(_element_changed)
return True
async def async_unload_entry(hass, config_entry):
"""Unload the config_entry."""
unload_ok = all(
await asyncio.gather(
*[
hass.config_entries.async_forward_entry_unload(config_entry, component)
for component in UPB_PLATFORMS
]
)
)
if unload_ok:
upb = hass.data[DOMAIN][config_entry.entry_id]["upb"]
upb.disconnect()
hass.data[DOMAIN].pop(config_entry.entry_id)
return unload_ok
class UpbEntity(Entity):
"""Base class for all UPB entities."""
def __init__(self, element, unique_id, upb):
"""Initialize the base of all UPB devices."""
self._upb = upb
self._element = element
element_type = "link" if element.addr.is_link else "device"
self._unique_id = f"{unique_id}_{element_type}_{element.addr}"
@property
def name(self):
"""Name of the element."""
return self._element.name
@property
def unique_id(self):
"""Return unique id of the element."""
return self._unique_id
@property
def should_poll(self) -> bool:
"""Don't poll this device."""
return False
@property
def device_state_attributes(self):
"""Return the default attributes of the element."""
return self._element.as_dict()
@property
def available(self):
"""Is the entity available to be updated."""
return self._upb.is_connected()
def _element_changed(self, element, changeset):
pass
@callback
def _element_callback(self, element, changeset):
"""Handle callback from an UPB element that has changed."""
self._element_changed(element, changeset)
self.async_write_ha_state()
async def async_added_to_hass(self):
"""Register callback for UPB changes and update entity state."""
self._element.add_callback(self._element_callback)
self._element_callback(self._element, {})
class UpbAttachedEntity(UpbEntity):
"""Base class for UPB attached entities."""
@property
def device_info(self):
"""Device info for the entity."""
return {
"name": self._element.name,
"identifiers": {(DOMAIN, self._element.index)},
"sw_version": self._element.version,
"manufacturer": self._element.manufacturer,
"model": self._element.product,
}