Skip to content
Closed
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
53 changes: 52 additions & 1 deletion custom_components/dirigera_platform/dirigera_lib_patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,26 @@ def delete_empty_scenes(self):
if scene.name.startswith("dirigera_integration_empty_scene_"):
logging.debug(f"Deleting Scene id: {scene.id} name: {scene.name}...")
self.delete_scene(scene.id)

def get_motion_sensors(self) -> List[MotionSensorX]:
"""
Fetches all motion sensors registered in the Hub.
Includes both motionSensor and occupancySensor device types.
IKEA MYGGSPRAY sensors report as occupancySensor instead of motionSensor.
"""
devices = self.get("/devices")
sensors = list(filter(lambda x: x["deviceType"] in ("motionSensor", "occupancySensor"), devices))
return [dict_to_motion_sensor_x(sensor, self) for sensor in sensors]

def get_motion_sensor_by_id(self, id_: str) -> MotionSensorX:
"""
Fetches a motion sensor by ID.
Accepts both motionSensor and occupancySensor device types.
"""
motion_sensor = self._get_device_data_by_id(id_)
if motion_sensor["deviceType"] not in ("motionSensor", "occupancySensor"):
raise ValueError("Device is not a MotionSensor or OccupancySensor")
return dict_to_motion_sensor_x(motion_sensor, self)

class ControllerAttributesX(Attributes):
is_on: Optional[bool] = None
Expand Down Expand Up @@ -136,4 +156,35 @@ 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")
self.hub.post(route=f"/scenes/{self.id}/undo")


# Motion sensor patch for MYGGSPRAY (occupancySensor)
# MYGGSPRAY sensors don't have is_on attribute, so we make it optional
class MotionSensorAttributesX(Attributes):
battery_percentage: Optional[int] = None
is_on: Optional[bool] = None # Made optional for MYGGSPRAY compatibility
light_level: Optional[float] = None
is_detected: Optional[bool] = False


class MotionSensorX(Device):
dirigera_client: AbstractSmartHomeHub
attributes: MotionSensorAttributesX

def reload(self) -> "MotionSensorX":
data = self.dirigera_client.get(route=f"/devices/{self.id}")
return MotionSensorX(dirigeraClient=self.dirigera_client, **data)

def set_name(self, name: str) -> None:
if "customName" not in self.capabilities.can_receive:
raise AssertionError("This sensor does not support the set_name function")
data = [{"attributes": {"customName": name}}]
self.dirigera_client.patch(route=f"/devices/{self.id}", data=data)
self.attributes.custom_name = name


def dict_to_motion_sensor_x(
data: Dict[str, Any], dirigera_client: AbstractSmartHomeHub
) -> MotionSensorX:
return MotionSensorX(dirigeraClient=dirigera_client, **data)
1 change: 1 addition & 0 deletions custom_components/dirigera_platform/hub_event_listener.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

process_events_from = {
"motionSensor" : ["isDetected","isOn","batteryPercentage"],
"occupancySensor" : ["isDetected","isOn","batteryPercentage"],
"outlet" : [ "isOn",
"currentAmps",
"currentActivePower",
Expand Down