diff --git a/custom_components/sberdevices/api.py b/custom_components/sberdevices/api.py index 14e54ba..f4418f0 100755 --- a/custom_components/sberdevices/api.py +++ b/custom_components/sberdevices/api.py @@ -1,5 +1,5 @@ -from datetime import datetime import tempfile +from datetime import datetime from authlib.common.security import generate_token from authlib.integrations.httpx_client import AsyncOAuth2Client @@ -82,7 +82,7 @@ async def authorize_by_url(self, url: str) -> bool: code_verifier=self._verify_token, ) return token is not None - except: + except Exception: return False async def fetch_home_token(self) -> str: @@ -111,7 +111,7 @@ async def update_token(self) -> None: self._client.headers.update({"X-AUTH-jwt": token}) async def request( - self, method: str, url: str, retry: bool = True, **kwargs + self, method: str, url: str, retry: bool = True, **kwargs ) -> dict[str, any]: await self.update_token() @@ -132,7 +132,7 @@ async def get_device_tree(self) -> dict[str, any]: return (await self.request("GET", "/device_groups/tree"))["result"] # Cache - async def update_devices_cache(self) -> list[dict[str, any]]: + async def update_devices_cache(self): self._devices = extract_devices(await self.get_device_tree()) def get_cached_devices(self) -> list[dict[str, any]]: @@ -149,7 +149,7 @@ async def set_device_state(self, device_id: str, state: [dict[str, any]]) -> Non "device_id": device_id, "desired_state": state, "timestamp": datetime.now().isoformat() - + "Z", # 2023-12-01T17:00:35.537Z + + "Z", # 2023-12-01T17:00:35.537Z }, ) @@ -205,8 +205,9 @@ def find_from_list(data: [dict[str, any]], key: str) -> dict[str, any] | None: def does_exist_in_list(data: [dict[str, any]], key: str) -> bool: return find_from_list(data, key) is not None + def extract_devices(d: dict[str, any]) -> dict[str, any]: devices: dict[str, any] = {device["id"]: device for device in d["devices"]} for children in d["children"]: devices.update(extract_devices(children)) - return devices \ No newline at end of file + return devices diff --git a/custom_components/sberdevices/config_flow.py b/custom_components/sberdevices/config_flow.py index df9f269..35a5a49 100755 --- a/custom_components/sberdevices/config_flow.py +++ b/custom_components/sberdevices/config_flow.py @@ -1,12 +1,11 @@ """Config flow for SberDevices integration.""" from __future__ import annotations -import asyncio +import asyncio import logging from typing import Any import voluptuous as vol - from homeassistant import config_entries from homeassistant.data_entry_flow import FlowResult diff --git a/custom_components/sberdevices/light.py b/custom_components/sberdevices/light.py index 887fe72..1bd0afb 100755 --- a/custom_components/sberdevices/light.py +++ b/custom_components/sberdevices/light.py @@ -21,27 +21,31 @@ from .api import DeviceAPI, HomeAPI from .const import DOMAIN + # hardcode xd def get_color_temp_range(device_type: str) -> (int, int): match device_type: - case "bulb": # Sber A60 bulb - return (2700, 6500) - case "ledstrip": # SBDV-00033 led strip - return (2000, 6500) - return (2700, 6500) + case "ledstrip": # SBDV-00033 led strip + return 2000, 6500 + case "bulb": # Sber A60 bulb + return 2700, 6500 + case _: + return 2700, 6500 + H_RANGE = (0, 360) S_RANGE = (0, 100) async def async_setup_entry( - hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback ) -> None: home: HomeAPI = hass.data[DOMAIN][entry.entry_id]["home"] await home.update_devices_cache() async_add_entities( [ - SberLightEntity(DeviceAPI(home, device["id"]), "ledstrip" if "ledstrip" in device["image_set_type"] else "bulb") + SberLightEntity(DeviceAPI(home, device["id"]), + "ledstrip" if "ledstrip" in device["image_set_type"] else "bulb") for device in home.get_cached_devices().values() if "bulb" in device["image_set_type"] or "ledstrip" in device["image_set_type"] # TODO: lutiy kostyl' ] @@ -88,28 +92,29 @@ def is_on(self) -> bool: @property def supported_color_modes(self) -> set[ColorMode]: - m = { + modes = { "light_brightness": ColorMode.BRIGHTNESS, "light_colour_temp": ColorMode.COLOR_TEMP, } - v = {m[k] for k in m if self._api.get_attribute(k) is not None} + values = {modes[k] for k in modes if self._api.get_attribute(k) is not None} light_mode = self._api.get_attribute("light_mode")["enum_values"]["values"] if "white" in light_mode: - v.add(ColorMode.WHITE) + values.add(ColorMode.WHITE) if "colour" in light_mode: - v.add(ColorMode.HS) + values.add(ColorMode.HS) - return v + return values @property def color_mode(self) -> ColorMode: mode = self._api.get_state("light_mode")["enum_value"] - if mode == "white": - return ColorMode.COLOR_TEMP - elif mode == "colour": - return ColorMode.HS - else: - return ColorMode.UNKNOWN + match mode: + case "white": + return ColorMode.COLOR_TEMP + case "colour": + return ColorMode.HS + case _: + return ColorMode.UNKNOWN @property def brightness_range(self) -> tuple[int, int]: @@ -152,7 +157,7 @@ def color_temp_range(self) -> tuple[int, int]: ) @property - def color_temp_kelvin(self) -> int: + def color_temp_kelvin(self) -> int | None: if ColorMode.COLOR_TEMP not in self.supported_color_modes: return None @@ -164,10 +169,13 @@ def color_temp_kelvin(self) -> int: @property def color_range(self) -> dict[str, tuple[int, int]]: colour_values = self._api.get_attribute("light_colour")["color_values"] + h = colour_values["h"] + s = colour_values["s"] + v = colour_values["v"] return { - "h": (colour_values["h"]["min"], colour_values["h"]["max"]), - "s": (colour_values["s"]["min"], colour_values["s"]["max"]), - "v": (colour_values["v"]["min"], colour_values["v"]["max"]), + "h": (h["min"], h["max"]), + "s": (s["min"], s["max"]), + "v": (v["min"], v["max"]), } @property @@ -256,7 +264,7 @@ async def async_turn_on(self, **kwargs) -> None: brightness = kwargs.get(ATTR_BRIGHTNESS) or kwargs.get(ATTR_WHITE) if ( - self.color_mode != ColorMode.HS or ATTR_WHITE in kwargs + self.color_mode != ColorMode.HS or ATTR_WHITE in kwargs ) and brightness is not None: states.extend( ( diff --git a/custom_components/sberdevices/translations/en.json b/custom_components/sberdevices/translations/en.json index 4c14b21..2c7c352 100755 --- a/custom_components/sberdevices/translations/en.json +++ b/custom_components/sberdevices/translations/en.json @@ -1,26 +1,26 @@ { - "config": { - "abort": { - "already_configured": "Device is already configured" + "config": { + "abort": { + "already_configured": "Device is already configured" + }, + "error": { + "cannot_connect": "Failed to connect", + "invalid_auth": "Invalid authentication", + "unknown": "Unexpected error" + }, + "step": { + "user": { + "title": "Wait 10 seconds..." + }, + "finish": { + "data": { + "url": "URL" }, - "error": { - "cannot_connect": "Failed to connect", - "invalid_auth": "Invalid authentication", - "unknown": "Unexpected error" + "data_description": { + "url": "Redirect URL from the developer console" }, - "step": { - "user": { - "title": "Wait 10 seconds..." - }, - "finish": { - "data": { - "url": "URL" - }, - "data_description": { - "url": "Redirect URL from the developer console" - }, - "title": "Authorization" - } - } + "title": "Authorization" + } } + } } \ No newline at end of file diff --git a/custom_components/sberdevices/translations/ru.json b/custom_components/sberdevices/translations/ru.json new file mode 100755 index 0000000..0acc5bc --- /dev/null +++ b/custom_components/sberdevices/translations/ru.json @@ -0,0 +1,26 @@ +{ + "config": { + "abort": { + "already_configured": "Устройство уже настроено" + }, + "error": { + "cannot_connect": "Не удалось подключиться", + "invalid_auth": "Неверные данные авторизации", + "unknown": "Неизвестная ошибка" + }, + "step": { + "user": { + "title": "Подождите 10 секунд..." + }, + "finish": { + "data": { + "url": "URL" + }, + "data_description": { + "url": "URL перенаправления из консоли разработчика" + }, + "title": "Авторизация" + } + } + } +} \ No newline at end of file