From 414508f8965f76bc3599390b165bade60102e808 Mon Sep 17 00:00:00 2001 From: Siddhu <693151+arevindh@users.noreply.github.com> Date: Sun, 16 Jun 2024 19:37:15 +0530 Subject: [PATCH] Support for lock added Signed-off-by: Siddhu <693151+arevindh@users.noreply.github.com> --- custom_components/tinxy/__init__.py | 2 +- custom_components/tinxy/lock.py | 147 ++++++++++++++++++++++++++ custom_components/tinxy/tinxycloud.py | 15 ++- 3 files changed, 160 insertions(+), 4 deletions(-) create mode 100644 custom_components/tinxy/lock.py diff --git a/custom_components/tinxy/__init__.py b/custom_components/tinxy/__init__.py index 2644c0b..a60dfdc 100644 --- a/custom_components/tinxy/__init__.py +++ b/custom_components/tinxy/__init__.py @@ -12,7 +12,7 @@ # TODO List the platforms that you want to support. # For your initial PR, limit it to 1 platform. -PLATFORMS: list[Platform] = [Platform.SWITCH, Platform.LIGHT, Platform.FAN] +PLATFORMS: list[Platform] = [Platform.SWITCH, Platform.LIGHT, Platform.FAN, Platform.LOCK] async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: diff --git a/custom_components/tinxy/lock.py b/custom_components/tinxy/lock.py new file mode 100644 index 0000000..050a101 --- /dev/null +++ b/custom_components/tinxy/lock.py @@ -0,0 +1,147 @@ +"""Example integration using DataUpdateCoordinator.""" + +import logging +from typing import Any + +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers.update_coordinator import CoordinatorEntity +from homeassistant.components.lock import ( + LockEntityFeature, + LockEntity +) + +from .const import DOMAIN +from .coordinator import TinxyUpdateCoordinator + +_LOGGER = logging.getLogger(__name__) + + +async def async_setup_entry( + hass: HomeAssistant, entry: ConfigEntry, async_add_entities +) -> None: + """Config entry example.""" + # assuming API object stored here by __init__.py + apidata, coordinator = hass.data[DOMAIN][entry.entry_id] + + # _LOGGER.error(apidata) + + # Fetch initial data so we have data when entities subscribe + # + # If the refresh fails, async_config_entry_first_refresh will + # raise ConfigEntryNotReady and setup will try again later + # + # If you do not want to retry setup on failure, use + # coordinator.async_refresh() instead + # + await coordinator.async_config_entry_first_refresh() + locks = [] + + status_list = {} + + all_devices = apidata.list_locks() + result = await apidata.get_all_status() + + for device in all_devices: + if device["id"] in result: + status_list[device["id"]] = device | result[device["id"]] + + for th_device in status_list: + locks.append(TinxyLock(coordinator, apidata, th_device)) + + async_add_entities(locks) + + +class TinxyLock(CoordinatorEntity, LockEntity): + """An entity using CoordinatorEntity. + + The CoordinatorEntity class provides: + should_poll + async_update + async_added_to_hass + available + + """ + + def __init__(self, coordinator, apidata, idx) -> None: + """Pass coordinator to CoordinatorEntity.""" + super().__init__(coordinator, context=idx) + self.idx = idx + self.coordinator = coordinator + self.api = apidata + # _LOGGER.warning( + # self.coordinator.data[self.idx]["name"] + # + " - " + # + self.coordinator.data[self.idx]["state"] + # ) + + @callback + def _handle_coordinator_update(self) -> None: + """Handle updated data from the coordinator.""" + self._attr_is_open = self.coordinator.data[self.idx]["door"] == "OPEN" + + _LOGGER.error( + self.coordinator.data[self.idx] + ) + + self.async_write_ha_state() + + @property + def unique_id(self) -> str: + """dasdasdasd.""" + return self.coordinator.data[self.idx]["id"] + + @property + def icon(self) -> str: + """Icon for entity.""" + return self.coordinator.data[self.idx]["icon"] + + @property + def name(self) -> str: + """Name of the entity.""" + return self.coordinator.data[self.idx]["name"] + + @property + def is_locked(self) -> bool: + """If the switch is currently on or off.""" + # self.read_status() + return self.coordinator.data[self.idx]["door"] != "OPEN" + # return False + + @property + def is_open(self) -> bool: + """If the switch is currently on or off.""" + # self.read_status() + return self.coordinator.data[self.idx]["door"] == "OPEN" + # return False + + + @property + def available(self) -> bool: + """Device available status.""" + return True if self.coordinator.data[self.idx]["status"] == 1 else False + + @property + def device_info(self): + return self.coordinator.data[self.idx]["device"] + + async def async_unlock(self, **kwargs: Any) -> None: + """Turn the switch on.""" + # self._is_on = True + await self.api.set_device_state( + self.coordinator.data[self.idx]["device_id"], + str(self.coordinator.data[self.idx]["relay_no"]), + 1, + ) + + await self.coordinator.async_request_refresh() + + async def async_lock(self, **kwargs: Any) -> None: + """Turn the switch off.""" + # self._is_on = False + await self.api.set_device_state( + self.coordinator.data[self.idx]["device_id"], + str(self.coordinator.data[self.idx]["relay_no"]), + 0, + ) + await self.coordinator.async_request_refresh() \ No newline at end of file diff --git a/custom_components/tinxy/tinxycloud.py b/custom_components/tinxy/tinxycloud.py index 2281472..82b2100 100644 --- a/custom_components/tinxy/tinxycloud.py +++ b/custom_components/tinxy/tinxycloud.py @@ -67,6 +67,7 @@ class TinxyCloud: gtype_light = ["action.devices.types.LIGHT"] gtype_switch = ["action.devices.types.SWITCH"] gtype_lock = ["action.devices.types.LOCK"] + typeId_lock = ["WIRED_DOOR_LOCK_V3"] typeId_fan = ["WIFI_3SWITCH_1FAN", "Fan", "WIFI_SWITCH_1FAN_V1","WIFI_3SWITCH_1FAN_V3"] def __init__(self, host_config: TinxyHostConfiguration, web_session) -> None: @@ -122,7 +123,7 @@ def list_fans(self): return [d for d in self.devices if d["device_type"] == "Fan"] def list_locks(self): - """List lokcs.""" + """List locks.""" return [d for d in self.devices if d["gtype"] in self.gtype_lock] async def get_device_state(self, id, device_number): @@ -160,6 +161,9 @@ async def get_all_status(self): single_device["status"] = item["state"]["status"] if "brightness" in item["state"]: single_device["brightness"] = item["state"]["brightness"] + # fix for lock + if "door" in item["state"]: + single_device["door"] = item["state"]["door"] device_status[device_id] = single_device else: single_device = {} @@ -172,6 +176,9 @@ async def get_all_status(self): single_device["status"] = status["state"]["status"] if "brightness" in status["state"]: single_device["brightness"] = status["state"]["brightness"] + # fix for lock + if "door" in status["state"]: + single_device["door"] = status["state"]["door"] device_status[device_id] = single_device return device_status @@ -286,8 +293,8 @@ def get_device_type(self, tinxy_type, itemid): return "Fan" elif tinxy_type in light_list: return "Light" - elif tinxy_type in self.gtype_lock: - return "Switch" + elif tinxy_type in self.typeId_lock: + return "Lock" else: return "Switch" @@ -312,5 +319,7 @@ def icon_generate(self, devicetype): return "mdi:power-socket-eu" elif devicetype == "TV": return "mdi:television" + elif devicetype == "Lock": + return "mdi:lock" else: return "mdi:toggle-switch"