Skip to content

Commit

Permalink
Entities and Devices Appear Now. Also added support for
Browse files Browse the repository at this point in the history
1. Motion Sensor
2. Open Close Sensor
  • Loading branch information
c503ghosh committed Jan 31, 2024
1 parent 8a6d1d4 commit 13b7c1c
Show file tree
Hide file tree
Showing 11 changed files with 429 additions and 59 deletions.
52 changes: 45 additions & 7 deletions custom_components/dirigera_platform/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import homeassistant.helpers.config_validation as cv
from homeassistant.components.light import PLATFORM_SCHEMA
from homeassistant.const import CONF_IP_ADDRESS, CONF_TOKEN
from homeassistant.helpers.entity import DeviceInfo

from .const import DOMAIN

Expand All @@ -22,35 +23,64 @@
})

async def async_setup(hass: HomeAssistant, config: dict) -> bool:
logger.debug("In init asetup...")
logger.debug("Starting async_setup...")
logger.debug(config)
logger.debug("asetup complete...")
logger.debug("Complete async_setup...")

def handle_dump_data(call):
import dirigera
logger.info("=== START Devices JSON ===")

# we could have multiple hubs set up
for key in hass.data[DOMAIN].keys():
logger.info("--------------")
config_data = hass.data[DOMAIN][key]
ip = config_data[CONF_IP_ADDRESS]
token = config_data[CONF_TOKEN]
if ip == "mock":
logger.info("{ MOCK JSON }")
else:
hub = dirigera.Hub(token, ip)
json_resp = hub.get("/devices")
logger.info(json_resp)
logger.info("--------------")

logger.info("=== END Devices JSON ===")

hass.services.async_register(DOMAIN, "dump_data", handle_dump_data)
return True

async def async_setup_entry(hass: core.HomeAssistant, entry: config_entries.ConfigEntry) -> bool:
"""Set up platform from a ConfigEntry."""
logger.debug("Staring async_setup_entry...")
logger.debug("Staring async_setup_entry in init...")
logger.debug(dict(entry.data))

hass.data.setdefault(DOMAIN, {})
hass_data = dict(entry.data)

logger.debug("hass_data")
logger.debug(hass_data)

ip = hass_data[CONF_IP_ADDRESS]

# Registers update listener to update config entry when options are updated.
unsub_options_update_listener = entry.add_update_listener(options_update_listener)

# Store a reference to the unsubscribe function to cleanup if an entry is unloaded.
hass_data["unsub_options_update_listener"] = unsub_options_update_listener
hass.data[DOMAIN][entry.entry_id] = hass_data

# Setup the entities
hass.async_create_task(hass.config_entries.async_forward_entry_setup(entry, "light"))
hass.async_create_task(hass.config_entries.async_forward_entry_setup(entry, "switch"))
hass.async_create_task(hass.config_entries.async_forward_entry_setup(entry, "binary_sensor"))

logger.debug("Complete async_setup_entry...")

return True

async def options_update_listener(hass: core.HomeAssistant, config_entry: config_entries.ConfigEntry):
logger.debug("Starting options_update_listener")
logger.debug("In options_update_listener")
"""Handle options update."""
await hass.config_entries.async_reload(config_entry.entry_id)

