Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
## IKEA Dirigera Hub Integration

This is an actively maintained fork of [sanjoyg/dirigera_platform](https://github.com/sanjoyg/dirigera_platform), which appears to be abandoned (last activity March 2025). This integration connects Home Assistant with the IKEA Dirigera hub, built on the [dirigera](https://github.com/Leggin/dirigera) Python library by Nicolas Hilberg.
This is a fork of [sanjoyg/dirigera_platform](https://github.com/sanjoyg/dirigera_platform), which was stagnant for a while, but the upstream maintainer resumed working on it, so I recommend to switch back to the upstream repository by SanjoyG. I will keep this respository up and may or may not continue working on it separately from the upstream repo and will post PR requests upstream when I add or improve things.

This integration connects Home Assistant with the IKEA Dirigera hub, built on the [dirigera](https://github.com/Leggin/dirigera) Python library by Nicolas Hilberg.

This fork addresses most of the outstanding issues from the upstream repository. Contributions are welcome — feel free to open [issues](https://github.com/nrbrt/dirigera_platform/issues) or submit pull requests.

Expand Down
8 changes: 7 additions & 1 deletion custom_components/dirigera_platform/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import voluptuous as vol

from homeassistant import config_entries, core
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.components.light import PLATFORM_SCHEMA
from homeassistant.const import CONF_IP_ADDRESS, CONF_TOKEN, Platform

Expand Down Expand Up @@ -195,7 +196,12 @@ async def async_setup_entry(
platform = ikea_gateway()
hass.data[DOMAIN][PLATFORM] = platform
logger.debug("Starting make_devices...")
await platform.make_devices(hass,hass_data[CONF_IP_ADDRESS], hass_data[CONF_TOKEN])
try:
await platform.make_devices(hass,hass_data[CONF_IP_ADDRESS], hass_data[CONF_TOKEN])
except (ConnectionError, OSError) as err:
raise ConfigEntryNotReady(
f"Cannot connect to IKEA Dirigera hub at {hass_data[CONF_IP_ADDRESS]}: {err}"
) from err

#await hass.async_add_executor_job(platform.make_devices,hass, hass_data[CONF_IP_ADDRESS], hass_data[CONF_TOKEN])

Expand Down
21 changes: 19 additions & 2 deletions custom_components/dirigera_platform/base_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,19 @@ def available(self):
def should_register_with_listener(self):
return True

@property
def device_identifier(self) -> str:
"""Return the identifier used for HA device grouping.
Uses relation_id to group sub-devices of the same physical hardware."""
if self._json_data.relation_id:
return self._json_data.relation_id
return self._json_data.id

@property
def device_info(self) -> DeviceInfo:

return DeviceInfo(
identifiers={("dirigera_platform", self._json_data.id)},
identifiers={("dirigera_platform", self.device_identifier)},
name=self.name,
manufacturer=self._json_data.attributes.manufacturer,
model=self._json_data.attributes.model,
Expand All @@ -107,6 +115,15 @@ def device_info(self) -> DeviceInfo:
@property
def name(self):
if self._json_data.attributes.custom_name is None or len(self._json_data.attributes.custom_name) == 0:
# For sub-devices with relation_id, try to get name from a sibling
if self._json_data.relation_id:
for reg_entry in hub_event_listener.device_registry.values():
sibling = reg_entry.entity
if (hasattr(sibling, '_json_data')
and sibling._json_data.relation_id == self._json_data.relation_id
and sibling._json_data.id != self._json_data.id
and sibling._json_data.attributes.custom_name):
return sibling._json_data.attributes.custom_name
return self.unique_id
return self._json_data.attributes.custom_name

Expand Down
7 changes: 2 additions & 5 deletions custom_components/dirigera_platform/device_trigger.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,8 @@ async def async_get_triggers(hass: HomeAssistant, device_id: str) -> list[dict[s

registry_entity = registry_entry.entity

if "identifiers" not in registry_entity.device_info or len(list(registry_entity.device_info["identifiers"])[0]) < 2:
logger.warning(f"entity_id: {entity_id} corresponding in dirigera_platform entity doesnt have identifiers or isnt 2 entries long, device_info : {registry_entity.device_info}")
logger.info(registry_entity.device_info["identifiers"])
registry_entity_id = list(registry_entity.device_info["identifiers"])[0][1]

registry_entity_id = registry_entity.unique_id

if registry_entity_id != entity_id:
logger.error(f"Found controller with entity id : {registry_entity_id} but doesnt match requested entity id: {entity_id}")
continue
Expand Down
9 changes: 5 additions & 4 deletions custom_components/dirigera_platform/hub_event_listener.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ async def sync_all_device_areas(self):
entity = registry_entry.entity
if hasattr(entity, '_json_data') and entity._json_data.room is not None:
room_name = entity._json_data.room.name
await self._update_device_area(device_id, room_name)
identifier = entity._json_data.relation_id or entity._json_data.id
await self._update_device_area(identifier, room_name)
synced_count += 1
except Exception as ex:
logger.error(f"Failed to sync area for device {device_id}: {ex}")
Expand Down Expand Up @@ -536,7 +537,7 @@ def on_message(self, ws:Any, ws_msg:str):
# but not yet in the HA device registry
try:
self._hass.loop.call_soon_threadsafe(
lambda room=new_room.name, device_id=id: self._hass.async_create_task(
lambda room=new_room.name, device_id=(entity._json_data.relation_id or id): self._hass.async_create_task(
self._update_device_area(device_id, room)
)
)
Expand All @@ -549,7 +550,7 @@ def on_message(self, ws:Any, ws_msg:str):
room_changed = True
try:
self._hass.loop.call_soon_threadsafe(
lambda device_id=id: self._hass.async_create_task(
lambda device_id=(entity._json_data.relation_id or id): self._hass.async_create_task(
self._update_device_area(device_id, "")
)
)
Expand Down Expand Up @@ -621,7 +622,7 @@ def on_message(self, ws:Any, ws_msg:str):
if name_changed and new_name is not None:
try:
self._hass.loop.call_soon_threadsafe(
lambda name=new_name, device_id=id: self._hass.async_create_task(
lambda name=new_name, device_id=(entity._json_data.relation_id or id): self._hass.async_create_task(
self._update_device_name(device_id, name)
)
)
Expand Down
4 changes: 2 additions & 2 deletions custom_components/dirigera_platform/light.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ def available(self):
def device_info(self) -> DeviceInfo:

return DeviceInfo(
identifiers={("dirigera_platform", self._json_data.id)},
identifiers={("dirigera_platform", self._json_data.relation_id or self._json_data.id)},
name=self.name,
manufacturer=self._json_data.attributes.manufacturer,
model=self._json_data.attributes.model,
Expand Down Expand Up @@ -394,7 +394,7 @@ def available(self):
def device_info(self) -> DeviceInfo:

# Register the device for updates
hub_event_listener.register(self.unique_id, self)
hub_event_listener.register(self.unique_id, registry_entry(self))

return DeviceInfo(
identifiers={("dirigera_platform", self._device_set.id)},
Expand Down