From 3cd38a57e04ebffd41e06288a02ba4d8b42dd7c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=D0=BE=D0=B2=20=D0=90?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=93=D0=B5=D1=80=D0=BC=D0=B0?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2=D0=B8=D1=87?= Date: Sat, 14 Oct 2023 18:57:47 +0300 Subject: [PATCH] fix updater service --- custom_components/mega/__init__.py | 250 +++++++++++++++++------------ 1 file changed, 149 insertions(+), 101 deletions(-) diff --git a/custom_components/mega/__init__.py b/custom_components/mega/__init__.py index a4dd3f7..88960de 100644 --- a/custom_components/mega/__init__.py +++ b/custom_components/mega/__init__.py @@ -1,25 +1,57 @@ """The mega integration.""" import asyncio import logging -import typing from functools import partial import voluptuous as vol from homeassistant.const import ( - CONF_NAME, CONF_DOMAIN, - CONF_UNIT_OF_MEASUREMENT, CONF_VALUE_TEMPLATE, CONF_DEVICE_CLASS, CONF_PORT + CONF_NAME, + CONF_DOMAIN, + CONF_UNIT_OF_MEASUREMENT, + CONF_VALUE_TEMPLATE, + CONF_DEVICE_CLASS, + CONF_PORT, ) from homeassistant.core import HomeAssistant, ServiceCall from homeassistant.helpers.service import bind_hass from homeassistant.helpers import config_validation as cv from homeassistant.config_entries import ConfigEntry -from .const import DOMAIN, CONF_INVERT, CONF_RELOAD, PLATFORMS, CONF_PORTS, CONF_CUSTOM, CONF_SKIP, CONF_PORT_TO_SCAN, \ - CONF_MQTT_INPUTS, CONF_HTTP, CONF_RESPONSE_TEMPLATE, CONF_ACTION, CONF_GET_VALUE, CONF_ALLOW_HOSTS, \ - CONF_CONV_TEMPLATE, CONF_ALL, CONF_FORCE_D, CONF_DEF_RESPONSE, CONF_FORCE_I2C_SCAN, CONF_HEX_TO_FLOAT, \ - RGB_COMBINATIONS, CONF_WS28XX, CONF_ORDER, CONF_SMOOTH, CONF_LED, CONF_WHITE_SEP, CONF_CHIP, CONF_RANGE, \ - CONF_FILTER_VALUES, CONF_FILTER_SCALE, CONF_FILTER_LOW, CONF_FILTER_HIGH, CONF_FILL_NA, CONF_MEGA_ID, CONF_ADDR, \ - CONF_1WBUS +from .const import ( + DOMAIN, + CONF_INVERT, + PLATFORMS, + CONF_PORTS, + CONF_CUSTOM, + CONF_SKIP, + CONF_HTTP, + CONF_RESPONSE_TEMPLATE, + CONF_ACTION, + CONF_GET_VALUE, + CONF_ALLOW_HOSTS, + CONF_CONV_TEMPLATE, + CONF_ALL, + CONF_FORCE_D, + CONF_DEF_RESPONSE, + CONF_FORCE_I2C_SCAN, + CONF_HEX_TO_FLOAT, + RGB_COMBINATIONS, + CONF_WS28XX, + CONF_ORDER, + CONF_SMOOTH, + CONF_LED, + CONF_WHITE_SEP, + CONF_CHIP, + CONF_RANGE, + CONF_FILTER_VALUES, + CONF_FILTER_SCALE, + CONF_FILTER_LOW, + CONF_FILTER_HIGH, + CONF_FILL_NA, + CONF_MEGA_ID, + CONF_ADDR, + CONF_1WBUS, +) from .hub import MegaD from .config_flow import ConfigFlow from .http import MegaView @@ -28,58 +60,53 @@ _LOGGER = logging.getLogger(__name__) _port_n = vol.Any(int, str) -LED_LIGHT = \ - { - str: vol.Any( - { - vol.Required(CONF_PORTS): vol.Any( - vol.ExactSequence([_port_n, _port_n, _port_n]), - vol.ExactSequence([_port_n, _port_n, _port_n, _port_n]), - msg='ports must be [R, G, B] or [R, G, B, W] of integers 0..255' - ), - vol.Optional(CONF_NAME): str, - vol.Optional(CONF_WHITE_SEP, default=True): bool, - vol.Optional(CONF_SMOOTH, default=1): cv.time_period_seconds, - }, - { - vol.Required(CONF_PORT): int, - vol.Required(CONF_WS28XX): True, - vol.Optional(CONF_CHIP, default=100): int, - vol.Optional(CONF_ORDER, default='rgb'): vol.Any(*RGB_COMBINATIONS, msg=f'order must be one of {RGB_COMBINATIONS}'), - vol.Optional(CONF_SMOOTH, default=1): cv.time_period_seconds, - vol.Optional(CONF_NAME): str, - }, - ) - } +LED_LIGHT = { + str: vol.Any( + { + vol.Required(CONF_PORTS): vol.Any( + vol.ExactSequence([_port_n, _port_n, _port_n]), + vol.ExactSequence([_port_n, _port_n, _port_n, _port_n]), + msg="ports must be [R, G, B] or [R, G, B, W] of integers 0..255", + ), + vol.Optional(CONF_NAME): str, + vol.Optional(CONF_WHITE_SEP, default=True): bool, + vol.Optional(CONF_SMOOTH, default=1): cv.time_period_seconds, + }, + { + vol.Required(CONF_PORT): int, + vol.Required(CONF_WS28XX): True, + vol.Optional(CONF_CHIP, default=100): int, + vol.Optional(CONF_ORDER, default="rgb"): vol.Any( + *RGB_COMBINATIONS, msg=f"order must be one of {RGB_COMBINATIONS}" + ), + vol.Optional(CONF_SMOOTH, default=1): cv.time_period_seconds, + vol.Optional(CONF_NAME): str, + }, + ) +} CUSTOMIZE_PORT = { - vol.Optional(CONF_SKIP, description='исключить порт из сканирования', default=False): bool, - vol.Optional(CONF_FILL_NA, default='last'): vol.Any( - 'last', - 'none' - ), - vol.Optional(CONF_RANGE, description='диапазон диммирования'): [ + vol.Optional( + CONF_SKIP, description="исключить порт из сканирования", default=False + ): bool, + vol.Optional(CONF_FILL_NA, default="last"): vol.Any("last", "none"), + vol.Optional(CONF_RANGE, description="диапазон диммирования"): [ vol.Range(0, 255), vol.Range(0, 255), ], vol.Optional(CONF_INVERT, default=False): bool, - vol.Optional(CONF_NAME): vol.Any(str, { - vol.Required(str): str - }), - vol.Optional(CONF_DOMAIN): vol.Any('light', 'switch'), - vol.Optional(CONF_UNIT_OF_MEASUREMENT, description='единицы измерений, либо строка либо мепинг'): - vol.Any(str, { - vol.Required(str): str - }), - vol.Optional(CONF_DEVICE_CLASS): - vol.Any(str, { - vol.Required(str): str - }), + vol.Optional(CONF_NAME): vol.Any(str, {vol.Required(str): str}), + vol.Optional(CONF_DOMAIN): vol.Any("light", "switch"), + vol.Optional( + CONF_UNIT_OF_MEASUREMENT, + description="единицы измерений, либо строка либо мепинг", + ): vol.Any(str, {vol.Required(str): str}), + vol.Optional(CONF_DEVICE_CLASS): vol.Any(str, {vol.Required(str): str}), vol.Optional( CONF_RESPONSE_TEMPLATE, - description='шаблон ответа когда на этот порт приходит' - 'сообщение из меги '): cv.template, - vol.Optional(CONF_ACTION): cv.script_action, # пока не реализовано + description="шаблон ответа когда на этот порт приходит" "сообщение из меги ", + ): cv.template, + vol.Optional(CONF_ACTION): cv.script_action, # пока не реализовано vol.Optional(CONF_GET_VALUE, default=True): bool, vol.Optional(CONF_CONV_TEMPLATE): cv.template, vol.Optional(CONF_VALUE_TEMPLATE): cv.template, @@ -96,43 +123,48 @@ CUSTOMIZE_PORT = { vol.Optional(CONF_DEVICE_CLASS): str, vol.Optional(CONF_UNIT_OF_MEASUREMENT): str, vol.Optional(CONF_VALUE_TEMPLATE): cv.template, - } + }, } CUSTOMIZE_DS2413 = { - vol.Optional(str.lower, description='адрес и индекс устройства'): CUSTOMIZE_PORT + vol.Optional(str.lower, description="адрес и индекс устройства"): CUSTOMIZE_PORT } def extender(x): - if isinstance(x, str) and 'e' in x: + if isinstance(x, str) and "e" in x: return x else: raise ValueError('must has "e" in port name') -OWBUS = vol.Schema({ - vol.Required(CONF_PORT): vol.Any(vol.Coerce(int), vol.Coerce(str)), - vol.Required(CONF_MEGA_ID): vol.Coerce(str), - vol.Required(CONF_ADDR): [str], -}) + +OWBUS = vol.Schema( + { + vol.Required(CONF_PORT): vol.Any(vol.Coerce(int), vol.Coerce(str)), + vol.Required(CONF_MEGA_ID): vol.Coerce(str), + vol.Required(CONF_ADDR): [str], + } +) CONFIG_SCHEMA = vol.Schema( { DOMAIN: { vol.Optional(CONF_ALLOW_HOSTS): [str], - vol.Optional('entities'): { - vol.Optional(str): vol.Any( - CUSTOMIZE_PORT, - CUSTOMIZE_DS2413 - )}, - vol.Optional(vol.Any(str, int), description='id меги из веб-интерфейса'): { - vol.Optional(CONF_FORCE_D, description='Принудительно слать d после срабатывания входа', default=False): bool, + vol.Optional("entities"): { + vol.Optional(str): vol.Any(CUSTOMIZE_PORT, CUSTOMIZE_DS2413) + }, + vol.Optional(vol.Any(str, int), description="id меги из веб-интерфейса"): { vol.Optional( - CONF_DEF_RESPONSE, - description='Ответ по умолчанию', - default=None + CONF_FORCE_D, + description="Принудительно слать d после срабатывания входа", + default=False, + ): bool, + vol.Optional( + CONF_DEF_RESPONSE, description="Ответ по умолчанию", default=None ): vol.Any(cv.template, None), vol.Optional(CONF_LED): LED_LIGHT, - vol.Optional(vol.Any(int, extender), description='номер порта'): vol.Any( + vol.Optional( + vol.Any(int, extender), description="номер порта" + ): vol.Any( CUSTOMIZE_PORT, CUSTOMIZE_DS2413, ), @@ -141,14 +173,14 @@ CONFIG_SCHEMA = vol.Schema( vol.Optional(CONF_FILTER_LOW): vol.Coerce(float), vol.Optional(CONF_FILTER_HIGH): vol.Coerce(float), }, - vol.Optional(CONF_1WBUS): [OWBUS] + vol.Optional(CONF_1WBUS): [OWBUS], } }, extra=vol.ALLOW_EXTRA, ) -ALIVE_STATE = 'alive' -DEF_ID = 'def' +ALIVE_STATE = "alive" +DEF_ID = "def" _POLL_TASKS = {} _hubs = {} _subs = {} @@ -162,29 +194,40 @@ async def async_setup(hass: HomeAssistant, config: dict): view.allowed_hosts |= set(config.get(DOMAIN, {}).get(CONF_ALLOW_HOSTS, [])) hass.http.register_view(view) hass.services.async_register( - DOMAIN, 'save', partial(_save_service, hass), schema=vol.Schema({ - vol.Optional('mega_id'): str - }) + DOMAIN, + "save", + partial(_save_service, hass), + schema=vol.Schema({vol.Optional("mega_id"): str}), ) hass.services.async_register( - DOMAIN, 'get_port', partial(_get_port, hass), schema=vol.Schema({ - vol.Optional('mega_id'): str, - vol.Optional('port'): vol.Any(int, [int]), - }) + DOMAIN, + "get_port", + partial(_get_port, hass), + schema=vol.Schema( + { + vol.Optional("mega_id"): str, + vol.Optional("port"): vol.Any(int, [int]), + } + ), ) hass.services.async_register( - DOMAIN, 'run_cmd', partial(_run_cmd, hass), schema=vol.Schema({ - vol.Optional('port'): int, - vol.Required('cmd'): str, - vol.Optional('mega_id'): str, - }) + DOMAIN, + "run_cmd", + partial(_run_cmd, hass), + schema=vol.Schema( + { + vol.Optional("port"): int, + vol.Required("cmd"): str, + vol.Optional("mega_id"): str, + } + ), ) return True async def get_hub(hass, entry): - id = entry.data.get('id', entry.entry_id) + id = entry.data.get("id", entry.entry_id) data = dict(entry.data) data.update(entry.options or {}) data.update(id=id) @@ -194,7 +237,7 @@ async def get_hub(hass, entry): async def _add_mega(hass: HomeAssistant, entry: ConfigEntry): - id = entry.data.get('id', entry.entry_id) + id = entry.data.get("id", entry.entry_id) hub = await get_hub(hass, entry) hub.fw = await hub.get_fw() hass.data[DOMAIN][id] = hub @@ -213,9 +256,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): await hub.start() for platform in PLATFORMS: hass.async_create_task( - hass.config_entries.async_forward_entry_setup( - entry, platform - ) + hass.config_entries.async_forward_entry_setup(entry, platform) ) await hub.updater.async_refresh() return True @@ -237,11 +278,11 @@ async def updater(hass: HomeAssistant, entry: ConfigEntry): async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None: """Handle removal of an entry.""" - id = entry.data.get('id', entry.entry_id) + id = entry.data.get("id", entry.entry_id) hub: MegaD = hass.data[DOMAIN].get(id) if hub is None: return True - _LOGGER.debug(f'remove {id}') + _LOGGER.debug(f"remove {id}") _hubs.pop(id, None) hass.data[DOMAIN].pop(id, None) hass.data[DOMAIN][CONF_ALL].pop(id, None) @@ -255,19 +296,24 @@ async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None: await hub.stop() return True + async_unload_entry = async_remove_entry async def async_migrate_entry(hass, config_entry: ConfigEntry): """Migrate old entry.""" - _LOGGER.debug("Migrating from version %s to version %s", config_entry.version, ConfigFlow.VERSION) + _LOGGER.debug( + "Migrating from version %s to version %s", + config_entry.version, + ConfigFlow.VERSION, + ) hub = await get_hub(hass, config_entry) new = dict(config_entry.data) await hub.start() cfg = await hub.get_config() await hub.stop() new.update(cfg) - _LOGGER.debug(f'new config: %s', new) + _LOGGER.debug(f"new config: %s", new) config_entry.data = new config_entry.version = ConfigFlow.VERSION @@ -277,7 +323,7 @@ async def async_migrate_entry(hass, config_entry: ConfigEntry): async def _save_service(hass: HomeAssistant, call: ServiceCall): - mega_id = call.data.get('mega_id') + mega_id = call.data.get("mega_id") if mega_id: hub: MegaD = hass.data[DOMAIN][mega_id] await hub.save() @@ -289,8 +335,8 @@ async def _save_service(hass: HomeAssistant, call: ServiceCall): @bind_hass async def _get_port(hass: HomeAssistant, call: ServiceCall): - port = call.data.get('port') - mega_id = call.data.get('mega_id') + port = call.data.get("port") + mega_id = call.data.get("mega_id") if mega_id: hub: MegaD = hass.data[DOMAIN][mega_id] if port is None: @@ -300,6 +346,7 @@ async def _get_port(hass: HomeAssistant, call: ServiceCall): elif isinstance(port, list): for x in port: await hub.get_port(x) + hub.updater.async_set_updated_data(hub.values) else: for hub in hass.data[DOMAIN][CONF_ALL].values(): if not isinstance(hub, MegaD): @@ -311,12 +358,13 @@ async def _get_port(hass: HomeAssistant, call: ServiceCall): elif isinstance(port, list): for x in port: await hub.get_port(x) + hub.updater.async_set_updated_data(hub.values) @bind_hass async def _run_cmd(hass: HomeAssistant, call: ServiceCall): - mega_id = call.data.get('mega_id') - cmd = call.data.get('cmd') + mega_id = call.data.get("mega_id") + cmd = call.data.get("cmd") if mega_id: hub: MegaD = hass.data[DOMAIN][mega_id] await hub.request(cmd=cmd)