Expand All @@ -67,5 +97,13 @@ async def async_unload_entry(hass: core.HomeAssistant, entry: config_entries.Con
# Remove options_update_listener.
hass.data[DOMAIN][entry.entry_id]["unsub_options_update_listener"]()
hass.data[DOMAIN].pop(entry.entry_id)
logger.debug("successfully popped")
return unload_ok
logger.debug("Successfully popped entry")
logger.debug("Complete async_unload_entry")

return unload_ok

async def async_remove_config_entry_device( hass: HomeAssistant, config_entry: config_entries.ConfigEntry, device_entry: config_entries.DeviceEntry) -> bool:
logger.info("Got request to remove device")
logger.info(config_entry)
logger.info(device_entry)
return True
115 changes: 115 additions & 0 deletions custom_components/dirigera_platform/binary_sensor.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
from homeassistant import config_entries, core
from homeassistant.const import CONF_IP_ADDRESS, CONF_TOKEN
from homeassistant.core import HomeAssistantError
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.components.binary_sensor import BinarySensorEntity

import dirigera
from .dirigera_lib_patch import HubX

from .const import DOMAIN
from .mocks.ikea_motion_sensor_mock import ikea_motion_sensor_mock
from .mocks.ikea_open_close_mock import ikea_open_close_mock

import logging
logger = logging.getLogger("custom_components.dirigera_platform")

async def async_setup_entry(
hass: core.HomeAssistant,
config_entry: config_entries.ConfigEntry,
async_add_entities,
):
logger.debug("Binary Sensor Starting async_setup_entry")
"""Setup sensors from a config entry created in the integrations UI."""
config = hass.data[DOMAIN][config_entry.entry_id]
logger.debug(config)

#hub = dirigera.Hub(config[CONF_TOKEN], config[CONF_IP_ADDRESS])
hub = HubX(config[CONF_TOKEN], config[CONF_IP_ADDRESS])

lights = []

# If mock then start with mocks
if config[CONF_IP_ADDRESS] == "mock":
logger.warning("Setting up mock motion sensors")
mock_motion_sensor1 = ikea_motion_sensor_mock(hub,"mock_motion_sensor1")
mock_motion_sensor2 = ikea_motion_sensor_mock(hub,"mock_motion_sensor2")
motion_sensors = [mock_motion_sensor1,mock_motion_sensor2]

logger.warning("Setting up mock open/close sensors")
mock_open_close_sensor1 = ikea_open_close_mock(hub,"mock_open_close_sensor1")
mock_open_close_sensor2 = ikea_open_close_mock(hub,"mock_open_close_sensor2")
open_close_sensors = [mock_open_close_sensor1,mock_open_close_sensor2]

else:
hub_motion_sensors = await hass.async_add_executor_job(hub.get_motion_sensors)
motion_sensors = [ikea_motion_sensor(hub, motion_sensor) for motion_sensor in hub_motion_sensors]

hub_open_close_sensors = await hass.async_add_executor_job(hub.get_open_close_sensors)
open_close_sensors = [ikea_open_close(hub, open_close_sensor) for open_close_sensor in hub_open_close_sensors]

logger.debug("Found {} motion_sensor entities to setup...".format(len(motion_sensors)))
async_add_entities(motion_sensors)
logger.debug("Found {} open close entities to setup...".format(len(open_close_sensors)))
async_add_entities(open_close_sensors)

logger.debug("Binary Sensor Complete async_setup_entry")

class ikea_motion_sensor(BinarySensorEntity):
def __init__(self, hub, json_data):
logger.debug("ikea_motion_sensor ctor...")
self._hub = hub
self._json_data = json_data

@property
def unique_id(self):
return self._json_data.id

@property
def available(self):
return self._json_data.is_reachable

@property
def device_info(self) -> DeviceInfo:
return DeviceInfo(
identifiers={("dirigera_platform",self._json_data.id)},
name = self._json_data.attributes.custom_name,
manufacturer = self._json_data.attributes.manufacturer,
model=self._json_data.attributes.model ,
sw_version=self._json_data.attributes.firmware_version
)

@property
def name(self):
return self._json_data.attributes.custom_name

@property
def is_on(self):
return self._json_data.attributes.is_on

def update(self):
logger.debug("motion sensor update...")
try:
self._json_data = self._hub.get_motion_sensor_by_id(self._json_data.id)
except Exception as ex:
logger.error("error encountered running update on : {}".format(self.name))
logger.error(ex)
raise HomeAssistantError(ex,DOMAIN,"hub_exception")

class ikea_open_close(ikea_motion_sensor):
def __init__(self, hub, json_data):
logger.debug("ikea_open_close ctor...")
self._hub = hub
self._json_data = json_data

def update(self):
logger.debug("open close sensor update...")
try:
self._json_data = self._hub.get_open_close_by_id(self._json_data.id)
except Exception as ex:
logger.error("error encountered running update on : {}".format(self.name))
logger.error(ex)
raise HomeAssistantError(ex,DOMAIN,"hub_exception")

def is_on(self):
return self._json_data.attributes.is_open
4 changes: 2 additions & 2 deletions custom_components/dirigera_platform/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ async def async_step_action( self, user_input: Dict[str, Any] = None) -> Dict[st
token = "mock"
else:
token = await core.async_get_hass().async_add_executor_job(get_dirigera_token_step_two,self.ip, self.code, self.code_verifier)
logger.debug("Successful generating token")
logger.info("Successful generating token")
logger.debug(token)

user_input[CONF_IP_ADDRESS] = self.ip
Expand Down Expand Up @@ -162,7 +162,7 @@ async def async_step_action( self, user_input: Dict[str, Any] = None) -> Dict[st
token = "mock"
else:
token = await core.async_get_hass().async_add_executor_job(get_dirigera_token_step_two,self.ip, self.code, self.code_verifier)
logger.debug("Successful generating token")
logger.info("Successful generating token")
logger.debug(token)

user_input[CONF_IP_ADDRESS] = self.ip
Expand Down
40 changes: 40 additions & 0 deletions custom_components/dirigera_platform/dirigera_lib_patch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from dirigera import Hub
from dirigera.devices.device import Attributes
from dirigera.devices.motion_sensor import MotionSensor
from dirigera.devices.open_close_sensor import OpenCloseSensor, dict_to_open_close_sensor
from dirigera.hub.abstract_smart_home_hub import AbstractSmartHomeHub
from typing import Any, Dict, List

# Patch to fix issues with motion sensor

class MotionSensorAttributesX(Attributes):
battery_percentage: int
is_on: bool

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

def dict_to_motion_sensorx(data: Dict[str, Any], dirigera_client: AbstractSmartHomeHub) -> MotionSensorX:
return MotionSensorX(dirigeraClient=dirigera_client, **data)

class HubX(Hub):
def __init__( self, token: str, ip_address: str, port: str = "8443", api_version: str = "v1") -> None:
super().__init__(token, ip_address, port, api_version)

def get_motion_sensors(self) -> List[MotionSensor]:
devices = self.get("/devices")
sensors = list(filter(lambda x: x["deviceType"] == "motionSensor", devices))
return [dict_to_motion_sensorx(sensor, self) for sensor in sensors]

def get_motion_sensor_by_id(self, id_: str) -> MotionSensorX:
motion_sensor = self._get_device_data_by_id(id_)
if motion_sensor["deviceType"] != "motionSensor":
raise ValueError("Device is not an MotionSensor")
return dict_to_motion_sensorx(motion_sensor, self)

def get_open_close_by_id(self, id_: str) -> OpenCloseSensor:
open_close_sensor = self._get_device_data_by_id(id_)
if open_close_sensor["deviceType"] != "openCloseSensor":
raise ValueError("Device is not an OpenCloseSensor")
return dict_to_open_close_sensor(open_close_sensor, self)
Loading

0 comments on commit 13b7c1c

Please sign in to comment.