diff --git a/custom_components/dirigera_platform/dirigera_lib_patch.py b/custom_components/dirigera_platform/dirigera_lib_patch.py index f281de8..f849c96 100644 --- a/custom_components/dirigera_platform/dirigera_lib_patch.py +++ b/custom_components/dirigera_platform/dirigera_lib_patch.py @@ -26,6 +26,23 @@ def get_controllers(self) -> List[ControllerX]: controllers = list(filter(lambda x: x["type"] == "controller", devices)) return [dict_to_controller(controller, self) for controller in controllers] + # Scenes are a problem so making a hack + def get_scenes(self): + """ + Fetches all controllers registered in the Hub + """ + scenes = self.get("/scenes") + #scenes = list(filter(lambda x: x["type"] == "scene", devices)) + + return [HackScene.make_scene(self, scene) for scene in scenes] + + def get_scene_by_id(self, scene_id: str): + """ + Fetches a specific scene by a given id + """ + data = self.get(f"/scenes/{scene_id}") + return HackScene.make_scene(self, data) + def create_empty_scene(self, controller_id: str, clicks_supported:list): logging.debug(f"Creating empty scene for controller : {controller_id} with clicks : {clicks_supported}") for click in clicks_supported: @@ -60,8 +77,8 @@ def create_empty_scene(self, controller_id: str, clicks_supported:list): def delete_empty_scenes(self): scenes = self.get_scenes() for scene in scenes: - if scene.info.name.startswith("dirigera_integration_empty_scene_"): - logging.debug(f"Deleting Scene id: {scene.id} name: {scene.info.name}...") + if scene.name.startswith("dirigera_integration_empty_scene_"): + logging.debug(f"Deleting Scene id: {scene.id} name: {scene.name}...") self.delete_scene(scene.id) class ControllerAttributesX(Attributes): @@ -90,4 +107,33 @@ def set_name(self, name: str) -> None: def dict_to_controller( data: Dict[str, Any], dirigera_client: AbstractSmartHomeHub ) -> ControllerX: - return ControllerX(dirigeraClient=dirigera_client, **data) \ No newline at end of file + return ControllerX(dirigeraClient=dirigera_client, **data) + +class HackScene(): + + def __init__(self, hub, id, name, icon): + self.hub = hub + self.id = id + self.name = name + self.icon = icon + + def parse_scene_json(json_data): + id = json_data["id"] + name = json_data["info"]["name"] + icon = json_data["info"]["icon"] + return id, name, icon + + def make_scene(dirigera_client, json_data): + id, name, icon = HackScene.parse_scene_json(json_data) + return HackScene(dirigera_client, id, name, icon) + + def reload(self) -> HackScene: + data = self.dirigera_client.get(route=f"/scenes/{self.id}") + return HackScene.make_scene(self, data) + #return Scene(dirigeraClient=self.dirigera_client, **data) + + def trigger(self) -> HackScene: + self.hub.post(route=f"/scenes/{self.id}/trigger") + + def undo(self) -> HackScene: + self.hub.post(route=f"/scenes/{self.id}/undo") \ No newline at end of file diff --git a/custom_components/dirigera_platform/icons.py b/custom_components/dirigera_platform/icons.py index ff7473e..35215f9 100644 --- a/custom_components/dirigera_platform/icons.py +++ b/custom_components/dirigera_platform/icons.py @@ -47,6 +47,50 @@ Icon.SCENES_YOGA: "mdi:yoga", } +ikea_to_hass_mapping: dict[str, str] = { + "scenes_arrive_home": "mdi:home-import-outline", + "scenes_book": "mdi:book", + "scenes_briefcase": "mdi:briefcase", + "scenes_brightness_up": "mdi:lightbulb", + "scenes_broom": "mdi:broom", + "scenes_cake": "mdi:cake", + "scenes_clapper": "mdi:movie-open", + "scenes_clean_sparkles": "mdi:creation", + "scenes_cutlery": "mdi:silverware-fork-knife", + "scenes_disco_ball": "mdi:ceiling-light", + "scenes_game_pad": "mdi:gamepad", + "scenes_gift_bag": "mdi:shopping", + "scenes_gift_box": "mdi:gift", + "scenes_headphones": "mdi:headphones", + "scenes_heart": "mdi:heart", + "scenes_home_filled": "mdi:home", + "scenes_hot_drink": "mdi:cup", + "scenes_ladle": "mdi:silverware-spoon", + "scenes_leaf": "mdi:leaf", + "scenes_leave_home": "mdi:home-export-outline", + "scenes_moon": "mdi:moon-waning-crescent", + "scenes_music_note": "mdi:music-note", + "scenes_painting": "mdi:palette", + "scenes_popcorn": "mdi:popcorn", + "scenes_pot_with_lid": "mdi:pot", + "scenes_speaker_generic": "mdi:speaker", + "scenes_spray_bottle": "mdi:spray", + "scenes_suitcase": "mdi:suitcase", + "scenes_suitcase_2": "mdi:briefcase", + "scenes_sun_horizon": "mdi:weather-sunset", + "scenes_tree": "mdi:pine-tree", + "scenes_trophy": "mdi:trophy", + "scenes_wake_up": "mdi:alarm", + "scenes_weights": "mdi:dumbbell", + "scenes_yoga": "mdi:yoga" +} + +def ikea_to_hass_icon(ikea_icon) -> str: + if ikea_icon not in ikea_to_hass_mapping: + return ikea_to_hass_mapping[ikea_icon] + + logger.warning(f"Unknown icon {ikea_icon}") + return "mdi:help" def to_hass_icon(dirigera_icon: Icon) -> str: """Return suitable replacement icon.""" diff --git a/custom_components/dirigera_platform/ikea_gateway.py b/custom_components/dirigera_platform/ikea_gateway.py index a5795bd..d2df3d9 100644 --- a/custom_components/dirigera_platform/ikea_gateway.py +++ b/custom_components/dirigera_platform/ikea_gateway.py @@ -42,7 +42,7 @@ def __init__(self): self.devices = {} async def make_devices(self, hass, ip, token): - hub = HubX(token, ip) + hub: HubX = HubX(token, ip) #Scenes scenes = await hass.async_add_executor_job(hub.get_scenes) @@ -50,7 +50,7 @@ async def make_devices(self, hass, ip, token): empty_scenes = [] non_empty_scenes = [] for scene in scenes: - if scene.info.name.startswith("dirigera_integration_empty_scene_"): + if scene.name.startswith("dirigera_integration_empty_scene_"): empty_scenes.append(ikea_scene(hub,scene)) else: non_empty_scenes.append(ikea_scene(hub,scene)) diff --git a/custom_components/dirigera_platform/scene.py b/custom_components/dirigera_platform/scene.py index 09d3ad2..9724bd1 100644 --- a/custom_components/dirigera_platform/scene.py +++ b/custom_components/dirigera_platform/scene.py @@ -3,9 +3,10 @@ import logging from typing import Any -from dirigera import Hub -from dirigera.devices.scene import Scene as DirigeraScene -from dirigera.devices.scene import Trigger, TriggerDetails, EndTriggerEvent +#from dirigera import Hub +from .dirigera_lib_patch import HubX, HackScene +#from dirigera.devices.scene import Scene as DirigeraScene +#from dirigera.devices.scene import Trigger, TriggerDetails, EndTriggerEvent from homeassistant.components.scene import Scene from homeassistant.config_entries import ConfigEntry @@ -14,7 +15,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import DOMAIN, PLATFORM -from .icons import to_hass_icon +from .icons import to_hass_icon, ikea_to_hass_icon logger = logging.getLogger("custom_components.dirigera_platform") @@ -24,9 +25,10 @@ async def async_setup_entry( """Create scene entities from Dirigera scene.""" logger.debug("async_setup_entry for scenes...") - Trigger.update_forward_refs() - TriggerDetails.update_forward_refs() - EndTriggerEvent.update_forward_refs() + #Commented as hack for pydantic scene issue + #Trigger.update_forward_refs() + #TriggerDetails.update_forward_refs() + #EndTriggerEvent.update_forward_refs() async_add_entities(hass.data[DOMAIN][PLATFORM].scenes) logger.debug("async_setup_entry complete for scenes...") @@ -36,34 +38,37 @@ class ikea_scene(Scene): _attr_has_entity_name = True - def __init__(self, hub: Hub, dirigera_scene: DirigeraScene) -> None: + def __init__(self, hub: HubX, scene: HackScene) -> None: """Initialize.""" self._hub = hub - self._dirigera_scene = dirigera_scene - self._attr_unique_id = dirigera_scene.id - + self._scene = scene + + @property + def unique_id(self): + return self._scene.id + @property def name(self) -> str: """Return name from Dirigera.""" - return self._dirigera_scene.info.name - + #return self._dirigera_scene.info.name + return self._scene.name + @property def icon(self) -> str: """Return suitable replacement icon.""" - return to_hass_icon(self._dirigera_scene.info.icon) - + #return to_hass_icon(self._dirigera_scene.info.icon) + return ikea_to_hass_icon(self._scene.icon) + async def async_activate(self, **kwargs: Any) -> None: """Trigger Dirigera Scene.""" logger.debug("Activating scene '%s' (%s)", self.name, self.unique_id) - await self.hass.async_add_executor_job(self._dirigera_scene.trigger) + await self.hass.async_add_executor_job(self._scene.trigger) async def async_update(self) -> None: """Fetch updated scene definition from Dirigera.""" logger.debug("Updating scene '%s' (%s)", self.name, self.unique_id) try: - self._dirigera_scene = await self.hass.async_add_executor_job( - self._hub.get_scene_by_id, self.unique_id - ) + self._dirigera_scene = await self.hass.async_add_executor_job(self._hub.get_scene_by_id, self.unique_id) except Exception as ex: logger.error("Error encountered on update of '%s' (%s)", self.name, self.unique_id) logger.error(ex)