From 7a9b2a22342ec14c88f445f4dcd0c8008495c21e Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 17 Feb 2020 15:26:37 -0800 Subject: [PATCH 01/39] Bumped version to 0.106.0b0 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 2f97f6968de..ff918aaacb8 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 106 -PATCH_VERSION = "0.dev0" +PATCH_VERSION = "0b0" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER = (3, 7, 0) From 1b2bb87566238ef27c4544e750a2099d93612558 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 19 Feb 2020 06:56:46 -0800 Subject: [PATCH 02/39] =?UTF-8?q?Only=20check=20frontend=20for=20safe=20mo?= =?UTF-8?q?de=20if=20frontend=20wanted=20to=20be=20loa=E2=80=A6=20(#31969)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Only check frontend for safe mode if frontend wanted to be loaded * Update test --- homeassistant/bootstrap.py | 7 +++++-- tests/test_bootstrap.py | 3 ++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index 723e3c512e2..7d4155257db 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -20,7 +20,7 @@ from homeassistant.const import ( REQUIRED_NEXT_PYTHON_VER, ) from homeassistant.exceptions import HomeAssistantError -from homeassistant.setup import async_setup_component +from homeassistant.setup import DATA_SETUP, async_setup_component from homeassistant.util.logging import AsyncHandler from homeassistant.util.package import async_get_user_site, is_virtual_env from homeassistant.util.yaml import clear_secret_cache @@ -102,7 +102,10 @@ async def async_setup_hass( _LOGGER.warning("Unable to set up core integrations. Activating safe mode") safe_mode = True - elif "frontend" not in hass.config.components: + elif ( + "frontend" in hass.data.get(DATA_SETUP, {}) + and "frontend" not in hass.config.components + ): _LOGGER.warning("Detected that frontend did not load. Activating safe mode") # Ask integrations to shut down. It's messy but we can't # do a clean stop without knowing what is broken diff --git a/tests/test_bootstrap.py b/tests/test_bootstrap.py index dac32b4728d..34704ddfb74 100644 --- a/tests/test_bootstrap.py +++ b/tests/test_bootstrap.py @@ -400,7 +400,8 @@ async def test_setup_safe_mode_if_no_frontend( log_no_color = Mock() with patch( - "homeassistant.config.async_hass_config_yaml", return_value={"browser": {}} + "homeassistant.config.async_hass_config_yaml", + return_value={"map": {}, "person": {"invalid": True}}, ): hass = await bootstrap.async_setup_hass( config_dir=get_test_config_dir(), From 16f094d4d36a5813d64eb46d516233c7df095067 Mon Sep 17 00:00:00 2001 From: jjlawren Date: Thu, 20 Feb 2020 00:33:38 -0600 Subject: [PATCH 03/39] Fix Plex sensor title handling (#31973) * Fix Plex sensor title parsing * Revert episode year for now --- homeassistant/components/plex/sensor.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/plex/sensor.py b/homeassistant/components/plex/sensor.py index 1caf8ec5f75..b1e93aec8c0 100644 --- a/homeassistant/components/plex/sensor.py +++ b/homeassistant/components/plex/sensor.py @@ -109,18 +109,16 @@ class PlexSensor(Entity): now_playing_user = f"{user} - {device}" now_playing_title = "" - if sess.TYPE == "episode": + if sess.TYPE in ["clip", "episode"]: # example: - # "Supernatural (2005) - S01 · E13 - Route 666" + # "Supernatural (2005) - s01e13 - Route 666" season_title = sess.grandparentTitle if sess.show().year is not None: - season_title += " ({0})".format(sess.show().year) - season_episode = "S{0}".format(sess.parentIndex) - if sess.index is not None: - season_episode += f" · E{sess.index}" + season_title += f" ({sess.show().year!s})" + season_episode = sess.seasonEpisode episode_title = sess.title - now_playing_title = "{0} - {1} - {2}".format( - season_title, season_episode, episode_title + now_playing_title = ( + f"{season_title} - {season_episode} - {episode_title}" ) elif sess.TYPE == "track": # example: @@ -128,9 +126,7 @@ class PlexSensor(Entity): track_artist = sess.grandparentTitle track_album = sess.parentTitle track_title = sess.title - now_playing_title = "{0} - {1} - {2}".format( - track_artist, track_album, track_title - ) + now_playing_title = f"{track_artist} - {track_album} - {track_title}" else: # example: # "picture_of_last_summer_camp (2015)" From bf92b3099d4c250ff6f47e6e3573d2079fc2caa7 Mon Sep 17 00:00:00 2001 From: "David F. Mulcahey" Date: Wed, 19 Feb 2020 09:19:26 -0500 Subject: [PATCH 04/39] Bump ZHA quirks and add skip configuration support (#31982) * add skip configuration * Bump quirks * add skip configuration to FakeDevice --- homeassistant/components/zha/core/channels/__init__.py | 10 +++++----- homeassistant/components/zha/core/channels/security.py | 5 ++--- homeassistant/components/zha/core/device.py | 5 +++++ homeassistant/components/zha/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/zha/common.py | 1 + 7 files changed, 16 insertions(+), 11 deletions(-) diff --git a/homeassistant/components/zha/core/channels/__init__.py b/homeassistant/components/zha/core/channels/__init__.py index a5ecf21e0c3..d899f51b487 100644 --- a/homeassistant/components/zha/core/channels/__init__.py +++ b/homeassistant/components/zha/core/channels/__init__.py @@ -194,8 +194,7 @@ class ZigbeeChannel(LogMixin): async def async_configure(self): """Set cluster binding and attribute reporting.""" - # Xiaomi devices don't need this and it disrupts pairing - if self._zha_device.manufacturer != "LUMI": + if not self._zha_device.skip_configuration: await self.bind() if self.cluster.is_server: for report_config in self._report_config: @@ -203,8 +202,9 @@ class ZigbeeChannel(LogMixin): report_config["attr"], report_config["config"] ) await asyncio.sleep(uniform(0.1, 0.5)) - - self.debug("finished channel configuration") + self.debug("finished channel configuration") + else: + self.debug("skipping channel configuration") self._status = ChannelStatus.CONFIGURED async def async_initialize(self, from_cache): @@ -264,7 +264,7 @@ class ZigbeeChannel(LogMixin): def log(self, level, msg, *args): """Log a message.""" msg = f"[%s:%s]: {msg}" - args = (self.device.nwk, self._id,) + args + args = (self.device.nwk, self._id) + args _LOGGER.log(level, msg, *args) def __getattr__(self, name): diff --git a/homeassistant/components/zha/core/channels/security.py b/homeassistant/components/zha/core/channels/security.py index 69e4ea1a27a..781738fc048 100644 --- a/homeassistant/components/zha/core/channels/security.py +++ b/homeassistant/components/zha/core/channels/security.py @@ -146,9 +146,8 @@ class IASZoneChannel(ZigbeeChannel): async def async_configure(self): """Configure IAS device.""" - # Xiaomi devices don't need this and it disrupts pairing - if self._zha_device.manufacturer == "LUMI": - self.debug("finished IASZoneChannel configuration") + if self._zha_device.skip_configuration: + self.debug("skipping IASZoneChannel configuration") return self.debug("started IASZoneChannel configuration") diff --git a/homeassistant/components/zha/core/device.py b/homeassistant/components/zha/core/device.py index 8810fd77fe7..2e7c48c639f 100644 --- a/homeassistant/components/zha/core/device.py +++ b/homeassistant/components/zha/core/device.py @@ -213,6 +213,11 @@ class ZHADevice(LogMixin): if Groups.cluster_id in clusters: return True + @property + def skip_configuration(self): + """Return true if the device should not issue configuration related commands.""" + return self._zigpy_device.skip_configuration + @property def gateway(self): """Return the gateway for this device.""" diff --git a/homeassistant/components/zha/manifest.json b/homeassistant/components/zha/manifest.json index c0b7a0719f8..16c5604587d 100644 --- a/homeassistant/components/zha/manifest.json +++ b/homeassistant/components/zha/manifest.json @@ -5,7 +5,7 @@ "documentation": "https://www.home-assistant.io/integrations/zha", "requirements": [ "bellows-homeassistant==0.13.2", - "zha-quirks==0.0.32", + "zha-quirks==0.0.33", "zigpy-cc==0.1.0", "zigpy-deconz==0.7.0", "zigpy-homeassistant==0.13.2", diff --git a/requirements_all.txt b/requirements_all.txt index b72a61f57f3..9bde09768bb 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2130,7 +2130,7 @@ zengge==0.2 zeroconf==0.24.4 # homeassistant.components.zha -zha-quirks==0.0.32 +zha-quirks==0.0.33 # homeassistant.components.zhong_hong zhong_hong_hvac==1.0.9 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 48863e32db9..86f8e9f12cc 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -732,7 +732,7 @@ yahooweather==0.10 zeroconf==0.24.4 # homeassistant.components.zha -zha-quirks==0.0.32 +zha-quirks==0.0.33 # homeassistant.components.zha zigpy-cc==0.1.0 diff --git a/tests/components/zha/common.py b/tests/components/zha/common.py index a9f040eda68..03b6ed21148 100644 --- a/tests/components/zha/common.py +++ b/tests/components/zha/common.py @@ -72,6 +72,7 @@ class FakeDevice: self.last_seen = time.time() self.status = 2 self.initializing = False + self.skip_configuration = False self.manufacturer = manufacturer self.model = model self.node_desc = zigpy.zdo.types.NodeDescriptor() From 1e52dd5945673aa018023515e81793d89ba11e63 Mon Sep 17 00:00:00 2001 From: Mark Coombes Date: Thu, 20 Feb 2020 00:05:22 -0500 Subject: [PATCH 05/39] Fix bug in ecobee integration (#32008) * Bump python-ecobee-api to 0.2.1 * Update log messages for clarity * Update requirements_all --- homeassistant/components/ecobee/__init__.py | 6 ++---- homeassistant/components/ecobee/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/ecobee/__init__.py b/homeassistant/components/ecobee/__init__.py index 80c3be7954b..26bfbe5b3da 100644 --- a/homeassistant/components/ecobee/__init__.py +++ b/homeassistant/components/ecobee/__init__.py @@ -96,9 +96,7 @@ class EcobeeData: await self._hass.async_add_executor_job(self.ecobee.update) _LOGGER.debug("Updating ecobee") except ExpiredTokenError: - _LOGGER.warning( - "Ecobee update failed; attempting to refresh expired tokens" - ) + _LOGGER.debug("Refreshing expired ecobee tokens") await self.refresh() async def refresh(self) -> bool: @@ -113,7 +111,7 @@ class EcobeeData: }, ) return True - _LOGGER.error("Error updating ecobee tokens") + _LOGGER.error("Error refreshing ecobee tokens") return False diff --git a/homeassistant/components/ecobee/manifest.json b/homeassistant/components/ecobee/manifest.json index 5df89c3d90d..8e21b9931cd 100644 --- a/homeassistant/components/ecobee/manifest.json +++ b/homeassistant/components/ecobee/manifest.json @@ -4,6 +4,6 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/ecobee", "dependencies": [], - "requirements": ["python-ecobee-api==0.1.4"], + "requirements": ["python-ecobee-api==0.2.1"], "codeowners": ["@marthoc"] } diff --git a/requirements_all.txt b/requirements_all.txt index 9bde09768bb..3094bec74ec 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1559,7 +1559,7 @@ python-clementine-remote==1.0.1 python-digitalocean==1.13.2 # homeassistant.components.ecobee -python-ecobee-api==0.1.4 +python-ecobee-api==0.2.1 # homeassistant.components.eq3btsmart # python-eq3bt==0.1.11 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 86f8e9f12cc..893c50917d4 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -560,7 +560,7 @@ pysonos==0.0.24 pyspcwebgw==0.4.0 # homeassistant.components.ecobee -python-ecobee-api==0.1.4 +python-ecobee-api==0.2.1 # homeassistant.components.darksky python-forecastio==1.4.0 From 35e9b52e2e3c5c13e18058f17db1174b6562e024 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 20 Feb 2020 08:51:00 -0800 Subject: [PATCH 06/39] Fix recursion bug (#32009) * Fix recursion bug * Remove shield --- homeassistant/components/homeassistant/__init__.py | 12 +++++++++++- tests/components/homeassistant/test_init.py | 14 ++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/homeassistant/__init__.py b/homeassistant/components/homeassistant/__init__.py index 17ab9ba3b44..7a0ae33345a 100644 --- a/homeassistant/components/homeassistant/__init__.py +++ b/homeassistant/components/homeassistant/__init__.py @@ -55,6 +55,15 @@ async def async_setup(hass: ha.HomeAssistant, config: dict) -> Awaitable[bool]: tasks = [] for domain, ent_ids in by_domain: + # This leads to endless loop. + if domain == DOMAIN: + _LOGGER.warning( + "Called service homeassistant.%s with invalid entity IDs %s", + service.service, + ", ".join(ent_ids), + ) + continue + # We want to block for all calls and only return when all calls # have been processed. If a service does not exist it causes a 10 # second delay while we're blocking waiting for a response. @@ -73,7 +82,8 @@ async def async_setup(hass: ha.HomeAssistant, config: dict) -> Awaitable[bool]: hass.services.async_call(domain, service.service, data, blocking) ) - await asyncio.wait(tasks) + if tasks: + await asyncio.gather(*tasks) service_schema = vol.Schema({ATTR_ENTITY_ID: cv.entity_ids}, extra=vol.ALLOW_EXTRA) diff --git a/tests/components/homeassistant/test_init.py b/tests/components/homeassistant/test_init.py index 0f7dc7ed309..38a76b7c3fb 100644 --- a/tests/components/homeassistant/test_init.py +++ b/tests/components/homeassistant/test_init.py @@ -372,3 +372,17 @@ async def test_turn_on_off_toggle_schema(hass, hass_read_only_user): context=ha.Context(user_id=hass_read_only_user.id), blocking=True, ) + + +async def test_not_allowing_recursion(hass, caplog): + """Test we do not allow recursion.""" + await async_setup_component(hass, "homeassistant", {}) + + for service in SERVICE_TURN_ON, SERVICE_TURN_OFF, SERVICE_TOGGLE: + await hass.services.async_call( + ha.DOMAIN, service, {"entity_id": "homeassistant.light"}, blocking=True, + ) + assert ( + f"Called service homeassistant.{service} with invalid entity IDs homeassistant.light" + in caplog.text + ), service From 2fb6bb2a92c793689aaacacc7113f8d4ed77ec3e Mon Sep 17 00:00:00 2001 From: Tsvi Mostovicz Date: Thu, 20 Feb 2020 08:21:09 +0200 Subject: [PATCH 07/39] Don't return coroutine in DLNA/DMR service handler (#32011) Fixes #32010 --- homeassistant/components/dlna_dmr/media_player.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/dlna_dmr/media_player.py b/homeassistant/components/dlna_dmr/media_player.py index fa6b60d0c19..1e3ba840d6f 100644 --- a/homeassistant/components/dlna_dmr/media_player.py +++ b/homeassistant/components/dlna_dmr/media_player.py @@ -99,10 +99,10 @@ def catch_request_errors(): """Call wrapper for decorator.""" @functools.wraps(func) - def wrapper(self, *args, **kwargs): + async def wrapper(self, *args, **kwargs): """Catch asyncio.TimeoutError, aiohttp.ClientError errors.""" try: - return func(self, *args, **kwargs) + return await func(self, *args, **kwargs) except (asyncio.TimeoutError, aiohttp.ClientError): _LOGGER.error("Error during call %s", func.__name__) From f58e5a21857174f4b89d572875cf981a48552516 Mon Sep 17 00:00:00 2001 From: cgtobi Date: Thu, 20 Feb 2020 17:25:49 +0100 Subject: [PATCH 08/39] Bump pyatmo to 3.2.4 (#32018) * Bump pyatmo to 3.2.3 * Bump pyatmo version to 3.2.4 * Update requirements_test_all.txt --- homeassistant/components/netatmo/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/netatmo/manifest.json b/homeassistant/components/netatmo/manifest.json index 14ec2e61b9c..6fe084cc885 100644 --- a/homeassistant/components/netatmo/manifest.json +++ b/homeassistant/components/netatmo/manifest.json @@ -3,7 +3,7 @@ "name": "Netatmo", "documentation": "https://www.home-assistant.io/integrations/netatmo", "requirements": [ - "pyatmo==3.2.2" + "pyatmo==3.2.4" ], "dependencies": [ "webhook" diff --git a/requirements_all.txt b/requirements_all.txt index 3094bec74ec..c51017a0a63 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1145,7 +1145,7 @@ pyalmond==0.0.2 pyarlo==0.2.3 # homeassistant.components.netatmo -pyatmo==3.2.2 +pyatmo==3.2.4 # homeassistant.components.atome pyatome==0.1.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 893c50917d4..a5ba0c31e49 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -425,7 +425,7 @@ pyalmond==0.0.2 pyarlo==0.2.3 # homeassistant.components.netatmo -pyatmo==3.2.2 +pyatmo==3.2.4 # homeassistant.components.blackbird pyblackbird==0.5 From 425e6b2b1fe9197334135afba6fdc03df69f8a63 Mon Sep 17 00:00:00 2001 From: MatthewFlamm <39341281+MatthewFlamm@users.noreply.github.com> Date: Thu, 20 Feb 2020 10:51:15 -0500 Subject: [PATCH 09/39] Add missing name to logging in DataUpdateCoordinator (#32023) --- homeassistant/helpers/update_coordinator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/helpers/update_coordinator.py b/homeassistant/helpers/update_coordinator.py index 5f0490b6ea2..fe877fe9bb8 100644 --- a/homeassistant/helpers/update_coordinator.py +++ b/homeassistant/helpers/update_coordinator.py @@ -128,7 +128,7 @@ class DataUpdateCoordinator: else: if not self.last_update_success: self.last_update_success = True - self.logger.info("Fetching %s data recovered") + self.logger.info("Fetching %s data recovered", self.name) finally: self.logger.debug( From fdd0becd5f79dbe46f930d2ff60414241754651b Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Thu, 20 Feb 2020 19:19:09 +0100 Subject: [PATCH 10/39] Add minimal version contrain to urllib3 (#32031) --- homeassistant/package_constraints.txt | 3 +++ script/gen_requirements_all.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 1cfc92a6aab..396e1391d4e 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -28,6 +28,9 @@ zeroconf==0.24.4 pycryptodome>=3.6.6 +# Constrain urllib3 to ensure we deal with CVE-2019-11236 & CVE-2019-11324 +urllib3>=1.24.3 + # Not needed for our supported Python versions enum34==1000000000.0.0 diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index 1bf9031a536..c4a94f99b18 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -58,6 +58,9 @@ CONSTRAINT_PATH = os.path.join( CONSTRAINT_BASE = """ pycryptodome>=3.6.6 +# Constrain urllib3 to ensure we deal with CVE-2019-11236 & CVE-2019-11324 +urllib3>=1.24.3 + # Not needed for our supported Python versions enum34==1000000000.0.0 From b2310d6341c38a5ccfd362f31d52d608a4a82bc0 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 20 Feb 2020 11:01:20 -0800 Subject: [PATCH 11/39] Updated frontend to 20200220.0 (#32033) --- homeassistant/components/frontend/manifest.json | 2 +- homeassistant/package_constraints.txt | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/frontend/manifest.json b/homeassistant/components/frontend/manifest.json index d35801d9177..04f0f45344d 100644 --- a/homeassistant/components/frontend/manifest.json +++ b/homeassistant/components/frontend/manifest.json @@ -3,7 +3,7 @@ "name": "Home Assistant Frontend", "documentation": "https://www.home-assistant.io/integrations/frontend", "requirements": [ - "home-assistant-frontend==20200219.0" + "home-assistant-frontend==20200220.0" ], "dependencies": [ "api", diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 396e1391d4e..542d8bcaabc 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -11,7 +11,7 @@ cryptography==2.8 defusedxml==0.6.0 distro==1.4.0 hass-nabucasa==0.31 -home-assistant-frontend==20200219.0 +home-assistant-frontend==20200220.0 importlib-metadata==1.5.0 jinja2>=2.10.3 netdisco==2.6.0 diff --git a/requirements_all.txt b/requirements_all.txt index c51017a0a63..78216da0674 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -683,7 +683,7 @@ hole==0.5.0 holidays==0.10.1 # homeassistant.components.frontend -home-assistant-frontend==20200219.0 +home-assistant-frontend==20200220.0 # homeassistant.components.zwave homeassistant-pyozw==0.1.8 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index a5ba0c31e49..9e7201ade66 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -254,7 +254,7 @@ hole==0.5.0 holidays==0.10.1 # homeassistant.components.frontend -home-assistant-frontend==20200219.0 +home-assistant-frontend==20200220.0 # homeassistant.components.zwave homeassistant-pyozw==0.1.8 From fbe7ec7b11addc5a467a7e3827acc97ff3bf13aa Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 20 Feb 2020 11:02:23 -0800 Subject: [PATCH 12/39] Bumped version to 0.106.0b1 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index ff918aaacb8..26f442947a9 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 106 -PATCH_VERSION = "0b0" +PATCH_VERSION = "0b1" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER = (3, 7, 0) From a1027289977f052480df8ad748eaccee00b5a8bb Mon Sep 17 00:00:00 2001 From: Ziv <16467659+ziv1234@users.noreply.github.com> Date: Sat, 22 Feb 2020 00:29:59 +0200 Subject: [PATCH 13/39] Enhance Dynalite Integration after review (#31760) * fixes per Martin Hjelmare * pylint fix * final fixes per request * fixed unit tests for new config flow * Added unit-tests to increase coverage. at 97% now * Added unit tests for 100% coverage of component * removed configured_host function and updated config_flow unit tests * added a pylint directive since it tells me by mistake DOMAIN is not used * fixed path (removed __init__) * Update homeassistant/components/dynalite/light.py Co-Authored-By: Martin Hjelmare * Update homeassistant/components/dynalite/light.py Co-Authored-By: Martin Hjelmare * fixed the test as we moved from schedule_update_... to async_schedule * Update homeassistant/components/dynalite/bridge.py Co-Authored-By: Martin Hjelmare * removed context from config_flow changed test_init to use the core methods * moved test_light to also use the core interfaces * moved to config_entries.async_unload * additional fixes for the tests * pylint fix and removed unnecessary code * Update tests/components/dynalite/test_light.py Co-Authored-By: Martin Hjelmare * Update tests/components/dynalite/test_light.py Co-Authored-By: Martin Hjelmare * Update tests/components/dynalite/test_light.py Co-Authored-By: Martin Hjelmare * Update tests/components/dynalite/test_light.py Co-Authored-By: Martin Hjelmare * Update tests/components/dynalite/test_light.py Co-Authored-By: Martin Hjelmare * Update tests/components/dynalite/test_light.py Co-Authored-By: Martin Hjelmare * Update tests/components/dynalite/test_light.py Co-Authored-By: Martin Hjelmare * Update tests/components/dynalite/test_light.py Co-Authored-By: Martin Hjelmare * Update tests/components/dynalite/test_light.py Co-Authored-By: Martin Hjelmare * added break in loop * removed last mock_coro reference pylint fix * added coverage for try_connect * added check for a successful connection before bridge.async_setup succeeds also added a "nowait" config option (default False) that avoids this check * changed log level * fixed accidental chmod I did * fixed accidental change * not storing config in bridge * not patching asyncio * moved CONFIG_SCHEMA into component * moved all logs to start capitalized (and revised some of them) * moved test_config_flow to not patch the DynaliteBridge * also took DynaliteBridge patching out of test_init * removed NO_WAIT * fixes to SCHEMA * changed _ in multi-word CONF moved imports to component const.py * removed tries * removed redundant tests * fixed some small change i broke in the library. only version update * fixed rewuirements * Update tests/components/dynalite/test_config_flow.py Co-Authored-By: Martin Hjelmare * Update tests/components/dynalite/test_light.py Co-Authored-By: Martin Hjelmare * Update tests/components/dynalite/test_config_flow.py Co-Authored-By: Martin Hjelmare * removed HIDDEN_ENTITY removed hass in test fixture * black fixes * removed final piece of hidden_entity from light fix in the library updated config flow so if the entry is already set but with a different config, calls async_update_entry * removed DATA_CONFIGS - no longer necessary * pylint fixes * added coverage * use abort in config_flow * test update * removed logs * test that update actually updates the entry Co-authored-by: Martin Hjelmare --- homeassistant/components/dynalite/__init__.py | 109 ++++++++---- homeassistant/components/dynalite/bridge.py | 128 +++++--------- .../components/dynalite/config_flow.py | 53 ++---- homeassistant/components/dynalite/const.py | 12 +- homeassistant/components/dynalite/light.py | 48 ++++-- .../components/dynalite/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/dynalite/test_bridge.py | 157 ++++++------------ tests/components/dynalite/test_config_flow.py | 116 +++++++++---- tests/components/dynalite/test_init.py | 116 ++++++------- tests/components/dynalite/test_light.py | 110 +++++++----- 12 files changed, 442 insertions(+), 413 deletions(-) diff --git a/homeassistant/components/dynalite/__init__.py b/homeassistant/components/dynalite/__init__.py index cb6b52483b7..f4fc65b8261 100755 --- a/homeassistant/components/dynalite/__init__.py +++ b/homeassistant/components/dynalite/__init__.py @@ -1,24 +1,75 @@ """Support for the Dynalite networks.""" -from dynalite_devices_lib import BRIDGE_CONFIG_SCHEMA import voluptuous as vol from homeassistant import config_entries from homeassistant.const import CONF_HOST +from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import config_validation as cv # Loading the config flow file will register the flow from .bridge import DynaliteBridge -from .config_flow import configured_hosts -from .const import CONF_BRIDGES, DATA_CONFIGS, DOMAIN, LOGGER +from .const import ( + CONF_ACTIVE, + CONF_AREA, + CONF_AUTO_DISCOVER, + CONF_BRIDGES, + CONF_CHANNEL, + CONF_DEFAULT, + CONF_FADE, + CONF_NAME, + CONF_POLLTIMER, + CONF_PORT, + DEFAULT_NAME, + DEFAULT_PORT, + DOMAIN, + LOGGER, +) + + +def num_string(value): + """Test if value is a string of digits, aka an integer.""" + new_value = str(value) + if new_value.isdigit(): + return new_value + raise vol.Invalid("Not a string with numbers") + + +CHANNEL_DATA_SCHEMA = vol.Schema( + {vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_FADE): vol.Coerce(float)} +) + +CHANNEL_SCHEMA = vol.Schema({num_string: CHANNEL_DATA_SCHEMA}) + +AREA_DATA_SCHEMA = vol.Schema( + { + vol.Required(CONF_NAME): cv.string, + vol.Optional(CONF_FADE): vol.Coerce(float), + vol.Optional(CONF_CHANNEL): CHANNEL_SCHEMA, + }, +) + +AREA_SCHEMA = vol.Schema({num_string: vol.Any(AREA_DATA_SCHEMA, None)}) + +PLATFORM_DEFAULTS_SCHEMA = vol.Schema({vol.Optional(CONF_FADE): vol.Coerce(float)}) + + +BRIDGE_SCHEMA = vol.Schema( + { + vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, + vol.Required(CONF_HOST): cv.string, + vol.Optional(CONF_PORT, default=DEFAULT_PORT): int, + vol.Optional(CONF_AUTO_DISCOVER, default=False): vol.Coerce(bool), + vol.Optional(CONF_POLLTIMER, default=1.0): vol.Coerce(float), + vol.Optional(CONF_AREA): AREA_SCHEMA, + vol.Optional(CONF_DEFAULT): PLATFORM_DEFAULTS_SCHEMA, + vol.Optional(CONF_ACTIVE, default=False): vol.Coerce(bool), + } +) CONFIG_SCHEMA = vol.Schema( { DOMAIN: vol.Schema( - { - vol.Optional(CONF_BRIDGES): vol.All( - cv.ensure_list, [BRIDGE_CONFIG_SCHEMA] - ) - } + {vol.Optional(CONF_BRIDGES): vol.All(cv.ensure_list, [BRIDGE_SCHEMA])} ) }, extra=vol.ALLOW_EXTRA, @@ -35,9 +86,6 @@ async def async_setup(hass, config): conf = {} hass.data[DOMAIN] = {} - hass.data[DOMAIN][DATA_CONFIGS] = {} - - configured = configured_hosts(hass) # User has configured bridges if CONF_BRIDGES not in conf: @@ -47,20 +95,13 @@ async def async_setup(hass, config): for bridge_conf in bridges: host = bridge_conf[CONF_HOST] - LOGGER.debug("async_setup host=%s conf=%s", host, bridge_conf) - - # Store config in hass.data so the config entry can find it - hass.data[DOMAIN][DATA_CONFIGS][host] = bridge_conf - - if host in configured: - LOGGER.debug("async_setup host=%s already configured", host) - continue + LOGGER.debug("Starting config entry flow host=%s conf=%s", host, bridge_conf) hass.async_create_task( hass.config_entries.flow.async_init( DOMAIN, context={"source": config_entries.SOURCE_IMPORT}, - data={CONF_HOST: bridge_conf[CONF_HOST]}, + data=bridge_conf, ) ) @@ -69,25 +110,29 @@ async def async_setup(hass, config): async def async_setup_entry(hass, entry): """Set up a bridge from a config entry.""" - LOGGER.debug("__init async_setup_entry %s", entry.data) - host = entry.data[CONF_HOST] - config = hass.data[DOMAIN][DATA_CONFIGS].get(host) + LOGGER.debug("Setting up entry %s", entry.data) - if config is None: - LOGGER.error("__init async_setup_entry empty config for host %s", host) - return False - - bridge = DynaliteBridge(hass, entry) + bridge = DynaliteBridge(hass, entry.data) if not await bridge.async_setup(): - LOGGER.error("bridge.async_setup failed") + LOGGER.error("Could not set up bridge for entry %s", entry.data) return False + + if not await bridge.try_connection(): + LOGGER.errot("Could not connect with entry %s", entry) + raise ConfigEntryNotReady + hass.data[DOMAIN][entry.entry_id] = bridge + + hass.async_create_task( + hass.config_entries.async_forward_entry_setup(entry, "light") + ) return True async def async_unload_entry(hass, entry): """Unload a config entry.""" - LOGGER.error("async_unload_entry %s", entry.data) - bridge = hass.data[DOMAIN].pop(entry.entry_id) - return await bridge.async_reset() + LOGGER.debug("Unloading entry %s", entry.data) + hass.data[DOMAIN].pop(entry.entry_id) + result = await hass.config_entries.async_forward_entry_unload(entry, "light") + return result diff --git a/homeassistant/components/dynalite/bridge.py b/homeassistant/components/dynalite/bridge.py index 1bf86001cc5..cbe08fdadb5 100755 --- a/homeassistant/components/dynalite/bridge.py +++ b/homeassistant/components/dynalite/bridge.py @@ -1,118 +1,82 @@ """Code to handle a Dynalite bridge.""" +import asyncio + from dynalite_devices_lib import DynaliteDevices -from dynalite_lib import CONF_ALL -from homeassistant.const import CONF_HOST from homeassistant.core import callback +from homeassistant.helpers.dispatcher import async_dispatcher_send -from .const import DATA_CONFIGS, DOMAIN, LOGGER -from .light import DynaliteLight +from .const import CONF_ALL, CONF_HOST, LOGGER - -class BridgeError(Exception): - """Class to throw exceptions from DynaliteBridge.""" - - def __init__(self, message): - """Initialize the exception.""" - super().__init__() - self.message = message +CONNECT_TIMEOUT = 30 +CONNECT_INTERVAL = 1 class DynaliteBridge: """Manages a single Dynalite bridge.""" - def __init__(self, hass, config_entry): + def __init__(self, hass, config): """Initialize the system based on host parameter.""" - self.config_entry = config_entry self.hass = hass self.area = {} - self.async_add_entities = None - self.waiting_entities = [] - self.all_entities = {} - self.config = None - self.host = config_entry.data[CONF_HOST] - if self.host not in hass.data[DOMAIN][DATA_CONFIGS]: - LOGGER.info("invalid host - %s", self.host) - raise BridgeError(f"invalid host - {self.host}") - self.config = hass.data[DOMAIN][DATA_CONFIGS][self.host] + self.async_add_devices = None + self.waiting_devices = [] + self.host = config[CONF_HOST] # Configure the dynalite devices self.dynalite_devices = DynaliteDevices( - config=self.config, - newDeviceFunc=self.add_devices, + config=config, + newDeviceFunc=self.add_devices_when_registered, updateDeviceFunc=self.update_device, ) - async def async_setup(self, tries=0): + async def async_setup(self): """Set up a Dynalite bridge.""" # Configure the dynalite devices - await self.dynalite_devices.async_setup() + return await self.dynalite_devices.async_setup() - self.hass.async_create_task( - self.hass.config_entries.async_forward_entry_setup( - self.config_entry, "light" - ) - ) - - return True - - @callback - def add_devices(self, devices): - """Call when devices should be added to home assistant.""" - added_entities = [] - - for device in devices: - if device.category == "light": - entity = DynaliteLight(device, self) - else: - LOGGER.debug("Illegal device category %s", device.category) - continue - added_entities.append(entity) - self.all_entities[entity.unique_id] = entity - - if added_entities: - self.add_entities_when_registered(added_entities) + def update_signal(self, device=None): + """Create signal to use to trigger entity update.""" + if device: + signal = f"dynalite-update-{self.host}-{device.unique_id}" + else: + signal = f"dynalite-update-{self.host}" + return signal @callback def update_device(self, device): """Call when a device or all devices should be updated.""" if device == CONF_ALL: # This is used to signal connection or disconnection, so all devices may become available or not. - if self.dynalite_devices.available: - LOGGER.info("Connected to dynalite host") - else: - LOGGER.info("Disconnected from dynalite host") - for uid in self.all_entities: - self.all_entities[uid].try_schedule_ha() + log_string = ( + "Connected" if self.dynalite_devices.available else "Disconnected" + ) + LOGGER.info("%s to dynalite host", log_string) + async_dispatcher_send(self.hass, self.update_signal()) else: - uid = device.unique_id - if uid in self.all_entities: - self.all_entities[uid].try_schedule_ha() + async_dispatcher_send(self.hass, self.update_signal(device)) + + async def try_connection(self): + """Try to connect to dynalite with timeout.""" + # Currently by polling. Future - will need to change the library to be proactive + for _ in range(0, CONNECT_TIMEOUT): + if self.dynalite_devices.available: + return True + await asyncio.sleep(CONNECT_INTERVAL) + return False @callback - def register_add_entities(self, async_add_entities): + def register_add_devices(self, async_add_devices): """Add an async_add_entities for a category.""" - self.async_add_entities = async_add_entities - if self.waiting_entities: - self.async_add_entities(self.waiting_entities) + self.async_add_devices = async_add_devices + if self.waiting_devices: + self.async_add_devices(self.waiting_devices) - def add_entities_when_registered(self, entities): - """Add the entities to HA if async_add_entities was registered, otherwise queue until it is.""" - if not entities: + def add_devices_when_registered(self, devices): + """Add the devices to HA if the add devices callback was registered, otherwise queue until it is.""" + if not devices: return - if self.async_add_entities: - self.async_add_entities(entities) + if self.async_add_devices: + self.async_add_devices(devices) else: # handle it later when it is registered - self.waiting_entities.extend(entities) - - async def async_reset(self): - """Reset this bridge to default state. - - Will cancel any scheduled setup retry and will unload - the config entry. - """ - result = await self.hass.config_entries.async_forward_entry_unload( - self.config_entry, "light" - ) - # None and True are OK - return result + self.waiting_devices.extend(devices) diff --git a/homeassistant/components/dynalite/config_flow.py b/homeassistant/components/dynalite/config_flow.py index 9aaaee00717..aac42172181 100755 --- a/homeassistant/components/dynalite/config_flow.py +++ b/homeassistant/components/dynalite/config_flow.py @@ -1,19 +1,9 @@ """Config flow to configure Dynalite hub.""" -import asyncio - from homeassistant import config_entries from homeassistant.const import CONF_HOST -from homeassistant.core import callback -from .const import DOMAIN, LOGGER - - -@callback -def configured_hosts(hass): - """Return a set of the configured hosts.""" - return set( - entry.data[CONF_HOST] for entry in hass.config_entries.async_entries(DOMAIN) - ) +from .bridge import DynaliteBridge +from .const import DOMAIN, LOGGER # pylint: disable=unused-import class DynaliteFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): @@ -30,29 +20,16 @@ class DynaliteFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): async def async_step_import(self, import_info): """Import a new bridge as a config entry.""" - LOGGER.debug("async_step_import - %s", import_info) - host = self.context[CONF_HOST] = import_info[CONF_HOST] - return await self._entry_from_bridge(host) - - async def _entry_from_bridge(self, host): - """Return a config entry from an initialized bridge.""" - LOGGER.debug("entry_from_bridge - %s", host) - # Remove all other entries of hubs with same ID or host - - same_hub_entries = [ - entry.entry_id - for entry in self.hass.config_entries.async_entries(DOMAIN) - if entry.data[CONF_HOST] == host - ] - - LOGGER.debug("entry_from_bridge same_hub - %s", same_hub_entries) - - if same_hub_entries: - await asyncio.wait( - [ - self.hass.config_entries.async_remove(entry_id) - for entry_id in same_hub_entries - ] - ) - - return self.async_create_entry(title=host, data={CONF_HOST: host}) + LOGGER.debug("Starting async_step_import - %s", import_info) + host = import_info[CONF_HOST] + await self.async_set_unique_id(host) + self._abort_if_unique_id_configured(import_info) + # New entry + bridge = DynaliteBridge(self.hass, import_info) + if not await bridge.async_setup(): + LOGGER.error("Unable to setup bridge - import info=%s", import_info) + return self.async_abort(reason="bridge_setup_failed") + if not await bridge.try_connection(): + return self.async_abort(reason="no_connection") + LOGGER.debug("Creating entry for the bridge - %s", import_info) + return self.async_create_entry(title=host, data=import_info) diff --git a/homeassistant/components/dynalite/const.py b/homeassistant/components/dynalite/const.py index f433214913a..f7795554465 100755 --- a/homeassistant/components/dynalite/const.py +++ b/homeassistant/components/dynalite/const.py @@ -3,9 +3,19 @@ import logging LOGGER = logging.getLogger(__package__) DOMAIN = "dynalite" -DATA_CONFIGS = "dynalite_configs" +CONF_ACTIVE = "active" +CONF_ALL = "ALL" +CONF_AREA = "area" +CONF_AUTO_DISCOVER = "autodiscover" CONF_BRIDGES = "bridges" +CONF_CHANNEL = "channel" +CONF_DEFAULT = "default" +CONF_FADE = "fade" +CONF_HOST = "host" +CONF_NAME = "name" +CONF_POLLTIMER = "polltimer" +CONF_PORT = "port" DEFAULT_NAME = "dynalite" DEFAULT_PORT = 12345 diff --git a/homeassistant/components/dynalite/light.py b/homeassistant/components/dynalite/light.py index d3263941f9f..652a6178705 100755 --- a/homeassistant/components/dynalite/light.py +++ b/homeassistant/components/dynalite/light.py @@ -1,15 +1,26 @@ """Support for Dynalite channels as lights.""" from homeassistant.components.light import SUPPORT_BRIGHTNESS, Light from homeassistant.core import callback +from homeassistant.helpers.dispatcher import async_dispatcher_connect from .const import DOMAIN, LOGGER async def async_setup_entry(hass, config_entry, async_add_entities): """Record the async_add_entities function to add them later when received from Dynalite.""" - LOGGER.debug("async_setup_entry light entry = %s", config_entry.data) + LOGGER.debug("Setting up light entry = %s", config_entry.data) bridge = hass.data[DOMAIN][config_entry.entry_id] - bridge.register_add_entities(async_add_entities) + + @callback + def async_add_lights(devices): + added_lights = [] + for device in devices: + if device.category == "light": + added_lights.append(DynaliteLight(device, bridge)) + if added_lights: + async_add_entities(added_lights) + + bridge.register_add_devices(async_add_lights) class DynaliteLight(Light): @@ -20,11 +31,6 @@ class DynaliteLight(Light): self._device = device self._bridge = bridge - @property - def device(self): - """Return the underlying device - mostly for testing.""" - return self._device - @property def name(self): """Return the name of the entity.""" @@ -40,11 +46,6 @@ class DynaliteLight(Light): """Return if entity is available.""" return self._device.available - @property - def hidden(self): - """Return true if this entity should be hidden from UI.""" - return self._device.hidden - async def async_update(self): """Update the entity.""" return @@ -52,7 +53,11 @@ class DynaliteLight(Light): @property def device_info(self): """Device info for this entity.""" - return self._device.device_info + return { + "identifiers": {(DOMAIN, self.unique_id)}, + "name": self.name, + "manufacturer": "Dynalite", + } @property def brightness(self): @@ -77,8 +82,15 @@ class DynaliteLight(Light): """Flag supported features.""" return SUPPORT_BRIGHTNESS - @callback - def try_schedule_ha(self): - """Schedule update HA state if configured.""" - if self.hass: - self.schedule_update_ha_state() + async def async_added_to_hass(self): + """Added to hass so need to register to dispatch.""" + # register for device specific update + async_dispatcher_connect( + self.hass, + self._bridge.update_signal(self._device), + self.async_schedule_update_ha_state, + ) + # register for wide update + async_dispatcher_connect( + self.hass, self._bridge.update_signal(), self.async_schedule_update_ha_state + ) diff --git a/homeassistant/components/dynalite/manifest.json b/homeassistant/components/dynalite/manifest.json index 4df580c16a2..95667733d38 100755 --- a/homeassistant/components/dynalite/manifest.json +++ b/homeassistant/components/dynalite/manifest.json @@ -5,5 +5,5 @@ "documentation": "https://www.home-assistant.io/integrations/dynalite", "dependencies": [], "codeowners": ["@ziv1234"], - "requirements": ["dynalite_devices==0.1.17"] + "requirements": ["dynalite_devices==0.1.22"] } diff --git a/requirements_all.txt b/requirements_all.txt index 78216da0674..83dde0f26e2 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -456,7 +456,7 @@ dsmr_parser==0.18 dweepy==0.3.0 # homeassistant.components.dynalite -dynalite_devices==0.1.17 +dynalite_devices==0.1.22 # homeassistant.components.rainforest_eagle eagle200_reader==0.2.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 9e7201ade66..d8924efeaab 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -168,7 +168,7 @@ distro==1.4.0 dsmr_parser==0.18 # homeassistant.components.dynalite -dynalite_devices==0.1.17 +dynalite_devices==0.1.22 # homeassistant.components.ee_brightbox eebrightbox==0.0.4 diff --git a/tests/components/dynalite/test_bridge.py b/tests/components/dynalite/test_bridge.py index c0aa2b3c143..133e03d9f3d 100755 --- a/tests/components/dynalite/test_bridge.py +++ b/tests/components/dynalite/test_bridge.py @@ -1,136 +1,81 @@ """Test Dynalite bridge.""" -from unittest.mock import Mock, call, patch +from unittest.mock import Mock, call +from asynctest import patch from dynalite_lib import CONF_ALL import pytest -from homeassistant.components.dynalite import DATA_CONFIGS, DOMAIN -from homeassistant.components.dynalite.bridge import BridgeError, DynaliteBridge - -from tests.common import mock_coro +from homeassistant.components import dynalite -async def test_bridge_setup(): +@pytest.fixture +def dyn_bridge(): + """Define a basic mock bridge.""" + hass = Mock() + host = "1.2.3.4" + bridge = dynalite.DynaliteBridge(hass, {dynalite.CONF_HOST: host}) + return bridge + + +async def test_update_device(dyn_bridge): """Test a successful setup.""" - hass = Mock() - entry = Mock() - host = "1.2.3.4" - entry.data = {"host": host} - hass.data = {DOMAIN: {DATA_CONFIGS: {host: {}}}} - dyn_bridge = DynaliteBridge(hass, entry) + async_dispatch = Mock() - with patch.object( - dyn_bridge.dynalite_devices, "async_setup", return_value=mock_coro(True) + with patch( + "homeassistant.components.dynalite.bridge.async_dispatcher_send", async_dispatch ): - assert await dyn_bridge.async_setup() is True - - forward_entries = set( - c[1][1] for c in hass.config_entries.async_forward_entry_setup.mock_calls - ) - hass.config_entries.async_forward_entry_setup.assert_called_once() - assert forward_entries == set(["light"]) + dyn_bridge.update_device(CONF_ALL) + async_dispatch.assert_called_once() + assert async_dispatch.mock_calls[0] == call( + dyn_bridge.hass, f"dynalite-update-{dyn_bridge.host}" + ) + async_dispatch.reset_mock() + device = Mock + device.unique_id = "abcdef" + dyn_bridge.update_device(device) + async_dispatch.assert_called_once() + assert async_dispatch.mock_calls[0] == call( + dyn_bridge.hass, f"dynalite-update-{dyn_bridge.host}-{device.unique_id}" + ) -async def test_invalid_host(): - """Test without host in hass.data.""" - hass = Mock() - entry = Mock() - host = "1.2.3.4" - entry.data = {"host": host} - hass.data = {DOMAIN: {DATA_CONFIGS: {}}} - - dyn_bridge = None - with pytest.raises(BridgeError): - dyn_bridge = DynaliteBridge(hass, entry) - assert dyn_bridge is None - - -async def test_add_devices_then_register(): +async def test_add_devices_then_register(dyn_bridge): """Test that add_devices work.""" - hass = Mock() - entry = Mock() - host = "1.2.3.4" - entry.data = {"host": host} - hass.data = {DOMAIN: {DATA_CONFIGS: {host: {}}}} - dyn_bridge = DynaliteBridge(hass, entry) - + # First test empty + dyn_bridge.add_devices_when_registered([]) + assert not dyn_bridge.waiting_devices + # Now with devices device1 = Mock() device1.category = "light" device2 = Mock() device2.category = "switch" - dyn_bridge.add_devices([device1, device2]) + dyn_bridge.add_devices_when_registered([device1, device2]) reg_func = Mock() - dyn_bridge.register_add_entities(reg_func) + dyn_bridge.register_add_devices(reg_func) reg_func.assert_called_once() - assert reg_func.mock_calls[0][1][0][0].device is device1 + assert reg_func.mock_calls[0][1][0][0] is device1 -async def test_register_then_add_devices(): +async def test_register_then_add_devices(dyn_bridge): """Test that add_devices work after register_add_entities.""" - hass = Mock() - entry = Mock() - host = "1.2.3.4" - entry.data = {"host": host} - hass.data = {DOMAIN: {DATA_CONFIGS: {host: {}}}} - dyn_bridge = DynaliteBridge(hass, entry) - device1 = Mock() device1.category = "light" device2 = Mock() device2.category = "switch" reg_func = Mock() - dyn_bridge.register_add_entities(reg_func) - dyn_bridge.add_devices([device1, device2]) + dyn_bridge.register_add_devices(reg_func) + dyn_bridge.add_devices_when_registered([device1, device2]) reg_func.assert_called_once() - assert reg_func.mock_calls[0][1][0][0].device is device1 + assert reg_func.mock_calls[0][1][0][0] is device1 -async def test_update_device(): - """Test the update_device callback.""" - hass = Mock() - entry = Mock() - host = "1.2.3.4" - entry.data = {"host": host} - hass.data = {DOMAIN: {DATA_CONFIGS: {host: {}}}} - dyn_bridge = DynaliteBridge(hass, entry) - with patch.object(dyn_bridge, "dynalite_devices") as devices_mock: - # Single device update - device1 = Mock() - device1.unique_id = "testing1" - device2 = Mock() - device2.unique_id = "testing2" - dyn_bridge.all_entities = { - device1.unique_id: device1, - device2.unique_id: device2, - } - dyn_bridge.update_device(device1) - device1.try_schedule_ha.assert_called_once() - device2.try_schedule_ha.assert_not_called() - # connected to network - all devices update - devices_mock.available = True - dyn_bridge.update_device(CONF_ALL) - assert device1.try_schedule_ha.call_count == 2 - device2.try_schedule_ha.assert_called_once() - # disconnected from network - all devices update - devices_mock.available = False - dyn_bridge.update_device(CONF_ALL) - assert device1.try_schedule_ha.call_count == 3 - assert device2.try_schedule_ha.call_count == 2 - - -async def test_async_reset(): - """Test async_reset.""" - hass = Mock() - hass.config_entries.async_forward_entry_unload = Mock( - return_value=mock_coro(Mock()) - ) - entry = Mock() - host = "1.2.3.4" - entry.data = {"host": host} - hass.data = {DOMAIN: {DATA_CONFIGS: {host: {}}}} - dyn_bridge = DynaliteBridge(hass, entry) - await dyn_bridge.async_reset() - hass.config_entries.async_forward_entry_unload.assert_called_once() - assert hass.config_entries.async_forward_entry_unload.mock_calls[0] == call( - entry, "light" - ) +async def test_try_connection(dyn_bridge): + """Test that try connection works.""" + # successful + with patch.object(dyn_bridge.dynalite_devices, "connected", True): + assert await dyn_bridge.try_connection() + # unsuccessful + with patch.object(dyn_bridge.dynalite_devices, "connected", False), patch( + "homeassistant.components.dynalite.bridge.CONNECT_INTERVAL", 0 + ): + assert not await dyn_bridge.try_connection() diff --git a/tests/components/dynalite/test_config_flow.py b/tests/components/dynalite/test_config_flow.py index 1cf82143f1b..1f8be61f646 100755 --- a/tests/components/dynalite/test_config_flow.py +++ b/tests/components/dynalite/test_config_flow.py @@ -1,36 +1,90 @@ """Test Dynalite config flow.""" -from unittest.mock import Mock, call, patch +from asynctest import patch -from homeassistant.components.dynalite import config_flow +from homeassistant import config_entries +from homeassistant.components import dynalite -from tests.common import mock_coro +from tests.common import MockConfigEntry -async def test_step_import(): - """Test a successful setup.""" - flow_handler = config_flow.DynaliteFlowHandler() - with patch.object(flow_handler, "context", create=True): - with patch.object(flow_handler, "hass", create=True) as mock_hass: - with patch.object( - flow_handler, "async_create_entry", create=True - ) as mock_create: - host = "1.2.3.4" - entry1 = Mock() - entry1.data = {"host": host} - entry2 = Mock() - entry2.data = {"host": "5.5"} - mock_hass.config_entries.async_entries = Mock( - return_value=[entry1, entry2] - ) - mock_hass.config_entries.async_remove = Mock( - return_value=mock_coro(Mock()) - ) - await flow_handler.async_step_import({"host": "1.2.3.4"}) - mock_hass.config_entries.async_remove.assert_called_once() - assert mock_hass.config_entries.async_remove.mock_calls[0] == call( - entry1.entry_id - ) - mock_create.assert_called_once() - assert mock_create.mock_calls[0] == call( - title=host, data={"host": host} - ) +async def run_flow(hass, setup, connection): + """Run a flow with or without errors and return result.""" + host = "1.2.3.4" + with patch( + "homeassistant.components.dynalite.bridge.DynaliteDevices.async_setup", + return_value=setup, + ), patch( + "homeassistant.components.dynalite.bridge.DynaliteDevices.available", connection + ), patch( + "homeassistant.components.dynalite.bridge.CONNECT_INTERVAL", 0 + ): + result = await hass.config_entries.flow.async_init( + dynalite.DOMAIN, + context={"source": config_entries.SOURCE_IMPORT}, + data={dynalite.CONF_HOST: host}, + ) + return result + + +async def test_flow_works(hass): + """Test a successful config flow.""" + result = await run_flow(hass, True, True) + assert result["type"] == "create_entry" + + +async def test_flow_setup_fails(hass): + """Test a flow where async_setup fails.""" + result = await run_flow(hass, False, True) + assert result["type"] == "abort" + assert result["reason"] == "bridge_setup_failed" + + +async def test_flow_no_connection(hass): + """Test a flow where connection times out.""" + result = await run_flow(hass, True, False) + assert result["type"] == "abort" + assert result["reason"] == "no_connection" + + +async def test_existing(hass): + """Test when the entry exists with the same config.""" + host = "1.2.3.4" + MockConfigEntry( + domain=dynalite.DOMAIN, unique_id=host, data={dynalite.CONF_HOST: host} + ).add_to_hass(hass) + with patch( + "homeassistant.components.dynalite.bridge.DynaliteDevices.async_setup", + return_value=True, + ), patch( + "homeassistant.components.dynalite.bridge.DynaliteDevices.available", True + ): + result = await hass.config_entries.flow.async_init( + dynalite.DOMAIN, + context={"source": config_entries.SOURCE_IMPORT}, + data={dynalite.CONF_HOST: host}, + ) + assert result["type"] == "abort" + assert result["reason"] == "already_configured" + + +async def test_existing_update(hass): + """Test when the entry exists with the same config.""" + host = "1.2.3.4" + mock_entry = MockConfigEntry( + domain=dynalite.DOMAIN, unique_id=host, data={dynalite.CONF_HOST: host} + ) + mock_entry.add_to_hass(hass) + with patch( + "homeassistant.components.dynalite.bridge.DynaliteDevices.async_setup", + return_value=True, + ), patch( + "homeassistant.components.dynalite.bridge.DynaliteDevices.available", True + ): + result = await hass.config_entries.flow.async_init( + dynalite.DOMAIN, + context={"source": config_entries.SOURCE_IMPORT}, + data={dynalite.CONF_HOST: host, "aaa": "bbb"}, + ) + assert result["type"] == "abort" + assert result["reason"] == "already_configured" + assert mock_entry.data.get("aaa") == "bbb" diff --git a/tests/components/dynalite/test_init.py b/tests/components/dynalite/test_init.py index beb96a5e78f..d8ef0d7d259 100755 --- a/tests/components/dynalite/test_init.py +++ b/tests/components/dynalite/test_init.py @@ -1,74 +1,62 @@ """Test Dynalite __init__.""" -from unittest.mock import Mock, call, patch -from homeassistant.components.dynalite import DATA_CONFIGS, DOMAIN, LOGGER -from homeassistant.components.dynalite.__init__ import ( - async_setup, - async_setup_entry, - async_unload_entry, -) +from asynctest import patch -from tests.common import mock_coro +from homeassistant.components import dynalite +from homeassistant.setup import async_setup_component + +from tests.common import MockConfigEntry -async def test_async_setup(): +async def test_empty_config(hass): + """Test with an empty config.""" + assert await async_setup_component(hass, dynalite.DOMAIN, {}) is True + assert len(hass.config_entries.flow.async_progress()) == 0 + assert hass.data[dynalite.DOMAIN] == {} + + +async def test_async_setup(hass): """Test a successful setup.""" - new_host = "1.2.3.4" - old_host = "5.6.7.8" - hass = Mock() - hass.data = {} - config = {DOMAIN: {"bridges": [{"host": old_host}, {"host": new_host}]}} - mock_conf_host = Mock(return_value=[old_host]) - with patch( - "homeassistant.components.dynalite.__init__.configured_hosts", mock_conf_host - ): - await async_setup(hass, config) - mock_conf_host.assert_called_once() - assert mock_conf_host.mock_calls[0] == call(hass) - assert hass.data[DOMAIN][DATA_CONFIGS] == { - new_host: {"host": new_host}, - old_host: {"host": old_host}, - } - hass.async_create_task.assert_called_once() - - -async def test_async_setup_entry(): - """Test setup of an entry.""" - - def async_mock(mock): - """Return the return value of a mock from async.""" - - async def async_func(*args, **kwargs): - return mock() - - return async_func - host = "1.2.3.4" - hass = Mock() - entry = Mock() - entry.data = {"host": host} - hass.data = {} - hass.data[DOMAIN] = {} - hass.data[DOMAIN][DATA_CONFIGS] = {host: {}} - mock_async_setup = Mock(return_value=True) with patch( - "homeassistant.components.dynalite.__init__.DynaliteBridge.async_setup", - async_mock(mock_async_setup), - ): - assert await async_setup_entry(hass, entry) - mock_async_setup.assert_called_once() + "dynalite_devices_lib.DynaliteDevices.async_setup", return_value=True + ), patch("dynalite_devices_lib.DynaliteDevices.available", True): + assert await async_setup_component( + hass, + dynalite.DOMAIN, + {dynalite.DOMAIN: {dynalite.CONF_BRIDGES: [{dynalite.CONF_HOST: host}]}}, + ) + + assert len(hass.data[dynalite.DOMAIN]) == 1 -async def test_async_unload_entry(): - """Test unloading of an entry.""" - hass = Mock() - mock_bridge = Mock() - mock_bridge.async_reset.return_value = mock_coro(True) - entry = Mock() - hass.data = {} - hass.data[DOMAIN] = {} - hass.data[DOMAIN][entry.entry_id] = mock_bridge - await async_unload_entry(hass, entry) - LOGGER.error("XXX calls=%s", mock_bridge.mock_calls) - mock_bridge.async_reset.assert_called_once() - assert mock_bridge.mock_calls[0] == call.async_reset() +async def test_async_setup_failed(hass): + """Test a setup when DynaliteBridge.async_setup fails.""" + host = "1.2.3.4" + with patch("dynalite_devices_lib.DynaliteDevices.async_setup", return_value=False): + assert await async_setup_component( + hass, + dynalite.DOMAIN, + {dynalite.DOMAIN: {dynalite.CONF_BRIDGES: [{dynalite.CONF_HOST: host}]}}, + ) + assert hass.data[dynalite.DOMAIN] == {} + + +async def test_unload_entry(hass): + """Test being able to unload an entry.""" + host = "1.2.3.4" + entry = MockConfigEntry(domain=dynalite.DOMAIN, data={"host": host}) + entry.add_to_hass(hass) + + with patch( + "dynalite_devices_lib.DynaliteDevices.async_setup", return_value=True + ), patch("dynalite_devices_lib.DynaliteDevices.available", True): + assert await async_setup_component( + hass, + dynalite.DOMAIN, + {dynalite.DOMAIN: {dynalite.CONF_BRIDGES: [{dynalite.CONF_HOST: host}]}}, + ) + assert hass.data[dynalite.DOMAIN].get(entry.entry_id) + + assert await hass.config_entries.async_unload(entry.entry_id) + assert not hass.data[dynalite.DOMAIN].get(entry.entry_id) diff --git a/tests/components/dynalite/test_light.py b/tests/components/dynalite/test_light.py index cfc9d42d0e4..9934bac8720 100755 --- a/tests/components/dynalite/test_light.py +++ b/tests/components/dynalite/test_light.py @@ -1,44 +1,78 @@ """Test Dynalite light.""" -from unittest.mock import Mock, call, patch +from unittest.mock import Mock -from homeassistant.components.dynalite import DOMAIN -from homeassistant.components.dynalite.light import DynaliteLight, async_setup_entry +from asynctest import CoroutineMock, patch +import pytest -from tests.common import mock_coro +from homeassistant.components import dynalite +from homeassistant.components.light import SUPPORT_BRIGHTNESS +from homeassistant.setup import async_setup_component -async def test_light_setup(): - """Test a successful setup.""" - hass = Mock() - entry = Mock() - async_add = Mock() - bridge = Mock() - hass.data = {DOMAIN: {entry.entry_id: bridge}} - await async_setup_entry(hass, entry, async_add) - bridge.register_add_entities.assert_called_once() - assert bridge.register_add_entities.mock_calls[0] == call(async_add) - - -async def test_light(): - """Test the light entity.""" +@pytest.fixture +def mock_device(): + """Mock a Dynalite device.""" device = Mock() - device.async_turn_on = Mock(return_value=mock_coro(Mock())) - device.async_turn_off = Mock(return_value=mock_coro(Mock())) - bridge = Mock() - dyn_light = DynaliteLight(device, bridge) - assert dyn_light.name is device.name - assert dyn_light.unique_id is device.unique_id - assert dyn_light.available is device.available - assert dyn_light.hidden is device.hidden - await dyn_light.async_update() # does nothing - assert dyn_light.device_info is device.device_info - assert dyn_light.brightness is device.brightness - assert dyn_light.is_on is device.is_on - await dyn_light.async_turn_on(aaa="bbb") - assert device.async_turn_on.mock_calls[0] == call(aaa="bbb") - await dyn_light.async_turn_off(ccc="ddd") - assert device.async_turn_off.mock_calls[0] == call(ccc="ddd") - with patch.object(dyn_light, "hass"): - with patch.object(dyn_light, "schedule_update_ha_state") as update_ha: - dyn_light.try_schedule_ha() - update_ha.assert_called_once() + device.category = "light" + device.unique_id = "UNIQUE" + device.name = "NAME" + device.device_info = { + "identifiers": {(dynalite.DOMAIN, device.unique_id)}, + "name": device.name, + "manufacturer": "Dynalite", + } + return device + + +async def create_light_from_device(hass, device): + """Set up the component and platform and create a light based on the device provided.""" + host = "1.2.3.4" + with patch( + "homeassistant.components.dynalite.bridge.DynaliteDevices.async_setup", + return_value=True, + ), patch( + "homeassistant.components.dynalite.bridge.DynaliteDevices.available", True + ): + assert await async_setup_component( + hass, + dynalite.DOMAIN, + {dynalite.DOMAIN: {dynalite.CONF_BRIDGES: [{dynalite.CONF_HOST: host}]}}, + ) + await hass.async_block_till_done() + # Find the bridge + bridge = None + assert len(hass.data[dynalite.DOMAIN]) == 1 + key = next(iter(hass.data[dynalite.DOMAIN])) + bridge = hass.data[dynalite.DOMAIN][key] + bridge.dynalite_devices.newDeviceFunc([device]) + await hass.async_block_till_done() + + +async def test_light_setup(hass, mock_device): + """Test a successful setup.""" + await create_light_from_device(hass, mock_device) + entity_state = hass.states.get("light.name") + assert entity_state.attributes["brightness"] == mock_device.brightness + assert entity_state.attributes["supported_features"] == SUPPORT_BRIGHTNESS + + +async def test_turn_on(hass, mock_device): + """Test turning a light on.""" + mock_device.async_turn_on = CoroutineMock(return_value=True) + await create_light_from_device(hass, mock_device) + await hass.services.async_call( + "light", "turn_on", {"entity_id": "light.name"}, blocking=True + ) + await hass.async_block_till_done() + mock_device.async_turn_on.assert_awaited_once() + + +async def test_turn_off(hass, mock_device): + """Test turning a light off.""" + mock_device.async_turn_off = CoroutineMock(return_value=True) + await create_light_from_device(hass, mock_device) + await hass.services.async_call( + "light", "turn_off", {"entity_id": "light.name"}, blocking=True + ) + await hass.async_block_till_done() + mock_device.async_turn_off.assert_awaited_once() From a3b3ff52fc26074be2efdaff854a45a41323aa33 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 21 Feb 2020 17:36:19 -0800 Subject: [PATCH 14/39] Remove YAML config from Ring integration (#32039) --- homeassistant/components/ring/__init__.py | 27 +------------------- homeassistant/components/ring/config_flow.py | 7 ----- tests/components/ring/test_init.py | 24 ----------------- 3 files changed, 1 insertion(+), 57 deletions(-) diff --git a/homeassistant/components/ring/__init__.py b/homeassistant/components/ring/__init__.py index 34aa9f6b0ec..0d54db5993f 100644 --- a/homeassistant/components/ring/__init__.py +++ b/homeassistant/components/ring/__init__.py @@ -9,12 +9,9 @@ from typing import Optional from oauthlib.oauth2 import AccessDeniedError import requests from ring_doorbell import Auth, Ring -import voluptuous as vol -from homeassistant import config_entries -from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, __version__ +from homeassistant.const import __version__ from homeassistant.core import HomeAssistant, callback -import homeassistant.helpers.config_validation as cv from homeassistant.helpers.event import async_track_time_interval from homeassistant.util.async_ import run_callback_threadsafe @@ -30,18 +27,6 @@ DEFAULT_ENTITY_NAMESPACE = "ring" PLATFORMS = ("binary_sensor", "light", "sensor", "switch", "camera") -CONFIG_SCHEMA = vol.Schema( - { - vol.Optional(DOMAIN): vol.Schema( - { - vol.Required(CONF_USERNAME): cv.string, - vol.Required(CONF_PASSWORD): cv.string, - } - ) - }, - extra=vol.ALLOW_EXTRA, -) - async def async_setup(hass, config): """Set up the Ring component.""" @@ -56,16 +41,6 @@ async def async_setup(hass, config): await hass.async_add_executor_job(legacy_cleanup) - hass.async_create_task( - hass.config_entries.flow.async_init( - DOMAIN, - context={"source": config_entries.SOURCE_IMPORT}, - data={ - "username": config[DOMAIN]["username"], - "password": config[DOMAIN]["password"], - }, - ) - ) return True diff --git a/homeassistant/components/ring/config_flow.py b/homeassistant/components/ring/config_flow.py index a25e0283753..fd9dbe0a17e 100644 --- a/homeassistant/components/ring/config_flow.py +++ b/homeassistant/components/ring/config_flow.py @@ -75,13 +75,6 @@ class RingConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): step_id="2fa", data_schema=vol.Schema({"2fa": str}), ) - async def async_step_import(self, user_input): - """Handle import.""" - if self._async_current_entries(): - return self.async_abort(reason="already_configured") - - return await self.async_step_user(user_input) - class Require2FA(exceptions.HomeAssistantError): """Error to indicate we require 2FA.""" diff --git a/tests/components/ring/test_init.py b/tests/components/ring/test_init.py index 809c71562c0..39d2c63ffdd 100644 --- a/tests/components/ring/test_init.py +++ b/tests/components/ring/test_init.py @@ -1,12 +1,10 @@ """The tests for the Ring component.""" from asyncio import run_coroutine_threadsafe -from copy import deepcopy from datetime import timedelta import unittest import requests_mock -from homeassistant import setup import homeassistant.components.ring as ring from tests.common import get_test_home_assistant, load_fixture @@ -57,25 +55,3 @@ class TestRing(unittest.TestCase): ).result() assert response - - @requests_mock.Mocker() - def test_setup_component_no_login(self, mock): - """Test the setup when no login is configured.""" - mock.post( - "https://api.ring.com/clients_api/session", - text=load_fixture("ring_session.json"), - ) - conf = deepcopy(VALID_CONFIG) - del conf["ring"]["username"] - assert not setup.setup_component(self.hass, ring.DOMAIN, conf) - - @requests_mock.Mocker() - def test_setup_component_no_pwd(self, mock): - """Test the setup when no password is configured.""" - mock.post( - "https://api.ring.com/clients_api/session", - text=load_fixture("ring_session.json"), - ) - conf = deepcopy(VALID_CONFIG) - del conf["ring"]["password"] - assert not setup.setup_component(self.hass, ring.DOMAIN, conf) From cc8430ebed699d17a43148b6e98cc0d2131c340a Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 21 Feb 2020 00:39:07 -0600 Subject: [PATCH 15/39] Fix i/o in august camera async image update (#32044) * Fix i/o in august camera image update * Address review comments --- homeassistant/components/august/camera.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/august/camera.py b/homeassistant/components/august/camera.py index afc22716421..5426d9574dc 100644 --- a/homeassistant/components/august/camera.py +++ b/homeassistant/components/august/camera.py @@ -64,12 +64,17 @@ class AugustCamera(Camera): if self._image_url is not latest.image_url: self._image_url = latest.image_url - self._image_content = requests.get( - self._image_url, timeout=self._timeout - ).content + self._image_content = await self.hass.async_add_executor_job( + self._camera_image + ) return self._image_content + def _camera_image(self): + """Return bytes of camera image via http get.""" + # Move this to py-august: see issue#32048 + return requests.get(self._image_url, timeout=self._timeout).content + @property def unique_id(self) -> str: """Get the unique id of the camera.""" From ca07ae5b1ea3b5f423f6520c75e37c6ea4e26827 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 20 Feb 2020 14:51:27 -0800 Subject: [PATCH 16/39] Updated frontend to 20200220.1 (#32046) --- homeassistant/components/frontend/manifest.json | 2 +- homeassistant/package_constraints.txt | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/frontend/manifest.json b/homeassistant/components/frontend/manifest.json index 04f0f45344d..993d63ea29b 100644 --- a/homeassistant/components/frontend/manifest.json +++ b/homeassistant/components/frontend/manifest.json @@ -3,7 +3,7 @@ "name": "Home Assistant Frontend", "documentation": "https://www.home-assistant.io/integrations/frontend", "requirements": [ - "home-assistant-frontend==20200220.0" + "home-assistant-frontend==20200220.1" ], "dependencies": [ "api", diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 542d8bcaabc..c2680ee54fe 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -11,7 +11,7 @@ cryptography==2.8 defusedxml==0.6.0 distro==1.4.0 hass-nabucasa==0.31 -home-assistant-frontend==20200220.0 +home-assistant-frontend==20200220.1 importlib-metadata==1.5.0 jinja2>=2.10.3 netdisco==2.6.0 diff --git a/requirements_all.txt b/requirements_all.txt index 83dde0f26e2..2fe89fc5bee 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -683,7 +683,7 @@ hole==0.5.0 holidays==0.10.1 # homeassistant.components.frontend -home-assistant-frontend==20200220.0 +home-assistant-frontend==20200220.1 # homeassistant.components.zwave homeassistant-pyozw==0.1.8 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index d8924efeaab..c1b575c6487 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -254,7 +254,7 @@ hole==0.5.0 holidays==0.10.1 # homeassistant.components.frontend -home-assistant-frontend==20200220.0 +home-assistant-frontend==20200220.1 # homeassistant.components.zwave homeassistant-pyozw==0.1.8 From 39fd7ca5d3f76230a51c944fff11dcf7fb450277 Mon Sep 17 00:00:00 2001 From: Maciej Bieniek Date: Fri, 21 Feb 2020 10:32:48 +0100 Subject: [PATCH 17/39] Bump brother to 0.1.6 (#32054) --- homeassistant/components/brother/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/brother/manifest.json b/homeassistant/components/brother/manifest.json index e63fb9b0d7c..51e6c3284ff 100644 --- a/homeassistant/components/brother/manifest.json +++ b/homeassistant/components/brother/manifest.json @@ -4,7 +4,7 @@ "documentation": "https://www.home-assistant.io/integrations/brother", "dependencies": [], "codeowners": ["@bieniu"], - "requirements": ["brother==0.1.4"], + "requirements": ["brother==0.1.6"], "zeroconf": ["_printer._tcp.local."], "config_flow": true } diff --git a/requirements_all.txt b/requirements_all.txt index 2fe89fc5bee..1b7d1dada43 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -343,7 +343,7 @@ bravia-tv==1.0 broadlink==0.12.0 # homeassistant.components.brother -brother==0.1.4 +brother==0.1.6 # homeassistant.components.brottsplatskartan brottsplatskartan==0.0.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index c1b575c6487..5cbc1df6be5 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -124,7 +124,7 @@ bomradarloop==0.1.3 broadlink==0.12.0 # homeassistant.components.brother -brother==0.1.4 +brother==0.1.6 # homeassistant.components.buienradar buienradar==1.0.1 From 9dda44ffdde9331d05a0244c2edca6ab42b52a49 Mon Sep 17 00:00:00 2001 From: Alok Saboo Date: Fri, 21 Feb 2020 15:11:25 -0500 Subject: [PATCH 18/39] Add additional logging to rest sensor (#32068) --- homeassistant/components/rest/sensor.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/homeassistant/components/rest/sensor.py b/homeassistant/components/rest/sensor.py index 36fd27c29a5..70424325241 100644 --- a/homeassistant/components/rest/sensor.py +++ b/homeassistant/components/rest/sensor.py @@ -201,11 +201,13 @@ class RestSensor(Entity): self.rest.update() value = self.rest.data + _LOGGER.debug("Data fetched from resource: %s", value) content_type = self.rest.headers.get("content-type") if content_type and content_type.startswith("text/xml"): try: value = json.dumps(xmltodict.parse(value)) + _LOGGER.debug("JSON converted from XML: %s", value) except ExpatError: _LOGGER.warning( "REST xml result could not be parsed and converted to JSON." From f30ff314398e497b0166cfd304f1986f4a584ca9 Mon Sep 17 00:00:00 2001 From: jjlawren Date: Fri, 21 Feb 2020 15:07:26 -0600 Subject: [PATCH 19/39] Add ConfigEntryNotReady exception to Plex (#32071) --- homeassistant/components/plex/__init__.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/plex/__init__.py b/homeassistant/components/plex/__init__.py index 0f1873fc86f..c9b120f75f6 100644 --- a/homeassistant/components/plex/__init__.py +++ b/homeassistant/components/plex/__init__.py @@ -19,6 +19,7 @@ from homeassistant.const import ( CONF_VERIFY_SSL, EVENT_HOMEASSISTANT_STOP, ) +from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import config_validation as cv from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.dispatcher import ( @@ -129,7 +130,7 @@ async def async_setup_entry(hass, entry): server_config[CONF_URL], error, ) - return False + raise ConfigEntryNotReady except ( plexapi.exceptions.BadRequest, plexapi.exceptions.Unauthorized, From e78449904b66382092a42cb0e03e8cb3837a3c01 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 21 Feb 2020 17:38:43 -0800 Subject: [PATCH 20/39] Bumped version to 0.106.0b2 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 26f442947a9..815eea35a5f 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 106 -PATCH_VERSION = "0b1" +PATCH_VERSION = "0b2" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER = (3, 7, 0) From 1d075a7dd05b59b6b7a35b55df9a703b59e40b69 Mon Sep 17 00:00:00 2001 From: Tom Date: Sun, 23 Feb 2020 17:02:42 +0100 Subject: [PATCH 21/39] Fix Plugwise climate issues for new firmware #32080 (#32109) * Fix Plugwise climate issue firmare 3.1.11 (#32080) * Submit checklist actions --- homeassistant/components/plugwise/manifest.json | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/plugwise/manifest.json b/homeassistant/components/plugwise/manifest.json index 5fc3d189b69..601f017d42f 100644 --- a/homeassistant/components/plugwise/manifest.json +++ b/homeassistant/components/plugwise/manifest.json @@ -4,5 +4,5 @@ "documentation": "https://www.home-assistant.io/integrations/plugwise", "dependencies": [], "codeowners": ["@laetificat", "@CoMPaTech", "@bouwew"], - "requirements": ["haanna==0.14.1"] + "requirements": ["haanna==0.14.3"] } diff --git a/requirements_all.txt b/requirements_all.txt index 1b7d1dada43..93ec58526d7 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -644,7 +644,7 @@ ha-ffmpeg==2.0 ha-philipsjs==0.0.8 # homeassistant.components.plugwise -haanna==0.14.1 +haanna==0.14.3 # homeassistant.components.habitica habitipy==0.2.0 From 6f1f9bdd453821b8c19e6be6dd09f700a32ad917 Mon Sep 17 00:00:00 2001 From: Kit Klein <33464407+kit-klein@users.noreply.github.com> Date: Sun, 23 Feb 2020 16:54:18 -0500 Subject: [PATCH 22/39] 0.106 Beta - provide correctly formatted placeholders (#32119) --- .../components/konnected/config_flow.py | 14 ++-- .../components/konnected/test_config_flow.py | 15 ++++ tests/components/konnected/test_init.py | 68 +++++++++++++++++++ 3 files changed, 92 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/konnected/config_flow.py b/homeassistant/components/konnected/config_flow.py index 447211308ae..b6e0c00c465 100644 --- a/homeassistant/components/konnected/config_flow.py +++ b/homeassistant/components/konnected/config_flow.py @@ -270,6 +270,10 @@ class KonnectedFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): return self.async_show_form( step_id="user", + description_placeholders={ + "host": self.data.get(CONF_HOST, "Unknown"), + "port": self.data.get(CONF_PORT, "Unknown"), + }, data_schema=vol.Schema( { vol.Required(CONF_HOST, default=self.data.get(CONF_HOST)): str, @@ -556,7 +560,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow): } ), description_placeholders={ - "zone": "Zone {self.active_cfg}" + "zone": f"Zone {self.active_cfg}" if len(self.active_cfg) < 3 else self.active_cfg.upper }, @@ -594,7 +598,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow): } ), description_placeholders={ - "zone": "Zone {self.active_cfg}" + "zone": f"Zone {self.active_cfg}" if len(self.active_cfg) < 3 else self.active_cfg.upper() }, @@ -624,7 +628,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow): } ), description_placeholders={ - "zone": "Zone {self.active_cfg}" + "zone": f"Zone {self.active_cfg}" if len(self.active_cfg) < 3 else self.active_cfg.upper() }, @@ -671,7 +675,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow): } ), description_placeholders={ - "zone": "Zone {self.active_cfg}" + "zone": f"Zone {self.active_cfg}" if len(self.active_cfg) < 3 else self.active_cfg.upper() }, @@ -710,7 +714,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow): } ), description_placeholders={ - "zone": "Zone {self.active_cfg}" + "zone": f"Zone {self.active_cfg}" if len(self.active_cfg) < 3 else self.active_cfg.upper() }, diff --git a/tests/components/konnected/test_config_flow.py b/tests/components/konnected/test_config_flow.py index 9b7a498731d..8dfead58659 100644 --- a/tests/components/konnected/test_config_flow.py +++ b/tests/components/konnected/test_config_flow.py @@ -597,6 +597,9 @@ async def test_option_flow(hass, mock_panel): ) assert result["type"] == "form" assert result["step_id"] == "options_binary" + assert result["description_placeholders"] == { + "zone": "Zone 2", + } # zone 2 result = await hass.config_entries.options.async_configure( @@ -604,6 +607,9 @@ async def test_option_flow(hass, mock_panel): ) assert result["type"] == "form" assert result["step_id"] == "options_binary" + assert result["description_placeholders"] == { + "zone": "Zone 6", + } # zone 6 result = await hass.config_entries.options.async_configure( @@ -612,6 +618,9 @@ async def test_option_flow(hass, mock_panel): ) assert result["type"] == "form" assert result["step_id"] == "options_digital" + assert result["description_placeholders"] == { + "zone": "Zone 3", + } # zone 3 result = await hass.config_entries.options.async_configure( @@ -619,6 +628,9 @@ async def test_option_flow(hass, mock_panel): ) assert result["type"] == "form" assert result["step_id"] == "options_switch" + assert result["description_placeholders"] == { + "zone": "Zone 4", + } # zone 4 result = await hass.config_entries.options.async_configure( @@ -626,6 +638,9 @@ async def test_option_flow(hass, mock_panel): ) assert result["type"] == "form" assert result["step_id"] == "options_switch" + assert result["description_placeholders"] == { + "zone": "OUT", + } # zone out result = await hass.config_entries.options.async_configure( diff --git a/tests/components/konnected/test_init.py b/tests/components/konnected/test_init.py index e1a1d2e72f8..907f83cd981 100644 --- a/tests/components/konnected/test_init.py +++ b/tests/components/konnected/test_init.py @@ -250,6 +250,74 @@ async def test_setup_defined_hosts_no_known_auth(hass): assert len(hass.config_entries.flow.async_progress()) == 1 +async def test_setup_multiple(hass): + """Test we initiate config entry for multiple panels.""" + assert ( + await async_setup_component( + hass, + konnected.DOMAIN, + { + konnected.DOMAIN: { + konnected.CONF_ACCESS_TOKEN: "arandomstringvalue", + konnected.CONF_API_HOST: "http://192.168.86.32:8123", + konnected.CONF_DEVICES: [ + { + konnected.CONF_ID: "aabbccddeeff", + "binary_sensors": [ + { + "zone": 4, + "type": "motion", + "name": "Hallway Motion", + }, + { + "zone": 5, + "type": "window", + "name": "Master Bedroom Window", + }, + { + "zone": 6, + "type": "window", + "name": "Downstairs Windows", + }, + ], + "switches": [{"zone": "out", "name": "siren"}], + }, + { + konnected.CONF_ID: "445566778899", + "binary_sensors": [ + {"zone": 1, "type": "motion", "name": "Front"}, + {"zone": 2, "type": "window", "name": "Back"}, + ], + "switches": [ + { + "zone": "out", + "name": "Buzzer", + "momentary": 65, + "pause": 55, + "repeat": 4, + }, + ], + }, + ], + } + }, + ) + is True + ) + + # Flow started for discovered bridge + assert len(hass.config_entries.flow.async_progress()) == 2 + + # Globals saved + assert ( + hass.data[konnected.DOMAIN][konnected.CONF_ACCESS_TOKEN] == "arandomstringvalue" + ) + assert ( + hass.data[konnected.DOMAIN][konnected.CONF_API_HOST] + == "http://192.168.86.32:8123" + ) + + async def test_config_passed_to_config_entry(hass): """Test that configured options for a host are loaded via config entry.""" entry = MockConfigEntry( From 6edef444a72d1227bff006d54cfb36b76461d25e Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 24 Feb 2020 00:03:33 -0800 Subject: [PATCH 23/39] =?UTF-8?q?Properly=20define=20depenency=20for=20Scr?= =?UTF-8?q?ape=20integration=20on=20Rest=20integ=E2=80=A6=20(#32136)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- homeassistant/components/scrape/manifest.json | 1 + script/hassfest/dependencies.py | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/homeassistant/components/scrape/manifest.json b/homeassistant/components/scrape/manifest.json index e0800cdef27..90352bbd108 100644 --- a/homeassistant/components/scrape/manifest.json +++ b/homeassistant/components/scrape/manifest.json @@ -4,5 +4,6 @@ "documentation": "https://www.home-assistant.io/integrations/scrape", "requirements": ["beautifulsoup4==4.8.2"], "dependencies": [], + "after_dependencies": ["rest"], "codeowners": ["@fabaff"] } diff --git a/script/hassfest/dependencies.py b/script/hassfest/dependencies.py index 4d8fbb226f8..c909b6216a9 100644 --- a/script/hassfest/dependencies.py +++ b/script/hassfest/dependencies.py @@ -133,8 +133,6 @@ IGNORE_VIOLATIONS = { # These should be extracted to external package "pvoutput", "dwd_weather_warnings", - # Should be rewritten to use own data fetcher - "scrape", } From 45d63e22d5175748b9787c6d67fd39cefe3a9722 Mon Sep 17 00:00:00 2001 From: Raman Gupta <7243222+raman325@users.noreply.github.com> Date: Mon, 24 Feb 2020 17:37:54 -0500 Subject: [PATCH 24/39] Fix vizio bug to use 'get' to get volume_step since it is optional (#32151) * use get to get volume_step since it is optional * always set volume_step to default in options and data if its not included --- homeassistant/components/vizio/config_flow.py | 7 +++++-- tests/components/vizio/test_config_flow.py | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/vizio/config_flow.py b/homeassistant/components/vizio/config_flow.py index 4fba0f06165..c2b2bf05336 100644 --- a/homeassistant/components/vizio/config_flow.py +++ b/homeassistant/components/vizio/config_flow.py @@ -177,8 +177,11 @@ class VizioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): if entry.data[CONF_NAME] != import_config[CONF_NAME]: updated_name[CONF_NAME] = import_config[CONF_NAME] - if entry.data[CONF_VOLUME_STEP] != import_config[CONF_VOLUME_STEP]: - updated_options[CONF_VOLUME_STEP] = import_config[CONF_VOLUME_STEP] + import_volume_step = import_config.get( + CONF_VOLUME_STEP, DEFAULT_VOLUME_STEP + ) + if entry.data.get(CONF_VOLUME_STEP) != import_volume_step: + updated_options[CONF_VOLUME_STEP] = import_volume_step if updated_options or updated_name: new_data = entry.data.copy() diff --git a/tests/components/vizio/test_config_flow.py b/tests/components/vizio/test_config_flow.py index 5a24e2d1d69..9683ebd87b0 100644 --- a/tests/components/vizio/test_config_flow.py +++ b/tests/components/vizio/test_config_flow.py @@ -300,15 +300,15 @@ async def test_import_flow_update_options( result = await hass.config_entries.flow.async_init( DOMAIN, context={"source": SOURCE_IMPORT}, - data=vol.Schema(VIZIO_SCHEMA)(MOCK_IMPORT_VALID_TV_CONFIG), + data=vol.Schema(VIZIO_SCHEMA)(MOCK_SPEAKER_CONFIG), ) await hass.async_block_till_done() - assert result["result"].options == {CONF_VOLUME_STEP: VOLUME_STEP} + assert result["result"].options == {CONF_VOLUME_STEP: DEFAULT_VOLUME_STEP} assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY entry_id = result["result"].entry_id - updated_config = MOCK_IMPORT_VALID_TV_CONFIG.copy() + updated_config = MOCK_SPEAKER_CONFIG.copy() updated_config[CONF_VOLUME_STEP] = VOLUME_STEP + 1 result = await hass.config_entries.flow.async_init( DOMAIN, From 5dc93aeeb15624ffda1ccc5684ede7cc6589f93e Mon Sep 17 00:00:00 2001 From: Raman Gupta <7243222+raman325@users.noreply.github.com> Date: Mon, 24 Feb 2020 22:35:28 -0500 Subject: [PATCH 25/39] Improve Vizio fix to avoid KeyError (#32163) * dont set default volume_step on import check * ensure config entry data['volume_step'] is set * consolidate entry update during entry setup --- homeassistant/components/vizio/config_flow.py | 7 ++----- homeassistant/components/vizio/media_player.py | 14 +++++++++++--- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/vizio/config_flow.py b/homeassistant/components/vizio/config_flow.py index c2b2bf05336..ea0e9ede237 100644 --- a/homeassistant/components/vizio/config_flow.py +++ b/homeassistant/components/vizio/config_flow.py @@ -177,11 +177,8 @@ class VizioConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): if entry.data[CONF_NAME] != import_config[CONF_NAME]: updated_name[CONF_NAME] = import_config[CONF_NAME] - import_volume_step = import_config.get( - CONF_VOLUME_STEP, DEFAULT_VOLUME_STEP - ) - if entry.data.get(CONF_VOLUME_STEP) != import_volume_step: - updated_options[CONF_VOLUME_STEP] = import_volume_step + if entry.data.get(CONF_VOLUME_STEP) != import_config[CONF_VOLUME_STEP]: + updated_options[CONF_VOLUME_STEP] = import_config[CONF_VOLUME_STEP] if updated_options or updated_name: new_data = entry.data.copy() diff --git a/homeassistant/components/vizio/media_player.py b/homeassistant/components/vizio/media_player.py index 349373017da..7d76505a457 100644 --- a/homeassistant/components/vizio/media_player.py +++ b/homeassistant/components/vizio/media_player.py @@ -56,10 +56,18 @@ async def async_setup_entry( volume_step = config_entry.options.get( CONF_VOLUME_STEP, config_entry.data.get(CONF_VOLUME_STEP, DEFAULT_VOLUME_STEP), ) + + params = {} if not config_entry.options: - hass.config_entries.async_update_entry( - config_entry, options={CONF_VOLUME_STEP: volume_step} - ) + params["options"] = {CONF_VOLUME_STEP: volume_step} + + if not config_entry.data.get(CONF_VOLUME_STEP): + new_data = config_entry.data.copy() + new_data.update({CONF_VOLUME_STEP: volume_step}) + params["data"] = new_data + + if params: + hass.config_entries.async_update_entry(config_entry, **params) device = VizioAsync( DEVICE_ID, From 9e832aaaa651076d8e5353efef1c909fd377a8d6 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 24 Feb 2020 19:36:26 -0800 Subject: [PATCH 26/39] Bumped version to 0.106.0b3 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 815eea35a5f..1c875afc200 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 106 -PATCH_VERSION = "0b2" +PATCH_VERSION = "0b3" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER = (3, 7, 0) From 9007d37de175caf4ef961656bf6e3e41cd5b1958 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 24 Feb 2020 21:05:10 -0800 Subject: [PATCH 27/39] Bumped version to 0.106.0b4 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 1c875afc200..c509ee5f0fa 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 106 -PATCH_VERSION = "0b3" +PATCH_VERSION = "0b4" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER = (3, 7, 0) From 61e2ce5faf2a1015bb94af0a62e4ad127a9065ac Mon Sep 17 00:00:00 2001 From: Kit Klein <33464407+kit-klein@users.noreply.github.com> Date: Tue, 25 Feb 2020 07:55:06 -0500 Subject: [PATCH 28/39] Dedup and clarify imported konnected config flows (#32138) * dedup config flows * use default (imported) options until user goes thru options flow * address pr feedback * correct key used to distinguish pro model --- .../konnected/.translations/en.json | 7 +- .../components/konnected/config_flow.py | 55 +- homeassistant/components/konnected/const.py | 1 + homeassistant/components/konnected/panel.py | 5 +- .../components/konnected/strings.json | 6 +- .../components/konnected/test_config_flow.py | 103 +++- tests/components/konnected/test_panel.py | 482 ++++++++++++------ 7 files changed, 478 insertions(+), 181 deletions(-) diff --git a/homeassistant/components/konnected/.translations/en.json b/homeassistant/components/konnected/.translations/en.json index cb6d2d24ff1..9d642a43603 100644 --- a/homeassistant/components/konnected/.translations/en.json +++ b/homeassistant/components/konnected/.translations/en.json @@ -11,9 +11,13 @@ }, "step": { "confirm": { - "description": "Model: {model}\nHost: {host}\nPort: {port}\n\nYou can configure the IO and panel behavior in the Konnected Alarm Panel settings.", + "description": "Model: {model}\nID: {id}\nHost: {host}\nPort: {port}\n\nYou can configure the IO and panel behavior in the Konnected Alarm Panel settings.", "title": "Konnected Device Ready" }, + "import_confirm": { + "description": "A Konnected Alarm Panel with ID {id} has been discovered in configuration.yaml. This flow will allow you to import it into a config entry.", + "title": "Import Konnected Device" + }, "user": { "data": { "host": "Konnected device IP address", @@ -29,6 +33,7 @@ "abort": { "not_konn_panel": "Not a recognized Konnected.io device" }, + "error": {}, "step": { "options_binary": { "data": { diff --git a/homeassistant/components/konnected/config_flow.py b/homeassistant/components/konnected/config_flow.py index b6e0c00c465..cb9004c9efe 100644 --- a/homeassistant/components/konnected/config_flow.py +++ b/homeassistant/components/konnected/config_flow.py @@ -32,6 +32,7 @@ from homeassistant.helpers import config_validation as cv from .const import ( CONF_ACTIVATION, CONF_BLINK, + CONF_DEFAULT_OPTIONS, CONF_DISCOVERY, CONF_INVERSE, CONF_MODEL, @@ -138,7 +139,6 @@ OPTIONS_SCHEMA = vol.Schema( extra=vol.REMOVE_EXTRA, ) -CONF_DEFAULT_OPTIONS = "default_options" CONFIG_ENTRY_SCHEMA = vol.Schema( { vol.Required(CONF_ID): cv.matches_regex("[0-9a-f]{12}"), @@ -158,6 +158,9 @@ class KonnectedFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): VERSION = 1 CONNECTION_CLASS = config_entries.CONN_CLASS_LOCAL_PUSH + # class variable to store/share discovered host information + discovered_hosts = {} + # pylint: disable=no-member # https://github.com/PyCQA/pylint/issues/3167 def __init__(self): @@ -178,7 +181,7 @@ class KonnectedFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): except (CannotConnect, KeyError): raise CannotConnect else: - self.data[CONF_MODEL] = status.get("name", KONN_MODEL) + self.data[CONF_MODEL] = status.get("model", KONN_MODEL) self.data[CONF_ACCESS_TOKEN] = "".join( random.choices(f"{string.ascii_uppercase}{string.digits}", k=20) ) @@ -196,6 +199,7 @@ class KonnectedFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): # config schema ensures we have port if we have host if device_config.get(CONF_HOST): + # automatically connect if we have host info return await self.async_step_user( user_input={ CONF_HOST: device_config[CONF_HOST], @@ -205,6 +209,28 @@ class KonnectedFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): # if we have no host info wait for it or abort if previously configured self._abort_if_unique_id_configured() + return await self.async_step_import_confirm() + + async def async_step_import_confirm(self, user_input=None): + """Confirm the user wants to import the config entry.""" + if user_input is None: + return self.async_show_form( + step_id="import_confirm", + description_placeholders={"id": self.unique_id}, + ) + + # if we have ssdp discovered applicable host info use it + if KonnectedFlowHandler.discovered_hosts.get(self.unique_id): + return await self.async_step_user( + user_input={ + CONF_HOST: KonnectedFlowHandler.discovered_hosts[self.unique_id][ + CONF_HOST + ], + CONF_PORT: KonnectedFlowHandler.discovered_hosts[self.unique_id][ + CONF_PORT + ], + } + ) return await self.async_step_user() async def async_step_ssdp(self, discovery_info): @@ -265,7 +291,13 @@ class KonnectedFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): errors["base"] = "cannot_connect" else: self.data[CONF_ID] = status["mac"].replace(":", "") - self.data[CONF_MODEL] = status.get("name", KONN_MODEL) + self.data[CONF_MODEL] = status.get("model", KONN_MODEL) + + # save off our discovered host info + KonnectedFlowHandler.discovered_hosts[self.data[CONF_ID]] = { + CONF_HOST: self.data[CONF_HOST], + CONF_PORT: self.data[CONF_PORT], + } return await self.async_step_confirm() return self.async_show_form( @@ -290,23 +322,14 @@ class KonnectedFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): the connection. """ if user_input is None: - # update an existing config entry if host info changes - entry = await self.async_set_unique_id( - self.data[CONF_ID], raise_on_progress=False - ) - if entry and ( - entry.data[CONF_HOST] != self.data[CONF_HOST] - or entry.data[CONF_PORT] != self.data[CONF_PORT] - ): - entry_data = copy.deepcopy(entry.data) - entry_data.update(self.data) - self.hass.config_entries.async_update_entry(entry, data=entry_data) - - self._abort_if_unique_id_configured() + # abort and update an existing config entry if host info changes + await self.async_set_unique_id(self.data[CONF_ID]) + self._abort_if_unique_id_configured(updates=self.data) return self.async_show_form( step_id="confirm", description_placeholders={ "model": KONN_PANEL_MODEL_NAMES[self.data[CONF_MODEL]], + "id": self.unique_id, "host": self.data[CONF_HOST], "port": self.data[CONF_PORT], }, diff --git a/homeassistant/components/konnected/const.py b/homeassistant/components/konnected/const.py index d8777a5611e..d6819dcf71f 100644 --- a/homeassistant/components/konnected/const.py +++ b/homeassistant/components/konnected/const.py @@ -4,6 +4,7 @@ DOMAIN = "konnected" CONF_ACTIVATION = "activation" CONF_API_HOST = "api_host" +CONF_DEFAULT_OPTIONS = "default_options" CONF_MOMENTARY = "momentary" CONF_PAUSE = "pause" CONF_POLL_INTERVAL = "poll_interval" diff --git a/homeassistant/components/konnected/panel.py b/homeassistant/components/konnected/panel.py index 9f4b39e82bc..2668a382ccc 100644 --- a/homeassistant/components/konnected/panel.py +++ b/homeassistant/components/konnected/panel.py @@ -28,6 +28,7 @@ from .const import ( CONF_ACTIVATION, CONF_API_HOST, CONF_BLINK, + CONF_DEFAULT_OPTIONS, CONF_DHT_SENSORS, CONF_DISCOVERY, CONF_DS18B20_SENSORS, @@ -64,7 +65,9 @@ class AlarmPanel: self.hass = hass self.config_entry = config_entry self.config = config_entry.data - self.options = config_entry.options + self.options = config_entry.options or config_entry.data.get( + CONF_DEFAULT_OPTIONS, {} + ) self.host = self.config.get(CONF_HOST) self.port = self.config.get(CONF_PORT) self.client = None diff --git a/homeassistant/components/konnected/strings.json b/homeassistant/components/konnected/strings.json index 1f27b04d811..4d923238df4 100644 --- a/homeassistant/components/konnected/strings.json +++ b/homeassistant/components/konnected/strings.json @@ -2,6 +2,10 @@ "config": { "title": "Konnected.io", "step": { + "import_confirm": { + "title": "Import Konnected Device", + "description": "A Konnected Alarm Panel with ID {id} has been discovered in configuration.yaml. This flow will allow you to import it into a config entry." + }, "user": { "title": "Discover Konnected Device", "description": "Please enter the host information for your Konnected Panel.", @@ -12,7 +16,7 @@ }, "confirm": { "title": "Konnected Device Ready", - "description": "Model: {model}\nHost: {host}\nPort: {port}\n\nYou can configure the IO and panel behavior in the Konnected Alarm Panel settings." + "description": "Model: {model}\nID: {id}\nHost: {host}\nPort: {port}\n\nYou can configure the IO and panel behavior in the Konnected Alarm Panel settings." } }, "error": { diff --git a/tests/components/konnected/test_config_flow.py b/tests/components/konnected/test_config_flow.py index 8dfead58659..3638f40735b 100644 --- a/tests/components/konnected/test_config_flow.py +++ b/tests/components/konnected/test_config_flow.py @@ -34,7 +34,7 @@ async def test_flow_works(hass, mock_panel): mock_panel.get_status.return_value = { "mac": "11:22:33:44:55:66", - "name": "Konnected", + "model": "Konnected", } result = await hass.config_entries.flow.async_configure( result["flow_id"], user_input={"port": 1234, "host": "1.2.3.4"} @@ -43,6 +43,7 @@ async def test_flow_works(hass, mock_panel): assert result["step_id"] == "confirm" assert result["description_placeholders"] == { "model": "Konnected Alarm Panel", + "id": "112233445566", "host": "1.2.3.4", "port": 1234, } @@ -70,7 +71,7 @@ async def test_pro_flow_works(hass, mock_panel): mock_panel.get_status.return_value = { "mac": "11:22:33:44:55:66", - "name": "Konnected Pro", + "model": "Konnected Pro", } result = await hass.config_entries.flow.async_configure( result["flow_id"], user_input={"port": 1234, "host": "1.2.3.4"} @@ -79,6 +80,7 @@ async def test_pro_flow_works(hass, mock_panel): assert result["step_id"] == "confirm" assert result["description_placeholders"] == { "model": "Konnected Alarm Panel Pro", + "id": "112233445566", "host": "1.2.3.4", "port": 1234, } @@ -100,7 +102,7 @@ async def test_ssdp(hass, mock_panel): """Test a panel being discovered.""" mock_panel.get_status.return_value = { "mac": "11:22:33:44:55:66", - "name": "Konnected", + "model": "Konnected", } result = await hass.config_entries.flow.async_init( @@ -117,6 +119,7 @@ async def test_ssdp(hass, mock_panel): assert result["step_id"] == "confirm" assert result["description_placeholders"] == { "model": "Konnected Alarm Panel", + "id": "112233445566", "host": "1.2.3.4", "port": 1234, } @@ -125,8 +128,8 @@ async def test_ssdp(hass, mock_panel): async def test_import_no_host_user_finish(hass, mock_panel): """Test importing a panel with no host info.""" mock_panel.get_status.return_value = { - "mac": "11:22:33:44:55:66", - "name": "Konnected Pro", + "mac": "aa:bb:cc:dd:ee:ff", + "model": "Konnected Pro", } result = await hass.config_entries.flow.async_init( @@ -159,6 +162,13 @@ async def test_import_no_host_user_finish(hass, mock_panel): }, ) assert result["type"] == "form" + assert result["step_id"] == "import_confirm" + assert result["description_placeholders"]["id"] == "aabbccddeeff" + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], user_input={} + ) + assert result["type"] == "form" assert result["step_id"] == "user" # confirm user is prompted to enter host @@ -169,6 +179,7 @@ async def test_import_no_host_user_finish(hass, mock_panel): assert result["step_id"] == "confirm" assert result["description_placeholders"] == { "model": "Konnected Alarm Panel Pro", + "id": "aabbccddeeff", "host": "1.1.1.1", "port": 1234, } @@ -180,6 +191,78 @@ async def test_import_no_host_user_finish(hass, mock_panel): assert result["type"] == "create_entry" +async def test_import_ssdp_host_user_finish(hass, mock_panel): + """Test importing a panel with no host info which ssdp discovers.""" + mock_panel.get_status.return_value = { + "mac": "11:22:33:44:55:66", + "model": "Konnected Pro", + } + + result = await hass.config_entries.flow.async_init( + config_flow.DOMAIN, + context={"source": "import"}, + data={ + "default_options": { + "blink": True, + "discovery": True, + "io": { + "1": "Disabled", + "10": "Disabled", + "11": "Disabled", + "12": "Disabled", + "2": "Disabled", + "3": "Disabled", + "4": "Disabled", + "5": "Disabled", + "6": "Disabled", + "7": "Disabled", + "8": "Disabled", + "9": "Disabled", + "alarm1": "Disabled", + "alarm2_out2": "Disabled", + "out": "Disabled", + "out1": "Disabled", + }, + }, + "id": "112233445566", + }, + ) + assert result["type"] == "form" + assert result["step_id"] == "import_confirm" + assert result["description_placeholders"]["id"] == "112233445566" + + # discover the panel via ssdp + ssdp_result = await hass.config_entries.flow.async_init( + config_flow.DOMAIN, + context={"source": "ssdp"}, + data={ + "ssdp_location": "http://0.0.0.0:1234/Device.xml", + "manufacturer": config_flow.KONN_MANUFACTURER, + "modelName": config_flow.KONN_MODEL_PRO, + }, + ) + assert ssdp_result["type"] == "abort" + assert ssdp_result["reason"] == "already_in_progress" + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], user_input={} + ) + assert result["type"] == "form" + assert result["step_id"] == "confirm" + assert result["description_placeholders"] == { + "model": "Konnected Alarm Panel Pro", + "id": "112233445566", + "host": "0.0.0.0", + "port": 1234, + } + + # final confirmation + result = await hass.config_entries.flow.async_configure( + result["flow_id"], user_input={} + ) + assert result["type"] == "create_entry" + + async def test_ssdp_already_configured(hass, mock_panel): """Test if a discovered panel has already been configured.""" MockConfigEntry( @@ -189,7 +272,7 @@ async def test_ssdp_already_configured(hass, mock_panel): ).add_to_hass(hass) mock_panel.get_status.return_value = { "mac": "11:22:33:44:55:66", - "name": "Konnected Pro", + "model": "Konnected Pro", } result = await hass.config_entries.flow.async_init( @@ -265,7 +348,7 @@ async def test_ssdp_host_update(hass, mock_panel): ).add_to_hass(hass) mock_panel.get_status.return_value = { "mac": "11:22:33:44:55:66", - "name": "Konnected Pro", + "model": "Konnected Pro", } result = await hass.config_entries.flow.async_init( @@ -289,7 +372,7 @@ async def test_import_existing_config(hass, mock_panel): """Test importing a host with an existing config file.""" mock_panel.get_status.return_value = { "mac": "11:22:33:44:55:66", - "name": "Konnected Pro", + "model": "Konnected Pro", } result = await hass.config_entries.flow.async_init( @@ -402,7 +485,7 @@ async def test_import_existing_config_entry(hass, mock_panel): mock_panel.get_status.return_value = { "mac": "11:22:33:44:55:66", - "name": "Konnected Pro", + "model": "Konnected Pro", } # utilize a global access token this time @@ -462,7 +545,7 @@ async def test_import_pin_config(hass, mock_panel): """Test importing a host with an existing config file that specifies pin configs.""" mock_panel.get_status.return_value = { "mac": "11:22:33:44:55:66", - "name": "Konnected Pro", + "model": "Konnected Pro", } result = await hass.config_entries.flow.async_init( diff --git a/tests/components/konnected/test_panel.py b/tests/components/konnected/test_panel.py index 0ad384bd35e..f1ae8a4357c 100644 --- a/tests/components/konnected/test_panel.py +++ b/tests/components/konnected/test_panel.py @@ -3,6 +3,7 @@ from asynctest import patch import pytest from homeassistant.components.konnected import config_flow, panel +from homeassistant.setup import async_setup_component from tests.common import MockConfigEntry @@ -92,9 +93,6 @@ async def test_create_and_setup(hass, mock_panel): options=device_options, ) entry.add_to_hass(hass) - hass.data[panel.DOMAIN] = { - panel.CONF_API_HOST: "192.168.1.1", - } # override get_status to reflect non-pro board mock_panel.get_status.return_value = { @@ -111,19 +109,35 @@ async def test_create_and_setup(hass, mock_panel): "mac": "11:22:33:44:55:66", "settings": {}, } - device = panel.AlarmPanel(hass, entry) - await device.async_save_data() - await device.async_connect() + + # setup the integration and inspect panel behavior + assert ( + await async_setup_component( + hass, + panel.DOMAIN, + { + panel.DOMAIN: { + panel.CONF_ACCESS_TOKEN: "arandomstringvalue", + panel.CONF_API_HOST: "http://192.168.1.1:8123", + } + }, + ) + is True + ) + + # confirm panel instance was created and configured + # hass.data is the only mechanism to get a reference to the created panel instance + device = hass.data[panel.DOMAIN][panel.CONF_DEVICES]["112233445566"]["panel"] await device.update_switch("1", 0) # confirm the correct api is used # pylint: disable=no-member - assert device.client.put_device.call_count == 1 - assert device.client.put_zone.call_count == 0 + assert mock_panel.put_device.call_count == 1 + assert mock_panel.put_zone.call_count == 0 # confirm the settings are sent to the panel # pylint: disable=no-member - assert device.client.put_settings.call_args_list[0][1] == { + assert mock_panel.put_settings.call_args_list[0][1] == { "sensors": [{"pin": "1"}, {"pin": "2"}, {"pin": "5"}], "actuators": [{"trigger": 0, "pin": "8"}, {"trigger": 1, "pin": "9"}], "dht_sensors": [{"poll_interval": 3, "pin": "6"}], @@ -131,67 +145,60 @@ async def test_create_and_setup(hass, mock_panel): "auth_token": "11223344556677889900", "blink": True, "discovery": True, - "endpoint": "192.168.1.1/api/konnected", + "endpoint": "http://192.168.1.1:8123/api/konnected", } # confirm the device settings are saved in hass.data - assert hass.data[panel.DOMAIN][panel.CONF_DEVICES] == { - "112233445566": { - "binary_sensors": { - "1": { - "inverse": False, - "name": "Konnected 445566 Zone 1", - "state": None, - "type": "door", - }, - "2": { - "inverse": True, - "name": "winder", - "state": None, - "type": "window", - }, - "3": { - "inverse": False, - "name": "Konnected 445566 Zone 3", - "state": None, - "type": "door", - }, + assert device.stored_configuration == { + "binary_sensors": { + "1": { + "inverse": False, + "name": "Konnected 445566 Zone 1", + "state": None, + "type": "door", }, - "blink": True, - "panel": device, - "discovery": True, - "host": "1.2.3.4", - "port": 1234, - "sensors": [ - { - "name": "Konnected 445566 Sensor 4", - "poll_interval": 3, - "type": "dht", - "zone": "4", - }, - {"name": "temper", "poll_interval": 3, "type": "ds18b20", "zone": "5"}, - ], - "switches": [ - { - "activation": "low", - "momentary": 50, - "name": "switcher", - "pause": 100, - "repeat": 4, - "state": None, - "zone": "out", - }, - { - "activation": "high", - "momentary": None, - "name": "Konnected 445566 Actuator 6", - "pause": None, - "repeat": None, - "state": None, - "zone": "6", - }, - ], - } + "2": {"inverse": True, "name": "winder", "state": None, "type": "window"}, + "3": { + "inverse": False, + "name": "Konnected 445566 Zone 3", + "state": None, + "type": "door", + }, + }, + "blink": True, + "panel": device, + "discovery": True, + "host": "1.2.3.4", + "port": 1234, + "sensors": [ + { + "name": "Konnected 445566 Sensor 4", + "poll_interval": 3, + "type": "dht", + "zone": "4", + }, + {"name": "temper", "poll_interval": 3, "type": "ds18b20", "zone": "5"}, + ], + "switches": [ + { + "activation": "low", + "momentary": 50, + "name": "switcher", + "pause": 100, + "repeat": 4, + "state": None, + "zone": "out", + }, + { + "activation": "high", + "momentary": None, + "name": "Konnected 445566 Actuator 6", + "pause": None, + "repeat": None, + "state": None, + "zone": "6", + }, + ], } @@ -255,23 +262,35 @@ async def test_create_and_setup_pro(hass, mock_panel): options=device_options, ) entry.add_to_hass(hass) - hass.data[panel.DOMAIN] = { - panel.CONF_API_HOST: "192.168.1.1", - } - device = panel.AlarmPanel(hass, entry) - await device.async_save_data() - await device.async_connect() + # setup the integration and inspect panel behavior + assert ( + await async_setup_component( + hass, + panel.DOMAIN, + { + panel.DOMAIN: { + panel.CONF_ACCESS_TOKEN: "arandomstringvalue", + panel.CONF_API_HOST: "http://192.168.1.1:8123", + } + }, + ) + is True + ) + + # confirm panel instance was created and configured + # hass.data is the only mechanism to get a reference to the created panel instance + device = hass.data[panel.DOMAIN][panel.CONF_DEVICES]["112233445566"]["panel"] await device.update_switch("2", 1) # confirm the correct api is used # pylint: disable=no-member - assert device.client.put_device.call_count == 0 - assert device.client.put_zone.call_count == 1 + assert mock_panel.put_device.call_count == 0 + assert mock_panel.put_zone.call_count == 1 # confirm the settings are sent to the panel # pylint: disable=no-member - assert device.client.put_settings.call_args_list[0][1] == { + assert mock_panel.put_settings.call_args_list[0][1] == { "sensors": [{"zone": "2"}, {"zone": "6"}, {"zone": "10"}], "actuators": [ {"trigger": 1, "zone": "4"}, @@ -287,89 +306,248 @@ async def test_create_and_setup_pro(hass, mock_panel): "auth_token": "11223344556677889900", "blink": True, "discovery": True, - "endpoint": "192.168.1.1/api/konnected", + "endpoint": "http://192.168.1.1:8123/api/konnected", } # confirm the device settings are saved in hass.data - assert hass.data[panel.DOMAIN][panel.CONF_DEVICES] == { - "112233445566": { - "binary_sensors": { - "10": { - "inverse": False, - "name": "Konnected 445566 Zone 10", - "state": None, - "type": "door", - }, - "2": { - "inverse": False, - "name": "Konnected 445566 Zone 2", - "state": None, - "type": "door", - }, - "6": { - "inverse": True, - "name": "winder", - "state": None, - "type": "window", - }, + assert device.stored_configuration == { + "binary_sensors": { + "10": { + "inverse": False, + "name": "Konnected 445566 Zone 10", + "state": None, + "type": "door", }, - "blink": True, - "panel": device, - "discovery": True, + "2": { + "inverse": False, + "name": "Konnected 445566 Zone 2", + "state": None, + "type": "door", + }, + "6": {"inverse": True, "name": "winder", "state": None, "type": "window"}, + }, + "blink": True, + "panel": device, + "discovery": True, + "host": "1.2.3.4", + "port": 1234, + "sensors": [ + { + "name": "Konnected 445566 Sensor 3", + "poll_interval": 3, + "type": "dht", + "zone": "3", + }, + {"name": "temper", "poll_interval": 3, "type": "ds18b20", "zone": "7"}, + { + "name": "Konnected 445566 Sensor 11", + "poll_interval": 5, + "type": "dht", + "zone": "11", + }, + ], + "switches": [ + { + "activation": "high", + "momentary": None, + "name": "Konnected 445566 Actuator 4", + "pause": None, + "repeat": None, + "state": None, + "zone": "4", + }, + { + "activation": "low", + "momentary": 50, + "name": "switcher", + "pause": 100, + "repeat": 4, + "state": None, + "zone": "8", + }, + { + "activation": "high", + "momentary": None, + "name": "Konnected 445566 Actuator out1", + "pause": None, + "repeat": None, + "state": None, + "zone": "out1", + }, + { + "activation": "high", + "momentary": None, + "name": "Konnected 445566 Actuator alarm1", + "pause": None, + "repeat": None, + "state": None, + "zone": "alarm1", + }, + ], + } + + +async def test_default_options(hass, mock_panel): + """Test that we create a Konnected Panel and save the data.""" + device_config = config_flow.CONFIG_ENTRY_SCHEMA( + { "host": "1.2.3.4", "port": 1234, - "sensors": [ + "id": "112233445566", + "model": "Konnected Pro", + "access_token": "11223344556677889900", + "default_options": config_flow.OPTIONS_SCHEMA( { - "name": "Konnected 445566 Sensor 3", - "poll_interval": 3, - "type": "dht", - "zone": "3", - }, - {"name": "temper", "poll_interval": 3, "type": "ds18b20", "zone": "7"}, - { - "name": "Konnected 445566 Sensor 11", - "poll_interval": 5, - "type": "dht", - "zone": "11", - }, - ], - "switches": [ - { - "activation": "high", - "momentary": None, - "name": "Konnected 445566 Actuator 4", - "pause": None, - "repeat": None, - "state": None, - "zone": "4", - }, - { - "activation": "low", - "momentary": 50, - "name": "switcher", - "pause": 100, - "repeat": 4, - "state": None, - "zone": "8", - }, - { - "activation": "high", - "momentary": None, - "name": "Konnected 445566 Actuator out1", - "pause": None, - "repeat": None, - "state": None, - "zone": "out1", - }, - { - "activation": "high", - "momentary": None, - "name": "Konnected 445566 Actuator alarm1", - "pause": None, - "repeat": None, - "state": None, - "zone": "alarm1", - }, - ], + "io": { + "1": "Binary Sensor", + "2": "Binary Sensor", + "3": "Binary Sensor", + "4": "Digital Sensor", + "5": "Digital Sensor", + "6": "Switchable Output", + "out": "Switchable Output", + }, + "binary_sensors": [ + {"zone": "1", "type": "door"}, + { + "zone": "2", + "type": "window", + "name": "winder", + "inverse": True, + }, + {"zone": "3", "type": "door"}, + ], + "sensors": [ + {"zone": "4", "type": "dht"}, + {"zone": "5", "type": "ds18b20", "name": "temper"}, + ], + "switches": [ + { + "zone": "out", + "name": "switcher", + "activation": "low", + "momentary": 50, + "pause": 100, + "repeat": 4, + }, + {"zone": "6"}, + ], + } + ), } + ) + + entry = MockConfigEntry( + domain="konnected", + title="Konnected Alarm Panel", + data=device_config, + options={}, + ) + entry.add_to_hass(hass) + + # override get_status to reflect non-pro board + mock_panel.get_status.return_value = { + "hwVersion": "2.3.0", + "swVersion": "2.3.1", + "heap": 10000, + "uptime": 12222, + "ip": "192.168.1.90", + "port": 9123, + "sensors": [], + "actuators": [], + "dht_sensors": [], + "ds18b20_sensors": [], + "mac": "11:22:33:44:55:66", + "settings": {}, + } + + # setup the integration and inspect panel behavior + assert ( + await async_setup_component( + hass, + panel.DOMAIN, + { + panel.DOMAIN: { + panel.CONF_ACCESS_TOKEN: "arandomstringvalue", + panel.CONF_API_HOST: "http://192.168.1.1:8123", + } + }, + ) + is True + ) + + # confirm panel instance was created and configured. + # hass.data is the only mechanism to get a reference to the created panel instance + device = hass.data[panel.DOMAIN][panel.CONF_DEVICES]["112233445566"]["panel"] + await device.update_switch("1", 0) + + # confirm the correct api is used + # pylint: disable=no-member + assert mock_panel.put_device.call_count == 1 + assert mock_panel.put_zone.call_count == 0 + + # confirm the settings are sent to the panel + # pylint: disable=no-member + assert mock_panel.put_settings.call_args_list[0][1] == { + "sensors": [{"pin": "1"}, {"pin": "2"}, {"pin": "5"}], + "actuators": [{"trigger": 0, "pin": "8"}, {"trigger": 1, "pin": "9"}], + "dht_sensors": [{"poll_interval": 3, "pin": "6"}], + "ds18b20_sensors": [{"pin": "7"}], + "auth_token": "11223344556677889900", + "blink": True, + "discovery": True, + "endpoint": "http://192.168.1.1:8123/api/konnected", + } + + # confirm the device settings are saved in hass.data + assert device.stored_configuration == { + "binary_sensors": { + "1": { + "inverse": False, + "name": "Konnected 445566 Zone 1", + "state": None, + "type": "door", + }, + "2": {"inverse": True, "name": "winder", "state": None, "type": "window"}, + "3": { + "inverse": False, + "name": "Konnected 445566 Zone 3", + "state": None, + "type": "door", + }, + }, + "blink": True, + "panel": device, + "discovery": True, + "host": "1.2.3.4", + "port": 1234, + "sensors": [ + { + "name": "Konnected 445566 Sensor 4", + "poll_interval": 3, + "type": "dht", + "zone": "4", + }, + {"name": "temper", "poll_interval": 3, "type": "ds18b20", "zone": "5"}, + ], + "switches": [ + { + "activation": "low", + "momentary": 50, + "name": "switcher", + "pause": 100, + "repeat": 4, + "state": None, + "zone": "out", + }, + { + "activation": "high", + "momentary": None, + "name": "Konnected 445566 Actuator 6", + "pause": None, + "repeat": None, + "state": None, + "zone": "6", + }, + ], } From d3629d9f32796af161571a079862d759f98805df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Arnauts?= Date: Tue, 25 Feb 2020 21:29:45 +0100 Subject: [PATCH 29/39] Bump python-tado to 0.3.0 (#32186) --- homeassistant/components/tado/manifest.json | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/tado/manifest.json b/homeassistant/components/tado/manifest.json index 4728f1622ed..e51cc53caa5 100644 --- a/homeassistant/components/tado/manifest.json +++ b/homeassistant/components/tado/manifest.json @@ -3,7 +3,7 @@ "name": "Tado", "documentation": "https://www.home-assistant.io/integrations/tado", "requirements": [ - "python-tado==0.2.9" + "python-tado==0.3.0" ], "dependencies": [], "codeowners": [ diff --git a/requirements_all.txt b/requirements_all.txt index 93ec58526d7..ea7d19307e1 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1628,7 +1628,7 @@ python-songpal==0.11.2 python-synology==0.4.0 # homeassistant.components.tado -python-tado==0.2.9 +python-tado==0.3.0 # homeassistant.components.telegram_bot python-telegram-bot==11.1.0 From ff6d415c67ff86c717a7b26a80696c17e9fd3c41 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 25 Feb 2020 23:15:25 +0100 Subject: [PATCH 30/39] Updated frontend to 20200220.3 (#32189) --- homeassistant/components/frontend/manifest.json | 2 +- homeassistant/package_constraints.txt | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/frontend/manifest.json b/homeassistant/components/frontend/manifest.json index 993d63ea29b..2b39681af25 100644 --- a/homeassistant/components/frontend/manifest.json +++ b/homeassistant/components/frontend/manifest.json @@ -3,7 +3,7 @@ "name": "Home Assistant Frontend", "documentation": "https://www.home-assistant.io/integrations/frontend", "requirements": [ - "home-assistant-frontend==20200220.1" + "home-assistant-frontend==20200220.3" ], "dependencies": [ "api", diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index c2680ee54fe..246d63d984b 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -11,7 +11,7 @@ cryptography==2.8 defusedxml==0.6.0 distro==1.4.0 hass-nabucasa==0.31 -home-assistant-frontend==20200220.1 +home-assistant-frontend==20200220.3 importlib-metadata==1.5.0 jinja2>=2.10.3 netdisco==2.6.0 diff --git a/requirements_all.txt b/requirements_all.txt index ea7d19307e1..d39f90992d9 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -683,7 +683,7 @@ hole==0.5.0 holidays==0.10.1 # homeassistant.components.frontend -home-assistant-frontend==20200220.1 +home-assistant-frontend==20200220.3 # homeassistant.components.zwave homeassistant-pyozw==0.1.8 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 5cbc1df6be5..7139bcbd4ec 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -254,7 +254,7 @@ hole==0.5.0 holidays==0.10.1 # homeassistant.components.frontend -home-assistant-frontend==20200220.1 +home-assistant-frontend==20200220.3 # homeassistant.components.zwave homeassistant-pyozw==0.1.8 From e60a6cfa194572fb7d46f8acb4a5c7010f1b93f3 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 25 Feb 2020 14:10:43 -0800 Subject: [PATCH 31/39] Fix Arlo doing I/O in event loop (#32190) --- homeassistant/components/arlo/alarm_control_panel.py | 8 ++++---- homeassistant/components/arlo/camera.py | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/arlo/alarm_control_panel.py b/homeassistant/components/arlo/alarm_control_panel.py index 838f319abc1..49a1bced577 100644 --- a/homeassistant/components/arlo/alarm_control_panel.py +++ b/homeassistant/components/arlo/alarm_control_panel.py @@ -110,19 +110,19 @@ class ArloBaseStation(AlarmControlPanel): else: self._state = None - async def async_alarm_disarm(self, code=None): + def alarm_disarm(self, code=None): """Send disarm command.""" self._base_station.mode = DISARMED - async def async_alarm_arm_away(self, code=None): + def alarm_arm_away(self, code=None): """Send arm away command. Uses custom mode.""" self._base_station.mode = self._away_mode_name - async def async_alarm_arm_home(self, code=None): + def alarm_arm_home(self, code=None): """Send arm home command. Uses custom mode.""" self._base_station.mode = self._home_mode_name - async def async_alarm_arm_night(self, code=None): + def alarm_arm_night(self, code=None): """Send arm night command. Uses custom mode.""" self._base_station.mode = self._night_mode_name diff --git a/homeassistant/components/arlo/camera.py b/homeassistant/components/arlo/camera.py index 958c383765a..22b1bfbe810 100644 --- a/homeassistant/components/arlo/camera.py +++ b/homeassistant/components/arlo/camera.py @@ -78,8 +78,10 @@ class ArloCam(Camera): async def handle_async_mjpeg_stream(self, request): """Generate an HTTP MJPEG stream from the camera.""" + video = await self.hass.async_add_executor_job( + getattr, self._camera, "last_video" + ) - video = self._camera.last_video if not video: error_msg = "Video not found for {0}. Is it older than {1} days?".format( self.name, self._camera.min_days_vdo_cache From 6f8380b442154b3cfd3a8ae0c097c962e520f83b Mon Sep 17 00:00:00 2001 From: Jenny Date: Tue, 25 Feb 2020 22:01:18 +0000 Subject: [PATCH 32/39] Bump socialbladeclient to 0.5 (#32191) --- homeassistant/components/socialblade/manifest.json | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/socialblade/manifest.json b/homeassistant/components/socialblade/manifest.json index 2ce7fbabf0f..540febe7f2e 100644 --- a/homeassistant/components/socialblade/manifest.json +++ b/homeassistant/components/socialblade/manifest.json @@ -2,7 +2,7 @@ "domain": "socialblade", "name": "Social Blade", "documentation": "https://www.home-assistant.io/integrations/socialblade", - "requirements": ["socialbladeclient==0.2"], + "requirements": ["socialbladeclient==0.5"], "dependencies": [], "codeowners": [] } diff --git a/requirements_all.txt b/requirements_all.txt index d39f90992d9..3185524db20 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1865,7 +1865,7 @@ smhi-pkg==1.0.10 snapcast==2.0.10 # homeassistant.components.socialblade -socialbladeclient==0.2 +socialbladeclient==0.5 # homeassistant.components.solaredge_local solaredge-local==0.2.0 From 0e7e0086cdf0a58249262a09f244a13eb1cb49c6 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 25 Feb 2020 14:17:28 -0800 Subject: [PATCH 33/39] Update translations --- .../ambient_station/.translations/ca.json | 3 + .../ambient_station/.translations/de.json | 3 + .../ambient_station/.translations/en.json | 3 + .../ambient_station/.translations/ko.json | 3 + .../ambient_station/.translations/no.json | 3 + .../ambient_station/.translations/pl.json | 3 + .../.translations/zh-Hant.json | 3 + .../components/august/.translations/de.json | 31 ++++++ .../components/august/.translations/en.json | 32 ++++++ .../components/deconz/.translations/ca.json | 13 ++- .../components/deconz/.translations/da.json | 3 +- .../components/deconz/.translations/de.json | 3 +- .../components/deconz/.translations/es.json | 3 +- .../components/deconz/.translations/it.json | 3 +- .../components/deconz/.translations/ko.json | 3 +- .../components/deconz/.translations/lb.json | 3 +- .../components/deconz/.translations/no.json | 3 +- .../components/deconz/.translations/pl.json | 3 +- .../components/deconz/.translations/ru.json | 11 +- .../deconz/.translations/zh-Hans.json | 7 ++ .../deconz/.translations/zh-Hant.json | 3 +- .../components/demo/.translations/da.json | 23 ++++ .../components/demo/.translations/de.json | 17 +++ .../components/demo/.translations/es.json | 17 +++ .../components/demo/.translations/ko.json | 17 +++ .../components/demo/.translations/lb.json | 9 ++ .../components/demo/.translations/no.json | 17 +++ .../components/demo/.translations/pl.json | 25 +++++ .../components/demo/.translations/ru.json | 17 +++ .../demo/.translations/zh-Hans.json | 19 ++++ .../esphome/.translations/zh-Hans.json | 1 + .../components/gios/.translations/ru.json | 2 +- .../components/hue/.translations/zh-Hans.json | 2 +- .../components/ipma/.translations/da.json | 1 + .../components/ipma/.translations/pl.json | 1 + .../ipma/.translations/zh-Hans.json | 1 + .../konnected/.translations/da.json | 104 +++++++++++++++++- .../konnected/.translations/de.json | 3 + .../konnected/.translations/en.json | 1 - .../konnected/.translations/ko.json | 4 + .../konnected/.translations/pl.json | 70 +++++++++++- .../konnected/.translations/ru.json | 14 +-- .../konnected/.translations/zh-Hans.json | 9 ++ .../linky/.translations/zh-Hans.json | 3 + .../components/local_ip/.translations/ru.json | 2 +- .../luftdaten/.translations/ru.json | 6 +- .../mikrotik/.translations/zh-Hans.json | 16 +++ .../components/mqtt/.translations/ca.json | 22 ++++ .../components/mqtt/.translations/da.json | 22 ++++ .../components/mqtt/.translations/de.json | 22 ++++ .../components/mqtt/.translations/es.json | 22 ++++ .../components/mqtt/.translations/it.json | 22 ++++ .../components/mqtt/.translations/ko.json | 22 ++++ .../components/mqtt/.translations/lb.json | 12 ++ .../components/mqtt/.translations/no.json | 22 ++++ .../components/mqtt/.translations/pl.json | 22 ++++ .../components/mqtt/.translations/ro.json | 2 +- .../components/mqtt/.translations/ru.json | 22 ++++ .../mqtt/.translations/zh-Hans.json | 22 ++++ .../mqtt/.translations/zh-Hant.json | 22 ++++ .../nest/.translations/zh-Hans.json | 8 +- .../components/notion/.translations/ca.json | 3 + .../components/notion/.translations/de.json | 3 + .../components/notion/.translations/en.json | 3 + .../components/notion/.translations/ko.json | 3 + .../components/notion/.translations/no.json | 3 + .../components/notion/.translations/pl.json | 3 + .../notion/.translations/zh-Hant.json | 3 + .../components/plex/.translations/ca.json | 2 + .../components/plex/.translations/da.json | 2 + .../components/plex/.translations/de.json | 2 + .../components/plex/.translations/en.json | 2 + .../components/plex/.translations/es.json | 2 + .../components/plex/.translations/it.json | 2 + .../components/plex/.translations/ko.json | 2 + .../components/plex/.translations/lb.json | 2 + .../components/plex/.translations/no.json | 2 + .../components/plex/.translations/pl.json | 2 + .../components/plex/.translations/ru.json | 2 + .../plex/.translations/zh-Hans.json | 12 ++ .../plex/.translations/zh-Hant.json | 2 + .../rainmachine/.translations/ca.json | 3 + .../rainmachine/.translations/da.json | 3 + .../rainmachine/.translations/de.json | 3 + .../rainmachine/.translations/en.json | 3 + .../rainmachine/.translations/ko.json | 3 + .../rainmachine/.translations/no.json | 3 + .../rainmachine/.translations/pl.json | 3 + .../rainmachine/.translations/ru.json | 3 + .../rainmachine/.translations/zh-Hant.json | 3 + .../simplisafe/.translations/ca.json | 3 + .../simplisafe/.translations/da.json | 3 + .../simplisafe/.translations/de.json | 3 + .../simplisafe/.translations/en.json | 3 + .../simplisafe/.translations/ko.json | 3 + .../simplisafe/.translations/no.json | 3 + .../simplisafe/.translations/pl.json | 3 + .../simplisafe/.translations/ru.json | 3 + .../simplisafe/.translations/zh-Hant.json | 3 + .../components/solarlog/.translations/ru.json | 2 +- .../sonos/.translations/zh-Hans.json | 2 +- .../components/unifi/.translations/ca.json | 9 +- .../components/unifi/.translations/da.json | 11 +- .../components/unifi/.translations/de.json | 9 +- .../components/unifi/.translations/es.json | 9 +- .../components/unifi/.translations/it.json | 11 +- .../components/unifi/.translations/ko.json | 11 +- .../components/unifi/.translations/lb.json | 7 +- .../components/unifi/.translations/no.json | 11 +- .../components/unifi/.translations/pl.json | 9 +- .../components/unifi/.translations/ru.json | 11 +- .../unifi/.translations/zh-Hans.json | 9 +- .../unifi/.translations/zh-Hant.json | 11 +- .../components/upnp/.translations/ru.json | 4 +- .../components/vilfo/.translations/da.json | 23 ++++ .../components/vilfo/.translations/es.json | 6 +- .../components/vilfo/.translations/pl.json | 18 ++- .../vilfo/.translations/zh-Hans.json | 19 ++++ .../components/vizio/.translations/da.json | 2 +- .../components/vizio/.translations/en.json | 2 +- .../components/vizio/.translations/ko.json | 2 +- .../components/vizio/.translations/no.json | 2 +- .../vizio/.translations/zh-Hant.json | 2 +- .../components/zha/.translations/ca.json | 10 +- .../components/zha/.translations/pl.json | 16 +-- .../components/zha/.translations/ru.json | 4 +- .../zone/.translations/zh-Hans.json | 4 +- 127 files changed, 1046 insertions(+), 108 deletions(-) create mode 100644 homeassistant/components/august/.translations/de.json create mode 100644 homeassistant/components/august/.translations/en.json create mode 100644 homeassistant/components/demo/.translations/zh-Hans.json create mode 100644 homeassistant/components/konnected/.translations/zh-Hans.json create mode 100644 homeassistant/components/mikrotik/.translations/zh-Hans.json create mode 100644 homeassistant/components/plex/.translations/zh-Hans.json create mode 100644 homeassistant/components/vilfo/.translations/da.json create mode 100644 homeassistant/components/vilfo/.translations/zh-Hans.json diff --git a/homeassistant/components/ambient_station/.translations/ca.json b/homeassistant/components/ambient_station/.translations/ca.json index d3c451f3e3f..280a90354b0 100644 --- a/homeassistant/components/ambient_station/.translations/ca.json +++ b/homeassistant/components/ambient_station/.translations/ca.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "Aquesta clau d'aplicaci\u00f3 ja est\u00e0 en \u00fas." + }, "error": { "identifier_exists": "Clau d'aplicaci\u00f3 i/o clau API ja registrada", "invalid_key": "Clau API i/o clau d'aplicaci\u00f3 inv\u00e0lida/es", diff --git a/homeassistant/components/ambient_station/.translations/de.json b/homeassistant/components/ambient_station/.translations/de.json index 1431efbf167..451a2e70e68 100644 --- a/homeassistant/components/ambient_station/.translations/de.json +++ b/homeassistant/components/ambient_station/.translations/de.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "Dieser App-Schl\u00fcssel wird bereits verwendet." + }, "error": { "identifier_exists": "Anwendungsschl\u00fcssel und / oder API-Schl\u00fcssel bereits registriert", "invalid_key": "Ung\u00fcltiger API Key und / oder Anwendungsschl\u00fcssel", diff --git a/homeassistant/components/ambient_station/.translations/en.json b/homeassistant/components/ambient_station/.translations/en.json index 5bd643da55c..8b8e71d5316 100644 --- a/homeassistant/components/ambient_station/.translations/en.json +++ b/homeassistant/components/ambient_station/.translations/en.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "This app key is already in use." + }, "error": { "identifier_exists": "Application Key and/or API Key already registered", "invalid_key": "Invalid API Key and/or Application Key", diff --git a/homeassistant/components/ambient_station/.translations/ko.json b/homeassistant/components/ambient_station/.translations/ko.json index eb9209a6c37..3379411678b 100644 --- a/homeassistant/components/ambient_station/.translations/ko.json +++ b/homeassistant/components/ambient_station/.translations/ko.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "\uc774 \uc571 \ud0a4\ub294 \uc774\ubbf8 \uc0ac\uc6a9 \uc911\uc785\ub2c8\ub2e4." + }, "error": { "identifier_exists": "\uc560\ud50c\ub9ac\ucf00\uc774\uc158 \ud0a4 \ud639\uc740 API \ud0a4\uac00 \uc774\ubbf8 \ub4f1\ub85d\ub418\uc5c8\uc2b5\ub2c8\ub2e4", "invalid_key": "\uc560\ud50c\ub9ac\ucf00\uc774\uc158 \ud0a4 \ud639\uc740 API \ud0a4\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4", diff --git a/homeassistant/components/ambient_station/.translations/no.json b/homeassistant/components/ambient_station/.translations/no.json index 0b9d377718b..4a089eba4c0 100644 --- a/homeassistant/components/ambient_station/.translations/no.json +++ b/homeassistant/components/ambient_station/.translations/no.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "Denne app n\u00f8kkelen er allerede i bruk." + }, "error": { "identifier_exists": "Programn\u00f8kkel og/eller API-n\u00f8kkel er allerede registrert", "invalid_key": "Ugyldig API-n\u00f8kkel og/eller programn\u00f8kkel", diff --git a/homeassistant/components/ambient_station/.translations/pl.json b/homeassistant/components/ambient_station/.translations/pl.json index 3ac612d0ea7..5da886f05cd 100644 --- a/homeassistant/components/ambient_station/.translations/pl.json +++ b/homeassistant/components/ambient_station/.translations/pl.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "Ten klucz aplikacji jest ju\u017c w u\u017cyciu." + }, "error": { "identifier_exists": "Klucz aplikacji i/lub klucz API ju\u017c jest zarejestrowany.", "invalid_key": "Nieprawid\u0142owy klucz API i/lub klucz aplikacji", diff --git a/homeassistant/components/ambient_station/.translations/zh-Hant.json b/homeassistant/components/ambient_station/.translations/zh-Hant.json index 6c7c88a8045..6de1579f6ff 100644 --- a/homeassistant/components/ambient_station/.translations/zh-Hant.json +++ b/homeassistant/components/ambient_station/.translations/zh-Hant.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "\u6b64\u61c9\u7528\u7a0b\u5f0f\u5bc6\u9470\u5df2\u88ab\u4f7f\u7528\u3002" + }, "error": { "identifier_exists": "API \u5bc6\u9470\u53ca/\u6216\u61c9\u7528\u5bc6\u9470\u5df2\u8a3b\u518a", "invalid_key": "API \u5bc6\u9470\u53ca/\u6216\u61c9\u7528\u5bc6\u9470\u7121\u6548", diff --git a/homeassistant/components/august/.translations/de.json b/homeassistant/components/august/.translations/de.json new file mode 100644 index 00000000000..dd3b2ea9f44 --- /dev/null +++ b/homeassistant/components/august/.translations/de.json @@ -0,0 +1,31 @@ +{ + "config": { + "abort": { + "already_configured": "Konto ist bereits konfiguriert" + }, + "error": { + "cannot_connect": "Verbindung fehlgeschlagen, versuchen Sie es erneut", + "invalid_auth": "Ung\u00fcltige Authentifizierung", + "unknown": "Unerwarteter Fehler" + }, + "step": { + "user": { + "data": { + "login_method": "Anmeldemethode", + "password": "Passwort", + "timeout": "Zeit\u00fcberschreitung (Sekunden)", + "username": "Benutzername" + }, + "title": "Richten Sie ein August-Konto ein" + }, + "validation": { + "data": { + "code": "Verifizierungs-Code" + }, + "description": "Bitte \u00fcberpr\u00fcfen Sie Ihre {login_method} ({username}) und geben Sie den Best\u00e4tigungscode ein", + "title": "Zwei-Faktor-Authentifizierung" + } + }, + "title": "August" + } +} \ No newline at end of file diff --git a/homeassistant/components/august/.translations/en.json b/homeassistant/components/august/.translations/en.json new file mode 100644 index 00000000000..32c628f0b0d --- /dev/null +++ b/homeassistant/components/august/.translations/en.json @@ -0,0 +1,32 @@ +{ + "config": { + "abort": { + "already_configured": "Account is already configured" + }, + "error": { + "cannot_connect": "Failed to connect, please try again", + "invalid_auth": "Invalid authentication", + "unknown": "Unexpected error" + }, + "step": { + "user": { + "data": { + "login_method": "Login Method", + "password": "Password", + "timeout": "Timeout (seconds)", + "username": "Username" + }, + "description": "If the Login Method is 'email', Username is the email address. If the Login Method is 'phone', Username is the phone number in the format '+NNNNNNNNN'.", + "title": "Setup an August account" + }, + "validation": { + "data": { + "code": "Verification code" + }, + "description": "Please check your {login_method} ({username}) and enter the verification code below", + "title": "Two factor authentication" + } + }, + "title": "August" + } +} \ No newline at end of file diff --git a/homeassistant/components/deconz/.translations/ca.json b/homeassistant/components/deconz/.translations/ca.json index 8a9ae15a7c1..e690d597dce 100644 --- a/homeassistant/components/deconz/.translations/ca.json +++ b/homeassistant/components/deconz/.translations/ca.json @@ -66,16 +66,16 @@ }, "trigger_type": { "remote_awakened": "Dispositiu despertat", - "remote_button_double_press": "Bot\u00f3 \"{subtype}\" clicat dues vegades consecutives", - "remote_button_long_press": "Bot\u00f3 \"{subtype}\" premut continuament", + "remote_button_double_press": "Bot\u00f3 \"{subtype}\" clicat dues vegades", + "remote_button_long_press": "Bot\u00f3 \"{subtype}\" premut cont\u00ednuament", "remote_button_long_release": "Bot\u00f3 \"{subtype}\" alliberat despr\u00e9s d'una estona premut", - "remote_button_quadruple_press": "Bot\u00f3 \"{subtype}\" clicat quatre vegades consecutives", - "remote_button_quintuple_press": "Bot\u00f3 \"{subtype}\" clicat cinc vegades consecutives", + "remote_button_quadruple_press": "Bot\u00f3 \"{subtype}\" clicat quatre vegades", + "remote_button_quintuple_press": "Bot\u00f3 \"{subtype}\" clicat cinc vegades", "remote_button_rotated": "Bot\u00f3 \"{subtype}\" girat", "remote_button_rotation_stopped": "La rotaci\u00f3 del bot\u00f3 \"{subtype}\" s'ha aturat", "remote_button_short_press": "Bot\u00f3 \"{subtype}\" premut", "remote_button_short_release": "Bot\u00f3 \"{subtype}\" alliberat", - "remote_button_triple_press": "Bot\u00f3 \"{subtype}\" clicat tres vegades consecutives", + "remote_button_triple_press": "Bot\u00f3 \"{subtype}\" clicat tres vegades", "remote_double_tap": "Dispositiu \"{subtype}\" tocat dues vegades", "remote_double_tap_any_side": "Dispositiu tocat dues vegades a alguna cara", "remote_falling": "Dispositiu en caiguda lliure", @@ -108,7 +108,8 @@ "allow_clip_sensor": "Permet sensors deCONZ CLIP", "allow_deconz_groups": "Permet grups de llums deCONZ" }, - "description": "Configura la visibilitat dels tipus dels dispositius deCONZ" + "description": "Configura la visibilitat dels tipus dels dispositius deCONZ", + "title": "Opcions de deCONZ" } } } diff --git a/homeassistant/components/deconz/.translations/da.json b/homeassistant/components/deconz/.translations/da.json index ed1f0b06e64..d1af7e1f4ba 100644 --- a/homeassistant/components/deconz/.translations/da.json +++ b/homeassistant/components/deconz/.translations/da.json @@ -108,7 +108,8 @@ "allow_clip_sensor": "Tillad deCONZ CLIP-sensorer", "allow_deconz_groups": "Tillad deCONZ-lysgrupper" }, - "description": "Konfigurer synligheden af deCONZ-enhedstyper" + "description": "Konfigurer synligheden af deCONZ-enhedstyper", + "title": "deCONZ-indstillinger" } } } diff --git a/homeassistant/components/deconz/.translations/de.json b/homeassistant/components/deconz/.translations/de.json index 479e645173b..c3ad3cd24c8 100644 --- a/homeassistant/components/deconz/.translations/de.json +++ b/homeassistant/components/deconz/.translations/de.json @@ -108,7 +108,8 @@ "allow_clip_sensor": "deCONZ CLIP-Sensoren zulassen", "allow_deconz_groups": "deCONZ-Lichtgruppen zulassen" }, - "description": "Sichtbarkeit der deCONZ-Ger\u00e4tetypen konfigurieren" + "description": "Sichtbarkeit der deCONZ-Ger\u00e4tetypen konfigurieren", + "title": "deCONZ-Optionen" } } } diff --git a/homeassistant/components/deconz/.translations/es.json b/homeassistant/components/deconz/.translations/es.json index 6f5513d9729..cfff05b1e02 100644 --- a/homeassistant/components/deconz/.translations/es.json +++ b/homeassistant/components/deconz/.translations/es.json @@ -108,7 +108,8 @@ "allow_clip_sensor": "Permitir sensores deCONZ CLIP", "allow_deconz_groups": "Permitir grupos de luz deCONZ" }, - "description": "Configurar la visibilidad de los tipos de dispositivos deCONZ" + "description": "Configurar la visibilidad de los tipos de dispositivos deCONZ", + "title": "Opciones deCONZ" } } } diff --git a/homeassistant/components/deconz/.translations/it.json b/homeassistant/components/deconz/.translations/it.json index 980409d6987..f6223cec6c1 100644 --- a/homeassistant/components/deconz/.translations/it.json +++ b/homeassistant/components/deconz/.translations/it.json @@ -108,7 +108,8 @@ "allow_clip_sensor": "Consentire sensori CLIP deCONZ", "allow_deconz_groups": "Consentire gruppi luce deCONZ" }, - "description": "Configurare la visibilit\u00e0 dei tipi di dispositivi deCONZ" + "description": "Configurare la visibilit\u00e0 dei tipi di dispositivi deCONZ", + "title": "Opzioni deCONZ" } } } diff --git a/homeassistant/components/deconz/.translations/ko.json b/homeassistant/components/deconz/.translations/ko.json index d526d706a8b..1b72545bc09 100644 --- a/homeassistant/components/deconz/.translations/ko.json +++ b/homeassistant/components/deconz/.translations/ko.json @@ -108,7 +108,8 @@ "allow_clip_sensor": "deCONZ CLIP \uc13c\uc11c \ud5c8\uc6a9", "allow_deconz_groups": "deCONZ \ub77c\uc774\ud2b8 \uadf8\ub8f9 \ud5c8\uc6a9" }, - "description": "deCONZ \uae30\uae30 \uc720\ud615\uc758 \ud45c\uc2dc \uc5ec\ubd80 \uad6c\uc131" + "description": "deCONZ \uae30\uae30 \uc720\ud615\uc758 \ud45c\uc2dc \uc5ec\ubd80 \uad6c\uc131", + "title": "deCONZ \uc635\uc158" } } } diff --git a/homeassistant/components/deconz/.translations/lb.json b/homeassistant/components/deconz/.translations/lb.json index 4b04cfa03ce..42fd840524f 100644 --- a/homeassistant/components/deconz/.translations/lb.json +++ b/homeassistant/components/deconz/.translations/lb.json @@ -108,7 +108,8 @@ "allow_clip_sensor": "deCONZ Clip Sensoren erlaben", "allow_deconz_groups": "deCONZ Luucht Gruppen erlaben" }, - "description": "Visibilit\u00e9it vun deCONZ Apparater konfigur\u00e9ieren" + "description": "Visibilit\u00e9it vun deCONZ Apparater konfigur\u00e9ieren", + "title": "deCONZ Optiounen" } } } diff --git a/homeassistant/components/deconz/.translations/no.json b/homeassistant/components/deconz/.translations/no.json index d6133542c64..3387c993ae0 100644 --- a/homeassistant/components/deconz/.translations/no.json +++ b/homeassistant/components/deconz/.translations/no.json @@ -108,7 +108,8 @@ "allow_clip_sensor": "Tillat deCONZ CLIP-sensorer", "allow_deconz_groups": "Tillat deCONZ lys grupper" }, - "description": "Konfigurere synlighet av deCONZ enhetstyper" + "description": "Konfigurere synlighet av deCONZ enhetstyper", + "title": "deCONZ alternativer" } } } diff --git a/homeassistant/components/deconz/.translations/pl.json b/homeassistant/components/deconz/.translations/pl.json index 65e858a626d..d12e633bf23 100644 --- a/homeassistant/components/deconz/.translations/pl.json +++ b/homeassistant/components/deconz/.translations/pl.json @@ -108,7 +108,8 @@ "allow_clip_sensor": "Zezwalaj na czujniki deCONZ CLIP", "allow_deconz_groups": "Zezwalaj na grupy \u015bwiate\u0142 deCONZ" }, - "description": "Skonfiguruj widoczno\u015b\u0107 typ\u00f3w urz\u0105dze\u0144 deCONZ" + "description": "Skonfiguruj widoczno\u015b\u0107 typ\u00f3w urz\u0105dze\u0144 deCONZ", + "title": "Opcje deCONZ" } } } diff --git a/homeassistant/components/deconz/.translations/ru.json b/homeassistant/components/deconz/.translations/ru.json index 3c61e447bca..054c85f595a 100644 --- a/homeassistant/components/deconz/.translations/ru.json +++ b/homeassistant/components/deconz/.translations/ru.json @@ -15,7 +15,7 @@ "step": { "hassio_confirm": { "data": { - "allow_clip_sensor": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0438\u043c\u043f\u043e\u0440\u0442 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0445 \u0434\u0430\u0442\u0447\u0438\u043a\u043e\u0432", + "allow_clip_sensor": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0438\u043c\u043f\u043e\u0440\u0442 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0445 \u0441\u0435\u043d\u0441\u043e\u0440\u043e\u0432", "allow_deconz_groups": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0438\u043c\u043f\u043e\u0440\u0442 \u0433\u0440\u0443\u043f\u043f deCONZ" }, "description": "\u0412\u044b \u0443\u0432\u0435\u0440\u0435\u043d\u044b, \u0447\u0442\u043e \u0445\u043e\u0442\u0438\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043a deCONZ (\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0434\u043b\u044f Hass.io \"{addon}\")?", @@ -34,7 +34,7 @@ }, "options": { "data": { - "allow_clip_sensor": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0438\u043c\u043f\u043e\u0440\u0442 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0445 \u0434\u0430\u0442\u0447\u0438\u043a\u043e\u0432", + "allow_clip_sensor": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0438\u043c\u043f\u043e\u0440\u0442 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0445 \u0441\u0435\u043d\u0441\u043e\u0440\u043e\u0432", "allow_deconz_groups": "\u0420\u0430\u0437\u0440\u0435\u0448\u0438\u0442\u044c \u0438\u043c\u043f\u043e\u0440\u0442 \u0433\u0440\u0443\u043f\u043f deCONZ" }, "title": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 deCONZ" @@ -98,17 +98,18 @@ "step": { "async_step_deconz_devices": { "data": { - "allow_clip_sensor": "\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0434\u0430\u0442\u0447\u0438\u043a\u0438 deCONZ CLIP", + "allow_clip_sensor": "\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0441\u0435\u043d\u0441\u043e\u0440\u044b deCONZ CLIP", "allow_deconz_groups": "\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0433\u0440\u0443\u043f\u043f\u044b \u043e\u0441\u0432\u0435\u0449\u0435\u043d\u0438\u044f deCONZ" }, "description": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0442\u0438\u043f\u043e\u0432 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 deCONZ" }, "deconz_devices": { "data": { - "allow_clip_sensor": "\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0434\u0430\u0442\u0447\u0438\u043a\u0438 deCONZ CLIP", + "allow_clip_sensor": "\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0441\u0435\u043d\u0441\u043e\u0440\u044b deCONZ CLIP", "allow_deconz_groups": "\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0433\u0440\u0443\u043f\u043f\u044b \u043e\u0441\u0432\u0435\u0449\u0435\u043d\u0438\u044f deCONZ" }, - "description": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0442\u0438\u043f\u043e\u0432 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 deCONZ" + "description": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0442\u0438\u043f\u043e\u0432 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 deCONZ", + "title": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 deCONZ" } } } diff --git a/homeassistant/components/deconz/.translations/zh-Hans.json b/homeassistant/components/deconz/.translations/zh-Hans.json index 37b82cff29c..ce51a54ac77 100644 --- a/homeassistant/components/deconz/.translations/zh-Hans.json +++ b/homeassistant/components/deconz/.translations/zh-Hans.json @@ -52,5 +52,12 @@ "remote_rotate_from_side_5": "\u8bbe\u5907\u4ece\u201c\u7b2c 5 \u9762\u201d\u7ffb\u8f6c\u5230\u201c{subtype}\u201d", "remote_rotate_from_side_6": "\u8bbe\u5907\u4ece\u201c\u7b2c 6 \u9762\u201d\u7ffb\u8f6c\u5230\u201c{subtype}\u201d" } + }, + "options": { + "step": { + "deconz_devices": { + "title": "deCONZ \u9009\u9879" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/deconz/.translations/zh-Hant.json b/homeassistant/components/deconz/.translations/zh-Hant.json index 96ab68a8dbb..073ebd784c6 100644 --- a/homeassistant/components/deconz/.translations/zh-Hant.json +++ b/homeassistant/components/deconz/.translations/zh-Hant.json @@ -108,7 +108,8 @@ "allow_clip_sensor": "\u5141\u8a31 deCONZ CLIP \u611f\u61c9\u5668", "allow_deconz_groups": "\u5141\u8a31 deCONZ \u71c8\u5149\u7fa4\u7d44" }, - "description": "\u8a2d\u5b9a deCONZ \u53ef\u8996\u8a2d\u5099\u985e\u578b" + "description": "\u8a2d\u5b9a deCONZ \u53ef\u8996\u8a2d\u5099\u985e\u578b", + "title": "deCONZ \u9078\u9805" } } } diff --git a/homeassistant/components/demo/.translations/da.json b/homeassistant/components/demo/.translations/da.json index ef01fcb4f3c..fd2764e5ec9 100644 --- a/homeassistant/components/demo/.translations/da.json +++ b/homeassistant/components/demo/.translations/da.json @@ -1,5 +1,28 @@ { "config": { "title": "Demo" + }, + "options": { + "step": { + "init": { + "data": { + "one": "en", + "other": "anden" + } + }, + "options_1": { + "data": { + "bool": "Valgfri boolsk", + "int": "Numerisk input" + } + }, + "options_2": { + "data": { + "multi": "Multimarkering", + "select": "V\u00e6lg en mulighed", + "string": "Strengv\u00e6rdi" + } + } + } } } \ No newline at end of file diff --git a/homeassistant/components/demo/.translations/de.json b/homeassistant/components/demo/.translations/de.json index ef01fcb4f3c..a600790d2fc 100644 --- a/homeassistant/components/demo/.translations/de.json +++ b/homeassistant/components/demo/.translations/de.json @@ -1,5 +1,22 @@ { "config": { "title": "Demo" + }, + "options": { + "step": { + "options_1": { + "data": { + "bool": "Optionaler Boolescher Wert", + "int": "Numerische Eingabe" + } + }, + "options_2": { + "data": { + "multi": "Mehrfachauswahl", + "select": "W\u00e4hlen Sie eine Option", + "string": "String-Wert" + } + } + } } } \ No newline at end of file diff --git a/homeassistant/components/demo/.translations/es.json b/homeassistant/components/demo/.translations/es.json index ef01fcb4f3c..73ed9809d65 100644 --- a/homeassistant/components/demo/.translations/es.json +++ b/homeassistant/components/demo/.translations/es.json @@ -1,5 +1,22 @@ { "config": { "title": "Demo" + }, + "options": { + "step": { + "options_1": { + "data": { + "bool": "Booleano opcional", + "int": "Entrada num\u00e9rica" + } + }, + "options_2": { + "data": { + "multi": "Multiselecci\u00f3n", + "select": "Selecciona una opci\u00f3n", + "string": "Valor de cadena" + } + } + } } } \ No newline at end of file diff --git a/homeassistant/components/demo/.translations/ko.json b/homeassistant/components/demo/.translations/ko.json index d20943c7b36..efe69b575fb 100644 --- a/homeassistant/components/demo/.translations/ko.json +++ b/homeassistant/components/demo/.translations/ko.json @@ -1,5 +1,22 @@ { "config": { "title": "\ub370\ubaa8" + }, + "options": { + "step": { + "options_1": { + "data": { + "bool": "\ub17c\ub9ac \uc120\ud0dd", + "int": "\uc22b\uc790 \uc785\ub825" + } + }, + "options_2": { + "data": { + "multi": "\ub2e4\uc911 \uc120\ud0dd", + "select": "\uc635\uc158 \uc120\ud0dd", + "string": "\ubb38\uc790\uc5f4 \uac12" + } + } + } } } \ No newline at end of file diff --git a/homeassistant/components/demo/.translations/lb.json b/homeassistant/components/demo/.translations/lb.json index ef01fcb4f3c..d968b43af8b 100644 --- a/homeassistant/components/demo/.translations/lb.json +++ b/homeassistant/components/demo/.translations/lb.json @@ -1,5 +1,14 @@ { "config": { "title": "Demo" + }, + "options": { + "step": { + "options_2": { + "data": { + "select": "Eng Optioun auswielen" + } + } + } } } \ No newline at end of file diff --git a/homeassistant/components/demo/.translations/no.json b/homeassistant/components/demo/.translations/no.json index ef01fcb4f3c..a46606621b9 100644 --- a/homeassistant/components/demo/.translations/no.json +++ b/homeassistant/components/demo/.translations/no.json @@ -1,5 +1,22 @@ { "config": { "title": "Demo" + }, + "options": { + "step": { + "options_1": { + "data": { + "bool": "Valgfri boolean", + "int": "Numerisk inndata" + } + }, + "options_2": { + "data": { + "multi": "Flervalg", + "select": "Velg et alternativ", + "string": "Strengverdi" + } + } + } } } \ No newline at end of file diff --git a/homeassistant/components/demo/.translations/pl.json b/homeassistant/components/demo/.translations/pl.json index ef01fcb4f3c..f224d100929 100644 --- a/homeassistant/components/demo/.translations/pl.json +++ b/homeassistant/components/demo/.translations/pl.json @@ -1,5 +1,30 @@ { "config": { "title": "Demo" + }, + "options": { + "step": { + "init": { + "data": { + "few": "kilka", + "many": "wiele", + "one": "jedena", + "other": "inne" + } + }, + "options_1": { + "data": { + "bool": "Warto\u015b\u0107 logiczna", + "int": "Warto\u015b\u0107 numeryczna" + } + }, + "options_2": { + "data": { + "multi": "Wielokrotny wyb\u00f3r", + "select": "Wybierz opcj\u0119", + "string": "Warto\u015b\u0107 tekstowa" + } + } + } } } \ No newline at end of file diff --git a/homeassistant/components/demo/.translations/ru.json b/homeassistant/components/demo/.translations/ru.json index 0438252a429..22ea3d2e196 100644 --- a/homeassistant/components/demo/.translations/ru.json +++ b/homeassistant/components/demo/.translations/ru.json @@ -1,5 +1,22 @@ { "config": { "title": "\u0414\u0435\u043c\u043e" + }, + "options": { + "step": { + "options_1": { + "data": { + "bool": "\u041b\u043e\u0433\u0438\u0447\u0435\u0441\u043a\u0438\u0439", + "int": "\u0427\u0438\u0441\u043b\u043e\u0432\u043e\u0439" + } + }, + "options_2": { + "data": { + "multi": "\u0412\u044b\u0431\u0440\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e", + "select": "\u0412\u044b\u0431\u0440\u0430\u0442\u044c \u043e\u043f\u0446\u0438\u044e", + "string": "\u0421\u0442\u0440\u043e\u043a\u043e\u0432\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435" + } + } + } } } \ No newline at end of file diff --git a/homeassistant/components/demo/.translations/zh-Hans.json b/homeassistant/components/demo/.translations/zh-Hans.json new file mode 100644 index 00000000000..9155b5066c5 --- /dev/null +++ b/homeassistant/components/demo/.translations/zh-Hans.json @@ -0,0 +1,19 @@ +{ + "options": { + "step": { + "options_1": { + "data": { + "bool": "\u5e03\u5c14\u9009\u9879", + "int": "\u6570\u503c\u8f93\u5165" + } + }, + "options_2": { + "data": { + "multi": "\u591a\u91cd\u9009\u62e9", + "select": "\u9009\u62e9\u9009\u9879", + "string": "\u5b57\u7b26\u4e32\u503c" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/esphome/.translations/zh-Hans.json b/homeassistant/components/esphome/.translations/zh-Hans.json index 46790868aba..4839167785d 100644 --- a/homeassistant/components/esphome/.translations/zh-Hans.json +++ b/homeassistant/components/esphome/.translations/zh-Hans.json @@ -8,6 +8,7 @@ "invalid_password": "\u65e0\u6548\u7684\u5bc6\u7801\uff01", "resolve_error": "\u65e0\u6cd5\u89e3\u6790 ESP \u7684\u5730\u5740\u3002\u5982\u679c\u6b64\u9519\u8bef\u6301\u7eed\u5b58\u5728\uff0c\u8bf7\u8bbe\u7f6e\u9759\u6001IP\u5730\u5740\uff1ahttps://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips" }, + "flow_title": "ESPHome: {name}", "step": { "authenticate": { "data": { diff --git a/homeassistant/components/gios/.translations/ru.json b/homeassistant/components/gios/.translations/ru.json index 69ffff98517..0045b08cec8 100644 --- a/homeassistant/components/gios/.translations/ru.json +++ b/homeassistant/components/gios/.translations/ru.json @@ -5,7 +5,7 @@ }, "error": { "cannot_connect": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443 GIO\u015a.", - "invalid_sensors_data": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u0430\u0442\u0447\u0438\u043a\u043e\u0432 \u0434\u043b\u044f \u044d\u0442\u043e\u0439 \u0438\u0437\u043c\u0435\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0441\u0442\u0430\u043d\u0446\u0438\u0438.", + "invalid_sensors_data": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0441\u0435\u043d\u0441\u043e\u0440\u043e\u0432 \u0434\u043b\u044f \u044d\u0442\u043e\u0439 \u0438\u0437\u043c\u0435\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0441\u0442\u0430\u043d\u0446\u0438\u0438.", "wrong_station_id": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0439 ID \u0438\u0437\u043c\u0435\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0441\u0442\u0430\u043d\u0446\u0438\u0438." }, "step": { diff --git a/homeassistant/components/hue/.translations/zh-Hans.json b/homeassistant/components/hue/.translations/zh-Hans.json index 1c6d78f9343..5e2f35bfea8 100644 --- a/homeassistant/components/hue/.translations/zh-Hans.json +++ b/homeassistant/components/hue/.translations/zh-Hans.json @@ -5,7 +5,7 @@ "already_configured": "\u98de\u5229\u6d66 Hue Bridge \u5df2\u914d\u7f6e\u5b8c\u6210", "already_in_progress": "\u7f51\u6865\u7684\u914d\u7f6e\u6d41\u5df2\u5728\u8fdb\u884c\u4e2d\u3002", "cannot_connect": "\u65e0\u6cd5\u8fde\u63a5\u5230 \u98de\u5229\u6d66 Hue Bridge", - "discover_timeout": "\u65e0\u6cd5\u55c5\u63a2 Hue \u6865\u63a5\u5668", + "discover_timeout": "\u65e0\u6cd5\u55c5\u63a2\u5230 Hue \u6865\u63a5\u5668", "no_bridges": "\u672a\u53d1\u73b0\u98de\u5229\u6d66 Hue Bridge", "unknown": "\u51fa\u73b0\u672a\u77e5\u7684\u9519\u8bef" }, diff --git a/homeassistant/components/ipma/.translations/da.json b/homeassistant/components/ipma/.translations/da.json index 017aff4d0ec..e2f72db7c4d 100644 --- a/homeassistant/components/ipma/.translations/da.json +++ b/homeassistant/components/ipma/.translations/da.json @@ -8,6 +8,7 @@ "data": { "latitude": "Breddegrad", "longitude": "L\u00e6ngdegrad", + "mode": "Tilstand", "name": "Navn" }, "description": "Instituto Portugu\u00eas do Mar e Atmosfera", diff --git a/homeassistant/components/ipma/.translations/pl.json b/homeassistant/components/ipma/.translations/pl.json index 7eb8055e1a1..267b4e79137 100644 --- a/homeassistant/components/ipma/.translations/pl.json +++ b/homeassistant/components/ipma/.translations/pl.json @@ -8,6 +8,7 @@ "data": { "latitude": "Szeroko\u015b\u0107 geograficzna", "longitude": "D\u0142ugo\u015b\u0107 geograficzna", + "mode": "Tryb", "name": "Nazwa" }, "description": "Portugalski Instytut Morza i Atmosfery", diff --git a/homeassistant/components/ipma/.translations/zh-Hans.json b/homeassistant/components/ipma/.translations/zh-Hans.json index 6c5654b6388..10d51832964 100644 --- a/homeassistant/components/ipma/.translations/zh-Hans.json +++ b/homeassistant/components/ipma/.translations/zh-Hans.json @@ -8,6 +8,7 @@ "data": { "latitude": "\u7eac\u5ea6", "longitude": "\u7ecf\u5ea6", + "mode": "\u6a21\u5f0f", "name": "\u540d\u79f0" }, "description": "\u8461\u8404\u7259\u56fd\u5bb6\u5927\u6c14\u7814\u7a76\u6240", diff --git a/homeassistant/components/konnected/.translations/da.json b/homeassistant/components/konnected/.translations/da.json index b8b8acc2f49..db37ad73610 100644 --- a/homeassistant/components/konnected/.translations/da.json +++ b/homeassistant/components/konnected/.translations/da.json @@ -1,8 +1,104 @@ { - "options": { + "config": { + "abort": { + "already_configured": "Enheden er allerede konfigureret", + "already_in_progress": "Enhedskonfiguration er allerede i gang.", + "not_konn_panel": "Ikke en genkendt Konnected.io-enhed", + "unknown": "Ukendt fejl opstod" + }, "error": { - "one": "EN", - "other": "ANDEN" - } + "cannot_connect": "Der kan ikke oprettes forbindelse til et Konnected-panel p\u00e5 {host}:{port}" + }, + "step": { + "confirm": { + "description": "Model: {model}\nV\u00e6rt: {host}\nPort: {port}\n\nDu kan konfigurere IO og panelfunktionsm\u00e5den i indstillingerne for Konnected-alarmpanel.", + "title": "Konnected-enhed klar" + }, + "user": { + "data": { + "host": "Konnected-enhedens IP-adresse", + "port": "Konnected-enhedsport" + }, + "description": "Indtast v\u00e6rtsinformationen for dit Konnected-panel.", + "title": "Find Konnected-enhed" + } + }, + "title": "Konnected.io" + }, + "options": { + "abort": { + "not_konn_panel": "Ikke en genkendt Konnected.io-enhed" + }, + "error": { + "one": "en", + "other": "anden" + }, + "step": { + "options_binary": { + "data": { + "inverse": "Inverter tilstanden \u00e5ben/lukket", + "name": "Navn (valgfrit)", + "type": "Bin\u00e6r sensortype" + }, + "description": "V\u00e6lg indstillingerne for den bin\u00e6re sensor, der er knyttet til {zone}", + "title": "Konfigurer bin\u00e6r sensor" + }, + "options_digital": { + "data": { + "name": "Navn (valgfrit)", + "poll_interval": "Foresp\u00f8rgselsinterval (minutter) (valgfrit)", + "type": "Sensortype" + }, + "description": "V\u00e6lg indstillingerne for den digitale sensor, der er knyttet til {zone}", + "title": "Konfigurer digital sensor" + }, + "options_io": { + "data": { + "1": "Zone 1", + "2": "Zone 2", + "3": "Zone 3", + "4": "Zone 4", + "5": "Zone 5", + "6": "Zone 6", + "7": "Zone 7", + "out": "OUT" + }, + "description": "Der blev fundet en {model} p\u00e5 {host}. V\u00e6lg basiskonfigurationen af hver I/O nedenfor - afh\u00e6ngigt af I/O kan det give mulighed for bin\u00e6re sensorer (\u00e5ben-/lukket-kontakter), digitale sensorer (dht og ds18b20) eller omskiftelige outputs. Du kan konfigurere detaljerede indstillinger i de n\u00e6ste trin.", + "title": "Konfigurer I/O" + }, + "options_io_ext": { + "data": { + "10": "Zone 10", + "11": "Zone 11", + "12": "Zone 12", + "8": "Zone 8", + "9": "Zone 9", + "alarm1": "ALARM1", + "alarm2_out2": "OUT2/ALARM2", + "out1": "OUT1" + }, + "description": "V\u00e6lg konfigurationen af det resterende I/O nedenfor. Du kan konfigurere detaljerede indstillinger i de n\u00e6ste trin.", + "title": "Konfigurer udvidet I/O" + }, + "options_misc": { + "data": { + "blink": "Blink panel-LED ved sending af tilstands\u00e6ndring" + }, + "description": "V\u00e6lg den \u00f8nskede funktionsm\u00e5de for panelet", + "title": "Konfigurer diverse" + }, + "options_switch": { + "data": { + "activation": "Output n\u00e5r der er t\u00e6ndt", + "momentary": "Impulsvarighed (ms) (valgfrit)", + "name": "Navn (valgfrit)", + "pause": "Pause mellem impulser (ms) (valgfrit)", + "repeat": "Gange til gentagelse (-1=uendelig) (valgfrit)" + }, + "description": "V\u00e6lg outputindstillingerne for {zone}", + "title": "Konfigurer skifteligt output" + } + }, + "title": "Indstillinger for Konnected-alarmpanel" } } \ No newline at end of file diff --git a/homeassistant/components/konnected/.translations/de.json b/homeassistant/components/konnected/.translations/de.json index ca4dd01f098..fa5b1f53dfb 100644 --- a/homeassistant/components/konnected/.translations/de.json +++ b/homeassistant/components/konnected/.translations/de.json @@ -14,6 +14,9 @@ "description": "Modell: {model} \nHost: {host} \nPort: {port} \n\nSie k\u00f6nnen das I / O - und Bedienfeldverhalten in den Einstellungen der verbundenen Alarmzentrale konfigurieren.", "title": "Konnected Device Bereit" }, + "import_confirm": { + "title": "Importieren von Konnected Ger\u00e4t" + }, "user": { "data": { "host": "Konnected Ger\u00e4t IP-Adresse", diff --git a/homeassistant/components/konnected/.translations/en.json b/homeassistant/components/konnected/.translations/en.json index 9d642a43603..fd0a8e84e37 100644 --- a/homeassistant/components/konnected/.translations/en.json +++ b/homeassistant/components/konnected/.translations/en.json @@ -33,7 +33,6 @@ "abort": { "not_konn_panel": "Not a recognized Konnected.io device" }, - "error": {}, "step": { "options_binary": { "data": { diff --git a/homeassistant/components/konnected/.translations/ko.json b/homeassistant/components/konnected/.translations/ko.json index d39ca606cc7..fe196050766 100644 --- a/homeassistant/components/konnected/.translations/ko.json +++ b/homeassistant/components/konnected/.translations/ko.json @@ -14,6 +14,10 @@ "description": "\ubaa8\ub378: {model}\n\ud638\uc2a4\ud2b8: {host}\n\ud3ec\ud2b8: {port}\n\nKonnected \uc54c\ub78c \ud328\ub110 \uc124\uc815\uc5d0\uc11c IO \uc640 \ud328\ub110 \ub3d9\uc791\uc744 \uad6c\uc131\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.", "title": "Konnected \uae30\uae30 \uc900\ube44" }, + "import_confirm": { + "description": "Konnected \uc54c\ub78c \ud328\ub110 ID {id} \uac00 configuration.yaml \uc5d0\uc11c \ubc1c\uacac\ub418\uc5c8\uc2b5\ub2c8\ub2e4. \uc774 \uacfc\uc815\uc744 \ud1b5\ud574 \uad6c\uc131 \ud56d\ubaa9\uc73c\ub85c \uac00\uc838\uc62c \uc218 \uc788\uc2b5\ub2c8\ub2e4.", + "title": "Konnected \uae30\uae30 \uac00\uc838\uc624\uae30" + }, "user": { "data": { "host": "Konnected \uae30\uae30 IP \uc8fc\uc18c", diff --git a/homeassistant/components/konnected/.translations/pl.json b/homeassistant/components/konnected/.translations/pl.json index c2f992116a8..b0d721891c0 100644 --- a/homeassistant/components/konnected/.translations/pl.json +++ b/homeassistant/components/konnected/.translations/pl.json @@ -26,23 +26,81 @@ "title": "Konnected.io" }, "options": { + "abort": { + "not_konn_panel": "Nie rozpoznano urz\u0105dzenia Konnected.io" + }, + "error": { + "few": "kilka", + "many": "wiele", + "one": "jeden", + "other": "inny" + }, "step": { "options_binary": { "data": { - "name": "Nazwa (opcjonalnie)" - } + "inverse": "Odwr\u00f3\u0107 stan otwarty/zamkni\u0119ty", + "name": "Nazwa (opcjonalnie)", + "type": "Typ sensora binarnego" + }, + "description": "Wybierz opcje dla sensora binarnego powi\u0105zanego ze {zone}", + "title": "Konfiguracja sensora binarnego" }, "options_digital": { "data": { "name": "Nazwa (opcjonalnie)", + "poll_interval": "Cz\u0119stotliwo\u015b\u0107 aktualizacji (minuty) (opcjonalnie)", "type": "Typ sensora" - } + }, + "description": "Wybierz opcje dla cyfrowego sensora powi\u0105zanego ze {zone}", + "title": "Konfiguracja sensora cyfrowego" + }, + "options_io": { + "data": { + "1": "Strefa 1", + "2": "Strefa 2", + "3": "Strefa 3", + "4": "Strefa 4", + "5": "Strefa 5", + "6": "Strefa 6", + "7": "Strefa 7", + "out": "OUT" + }, + "description": "Wykryto {model} na ho\u015bcie {host}. Wybierz podstawow\u0105 konfiguracj\u0119 ka\u017cdego wej\u015bcia/wyj\u015bcia poni\u017cej \u2014 w zale\u017cno\u015bci od typu wej\u015b\u0107/wyj\u015b\u0107 mo\u017ce zastosowa\u0107 sensory binarne (otwarte/ amkni\u0119te), sensory cyfrowe (dht i ds18b20) lub prze\u0142\u0105czane wyj\u015bcia. B\u0119dziesz m\u00f3g\u0142 skonfigurowa\u0107 szczeg\u00f3\u0142owe opcje w kolejnych krokach.", + "title": "Konfiguracja wej\u015bcia/wyj\u015bcia" + }, + "options_io_ext": { + "data": { + "10": "Strefa 10", + "11": "Strefa 11", + "12": "Strefa 12", + "8": "Strefa 8", + "9": "Strefa 9", + "alarm1": "ALARM1", + "alarm2_out2": "OUT2/ALARM2", + "out1": "OUT1" + }, + "description": "Wybierz konfiguracj\u0119 pozosta\u0142ych wej\u015b\u0107/wyj\u015b\u0107 poni\u017cej. B\u0119dziesz m\u00f3g\u0142 skonfigurowa\u0107 szczeg\u00f3\u0142owe opcje w kolejnych krokach.", + "title": "Konfiguracja rozszerzonego wej\u015bcia/wyj\u015bcia" + }, + "options_misc": { + "data": { + "blink": "Miganie diody LED panelu podczas wysy\u0142ania zmiany stanu" + }, + "description": "Wybierz po\u017c\u0105dane zachowanie dla swojego panelu", + "title": "R\u00f3\u017cne opcje" }, "options_switch": { "data": { - "name": "Nazwa (opcjonalnie)" - } + "activation": "Wyj\u015bcie, gdy w\u0142\u0105czone", + "momentary": "Czas trwania impulsu (ms) (opcjonalnie)", + "name": "Nazwa (opcjonalnie)", + "pause": "Przerwa mi\u0119dzy impulsami (ms) (opcjonalnie)", + "repeat": "Ilo\u015b\u0107 powt\u00f3rze\u0144 (-1=niesko\u0144czenie) (opcjonalnie)" + }, + "description": "Wybierz opcje wyj\u015bcia dla {zone}", + "title": "Konfiguracja prze\u0142\u0105czalne wyj\u015bcie" } - } + }, + "title": "Opcje panelu alarmu Konnected" } } \ No newline at end of file diff --git a/homeassistant/components/konnected/.translations/ru.json b/homeassistant/components/konnected/.translations/ru.json index 59d4a199576..25cb03b1578 100644 --- a/homeassistant/components/konnected/.translations/ru.json +++ b/homeassistant/components/konnected/.translations/ru.json @@ -34,19 +34,19 @@ "data": { "inverse": "\u0418\u043d\u0432\u0435\u0440\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u043a\u0440\u044b\u0442\u043e\u0435/\u0437\u0430\u043a\u0440\u044b\u0442\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435", "name": "\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 (\u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e)", - "type": "\u0422\u0438\u043f \u0431\u0438\u043d\u0430\u0440\u043d\u043e\u0433\u043e \u0434\u0430\u0442\u0447\u0438\u043a\u0430" + "type": "\u0422\u0438\u043f \u0431\u0438\u043d\u0430\u0440\u043d\u043e\u0433\u043e \u0441\u0435\u043d\u0441\u043e\u0440\u0430" }, - "description": "\u0423\u043a\u0430\u0436\u0438\u0442\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0431\u0438\u043d\u0430\u0440\u043d\u043e\u0433\u043e \u0434\u0430\u0442\u0447\u0438\u043a\u0430, \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u043a {zone}.", - "title": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0431\u0438\u043d\u0430\u0440\u043d\u043e\u0433\u043e \u0434\u0430\u0442\u0447\u0438\u043a\u0430" + "description": "\u0423\u043a\u0430\u0436\u0438\u0442\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0431\u0438\u043d\u0430\u0440\u043d\u043e\u0433\u043e \u0441\u0435\u043d\u0441\u043e\u0440\u0430, \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u043a {zone}.", + "title": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0431\u0438\u043d\u0430\u0440\u043d\u043e\u0433\u043e \u0441\u0435\u043d\u0441\u043e\u0440\u0430" }, "options_digital": { "data": { "name": "\u041d\u0430\u0437\u0432\u0430\u043d\u0438\u0435 (\u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e)", "poll_interval": "\u0418\u043d\u0442\u0435\u0440\u0432\u0430\u043b \u043e\u043f\u0440\u043e\u0441\u0430 \u0432 \u043c\u0438\u043d\u0443\u0442\u0430\u0445 (\u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e)", - "type": "\u0422\u0438\u043f \u0434\u0430\u0442\u0447\u0438\u043a\u0430" + "type": "\u0422\u0438\u043f \u0441\u0435\u043d\u0441\u043e\u0440\u0430" }, - "description": "\u0423\u043a\u0430\u0436\u0438\u0442\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0434\u0430\u0442\u0447\u0438\u043a\u0430, \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u043a {zone}.", - "title": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0434\u0430\u0442\u0447\u0438\u043a\u0430" + "description": "\u0423\u043a\u0430\u0436\u0438\u0442\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0441\u0435\u043d\u0441\u043e\u0440\u0430, \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u043a {zone}.", + "title": "\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0441\u0435\u043d\u0441\u043e\u0440\u0430" }, "options_io": { "data": { @@ -59,7 +59,7 @@ "7": "\u0417\u043e\u043d\u0430 7", "out": "\u0412\u042b\u0425\u041e\u0414" }, - "description": "\u041e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e {model} \u0441 \u0430\u0434\u0440\u0435\u0441\u043e\u043c {host}. \u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0439 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0432\u0445\u043e\u0434\u043e\u0432/\u0432\u044b\u0445\u043e\u0434\u043e\u0432, \u043a \u043f\u0430\u043d\u0435\u043b\u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u044b \u0431\u0438\u043d\u0430\u0440\u043d\u044b\u0435 \u0434\u0430\u0442\u0447\u0438\u043a\u0438 (\u0434\u0430\u0442\u0447\u0438\u043a\u0438 \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u044f/\u0437\u0430\u043a\u0440\u044b\u0442\u0438\u044f), \u0446\u0438\u0444\u0440\u043e\u0432\u044b\u0435 \u0434\u0430\u0442\u0447\u0438\u043a\u0438 (dht \u0438 ds18b20) \u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0435\u043c\u044b\u0435 \u0432\u044b\u0445\u043e\u0434\u044b. \u0411\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0430\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0448\u0430\u0433\u0430\u0445.", + "description": "\u041e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e {model} \u0441 \u0430\u0434\u0440\u0435\u0441\u043e\u043c {host}. \u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0439 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0432\u0445\u043e\u0434\u043e\u0432/\u0432\u044b\u0445\u043e\u0434\u043e\u0432, \u043a \u043f\u0430\u043d\u0435\u043b\u0438 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u044b \u0431\u0438\u043d\u0430\u0440\u043d\u044b\u0435 \u0441\u0435\u043d\u0441\u043e\u0440\u044b (\u0434\u0430\u0442\u0447\u0438\u043a\u0438 \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u044f/\u0437\u0430\u043a\u0440\u044b\u0442\u0438\u044f), \u0446\u0438\u0444\u0440\u043e\u0432\u044b\u0435 \u0441\u0435\u043d\u0441\u043e\u0440\u044b (dht \u0438 ds18b20) \u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0430\u0435\u043c\u044b\u0435 \u0432\u044b\u0445\u043e\u0434\u044b. \u0411\u043e\u043b\u0435\u0435 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0430\u044f \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u0430 \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u0448\u0430\u0433\u0430\u0445.", "title": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0432\u0445\u043e\u0434\u043e\u0432/\u0432\u044b\u0445\u043e\u0434\u043e\u0432" }, "options_io_ext": { diff --git a/homeassistant/components/konnected/.translations/zh-Hans.json b/homeassistant/components/konnected/.translations/zh-Hans.json new file mode 100644 index 00000000000..2bba1260764 --- /dev/null +++ b/homeassistant/components/konnected/.translations/zh-Hans.json @@ -0,0 +1,9 @@ +{ + "options": { + "step": { + "options_switch": { + "description": "\u8bf7\u9009\u62e9 {zone}\u8f93\u51fa\u9009\u9879" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/linky/.translations/zh-Hans.json b/homeassistant/components/linky/.translations/zh-Hans.json index 2c6b3ba34b5..62138856078 100644 --- a/homeassistant/components/linky/.translations/zh-Hans.json +++ b/homeassistant/components/linky/.translations/zh-Hans.json @@ -1,5 +1,8 @@ { "config": { + "error": { + "wrong_login": "\u767b\u5f55\u51fa\u9519\uff1a\u8bf7\u68c0\u67e5\u60a8\u7684\u7535\u5b50\u90ae\u7bb1\u548c\u5bc6\u7801" + }, "step": { "user": { "data": { diff --git a/homeassistant/components/local_ip/.translations/ru.json b/homeassistant/components/local_ip/.translations/ru.json index de92b9680f0..2cf8791e505 100644 --- a/homeassistant/components/local_ip/.translations/ru.json +++ b/homeassistant/components/local_ip/.translations/ru.json @@ -1,7 +1,7 @@ { "config": { "abort": { - "already_configured": "\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0443\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u0441 \u0442\u0430\u043a\u0438\u043c \u0436\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c \u0434\u0430\u0442\u0447\u0438\u043a\u0430." + "already_configured": "\u0418\u043d\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u044f \u0443\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u0430 \u0441 \u0442\u0430\u043a\u0438\u043c \u0436\u0435 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c." }, "step": { "user": { diff --git a/homeassistant/components/luftdaten/.translations/ru.json b/homeassistant/components/luftdaten/.translations/ru.json index 1a05137f82d..759fd926bdc 100644 --- a/homeassistant/components/luftdaten/.translations/ru.json +++ b/homeassistant/components/luftdaten/.translations/ru.json @@ -2,14 +2,14 @@ "config": { "error": { "communication_error": "\u041d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a API Luftdaten.", - "invalid_sensor": "\u0414\u0430\u0442\u0447\u0438\u043a \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u043b\u0438 \u043d\u0435\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u0435\u043d.", - "sensor_exists": "\u0414\u0430\u0442\u0447\u0438\u043a \u0443\u0436\u0435 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d." + "invalid_sensor": "\u0421\u0435\u043d\u0441\u043e\u0440 \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0438\u043b\u0438 \u043d\u0435\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u0435\u043d.", + "sensor_exists": "\u0421\u0435\u043d\u0441\u043e\u0440 \u0443\u0436\u0435 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d." }, "step": { "user": { "data": { "show_on_map": "\u041f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043d\u0430 \u043a\u0430\u0440\u0442\u0435", - "station_id": "\u0418\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0434\u0430\u0442\u0447\u0438\u043a\u0430 Luftdaten" + "station_id": "\u0418\u0434\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440 \u0441\u0435\u043d\u0441\u043e\u0440\u0430 Luftdaten" }, "title": "Luftdaten" } diff --git a/homeassistant/components/mikrotik/.translations/zh-Hans.json b/homeassistant/components/mikrotik/.translations/zh-Hans.json new file mode 100644 index 00000000000..9604af53495 --- /dev/null +++ b/homeassistant/components/mikrotik/.translations/zh-Hans.json @@ -0,0 +1,16 @@ +{ + "config": { + "step": { + "user": { + "data": { + "host": "\u4e3b\u673a", + "name": "\u540d\u5b57", + "password": "\u5bc6\u7801", + "port": "\u7aef\u53e3", + "username": "\u7528\u6237\u540d", + "verify_ssl": "\u4f7f\u7528 ssl" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/mqtt/.translations/ca.json b/homeassistant/components/mqtt/.translations/ca.json index 47dc4d344bc..b8cce4bd808 100644 --- a/homeassistant/components/mqtt/.translations/ca.json +++ b/homeassistant/components/mqtt/.translations/ca.json @@ -27,5 +27,27 @@ } }, "title": "MQTT" + }, + "device_automation": { + "trigger_subtype": { + "button_1": "Primer bot\u00f3", + "button_2": "Segon bot\u00f3", + "button_3": "Tercer bot\u00f3", + "button_4": "Quart bot\u00f3", + "button_5": "Cinqu\u00e8 bot\u00f3", + "button_6": "Sis\u00e8 bot\u00f3", + "turn_off": "Desactiva", + "turn_on": "Activa" + }, + "trigger_type": { + "button_double_press": "\"{subtype}\" clicat dues vegades", + "button_long_press": "\"{subtype}\" premut cont\u00ednuament", + "button_long_release": "\"{subtype}\" alliberat despr\u00e9s d'una estona premut", + "button_quadruple_press": "\"{subtype}\" clicat quatre vegades", + "button_quintuple_press": "\"{subtype}\" clicat cinc vegades", + "button_short_press": "\"{subtype}\" premut", + "button_short_release": "\"{subtype}\" alliberat", + "button_triple_press": "\"{subtype}\" clicat tres vegades" + } } } \ No newline at end of file diff --git a/homeassistant/components/mqtt/.translations/da.json b/homeassistant/components/mqtt/.translations/da.json index 93ea57d49ea..e018ab7aa14 100644 --- a/homeassistant/components/mqtt/.translations/da.json +++ b/homeassistant/components/mqtt/.translations/da.json @@ -27,5 +27,27 @@ } }, "title": "MQTT" + }, + "device_automation": { + "trigger_subtype": { + "button_1": "F\u00f8rste knap", + "button_2": "Anden knap", + "button_3": "Tredje knap", + "button_4": "Fjerde knap", + "button_5": "Femte knap", + "button_6": "Sjette knap", + "turn_off": "Sluk", + "turn_on": "T\u00e6nd" + }, + "trigger_type": { + "button_double_press": "\"{subtype}\" dobbeltklikket", + "button_long_press": "\"{subtype}\" trykket p\u00e5 konstant", + "button_long_release": "\"{subtype}\" sluppet efter langt tryk", + "button_quadruple_press": "\"{subtype}\" firedobbelt-klikket", + "button_quintuple_press": "\"{subtype}\" femdobbelt-klikket", + "button_short_press": "\"{subtype}\" trykket p\u00e5", + "button_short_release": "\"{subtype}\" sluppet", + "button_triple_press": "\"{subtype}\" tredobbeltklikket" + } } } \ No newline at end of file diff --git a/homeassistant/components/mqtt/.translations/de.json b/homeassistant/components/mqtt/.translations/de.json index 7bca8de54eb..87c6a989f52 100644 --- a/homeassistant/components/mqtt/.translations/de.json +++ b/homeassistant/components/mqtt/.translations/de.json @@ -27,5 +27,27 @@ } }, "title": "MQTT" + }, + "device_automation": { + "trigger_subtype": { + "button_1": "Erste Taste", + "button_2": "Zweite Taste", + "button_3": "Dritte Taste", + "button_4": "Vierte Taste", + "button_5": "F\u00fcnfte Taste", + "button_6": "Sechste Taste", + "turn_off": "Ausschalten", + "turn_on": "Einschalten" + }, + "trigger_type": { + "button_double_press": "\"{subtype}\" doppelt angeklickt", + "button_long_press": "\"{subtype}\" kontinuierlich gedr\u00fcckt", + "button_long_release": "\"{subtype}\" nach langem Dr\u00fccken freigegeben", + "button_quadruple_press": "\"{subtype}\" Vierfach geklickt", + "button_quintuple_press": "\"{subtype}\" f\u00fcnffach geklickt", + "button_short_press": "\"{subtype}\" gedr\u00fcckt", + "button_short_release": "\"{subtype}\" freigegeben", + "button_triple_press": "\"{subtype}\" dreifach geklickt" + } } } \ No newline at end of file diff --git a/homeassistant/components/mqtt/.translations/es.json b/homeassistant/components/mqtt/.translations/es.json index e0c94ac621a..a705a885494 100644 --- a/homeassistant/components/mqtt/.translations/es.json +++ b/homeassistant/components/mqtt/.translations/es.json @@ -27,5 +27,27 @@ } }, "title": "MQTT" + }, + "device_automation": { + "trigger_subtype": { + "button_1": "Primer bot\u00f3n", + "button_2": "Segundo bot\u00f3n", + "button_3": "Tercer bot\u00f3n", + "button_4": "Cuarto bot\u00f3n", + "button_5": "Quinto bot\u00f3n", + "button_6": "Sexto bot\u00f3n", + "turn_off": "Apagar", + "turn_on": "Encender" + }, + "trigger_type": { + "button_double_press": "\"{subtype}\" doble pulsaci\u00f3n", + "button_long_press": "\"{subtype}\" pulsado continuamente", + "button_long_release": "\"{subtype}\" soltado despu\u00e9s de pulsaci\u00f3n larga", + "button_quadruple_press": "\"{subtype}\" cu\u00e1druple pulsaci\u00f3n", + "button_quintuple_press": "\"{subtype}\" quintuple pulsaci\u00f3n", + "button_short_press": "\"{subtype}\" pulsado", + "button_short_release": "\"{subtype}\" soltado", + "button_triple_press": "\"{subtype}\" triple pulsaci\u00f3n" + } } } \ No newline at end of file diff --git a/homeassistant/components/mqtt/.translations/it.json b/homeassistant/components/mqtt/.translations/it.json index cf2b3ddf7d5..45f7f8dcdb5 100644 --- a/homeassistant/components/mqtt/.translations/it.json +++ b/homeassistant/components/mqtt/.translations/it.json @@ -27,5 +27,27 @@ } }, "title": "MQTT" + }, + "device_automation": { + "trigger_subtype": { + "button_1": "Primo pulsante", + "button_2": "Secondo pulsante", + "button_3": "Terzo pulsante", + "button_4": "Quarto pulsante", + "button_5": "Quinto pulsante", + "button_6": "Sesto pulsante", + "turn_off": "Spegni", + "turn_on": "Accendi" + }, + "trigger_type": { + "button_double_press": "\"{subtype}\" cliccato due volte", + "button_long_press": "\"{subtype}\" premuto continuamente", + "button_long_release": "\"{subtype}\" rilasciato dopo una lunga pressione", + "button_quadruple_press": "\"{subtype}\" cliccato quattro volte", + "button_quintuple_press": "\"{subtype}\" cliccato cinque volte", + "button_short_press": "\"{subtype}\" premuto", + "button_short_release": "\"{subtype}\" rilasciato", + "button_triple_press": "\"{subtype}\" cliccato tre volte" + } } } \ No newline at end of file diff --git a/homeassistant/components/mqtt/.translations/ko.json b/homeassistant/components/mqtt/.translations/ko.json index 307a6aaadeb..8a0243013d9 100644 --- a/homeassistant/components/mqtt/.translations/ko.json +++ b/homeassistant/components/mqtt/.translations/ko.json @@ -27,5 +27,27 @@ } }, "title": "MQTT" + }, + "device_automation": { + "trigger_subtype": { + "button_1": "\uccab \ubc88\uc9f8 \ubc84\ud2bc", + "button_2": "\ub450 \ubc88\uc9f8 \ubc84\ud2bc", + "button_3": "\uc138 \ubc88\uc9f8 \ubc84\ud2bc", + "button_4": "\ub124 \ubc88\uc9f8 \ubc84\ud2bc", + "button_5": "\ub2e4\uc12f \ubc88\uc9f8 \ubc84\ud2bc", + "button_6": "\uc5ec\uc12f \ubc88\uc9f8 \ubc84\ud2bc", + "turn_off": "\ub044\uae30", + "turn_on": "\ucf1c\uae30" + }, + "trigger_type": { + "button_double_press": "\"{subtype}\" \uc774 \ub450 \ubc88 \ub20c\ub9b4 \ub54c", + "button_long_press": "\"{subtype}\" \uc774 \uacc4\uc18d \ub20c\ub824\uc9c8 \ub54c", + "button_long_release": "\"{subtype}\" \uc774 \uae38\uac8c \ub20c\ub838\ub2e4\uac00 \uc190\uc744 \ub5c4 \ub54c", + "button_quadruple_press": "\"{subtype}\" \uc774 \ub124 \ubc88 \ub20c\ub9b4 \ub54c", + "button_quintuple_press": "\"{subtype}\" \uc774 \ub2e4\uc12f \ubc88 \ub20c\ub9b4 \ub54c", + "button_short_press": "\"{subtype}\" \uc774 \ub20c\ub9b4 \ub54c", + "button_short_release": "\"{subtype}\" \uc5d0\uc11c \uc190\uc744 \ub5c4 \ub54c", + "button_triple_press": "\"{subtype}\" \uc774 \uc138 \ubc88 \ub20c\ub9b4 \ub54c" + } } } \ No newline at end of file diff --git a/homeassistant/components/mqtt/.translations/lb.json b/homeassistant/components/mqtt/.translations/lb.json index 9dcd9c58a3a..9467ab8a9a7 100644 --- a/homeassistant/components/mqtt/.translations/lb.json +++ b/homeassistant/components/mqtt/.translations/lb.json @@ -27,5 +27,17 @@ } }, "title": "MQTT" + }, + "device_automation": { + "trigger_subtype": { + "button_1": "\u00c9ischte Kn\u00e4ppchen", + "button_2": "Zweete Kn\u00e4ppchen", + "button_3": "Dr\u00ebtte Kn\u00e4ppchen", + "button_4": "V\u00e9ierte Kn\u00e4ppchen", + "button_5": "F\u00ebnnefte Kn\u00e4ppchen", + "button_6": "Sechste Kn\u00e4ppchen", + "turn_off": "Ausschalten", + "turn_on": "Uschalten" + } } } \ No newline at end of file diff --git a/homeassistant/components/mqtt/.translations/no.json b/homeassistant/components/mqtt/.translations/no.json index 8dcc0bded9f..27a77a25226 100644 --- a/homeassistant/components/mqtt/.translations/no.json +++ b/homeassistant/components/mqtt/.translations/no.json @@ -27,5 +27,27 @@ } }, "title": "MQTT" + }, + "device_automation": { + "trigger_subtype": { + "button_1": "F\u00f8rste knapp", + "button_2": "Andre knapp", + "button_3": "Tredje knapp", + "button_4": "Fjerde knapp", + "button_5": "Femte knapp", + "button_6": "Sjette knapp", + "turn_off": "Skru av", + "turn_on": "Sl\u00e5 p\u00e5" + }, + "trigger_type": { + "button_double_press": "\"{subtype}\" dobbeltklikket", + "button_long_press": "{subtype}\" trykket kontinuerlig", + "button_long_release": "\"{subtype}\" utgitt etter lang trykk", + "button_quadruple_press": "\"{subtype}\" firedoblet klikket", + "button_quintuple_press": "\"{subtype}\" quintuple klikket", + "button_short_press": "{subtype}\u00bb trykket", + "button_short_release": "\"{subtype}\" utgitt", + "button_triple_press": "\"{subtype}\" trippel klikket" + } } } \ No newline at end of file diff --git a/homeassistant/components/mqtt/.translations/pl.json b/homeassistant/components/mqtt/.translations/pl.json index 24cdeb0f12e..86561f89d2b 100644 --- a/homeassistant/components/mqtt/.translations/pl.json +++ b/homeassistant/components/mqtt/.translations/pl.json @@ -27,5 +27,27 @@ } }, "title": "MQTT" + }, + "device_automation": { + "trigger_subtype": { + "button_1": "pierwszy przycisk", + "button_2": "drugi przycisk", + "button_3": "trzeci przycisk", + "button_4": "czwarty przycisk", + "button_5": "pi\u0105ty przycisk", + "button_6": "sz\u00f3sty przycisk", + "turn_off": "nast\u0105pi wy\u0142\u0105czenie", + "turn_on": "nast\u0105pi w\u0142\u0105czenie" + }, + "trigger_type": { + "button_double_press": "\"{subtype}\" zostanie podw\u00f3jnie naci\u015bni\u0119ty", + "button_long_press": "\"{subtype}\" zostanie naci\u015bni\u0119ty w spos\u00f3b ci\u0105g\u0142y", + "button_long_release": "\"{subtype}\" zostanie zwolniony po d\u0142ugim naci\u015bni\u0119ciu", + "button_quadruple_press": "\"{subtype}\" zostanie czterokrotnie naci\u015bni\u0119ty", + "button_quintuple_press": "\"{subtype}\" zostanie pi\u0119ciokrotnie naci\u015bni\u0119ty", + "button_short_press": "\"{subtype}\" zostanie naci\u015bni\u0119ty", + "button_short_release": "\"{subtype}\" zostanie zwolniony", + "button_triple_press": "\"{subtype}\" zostanie trzykrotnie naci\u015bni\u0119ty" + } } } \ No newline at end of file diff --git a/homeassistant/components/mqtt/.translations/ro.json b/homeassistant/components/mqtt/.translations/ro.json index bcd150e3063..0bbf39315d9 100644 --- a/homeassistant/components/mqtt/.translations/ro.json +++ b/homeassistant/components/mqtt/.translations/ro.json @@ -22,7 +22,7 @@ "data": { "discovery": "Activa\u021bi descoperirea" }, - "description": "Dori\u021bi s\u0103 configura\u021bi Home Assistant pentru a v\u0103 conecta la brokerul MQTT furnizat de addon-ul {addon} ?", + "description": "Dori\u021bi s\u0103 configura\u021bi Home Assistant pentru a se conecta la brokerul MQTT furnizat de addon-ul {addon} ?", "title": "MQTT Broker, prin intermediul Hass.io add-on" } }, diff --git a/homeassistant/components/mqtt/.translations/ru.json b/homeassistant/components/mqtt/.translations/ru.json index 925b8cf5ab4..3559fcc6b2b 100644 --- a/homeassistant/components/mqtt/.translations/ru.json +++ b/homeassistant/components/mqtt/.translations/ru.json @@ -27,5 +27,27 @@ } }, "title": "MQTT" + }, + "device_automation": { + "trigger_subtype": { + "button_1": "\u041f\u0435\u0440\u0432\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430", + "button_2": "\u0412\u0442\u043e\u0440\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430", + "button_3": "\u0422\u0440\u0435\u0442\u044c\u044f \u043a\u043d\u043e\u043f\u043a\u0430", + "button_4": "\u0427\u0435\u0442\u0432\u0435\u0440\u0442\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430", + "button_5": "\u041f\u044f\u0442\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430", + "button_6": "\u0428\u0435\u0441\u0442\u0430\u044f \u043a\u043d\u043e\u043f\u043a\u0430", + "turn_off": "\u0412\u044b\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f", + "turn_on": "\u0412\u043a\u043b\u044e\u0447\u0430\u0435\u0442\u0441\u044f" + }, + "trigger_type": { + "button_double_press": "\"{subtype}\" \u043d\u0430\u0436\u0430\u0442\u0430 \u0434\u0432\u0430 \u0440\u0430\u0437\u0430", + "button_long_press": "\"{subtype}\" \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e \u043d\u0430\u0436\u0430\u0442\u0430", + "button_long_release": "\"{subtype}\" \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u0430 \u043f\u043e\u0441\u043b\u0435 \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e\u0433\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044f", + "button_quadruple_press": "\"{subtype}\" \u043d\u0430\u0436\u0430\u0442\u0430 \u0447\u0435\u0442\u044b\u0440\u0435 \u0440\u0430\u0437\u0430", + "button_quintuple_press": "\"{subtype}\" \u043d\u0430\u0436\u0430\u0442\u0430 \u043f\u044f\u0442\u044c \u0440\u0430\u0437", + "button_short_press": "\"{subtype}\" \u043d\u0430\u0436\u0430\u0442\u0430", + "button_short_release": "\"{subtype}\" \u043e\u0442\u043f\u0443\u0449\u0435\u043d\u0430", + "button_triple_press": "\"{subtype}\" \u043d\u0430\u0436\u0430\u0442\u0430 \u0442\u0440\u0438 \u0440\u0430\u0437\u0430" + } } } \ No newline at end of file diff --git a/homeassistant/components/mqtt/.translations/zh-Hans.json b/homeassistant/components/mqtt/.translations/zh-Hans.json index f30e1bf10b4..c12004236bd 100644 --- a/homeassistant/components/mqtt/.translations/zh-Hans.json +++ b/homeassistant/components/mqtt/.translations/zh-Hans.json @@ -27,5 +27,27 @@ } }, "title": "MQTT" + }, + "device_automation": { + "trigger_subtype": { + "button_1": "\u7b2c\u4e00\u4e2a\u6309\u94ae", + "button_2": "\u7b2c\u4e8c\u4e2a\u6309\u94ae", + "button_3": "\u7b2c\u4e09\u4e2a\u6309\u94ae", + "button_4": "\u7b2c\u56db\u4e2a\u6309\u94ae", + "button_5": "\u7b2c\u4e94\u4e2a\u6309\u94ae", + "button_6": "\u7b2c\u516d\u4e2a\u6309\u94ae", + "turn_off": "\u5173\u95ed", + "turn_on": "\u6253\u5f00" + }, + "trigger_type": { + "button_double_press": "\"{subtype}\" \u53cc\u51fb", + "button_long_press": "\"{subtype}\" \u6301\u7eed\u6309\u4e0b", + "button_long_release": "\"{subtype}\" \u957f\u6309\u540e\u91ca\u653e", + "button_quadruple_press": "\"{subtype}\" \u56db\u8fde\u51fb", + "button_quintuple_press": "\"{subtype}\" \u4e94\u8fde\u51fb", + "button_short_press": "\"{subtype}\" \u6309\u4e0b", + "button_short_release": "\"{subtype}\" \u91ca\u653e", + "button_triple_press": "\"{subtype}\" \u4e09\u8fde\u51fb" + } } } \ No newline at end of file diff --git a/homeassistant/components/mqtt/.translations/zh-Hant.json b/homeassistant/components/mqtt/.translations/zh-Hant.json index 09f2f44a902..3c57e7b6bb0 100644 --- a/homeassistant/components/mqtt/.translations/zh-Hant.json +++ b/homeassistant/components/mqtt/.translations/zh-Hant.json @@ -27,5 +27,27 @@ } }, "title": "MQTT" + }, + "device_automation": { + "trigger_subtype": { + "button_1": "\u7b2c\u4e00\u500b\u6309\u9215", + "button_2": "\u7b2c\u4e8c\u500b\u6309\u9215", + "button_3": "\u7b2c\u4e09\u500b\u6309\u9215", + "button_4": "\u7b2c\u56db\u500b\u6309\u9215", + "button_5": "\u7b2c\u4e94\u500b\u6309\u9215", + "button_6": "\u7b2c\u516d\u500b\u6309\u9215", + "turn_off": "\u95dc\u9589", + "turn_on": "\u958b\u555f" + }, + "trigger_type": { + "button_double_press": "\"{subtype}\" \u96d9\u64ca", + "button_long_press": "\"{subtype}\" \u6301\u7e8c\u6309\u4e0b", + "button_long_release": "\"{subtype}\" \u9577\u6309\u5f8c\u91cb\u653e", + "button_quadruple_press": "\"{subtype}\" \u56db\u9023\u64ca", + "button_quintuple_press": "\"{subtype}\" \u4e94\u9023\u64ca", + "button_short_press": "\"{subtype}\" \u6309\u4e0b", + "button_short_release": "\"{subtype}\" \u91cb\u653e", + "button_triple_press": "\"{subtype}\" \u4e09\u9023\u64ca" + } } } \ No newline at end of file diff --git a/homeassistant/components/nest/.translations/zh-Hans.json b/homeassistant/components/nest/.translations/zh-Hans.json index 0b5cbc989fd..0825fdfdc79 100644 --- a/homeassistant/components/nest/.translations/zh-Hans.json +++ b/homeassistant/components/nest/.translations/zh-Hans.json @@ -8,14 +8,14 @@ }, "error": { "internal_error": "\u9a8c\u8bc1\u4ee3\u7801\u65f6\u53d1\u751f\u5185\u90e8\u9519\u8bef", - "invalid_code": "\u65e0\u6548\u4ee3\u7801", - "timeout": "\u4ee3\u7801\u9a8c\u8bc1\u8d85\u65f6", - "unknown": "\u9a8c\u8bc1\u4ee3\u7801\u65f6\u53d1\u751f\u672a\u77e5\u9519\u8bef" + "invalid_code": "\u9a8c\u8bc1\u7801\u65e0\u6548", + "timeout": "\u9a8c\u8bc1\u7801\u8d85\u65f6", + "unknown": "\u9a8c\u8bc1\u7801\u672a\u77e5\u9519\u8bef" }, "step": { "init": { "data": { - "flow_impl": "\u63d0\u4f9b\u8005" + "flow_impl": "\u8ba4\u8bc1\u63d0\u4f9b\u8005" }, "description": "\u9009\u62e9\u60a8\u60f3\u901a\u8fc7\u54ea\u4e2a\u6388\u6743\u63d0\u4f9b\u8005\u4e0e Nest \u8fdb\u884c\u6388\u6743\u3002", "title": "\u6388\u6743\u63d0\u4f9b\u8005" diff --git a/homeassistant/components/notion/.translations/ca.json b/homeassistant/components/notion/.translations/ca.json index 0b6a24626be..09f598ef5d1 100644 --- a/homeassistant/components/notion/.translations/ca.json +++ b/homeassistant/components/notion/.translations/ca.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "Aquest nom d'usuari ja est\u00e0 en \u00fas." + }, "error": { "identifier_exists": "Nom d'usuari ja registrat", "invalid_credentials": "Nom d'usuari o contrasenya incorrectes", diff --git a/homeassistant/components/notion/.translations/de.json b/homeassistant/components/notion/.translations/de.json index e9c735001e9..e11a16458c9 100644 --- a/homeassistant/components/notion/.translations/de.json +++ b/homeassistant/components/notion/.translations/de.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "Dieser Benutzername wird bereits benutzt." + }, "error": { "identifier_exists": "Benutzername bereits registriert", "invalid_credentials": "Ung\u00fcltiger Benutzername oder Passwort", diff --git a/homeassistant/components/notion/.translations/en.json b/homeassistant/components/notion/.translations/en.json index b05f613a73f..2476293a216 100644 --- a/homeassistant/components/notion/.translations/en.json +++ b/homeassistant/components/notion/.translations/en.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "This username is already in use." + }, "error": { "identifier_exists": "Username already registered", "invalid_credentials": "Invalid username or password", diff --git a/homeassistant/components/notion/.translations/ko.json b/homeassistant/components/notion/.translations/ko.json index 76dc91cf46b..52c7b6339cb 100644 --- a/homeassistant/components/notion/.translations/ko.json +++ b/homeassistant/components/notion/.translations/ko.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "\uc774 \uc0ac\uc6a9\uc790 \uc774\ub984\uc740 \uc774\ubbf8 \uc0ac\uc6a9 \uc911\uc785\ub2c8\ub2e4." + }, "error": { "identifier_exists": "\uc0ac\uc6a9\uc790 \uc774\ub984\uc774 \uc774\ubbf8 \ub4f1\ub85d\ub418\uc5c8\uc2b5\ub2c8\ub2e4", "invalid_credentials": "\uc0ac\uc6a9\uc790 \uc774\ub984 \ub610\ub294 \ube44\ubc00\ubc88\ud638\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4", diff --git a/homeassistant/components/notion/.translations/no.json b/homeassistant/components/notion/.translations/no.json index 2798db1cbc3..16105e680c5 100644 --- a/homeassistant/components/notion/.translations/no.json +++ b/homeassistant/components/notion/.translations/no.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "Dette brukernavnet er allerede i bruk." + }, "error": { "identifier_exists": "Brukernavn er allerede registrert", "invalid_credentials": "Ugyldig brukernavn eller passord", diff --git a/homeassistant/components/notion/.translations/pl.json b/homeassistant/components/notion/.translations/pl.json index ffb3b8386dd..07facb21e93 100644 --- a/homeassistant/components/notion/.translations/pl.json +++ b/homeassistant/components/notion/.translations/pl.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "Ta nazwa u\u017cytkownika jest ju\u017c w u\u017cyciu." + }, "error": { "identifier_exists": "Nazwa u\u017cytkownika jest ju\u017c zarejestrowana.", "invalid_credentials": "Nieprawid\u0142owa nazwa u\u017cytkownika lub has\u0142o", diff --git a/homeassistant/components/notion/.translations/zh-Hant.json b/homeassistant/components/notion/.translations/zh-Hant.json index f672f519f40..c426dfa3265 100644 --- a/homeassistant/components/notion/.translations/zh-Hant.json +++ b/homeassistant/components/notion/.translations/zh-Hant.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "\u6b64\u4f7f\u7528\u8005\u540d\u7a31\u5df2\u88ab\u4f7f\u7528\u3002" + }, "error": { "identifier_exists": "\u4f7f\u7528\u8005\u540d\u7a31\u5df2\u8a3b\u518a", "invalid_credentials": "\u4f7f\u7528\u8005\u540d\u7a31\u6216\u5bc6\u78bc\u7121\u6548", diff --git a/homeassistant/components/plex/.translations/ca.json b/homeassistant/components/plex/.translations/ca.json index 63cf65b8d6c..d562d62b602 100644 --- a/homeassistant/components/plex/.translations/ca.json +++ b/homeassistant/components/plex/.translations/ca.json @@ -53,6 +53,8 @@ "step": { "plex_mp_settings": { "data": { + "ignore_new_shared_users": "Ignora els nous usuaris gestionats/compartits", + "monitored_users": "Usuaris monitoritzats", "show_all_controls": "Mostra tots els controls", "use_episode_art": "Utilitza imatges de l'episodi" }, diff --git a/homeassistant/components/plex/.translations/da.json b/homeassistant/components/plex/.translations/da.json index 18dbbb840c3..9b80373727d 100644 --- a/homeassistant/components/plex/.translations/da.json +++ b/homeassistant/components/plex/.translations/da.json @@ -53,6 +53,8 @@ "step": { "plex_mp_settings": { "data": { + "ignore_new_shared_users": "Ignorer nye administrerede/delte brugere", + "monitored_users": "Monitorerede brugere", "show_all_controls": "Vis alle kontrolelementer", "use_episode_art": "Brug episodekunst" }, diff --git a/homeassistant/components/plex/.translations/de.json b/homeassistant/components/plex/.translations/de.json index aa8c5e08dd6..ea8f4b60de4 100644 --- a/homeassistant/components/plex/.translations/de.json +++ b/homeassistant/components/plex/.translations/de.json @@ -53,6 +53,8 @@ "step": { "plex_mp_settings": { "data": { + "ignore_new_shared_users": "Ignorieren neuer verwalteter/freigegebener Benutzer", + "monitored_users": "\u00dcberwachte Benutzer", "show_all_controls": "Alle Steuerelemente anzeigen", "use_episode_art": "Episode-Bilder verwenden" }, diff --git a/homeassistant/components/plex/.translations/en.json b/homeassistant/components/plex/.translations/en.json index b75589e3a81..4567171af77 100644 --- a/homeassistant/components/plex/.translations/en.json +++ b/homeassistant/components/plex/.translations/en.json @@ -53,6 +53,8 @@ "step": { "plex_mp_settings": { "data": { + "ignore_new_shared_users": "Ignore new managed/shared users", + "monitored_users": "Monitored users", "show_all_controls": "Show all controls", "use_episode_art": "Use episode art" }, diff --git a/homeassistant/components/plex/.translations/es.json b/homeassistant/components/plex/.translations/es.json index 53dd3228288..24127a7332c 100644 --- a/homeassistant/components/plex/.translations/es.json +++ b/homeassistant/components/plex/.translations/es.json @@ -53,6 +53,8 @@ "step": { "plex_mp_settings": { "data": { + "ignore_new_shared_users": "Ignorar nuevos usuarios administrados/compartidos", + "monitored_users": "Usuarios monitorizados", "show_all_controls": "Mostrar todos los controles", "use_episode_art": "Usar el arte de episodios" }, diff --git a/homeassistant/components/plex/.translations/it.json b/homeassistant/components/plex/.translations/it.json index 0cf7b943fd2..e5ff4e01dc0 100644 --- a/homeassistant/components/plex/.translations/it.json +++ b/homeassistant/components/plex/.translations/it.json @@ -53,6 +53,8 @@ "step": { "plex_mp_settings": { "data": { + "ignore_new_shared_users": "Ignora nuovi utenti gestiti/condivisi", + "monitored_users": "Utenti monitorati", "show_all_controls": "Mostra tutti i controlli", "use_episode_art": "Usa la grafica dell'episodio" }, diff --git a/homeassistant/components/plex/.translations/ko.json b/homeassistant/components/plex/.translations/ko.json index cf5a7946b9d..3292fab0a8e 100644 --- a/homeassistant/components/plex/.translations/ko.json +++ b/homeassistant/components/plex/.translations/ko.json @@ -53,6 +53,8 @@ "step": { "plex_mp_settings": { "data": { + "ignore_new_shared_users": "\uc0c8\ub85c\uc6b4 \uad00\ub9ac/\uacf5\uc720 \uc0ac\uc6a9\uc790 \ubb34\uc2dc", + "monitored_users": "\ubaa8\ub2c8\ud130\ub9c1\ub418\ub294 \uc0ac\uc6a9\uc790", "show_all_controls": "\ubaa8\ub4e0 \ucee8\ud2b8\ub864 \ud45c\uc2dc\ud558\uae30", "use_episode_art": "\uc5d0\ud53c\uc18c\ub4dc \uc544\ud2b8 \uc0ac\uc6a9" }, diff --git a/homeassistant/components/plex/.translations/lb.json b/homeassistant/components/plex/.translations/lb.json index c6fcabc40d7..6ed9d372fc1 100644 --- a/homeassistant/components/plex/.translations/lb.json +++ b/homeassistant/components/plex/.translations/lb.json @@ -53,6 +53,8 @@ "step": { "plex_mp_settings": { "data": { + "ignore_new_shared_users": "Nei verwalt / gedeelt Benotzer ignor\u00e9ieren", + "monitored_users": "Iwwerwaachte Benotzer", "show_all_controls": "Weis all Kontrollen", "use_episode_art": "Benotz Biller vun der Episode" }, diff --git a/homeassistant/components/plex/.translations/no.json b/homeassistant/components/plex/.translations/no.json index 7d2b7cf2760..c80ba5f2e06 100644 --- a/homeassistant/components/plex/.translations/no.json +++ b/homeassistant/components/plex/.translations/no.json @@ -53,6 +53,8 @@ "step": { "plex_mp_settings": { "data": { + "ignore_new_shared_users": "Ignorer nye administrerte/delte brukere", + "monitored_users": "Overv\u00e5kede brukere", "show_all_controls": "Vis alle kontroller", "use_episode_art": "Bruk episode bilde" }, diff --git a/homeassistant/components/plex/.translations/pl.json b/homeassistant/components/plex/.translations/pl.json index d9ab9db8bc9..6531b552000 100644 --- a/homeassistant/components/plex/.translations/pl.json +++ b/homeassistant/components/plex/.translations/pl.json @@ -53,6 +53,8 @@ "step": { "plex_mp_settings": { "data": { + "ignore_new_shared_users": "Ignoruj nowych zarz\u0105dzanych/wsp\u00f3\u0142dzielonych u\u017cytkownik\u00f3w", + "monitored_users": "Monitorowani u\u017cytkownicy", "show_all_controls": "Poka\u017c wszystkie elementy steruj\u0105ce", "use_episode_art": "U\u017cyj grafiki odcinka" }, diff --git a/homeassistant/components/plex/.translations/ru.json b/homeassistant/components/plex/.translations/ru.json index 334a4e353d4..2da10b1e8c4 100644 --- a/homeassistant/components/plex/.translations/ru.json +++ b/homeassistant/components/plex/.translations/ru.json @@ -53,6 +53,8 @@ "step": { "plex_mp_settings": { "data": { + "ignore_new_shared_users": "\u0418\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0445 \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c\u044b\u0445/\u043e\u0431\u0449\u0438\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439", + "monitored_users": "\u041e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0435\u043c\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438", "show_all_controls": "\u041f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0442\u044c \u0432\u0441\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f", "use_episode_art": "\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u043b\u043e\u0436\u043a\u0438 \u044d\u043f\u0438\u0437\u043e\u0434\u043e\u0432" }, diff --git a/homeassistant/components/plex/.translations/zh-Hans.json b/homeassistant/components/plex/.translations/zh-Hans.json new file mode 100644 index 00000000000..614f83e3cc0 --- /dev/null +++ b/homeassistant/components/plex/.translations/zh-Hans.json @@ -0,0 +1,12 @@ +{ + "options": { + "step": { + "plex_mp_settings": { + "data": { + "ignore_new_shared_users": "\u5ffd\u7565\u65b0\u589e\u7ba1\u7406/\u5171\u4eab\u4f7f\u7528\u8005", + "monitored_users": "\u53d7\u76d1\u89c6\u7684\u7528\u6237" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/plex/.translations/zh-Hant.json b/homeassistant/components/plex/.translations/zh-Hant.json index 5c05d2104f9..436333b0a79 100644 --- a/homeassistant/components/plex/.translations/zh-Hant.json +++ b/homeassistant/components/plex/.translations/zh-Hant.json @@ -53,6 +53,8 @@ "step": { "plex_mp_settings": { "data": { + "ignore_new_shared_users": "\u5ffd\u7565\u65b0\u589e\u7ba1\u7406/\u5206\u4eab\u4f7f\u7528\u8005", + "monitored_users": "\u5df2\u76e3\u63a7\u4f7f\u7528\u8005", "show_all_controls": "\u986f\u793a\u6240\u6709\u63a7\u5236", "use_episode_art": "\u4f7f\u7528\u5f71\u96c6\u5287\u7167" }, diff --git a/homeassistant/components/rainmachine/.translations/ca.json b/homeassistant/components/rainmachine/.translations/ca.json index 60458f1469e..494b1ecc69c 100644 --- a/homeassistant/components/rainmachine/.translations/ca.json +++ b/homeassistant/components/rainmachine/.translations/ca.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "Aquest controlador RainMachine ja est\u00e0 configurat." + }, "error": { "identifier_exists": "Aquest compte ja est\u00e0 registrat", "invalid_credentials": "Credencials inv\u00e0lides" diff --git a/homeassistant/components/rainmachine/.translations/da.json b/homeassistant/components/rainmachine/.translations/da.json index 34f4fff4ed0..fe53a86993d 100644 --- a/homeassistant/components/rainmachine/.translations/da.json +++ b/homeassistant/components/rainmachine/.translations/da.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "Denne RainMachine-controller er allerede konfigureret." + }, "error": { "identifier_exists": "Konto er allerede registreret", "invalid_credentials": "Ugyldige legitimationsoplysninger" diff --git a/homeassistant/components/rainmachine/.translations/de.json b/homeassistant/components/rainmachine/.translations/de.json index c262fa5a652..257a0908c6a 100644 --- a/homeassistant/components/rainmachine/.translations/de.json +++ b/homeassistant/components/rainmachine/.translations/de.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "Dieser RainMachine-Kontroller ist bereits konfiguriert." + }, "error": { "identifier_exists": "Konto bereits registriert", "invalid_credentials": "Ung\u00fcltige Anmeldeinformationen" diff --git a/homeassistant/components/rainmachine/.translations/en.json b/homeassistant/components/rainmachine/.translations/en.json index 54b67066f2b..4ad5bfd7c0d 100644 --- a/homeassistant/components/rainmachine/.translations/en.json +++ b/homeassistant/components/rainmachine/.translations/en.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "This RainMachine controller is already configured." + }, "error": { "identifier_exists": "Account already registered", "invalid_credentials": "Invalid credentials" diff --git a/homeassistant/components/rainmachine/.translations/ko.json b/homeassistant/components/rainmachine/.translations/ko.json index 4e2df2ca217..66d6cb0b740 100644 --- a/homeassistant/components/rainmachine/.translations/ko.json +++ b/homeassistant/components/rainmachine/.translations/ko.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "\uc774 RainMachine \ucee8\ud2b8\ub864\ub7ec\ub294 \uc774\ubbf8 \uad6c\uc131\ub418\uc5c8\uc2b5\ub2c8\ub2e4." + }, "error": { "identifier_exists": "\uacc4\uc815\uc774 \uc774\ubbf8 \ub4f1\ub85d\ub418\uc5c8\uc2b5\ub2c8\ub2e4", "invalid_credentials": "\ube44\ubc00\ubc88\ud638\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4" diff --git a/homeassistant/components/rainmachine/.translations/no.json b/homeassistant/components/rainmachine/.translations/no.json index 5ec4e5fdc34..980c2c693ce 100644 --- a/homeassistant/components/rainmachine/.translations/no.json +++ b/homeassistant/components/rainmachine/.translations/no.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "Denne RainMachine-kontrolleren er allerede konfigurert." + }, "error": { "identifier_exists": "Konto er allerede registrert", "invalid_credentials": "Ugyldig legitimasjon" diff --git a/homeassistant/components/rainmachine/.translations/pl.json b/homeassistant/components/rainmachine/.translations/pl.json index d5b853122a6..5e813243f13 100644 --- a/homeassistant/components/rainmachine/.translations/pl.json +++ b/homeassistant/components/rainmachine/.translations/pl.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "Ten kontroler RainMachine jest ju\u017c skonfigurowany." + }, "error": { "identifier_exists": "Konto jest ju\u017c zarejestrowane.", "invalid_credentials": "Nieprawid\u0142owe dane uwierzytelniaj\u0105ce" diff --git a/homeassistant/components/rainmachine/.translations/ru.json b/homeassistant/components/rainmachine/.translations/ru.json index ca535663f54..e1bce5874e3 100644 --- a/homeassistant/components/rainmachine/.translations/ru.json +++ b/homeassistant/components/rainmachine/.translations/ru.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430." + }, "error": { "identifier_exists": "\u0423\u0447\u0451\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0443\u0436\u0435 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0430.", "invalid_credentials": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0435 \u0443\u0447\u0451\u0442\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435." diff --git a/homeassistant/components/rainmachine/.translations/zh-Hant.json b/homeassistant/components/rainmachine/.translations/zh-Hant.json index 518cc54192f..3d9663a9a79 100644 --- a/homeassistant/components/rainmachine/.translations/zh-Hant.json +++ b/homeassistant/components/rainmachine/.translations/zh-Hant.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "\u6b64 RainMachine \u63a7\u5236\u5668\u5df2\u7d93\u8a2d\u5b9a\u5b8c\u6210\u3002" + }, "error": { "identifier_exists": "\u5e33\u865f\u5df2\u8a3b\u518a", "invalid_credentials": "\u6191\u8b49\u7121\u6548" diff --git a/homeassistant/components/simplisafe/.translations/ca.json b/homeassistant/components/simplisafe/.translations/ca.json index a02c3a5e28e..a89e4c753cb 100644 --- a/homeassistant/components/simplisafe/.translations/ca.json +++ b/homeassistant/components/simplisafe/.translations/ca.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "Aquest compte SimpliSafe ja est\u00e0 en \u00fas." + }, "error": { "identifier_exists": "Aquest compte ja est\u00e0 registrat", "invalid_credentials": "Credencials inv\u00e0lides" diff --git a/homeassistant/components/simplisafe/.translations/da.json b/homeassistant/components/simplisafe/.translations/da.json index 0d3970eeba5..ccd82979520 100644 --- a/homeassistant/components/simplisafe/.translations/da.json +++ b/homeassistant/components/simplisafe/.translations/da.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "Denne SimpliSafe-konto er allerede i brug." + }, "error": { "identifier_exists": "Konto er allerede registreret", "invalid_credentials": "Ugyldige legitimationsoplysninger" diff --git a/homeassistant/components/simplisafe/.translations/de.json b/homeassistant/components/simplisafe/.translations/de.json index 5ebc17f13b9..4d5eefc480b 100644 --- a/homeassistant/components/simplisafe/.translations/de.json +++ b/homeassistant/components/simplisafe/.translations/de.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "Dieses SimpliSafe-Konto wird bereits verwendet." + }, "error": { "identifier_exists": "Konto bereits registriert", "invalid_credentials": "Ung\u00fcltige Anmeldeinformationen" diff --git a/homeassistant/components/simplisafe/.translations/en.json b/homeassistant/components/simplisafe/.translations/en.json index b000335af8f..7e9c26291f7 100644 --- a/homeassistant/components/simplisafe/.translations/en.json +++ b/homeassistant/components/simplisafe/.translations/en.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "This SimpliSafe account is already in use." + }, "error": { "identifier_exists": "Account already registered", "invalid_credentials": "Invalid credentials" diff --git a/homeassistant/components/simplisafe/.translations/ko.json b/homeassistant/components/simplisafe/.translations/ko.json index 5cbe233a05e..3327ddf9ab1 100644 --- a/homeassistant/components/simplisafe/.translations/ko.json +++ b/homeassistant/components/simplisafe/.translations/ko.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "\uc774 SimpliSafe \uacc4\uc815\uc740 \uc774\ubbf8 \uc0ac\uc6a9 \uc911\uc785\ub2c8\ub2e4." + }, "error": { "identifier_exists": "\uacc4\uc815\uc774 \uc774\ubbf8 \ub4f1\ub85d\ub418\uc5c8\uc2b5\ub2c8\ub2e4", "invalid_credentials": "\ube44\ubc00\ubc88\ud638\uac00 \uc798\ubabb\ub418\uc5c8\uc2b5\ub2c8\ub2e4" diff --git a/homeassistant/components/simplisafe/.translations/no.json b/homeassistant/components/simplisafe/.translations/no.json index 7c28209514e..4c25893791b 100644 --- a/homeassistant/components/simplisafe/.translations/no.json +++ b/homeassistant/components/simplisafe/.translations/no.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "Denne SimpliSafe-kontoen er allerede i bruk." + }, "error": { "identifier_exists": "Konto er allerede registrert", "invalid_credentials": "Ugyldig legitimasjon" diff --git a/homeassistant/components/simplisafe/.translations/pl.json b/homeassistant/components/simplisafe/.translations/pl.json index 71316eb1a6c..3a9c160a0c5 100644 --- a/homeassistant/components/simplisafe/.translations/pl.json +++ b/homeassistant/components/simplisafe/.translations/pl.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "To konto SimpliSafe jest ju\u017c w u\u017cyciu." + }, "error": { "identifier_exists": "Konto jest ju\u017c zarejestrowane.", "invalid_credentials": "Nieprawid\u0142owe dane uwierzytelniaj\u0105ce" diff --git a/homeassistant/components/simplisafe/.translations/ru.json b/homeassistant/components/simplisafe/.translations/ru.json index 301eed6d1c1..2d8b63c4bab 100644 --- a/homeassistant/components/simplisafe/.translations/ru.json +++ b/homeassistant/components/simplisafe/.translations/ru.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "\u0423\u0447\u0451\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0443\u0436\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0430." + }, "error": { "identifier_exists": "\u0423\u0447\u0435\u0442\u043d\u0430\u044f \u0437\u0430\u043f\u0438\u0441\u044c \u0443\u0436\u0435 \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0430.", "invalid_credentials": "\u041d\u0435\u0432\u0435\u0440\u043d\u044b\u0435 \u0443\u0447\u0451\u0442\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435." diff --git a/homeassistant/components/simplisafe/.translations/zh-Hant.json b/homeassistant/components/simplisafe/.translations/zh-Hant.json index bd0b2c6f3d6..b456bde33c7 100644 --- a/homeassistant/components/simplisafe/.translations/zh-Hant.json +++ b/homeassistant/components/simplisafe/.translations/zh-Hant.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_configured": "\u6b64 SimpliSafe \u5e33\u865f\u5df2\u88ab\u4f7f\u7528\u3002" + }, "error": { "identifier_exists": "\u5e33\u865f\u5df2\u8a3b\u518a", "invalid_credentials": "\u6191\u8b49\u7121\u6548" diff --git a/homeassistant/components/solarlog/.translations/ru.json b/homeassistant/components/solarlog/.translations/ru.json index b64496c4591..3333d5c0d5f 100644 --- a/homeassistant/components/solarlog/.translations/ru.json +++ b/homeassistant/components/solarlog/.translations/ru.json @@ -11,7 +11,7 @@ "user": { "data": { "host": "\u0414\u043e\u043c\u0435\u043d\u043d\u043e\u0435 \u0438\u043c\u044f \u0438\u043b\u0438 IP-\u0430\u0434\u0440\u0435\u0441", - "name": "\u041f\u0440\u0435\u0444\u0438\u043a\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0434\u0430\u0442\u0447\u0438\u043a\u043e\u0432 Solar-Log" + "name": "\u041f\u0440\u0435\u0444\u0438\u043a\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u0441\u0435\u043d\u0441\u043e\u0440\u043e\u0432 Solar-Log" }, "title": "Solar-Log" } diff --git a/homeassistant/components/sonos/.translations/zh-Hans.json b/homeassistant/components/sonos/.translations/zh-Hans.json index 17c1e78d3e8..de2609f4a71 100644 --- a/homeassistant/components/sonos/.translations/zh-Hans.json +++ b/homeassistant/components/sonos/.translations/zh-Hans.json @@ -2,7 +2,7 @@ "config": { "abort": { "no_devices_found": "\u6ca1\u6709\u5728\u7f51\u7edc\u4e0a\u627e\u5230 Sonos \u8bbe\u5907\u3002", - "single_instance_allowed": "\u53ea\u6709\u4e00\u6b21 Sonos \u914d\u7f6e\u662f\u5fc5\u8981\u7684\u3002" + "single_instance_allowed": "\u53ea\u9700\u8bbe\u7f6e\u4e00\u6b21 Sonos \u5373\u53ef\u3002" }, "step": { "confirm": { diff --git a/homeassistant/components/unifi/.translations/ca.json b/homeassistant/components/unifi/.translations/ca.json index 899b532290e..89d299a2857 100644 --- a/homeassistant/components/unifi/.translations/ca.json +++ b/homeassistant/components/unifi/.translations/ca.json @@ -28,10 +28,13 @@ "device_tracker": { "data": { "detection_time": "Temps (en segons) des de s'ha vist per \u00faltima vegada fins que es considera a fora", + "ssid_filter": "Selecciona els SSID's on fer-hi el seguiment de clients", "track_clients": "Segueix clients de la xarxa", "track_devices": "Segueix dispositius de la xarxa (dispositius Ubiquiti)", "track_wired_clients": "Inclou clients de xarxa per cable" - } + }, + "description": "Configuraci\u00f3 de seguiment de dispositius", + "title": "Opcions d'UniFi" }, "init": { "data": { @@ -42,7 +45,9 @@ "statistics_sensors": { "data": { "allow_bandwidth_sensors": "Crea sensors d'\u00fas d'ample de banda per a clients de la xarxa" - } + }, + "description": "Configuraci\u00f3 dels sensors d\u2019estad\u00edstiques", + "title": "Opcions d'UniFi" } } } diff --git a/homeassistant/components/unifi/.translations/da.json b/homeassistant/components/unifi/.translations/da.json index 46a94cc4047..1afd1ca96ce 100644 --- a/homeassistant/components/unifi/.translations/da.json +++ b/homeassistant/components/unifi/.translations/da.json @@ -28,10 +28,13 @@ "device_tracker": { "data": { "detection_time": "Tid i sekunder fra sidst set indtil betragtet som v\u00e6k", + "ssid_filter": "V\u00e6lg SSIDer, der skal spores tr\u00e5dl\u00f8se klienter p\u00e5", "track_clients": "Spor netv\u00e6rksklienter", "track_devices": "Spor netv\u00e6rksenheder (Ubiquiti-enheder)", "track_wired_clients": "Inkluder kablede netv\u00e6rksklienter" - } + }, + "description": "Konfigurer enhedssporing", + "title": "UniFi-indstillinger" }, "init": { "data": { @@ -41,8 +44,10 @@ }, "statistics_sensors": { "data": { - "allow_bandwidth_sensors": "Opret b\u00e5ndbredde-forbrugssensorer for netv\u00e6rksklienter" - } + "allow_bandwidth_sensors": "B\u00e5ndbreddeforbrugssensorer for netv\u00e6rksklienter" + }, + "description": "Konfigurer statistiksensorer", + "title": "UniFi-indstillinger" } } } diff --git a/homeassistant/components/unifi/.translations/de.json b/homeassistant/components/unifi/.translations/de.json index 32a378b7c00..2f3db9d9b89 100644 --- a/homeassistant/components/unifi/.translations/de.json +++ b/homeassistant/components/unifi/.translations/de.json @@ -28,10 +28,13 @@ "device_tracker": { "data": { "detection_time": "Zeit in Sekunden vom letzten Gesehenen bis zur Entfernung", + "ssid_filter": "W\u00e4hlen Sie SSIDs zur Verfolgung von drahtlosen Clients aus", "track_clients": "Nachverfolgen von Netzwerkclients", "track_devices": "Verfolgen von Netzwerkger\u00e4ten (Ubiquiti-Ger\u00e4te)", "track_wired_clients": "Einbinden von kabelgebundenen Netzwerk-Clients" - } + }, + "description": "Konfigurieren Sie die Ger\u00e4teverfolgung", + "title": "UniFi-Optionen" }, "init": { "data": { @@ -42,7 +45,9 @@ "statistics_sensors": { "data": { "allow_bandwidth_sensors": "Erstellen von Bandbreiten-Nutzungssensoren f\u00fcr Netzwerk-Clients" - } + }, + "description": "Konfigurieren Sie Statistiksensoren", + "title": "UniFi-Optionen" } } } diff --git a/homeassistant/components/unifi/.translations/es.json b/homeassistant/components/unifi/.translations/es.json index 677899c0958..6c5e9d677c2 100644 --- a/homeassistant/components/unifi/.translations/es.json +++ b/homeassistant/components/unifi/.translations/es.json @@ -28,10 +28,13 @@ "device_tracker": { "data": { "detection_time": "Tiempo en segundos desde la \u00faltima vez que se vio hasta considerarlo desconectado", + "ssid_filter": "Seleccione los SSIDs para realizar seguimiento de clientes inal\u00e1mbricos", "track_clients": "Seguimiento de los clientes de red", "track_devices": "Rastree dispositivos de red (dispositivos Ubiquiti)", "track_wired_clients": "Incluir clientes de red cableada" - } + }, + "description": "Configurar dispositivo de seguimiento", + "title": "Opciones UniFi" }, "init": { "data": { @@ -42,7 +45,9 @@ "statistics_sensors": { "data": { "allow_bandwidth_sensors": "Crear sensores para monitorizar uso de ancho de banda de clientes de red" - } + }, + "description": "Configurar estad\u00edsticas de los sensores", + "title": "Opciones UniFi" } } } diff --git a/homeassistant/components/unifi/.translations/it.json b/homeassistant/components/unifi/.translations/it.json index 80b546ebcf8..c1aa9afe54f 100644 --- a/homeassistant/components/unifi/.translations/it.json +++ b/homeassistant/components/unifi/.translations/it.json @@ -28,10 +28,13 @@ "device_tracker": { "data": { "detection_time": "Tempo in secondi dall'ultima volta che viene visto fino a quando non \u00e8 considerato lontano", + "ssid_filter": "Selezionare gli SSID su cui tracciare i client wireless", "track_clients": "Traccia i client di rete", "track_devices": "Tracciare i dispositivi di rete (dispositivi Ubiquiti)", "track_wired_clients": "Includi i client di rete cablata" - } + }, + "description": "Configurare il tracciamento del dispositivo", + "title": "Opzioni UniFi" }, "init": { "data": { @@ -41,8 +44,10 @@ }, "statistics_sensors": { "data": { - "allow_bandwidth_sensors": "Creare sensori di utilizzo della larghezza di banda per i client di rete" - } + "allow_bandwidth_sensors": "Sensori di utilizzo della larghezza di banda per i client di rete" + }, + "description": "Configurare i sensori delle statistiche", + "title": "Opzioni UniFi" } } } diff --git a/homeassistant/components/unifi/.translations/ko.json b/homeassistant/components/unifi/.translations/ko.json index 295430b7284..dbcd4d7feee 100644 --- a/homeassistant/components/unifi/.translations/ko.json +++ b/homeassistant/components/unifi/.translations/ko.json @@ -28,15 +28,20 @@ "device_tracker": { "data": { "detection_time": "\ub9c8\uc9c0\ub9c9\uc73c\ub85c \ud655\uc778\ub41c \uc2dc\uac04\ubd80\ud130 \uc678\ucd9c \uc0c1\ud0dc\ub85c \uac04\uc8fc\ub418\ub294 \uc2dc\uac04 (\ucd08)", + "ssid_filter": "\ubb34\uc120 \ud074\ub77c\uc774\uc5b8\ud2b8\ub97c \ucd94\uc801\ud558\ub824\uba74 SSID\ub97c \uc120\ud0dd\ud574\uc8fc\uc138\uc694", "track_clients": "\ub124\ud2b8\uc6cc\ud06c \ud074\ub77c\uc774\uc5b8\ud2b8 \ucd94\uc801 \ub300\uc0c1", "track_devices": "\ub124\ud2b8\uc6cc\ud06c \uae30\uae30 \ucd94\uc801 (Ubiquiti \uae30\uae30)", "track_wired_clients": "\uc720\uc120 \ub124\ud2b8\uc6cc\ud06c \ud074\ub77c\uc774\uc5b8\ud2b8 \ud3ec\ud568" - } + }, + "description": "\uc7a5\uce58 \ucd94\uc801 \uad6c\uc131", + "title": "UniFi \uc635\uc158" }, "statistics_sensors": { "data": { - "allow_bandwidth_sensors": "\ub124\ud2b8\uc6cc\ud06c \ud074\ub77c\uc774\uc5b8\ud2b8\ub97c \uc704\ud55c \ub300\uc5ed\ud3ed \uc0ac\uc6a9\ub7c9 \uc13c\uc11c \uc0dd\uc131\ud558\uae30" - } + "allow_bandwidth_sensors": "\ub124\ud2b8\uc6cc\ud06c \ud074\ub77c\uc774\uc5b8\ud2b8 \ub300\uc5ed\ud3ed \uc0ac\uc6a9\ub7c9 \uc13c\uc11c" + }, + "description": "\ud1b5\uacc4 \uc13c\uc11c \uad6c\uc131", + "title": "UniFi \uc635\uc158" } } } diff --git a/homeassistant/components/unifi/.translations/lb.json b/homeassistant/components/unifi/.translations/lb.json index 4fa1f62c602..9707432540d 100644 --- a/homeassistant/components/unifi/.translations/lb.json +++ b/homeassistant/components/unifi/.translations/lb.json @@ -31,7 +31,8 @@ "track_clients": "Netzwierk Cliente verfollegen", "track_devices": "Netzwierk Apparater (Ubiquiti Apparater) verfollegen", "track_wired_clients": "Kabel Netzwierk Cliente abez\u00e9ien" - } + }, + "title": "UniFi Optiounen" }, "init": { "data": { @@ -42,7 +43,9 @@ "statistics_sensors": { "data": { "allow_bandwidth_sensors": "Bandbreet Benotzung Sensore fir Netzwierk Cliente erstellen" - } + }, + "description": "Statistik Sensoren konfigur\u00e9ieren", + "title": "UniFi Optiounen" } } } diff --git a/homeassistant/components/unifi/.translations/no.json b/homeassistant/components/unifi/.translations/no.json index 3448c291325..65730c7ab8b 100644 --- a/homeassistant/components/unifi/.translations/no.json +++ b/homeassistant/components/unifi/.translations/no.json @@ -28,15 +28,20 @@ "device_tracker": { "data": { "detection_time": "Tid i sekunder fra sist sett til den ble ansett borte", + "ssid_filter": "Velg SSID-er for \u00e5 spore tr\u00e5dl\u00f8se klienter p\u00e5", "track_clients": "Spor nettverksklienter", "track_devices": "Spore nettverksenheter (Ubiquiti-enheter)", "track_wired_clients": "Inkluder kablede nettverksklienter" - } + }, + "description": "Konfigurere enhetssporing", + "title": "UniFi-alternativer" }, "statistics_sensors": { "data": { - "allow_bandwidth_sensors": "Opprett b\u00e5ndbreddesensorer for nettverksklienter" - } + "allow_bandwidth_sensors": "B\u00e5ndbreddebrukssensorer for nettverksklienter" + }, + "description": "Konfigurer statistikk sensorer", + "title": "UniFi-alternativer" } } } diff --git a/homeassistant/components/unifi/.translations/pl.json b/homeassistant/components/unifi/.translations/pl.json index 9c71279c444..e016fbc7cce 100644 --- a/homeassistant/components/unifi/.translations/pl.json +++ b/homeassistant/components/unifi/.translations/pl.json @@ -28,10 +28,13 @@ "device_tracker": { "data": { "detection_time": "Czas w sekundach od momentu, kiedy ostatnio widziano, a\u017c do momentu, kiedy uznano go za nieobecny.", + "ssid_filter": "Wybierz SSIDy do \u015bledzenia klient\u00f3w bezprzewodowych", "track_clients": "\u015aled\u017a klient\u00f3w sieciowych", "track_devices": "\u015aled\u017a urz\u0105dzenia sieciowe (urz\u0105dzenia Ubiquiti)", "track_wired_clients": "Uwzgl\u0119dnij klient\u00f3w sieci przewodowej" - } + }, + "description": "Konfiguracja \u015bledzenia urz\u0105dze\u0144", + "title": "Opcje UniFi" }, "init": { "data": { @@ -44,7 +47,9 @@ "statistics_sensors": { "data": { "allow_bandwidth_sensors": "Stw\u00f3rz sensory wykorzystania przepustowo\u015bci przez klient\u00f3w sieciowych" - } + }, + "description": "Konfiguracja sensora statystyk", + "title": "Opcje UniFi" } } } diff --git a/homeassistant/components/unifi/.translations/ru.json b/homeassistant/components/unifi/.translations/ru.json index 3a67d483c0c..0080474cf64 100644 --- a/homeassistant/components/unifi/.translations/ru.json +++ b/homeassistant/components/unifi/.translations/ru.json @@ -28,10 +28,13 @@ "device_tracker": { "data": { "detection_time": "\u0412\u0440\u0435\u043c\u044f \u043e\u0442 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u0441\u0435\u0430\u043d\u0441\u0430 \u0441\u0432\u044f\u0437\u0438 \u0441 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e\u043c (\u0441\u0435\u043a.), \u043f\u043e \u0438\u0441\u0442\u0435\u0447\u0435\u043d\u0438\u044e \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442 \u0441\u0442\u0430\u0442\u0443\u0441 \"\u041d\u0435 \u0434\u043e\u043c\u0430\".", + "ssid_filter": "\u0412\u044b\u0431\u0435\u0440\u0438\u0442\u0435 SSID \u0434\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u0431\u0435\u0441\u043f\u0440\u043e\u0432\u043e\u0434\u043d\u044b\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432", "track_clients": "\u041e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u0435 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u0441\u0435\u0442\u0438", "track_devices": "\u041e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u0435 \u0441\u0435\u0442\u0435\u0432\u044b\u0445 \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432 (\u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 Ubiquiti)", "track_wired_clients": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432 \u043f\u0440\u043e\u0432\u043e\u0434\u043d\u043e\u0439 \u0441\u0435\u0442\u0438" - } + }, + "description": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432", + "title": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 UniFi" }, "init": { "data": { @@ -43,8 +46,10 @@ }, "statistics_sensors": { "data": { - "allow_bandwidth_sensors": "\u0421\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0434\u0430\u0442\u0447\u0438\u043a\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u043e\u043b\u043e\u0441\u044b \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u043d\u0438\u044f \u0434\u043b\u044f \u0441\u0435\u0442\u0435\u0432\u044b\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432" - } + "allow_bandwidth_sensors": "\u0421\u0435\u043d\u0441\u043e\u0440\u044b \u043f\u043e\u043b\u043e\u0441\u044b \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u043d\u0438\u044f \u0434\u043b\u044f \u0441\u0435\u0442\u0435\u0432\u044b\u0445 \u043a\u043b\u0438\u0435\u043d\u0442\u043e\u0432" + }, + "description": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u0441\u0435\u043d\u0441\u043e\u0440\u043e\u0432 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0438", + "title": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 UniFi" } } } diff --git a/homeassistant/components/unifi/.translations/zh-Hans.json b/homeassistant/components/unifi/.translations/zh-Hans.json index 2bc6bda37e4..ebed653732f 100644 --- a/homeassistant/components/unifi/.translations/zh-Hans.json +++ b/homeassistant/components/unifi/.translations/zh-Hans.json @@ -28,10 +28,17 @@ "device_tracker": { "data": { "detection_time": "\u8ddd\u79bb\u4e0a\u6b21\u53d1\u73b0\u591a\u5c11\u79d2\u540e\u8ba4\u4e3a\u79bb\u5f00", + "ssid_filter": "\u9009\u62e9\u6240\u8981\u8ffd\u8e2a\u7684\u65e0\u7ebf\u7f51\u7edcSSID", "track_clients": "\u8ddf\u8e2a\u7f51\u7edc\u5ba2\u6237\u7aef", "track_devices": "\u8ddf\u8e2a\u7f51\u7edc\u8bbe\u5907\uff08Ubiquiti \u8bbe\u5907\uff09", "track_wired_clients": "\u5305\u62ec\u6709\u7ebf\u7f51\u7edc\u5ba2\u6237\u7aef" - } + }, + "description": "\u914d\u7f6e\u8bbe\u5907\u8ddf\u8e2a", + "title": "UniFi \u9009\u9879" + }, + "statistics_sensors": { + "description": "\u914d\u7f6e\u7edf\u8ba1\u4f20\u611f\u5668", + "title": "UniFi \u9009\u9879" } } } diff --git a/homeassistant/components/unifi/.translations/zh-Hant.json b/homeassistant/components/unifi/.translations/zh-Hant.json index 5e0b881af15..cce150a6765 100644 --- a/homeassistant/components/unifi/.translations/zh-Hant.json +++ b/homeassistant/components/unifi/.translations/zh-Hant.json @@ -28,15 +28,20 @@ "device_tracker": { "data": { "detection_time": "\u6700\u7d42\u51fa\u73fe\u5f8c\u8996\u70ba\u96e2\u958b\u7684\u6642\u9593\uff08\u4ee5\u79d2\u70ba\u55ae\u4f4d\uff09", + "ssid_filter": "\u9078\u64c7\u6240\u8981\u8ffd\u8e64\u7684\u7121\u7dda\u7db2\u8def", "track_clients": "\u8ffd\u8e64\u7db2\u8def\u5ba2\u6236\u7aef", "track_devices": "\u8ffd\u8e64\u7db2\u8def\u8a2d\u5099\uff08Ubiquiti \u8a2d\u5099\uff09", "track_wired_clients": "\u5305\u542b\u6709\u7dda\u7db2\u8def\u5ba2\u6236\u7aef" - } + }, + "description": "\u8a2d\u5b9a\u8a2d\u5099\u8ffd\u8e64", + "title": "UniFi \u9078\u9805" }, "statistics_sensors": { "data": { - "allow_bandwidth_sensors": "\u65b0\u589e\u7db2\u8def\u5ba2\u6236\u7aef\u983b\u5bec\u7528\u91cf\u611f\u61c9\u5668" - } + "allow_bandwidth_sensors": "\u7db2\u8def\u5ba2\u6236\u7aef\u983b\u5bec\u7528\u91cf\u611f\u61c9\u5668" + }, + "description": "\u8a2d\u5b9a\u7d71\u8a08\u6578\u64da\u611f\u61c9\u5668", + "title": "UniFi \u9078\u9805" } } } diff --git a/homeassistant/components/upnp/.translations/ru.json b/homeassistant/components/upnp/.translations/ru.json index 6dce1b3d76c..b0a7b7e7b65 100644 --- a/homeassistant/components/upnp/.translations/ru.json +++ b/homeassistant/components/upnp/.translations/ru.json @@ -5,7 +5,7 @@ "incomplete_device": "\u0418\u0433\u043d\u043e\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043d\u0435\u043f\u043e\u043b\u043d\u043e\u0433\u043e \u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 UPnP.", "no_devices_discovered": "\u041d\u0435 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0435\u043d\u043e UPnP / IGD.", "no_devices_found": "\u0423\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0430 UPnP / IGD \u043d\u0435 \u043d\u0430\u0439\u0434\u0435\u043d\u044b \u0432 \u0441\u0435\u0442\u0438.", - "no_sensors_or_port_mapping": "\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0434\u0430\u0442\u0447\u0438\u043a\u0438 \u0438\u043b\u0438 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u043e\u0440\u0442\u043e\u0432.", + "no_sensors_or_port_mapping": "\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0439\u0442\u0435 \u0441\u0435\u043d\u0441\u043e\u0440\u044b \u0438\u043b\u0438 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u043e\u0440\u0442\u043e\u0432.", "single_instance_allowed": "\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430 \u0443\u0436\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430." }, "error": { @@ -25,7 +25,7 @@ "user": { "data": { "enable_port_mapping": "\u0412\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u043e\u0440\u0442\u043e\u0432 \u0434\u043b\u044f Home Assistant", - "enable_sensors": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0434\u0430\u0442\u0447\u0438\u043a\u0438 \u0441\u0435\u0442\u0435\u0432\u043e\u0433\u043e \u0442\u0440\u0430\u0444\u0438\u043a\u0430", + "enable_sensors": "\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0435\u043d\u0441\u043e\u0440\u044b \u0441\u0435\u0442\u0435\u0432\u043e\u0433\u043e \u0442\u0440\u0430\u0444\u0438\u043a\u0430", "igd": "UPnP / IGD" }, "title": "UPnP / IGD" diff --git a/homeassistant/components/vilfo/.translations/da.json b/homeassistant/components/vilfo/.translations/da.json new file mode 100644 index 00000000000..f233b4cb7b9 --- /dev/null +++ b/homeassistant/components/vilfo/.translations/da.json @@ -0,0 +1,23 @@ +{ + "config": { + "abort": { + "already_configured": "Denne Vilfo-router er allerede konfigureret." + }, + "error": { + "cannot_connect": "Forbindelsen kunne ikke oprettes. Tjek de oplysninger, du har angivet, og pr\u00f8v igen.", + "invalid_auth": "Ugyldig godkendelse. Kontroller adgangstoken og pr\u00f8v igen.", + "unknown": "Der opstod en uventet fejl under konfiguration af integrationen." + }, + "step": { + "user": { + "data": { + "access_token": "Adgangstoken til Vilfo-router-API", + "host": "Router-v\u00e6rtsnavn eller IP" + }, + "description": "Indstil Vilfo-routerintegration. Du har brug for dit Vilfo-routerv\u00e6rtsnavn/IP og et API-adgangstoken. For yderligere information om denne integration og hvordan du f\u00e5r disse detaljer, kan du bes\u00f8ge: https://www.home-assistant.io/integrations/vilfo", + "title": "Opret forbindelse til Vilfo-router" + } + }, + "title": "Vilfo-router" + } +} \ No newline at end of file diff --git a/homeassistant/components/vilfo/.translations/es.json b/homeassistant/components/vilfo/.translations/es.json index abf331a955a..170faa197da 100644 --- a/homeassistant/components/vilfo/.translations/es.json +++ b/homeassistant/components/vilfo/.translations/es.json @@ -11,13 +11,13 @@ "step": { "user": { "data": { - "access_token": "Token de acceso para la API de Vilfo Router", + "access_token": "Token de acceso para la API del Router Vilfo", "host": "Nombre de host o IP del router" }, - "description": "Configure la integraci\u00f3n de Vilfo Router. Necesita su nombre de host/IP de Vilfo Router y un token de acceso a la API. Para obtener informaci\u00f3n adicional sobre esta integraci\u00f3n y c\u00f3mo obtener esos detalles, visite: https://www.home-assistant.io/integrations/vilfo", + "description": "Configure la integraci\u00f3n del Router Vilfo. Necesita su nombre de host/IP del Router Vilfo y un token de acceso a la API. Para obtener informaci\u00f3n adicional sobre esta integraci\u00f3n y c\u00f3mo obtener esos detalles, visite: https://www.home-assistant.io/integrations/vilfo", "title": "Conectar con el Router Vilfo" } }, - "title": "Vilfo Router" + "title": "Router Vilfo" } } \ No newline at end of file diff --git a/homeassistant/components/vilfo/.translations/pl.json b/homeassistant/components/vilfo/.translations/pl.json index 9af4d104965..aef0c14703f 100644 --- a/homeassistant/components/vilfo/.translations/pl.json +++ b/homeassistant/components/vilfo/.translations/pl.json @@ -2,6 +2,22 @@ "config": { "abort": { "already_configured": "Ten router Vilfo jest ju\u017c skonfigurowany." - } + }, + "error": { + "cannot_connect": "Nie mo\u017cna nawi\u0105za\u0107 po\u0142\u0105czenia. Sprawd\u017a wprowadzone dane i spr\u00f3buj ponownie.", + "invalid_auth": "Nieudane uwierzytelnienie. Sprawd\u017a token dost\u0119pu i spr\u00f3buj ponownie.", + "unknown": "Wyst\u0105pi\u0142 nieoczekiwany b\u0142\u0105d podczas konfiguracji integracji." + }, + "step": { + "user": { + "data": { + "access_token": "Token dost\u0119pu do interfejsu API routera Vilfo", + "host": "Nazwa hosta lub adres IP routera" + }, + "description": "Skonfiguruj integracj\u0119 routera Vilfo. Potrzebujesz nazwy hosta/adresu IP routera Vilfo i tokena dost\u0119pu do interfejsu API. Aby uzyska\u0107 dodatkowe informacje na temat tej integracji i sposobu uzyskania niezb\u0119dnych danych do konfiguracji, odwied\u017a: https://www.home-assistant.io/integrations/vilfo", + "title": "Po\u0142\u0105cz si\u0119 z routerem Vilfo" + } + }, + "title": "Router Vilfo" } } \ No newline at end of file diff --git a/homeassistant/components/vilfo/.translations/zh-Hans.json b/homeassistant/components/vilfo/.translations/zh-Hans.json new file mode 100644 index 00000000000..788f85b9382 --- /dev/null +++ b/homeassistant/components/vilfo/.translations/zh-Hans.json @@ -0,0 +1,19 @@ +{ + "config": { + "error": { + "cannot_connect": "\u8fde\u63a5\u5931\u8d25\u3002\u8bf7\u68c0\u67e5\u8f93\u5165\u4fe1\u606f\u540e\uff0c\u518d\u8bd5\u4e00\u6b21\u3002", + "unknown": "\u8bbe\u7f6e\u6574\u5408\u65f6\u53d1\u751f\u610f\u5916\u9519\u8bef\u3002" + }, + "step": { + "user": { + "data": { + "access_token": "Vilfo \u8def\u7531\u5668 API \u5b58\u53d6\u5bc6\u94a5", + "host": "\u8def\u7531\u5668\u4e3b\u673a\u540d\u6216 IP \u5730\u5740" + }, + "description": "\u8bbe\u7f6e Vilfo \u8def\u7531\u5668\u6574\u5408\u3002\u60a8\u9700\u8981\u8f93\u5165 Vilfo \u8def\u7531\u5668\u4e3b\u673a\u540d/IP \u5730\u5740\u3001API\u5b58\u53d6\u5bc6\u94a5\u3002\u5176\u4ed6\u6574\u5408\u7684\u76f8\u5173\u4fe1\u606f\uff0c\u8bf7\u8bbf\u95ee\uff1ahttps://www.home-assistant.io/integrations/vilfo", + "title": "\u8fde\u63a5\u5230 Vilfo \u8def\u7531\u5668" + } + }, + "title": "Vilfo \u8def\u7531\u5668" + } +} \ No newline at end of file diff --git a/homeassistant/components/vizio/.translations/da.json b/homeassistant/components/vizio/.translations/da.json index 9ec9c4122ee..9bfd5864025 100644 --- a/homeassistant/components/vizio/.translations/da.json +++ b/homeassistant/components/vizio/.translations/da.json @@ -24,7 +24,7 @@ "host": ":", "name": "Navn" }, - "title": "Ops\u00e6tning af Vizio SmartCast-klient" + "title": "Ops\u00e6t Vizio SmartCast-enhed" } }, "title": "Vizio SmartCast" diff --git a/homeassistant/components/vizio/.translations/en.json b/homeassistant/components/vizio/.translations/en.json index 23b7c03d423..cee436c9647 100644 --- a/homeassistant/components/vizio/.translations/en.json +++ b/homeassistant/components/vizio/.translations/en.json @@ -24,7 +24,7 @@ "host": ":", "name": "Name" }, - "title": "Setup Vizio SmartCast Client" + "title": "Setup Vizio SmartCast Device" } }, "title": "Vizio SmartCast" diff --git a/homeassistant/components/vizio/.translations/ko.json b/homeassistant/components/vizio/.translations/ko.json index 4c0460ec0e1..64c0887b3f8 100644 --- a/homeassistant/components/vizio/.translations/ko.json +++ b/homeassistant/components/vizio/.translations/ko.json @@ -24,7 +24,7 @@ "host": "<\ud638\uc2a4\ud2b8/ip>:", "name": "\uc774\ub984" }, - "title": "Vizio SmartCast \ud074\ub77c\uc774\uc5b8\ud2b8 \uc124\uc815" + "title": "Vizio SmartCast \uae30\uae30 \uc124\uc815" } }, "title": "Vizio SmartCast" diff --git a/homeassistant/components/vizio/.translations/no.json b/homeassistant/components/vizio/.translations/no.json index fd81f0b7c3c..0b92497a5e7 100644 --- a/homeassistant/components/vizio/.translations/no.json +++ b/homeassistant/components/vizio/.translations/no.json @@ -24,7 +24,7 @@ "host": ":", "name": "Navn" }, - "title": "Oppsett Vizio SmartCast Client" + "title": "Sett opp Vizio SmartCast-enhet" } }, "title": "Vizio SmartCast" diff --git a/homeassistant/components/vizio/.translations/zh-Hant.json b/homeassistant/components/vizio/.translations/zh-Hant.json index cd859977551..24128bb1b9e 100644 --- a/homeassistant/components/vizio/.translations/zh-Hant.json +++ b/homeassistant/components/vizio/.translations/zh-Hant.json @@ -24,7 +24,7 @@ "host": "<\u4e3b\u6a5f\u7aef/IP>:", "name": "\u540d\u7a31" }, - "title": "\u8a2d\u5b9a Vizio SmartCast \u5ba2\u6236\u7aef" + "title": "\u8a2d\u5b9a Vizio SmartCast \u8a2d\u5099" } }, "title": "Vizio SmartCast" diff --git a/homeassistant/components/zha/.translations/ca.json b/homeassistant/components/zha/.translations/ca.json index 2b8230ad689..e5181fb5106 100644 --- a/homeassistant/components/zha/.translations/ca.json +++ b/homeassistant/components/zha/.translations/ca.json @@ -54,14 +54,14 @@ "device_shaken": "Dispositiu sacsejat", "device_slid": "Dispositiu lliscat a \"{subtype}\"", "device_tilted": "Dispositiu inclinat", - "remote_button_double_press": "Bot\u00f3 \"{subtype}\" clicat dues vegades consecutives", - "remote_button_long_press": "Bot\u00f3 \"{subtype}\" premut continuament", + "remote_button_double_press": "Bot\u00f3 \"{subtype}\" clicat dues vegades", + "remote_button_long_press": "Bot\u00f3 \"{subtype}\" premut cont\u00ednuament", "remote_button_long_release": "Bot\u00f3 \"{subtype}\" alliberat despr\u00e9s d'una estona premut", - "remote_button_quadruple_press": "Bot\u00f3 \"{subtype}\" clicat quatre vegades consecutives", - "remote_button_quintuple_press": "Bot\u00f3 \"{subtype}\" clicat cinc vegades consecutives", + "remote_button_quadruple_press": "Bot\u00f3 \"{subtype}\" clicat quatre vegades", + "remote_button_quintuple_press": "Bot\u00f3 \"{subtype}\" clicat cinc vegades", "remote_button_short_press": "Bot\u00f3 \"{subtype}\" premut", "remote_button_short_release": "Bot\u00f3 \"{subtype}\" alliberat", - "remote_button_triple_press": "Bot\u00f3 \"{subtype}\" clicat tres vegades consecutives" + "remote_button_triple_press": "Bot\u00f3 \"{subtype}\" clicat tres vegades" } } } \ No newline at end of file diff --git a/homeassistant/components/zha/.translations/pl.json b/homeassistant/components/zha/.translations/pl.json index 4189ea6d9be..4698a0a37ef 100644 --- a/homeassistant/components/zha/.translations/pl.json +++ b/homeassistant/components/zha/.translations/pl.json @@ -54,14 +54,14 @@ "device_shaken": "nast\u0105pi potrz\u0105\u015bni\u0119cie urz\u0105dzeniem", "device_slid": "nast\u0105pi przesuni\u0119cie urz\u0105dzenia \"{subtype}\"", "device_tilted": "nast\u0105pi przechylenie urz\u0105dzenia", - "remote_button_double_press": "przycisk \"{subtype}\" zostanie podw\u00f3jnie naci\u015bni\u0119ty", - "remote_button_long_press": "przycisk \"{subtype}\" zostanie naci\u015bni\u0119ty w spos\u00f3b ci\u0105g\u0142y", - "remote_button_long_release": "przycisk \"{subtype}\" zostanie zwolniony po d\u0142ugim naci\u015bni\u0119ciu", - "remote_button_quadruple_press": "przycisk \"{subtype}\" czterokrotnie naci\u015bni\u0119ty", - "remote_button_quintuple_press": "przycisk \"{subtype}\" zostanie pi\u0119ciokrotnie naci\u015bni\u0119ty", - "remote_button_short_press": "przycisk \"{subtype}\" zostanie naci\u015bni\u0119ty", - "remote_button_short_release": "przycisk \"{subtype}\" zostanie zwolniony", - "remote_button_triple_press": "przycisk \"{subtype}\" zostanie trzykrotnie naci\u015bni\u0119ty" + "remote_button_double_press": "\"{subtype}\" zostanie podw\u00f3jnie naci\u015bni\u0119ty", + "remote_button_long_press": "\"{subtype}\" zostanie naci\u015bni\u0119ty w spos\u00f3b ci\u0105g\u0142y", + "remote_button_long_release": "\"{subtype}\" zostanie zwolniony po d\u0142ugim naci\u015bni\u0119ciu", + "remote_button_quadruple_press": "\"{subtype}\" czterokrotnie naci\u015bni\u0119ty", + "remote_button_quintuple_press": "\"{subtype}\" zostanie pi\u0119ciokrotnie naci\u015bni\u0119ty", + "remote_button_short_press": "\"{subtype}\" zostanie naci\u015bni\u0119ty", + "remote_button_short_release": "\"{subtype}\" zostanie zwolniony", + "remote_button_triple_press": "\"{subtype}\" zostanie trzykrotnie naci\u015bni\u0119ty" } } } \ No newline at end of file diff --git a/homeassistant/components/zha/.translations/ru.json b/homeassistant/components/zha/.translations/ru.json index 8850fdfc07a..38b0aa8359c 100644 --- a/homeassistant/components/zha/.translations/ru.json +++ b/homeassistant/components/zha/.translations/ru.json @@ -12,10 +12,10 @@ "radio_type": "\u0422\u0438\u043f \u0420\u0430\u0434\u0438\u043e", "usb_path": "\u041f\u0443\u0442\u044c \u043a USB-\u0443\u0441\u0442\u0440\u043e\u0439\u0441\u0442\u0432\u0443" }, - "title": "Zigbee Home Automation (ZHA)" + "title": "Zigbee Home Automation" } }, - "title": "Zigbee Home Automation" + "title": "Zigbee Home Automation (ZHA)" }, "device_automation": { "action_type": { diff --git a/homeassistant/components/zone/.translations/zh-Hans.json b/homeassistant/components/zone/.translations/zh-Hans.json index 6d06b68dad8..6972b2946e4 100644 --- a/homeassistant/components/zone/.translations/zh-Hans.json +++ b/homeassistant/components/zone/.translations/zh-Hans.json @@ -1,7 +1,7 @@ { "config": { "error": { - "name_exists": "\u540d\u79f0\u5df2\u5b58\u5728" + "name_exists": "\u8be5\u540d\u79f0\u5df2\u5b58\u5728" }, "step": { "init": { @@ -13,7 +13,7 @@ "passive": "\u88ab\u52a8", "radius": "\u534a\u5f84" }, - "title": "\u5b9a\u4e49\u533a\u57df\u76f8\u5173\u53d8\u91cf" + "title": "\u5b9a\u4e49\u533a\u57df\u53c2\u6570" } }, "title": "\u533a\u57df" From 7391aa2d7e05641f3506c7e66a67aa6fc4801f31 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 25 Feb 2020 14:17:32 -0800 Subject: [PATCH 34/39] Bumped version to 0.106.0b5 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index c509ee5f0fa..f764b1eae78 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 106 -PATCH_VERSION = "0b4" +PATCH_VERSION = "0b5" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER = (3, 7, 0) From 89625010e50bb442be3d490a976431bc1a205528 Mon Sep 17 00:00:00 2001 From: Aaron Bach Date: Wed, 26 Feb 2020 04:19:14 -0700 Subject: [PATCH 35/39] Fix error where SimpliSafe websocket would disconnect and not reconnect (#32199) * Fix error where SimpliSafe websocket would disconnect and not reconnect * Await --- .../components/simplisafe/__init__.py | 56 +++++++++---------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/homeassistant/components/simplisafe/__init__.py b/homeassistant/components/simplisafe/__init__.py index 83ed7d22351..09004189820 100644 --- a/homeassistant/components/simplisafe/__init__.py +++ b/homeassistant/components/simplisafe/__init__.py @@ -520,41 +520,39 @@ class SimpliSafe: tasks = [update_system(system) for system in self.systems.values()] - def cancel_tasks(): - """Cancel tasks and ensure their cancellation is processed.""" - for task in tasks: - task.cancel() + results = await asyncio.gather(*tasks, return_exceptions=True) + for result in results: + if isinstance(result, InvalidCredentialsError): + if self._emergency_refresh_token_used: + _LOGGER.error( + "SimpliSafe authentication disconnected. Please restart HASS." + ) + remove_listener = self._hass.data[DOMAIN][DATA_LISTENER].pop( + self._config_entry.entry_id + ) + remove_listener() + return - try: - await asyncio.gather(*tasks) - except InvalidCredentialsError: - cancel_tasks() + _LOGGER.warning("SimpliSafe cloud error; trying stored refresh token") + self._emergency_refresh_token_used = True + return await self._api.refresh_access_token( + self._config_entry.data[CONF_TOKEN] + ) - if self._emergency_refresh_token_used: - _LOGGER.error( - "SimpliSafe authentication disconnected. Please restart HASS." - ) - remove_listener = self._hass.data[DOMAIN][DATA_LISTENER].pop( - self._config_entry.entry_id - ) - remove_listener() + if isinstance(result, SimplipyError): + _LOGGER.error("SimpliSafe error while updating: %s", result) return - _LOGGER.warning("SimpliSafe cloud error; trying stored refresh token") - self._emergency_refresh_token_used = True - return await self._api.refresh_access_token( - self._config_entry.data[CONF_TOKEN] - ) - except SimplipyError as err: - cancel_tasks() - _LOGGER.error("SimpliSafe error while updating: %s", err) - return - except Exception as err: # pylint: disable=broad-except - cancel_tasks() - _LOGGER.error("Unknown error while updating: %s", err) - return + if isinstance(result, SimplipyError): + _LOGGER.error("Unknown error while updating: %s", result) + return if self._api.refresh_token_dirty: + # Reconnect the websocket: + await self._api.websocket.async_disconnect() + await self._api.websocket.async_connect() + + # Save the new refresh token: _async_save_refresh_token( self._hass, self._config_entry, self._api.refresh_token ) From 897433ecba8034cb5436854ef96ac8b511f6f754 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 26 Feb 2020 11:32:15 +0100 Subject: [PATCH 36/39] Updated frontend to 20200220.4 (#32205) --- homeassistant/components/frontend/manifest.json | 2 +- homeassistant/package_constraints.txt | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/frontend/manifest.json b/homeassistant/components/frontend/manifest.json index 2b39681af25..b9575b7f21a 100644 --- a/homeassistant/components/frontend/manifest.json +++ b/homeassistant/components/frontend/manifest.json @@ -3,7 +3,7 @@ "name": "Home Assistant Frontend", "documentation": "https://www.home-assistant.io/integrations/frontend", "requirements": [ - "home-assistant-frontend==20200220.3" + "home-assistant-frontend==20200220.4" ], "dependencies": [ "api", diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 246d63d984b..7d6f445c1e4 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -11,7 +11,7 @@ cryptography==2.8 defusedxml==0.6.0 distro==1.4.0 hass-nabucasa==0.31 -home-assistant-frontend==20200220.3 +home-assistant-frontend==20200220.4 importlib-metadata==1.5.0 jinja2>=2.10.3 netdisco==2.6.0 diff --git a/requirements_all.txt b/requirements_all.txt index 3185524db20..a340f99d7c6 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -683,7 +683,7 @@ hole==0.5.0 holidays==0.10.1 # homeassistant.components.frontend -home-assistant-frontend==20200220.3 +home-assistant-frontend==20200220.4 # homeassistant.components.zwave homeassistant-pyozw==0.1.8 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 7139bcbd4ec..be073a4b929 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -254,7 +254,7 @@ hole==0.5.0 holidays==0.10.1 # homeassistant.components.frontend -home-assistant-frontend==20200220.3 +home-assistant-frontend==20200220.4 # homeassistant.components.zwave homeassistant-pyozw==0.1.8 From 1e5f0a51360dc3abc09b05a6cc5ffe6f2e06b433 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Wed, 26 Feb 2020 12:34:38 +0100 Subject: [PATCH 37/39] Bumped version to 0.106.0 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index f764b1eae78..ff8e6bf8a9e 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 106 -PATCH_VERSION = "0b5" +PATCH_VERSION = "0" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER = (3, 7, 0) From 9c755d8fd4a1217b8a903b61a14845bb2bbd6d72 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Thu, 20 Feb 2020 17:18:50 +0100 Subject: [PATCH 38/39] Remove deprecated Hue options (fixes CI) (#32027) From 4de3871a78ae255e36067f79e09f367dcb52d6bd Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 20 Feb 2020 08:11:27 -0800 Subject: [PATCH 39/39] Fix hue test --- homeassistant/components/hue/__init__.py | 8 +------- tests/components/hue/test_init.py | 3 +-- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/hue/__init__.py b/homeassistant/components/hue/__init__.py index dd2905c8783..7510ff22f16 100644 --- a/homeassistant/components/hue/__init__.py +++ b/homeassistant/components/hue/__init__.py @@ -46,13 +46,7 @@ CONFIG_SCHEMA = vol.Schema( DOMAIN: vol.Schema( { vol.Optional(CONF_BRIDGES): vol.All( - cv.ensure_list, - [ - vol.All( - cv.deprecated("filename", invalidation_version="0.106.0"), - BRIDGE_CONFIG_SCHEMA, - ), - ], + cv.ensure_list, [BRIDGE_CONFIG_SCHEMA], ) } ) diff --git a/tests/components/hue/test_init.py b/tests/components/hue/test_init.py index 375d5da4456..d9131dad226 100644 --- a/tests/components/hue/test_init.py +++ b/tests/components/hue/test_init.py @@ -37,7 +37,7 @@ async def test_setup_defined_hosts_known_auth(hass): hue.CONF_ALLOW_HUE_GROUPS: False, hue.CONF_ALLOW_UNREACHABLE: True, }, - {hue.CONF_HOST: "1.1.1.1", "filename": "bla"}, + {hue.CONF_HOST: "1.1.1.1"}, ] } }, @@ -59,7 +59,6 @@ async def test_setup_defined_hosts_known_auth(hass): hue.CONF_HOST: "1.1.1.1", hue.CONF_ALLOW_HUE_GROUPS: True, hue.CONF_ALLOW_UNREACHABLE: False, - "filename": "bla", }, }