From 8ace0587f655b26710d614a777064b9527030219 Mon Sep 17 00:00:00 2001 From: Paul Daumlechner Date: Mon, 2 Nov 2020 21:55:32 +0000 Subject: [PATCH 01/13] Velux refactor --- homeassistant/components/velux/__init__.py | 89 ++++++++--------- homeassistant/components/velux/config_flow.py | 99 +++++++++++++++++++ homeassistant/components/velux/const.py | 4 + homeassistant/components/velux/cover.py | 62 ++++++++++-- homeassistant/components/velux/manifest.json | 6 +- homeassistant/components/velux/scene.py | 13 ++- homeassistant/components/velux/services.yaml | 4 + homeassistant/components/velux/strings.json | 23 +++++ .../components/velux/translations/en.json | 23 +++++ homeassistant/generated/config_flows.py | 1 + homeassistant/generated/zeroconf.py | 3 +- requirements_all.txt | 2 +- 12 files changed, 268 insertions(+), 61 deletions(-) create mode 100644 homeassistant/components/velux/config_flow.py create mode 100644 homeassistant/components/velux/const.py create mode 100644 homeassistant/components/velux/services.yaml create mode 100644 homeassistant/components/velux/strings.json create mode 100644 homeassistant/components/velux/translations/en.json diff --git a/homeassistant/components/velux/__init__.py b/homeassistant/components/velux/__init__.py index bac65c969cff30..d53b7169ef9063 100644 --- a/homeassistant/components/velux/__init__.py +++ b/homeassistant/components/velux/__init__.py @@ -1,70 +1,63 @@ """Support for VELUX KLF 200 devices.""" import logging -from pyvlx import PyVLX, PyVLXException -import voluptuous as vol +from pyvlx import PyVLX -from homeassistant.const import CONF_HOST, CONF_PASSWORD, EVENT_HOMEASSISTANT_STOP -from homeassistant.helpers import discovery -import homeassistant.helpers.config_validation as cv +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import CONF_HOST, CONF_PASSWORD +from homeassistant.core import HomeAssistant + +from .const import DOMAIN, PLATFORMS -DOMAIN = "velux" -DATA_VELUX = "data_velux" -SUPPORTED_DOMAINS = ["cover", "scene"] _LOGGER = logging.getLogger(__name__) -CONFIG_SCHEMA = vol.Schema( - { - DOMAIN: vol.Schema( - {vol.Required(CONF_HOST): cv.string, vol.Required(CONF_PASSWORD): cv.string} + +async def async_setup(hass, config): + """Set up the Velux KLF platform via configuration.yaml.""" + if DOMAIN in config: + hass.async_create_task( + hass.config_entries.flow.async_init( + DOMAIN, context={"source": "import"}, data=config[DOMAIN] + ) ) - }, - extra=vol.ALLOW_EXTRA, -) + return True -async def async_setup(hass, config): - """Set up the velux component.""" - try: - hass.data[DATA_VELUX] = VeluxModule(hass, config[DOMAIN]) - hass.data[DATA_VELUX].setup() - await hass.data[DATA_VELUX].async_start() +async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): + """Set up the Velux KLF platforms via Config Flow.""" + _LOGGER.debug("Setting up velux entry: %s", entry.data) + host = entry.data[CONF_HOST] + password = entry.data[CONF_PASSWORD] + gateway = PyVLX(host=host, password=password) + + hass.data.setdefault(DOMAIN, {}) + hass.data[DOMAIN][entry.entry_id] = gateway - except PyVLXException as ex: - _LOGGER.exception("Can't connect to velux interface: %s", ex) + try: + await gateway.load_nodes() + await gateway.load_scenes() + except ConnectionRefusedError: return False - for component in SUPPORTED_DOMAINS: + for component in PLATFORMS: hass.async_create_task( - discovery.async_load_platform(hass, component, DOMAIN, {}, config) + hass.config_entries.async_forward_entry_setup(entry, component) ) - return True + async def async_reboot_gateway(service_call): + await gateway.reboot_gateway() -class VeluxModule: - """Abstraction for velux component.""" + hass.services.async_register(DOMAIN, "reboot_gateway", async_reboot_gateway) - def __init__(self, hass, domain_config): - """Initialize for velux component.""" - self.pyvlx = None - self._hass = hass - self._domain_config = domain_config + return True - def setup(self): - """Velux component setup.""" - async def on_hass_stop(event): - """Close connection when hass stops.""" - _LOGGER.debug("Velux interface terminated") - await self.pyvlx.disconnect() +async def async_unload_entry(hass, entry): + """Unloading the Velux platform.""" + gateway = hass.data[DOMAIN][entry.entry_id] + await gateway.disconnect() - self._hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, on_hass_stop) - host = self._domain_config.get(CONF_HOST) - password = self._domain_config.get(CONF_PASSWORD) - self.pyvlx = PyVLX(host=host, password=password) + for component in PLATFORMS: + await hass.config_entries.async_forward_entry_unload(entry, component) - async def async_start(self): - """Start velux component.""" - _LOGGER.debug("Velux interface started") - await self.pyvlx.load_scenes() - await self.pyvlx.load_nodes() + return True diff --git a/homeassistant/components/velux/config_flow.py b/homeassistant/components/velux/config_flow.py new file mode 100644 index 00000000000000..e1cc5893d288a4 --- /dev/null +++ b/homeassistant/components/velux/config_flow.py @@ -0,0 +1,99 @@ +"""SVelux component config flow.""" +# https://developers.home-assistant.io/docs/config_entries_config_flow_handler#defining-your-config-flow +import logging + +from pyvlx import PyVLX, PyVLXException +import voluptuous as vol + +from homeassistant import config_entries +from homeassistant.const import CONF_HOST, CONF_PASSWORD + +from .const import DOMAIN + +_LOGGER = logging.getLogger(__name__) + +RESULT_AUTH_FAILED = "connection_failed" +RESULT_SUCCESS = "success" + + +class VeluxConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): + """Velux config flow.""" + + def __init__(self): + """Initialize.""" + self._velux = None + self._host = None + self._password = None + self._hostname = None + self.bridge = None + + def _get_entry(self): + return self.async_create_entry( + title=self._host, + data={CONF_HOST: self._host, CONF_PASSWORD: self._password}, + ) + + async def _try_connect(self): + """Try to connect and check auth.""" + _LOGGER.debug("Try to connect to KLF200 via Config Flow") + self.bridge = PyVLX(host=self._host, password=self._password) + try: + await self.bridge.connect() + await self.bridge.disconnect() + return RESULT_SUCCESS + except PyVLXException: + _LOGGER.debug(PyVLXException) + return RESULT_AUTH_FAILED + except OSError: + _LOGGER.debug(OSError) + return RESULT_AUTH_FAILED + + async def async_step_import(self, user_input=None): + """Handle configuration by yaml file.""" + return await self.async_step_user(user_input) + + async def async_step_user(self, user_input=None): + """Handle configuration via user input.""" + errors = {} + if user_input is not None: + self._host = user_input[CONF_HOST] + self._password = user_input[CONF_PASSWORD] + + result = await self._try_connect() + if result == RESULT_SUCCESS: + await self.async_set_unique_id(self._host) + self._abort_if_unique_id_configured() + return self._get_entry() + else: + errors["base"] = RESULT_AUTH_FAILED + + data_schema = vol.Schema( + { + vol.Required(CONF_HOST, default=self._host): str, + vol.Required(CONF_PASSWORD, default=self._password): str, + } + ) + + return self.async_show_form( + step_id="user", data_schema=data_schema, errors=errors + ) + + async def async_step_unignore(self, user_input): + """Rediscover a previously ignored discover.""" + unique_id = user_input["unique_id"] + await self.async_set_unique_id(unique_id) + return await self.async_step_user() + + async def async_step_zeroconf(self, info): + """Handle discovery by zeroconf.""" + if info is None: + return self.async_abort(reason="connection_error") + + if not info.get("hostname") or not info["hostname"].startswith("VELUX_KLF_LAN"): + return self.async_abort(reason="not_velux_klf200") + + self._host = info.get("host") + await self.async_set_unique_id(self._host) + self._abort_if_unique_id_configured() + + return await self.async_step_user() diff --git a/homeassistant/components/velux/const.py b/homeassistant/components/velux/const.py new file mode 100644 index 00000000000000..dd61602b9c1328 --- /dev/null +++ b/homeassistant/components/velux/const.py @@ -0,0 +1,4 @@ +"""Constants for Valux Integration.""" + +DOMAIN = "velux" +PLATFORMS = ["cover", "scene"] diff --git a/homeassistant/components/velux/cover.py b/homeassistant/components/velux/cover.py index e8e210c1e531d4..ac76b6409ed653 100644 --- a/homeassistant/components/velux/cover.py +++ b/homeassistant/components/velux/cover.py @@ -1,9 +1,12 @@ """Support for Velux covers.""" +import logging + from pyvlx import OpeningDevice, Position from pyvlx.opening_device import Awning, Blind, GarageDoor, Gate, RollerShutter, Window from homeassistant.components.cover import ( ATTR_POSITION, + ATTR_TILT_POSITION, DEVICE_CLASS_AWNING, DEVICE_CLASS_BLIND, DEVICE_CLASS_GARAGE, @@ -11,20 +14,31 @@ DEVICE_CLASS_SHUTTER, DEVICE_CLASS_WINDOW, SUPPORT_CLOSE, + SUPPORT_CLOSE_TILT, SUPPORT_OPEN, + SUPPORT_OPEN_TILT, SUPPORT_SET_POSITION, + SUPPORT_SET_TILT_POSITION, SUPPORT_STOP, + SUPPORT_STOP_TILT, CoverEntity, ) from homeassistant.core import callback -from . import DATA_VELUX +from .const import DOMAIN + +_LOGGER = logging.getLogger(__name__) -async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): +async def async_setup_entry(hass, entry, async_add_entities): """Set up cover(s) for Velux platform.""" + _LOGGER.debug("Entered velux cover setup") + entities = [] - for node in hass.data[DATA_VELUX].pyvlx.nodes: + gateway = hass.data[DOMAIN][entry.entry_id] + + for node in gateway.nodes: + _LOGGER.debug("Node will be added: %s", node.name) if isinstance(node, OpeningDevice): entities.append(VeluxCover(node)) async_add_entities(entities) @@ -54,7 +68,7 @@ async def async_added_to_hass(self): @property def unique_id(self): """Return the unique ID of this cover.""" - return self.node.serial_number + return self.node.node_id @property def name(self): @@ -69,13 +83,29 @@ def should_poll(self): @property def supported_features(self): """Flag supported features.""" - return SUPPORT_OPEN | SUPPORT_CLOSE | SUPPORT_SET_POSITION | SUPPORT_STOP + supported_features = ( + SUPPORT_OPEN | SUPPORT_CLOSE | SUPPORT_SET_POSITION | SUPPORT_STOP + ) + if self.current_cover_tilt_position is not None: + supported_features |= ( + SUPPORT_OPEN_TILT + | SUPPORT_CLOSE_TILT + | SUPPORT_SET_TILT_POSITION + | SUPPORT_STOP_TILT + ) + return supported_features @property def current_cover_position(self): """Return the current position of the cover.""" return 100 - self.node.position.position_percent + @property + def current_cover_tilt_position(self): + """Return the current position of the cover.""" + if isinstance(self.node, Blind): + return 100 - self.node.orientation.position_percent + @property def device_class(self): """Define this cover as either awning, blind, garage, gate, shutter or window.""" @@ -110,7 +140,6 @@ async def async_set_cover_position(self, **kwargs): """Move the cover to a specific position.""" if ATTR_POSITION in kwargs: position_percent = 100 - kwargs[ATTR_POSITION] - await self.node.set_position( Position(position_percent=position_percent), wait_for_completion=False ) @@ -118,3 +147,24 @@ async def async_set_cover_position(self, **kwargs): async def async_stop_cover(self, **kwargs): """Stop the cover.""" await self.node.stop(wait_for_completion=False) + + async def async_close_cover_tilt(self, **kwargs): + """Close the cover.""" + await self.node.close_orientation(wait_for_completion=False) + + async def async_open_cover_tilt(self, **kwargs): + """Close the cover.""" + await self.node.open_orientation(wait_for_completion=False) + + async def async_stop_cover_tilt(self, **kwargs): + """Close the cover.""" + await self.node.stop_orientation(wait_for_completion=False) + + async def async_set_cover_tilt_position(self, **kwargs): + """Move the cover to a specific position.""" + if ATTR_TILT_POSITION in kwargs: + position_percent = 100 - kwargs[ATTR_TILT_POSITION] + orientation = Position(position_percent=position_percent) + await self.node.set_orientation( + orientation=orientation, wait_for_completion=False + ) diff --git a/homeassistant/components/velux/manifest.json b/homeassistant/components/velux/manifest.json index 73306bca7b5d68..134f1c360968f1 100644 --- a/homeassistant/components/velux/manifest.json +++ b/homeassistant/components/velux/manifest.json @@ -2,6 +2,8 @@ "domain": "velux", "name": "Velux", "documentation": "https://www.home-assistant.io/integrations/velux", - "requirements": ["pyvlx==0.2.16"], - "codeowners": ["@Julius2342"] + "codeowners": ["@Julius2342"], + "requirements": ["pyvlx==0.2.18"], + "zeroconf": ["_http._tcp.local."], + "config_flow": true } diff --git a/homeassistant/components/velux/scene.py b/homeassistant/components/velux/scene.py index 96ff0558fff791..78dff91a3e9bce 100644 --- a/homeassistant/components/velux/scene.py +++ b/homeassistant/components/velux/scene.py @@ -3,12 +3,14 @@ from homeassistant.components.scene import Scene -from . import _LOGGER, DATA_VELUX +from . import _LOGGER +from .const import DOMAIN -async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): +async def async_setup_entry(hass, entry, async_add_entities): """Set up the scenes for Velux platform.""" - entities = [VeluxScene(scene) for scene in hass.data[DATA_VELUX].pyvlx.scenes] + gateway = hass.data[DOMAIN][entry.entry_id] + entities = [VeluxScene(scene) for scene in gateway.scenes] async_add_entities(entities) @@ -25,6 +27,11 @@ def name(self): """Return the name of the scene.""" return self.scene.name + @property + def unique_id(self): + """Return the unique ID of this cover.""" + return self.scene.scene_id + async def async_activate(self, **kwargs: Any) -> None: """Activate the scene.""" await self.scene.run(wait_for_completion=False) diff --git a/homeassistant/components/velux/services.yaml b/homeassistant/components/velux/services.yaml new file mode 100644 index 00000000000000..2460db0bbb02e9 --- /dev/null +++ b/homeassistant/components/velux/services.yaml @@ -0,0 +1,4 @@ +# Velux Integration services + +reboot_gateway: + description: Reboots the KLF200 Gateway. diff --git a/homeassistant/components/velux/strings.json b/homeassistant/components/velux/strings.json new file mode 100644 index 00000000000000..09f39a14205d1a --- /dev/null +++ b/homeassistant/components/velux/strings.json @@ -0,0 +1,23 @@ +{ + "title": "Velux KLF200 Gateway", + "config": { + "step": { + "user": { + "title": "Pick the KLF200 Gateway", + "description": "You will find the password on the backside of the gateway", + "data": { + "host": "Host", + "password": "Password" + } + } + }, + "error": { + "connection_failed": "Connection could not be established, please check your input." + }, + "abort": { + "not_velux_klf200": "The discovered device is not a Velux KLF gateway", + "connection_error": "No information provided from zeroconf", + "already_configured": "Velux KLF200 gateway is already configured" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/velux/translations/en.json b/homeassistant/components/velux/translations/en.json new file mode 100644 index 00000000000000..951e77eac49fb5 --- /dev/null +++ b/homeassistant/components/velux/translations/en.json @@ -0,0 +1,23 @@ +{ + "config": { + "abort": { + "already_configured": "Velux KLF200 gateway is already configured", + "connection_error": "No information provided from zeroconf", + "not_velux_klf200": "The discovered device is not a Velux KLF gateway" + }, + "error": { + "connection_failed": "Connection could not be established, please check your input." + }, + "step": { + "user": { + "data": { + "host": "Host", + "password": "Password" + }, + "description": "You will find the password on the backside of the gateway", + "title": "Pick the KLF200 Gateway" + } + } + }, + "title": "Velux KLF200 Gateway" +} \ No newline at end of file diff --git a/homeassistant/generated/config_flows.py b/homeassistant/generated/config_flows.py index 05ce927c7739dd..110f43bb24979c 100644 --- a/homeassistant/generated/config_flows.py +++ b/homeassistant/generated/config_flows.py @@ -195,6 +195,7 @@ "upb", "upnp", "velbus", + "velux", "vera", "vesync", "vilfo", diff --git a/homeassistant/generated/zeroconf.py b/homeassistant/generated/zeroconf.py index ba12b4ec4dec12..50b772d7b4b46e 100644 --- a/homeassistant/generated/zeroconf.py +++ b/homeassistant/generated/zeroconf.py @@ -38,7 +38,8 @@ "homekit_controller" ], "_http._tcp.local.": [ - "shelly" + "shelly", + "velux" ], "_ipp._tcp.local.": [ "ipp" diff --git a/requirements_all.txt b/requirements_all.txt index 6b6c2fcd070b67..497fb408d9394a 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1833,7 +1833,7 @@ pyvesync==1.1.0 pyvizio==0.1.56 # homeassistant.components.velux -pyvlx==0.2.16 +pyvlx==0.2.18 # homeassistant.components.volumio pyvolumio==0.1.2 From 00247cf64fcd50e15041e5cf4af8b08ac67853bb Mon Sep 17 00:00:00 2001 From: Paul Daumlechner Date: Tue, 3 Nov 2020 20:50:40 +0000 Subject: [PATCH 02/13] several updates --- homeassistant/components/velux/__init__.py | 9 ++-- homeassistant/components/velux/config_flow.py | 42 ++++++++----------- homeassistant/components/velux/cover.py | 9 ++-- homeassistant/components/velux/manifest.json | 14 +++++-- homeassistant/components/velux/strings.json | 13 +++--- .../components/velux/translations/en.json | 13 +++--- 6 files changed, 48 insertions(+), 52 deletions(-) diff --git a/homeassistant/components/velux/__init__.py b/homeassistant/components/velux/__init__.py index d53b7169ef9063..64bd6508e7b904 100644 --- a/homeassistant/components/velux/__init__.py +++ b/homeassistant/components/velux/__init__.py @@ -33,11 +33,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN][entry.entry_id] = gateway - try: - await gateway.load_nodes() - await gateway.load_scenes() - except ConnectionRefusedError: - return False + await gateway.connect() + await gateway.load_nodes() + await gateway.load_scenes() for component in PLATFORMS: hass.async_create_task( @@ -55,6 +53,7 @@ async def async_reboot_gateway(service_call): async def async_unload_entry(hass, entry): """Unloading the Velux platform.""" gateway = hass.data[DOMAIN][entry.entry_id] + await gateway.reboot_gateway() await gateway.disconnect() for component in PLATFORMS: diff --git a/homeassistant/components/velux/config_flow.py b/homeassistant/components/velux/config_flow.py index e1cc5893d288a4..d4513fbd9aa9d0 100644 --- a/homeassistant/components/velux/config_flow.py +++ b/homeassistant/components/velux/config_flow.py @@ -1,4 +1,4 @@ -"""SVelux component config flow.""" +"""Velux component config flow.""" # https://developers.home-assistant.io/docs/config_entries_config_flow_handler#defining-your-config-flow import logging @@ -33,21 +33,6 @@ def _get_entry(self): data={CONF_HOST: self._host, CONF_PASSWORD: self._password}, ) - async def _try_connect(self): - """Try to connect and check auth.""" - _LOGGER.debug("Try to connect to KLF200 via Config Flow") - self.bridge = PyVLX(host=self._host, password=self._password) - try: - await self.bridge.connect() - await self.bridge.disconnect() - return RESULT_SUCCESS - except PyVLXException: - _LOGGER.debug(PyVLXException) - return RESULT_AUTH_FAILED - except OSError: - _LOGGER.debug(OSError) - return RESULT_AUTH_FAILED - async def async_step_import(self, user_input=None): """Handle configuration by yaml file.""" return await self.async_step_user(user_input) @@ -58,14 +43,19 @@ async def async_step_user(self, user_input=None): if user_input is not None: self._host = user_input[CONF_HOST] self._password = user_input[CONF_PASSWORD] - - result = await self._try_connect() - if result == RESULT_SUCCESS: + self.bridge = PyVLX(host=self._host, password=self._password) + try: + await self.bridge.connect() + await self.bridge.disconnect() await self.async_set_unique_id(self._host) self._abort_if_unique_id_configured() return self._get_entry() + except PyVLXException: + errors["base"] = "invalid_auth" + except OSError: + errors["base"] = "invalid_host" else: - errors["base"] = RESULT_AUTH_FAILED + errors["base"] = "cannot_connect" data_schema = vol.Schema( { @@ -86,13 +76,15 @@ async def async_step_unignore(self, user_input): async def async_step_zeroconf(self, info): """Handle discovery by zeroconf.""" - if info is None: - return self.async_abort(reason="connection_error") - - if not info.get("hostname") or not info["hostname"].startswith("VELUX_KLF_LAN"): - return self.async_abort(reason="not_velux_klf200") + if ( + info is None + or not info.get("hostname") + or not info["hostname"].startswith("VELUX_KLF_LAN") + ): + return self.async_abort(reason="no_devices_found") self._host = info.get("host") + await self.async_set_unique_id(self._host) self._abort_if_unique_id_configured() diff --git a/homeassistant/components/velux/cover.py b/homeassistant/components/velux/cover.py index ac76b6409ed653..db2d258bdb9933 100644 --- a/homeassistant/components/velux/cover.py +++ b/homeassistant/components/velux/cover.py @@ -32,11 +32,8 @@ async def async_setup_entry(hass, entry, async_add_entities): """Set up cover(s) for Velux platform.""" - _LOGGER.debug("Entered velux cover setup") - entities = [] gateway = hass.data[DOMAIN][entry.entry_id] - for node in gateway.nodes: _LOGGER.debug("Node will be added: %s", node.name) if isinstance(node, OpeningDevice): @@ -149,15 +146,15 @@ async def async_stop_cover(self, **kwargs): await self.node.stop(wait_for_completion=False) async def async_close_cover_tilt(self, **kwargs): - """Close the cover.""" + """Close cover tilt.""" await self.node.close_orientation(wait_for_completion=False) async def async_open_cover_tilt(self, **kwargs): - """Close the cover.""" + """Open cover tilt.""" await self.node.open_orientation(wait_for_completion=False) async def async_stop_cover_tilt(self, **kwargs): - """Close the cover.""" + """Stop cover tilt.""" await self.node.stop_orientation(wait_for_completion=False) async def async_set_cover_tilt_position(self, **kwargs): diff --git a/homeassistant/components/velux/manifest.json b/homeassistant/components/velux/manifest.json index 134f1c360968f1..61110bb9741b88 100644 --- a/homeassistant/components/velux/manifest.json +++ b/homeassistant/components/velux/manifest.json @@ -2,8 +2,14 @@ "domain": "velux", "name": "Velux", "documentation": "https://www.home-assistant.io/integrations/velux", - "codeowners": ["@Julius2342"], - "requirements": ["pyvlx==0.2.18"], - "zeroconf": ["_http._tcp.local."], + "codeowners": [ + "@Julius2342" + ], + "requirements": [ + "pyvlx==0.2.18" + ], + "zeroconf": [ + "_http._tcp.local." + ], "config_flow": true -} +} \ No newline at end of file diff --git a/homeassistant/components/velux/strings.json b/homeassistant/components/velux/strings.json index 09f39a14205d1a..6179bfd342497b 100644 --- a/homeassistant/components/velux/strings.json +++ b/homeassistant/components/velux/strings.json @@ -3,8 +3,8 @@ "config": { "step": { "user": { - "title": "Pick the KLF200 Gateway", - "description": "You will find the password on the backside of the gateway", + "title": "Configure the KLF200 Gateway", + "description": "Please enter your password, you will find it on the backside of the KLF200", "data": { "host": "Host", "password": "Password" @@ -12,12 +12,13 @@ } }, "error": { - "connection_failed": "Connection could not be established, please check your input." + "cannot_connect": "Failed to connect", + "invalid_auth": "Invalid authentication", + "invalid_host": "Invalid hostname or IP address" }, "abort": { - "not_velux_klf200": "The discovered device is not a Velux KLF gateway", - "connection_error": "No information provided from zeroconf", - "already_configured": "Velux KLF200 gateway is already configured" + "no_devices_found": "No devices found on the network", + "already_configured_device": "Device is already configured" } } } \ No newline at end of file diff --git a/homeassistant/components/velux/translations/en.json b/homeassistant/components/velux/translations/en.json index 951e77eac49fb5..4b522bc6ea4fa2 100644 --- a/homeassistant/components/velux/translations/en.json +++ b/homeassistant/components/velux/translations/en.json @@ -1,12 +1,13 @@ { "config": { "abort": { - "already_configured": "Velux KLF200 gateway is already configured", - "connection_error": "No information provided from zeroconf", - "not_velux_klf200": "The discovered device is not a Velux KLF gateway" + "already_configured_device": "Device is already configured", + "no_devices_found": "No devices found on the network" }, "error": { - "connection_failed": "Connection could not be established, please check your input." + "cannot_connect": "Failed to connect", + "invalid_auth": "Invalid authentication", + "invalid_host": "Invalid hostname or IP address" }, "step": { "user": { @@ -14,8 +15,8 @@ "host": "Host", "password": "Password" }, - "description": "You will find the password on the backside of the gateway", - "title": "Pick the KLF200 Gateway" + "description": "Please enter your password, you will find it on the backside of the KLF200", + "title": "Configure the KLF200 Gateway" } } }, From 7322c49f62f0151024d43633b994670974b03352 Mon Sep 17 00:00:00 2001 From: Paul Daumlechner Date: Thu, 5 Nov 2020 20:38:02 +0100 Subject: [PATCH 03/13] Update en.json --- .../components/velux/translations/en.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/velux/translations/en.json b/homeassistant/components/velux/translations/en.json index 4b522bc6ea4fa2..6ef97afce85bc8 100644 --- a/homeassistant/components/velux/translations/en.json +++ b/homeassistant/components/velux/translations/en.json @@ -1,19 +1,19 @@ { "config": { "abort": { - "already_configured_device": "Device is already configured", - "no_devices_found": "No devices found on the network" + "already_configured_device": "[%key:common::config_flow::error::already_configured_device%]", + "no_devices_found": "[%key:common::config_flow::error::no_devices_found%]" }, "error": { - "cannot_connect": "Failed to connect", - "invalid_auth": "Invalid authentication", - "invalid_host": "Invalid hostname or IP address" + "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", + "invalid_auth": "[%key:common::config_flow::error::invalid_auth%]", + "invalid_host": "[%key:common::config_flow::error::invalid_host%]" }, "step": { "user": { "data": { - "host": "Host", - "password": "Password" + "host": "[%key:common::config_flow::data::host%]", + "password": "[%key:common::config_flow::data::password%]" }, "description": "Please enter your password, you will find it on the backside of the KLF200", "title": "Configure the KLF200 Gateway" @@ -21,4 +21,4 @@ } }, "title": "Velux KLF200 Gateway" -} \ No newline at end of file +} From b54b05e90ba0423fb49c0fd6603ab99312d95ae4 Mon Sep 17 00:00:00 2001 From: Paul Daumlechner Date: Thu, 5 Nov 2020 20:38:28 +0100 Subject: [PATCH 04/13] Update strings.json --- homeassistant/components/velux/strings.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/velux/strings.json b/homeassistant/components/velux/strings.json index 6179bfd342497b..592f2ced405846 100644 --- a/homeassistant/components/velux/strings.json +++ b/homeassistant/components/velux/strings.json @@ -6,19 +6,19 @@ "title": "Configure the KLF200 Gateway", "description": "Please enter your password, you will find it on the backside of the KLF200", "data": { - "host": "Host", - "password": "Password" + "host": "[%key:common::config_flow::data::host%]", + "password": "[%key:common::config_flow::data::password%]" } } }, "error": { - "cannot_connect": "Failed to connect", - "invalid_auth": "Invalid authentication", - "invalid_host": "Invalid hostname or IP address" + "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", + "invalid_auth": "[%key:common::config_flow::error::invalid_auth%]", + "invalid_host": "[%key:common::config_flow::error::invalid_host%]" }, "abort": { - "no_devices_found": "No devices found on the network", - "already_configured_device": "Device is already configured" + "no_devices_found": "[%key:common::config_flow::abort::no_devices_found%]", + "already_configured": "[%key:common::config_flow::abort::already_configured_device%]" } } -} \ No newline at end of file +} From 9713708715061ff94d23df4be5f13505ca5f851b Mon Sep 17 00:00:00 2001 From: Paul Daumlechner Date: Thu, 5 Nov 2020 21:16:14 +0100 Subject: [PATCH 05/13] Update en.json --- .../components/velux/translations/en.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/velux/translations/en.json b/homeassistant/components/velux/translations/en.json index 6ef97afce85bc8..f894a66e028613 100644 --- a/homeassistant/components/velux/translations/en.json +++ b/homeassistant/components/velux/translations/en.json @@ -1,19 +1,19 @@ { "config": { "abort": { - "already_configured_device": "[%key:common::config_flow::error::already_configured_device%]", - "no_devices_found": "[%key:common::config_flow::error::no_devices_found%]" + "already_configured_device": "Device is already configured", + "no_devices_found": "No devices found on the network" }, "error": { - "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", - "invalid_auth": "[%key:common::config_flow::error::invalid_auth%]", - "invalid_host": "[%key:common::config_flow::error::invalid_host%]" + "cannot_connect": "Failed to connect", + "invalid_auth": "Invalid authentication", + "invalid_host": "Invalid hostname or IP address", }, "step": { "user": { "data": { - "host": "[%key:common::config_flow::data::host%]", - "password": "[%key:common::config_flow::data::password%]" + "host": "Host", + "password": "Password" }, "description": "Please enter your password, you will find it on the backside of the KLF200", "title": "Configure the KLF200 Gateway" From a81e9fedd075e482224cb41a9675bed7c621aea4 Mon Sep 17 00:00:00 2001 From: Paul Daumlechner Date: Thu, 12 Nov 2020 17:52:23 +0100 Subject: [PATCH 06/13] Update config_flow.py --- homeassistant/components/velux/config_flow.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/velux/config_flow.py b/homeassistant/components/velux/config_flow.py index d4513fbd9aa9d0..9ded81285258d1 100644 --- a/homeassistant/components/velux/config_flow.py +++ b/homeassistant/components/velux/config_flow.py @@ -43,12 +43,12 @@ async def async_step_user(self, user_input=None): if user_input is not None: self._host = user_input[CONF_HOST] self._password = user_input[CONF_PASSWORD] + await self.async_set_unique_id(self._host) + self._abort_if_unique_id_configured() self.bridge = PyVLX(host=self._host, password=self._password) try: await self.bridge.connect() await self.bridge.disconnect() - await self.async_set_unique_id(self._host) - self._abort_if_unique_id_configured() return self._get_entry() except PyVLXException: errors["base"] = "invalid_auth" From 242bab22cfc10529d7bba8a4553b711a2dde1820 Mon Sep 17 00:00:00 2001 From: Paul Daumlechner Date: Tue, 24 Nov 2020 21:14:21 +0100 Subject: [PATCH 07/13] Update const.py --- homeassistant/components/velux/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/velux/const.py b/homeassistant/components/velux/const.py index dd61602b9c1328..6cd668427eab0c 100644 --- a/homeassistant/components/velux/const.py +++ b/homeassistant/components/velux/const.py @@ -1,4 +1,4 @@ -"""Constants for Valux Integration.""" +"""Constants for Velux Integration.""" DOMAIN = "velux" PLATFORMS = ["cover", "scene"] From ae3a453f64b61528e634e2cc4df8616abc5bbc47 Mon Sep 17 00:00:00 2001 From: Paul Daumlechner Date: Tue, 24 Nov 2020 21:16:14 +0100 Subject: [PATCH 08/13] Update scene.py --- homeassistant/components/velux/scene.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/velux/scene.py b/homeassistant/components/velux/scene.py index 78dff91a3e9bce..a514c01e3fa3e3 100644 --- a/homeassistant/components/velux/scene.py +++ b/homeassistant/components/velux/scene.py @@ -29,7 +29,7 @@ def name(self): @property def unique_id(self): - """Return the unique ID of this cover.""" + """Return the unique ID of this scene.""" return self.scene.scene_id async def async_activate(self, **kwargs: Any) -> None: From 9b9b67145fd34a1de63a18c7cac27b2c72d9c689 Mon Sep 17 00:00:00 2001 From: Paul Daumlechner Date: Tue, 24 Nov 2020 21:17:11 +0100 Subject: [PATCH 09/13] Update strings.json --- homeassistant/components/velux/strings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/velux/strings.json b/homeassistant/components/velux/strings.json index 592f2ced405846..02556077e2df52 100644 --- a/homeassistant/components/velux/strings.json +++ b/homeassistant/components/velux/strings.json @@ -3,7 +3,7 @@ "config": { "step": { "user": { - "title": "Configure the KLF200 Gateway", + "title": "Configure your KLF200 Gateway", "description": "Please enter your password, you will find it on the backside of the KLF200", "data": { "host": "[%key:common::config_flow::data::host%]", From b5c19dc237625aea7c5de6d480f17ef7283d2ac0 Mon Sep 17 00:00:00 2001 From: Paul Daumlechner Date: Tue, 24 Nov 2020 21:17:47 +0100 Subject: [PATCH 10/13] Update en.json --- homeassistant/components/velux/translations/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/velux/translations/en.json b/homeassistant/components/velux/translations/en.json index f894a66e028613..9df757b194c38b 100644 --- a/homeassistant/components/velux/translations/en.json +++ b/homeassistant/components/velux/translations/en.json @@ -16,7 +16,7 @@ "password": "Password" }, "description": "Please enter your password, you will find it on the backside of the KLF200", - "title": "Configure the KLF200 Gateway" + "title": "Configure your KLF200 Gateway" } } }, From 52e72867ca03dea22d39fea76911fc4f62fa0002 Mon Sep 17 00:00:00 2001 From: Paul Daumlechner Date: Mon, 14 Dec 2020 17:18:42 +0100 Subject: [PATCH 11/13] Update en.json --- homeassistant/components/velux/translations/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/velux/translations/en.json b/homeassistant/components/velux/translations/en.json index 9df757b194c38b..397cefb7d05d1c 100644 --- a/homeassistant/components/velux/translations/en.json +++ b/homeassistant/components/velux/translations/en.json @@ -7,7 +7,7 @@ "error": { "cannot_connect": "Failed to connect", "invalid_auth": "Invalid authentication", - "invalid_host": "Invalid hostname or IP address", + "invalid_host": "Invalid hostname or IP address" }, "step": { "user": { From 61a6b9b35abf7b70c31b1ea8411b72dbe9a98a1e Mon Sep 17 00:00:00 2001 From: Paul Daumlechner Date: Mon, 14 Dec 2020 20:48:43 +0100 Subject: [PATCH 12/13] Add ConfigEntryNotReady exception --- homeassistant/components/velux/__init__.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/velux/__init__.py b/homeassistant/components/velux/__init__.py index 64bd6508e7b904..69698588dd13b4 100644 --- a/homeassistant/components/velux/__init__.py +++ b/homeassistant/components/velux/__init__.py @@ -6,6 +6,7 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_HOST, CONF_PASSWORD from homeassistant.core import HomeAssistant +from homeassistant.exceptions import ConfigEntryNotReady from .const import DOMAIN, PLATFORMS @@ -32,8 +33,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN][entry.entry_id] = gateway - - await gateway.connect() + try: + await gateway.connect() + except (OSError, ConnectionAbortedError) as ex: # pylint: disable=broad-except + _LOGGER.error("Unable to connect to KLF200: %s", str(ex)) + raise ConfigEntryNotReady from ex await gateway.load_nodes() await gateway.load_scenes() From c9ea07695f1f753e47f4cea43d7c17cebafd1511 Mon Sep 17 00:00:00 2001 From: Paul Daumlechner Date: Mon, 14 Dec 2020 21:10:10 +0100 Subject: [PATCH 13/13] Update __init__.py Removed pylint comment --- homeassistant/components/velux/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/velux/__init__.py b/homeassistant/components/velux/__init__.py index 69698588dd13b4..131f3fa10b16b5 100644 --- a/homeassistant/components/velux/__init__.py +++ b/homeassistant/components/velux/__init__.py @@ -35,7 +35,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): hass.data[DOMAIN][entry.entry_id] = gateway try: await gateway.connect() - except (OSError, ConnectionAbortedError) as ex: # pylint: disable=broad-except + except (OSError, ConnectionAbortedError) as ex: _LOGGER.error("Unable to connect to KLF200: %s", str(ex)) raise ConfigEntryNotReady from ex await gateway.load_nodes()