From 23cf8414b8de51d86719498c78b996b5ce203f1f Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 21 Aug 2019 16:20:08 -0700 Subject: [PATCH 01/40] Bumped version to 0.98.0b0 --- homeassistant/const.py | 2 +- script/version_bump.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index eebd10f4fb9..aebcb95c3b1 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 98 -PATCH_VERSION = "0.dev0" +PATCH_VERSION = "0b0" __short_version__ = "{}.{}".format(MAJOR_VERSION, MINOR_VERSION) __version__ = "{}.{}".format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 6, 0) diff --git a/script/version_bump.py b/script/version_bump.py index 7c584daae7e..db3f3ac273d 100755 --- a/script/version_bump.py +++ b/script/version_bump.py @@ -102,7 +102,7 @@ def write_version(version): "MINOR_VERSION = .*\n", "MINOR_VERSION = {}\n".format(minor), content ) content = re.sub( - "PATCH_VERSION = .*\n", "PATCH_VERSION = '{}'\n".format(patch), content + "PATCH_VERSION = .*\n", 'PATCH_VERSION = "{}"\n'.format(patch), content ) with open("homeassistant/const.py", "wt") as fil: From e53ecfb5d533a44f995484e27a7f58b6e2e99120 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Thu, 22 Aug 2019 08:58:41 +0200 Subject: [PATCH 02/40] Update azure-pipelines-release.yml for Azure Pipelines (#26128) * Update azure-pipelines-release.yml for Azure Pipelines * Update azure-pipelines-release.yml --- azure-pipelines-release.yml | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/azure-pipelines-release.yml b/azure-pipelines-release.yml index 81bb1944bed..d0cfc294db1 100644 --- a/azure-pipelines-release.yml +++ b/azure-pipelines-release.yml @@ -7,7 +7,7 @@ trigger: pr: none variables: - name: versionBuilder - value: '5.2' + value: '6.1' - group: docker - group: github - group: twine @@ -155,48 +155,46 @@ stages: vmImage: 'ubuntu-latest' steps: - script: | - echo '{ "experimental": true }' | sudo tee /etc/docker/daemon.json - sudo service docker restart + mkdir -p ~/.docker + echo '{ "experimental": "enabled" }' > .docker/config.json - sleep 15 sudo docker login -u $(dockerUser) -p $(dockerPassword) displayName: 'Enable manifest / Docker login' - script: | set -e - export DOCKER_CLI_EXPERIMENTAL=enabled function create_manifest() { local tag_l=$1 local tag_r=$2 - sudo docker manifest create homeassistant/home-assistant:${tag_l} \ + sudo docker --config .docker manifest create homeassistant/home-assistant:${tag_l} \ homeassistant/amd64-homeassistant:${tag_r} \ homeassistant/i386-homeassistant:${tag_r} \ homeassistant/armhf-homeassistant:${tag_r} \ homeassistant/armv7-homeassistant:${tag_r} \ homeassistant/aarch64-homeassistant:${tag_r} - sudo docker manifest annotate homeassistant/home-assistant:${tag_l} \ + sudo docker --config .docker manifest annotate homeassistant/home-assistant:${tag_l} \ homeassistant/amd64-homeassistant:${tag_r} \ --os linux --arch amd64 - sudo docker manifest annotate homeassistant/home-assistant:${tag_l} \ + sudo docker --config .docker manifest annotate homeassistant/home-assistant:${tag_l} \ homeassistant/i386-homeassistant:${tag_r} \ --os linux --arch i386 - sudo docker manifest annotate homeassistant/home-assistant:${tag_l} \ + sudo docker --config .docker manifest annotate homeassistant/home-assistant:${tag_l} \ homeassistant/armhf-homeassistant:${tag_r} \ --os linux --arch arm --variant=v6 - sudo docker manifest annotate homeassistant/home-assistant:${tag_l} \ + sudo docker --config .docker manifest annotate homeassistant/home-assistant:${tag_l} \ homeassistant/armv7-homeassistant:${tag_r} \ --os linux --arch arm --variant=v7 - sudo docker manifest annotate homeassistant/home-assistant:${tag_l} \ + sudo docker --config .docker manifest annotate homeassistant/home-assistant:${tag_l} \ homeassistant/aarch64-homeassistant:${tag_r} \ --os linux --arch arm64 --variant=v8 - sudo docker manifest push --purge homeassistant/home-assistant:${tag_l} + sudo docker --config .docker manifest push --purge homeassistant/home-assistant:${tag_l} } # Create version tag From a71a02926216f7c94d8fbd90943430ee8095595c Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Thu, 22 Aug 2019 09:29:03 +0200 Subject: [PATCH 03/40] Update azure-pipelines-release.yml for Azure Pipelines --- azure-pipelines-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines-release.yml b/azure-pipelines-release.yml index d0cfc294db1..7409be5f98c 100644 --- a/azure-pipelines-release.yml +++ b/azure-pipelines-release.yml @@ -180,7 +180,7 @@ stages: sudo docker --config .docker manifest annotate homeassistant/home-assistant:${tag_l} \ homeassistant/i386-homeassistant:${tag_r} \ - --os linux --arch i386 + --os linux --arch 386 sudo docker --config .docker manifest annotate homeassistant/home-assistant:${tag_l} \ homeassistant/armhf-homeassistant:${tag_r} \ From 44a528dee2e563d8b22400378f785dee7387e449 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Thu, 22 Aug 2019 17:35:22 +0200 Subject: [PATCH 04/40] Update azure-pipelines-release.yml for Azure Pipelines --- azure-pipelines-release.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/azure-pipelines-release.yml b/azure-pipelines-release.yml index 7409be5f98c..44d910a8106 100644 --- a/azure-pipelines-release.yml +++ b/azure-pipelines-release.yml @@ -197,6 +197,12 @@ stages: sudo docker --config .docker manifest push --purge homeassistant/home-assistant:${tag_l} } + sudo docker pull homeassistant/amd64-homeassistant:$(Build.SourceBranchName) + sudo docker pull homeassistant/i368-homeassistant:$(Build.SourceBranchName) + sudo docker pull homeassistant/armhf-homeassistant:$(Build.SourceBranchName) + sudo docker pull homeassistant/armv7-homeassistant:$(Build.SourceBranchName) + sudo docker pull homeassistant/aarch64-homeassistant:$(Build.SourceBranchName) + # Create version tag create_manifest "$(Build.SourceBranchName)" "$(Build.SourceBranchName)" @@ -205,6 +211,7 @@ stages: create_manifest "dev" "$(Build.SourceBranchName)" elif [[ "$version" =~ b ]]; then create_manifest "beta" "$(Build.SourceBranchName)" + create_manifest "rc" "$(Build.SourceBranchName)" else create_manifest "stable" "$(Build.SourceBranchName)" create_manifest "latest" "$(Build.SourceBranchName)" From 82e5a384039a64c97e388313c663434b8009a7e4 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Thu, 22 Aug 2019 17:47:04 +0200 Subject: [PATCH 05/40] Update azure-pipelines-release.yml for Azure Pipelines --- azure-pipelines-release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines-release.yml b/azure-pipelines-release.yml index 44d910a8106..2ad13288e08 100644 --- a/azure-pipelines-release.yml +++ b/azure-pipelines-release.yml @@ -215,6 +215,7 @@ stages: else create_manifest "stable" "$(Build.SourceBranchName)" create_manifest "latest" "$(Build.SourceBranchName)" + create_manifest "beta" "$(Build.SourceBranchName)" fi displayName: 'Create Meta-Image' From 5f8c3e623546e7e1b0cbef5bd377115befd59bd9 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Thu, 22 Aug 2019 17:50:51 +0200 Subject: [PATCH 06/40] Update azure-pipelines-release.yml --- azure-pipelines-release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines-release.yml b/azure-pipelines-release.yml index 2ad13288e08..6b986329291 100644 --- a/azure-pipelines-release.yml +++ b/azure-pipelines-release.yml @@ -216,6 +216,7 @@ stages: create_manifest "stable" "$(Build.SourceBranchName)" create_manifest "latest" "$(Build.SourceBranchName)" create_manifest "beta" "$(Build.SourceBranchName)" + create_manifest "rc" "$(Build.SourceBranchName)" fi displayName: 'Create Meta-Image' From 8856a1cda6e8965177ac904d62a185e92d26425c Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 22 Aug 2019 15:05:57 -0700 Subject: [PATCH 07/40] Updated frontend to 20190822.0 --- 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 648fc8b96df..8d6271183bd 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/components/frontend", "requirements": [ - "home-assistant-frontend==20190821.0" + "home-assistant-frontend==20190822.0" ], "dependencies": [ "api", diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index b26e1c7e59f..0f4fb56970b 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -11,7 +11,7 @@ contextvars==2.4;python_version<"3.7" cryptography==2.7 distro==1.4.0 hass-nabucasa==0.17 -home-assistant-frontend==20190821.0 +home-assistant-frontend==20190822.0 importlib-metadata==0.19 jinja2>=2.10.1 netdisco==2.6.0 diff --git a/requirements_all.txt b/requirements_all.txt index 33d6be841cf..f5484829de7 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -624,7 +624,7 @@ hole==0.5.0 holidays==0.9.11 # homeassistant.components.frontend -home-assistant-frontend==20190821.0 +home-assistant-frontend==20190822.0 # homeassistant.components.zwave homeassistant-pyozw==0.1.4 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 9d254f72e9b..b5d139719ef 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -176,7 +176,7 @@ hdate==0.9.0 holidays==0.9.11 # homeassistant.components.frontend -home-assistant-frontend==20190821.0 +home-assistant-frontend==20190822.0 # homeassistant.components.homekit_controller homekit[IP]==0.15.0 From 49bc3d3769c0e779f74a0fed8128a2ef24fa2287 Mon Sep 17 00:00:00 2001 From: Jeff Irion Date: Thu, 22 Aug 2019 11:01:56 -0700 Subject: [PATCH 08/40] Load user-provided descriptions for python_scripts (#26069) * Load user-provided descriptions for python_scripts * Import SERVICE_DESCRIPTION_CACHE * Use async_set_service_schema to register service descriptions * Add python_script tests for loading service descriptions * Use async/await in test --- .../components/python_script/__init__.py | 15 +++ tests/components/python_script/test_init.py | 100 +++++++++++++++++- 2 files changed, 114 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/python_script/__init__.py b/homeassistant/components/python_script/__init__.py index 788da6a8d64..715c06aca43 100644 --- a/homeassistant/components/python_script/__init__.py +++ b/homeassistant/components/python_script/__init__.py @@ -9,8 +9,10 @@ import voluptuous as vol from homeassistant.const import SERVICE_RELOAD from homeassistant.exceptions import HomeAssistantError +from homeassistant.helpers.service import async_set_service_schema from homeassistant.loader import bind_hass from homeassistant.util import sanitize_filename +from homeassistant.util.yaml.loader import load_yaml import homeassistant.util.dt as dt_util _LOGGER = logging.getLogger(__name__) @@ -90,10 +92,23 @@ def discover_scripts(hass): continue hass.services.remove(DOMAIN, existing_service) + # Load user-provided service descriptions from python_scripts/services.yaml + services_yaml = os.path.join(path, "services.yaml") + if os.path.exists(services_yaml): + services_dict = load_yaml(services_yaml) + else: + services_dict = {} + for fil in glob.iglob(os.path.join(path, "*.py")): name = os.path.splitext(os.path.basename(fil))[0] hass.services.register(DOMAIN, name, python_script_service_handler) + service_desc = { + "description": services_dict.get(name, {}).get("description", ""), + "fields": services_dict.get(name, {}).get("fields", {}), + } + async_set_service_schema(hass, DOMAIN, name, service_desc) + @bind_hass def execute_script(hass, name, data=None): diff --git a/tests/components/python_script/test_init.py b/tests/components/python_script/test_init.py index fcf1519d4c7..d7732c00f94 100644 --- a/tests/components/python_script/test_init.py +++ b/tests/components/python_script/test_init.py @@ -3,8 +3,11 @@ import asyncio import logging from unittest.mock import patch, mock_open +from homeassistant.helpers.service import async_get_all_descriptions from homeassistant.setup import async_setup_component -from homeassistant.components.python_script import execute +from homeassistant.components.python_script import DOMAIN, execute, FOLDER + +from tests.common import patch_yaml_files @asyncio.coroutine @@ -289,6 +292,101 @@ def test_reload(hass): assert hass.services.has_service("python_script", "reload") +async def test_service_descriptions(hass): + """Test that service descriptions are loaded and reloaded correctly.""" + # Test 1: no user-provided services.yaml file + scripts1 = [ + "/some/config/dir/python_scripts/hello.py", + "/some/config/dir/python_scripts/world_beer.py", + ] + + service_descriptions1 = ( + "hello:\n" + " description: Description of hello.py.\n" + " fields:\n" + " fake_param:\n" + " description: Parameter used by hello.py.\n" + " example: 'This is a test of python_script.hello'" + ) + services_yaml1 = { + "{}/{}/services.yaml".format( + hass.config.config_dir, FOLDER + ): service_descriptions1 + } + + with patch( + "homeassistant.components.python_script.os.path.isdir", return_value=True + ), patch( + "homeassistant.components.python_script.glob.iglob", return_value=scripts1 + ), patch( + "homeassistant.components.python_script.os.path.exists", return_value=True + ), patch_yaml_files( + services_yaml1 + ): + await async_setup_component(hass, DOMAIN, {}) + + descriptions = await async_get_all_descriptions(hass) + + assert len(descriptions) == 1 + + assert descriptions[DOMAIN]["hello"]["description"] == "Description of hello.py." + assert ( + descriptions[DOMAIN]["hello"]["fields"]["fake_param"]["description"] + == "Parameter used by hello.py." + ) + assert ( + descriptions[DOMAIN]["hello"]["fields"]["fake_param"]["example"] + == "This is a test of python_script.hello" + ) + + assert descriptions[DOMAIN]["world_beer"]["description"] == "" + assert bool(descriptions[DOMAIN]["world_beer"]["fields"]) is False + + # Test 2: user-provided services.yaml file + scripts2 = [ + "/some/config/dir/python_scripts/hello2.py", + "/some/config/dir/python_scripts/world_beer.py", + ] + + service_descriptions2 = ( + "hello2:\n" + " description: Description of hello2.py.\n" + " fields:\n" + " fake_param:\n" + " description: Parameter used by hello2.py.\n" + " example: 'This is a test of python_script.hello2'" + ) + services_yaml2 = { + "{}/{}/services.yaml".format( + hass.config.config_dir, FOLDER + ): service_descriptions2 + } + + with patch( + "homeassistant.components.python_script.os.path.isdir", return_value=True + ), patch( + "homeassistant.components.python_script.glob.iglob", return_value=scripts2 + ), patch( + "homeassistant.components.python_script.os.path.exists", return_value=True + ), patch_yaml_files( + services_yaml2 + ): + await hass.services.async_call(DOMAIN, "reload", {}, blocking=True) + descriptions = await async_get_all_descriptions(hass) + + assert len(descriptions) == 1 + + assert descriptions[DOMAIN]["hello2"]["description"] == "Description of hello2.py." + assert ( + descriptions[DOMAIN]["hello2"]["fields"]["fake_param"]["description"] + == "Parameter used by hello2.py." + ) + assert ( + descriptions[DOMAIN]["hello2"]["fields"]["fake_param"]["example"] + == "This is a test of python_script.hello2" + ) + + @asyncio.coroutine def test_sleep_warns_one(hass, caplog): """Test time.sleep warns once.""" From 08471e3e52a017ac59e5e73376a34b91732d5463 Mon Sep 17 00:00:00 2001 From: SukramJ Date: Thu, 22 Aug 2019 18:02:35 +0200 Subject: [PATCH 09/40] Splitt device_state_attributes between device and group for Homematic IP Cloud (#26137) * splitt device_state_attributes between device and group * readd device_state_attributes for access point --- .../components/homematicip_cloud/binary_sensor.py | 8 ++------ homeassistant/components/homematicip_cloud/device.py | 9 +++++---- homeassistant/components/homematicip_cloud/sensor.py | 6 ++++++ 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/homematicip_cloud/binary_sensor.py b/homeassistant/components/homematicip_cloud/binary_sensor.py index 8ecbfeab01a..97746f3f472 100644 --- a/homeassistant/components/homematicip_cloud/binary_sensor.py +++ b/homeassistant/components/homematicip_cloud/binary_sensor.py @@ -38,7 +38,7 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant from . import DOMAIN as HMIPC_DOMAIN, HMIPC_HAPID, HomematicipGenericDevice -from .device import ATTR_GROUP_MEMBER_UNREACHABLE, ATTR_ID +from .device import ATTR_GROUP_MEMBER_UNREACHABLE, ATTR_MODEL_TYPE _LOGGER = logging.getLogger(__name__) @@ -309,11 +309,7 @@ class HomematicipSecurityZoneSensorGroup(HomematicipGenericDevice, BinarySensorD @property def device_state_attributes(self): """Return the state attributes of the security zone group.""" - attr = super().device_state_attributes - - # Remove ATTR_ID from dict, because security groups don't have - # device id/sgtin, just an ugly uuid that is referenced no where else. - del attr[ATTR_ID] + attr = {ATTR_MODEL_TYPE: self._device.modelType} if self._device.motionDetected: attr[ATTR_MOTIONDETECTED] = True diff --git a/homeassistant/components/homematicip_cloud/device.py b/homeassistant/components/homematicip_cloud/device.py index 0fffad8e97e..b086eaa29c7 100644 --- a/homeassistant/components/homematicip_cloud/device.py +++ b/homeassistant/components/homematicip_cloud/device.py @@ -117,9 +117,10 @@ class HomematicipGenericDevice(Entity): def device_state_attributes(self): """Return the state attributes of the generic device.""" state_attr = {} - for attr, attr_key in DEVICE_ATTRIBUTES.items(): - attr_value = getattr(self._device, attr, None) - if attr_value: - state_attr[attr_key] = attr_value + if isinstance(self._device, AsyncDevice): + for attr, attr_key in DEVICE_ATTRIBUTES.items(): + attr_value = getattr(self._device, attr, None) + if attr_value: + state_attr[attr_key] = attr_value return state_attr diff --git a/homeassistant/components/homematicip_cloud/sensor.py b/homeassistant/components/homematicip_cloud/sensor.py index add03c6b644..c15b3121d3a 100644 --- a/homeassistant/components/homematicip_cloud/sensor.py +++ b/homeassistant/components/homematicip_cloud/sensor.py @@ -34,6 +34,7 @@ from homeassistant.const import ( from homeassistant.core import HomeAssistant from . import DOMAIN as HMIPC_DOMAIN, HMIPC_HAPID, HomematicipGenericDevice +from .device import ATTR_MODEL_TYPE _LOGGER = logging.getLogger(__name__) @@ -142,6 +143,11 @@ class HomematicipAccesspointStatus(HomematicipGenericDevice): """Return the unit this state is expressed in.""" return "%" + @property + def device_state_attributes(self): + """Return the state attributes of the security zone group.""" + return {ATTR_MODEL_TYPE: self._device.modelType} + class HomematicipHeatingThermostat(HomematicipGenericDevice): """Representation of a HomematicIP heating thermostat device.""" From a58211062993c1a669876e3ebf7e764f74603cba Mon Sep 17 00:00:00 2001 From: Phil Cole Date: Thu, 22 Aug 2019 20:40:48 +0100 Subject: [PATCH 10/40] Nissanleaf login fix (#26139) * Upgrade to pycarwings2.9 per 25 July 2019 API change * Remove rest of location tracker. Fix get_status_from_update call. --- .../components/nissan_leaf/__init__.py | 87 ++++--------------- .../components/nissan_leaf/device_tracker.py | 46 ---------- .../components/nissan_leaf/manifest.json | 2 +- requirements_all.txt | 2 +- 4 files changed, 21 insertions(+), 116 deletions(-) delete mode 100644 homeassistant/components/nissan_leaf/device_tracker.py diff --git a/homeassistant/components/nissan_leaf/__init__.py b/homeassistant/components/nissan_leaf/__init__.py index 409b4d38208..38b7018af6c 100644 --- a/homeassistant/components/nissan_leaf/__init__.py +++ b/homeassistant/components/nissan_leaf/__init__.py @@ -24,14 +24,12 @@ DOMAIN = "nissan_leaf" DATA_LEAF = "nissan_leaf_data" DATA_BATTERY = "battery" -DATA_LOCATION = "location" DATA_CHARGING = "charging" DATA_PLUGGED_IN = "plugged_in" DATA_CLIMATE = "climate" DATA_RANGE_AC = "range_ac_on" DATA_RANGE_AC_OFF = "range_ac_off" -CONF_NCONNECT = "nissan_connect" CONF_INTERVAL = "update_interval" CONF_CHARGING_INTERVAL = "update_interval_charging" CONF_CLIMATE_INTERVAL = "update_interval_climate" @@ -61,7 +59,6 @@ CONFIG_SCHEMA = vol.Schema( vol.Required(CONF_USERNAME): cv.string, vol.Required(CONF_PASSWORD): cv.string, vol.Required(CONF_REGION): vol.In(CONF_VALID_REGIONS), - vol.Optional(CONF_NCONNECT, default=True): cv.boolean, vol.Optional(CONF_INTERVAL, default=DEFAULT_INTERVAL): ( vol.All(cv.time_period, vol.Clamp(min=MIN_UPDATE_INTERVAL)) ), @@ -84,7 +81,7 @@ CONFIG_SCHEMA = vol.Schema( extra=vol.ALLOW_EXTRA, ) -LEAF_COMPONENTS = ["sensor", "switch", "binary_sensor", "device_tracker"] +LEAF_COMPONENTS = ["sensor", "switch", "binary_sensor"] SIGNAL_UPDATE_LEAF = "nissan_leaf_update" @@ -177,8 +174,7 @@ def setup(hass, config): hass.data[DATA_LEAF][leaf.vin] = data_store for component in LEAF_COMPONENTS: - if component != "device_tracker" or car_config[CONF_NCONNECT]: - load_platform(hass, component, DOMAIN, {}, car_config) + load_platform(hass, component, DOMAIN, {}, car_config) async_track_point_in_utc_time( hass, data_store.async_update_data, utcnow() + INITIAL_UPDATE @@ -209,24 +205,20 @@ class LeafDataStore: self.hass = hass self.leaf = leaf self.car_config = car_config - self.nissan_connect = car_config[CONF_NCONNECT] self.force_miles = car_config[CONF_FORCE_MILES] self.data = {} self.data[DATA_CLIMATE] = False self.data[DATA_BATTERY] = 0 self.data[DATA_CHARGING] = False - self.data[DATA_LOCATION] = False self.data[DATA_RANGE_AC] = 0 self.data[DATA_RANGE_AC_OFF] = 0 self.data[DATA_PLUGGED_IN] = False self.next_update = None self.last_check = None self.request_in_progress = False - # Timestamp of last successful response from battery, - # climate or location. + # Timestamp of last successful response from battery or climate. self.last_battery_response = None self.last_climate_response = None - self.last_location_response = None self._remove_listener = None async def async_update_data(self, now): @@ -334,20 +326,6 @@ class LeafDataStore: except CarwingsError: _LOGGER.error("Error fetching climate info") - if self.nissan_connect: - try: - location_response = await self.async_get_location() - - if location_response is None: - _LOGGER.debug("Empty Location Response Received") - self.data[DATA_LOCATION] = None - else: - _LOGGER.debug("Location Response: %s", location_response.__dict__) - self.data[DATA_LOCATION] = location_response - self.last_location_response = utcnow() - except CarwingsError: - _LOGGER.error("Error fetching location info") - self.request_in_progress = False async_dispatcher_send(self.hass, SIGNAL_UPDATE_LEAF) @@ -364,19 +342,6 @@ class LeafDataStore: from pycarwings2 import CarwingsError try: - # First, check nissan servers for the latest data - start_server_info = await self.hass.async_add_executor_job( - self.leaf.get_latest_battery_status - ) - - # Store the date from the nissan servers - start_date = self._extract_start_date(start_server_info) - if start_date is None: - _LOGGER.info("No start date from servers. Aborting") - return None - - _LOGGER.debug("Start server date=%s", start_date) - # Request battery update from the car _LOGGER.debug("Requesting battery update, %s", self.leaf.vin) request = await self.hass.async_add_executor_job(self.leaf.request_update) @@ -393,21 +358,30 @@ class LeafDataStore: ) await asyncio.sleep(PYCARWINGS2_SLEEP) - # Note leaf.get_status_from_update is always returning 0, so - # don't try to use it anymore. - server_info = await self.hass.async_add_executor_job( - self.leaf.get_latest_battery_status + # We don't use the response from get_status_from_update + # apart from knowing that the car has responded saying it + # has given the latest battery status to Nissan. + check_result_info = await self.hass.async_add_executor_job( + self.leaf.get_status_from_update, request ) - latest_date = self._extract_start_date(server_info) - _LOGGER.debug("Latest server date=%s", latest_date) - if latest_date is not None and latest_date != start_date: + if check_result_info is not None: + # Get the latest battery status from Nissan servers. + # This has the SOC in it. + server_info = await self.hass.async_add_executor_job( + self.leaf.get_latest_battery_status + ) return server_info _LOGGER.debug( "%s attempts exceeded return latest data from server", MAX_RESPONSE_ATTEMPTS, ) + # Get the latest data from the nissan servers, even though + # it may be out of date, it's better than nothing. + server_info = await self.hass.async_add_executor_job( + self.leaf.get_latest_battery_status + ) return server_info except CarwingsError: _LOGGER.error("An error occurred getting battery status.") @@ -465,29 +439,6 @@ class LeafDataStore: _LOGGER.debug("Climate result not returned by Nissan servers") return False - async def async_get_location(self): - """Get location from Nissan servers.""" - request = await self.hass.async_add_executor_job(self.leaf.request_location) - for attempt in range(MAX_RESPONSE_ATTEMPTS): - if attempt > 0: - _LOGGER.debug( - "Location data not in yet. (%s) (%s). " "Waiting %s seconds", - self.leaf.vin, - attempt, - PYCARWINGS2_SLEEP, - ) - await asyncio.sleep(PYCARWINGS2_SLEEP) - - location_status = await self.hass.async_add_executor_job( - self.leaf.get_status_from_location, request - ) - - if location_status is not None: - _LOGGER.debug("Location_status=%s", location_status.__dict__) - break - - return location_status - class LeafEntity(Entity): """Base class for Nissan Leaf entity.""" diff --git a/homeassistant/components/nissan_leaf/device_tracker.py b/homeassistant/components/nissan_leaf/device_tracker.py deleted file mode 100644 index 11d18ee5a8e..00000000000 --- a/homeassistant/components/nissan_leaf/device_tracker.py +++ /dev/null @@ -1,46 +0,0 @@ -"""Support for tracking a Nissan Leaf.""" -import logging - -from homeassistant.helpers.dispatcher import dispatcher_connect -from homeassistant.util import slugify - -from . import DATA_LEAF, DATA_LOCATION, SIGNAL_UPDATE_LEAF - -_LOGGER = logging.getLogger(__name__) - -ICON_CAR = "mdi:car" - - -def setup_scanner(hass, config, see, discovery_info=None): - """Set up the Nissan Leaf tracker.""" - if discovery_info is None: - return False - - def see_vehicle(): - """Handle the reporting of the vehicle position.""" - for vin, datastore in hass.data[DATA_LEAF].items(): - host_name = datastore.leaf.nickname - dev_id = "nissan_leaf_{}".format(slugify(host_name)) - if not datastore.data[DATA_LOCATION]: - _LOGGER.debug("No position found for vehicle %s", vin) - return - _LOGGER.debug( - "Updating device_tracker for %s with position %s", - datastore.leaf.nickname, - datastore.data[DATA_LOCATION].__dict__, - ) - attrs = {"updated_on": datastore.last_location_response} - see( - dev_id=dev_id, - host_name=host_name, - gps=( - datastore.data[DATA_LOCATION].latitude, - datastore.data[DATA_LOCATION].longitude, - ), - attributes=attrs, - icon=ICON_CAR, - ) - - dispatcher_connect(hass, SIGNAL_UPDATE_LEAF, see_vehicle) - - return True diff --git a/homeassistant/components/nissan_leaf/manifest.json b/homeassistant/components/nissan_leaf/manifest.json index ab94c01b7c1..70aaa112414 100644 --- a/homeassistant/components/nissan_leaf/manifest.json +++ b/homeassistant/components/nissan_leaf/manifest.json @@ -3,7 +3,7 @@ "name": "Nissan leaf", "documentation": "https://www.home-assistant.io/components/nissan_leaf", "requirements": [ - "pycarwings2==2.8" + "pycarwings2==2.9" ], "dependencies": [], "codeowners": [ diff --git a/requirements_all.txt b/requirements_all.txt index f5484829de7..a2b91f7eb7d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1071,7 +1071,7 @@ pyblackbird==0.5 pybotvac==0.0.15 # homeassistant.components.nissan_leaf -pycarwings2==2.8 +pycarwings2==2.9 # homeassistant.components.cloudflare pycfdns==0.0.1 From 7b62516e693de5ace5834553179c096d56032fff Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 22 Aug 2019 14:12:24 -0700 Subject: [PATCH 11/40] Log warning if disabled entities receive updates. (#26143) * Log warning if disabled entities receive updates. * Fix test * Always set entity ID on disabled entities --- homeassistant/helpers/entity.py | 13 ++++++++ homeassistant/helpers/entity_platform.py | 6 ++-- .../components/config/test_entity_registry.py | 21 ++++++++++--- tests/helpers/test_entity.py | 31 +++++++++++++++++-- tests/helpers/test_entity_platform.py | 2 +- 5 files changed, 63 insertions(+), 10 deletions(-) diff --git a/homeassistant/helpers/entity.py b/homeassistant/helpers/entity.py index aecdf45dde5..7de41415f08 100644 --- a/homeassistant/helpers/entity.py +++ b/homeassistant/helpers/entity.py @@ -99,6 +99,9 @@ class Entity: # If we reported if this entity was slow _slow_reported = False + # If we reported this entity is updated while disabled + _disabled_reported = False + # Protect for multiple updates _update_staged = False @@ -273,6 +276,16 @@ class Entity: @callback def _async_write_ha_state(self): """Write the state to the state machine.""" + if self.registry_entry and self.registry_entry.disabled_by: + if not self._disabled_reported: + self._disabled_reported = True + _LOGGER.warning( + "Entity %s is incorrectly being triggered for updates while it is disabled. This is a bug in the %s integration.", + self.entity_id, + self.platform.platform_name, + ) + return + start = timer() attr = {} diff --git a/homeassistant/helpers/entity_platform.py b/homeassistant/helpers/entity_platform.py index 74351ac50af..4a6a3038fd0 100644 --- a/homeassistant/helpers/entity_platform.py +++ b/homeassistant/helpers/entity_platform.py @@ -349,6 +349,9 @@ class EntityPlatform: disabled_by=disabled_by, ) + entity.registry_entry = entry + entity.entity_id = entry.entity_id + if entry.disabled: self.logger.info( "Not adding entity %s because it's disabled", @@ -358,9 +361,6 @@ class EntityPlatform: ) return - entity.registry_entry = entry - entity.entity_id = entry.entity_id - # We won't generate an entity ID if the platform has already set one # We will however make sure that platform cannot pick a registered ID elif entity.entity_id is not None and entity_registry.async_is_registered( diff --git a/tests/components/config/test_entity_registry.py b/tests/components/config/test_entity_registry.py index f18abe9b0e2..64328a0c8c5 100644 --- a/tests/components/config/test_entity_registry.py +++ b/tests/components/config/test_entity_registry.py @@ -127,13 +127,13 @@ async def test_update_entity(hass, client): assert state is not None assert state.name == "before update" + # UPDATE NAME await client.send_json( { "id": 6, "type": "config/entity_registry/update", "entity_id": "test_domain.world", "name": "after update", - "disabled_by": "user", } ) @@ -142,7 +142,7 @@ async def test_update_entity(hass, client): assert msg["result"] == { "config_entry_id": None, "device_id": None, - "disabled_by": "user", + "disabled_by": None, "platform": "test_platform", "entity_id": "test_domain.world", "name": "after update", @@ -151,13 +151,26 @@ async def test_update_entity(hass, client): state = hass.states.get("test_domain.world") assert state.name == "after update" - assert registry.entities["test_domain.world"].disabled_by == "user" - + # UPDATE DISABLED_BY TO USER await client.send_json( { "id": 7, "type": "config/entity_registry/update", "entity_id": "test_domain.world", + "disabled_by": "user", + } + ) + + msg = await client.receive_json() + + assert registry.entities["test_domain.world"].disabled_by == "user" + + # UPDATE DISABLED_BY TO NONE + await client.send_json( + { + "id": 8, + "type": "config/entity_registry/update", + "entity_id": "test_domain.world", "disabled_by": None, } ) diff --git a/tests/helpers/test_entity.py b/tests/helpers/test_entity.py index 58f76d396c1..94650592d8e 100644 --- a/tests/helpers/test_entity.py +++ b/tests/helpers/test_entity.py @@ -7,13 +7,13 @@ from unittest.mock import MagicMock, patch, PropertyMock import pytest -import homeassistant.helpers.entity as entity +from homeassistant.helpers import entity, entity_registry from homeassistant.core import Context from homeassistant.const import ATTR_HIDDEN, ATTR_DEVICE_CLASS from homeassistant.config import DATA_CUSTOMIZE from homeassistant.helpers.entity_values import EntityValues -from tests.common import get_test_home_assistant +from tests.common import get_test_home_assistant, mock_registry def test_generate_entity_id_requires_hass_or_ids(): @@ -499,3 +499,30 @@ async def test_set_context_expired(hass): assert hass.states.get("hello.world").context != context assert ent._context is None assert ent._context_set is None + + +async def test_warn_disabled(hass, caplog): + """Test we warn once if we write to a disabled entity.""" + entry = entity_registry.RegistryEntry( + entity_id="hello.world", + unique_id="test-unique-id", + platform="test-platform", + disabled_by="user", + ) + mock_registry(hass, {"hello.world": entry}) + + ent = entity.Entity() + ent.hass = hass + ent.entity_id = "hello.world" + ent.registry_entry = entry + ent.platform = MagicMock(platform_name="test-platform") + + caplog.clear() + ent.async_write_ha_state() + assert hass.states.get("hello.world") is None + assert "Entity hello.world is incorrectly being triggered" in caplog.text + + caplog.clear() + ent.async_write_ha_state() + assert hass.states.get("hello.world") is None + assert caplog.text == "" diff --git a/tests/helpers/test_entity_platform.py b/tests/helpers/test_entity_platform.py index 606a4c82096..caf8bb702af 100644 --- a/tests/helpers/test_entity_platform.py +++ b/tests/helpers/test_entity_platform.py @@ -491,7 +491,7 @@ async def test_registry_respect_entity_disabled(hass): platform = MockEntityPlatform(hass) entity = MockEntity(unique_id="1234") await platform.async_add_entities([entity]) - assert entity.entity_id is None + assert entity.entity_id == "test_domain.world" assert hass.states.async_entity_ids() == [] From 4d656e130ddb7ed45cde7422d8934d14ff653865 Mon Sep 17 00:00:00 2001 From: Paul Annekov Date: Thu, 22 Aug 2019 22:26:08 +0300 Subject: [PATCH 12/40] Fix tuya switch state (#26145) * bump tuyaha 0.0.3 * bump tuyaha 0.0.3 --- homeassistant/components/tuya/manifest.json | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/tuya/manifest.json b/homeassistant/components/tuya/manifest.json index 57eb3f17584..8d47d8a0173 100644 --- a/homeassistant/components/tuya/manifest.json +++ b/homeassistant/components/tuya/manifest.json @@ -3,7 +3,7 @@ "name": "Tuya", "documentation": "https://www.home-assistant.io/components/tuya", "requirements": [ - "tuyaha==0.0.2" + "tuyaha==0.0.3" ], "dependencies": [], "codeowners": [] diff --git a/requirements_all.txt b/requirements_all.txt index a2b91f7eb7d..d3d60e6a43e 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1854,7 +1854,7 @@ tplink==0.2.1 transmissionrpc==0.11 # homeassistant.components.tuya -tuyaha==0.0.2 +tuyaha==0.0.3 # homeassistant.components.twentemilieu twentemilieu==0.1.0 From c7477f00f533922cf8262e7e1a2105d65438d716 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 22 Aug 2019 15:09:26 -0700 Subject: [PATCH 13/40] Bumped version to 0.98.0b1 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index aebcb95c3b1..a2a79eee249 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 98 -PATCH_VERSION = "0b0" +PATCH_VERSION = "0b1" __short_version__ = "{}.{}".format(MAJOR_VERSION, MINOR_VERSION) __version__ = "{}.{}".format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 6, 0) From e4906c277a111b135b5becb241cc0724a3d53bbb Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Fri, 23 Aug 2019 13:55:23 +0200 Subject: [PATCH 14/40] Update azure-pipelines-release.yml for Azure Pipelines --- azure-pipelines-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines-release.yml b/azure-pipelines-release.yml index 6b986329291..2e537fbb774 100644 --- a/azure-pipelines-release.yml +++ b/azure-pipelines-release.yml @@ -198,7 +198,7 @@ stages: } sudo docker pull homeassistant/amd64-homeassistant:$(Build.SourceBranchName) - sudo docker pull homeassistant/i368-homeassistant:$(Build.SourceBranchName) + sudo docker pull homeassistant/i386-homeassistant:$(Build.SourceBranchName) sudo docker pull homeassistant/armhf-homeassistant:$(Build.SourceBranchName) sudo docker pull homeassistant/armv7-homeassistant:$(Build.SourceBranchName) sudo docker pull homeassistant/aarch64-homeassistant:$(Build.SourceBranchName) From 05ed3c44eacba77d631e4da3af78187c9f2f70f9 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 25 Aug 2019 22:24:46 -0700 Subject: [PATCH 15/40] Updated frontend to 20190825.0 --- 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 8d6271183bd..78f87639a99 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/components/frontend", "requirements": [ - "home-assistant-frontend==20190822.0" + "home-assistant-frontend==20190825.0" ], "dependencies": [ "api", diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 0f4fb56970b..873a5aaf31d 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -11,7 +11,7 @@ contextvars==2.4;python_version<"3.7" cryptography==2.7 distro==1.4.0 hass-nabucasa==0.17 -home-assistant-frontend==20190822.0 +home-assistant-frontend==20190825.0 importlib-metadata==0.19 jinja2>=2.10.1 netdisco==2.6.0 diff --git a/requirements_all.txt b/requirements_all.txt index d3d60e6a43e..c9475f4b65b 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -624,7 +624,7 @@ hole==0.5.0 holidays==0.9.11 # homeassistant.components.frontend -home-assistant-frontend==20190822.0 +home-assistant-frontend==20190825.0 # homeassistant.components.zwave homeassistant-pyozw==0.1.4 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index b5d139719ef..50f49296247 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -176,7 +176,7 @@ hdate==0.9.0 holidays==0.9.11 # homeassistant.components.frontend -home-assistant-frontend==20190822.0 +home-assistant-frontend==20190825.0 # homeassistant.components.homekit_controller homekit[IP]==0.15.0 From 65cf5a6ef5cf877666e24fb365978b6577e6d81e Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 22 Aug 2019 17:32:43 -0700 Subject: [PATCH 16/40] Reload config entry when entity enabled in entity registry, remove entity if disabled. (#26120) * Reload config entry when disabled_by updated in entity registry * Add types * Remove entities that get disabled * Remove unnecessary domain checks. * Attach handler in async_setup * Remove unused var * Type * Fix test * Fix tests --- homeassistant/config_entries.py | 116 ++++++++++++++++-- homeassistant/helpers/entity.py | 4 + homeassistant/helpers/entity_registry.py | 2 +- .../components/config/test_entity_registry.py | 1 + tests/helpers/test_entity.py | 31 +++++ tests/helpers/test_entity_registry.py | 1 + tests/test_config_entries.py | 76 ++++++++++++ 7 files changed, 219 insertions(+), 12 deletions(-) diff --git a/homeassistant/config_entries.py b/homeassistant/config_entries.py index 2e1fbea14d1..c2da37943c1 100644 --- a/homeassistant/config_entries.py +++ b/homeassistant/config_entries.py @@ -3,13 +3,7 @@ import asyncio import logging import functools import uuid -from typing import ( - Any, - Callable, - List, - Optional, - Set, # noqa pylint: disable=unused-import -) +from typing import Any, Callable, List, Optional, Set import weakref import attr @@ -19,6 +13,7 @@ from homeassistant.core import callback, HomeAssistant from homeassistant.exceptions import HomeAssistantError, ConfigEntryNotReady from homeassistant.setup import async_setup_component, async_process_deps_reqs from homeassistant.util.decorator import Registry +from homeassistant.helpers import entity_registry # mypy: allow-untyped-defs @@ -161,8 +156,6 @@ class ConfigEntry: try: component = integration.get_component() - if self.domain == integration.domain: - integration.get_platform("config_flow") except ImportError as err: _LOGGER.error( "Error importing integration %s to set up %s config entry: %s", @@ -174,8 +167,20 @@ class ConfigEntry: self.state = ENTRY_STATE_SETUP_ERROR return - # Perform migration - if integration.domain == self.domain: + if self.domain == integration.domain: + try: + integration.get_platform("config_flow") + except ImportError as err: + _LOGGER.error( + "Error importing platform config_flow from integration %s to set up %s config entry: %s", + integration.domain, + self.domain, + err, + ) + self.state = ENTRY_STATE_SETUP_ERROR + return + + # Perform migration if not await self.async_migrate(hass): self.state = ENTRY_STATE_MIGRATION_ERROR return @@ -383,6 +388,7 @@ class ConfigEntries: self._hass_config = hass_config self._entries = [] # type: List[ConfigEntry] self._store = hass.helpers.storage.Store(STORAGE_VERSION, STORAGE_KEY) + EntityRegistryDisabledHandler(hass).async_setup() @callback def async_domains(self) -> List[str]: @@ -757,3 +763,91 @@ class SystemOptions: def as_dict(self): """Return dictionary version of this config entrys system options.""" return {"disable_new_entities": self.disable_new_entities} + + +class EntityRegistryDisabledHandler: + """Handler to handle when entities related to config entries updating disabled_by.""" + + RELOAD_AFTER_UPDATE_DELAY = 30 + + def __init__(self, hass: HomeAssistant) -> None: + """Initialize the handler.""" + self.hass = hass + self.registry: Optional[entity_registry.EntityRegistry] = None + self.changed: Set[str] = set() + self._remove_call_later: Optional[Callable[[], None]] = None + + @callback + def async_setup(self) -> None: + """Set up the disable handler.""" + self.hass.bus.async_listen( + entity_registry.EVENT_ENTITY_REGISTRY_UPDATED, self._handle_entry_updated + ) + + async def _handle_entry_updated(self, event): + """Handle entity registry entry update.""" + if ( + event.data["action"] != "update" + or "disabled_by" not in event.data["changes"] + ): + return + + if self.registry is None: + self.registry = await entity_registry.async_get_registry(self.hass) + + entity_entry = self.registry.async_get(event.data["entity_id"]) + + if ( + # Stop if no entry found + entity_entry is None + # Stop if entry not connected to config entry + or entity_entry.config_entry_id is None + # Stop if the entry got disabled. In that case the entity handles it + # themselves. + or entity_entry.disabled_by + ): + return + + config_entry = self.hass.config_entries.async_get_entry( + entity_entry.config_entry_id + ) + + if config_entry.entry_id not in self.changed and await support_entry_unload( + self.hass, config_entry.domain + ): + self.changed.add(config_entry.entry_id) + + if not self.changed: + return + + # We are going to delay reloading on *every* entity registry change so that + # if a user is happily clicking along, it will only reload at the end. + + if self._remove_call_later: + self._remove_call_later() + + self._remove_call_later = self.hass.helpers.event.async_call_later( + self.RELOAD_AFTER_UPDATE_DELAY, self._handle_reload + ) + + async def _handle_reload(self, _now): + """Handle a reload.""" + self._remove_call_later = None + to_reload = self.changed + self.changed = set() + + _LOGGER.info( + "Reloading config entries because disabled_by changed in entity registry: %s", + ", ".join(self.changed), + ) + + await asyncio.gather( + *[self.hass.config_entries.async_reload(entry_id) for entry_id in to_reload] + ) + + +async def support_entry_unload(hass: HomeAssistant, domain: str) -> bool: + """Test if a domain supports entry unloading.""" + integration = await loader.async_get_integration(hass, domain) + component = integration.get_component() + return hasattr(component, "async_unload_entry") diff --git a/homeassistant/helpers/entity.py b/homeassistant/helpers/entity.py index 7de41415f08..bd96e1bafdb 100644 --- a/homeassistant/helpers/entity.py +++ b/homeassistant/helpers/entity.py @@ -503,6 +503,10 @@ class Entity: old = self.registry_entry self.registry_entry = ent_reg.async_get(data["entity_id"]) + if self.registry_entry.disabled_by is not None: + await self.async_remove() + return + if self.registry_entry.entity_id == old.entity_id: self.async_write_ha_state() return diff --git a/homeassistant/helpers/entity_registry.py b/homeassistant/helpers/entity_registry.py index 3d84313a5c6..7d81f62fa1c 100644 --- a/homeassistant/helpers/entity_registry.py +++ b/homeassistant/helpers/entity_registry.py @@ -302,7 +302,7 @@ class EntityRegistry: self.async_schedule_save() - data = {"action": "update", "entity_id": entity_id} + data = {"action": "update", "entity_id": entity_id, "changes": list(changes)} if old.entity_id != entity_id: data["old_entity_id"] = old.entity_id diff --git a/tests/components/config/test_entity_registry.py b/tests/components/config/test_entity_registry.py index 64328a0c8c5..9472d888254 100644 --- a/tests/components/config/test_entity_registry.py +++ b/tests/components/config/test_entity_registry.py @@ -163,6 +163,7 @@ async def test_update_entity(hass, client): msg = await client.receive_json() + assert hass.states.get("test_domain.world") is None assert registry.entities["test_domain.world"].disabled_by == "user" # UPDATE DISABLED_BY TO NONE diff --git a/tests/helpers/test_entity.py b/tests/helpers/test_entity.py index 94650592d8e..3c89a5c6537 100644 --- a/tests/helpers/test_entity.py +++ b/tests/helpers/test_entity.py @@ -526,3 +526,34 @@ async def test_warn_disabled(hass, caplog): ent.async_write_ha_state() assert hass.states.get("hello.world") is None assert caplog.text == "" + + +async def test_disabled_in_entity_registry(hass): + """Test entity is removed if we disable entity registry entry.""" + entry = entity_registry.RegistryEntry( + entity_id="hello.world", + unique_id="test-unique-id", + platform="test-platform", + disabled_by="user", + ) + registry = mock_registry(hass, {"hello.world": entry}) + + ent = entity.Entity() + ent.hass = hass + ent.entity_id = "hello.world" + ent.registry_entry = entry + ent.platform = MagicMock(platform_name="test-platform") + + await ent.async_internal_added_to_hass() + ent.async_write_ha_state() + assert hass.states.get("hello.world") is None + + entry2 = registry.async_update_entity("hello.world", disabled_by=None) + await hass.async_block_till_done() + assert entry2 != entry + assert ent.registry_entry == entry2 + + entry3 = registry.async_update_entity("hello.world", disabled_by="user") + await hass.async_block_till_done() + assert entry3 != entry2 + assert ent.registry_entry == entry3 diff --git a/tests/helpers/test_entity_registry.py b/tests/helpers/test_entity_registry.py index aee6b6f19a3..9debbdbcba7 100644 --- a/tests/helpers/test_entity_registry.py +++ b/tests/helpers/test_entity_registry.py @@ -219,6 +219,7 @@ async def test_updating_config_entry_id(hass, registry, update_events): assert update_events[0]["entity_id"] == entry.entity_id assert update_events[1]["action"] == "update" assert update_events[1]["entity_id"] == entry.entity_id + assert update_events[1]["changes"] == ["config_entry_id"] async def test_removing_config_entry_id(hass, registry, update_events): diff --git a/tests/test_config_entries.py b/tests/test_config_entries.py index ca6872a7a2c..d9dd614c9a5 100644 --- a/tests/test_config_entries.py +++ b/tests/test_config_entries.py @@ -20,6 +20,7 @@ from tests.common import ( MockEntity, mock_integration, mock_entity_platform, + mock_registry, ) @@ -925,3 +926,78 @@ async def test_init_custom_integration(hass): return_value=mock_coro(integration), ): await hass.config_entries.flow.async_init("bla") + + +async def test_support_entry_unload(hass): + """Test unloading entry.""" + assert await config_entries.support_entry_unload(hass, "light") + assert not await config_entries.support_entry_unload(hass, "auth") + + +async def test_reload_entry_entity_registry_ignores_no_entry(hass): + """Test reloading entry in entity registry skips if no config entry linked.""" + handler = config_entries.EntityRegistryDisabledHandler(hass) + registry = mock_registry(hass) + + # Test we ignore entities without config entry + entry = registry.async_get_or_create("light", "hue", "123") + registry.async_update_entity(entry.entity_id, disabled_by="user") + await hass.async_block_till_done() + assert not handler.changed + assert handler._remove_call_later is None + + +async def test_reload_entry_entity_registry_works(hass): + """Test we schedule an entry to be reloaded if disabled_by is updated.""" + handler = config_entries.EntityRegistryDisabledHandler(hass) + handler.async_setup() + registry = mock_registry(hass) + + config_entry = MockConfigEntry( + domain="comp", state=config_entries.ENTRY_STATE_LOADED + ) + config_entry.add_to_hass(hass) + mock_setup_entry = MagicMock(return_value=mock_coro(True)) + mock_unload_entry = MagicMock(return_value=mock_coro(True)) + mock_integration( + hass, + MockModule( + "comp", + async_setup_entry=mock_setup_entry, + async_unload_entry=mock_unload_entry, + ), + ) + mock_entity_platform(hass, "config_flow.comp", None) + + # Only changing disabled_by should update trigger + entity_entry = registry.async_get_or_create( + "light", "hue", "123", config_entry=config_entry + ) + registry.async_update_entity(entity_entry.entity_id, name="yo") + await hass.async_block_till_done() + assert not handler.changed + assert handler._remove_call_later is None + + # Disable entity, we should not do anything, only act when enabled. + registry.async_update_entity(entity_entry.entity_id, disabled_by="user") + await hass.async_block_till_done() + assert not handler.changed + assert handler._remove_call_later is None + + # Enable entity, check we are reloading config entry. + registry.async_update_entity(entity_entry.entity_id, disabled_by=None) + await hass.async_block_till_done() + assert handler.changed == {config_entry.entry_id} + assert handler._remove_call_later is not None + + async_fire_time_changed( + hass, + dt.utcnow() + + timedelta( + seconds=config_entries.EntityRegistryDisabledHandler.RELOAD_AFTER_UPDATE_DELAY + + 1 + ), + ) + await hass.async_block_till_done() + + assert len(mock_unload_entry.mock_calls) == 1 From 45a454ba535a884191987732aad2a52c678a0281 Mon Sep 17 00:00:00 2001 From: On Freund Date: Fri, 23 Aug 2019 16:59:25 +0300 Subject: [PATCH 17/40] CoolMaster: Change auto to heat_cool (#26144) --- homeassistant/components/coolmaster/climate.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/coolmaster/climate.py b/homeassistant/components/coolmaster/climate.py index 7379d66777b..8a319c655f6 100644 --- a/homeassistant/components/coolmaster/climate.py +++ b/homeassistant/components/coolmaster/climate.py @@ -7,7 +7,7 @@ import voluptuous as vol from homeassistant.components.climate import ClimateDevice, PLATFORM_SCHEMA from homeassistant.components.climate.const import ( HVAC_MODE_OFF, - HVAC_MODE_AUTO, + HVAC_MODE_HEAT_COOL, HVAC_MODE_COOL, HVAC_MODE_DRY, HVAC_MODE_FAN_ONLY, @@ -33,14 +33,14 @@ AVAILABLE_MODES = [ HVAC_MODE_HEAT, HVAC_MODE_COOL, HVAC_MODE_DRY, - HVAC_MODE_AUTO, + HVAC_MODE_HEAT_COOL, HVAC_MODE_FAN_ONLY, ] CM_TO_HA_STATE = { "heat": HVAC_MODE_HEAT, "cool": HVAC_MODE_COOL, - "auto": HVAC_MODE_AUTO, + "auto": HVAC_MODE_HEAT_COOL, "dry": HVAC_MODE_DRY, "fan": HVAC_MODE_FAN_ONLY, } From ee03f5d7c1445fafeac643efe5fc028b0619b3e1 Mon Sep 17 00:00:00 2001 From: Jeff Irion Date: Fri, 23 Aug 2019 06:58:24 -0700 Subject: [PATCH 18/40] Bump androidtv to 0.0.24 (#26158) * Bump androidtv to 0.0.24 * Add unique ID for Fire TV (not just Android TV) --- homeassistant/components/androidtv/manifest.json | 2 +- .../components/androidtv/media_player.py | 15 ++++++++------- requirements_all.txt | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/androidtv/manifest.json b/homeassistant/components/androidtv/manifest.json index 24eb61d52b0..047eaaaf5db 100644 --- a/homeassistant/components/androidtv/manifest.json +++ b/homeassistant/components/androidtv/manifest.json @@ -3,7 +3,7 @@ "name": "Androidtv", "documentation": "https://www.home-assistant.io/components/androidtv", "requirements": [ - "androidtv==0.0.23" + "androidtv==0.0.24" ], "dependencies": [], "codeowners": ["@JeffLIrion"] diff --git a/homeassistant/components/androidtv/media_player.py b/homeassistant/components/androidtv/media_player.py index ef9293381fd..db4ff9e851e 100644 --- a/homeassistant/components/androidtv/media_player.py +++ b/homeassistant/components/androidtv/media_player.py @@ -270,6 +270,9 @@ class ADBDevice(MediaPlayerDevice): self._apps.update(apps) self._keys = KEYS + self._device_properties = self.aftv.device_properties + self._unique_id = self._device_properties.get("serialno") + self.turn_on_command = turn_on_command self.turn_off_command = turn_off_command @@ -338,6 +341,11 @@ class ADBDevice(MediaPlayerDevice): """Return the state of the player.""" return self._state + @property + def unique_id(self): + """Return the device unique id.""" + return self._unique_id + @adb_decorator() def media_play(self): """Send play command.""" @@ -412,9 +420,7 @@ class AndroidTVDevice(ADBDevice): super().__init__(aftv, name, apps, turn_on_command, turn_off_command) self._device = None - self._device_properties = self.aftv.device_properties self._is_volume_muted = None - self._unique_id = self._device_properties.get("serialno") self._volume_level = None @adb_decorator(override_available=True) @@ -454,11 +460,6 @@ class AndroidTVDevice(ADBDevice): """Flag media player features that are supported.""" return SUPPORT_ANDROIDTV - @property - def unique_id(self): - """Return the device unique id.""" - return self._unique_id - @property def volume_level(self): """Return the volume level.""" diff --git a/requirements_all.txt b/requirements_all.txt index c9475f4b65b..70483d1f2e2 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -194,7 +194,7 @@ ambiclimate==0.2.0 amcrest==1.5.3 # homeassistant.components.androidtv -androidtv==0.0.23 +androidtv==0.0.24 # homeassistant.components.anel_pwrctrl anel_pwrctrl-homeassistant==0.0.1.dev2 From b64ac5be8564d8d11778e1b64fcb46293985bd2c Mon Sep 17 00:00:00 2001 From: Chao Date: Fri, 23 Aug 2019 13:14:18 -0400 Subject: [PATCH 19/40] fix issue setting scan_interval (#26165) I was getting the following error when i set the scan_interval ``` self.scan_interval = timedelta(seconds=config.get(CONF_SCAN_INTERVAL, 60)) TypeError: unsupported type for timedelta seconds component: datetime.timedelta ``` it turns out `config.get(CONF_SCAN_INTERVAL)` already returns `timedelta` ```('scan_interval', datetime.timedelta(seconds=180))``` --- homeassistant/components/google_maps/device_tracker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/google_maps/device_tracker.py b/homeassistant/components/google_maps/device_tracker.py index 0887aa19bfb..2149e40e504 100644 --- a/homeassistant/components/google_maps/device_tracker.py +++ b/homeassistant/components/google_maps/device_tracker.py @@ -52,7 +52,7 @@ class GoogleMapsScanner: self.see = see self.username = config[CONF_USERNAME] self.max_gps_accuracy = config[CONF_MAX_GPS_ACCURACY] - self.scan_interval = timedelta(seconds=config.get(CONF_SCAN_INTERVAL, 60)) + self.scan_interval = config.get(CONF_SCAN_INTERVAL) or timedelta(60) credfile = "{}.{}".format( hass.config.path(CREDENTIALS_FILE), slugify(self.username) From afab0a956822e6035222ac3843293aa3041a4ae2 Mon Sep 17 00:00:00 2001 From: Aaron Bach Date: Sat, 24 Aug 2019 18:18:31 -0600 Subject: [PATCH 20/40] Fix possible KeyError in SimpliSafe (#26190) --- homeassistant/components/simplisafe/alarm_control_panel.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/simplisafe/alarm_control_panel.py b/homeassistant/components/simplisafe/alarm_control_panel.py index 028121a9663..d44a1c7760a 100644 --- a/homeassistant/components/simplisafe/alarm_control_panel.py +++ b/homeassistant/components/simplisafe/alarm_control_panel.py @@ -170,7 +170,7 @@ class SimpliSafeAlarm(AlarmControlPanel): """Update alarm status.""" event_data = self._simplisafe.last_event_data[self._system.system_id] - if event_data["pinName"]: + if event_data.get("pinName"): self._changed_by = event_data["pinName"] if self._system.state == SystemStates.error: From 677995a05a604efb44730164e1c1e57d4a7d79c4 Mon Sep 17 00:00:00 2001 From: Andrew Sayre <6730289+andrewsayre@users.noreply.github.com> Date: Sun, 25 Aug 2019 13:57:43 -0500 Subject: [PATCH 21/40] Update pyheos to 0.6.0 (#26191) --- homeassistant/components/heos/__init__.py | 26 ++++-------- homeassistant/components/heos/config_flow.py | 6 +-- homeassistant/components/heos/manifest.json | 4 +- homeassistant/components/heos/media_player.py | 10 +---- homeassistant/components/heos/services.py | 9 ++--- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/heos/test_config_flow.py | 23 +++++------ tests/components/heos/test_init.py | 40 +++++++++---------- tests/components/heos/test_media_player.py | 28 ++++++------- tests/components/heos/test_services.py | 8 ++-- 11 files changed, 66 insertions(+), 92 deletions(-) diff --git a/homeassistant/components/heos/__init__.py b/homeassistant/components/heos/__init__.py index a5450253be0..20ed7930a4f 100644 --- a/homeassistant/components/heos/__init__.py +++ b/homeassistant/components/heos/__init__.py @@ -4,7 +4,7 @@ from datetime import timedelta import logging from typing import Dict -from pyheos import CommandError, Heos, const as heos_const +from pyheos import Heos, HeosError, const as heos_const import voluptuous as vol from homeassistant.components.media_player.const import DOMAIN as MEDIA_PLAYER_DOMAIN @@ -68,7 +68,7 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry): try: await controller.connect(auto_reconnect=True) # Auto reconnect only operates if initial connection was successful. - except (asyncio.TimeoutError, ConnectionError, CommandError) as error: + except HeosError as error: await controller.disconnect() _LOGGER.debug("Unable to connect to controller %s: %s", host, error) raise ConfigEntryNotReady @@ -93,13 +93,9 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry): host, ) inputs = await controller.get_input_sources() - except (asyncio.TimeoutError, ConnectionError, CommandError) as error: + except HeosError as error: await controller.disconnect() - _LOGGER.debug( - "Unable to retrieve players and sources: %s", - error, - exc_info=isinstance(error, CommandError), - ) + _LOGGER.debug("Unable to retrieve players and sources: %s", error) raise ConfigEntryNotReady controller_manager = ControllerManager(hass, controller) @@ -187,7 +183,7 @@ class ControllerManager: # Retrieve latest players and refresh status data = await self.controller.load_players() self.update_ids(data[heos_const.DATA_MAPPED_IDS]) - except (CommandError, asyncio.TimeoutError, ConnectionError) as ex: + except HeosError as ex: _LOGGER.error("Unable to refresh players: %s", ex) # Update players self._hass.helpers.dispatcher.async_dispatcher_send(SIGNAL_HEOS_UPDATED) @@ -312,21 +308,15 @@ class SourceManager: favorites = await controller.get_favorites() inputs = await controller.get_input_sources() return favorites, inputs - except (asyncio.TimeoutError, ConnectionError, CommandError) as error: + except HeosError as error: if retry_attempts < self.max_retry_attempts: retry_attempts += 1 _LOGGER.debug( - "Error retrieving sources and will " "retry: %s", - error, - exc_info=isinstance(error, CommandError), + "Error retrieving sources and will " "retry: %s", error ) await asyncio.sleep(self.retry_delay) else: - _LOGGER.error( - "Unable to update sources: %s", - error, - exc_info=isinstance(error, CommandError), - ) + _LOGGER.error("Unable to update sources: %s", error) return async def update_sources(event, data=None): diff --git a/homeassistant/components/heos/config_flow.py b/homeassistant/components/heos/config_flow.py index 7c7f57a91d7..1d56478ba3a 100644 --- a/homeassistant/components/heos/config_flow.py +++ b/homeassistant/components/heos/config_flow.py @@ -1,7 +1,5 @@ """Config flow to configure Heos.""" -import asyncio - -from pyheos import Heos +from pyheos import Heos, HeosError import voluptuous as vol from homeassistant import config_entries @@ -59,7 +57,7 @@ class HeosFlowHandler(config_entries.ConfigFlow): await heos.connect() self.hass.data.pop(DATA_DISCOVERED_HOSTS) return await self.async_step_import({CONF_HOST: host}) - except (asyncio.TimeoutError, ConnectionError): + except HeosError: errors[CONF_HOST] = "connection_failure" finally: await heos.disconnect() diff --git a/homeassistant/components/heos/manifest.json b/homeassistant/components/heos/manifest.json index 09833bb729b..eb9ef258a3c 100644 --- a/homeassistant/components/heos/manifest.json +++ b/homeassistant/components/heos/manifest.json @@ -4,7 +4,7 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/components/heos", "requirements": [ - "pyheos==0.5.2" + "pyheos==0.6.0" ], "ssdp": { "st": [ @@ -15,4 +15,4 @@ "codeowners": [ "@andrewsayre" ] -} +} \ No newline at end of file diff --git a/homeassistant/components/heos/media_player.py b/homeassistant/components/heos/media_player.py index a4094a0c216..40f6113a80d 100644 --- a/homeassistant/components/heos/media_player.py +++ b/homeassistant/components/heos/media_player.py @@ -1,11 +1,10 @@ """Denon HEOS Media Player.""" -import asyncio from functools import reduce, wraps import logging from operator import ior from typing import Sequence -from pyheos import CommandError, const as heos_const +from pyheos import HeosError, const as heos_const from homeassistant.components.media_player import MediaPlayerDevice from homeassistant.components.media_player.const import ( @@ -83,12 +82,7 @@ def log_command_error(command: str): async def wrapper(*args, **kwargs): try: await func(*args, **kwargs) - except ( - CommandError, - asyncio.TimeoutError, - ConnectionError, - ValueError, - ) as ex: + except (HeosError, ValueError) as ex: _LOGGER.error("Unable to %s: %s", command, ex) return wrapper diff --git a/homeassistant/components/heos/services.py b/homeassistant/components/heos/services.py index 8f3521399e2..ee5df1b483b 100644 --- a/homeassistant/components/heos/services.py +++ b/homeassistant/components/heos/services.py @@ -1,9 +1,8 @@ """Services for the HEOS integration.""" -import asyncio import functools import logging -from pyheos import CommandError, Heos, const +from pyheos import CommandFailedError, Heos, HeosError, const import voluptuous as vol from homeassistant.helpers import config_validation as cv @@ -57,9 +56,9 @@ async def _sign_in_handler(controller, service): password = service.data[ATTR_PASSWORD] try: await controller.sign_in(username, password) - except CommandError as err: + except CommandFailedError as err: _LOGGER.error("Sign in failed: %s", err) - except (asyncio.TimeoutError, ConnectionError) as err: + except HeosError as err: _LOGGER.error("Unable to sign in: %s", err) @@ -70,5 +69,5 @@ async def _sign_out_handler(controller, service): return try: await controller.sign_out() - except (asyncio.TimeoutError, ConnectionError, CommandError) as err: + except HeosError as err: _LOGGER.error("Unable to sign out: %s", err) diff --git a/requirements_all.txt b/requirements_all.txt index 70483d1f2e2..b467859343f 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1186,7 +1186,7 @@ pygtt==1.1.2 pyhaversion==3.0.2 # homeassistant.components.heos -pyheos==0.5.2 +pyheos==0.6.0 # homeassistant.components.hikvision pyhik==0.2.3 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 50f49296247..96b82caf968 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -277,7 +277,7 @@ pydeconz==62 pydispatcher==2.0.5 # homeassistant.components.heos -pyheos==0.5.2 +pyheos==0.6.0 # homeassistant.components.homematic pyhomematic==0.1.60 diff --git a/tests/components/heos/test_config_flow.py b/tests/components/heos/test_config_flow.py index 0d834ccc770..df021fea55d 100644 --- a/tests/components/heos/test_config_flow.py +++ b/tests/components/heos/test_config_flow.py @@ -1,5 +1,5 @@ """Tests for the Heos config flow module.""" -import asyncio +from pyheos import HeosError from homeassistant import data_entry_flow from homeassistant.components.heos.config_flow import HeosFlowHandler @@ -31,18 +31,15 @@ async def test_cannot_connect_shows_error_form(hass, controller): """Test form is shown with error when cannot connect.""" flow = HeosFlowHandler() flow.hass = hass - - errors = [ConnectionError, asyncio.TimeoutError] - for error in errors: - controller.connect.side_effect = error - result = await flow.async_step_user({CONF_HOST: "127.0.0.1"}) - assert result["type"] == data_entry_flow.RESULT_TYPE_FORM - assert result["step_id"] == "user" - assert result["errors"][CONF_HOST] == "connection_failure" - assert controller.connect.call_count == 1 - assert controller.disconnect.call_count == 1 - controller.connect.reset_mock() - controller.disconnect.reset_mock() + controller.connect.side_effect = HeosError() + result = await flow.async_step_user({CONF_HOST: "127.0.0.1"}) + assert result["type"] == data_entry_flow.RESULT_TYPE_FORM + assert result["step_id"] == "user" + assert result["errors"][CONF_HOST] == "connection_failure" + assert controller.connect.call_count == 1 + assert controller.disconnect.call_count == 1 + controller.connect.reset_mock() + controller.disconnect.reset_mock() async def test_create_entry_when_host_valid(hass, controller): diff --git a/tests/components/heos/test_init.py b/tests/components/heos/test_init.py index 728e65b81f5..7b2645cb8ec 100644 --- a/tests/components/heos/test_init.py +++ b/tests/components/heos/test_init.py @@ -2,7 +2,7 @@ import asyncio from asynctest import Mock, patch -from pyheos import CommandError, const +from pyheos import CommandFailedError, HeosError, const import pytest from homeassistant.components.heos import ( @@ -117,31 +117,27 @@ async def test_async_setup_entry_not_signed_in_loads_platforms( async def test_async_setup_entry_connect_failure(hass, config_entry, controller): """Connection failure raises ConfigEntryNotReady.""" config_entry.add_to_hass(hass) - errors = [ConnectionError, asyncio.TimeoutError] - for error in errors: - controller.connect.side_effect = error - with pytest.raises(ConfigEntryNotReady): - await async_setup_entry(hass, config_entry) - await hass.async_block_till_done() - assert controller.connect.call_count == 1 - assert controller.disconnect.call_count == 1 - controller.connect.reset_mock() - controller.disconnect.reset_mock() + controller.connect.side_effect = HeosError() + with pytest.raises(ConfigEntryNotReady): + await async_setup_entry(hass, config_entry) + await hass.async_block_till_done() + assert controller.connect.call_count == 1 + assert controller.disconnect.call_count == 1 + controller.connect.reset_mock() + controller.disconnect.reset_mock() async def test_async_setup_entry_player_failure(hass, config_entry, controller): """Failure to retrieve players/sources raises ConfigEntryNotReady.""" config_entry.add_to_hass(hass) - errors = [ConnectionError, asyncio.TimeoutError] - for error in errors: - controller.get_players.side_effect = error - with pytest.raises(ConfigEntryNotReady): - await async_setup_entry(hass, config_entry) - await hass.async_block_till_done() - assert controller.connect.call_count == 1 - assert controller.disconnect.call_count == 1 - controller.connect.reset_mock() - controller.disconnect.reset_mock() + controller.get_players.side_effect = HeosError() + with pytest.raises(ConfigEntryNotReady): + await async_setup_entry(hass, config_entry) + await hass.async_block_till_done() + assert controller.connect.call_count == 1 + assert controller.disconnect.call_count == 1 + controller.connect.reset_mock() + controller.disconnect.reset_mock() async def test_unload_entry(hass, config_entry, controller): @@ -167,7 +163,7 @@ async def test_update_sources_retry(hass, config_entry, config, controller, capl source_manager = hass.data[DOMAIN][DATA_SOURCE_MANAGER] source_manager.retry_delay = 0 source_manager.max_retry_attempts = 1 - controller.get_favorites.side_effect = CommandError("Test", "test", 0) + controller.get_favorites.side_effect = CommandFailedError("Test", "test", 0) controller.dispatcher.send( const.SIGNAL_CONTROLLER_EVENT, const.EVENT_SOURCES_CHANGED, {} ) diff --git a/tests/components/heos/test_media_player.py b/tests/components/heos/test_media_player.py index de062757803..0f9bf2d8b3e 100644 --- a/tests/components/heos/test_media_player.py +++ b/tests/components/heos/test_media_player.py @@ -1,7 +1,7 @@ """Tests for the Heos Media Player platform.""" import asyncio -from pyheos import CommandError, const +from pyheos import CommandFailedError, const from homeassistant.components.heos import media_player from homeassistant.components.heos.const import ( @@ -179,7 +179,7 @@ async def test_updates_from_connection_event( event.clear() player.reset_mock() controller.load_players.reset_mock() - controller.load_players.side_effect = CommandError(None, "Failure", 1) + controller.load_players.side_effect = CommandFailedError(None, "Failure", 1) player.available = True player.heos.dispatcher.send(const.SIGNAL_HEOS_EVENT, const.EVENT_CONNECTED) await event.wait() @@ -313,7 +313,7 @@ async def test_clear_playlist(hass, config_entry, config, controller, caplog): ) assert player.clear_queue.call_count == 1 player.clear_queue.reset_mock() - player.clear_queue.side_effect = CommandError(None, "Failure", 1) + player.clear_queue.side_effect = CommandFailedError(None, "Failure", 1) assert "Unable to clear playlist: Failure (1)" in caplog.text @@ -331,7 +331,7 @@ async def test_pause(hass, config_entry, config, controller, caplog): ) assert player.pause.call_count == 1 player.pause.reset_mock() - player.pause.side_effect = CommandError(None, "Failure", 1) + player.pause.side_effect = CommandFailedError(None, "Failure", 1) assert "Unable to pause: Failure (1)" in caplog.text @@ -349,7 +349,7 @@ async def test_play(hass, config_entry, config, controller, caplog): ) assert player.play.call_count == 1 player.play.reset_mock() - player.play.side_effect = CommandError(None, "Failure", 1) + player.play.side_effect = CommandFailedError(None, "Failure", 1) assert "Unable to play: Failure (1)" in caplog.text @@ -367,7 +367,7 @@ async def test_previous_track(hass, config_entry, config, controller, caplog): ) assert player.play_previous.call_count == 1 player.play_previous.reset_mock() - player.play_previous.side_effect = CommandError(None, "Failure", 1) + player.play_previous.side_effect = CommandFailedError(None, "Failure", 1) assert "Unable to move to previous track: Failure (1)" in caplog.text @@ -385,7 +385,7 @@ async def test_next_track(hass, config_entry, config, controller, caplog): ) assert player.play_next.call_count == 1 player.play_next.reset_mock() - player.play_next.side_effect = CommandError(None, "Failure", 1) + player.play_next.side_effect = CommandFailedError(None, "Failure", 1) assert "Unable to move to next track: Failure (1)" in caplog.text @@ -403,7 +403,7 @@ async def test_stop(hass, config_entry, config, controller, caplog): ) assert player.stop.call_count == 1 player.stop.reset_mock() - player.stop.side_effect = CommandError(None, "Failure", 1) + player.stop.side_effect = CommandFailedError(None, "Failure", 1) assert "Unable to stop: Failure (1)" in caplog.text @@ -421,7 +421,7 @@ async def test_volume_mute(hass, config_entry, config, controller, caplog): ) assert player.set_mute.call_count == 1 player.set_mute.reset_mock() - player.set_mute.side_effect = CommandError(None, "Failure", 1) + player.set_mute.side_effect = CommandFailedError(None, "Failure", 1) assert "Unable to set mute: Failure (1)" in caplog.text @@ -439,7 +439,7 @@ async def test_shuffle_set(hass, config_entry, config, controller, caplog): ) player.set_play_mode.assert_called_once_with(player.repeat, True) player.set_play_mode.reset_mock() - player.set_play_mode.side_effect = CommandError(None, "Failure", 1) + player.set_play_mode.side_effect = CommandFailedError(None, "Failure", 1) assert "Unable to set shuffle: Failure (1)" in caplog.text @@ -457,7 +457,7 @@ async def test_volume_set(hass, config_entry, config, controller, caplog): ) player.set_volume.assert_called_once_with(100) player.set_volume.reset_mock() - player.set_volume.side_effect = CommandError(None, "Failure", 1) + player.set_volume.side_effect = CommandFailedError(None, "Failure", 1) assert "Unable to set volume level: Failure (1)" in caplog.text @@ -516,7 +516,7 @@ async def test_select_radio_favorite_command_error( player = controller.players[1] # Test set radio preset favorite = favorites[2] - player.play_favorite.side_effect = CommandError(None, "Failure", 1) + player.play_favorite.side_effect = CommandFailedError(None, "Failure", 1) await hass.services.async_call( MEDIA_PLAYER_DOMAIN, SERVICE_SELECT_SOURCE, @@ -575,7 +575,7 @@ async def test_select_input_command_error( await setup_platform(hass, config_entry, config) player = controller.players[1] input_source = input_sources[0] - player.play_input_source.side_effect = CommandError(None, "Failure", 1) + player.play_input_source.side_effect = CommandFailedError(None, "Failure", 1) await hass.services.async_call( MEDIA_PLAYER_DOMAIN, SERVICE_SELECT_SOURCE, @@ -615,7 +615,7 @@ async def test_play_media_url(hass, config_entry, config, controller, caplog): ) player.play_url.assert_called_once_with(url) player.play_url.reset_mock() - player.play_url.side_effect = CommandError(None, "Failure", 1) + player.play_url.side_effect = CommandFailedError(None, "Failure", 1) assert "Unable to play media: Failure (1)" in caplog.text diff --git a/tests/components/heos/test_services.py b/tests/components/heos/test_services.py index 0e1cbc8ea2e..5a835cf7303 100644 --- a/tests/components/heos/test_services.py +++ b/tests/components/heos/test_services.py @@ -1,5 +1,5 @@ """Tests for the services module.""" -from pyheos import CommandError, const +from pyheos import CommandFailedError, HeosError, const from homeassistant.components.heos.const import ( ATTR_PASSWORD, @@ -51,7 +51,7 @@ async def test_sign_in_not_connected(hass, config_entry, controller, caplog): async def test_sign_in_failed(hass, config_entry, controller, caplog): """Test sign-in service logs error when not connected.""" await setup_component(hass, config_entry) - controller.sign_in.side_effect = CommandError("", "Invalid credentials", 6) + controller.sign_in.side_effect = CommandFailedError("", "Invalid credentials", 6) await hass.services.async_call( DOMAIN, @@ -67,7 +67,7 @@ async def test_sign_in_failed(hass, config_entry, controller, caplog): async def test_sign_in_unknown_error(hass, config_entry, controller, caplog): """Test sign-in service logs error for failure.""" await setup_component(hass, config_entry) - controller.sign_in.side_effect = ConnectionError + controller.sign_in.side_effect = HeosError() await hass.services.async_call( DOMAIN, @@ -103,7 +103,7 @@ async def test_sign_out_not_connected(hass, config_entry, controller, caplog): async def test_sign_out_unknown_error(hass, config_entry, controller, caplog): """Test the sign-out service.""" await setup_component(hass, config_entry) - controller.sign_out.side_effect = ConnectionError + controller.sign_out.side_effect = HeosError() await hass.services.async_call(DOMAIN, SERVICE_SIGN_OUT, {}, blocking=True) From 9d51262559865876f9e6670ec284f35794680436 Mon Sep 17 00:00:00 2001 From: "David F. Mulcahey" Date: Mon, 26 Aug 2019 01:34:43 -0400 Subject: [PATCH 22/40] bump quirks version (#26198) --- homeassistant/components/zha/manifest.json | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/zha/manifest.json b/homeassistant/components/zha/manifest.json index 0e004893033..8e7de41e626 100644 --- a/homeassistant/components/zha/manifest.json +++ b/homeassistant/components/zha/manifest.json @@ -5,7 +5,7 @@ "documentation": "https://www.home-assistant.io/components/zha", "requirements": [ "bellows-homeassistant==0.9.1", - "zha-quirks==0.0.21", + "zha-quirks==0.0.22", "zigpy-deconz==0.2.2", "zigpy-homeassistant==0.7.1", "zigpy-xbee-homeassistant==0.4.0", diff --git a/requirements_all.txt b/requirements_all.txt index b467859343f..42982b34134 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1971,7 +1971,7 @@ zengge==0.2 zeroconf==0.23.0 # homeassistant.components.zha -zha-quirks==0.0.21 +zha-quirks==0.0.22 # homeassistant.components.zhong_hong zhong_hong_hvac==1.0.9 From 9ad1a1ca1512da22b74c1fca87391001f42c5423 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 25 Aug 2019 22:37:34 -0700 Subject: [PATCH 23/40] Bumped version to 0.98.0b2 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index a2a79eee249..4d2998b85b8 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 98 -PATCH_VERSION = "0b1" +PATCH_VERSION = "0b2" __short_version__ = "{}.{}".format(MAJOR_VERSION, MINOR_VERSION) __version__ = "{}.{}".format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 6, 0) From 60256cca174fce680143f9a0feb6df790e054e81 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 26 Aug 2019 11:46:46 +0200 Subject: [PATCH 24/40] Nightly builds (#26204) * Nightly docker builds / Hass.io dev HA * use same style * Finish nightly build * Update builder version * Fix style * fix style part 2 * Last one * Fix order --- azure-pipelines-release.yml | 58 +++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/azure-pipelines-release.yml b/azure-pipelines-release.yml index 2e537fbb774..fab10bfeee6 100644 --- a/azure-pipelines-release.yml +++ b/azure-pipelines-release.yml @@ -3,11 +3,18 @@ trigger: tags: include: - - '*' + - '*' pr: none +schedules: + - cron: "0 1 * * *" + displayName: "nightly builds" + branches: + include: + - dev + always: true variables: - name: versionBuilder - value: '6.1' + value: '6.3' - group: docker - group: github - group: twine @@ -18,12 +25,13 @@ resources: name: 'home-assistant/ci-azure' endpoint: 'home-assistant' - stages: - stage: 'Validate' jobs: - template: templates/azp-job-version.yaml@azure + parameters: + ignoreDev: true - job: 'Permission' pool: vmImage: 'ubuntu-latest' @@ -42,10 +50,12 @@ stages: echo "${created_by} is not allowed to create an release!" exit 1 displayName: 'Check rights' + condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags')) - stage: 'Build' jobs: - job: 'ReleasePython' + condition: startsWith(variables['Build.SourceBranch'], 'refs/tags') pool: vmImage: 'ubuntu-latest' steps: @@ -86,6 +96,7 @@ stages: buildArch: 'aarch64' buildMachine: 'qemuarm-64,raspberrypi3-64,raspberrypi4-64,odroid-c2,orangepi-prime' steps: + - template: templates/azp-step-ha-version.yaml@azure - script: sudo docker login -u $(dockerUser) -p $(dockerPassword) displayName: 'Docker hub login' - script: sudo docker pull homeassistant/amd64-builder:$(versionBuilder) @@ -94,10 +105,11 @@ stages: set -e sudo docker run --rm --privileged \ - -v ~/.docker:/root/.docker \ + -v ~/.docker:/root/.docker:rw \ -v /run/docker.sock:/run/docker.sock:rw \ + -v $(pwd):/homeassistant:ro \ homeassistant/amd64-builder:$(versionBuilder) \ - --homeassistant $(Build.SourceBranchName) "--$(buildArch)" \ + --homeassistant $(homeassistantRelease) "--$(buildArch)" \ -r https://github.com/home-assistant/hassio-homeassistant \ -t generic --docker-hub homeassistant @@ -105,7 +117,7 @@ stages: -v ~/.docker:/root/.docker \ -v /run/docker.sock:/run/docker.sock:rw \ homeassistant/amd64-builder:$(versionBuilder) \ - --homeassistant-machine "$(Build.SourceBranchName)=$(buildMachine)" \ + --homeassistant-machine "$(homeassistantRelease)=$(buildMachine)" \ -r https://github.com/home-assistant/hassio-homeassistant \ -t machine --docker-hub homeassistant displayName: 'Build Release' @@ -116,6 +128,7 @@ stages: pool: vmImage: 'ubuntu-latest' steps: + - template: templates/azp-step-ha-version.yaml@azure - script: | sudo apt-get install -y --no-install-recommends \ git jq curl @@ -129,7 +142,7 @@ stages: - script: | set -e - version="$(Build.SourceBranchName)" + version="$(homeassistantRelease)" git clone https://github.com/home-assistant/hassio-version cd hassio-version @@ -138,11 +151,11 @@ stages: beta_version="$(jq --raw-output '.homeassistant.default' beta.json)" stable_version="$(jq --raw-output '.homeassistant.default' stable.json)" - if [[ "$version" =~ b ]]; then + if [[ "$version" =~ d ]]; then sed -i "s|$dev_version|$version|g" dev.json + elif [[ "$version" =~ b ]]; then sed -i "s|$beta_version|$version|g" beta.json else - sed -i "s|$dev_version|$version|g" dev.json sed -i "s|$beta_version|$version|g" beta.json sed -i "s|$stable_version|$version|g" stable.json fi @@ -154,6 +167,7 @@ stages: pool: vmImage: 'ubuntu-latest' steps: + - template: templates/azp-step-ha-version.yaml@azure - script: | mkdir -p ~/.docker echo '{ "experimental": "enabled" }' > .docker/config.json @@ -197,26 +211,26 @@ stages: sudo docker --config .docker manifest push --purge homeassistant/home-assistant:${tag_l} } - sudo docker pull homeassistant/amd64-homeassistant:$(Build.SourceBranchName) - sudo docker pull homeassistant/i386-homeassistant:$(Build.SourceBranchName) - sudo docker pull homeassistant/armhf-homeassistant:$(Build.SourceBranchName) - sudo docker pull homeassistant/armv7-homeassistant:$(Build.SourceBranchName) - sudo docker pull homeassistant/aarch64-homeassistant:$(Build.SourceBranchName) + sudo docker pull homeassistant/amd64-homeassistant:$(homeassistantRelease) + sudo docker pull homeassistant/i386-homeassistant:$(homeassistantRelease) + sudo docker pull homeassistant/armhf-homeassistant:$(homeassistantRelease) + sudo docker pull homeassistant/armv7-homeassistant:$(homeassistantRelease) + sudo docker pull homeassistant/aarch64-homeassistant:$(homeassistantRelease) # Create version tag - create_manifest "$(Build.SourceBranchName)" "$(Build.SourceBranchName)" + create_manifest "$(homeassistantRelease)" "$(homeassistantRelease)" # Create general tags if [[ "$version" =~ d ]]; then - create_manifest "dev" "$(Build.SourceBranchName)" + create_manifest "dev" "$(homeassistantRelease)" elif [[ "$version" =~ b ]]; then - create_manifest "beta" "$(Build.SourceBranchName)" - create_manifest "rc" "$(Build.SourceBranchName)" + create_manifest "beta" "$(homeassistantRelease)" + create_manifest "rc" "$(homeassistantRelease)" else - create_manifest "stable" "$(Build.SourceBranchName)" - create_manifest "latest" "$(Build.SourceBranchName)" - create_manifest "beta" "$(Build.SourceBranchName)" - create_manifest "rc" "$(Build.SourceBranchName)" + create_manifest "stable" "$(homeassistantRelease)" + create_manifest "latest" "$(homeassistantRelease)" + create_manifest "beta" "$(homeassistantRelease)" + create_manifest "rc" "$(homeassistantRelease)" fi displayName: 'Create Meta-Image' From efacfa3696a7567dc12ff0fb56512ed10316deb1 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 26 Aug 2019 21:03:37 +0200 Subject: [PATCH 25/40] Update azure-pipelines-release.yml for Azure Pipelines --- azure-pipelines-release.yml | 41 ++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/azure-pipelines-release.yml b/azure-pipelines-release.yml index fab10bfeee6..896aaa710c1 100644 --- a/azure-pipelines-release.yml +++ b/azure-pipelines-release.yml @@ -97,14 +97,15 @@ stages: buildMachine: 'qemuarm-64,raspberrypi3-64,raspberrypi4-64,odroid-c2,orangepi-prime' steps: - template: templates/azp-step-ha-version.yaml@azure - - script: sudo docker login -u $(dockerUser) -p $(dockerPassword) + - script: | + docker login -u $(dockerUser) -p $(dockerPassword) displayName: 'Docker hub login' - - script: sudo docker pull homeassistant/amd64-builder:$(versionBuilder) + - script: docker pull homeassistant/amd64-builder:$(versionBuilder) displayName: 'Install Builder' - script: | set -e - sudo docker run --rm --privileged \ + docker run --rm --privileged \ -v ~/.docker:/root/.docker:rw \ -v /run/docker.sock:/run/docker.sock:rw \ -v $(pwd):/homeassistant:ro \ @@ -113,7 +114,7 @@ stages: -r https://github.com/home-assistant/hassio-homeassistant \ -t generic --docker-hub homeassistant - sudo docker run --rm --privileged \ + docker run --rm --privileged \ -v ~/.docker:/root/.docker \ -v /run/docker.sock:/run/docker.sock:rw \ homeassistant/amd64-builder:$(versionBuilder) \ @@ -169,53 +170,51 @@ stages: steps: - template: templates/azp-step-ha-version.yaml@azure - script: | - mkdir -p ~/.docker - echo '{ "experimental": "enabled" }' > .docker/config.json - - sudo docker login -u $(dockerUser) -p $(dockerPassword) - displayName: 'Enable manifest / Docker login' + docker login -u $(dockerUser) -p $(dockerPassword) + displayName: 'Docker login' - script: | set -e + export DOCKER_CLI_EXPERIMENTAL=enabled function create_manifest() { local tag_l=$1 local tag_r=$2 - sudo docker --config .docker manifest create homeassistant/home-assistant:${tag_l} \ + docker manifest create homeassistant/home-assistant:${tag_l} \ homeassistant/amd64-homeassistant:${tag_r} \ homeassistant/i386-homeassistant:${tag_r} \ homeassistant/armhf-homeassistant:${tag_r} \ homeassistant/armv7-homeassistant:${tag_r} \ homeassistant/aarch64-homeassistant:${tag_r} - sudo docker --config .docker manifest annotate homeassistant/home-assistant:${tag_l} \ + docker manifest annotate homeassistant/home-assistant:${tag_l} \ homeassistant/amd64-homeassistant:${tag_r} \ --os linux --arch amd64 - sudo docker --config .docker manifest annotate homeassistant/home-assistant:${tag_l} \ + docker manifest annotate homeassistant/home-assistant:${tag_l} \ homeassistant/i386-homeassistant:${tag_r} \ --os linux --arch 386 - sudo docker --config .docker manifest annotate homeassistant/home-assistant:${tag_l} \ + docker manifest annotate homeassistant/home-assistant:${tag_l} \ homeassistant/armhf-homeassistant:${tag_r} \ --os linux --arch arm --variant=v6 - sudo docker --config .docker manifest annotate homeassistant/home-assistant:${tag_l} \ + docker manifest annotate homeassistant/home-assistant:${tag_l} \ homeassistant/armv7-homeassistant:${tag_r} \ --os linux --arch arm --variant=v7 - sudo docker --config .docker manifest annotate homeassistant/home-assistant:${tag_l} \ + docker manifest annotate homeassistant/home-assistant:${tag_l} \ homeassistant/aarch64-homeassistant:${tag_r} \ --os linux --arch arm64 --variant=v8 - sudo docker --config .docker manifest push --purge homeassistant/home-assistant:${tag_l} + docker manifest push --purge homeassistant/home-assistant:${tag_l} } - sudo docker pull homeassistant/amd64-homeassistant:$(homeassistantRelease) - sudo docker pull homeassistant/i386-homeassistant:$(homeassistantRelease) - sudo docker pull homeassistant/armhf-homeassistant:$(homeassistantRelease) - sudo docker pull homeassistant/armv7-homeassistant:$(homeassistantRelease) - sudo docker pull homeassistant/aarch64-homeassistant:$(homeassistantRelease) + docker pull homeassistant/amd64-homeassistant:$(homeassistantRelease) + docker pull homeassistant/i386-homeassistant:$(homeassistantRelease) + docker pull homeassistant/armhf-homeassistant:$(homeassistantRelease) + docker pull homeassistant/armv7-homeassistant:$(homeassistantRelease) + docker pull homeassistant/aarch64-homeassistant:$(homeassistantRelease) # Create version tag create_manifest "$(homeassistantRelease)" "$(homeassistantRelease)" From d7df61f9804844f32124c74f8210fd159b4f31d9 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Mon, 26 Aug 2019 21:12:49 +0200 Subject: [PATCH 26/40] Update azure-pipelines-release.yml for Azure Pipelines --- azure-pipelines-release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines-release.yml b/azure-pipelines-release.yml index 896aaa710c1..7c88e615fa5 100644 --- a/azure-pipelines-release.yml +++ b/azure-pipelines-release.yml @@ -220,9 +220,9 @@ stages: create_manifest "$(homeassistantRelease)" "$(homeassistantRelease)" # Create general tags - if [[ "$version" =~ d ]]; then + if [[ "$(homeassistantRelease)" =~ d ]]; then create_manifest "dev" "$(homeassistantRelease)" - elif [[ "$version" =~ b ]]; then + elif [[ "$(homeassistantRelease)" =~ b ]]; then create_manifest "beta" "$(homeassistantRelease)" create_manifest "rc" "$(homeassistantRelease)" else From 907ffdb762fee4e34cec21cd54733f32c610882c Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 28 Aug 2019 12:45:13 -0700 Subject: [PATCH 27/40] Update translations --- .../adguard/.translations/es-419.json | 3 +- .../components/adguard/.translations/hr.json | 7 +++ .../components/adguard/.translations/id.json | 15 +++++++ .../ambiclimate/.translations/es-419.json | 13 +++++- .../components/auth/.translations/es-419.json | 6 ++- .../components/axis/.translations/es-419.json | 11 +++-- .../components/axis/.translations/fr.json | 3 +- .../components/cast/.translations/hr.json | 10 +++++ .../components/deconz/.translations/en.json | 13 +----- .../deconz/.translations/es-419.json | 6 ++- .../components/deconz/.translations/hr.json | 17 ++++++++ .../dialogflow/.translations/pl.json | 2 +- .../esphome/.translations/es-419.json | 2 + .../hangouts/.translations/es-419.json | 3 ++ .../components/heos/.translations/es-419.json | 3 ++ .../.translations/es-419.json | 3 +- .../homematicip_cloud/.translations/hr.json | 7 +++ .../components/hue/.translations/es-419.json | 1 + .../components/hue/.translations/hr.json | 16 +++++++ .../components/ifttt/.translations/hr.json | 5 +++ .../iqvia/.translations/es-419.json | 14 ++++++ .../components/iqvia/.translations/id.json | 11 +++++ .../life360/.translations/es-419.json | 5 +++ .../components/life360/.translations/fr.json | 4 ++ .../components/life360/.translations/hr.json | 24 +++++++++++ .../components/life360/.translations/id.json | 7 +++ .../components/life360/.translations/pl.json | 8 ++-- .../logi_circle/.translations/es-419.json | 27 ++++++++++++ .../components/met/.translations/es-419.json | 20 +++++++++ .../components/met/.translations/hr.json | 20 +++++++++ .../components/met/.translations/id.json | 13 ++++++ .../components/met/.translations/pl.json | 2 +- .../mobile_app/.translations/es-419.json | 3 ++ .../moon/.translations/sensor.es-419.json | 7 +-- .../components/mqtt/.translations/hr.json | 15 +++++++ .../components/nest/.translations/hr.json | 21 +++++++++ .../notion/.translations/es-419.json | 18 ++++++++ .../components/notion/.translations/hr.json | 19 ++++++++ .../components/notion/.translations/pl.json | 4 +- .../onboarding/.translations/es-419.json | 7 +++ .../onboarding/.translations/id.json | 5 +++ .../components/openuv/.translations/hr.json | 13 ++++++ .../plaato/.translations/es-419.json | 18 ++++++++ .../components/plaato/.translations/hr.json | 18 ++++++++ .../components/plaato/.translations/pl.json | 2 +- .../point/.translations/es-419.json | 2 + .../components/ps4/.translations/es-419.json | 6 +++ .../season/.translations/sensor.es-419.json | 3 +- .../sensor/.translations/season.hr.json | 8 ++++ .../components/somfy/.translations/fr.json | 5 +++ .../components/somfy/.translations/hr.json | 8 ++++ .../components/sonos/.translations/hr.json | 10 +++++ .../tplink/.translations/es-419.json | 5 +++ .../components/traccar/.translations/en.json | 18 ++++++++ .../tradfri/.translations/es-419.json | 4 +- .../components/tradfri/.translations/hr.json | 15 +++++++ .../components/tradfri/.translations/pl.json | 2 +- .../components/unifi/.translations/en.json | 43 ++++++------------- .../components/unifi/.translations/hr.json | 14 ++++++ .../components/upnp/.translations/hr.json | 9 ++++ .../components/wemo/.translations/es-419.json | 15 +++++++ .../components/wemo/.translations/hr.json | 5 +++ .../wwlln/.translations/es-419.json | 18 ++++++++ .../components/wwlln/.translations/hr.json | 18 ++++++++ .../components/wwlln/.translations/pl.json | 6 +-- .../components/zone/.translations/hr.json | 21 +++++++++ .../zwave/.translations/es-419.json | 3 ++ 67 files changed, 617 insertions(+), 72 deletions(-) create mode 100644 homeassistant/components/adguard/.translations/hr.json create mode 100644 homeassistant/components/adguard/.translations/id.json create mode 100644 homeassistant/components/cast/.translations/hr.json create mode 100644 homeassistant/components/deconz/.translations/hr.json create mode 100644 homeassistant/components/homematicip_cloud/.translations/hr.json create mode 100644 homeassistant/components/hue/.translations/hr.json create mode 100644 homeassistant/components/ifttt/.translations/hr.json create mode 100644 homeassistant/components/iqvia/.translations/es-419.json create mode 100644 homeassistant/components/iqvia/.translations/id.json create mode 100644 homeassistant/components/life360/.translations/es-419.json create mode 100644 homeassistant/components/life360/.translations/hr.json create mode 100644 homeassistant/components/life360/.translations/id.json create mode 100644 homeassistant/components/logi_circle/.translations/es-419.json create mode 100644 homeassistant/components/met/.translations/es-419.json create mode 100644 homeassistant/components/met/.translations/hr.json create mode 100644 homeassistant/components/met/.translations/id.json create mode 100644 homeassistant/components/mqtt/.translations/hr.json create mode 100644 homeassistant/components/nest/.translations/hr.json create mode 100644 homeassistant/components/notion/.translations/es-419.json create mode 100644 homeassistant/components/notion/.translations/hr.json create mode 100644 homeassistant/components/onboarding/.translations/es-419.json create mode 100644 homeassistant/components/onboarding/.translations/id.json create mode 100644 homeassistant/components/openuv/.translations/hr.json create mode 100644 homeassistant/components/plaato/.translations/es-419.json create mode 100644 homeassistant/components/plaato/.translations/hr.json create mode 100644 homeassistant/components/sensor/.translations/season.hr.json create mode 100644 homeassistant/components/somfy/.translations/hr.json create mode 100644 homeassistant/components/sonos/.translations/hr.json create mode 100644 homeassistant/components/traccar/.translations/en.json create mode 100644 homeassistant/components/tradfri/.translations/hr.json create mode 100644 homeassistant/components/unifi/.translations/hr.json create mode 100644 homeassistant/components/upnp/.translations/hr.json create mode 100644 homeassistant/components/wemo/.translations/es-419.json create mode 100644 homeassistant/components/wemo/.translations/hr.json create mode 100644 homeassistant/components/wwlln/.translations/es-419.json create mode 100644 homeassistant/components/wwlln/.translations/hr.json create mode 100644 homeassistant/components/zone/.translations/hr.json diff --git a/homeassistant/components/adguard/.translations/es-419.json b/homeassistant/components/adguard/.translations/es-419.json index d62402f2eee..ed8e0c3a358 100644 --- a/homeassistant/components/adguard/.translations/es-419.json +++ b/homeassistant/components/adguard/.translations/es-419.json @@ -20,7 +20,8 @@ "username": "Nombre de usuario", "verify_ssl": "AdGuard Home utiliza un certificado adecuado" }, - "description": "Configure su instancia de AdGuard Home para permitir la supervisi\u00f3n y el control." + "description": "Configure su instancia de AdGuard Home para permitir la supervisi\u00f3n y el control.", + "title": "Enlace su AdGuard Home." } }, "title": "AdGuard Home" diff --git a/homeassistant/components/adguard/.translations/hr.json b/homeassistant/components/adguard/.translations/hr.json new file mode 100644 index 00000000000..869cc46ea10 --- /dev/null +++ b/homeassistant/components/adguard/.translations/hr.json @@ -0,0 +1,7 @@ +{ + "config": { + "abort": { + "existing_instance_updated": "Postoje\u0107a konfiguracija je a\u017eurirana." + } + } +} \ No newline at end of file diff --git a/homeassistant/components/adguard/.translations/id.json b/homeassistant/components/adguard/.translations/id.json new file mode 100644 index 00000000000..3548361e396 --- /dev/null +++ b/homeassistant/components/adguard/.translations/id.json @@ -0,0 +1,15 @@ +{ + "config": { + "error": { + "connection_error": "Gagal terhubung." + }, + "step": { + "user": { + "data": { + "password": "Kata sandi", + "port": "Port" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/ambiclimate/.translations/es-419.json b/homeassistant/components/ambiclimate/.translations/es-419.json index eaac252d605..607454f4402 100644 --- a/homeassistant/components/ambiclimate/.translations/es-419.json +++ b/homeassistant/components/ambiclimate/.translations/es-419.json @@ -7,6 +7,17 @@ }, "create_entry": { "default": "Autenticaci\u00f3n exitosa con Ambiclimate" - } + }, + "error": { + "follow_link": "Por favor, siga el enlace y autent\u00edquese antes de presionar Enviar", + "no_token": "No autenticado con Ambiclimate" + }, + "step": { + "auth": { + "description": "Por favor, siga este [link]('authorization_url') y Permitir acceso a su cuenta de Ambiclimate, luego vuelva y presione Enviar a continuaci\u00f3n.\n(Aseg\u00farese de que la url de devoluci\u00f3n de llamada especificada es {cb_url})", + "title": "Autenticaci\u00f3n de Ambiclimate" + } + }, + "title": "Ambiclimate" } } \ No newline at end of file diff --git a/homeassistant/components/auth/.translations/es-419.json b/homeassistant/components/auth/.translations/es-419.json index 852965596e0..4ac97068905 100644 --- a/homeassistant/components/auth/.translations/es-419.json +++ b/homeassistant/components/auth/.translations/es-419.json @@ -16,9 +16,13 @@ "description": "Se ha enviado una contrase\u00f1a \u00fanica a trav\u00e9s de **notify.{notify_service}**. Por favor ingr\u00e9selo a continuaci\u00f3n:", "title": "Verificar la configuracion" } - } + }, + "title": "Notificar contrase\u00f1a de un solo uso" }, "totp": { + "error": { + "invalid_code": "C\u00f3digo no v\u00e1lido, por favor vuelva a intentarlo. Si recibe este error constantemente, aseg\u00farese de que el reloj de su sistema Home Assistant sea exacto." + }, "step": { "init": { "description": "Para activar la autenticaci\u00f3n de dos factores utilizando contrase\u00f1as de un solo uso basadas en el tiempo, escanee el c\u00f3digo QR con su aplicaci\u00f3n de autenticaci\u00f3n. Si no tiene uno, le recomendamos [Autenticador de Google] (https://support.google.com/accounts/answer/1066447) o [Authy] (https://authy.com/). \n\n {qr_code} \n \n Despu\u00e9s de escanear el c\u00f3digo, ingrese el c\u00f3digo de seis d\u00edgitos de su aplicaci\u00f3n para verificar la configuraci\u00f3n. Si tiene problemas para escanear el c\u00f3digo QR, realice una configuraci\u00f3n manual con el c\u00f3digo ** ` {code} ` **.", diff --git a/homeassistant/components/axis/.translations/es-419.json b/homeassistant/components/axis/.translations/es-419.json index 1e9301a19da..c5404a173f6 100644 --- a/homeassistant/components/axis/.translations/es-419.json +++ b/homeassistant/components/axis/.translations/es-419.json @@ -2,10 +2,13 @@ "config": { "abort": { "already_configured": "El dispositivo ya est\u00e1 configurado", - "bad_config_file": "Datos err\u00f3neos del archivo de configuraci\u00f3n" + "bad_config_file": "Datos err\u00f3neos del archivo de configuraci\u00f3n", + "link_local_address": "Las direcciones locales de enlace no son compatibles", + "not_axis_device": "El dispositivo descubierto no es un dispositivo de Axis" }, "error": { "already_configured": "El dispositivo ya est\u00e1 configurado", + "already_in_progress": "El flujo de configuraci\u00f3n para el dispositivo ya est\u00e1 en progreso.", "device_unavailable": "El dispositivo no est\u00e1 disponible", "faulty_credentials": "Credenciales de usuario incorrectas" }, @@ -15,8 +18,10 @@ "password": "Contrase\u00f1a", "port": "Puerto", "username": "Nombre de usuario" - } + }, + "title": "Configurar dispositivo Axis" } - } + }, + "title": "Dispositivo Axis" } } \ No newline at end of file diff --git a/homeassistant/components/axis/.translations/fr.json b/homeassistant/components/axis/.translations/fr.json index 020cd8f5946..e85fceaf463 100644 --- a/homeassistant/components/axis/.translations/fr.json +++ b/homeassistant/components/axis/.translations/fr.json @@ -3,7 +3,8 @@ "abort": { "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9", "bad_config_file": "Mauvaises donn\u00e9es du fichier de configuration", - "link_local_address": "Les adresses locales ne sont pas prises en charge" + "link_local_address": "Les adresses locales ne sont pas prises en charge", + "not_axis_device": "L'appareil d\u00e9couvert n'est pas un appareil Axis" }, "error": { "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9", diff --git a/homeassistant/components/cast/.translations/hr.json b/homeassistant/components/cast/.translations/hr.json new file mode 100644 index 00000000000..91dafab0201 --- /dev/null +++ b/homeassistant/components/cast/.translations/hr.json @@ -0,0 +1,10 @@ +{ + "config": { + "step": { + "confirm": { + "title": "Google Cast" + } + }, + "title": "Google Cast" + } +} \ No newline at end of file diff --git a/homeassistant/components/deconz/.translations/en.json b/homeassistant/components/deconz/.translations/en.json index 34da602a6ce..dd8f1cc4026 100644 --- a/homeassistant/components/deconz/.translations/en.json +++ b/homeassistant/components/deconz/.translations/en.json @@ -40,16 +40,5 @@ } }, "title": "deCONZ Zigbee gateway" - }, - "options": { - "step": { - "deconz_devices": { - "description": "Configure visibility of deCONZ device types", - "data": { - "allow_clip_sensor": "Allow deCONZ CLIP sensors", - "allow_deconz_groups": "Allow deCONZ light groups" - } - } - } } -} +} \ No newline at end of file diff --git a/homeassistant/components/deconz/.translations/es-419.json b/homeassistant/components/deconz/.translations/es-419.json index 4ae633ef165..1a5d992ef7b 100644 --- a/homeassistant/components/deconz/.translations/es-419.json +++ b/homeassistant/components/deconz/.translations/es-419.json @@ -2,7 +2,9 @@ "config": { "abort": { "already_configured": "El Bridge ya est\u00e1 configurado", + "already_in_progress": "El flujo de configuraci\u00f3n para el puente ya est\u00e1 en progreso.", "no_bridges": "No se descubrieron puentes deCONZ", + "not_deconz_bridge": "No es un puente deCONZ", "one_instance_only": "El componente solo admite una instancia deCONZ" }, "error": { @@ -13,7 +15,8 @@ "data": { "allow_clip_sensor": "Permitir la importaci\u00f3n de sensores virtuales", "allow_deconz_groups": "Permitir la importaci\u00f3n de grupos deCONZ" - } + }, + "description": "\u00bfDesea configurar Home Assistant para conectarse a la puerta de enlace deCONZ proporcionada por el complemento hass.io {addon}?" }, "init": { "data": { @@ -23,6 +26,7 @@ "title": "Definir el gateway deCONZ" }, "link": { + "description": "Desbloquee su puerta de enlace deCONZ para registrarse con Home Assistant. \n\n 1. Vaya a Configuraci\u00f3n deCONZ - > Gateway - > Avanzado \n 2. Presione el bot\u00f3n \"Autenticar aplicaci\u00f3n\"", "title": "Enlazar con deCONZ" }, "options": { diff --git a/homeassistant/components/deconz/.translations/hr.json b/homeassistant/components/deconz/.translations/hr.json new file mode 100644 index 00000000000..2f2eb6df214 --- /dev/null +++ b/homeassistant/components/deconz/.translations/hr.json @@ -0,0 +1,17 @@ +{ + "config": { + "step": { + "init": { + "data": { + "host": "Host", + "port": "Port" + } + }, + "options": { + "data": { + "allow_clip_sensor": "Dopusti uvoz virtualnih senzora" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/dialogflow/.translations/pl.json b/homeassistant/components/dialogflow/.translations/pl.json index 3395b31b4c7..ee222c83b51 100644 --- a/homeassistant/components/dialogflow/.translations/pl.json +++ b/homeassistant/components/dialogflow/.translations/pl.json @@ -5,7 +5,7 @@ "one_instance_allowed": "Wymagana jest tylko jedna instancja." }, "create_entry": { - "default": "Aby wysy\u0142a\u0107 zdarzenia do Home Assistant'a, musisz skonfigurowa\u0107 [Dialogflow Webhook]({twilio_url}). \n\n Wprowad\u017a nast\u0119puj\u0105ce dane:\n\n - URL: `{webhook_url}` \n - Metoda: POST \n - Typ zawarto\u015bci: application/json\n\nZapoznaj si\u0119 z [dokumentacj\u0105]({docs_url}), by pozna\u0107 szczeg\u00f3\u0142y." + "default": "Aby wysy\u0142a\u0107 zdarzenia do Home Assistant'a, musisz skonfigurowa\u0107 [Dialogflow Webhook]({dialogflow_url}). \n\n Wprowad\u017a nast\u0119puj\u0105ce dane:\n\n - URL: `{webhook_url}` \n - Metoda: POST \n - Typ zawarto\u015bci: application/json\n\nZapoznaj si\u0119 z [dokumentacj\u0105]({docs_url}), by pozna\u0107 szczeg\u00f3\u0142y." }, "step": { "user": { diff --git a/homeassistant/components/esphome/.translations/es-419.json b/homeassistant/components/esphome/.translations/es-419.json index 58dbba34fa8..a0a2d77d48c 100644 --- a/homeassistant/components/esphome/.translations/es-419.json +++ b/homeassistant/components/esphome/.translations/es-419.json @@ -8,6 +8,7 @@ "invalid_password": "\u00a1Contrase\u00f1a invalida!", "resolve_error": "No se puede resolver la direcci\u00f3n de la ESP. Si este error persiste, configure una direcci\u00f3n IP est\u00e1tica: https://esphomelib.com/esphomeyaml/components/wifi.html#manual-ips" }, + "flow_title": "ESPHome: {name}", "step": { "authenticate": { "data": { @@ -17,6 +18,7 @@ "title": "Escriba la contrase\u00f1a" }, "discovery_confirm": { + "description": "\u00bfDesea agregar el nodo ESPHome `{name}` a Home Assistant?", "title": "Nodo ESPHome descubierto" }, "user": { diff --git a/homeassistant/components/hangouts/.translations/es-419.json b/homeassistant/components/hangouts/.translations/es-419.json index 951a30f1826..3a297eb15ea 100644 --- a/homeassistant/components/hangouts/.translations/es-419.json +++ b/homeassistant/components/hangouts/.translations/es-419.json @@ -9,6 +9,9 @@ }, "step": { "2fa": { + "data": { + "2fa": "Pin 2FA" + }, "title": "Autenticaci\u00f3n de 2 factores" }, "user": { diff --git a/homeassistant/components/heos/.translations/es-419.json b/homeassistant/components/heos/.translations/es-419.json index 12ed8cc457a..66c02884a7e 100644 --- a/homeassistant/components/heos/.translations/es-419.json +++ b/homeassistant/components/heos/.translations/es-419.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "already_setup": "Solo puede configurar una sola conexi\u00f3n Heos, ya que ser\u00e1 compatible con todos los dispositivos de la red." + }, "title": "Heos" } } \ No newline at end of file diff --git a/homeassistant/components/homekit_controller/.translations/es-419.json b/homeassistant/components/homekit_controller/.translations/es-419.json index b058e94e25a..9ddf336c060 100644 --- a/homeassistant/components/homekit_controller/.translations/es-419.json +++ b/homeassistant/components/homekit_controller/.translations/es-419.json @@ -15,6 +15,7 @@ "device": "Dispositivo" } } - } + }, + "title": "Accesorio HomeKit" } } \ No newline at end of file diff --git a/homeassistant/components/homematicip_cloud/.translations/hr.json b/homeassistant/components/homematicip_cloud/.translations/hr.json new file mode 100644 index 00000000000..648dbfe73f9 --- /dev/null +++ b/homeassistant/components/homematicip_cloud/.translations/hr.json @@ -0,0 +1,7 @@ +{ + "config": { + "abort": { + "unknown": "Do\u0161lo je do nepoznate pogre\u0161ke." + } + } +} \ No newline at end of file diff --git a/homeassistant/components/hue/.translations/es-419.json b/homeassistant/components/hue/.translations/es-419.json index 8efc9101d9a..48a2ff233da 100644 --- a/homeassistant/components/hue/.translations/es-419.json +++ b/homeassistant/components/hue/.translations/es-419.json @@ -6,6 +6,7 @@ "cannot_connect": "No se puede conectar al puente", "discover_timeout": "Incapaz de descubrir puentes Hue", "no_bridges": "No se descubrieron puentes Philips Hue", + "not_hue_bridge": "No es un puente Hue", "unknown": "Se produjo un error desconocido" }, "error": { diff --git a/homeassistant/components/hue/.translations/hr.json b/homeassistant/components/hue/.translations/hr.json new file mode 100644 index 00000000000..16a1b19ff8e --- /dev/null +++ b/homeassistant/components/hue/.translations/hr.json @@ -0,0 +1,16 @@ +{ + "config": { + "error": { + "linking": "Do\u0161lo je do nepoznate pogre\u0161ke u povezivanju.", + "register_failed": "Registracija nije uspjela. Poku\u0161ajte ponovo" + }, + "step": { + "init": { + "data": { + "host": "Host" + } + } + }, + "title": "Philips Hue" + } +} \ No newline at end of file diff --git a/homeassistant/components/ifttt/.translations/hr.json b/homeassistant/components/ifttt/.translations/hr.json new file mode 100644 index 00000000000..077956287b3 --- /dev/null +++ b/homeassistant/components/ifttt/.translations/hr.json @@ -0,0 +1,5 @@ +{ + "config": { + "title": "IFTTT" + } +} \ No newline at end of file diff --git a/homeassistant/components/iqvia/.translations/es-419.json b/homeassistant/components/iqvia/.translations/es-419.json new file mode 100644 index 00000000000..b107e1bb696 --- /dev/null +++ b/homeassistant/components/iqvia/.translations/es-419.json @@ -0,0 +1,14 @@ +{ + "config": { + "error": { + "invalid_zip_code": "El c\u00f3digo postal no es v\u00e1lido" + }, + "step": { + "user": { + "data": { + "zip_code": "C\u00f3digo postal" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/iqvia/.translations/id.json b/homeassistant/components/iqvia/.translations/id.json new file mode 100644 index 00000000000..a93f9aac26f --- /dev/null +++ b/homeassistant/components/iqvia/.translations/id.json @@ -0,0 +1,11 @@ +{ + "config": { + "step": { + "user": { + "data": { + "zip_code": "Kode Pos" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/life360/.translations/es-419.json b/homeassistant/components/life360/.translations/es-419.json new file mode 100644 index 00000000000..3f9bfab3304 --- /dev/null +++ b/homeassistant/components/life360/.translations/es-419.json @@ -0,0 +1,5 @@ +{ + "config": { + "title": "Life360" + } +} \ No newline at end of file diff --git a/homeassistant/components/life360/.translations/fr.json b/homeassistant/components/life360/.translations/fr.json index 95df1c991a2..cb4682fc937 100644 --- a/homeassistant/components/life360/.translations/fr.json +++ b/homeassistant/components/life360/.translations/fr.json @@ -4,6 +4,9 @@ "invalid_credentials": "Informations d'identification invalides", "user_already_configured": "Le compte a d\u00e9j\u00e0 \u00e9t\u00e9 configur\u00e9" }, + "create_entry": { + "default": "Pour d\u00e9finir les options avanc\u00e9es, voir [Documentation de Life360]( {docs_url} )." + }, "error": { "invalid_credentials": "Informations d'identification invalides", "invalid_username": "Nom d'utilisateur invalide", @@ -15,6 +18,7 @@ "password": "Mot de passe", "username": "Nom d'utilisateur" }, + "description": "Pour d\u00e9finir des options avanc\u00e9es, voir [Documentation Life360]({docs_url}).\nVous pouvez le faire avant d'ajouter des comptes.", "title": "Informations sur le compte Life360" } }, diff --git a/homeassistant/components/life360/.translations/hr.json b/homeassistant/components/life360/.translations/hr.json new file mode 100644 index 00000000000..5cf8cbef17f --- /dev/null +++ b/homeassistant/components/life360/.translations/hr.json @@ -0,0 +1,24 @@ +{ + "config": { + "abort": { + "invalid_credentials": "Neva\u017ee\u0107e vjerodajnice", + "user_already_configured": "Ra\u010dun je ve\u0107 konfiguriran" + }, + "create_entry": { + "default": "Da biste postavili napredne opcije, pogledajte [Life360 dokumentacija] ( {docs_url} )." + }, + "error": { + "invalid_credentials": "Neva\u017ee\u0107e vjerodajnice", + "invalid_username": "Neispravno korisni\u010dko ime", + "user_already_configured": "Ra\u010dun je ve\u0107 konfiguriran" + }, + "step": { + "user": { + "data": { + "password": "Lozinka", + "username": "Korisni\u010dko ime" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/life360/.translations/id.json b/homeassistant/components/life360/.translations/id.json new file mode 100644 index 00000000000..2bb7a1cca68 --- /dev/null +++ b/homeassistant/components/life360/.translations/id.json @@ -0,0 +1,7 @@ +{ + "config": { + "error": { + "invalid_username": "Nama pengguna tidak valid" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/life360/.translations/pl.json b/homeassistant/components/life360/.translations/pl.json index b1523da188c..15aabaa6308 100644 --- a/homeassistant/components/life360/.translations/pl.json +++ b/homeassistant/components/life360/.translations/pl.json @@ -1,16 +1,16 @@ { "config": { "abort": { - "invalid_credentials": "B\u0142\u0119dne dane uwierzytelniaj\u0105ce", - "user_already_configured": "Konto jest ju\u017c skonfigurowane." + "invalid_credentials": "Nieprawid\u0142owe dane uwierzytelniaj\u0105ce", + "user_already_configured": "Konto zosta\u0142o ju\u017c skonfigurowane." }, "create_entry": { "default": "Aby skonfigurowa\u0107 zaawansowane ustawienia, zapoznaj si\u0119 z [dokumentacj\u0105 Life360]({docs_url})." }, "error": { - "invalid_credentials": "B\u0142\u0119dne dane uwierzytelniaj\u0105ce", + "invalid_credentials": "Nieprawid\u0142owe dane uwierzytelniaj\u0105ce", "invalid_username": "Nieprawid\u0142owa nazwa u\u017cytkownika", - "user_already_configured": "Konto jest ju\u017c skonfigurowane." + "user_already_configured": "Konto zosta\u0142o ju\u017c skonfigurowane." }, "step": { "user": { diff --git a/homeassistant/components/logi_circle/.translations/es-419.json b/homeassistant/components/logi_circle/.translations/es-419.json new file mode 100644 index 00000000000..2393908e281 --- /dev/null +++ b/homeassistant/components/logi_circle/.translations/es-419.json @@ -0,0 +1,27 @@ +{ + "config": { + "abort": { + "already_setup": "Solo puede configurar una sola cuenta de Logi Circle.", + "external_error": "Se produjo una excepci\u00f3n de otro flujo.", + "external_setup": "Logi Circle se configur\u00f3 correctamente desde otro flujo." + }, + "create_entry": { + "default": "Autenticado con \u00e9xito con Logi Circle." + }, + "error": { + "auth_error": "Autorizaci\u00f3n de API fallida." + }, + "step": { + "auth": { + "title": "Autenticar con Logi Circle" + }, + "user": { + "data": { + "flow_impl": "Proveedor" + }, + "title": "Proveedor de autenticaci\u00f3n" + } + }, + "title": "Logi Circle" + } +} \ No newline at end of file diff --git a/homeassistant/components/met/.translations/es-419.json b/homeassistant/components/met/.translations/es-419.json new file mode 100644 index 00000000000..d744de150d2 --- /dev/null +++ b/homeassistant/components/met/.translations/es-419.json @@ -0,0 +1,20 @@ +{ + "config": { + "error": { + "name_exists": "El nombre ya existe" + }, + "step": { + "user": { + "data": { + "elevation": "Elevaci\u00f3n", + "latitude": "Latitud", + "longitude": "Longitud", + "name": "Nombre" + }, + "description": "Meteorologisk institutt", + "title": "Ubicaci\u00f3n" + } + }, + "title": "Met.no" + } +} \ No newline at end of file diff --git a/homeassistant/components/met/.translations/hr.json b/homeassistant/components/met/.translations/hr.json new file mode 100644 index 00000000000..6505229355c --- /dev/null +++ b/homeassistant/components/met/.translations/hr.json @@ -0,0 +1,20 @@ +{ + "config": { + "error": { + "name_exists": "Ime ve\u0107 postoji" + }, + "step": { + "user": { + "data": { + "elevation": "Elevacija", + "latitude": "Zemljopisna \u0161irina", + "longitude": "Zemljopisna du\u017eina", + "name": "Ime" + }, + "description": "Meteorolo\u0161ki institutt", + "title": "Lokacija" + } + }, + "title": "Met.no" + } +} \ No newline at end of file diff --git a/homeassistant/components/met/.translations/id.json b/homeassistant/components/met/.translations/id.json new file mode 100644 index 00000000000..12854e4ed61 --- /dev/null +++ b/homeassistant/components/met/.translations/id.json @@ -0,0 +1,13 @@ +{ + "config": { + "step": { + "user": { + "data": { + "elevation": "Ketinggian", + "name": "Nama" + }, + "title": "Lokasi" + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/met/.translations/pl.json b/homeassistant/components/met/.translations/pl.json index 61b66b794e1..d44142213bf 100644 --- a/homeassistant/components/met/.translations/pl.json +++ b/homeassistant/components/met/.translations/pl.json @@ -11,7 +11,7 @@ "longitude": "D\u0142ugo\u015b\u0107 geograficzna", "name": "Nazwa" }, - "description": "Meteorologisk institutt", + "description": "Instytut Meteorologiczny", "title": "Lokalizacja" } }, diff --git a/homeassistant/components/mobile_app/.translations/es-419.json b/homeassistant/components/mobile_app/.translations/es-419.json index 417d0627616..271e38147c3 100644 --- a/homeassistant/components/mobile_app/.translations/es-419.json +++ b/homeassistant/components/mobile_app/.translations/es-419.json @@ -1,5 +1,8 @@ { "config": { + "abort": { + "install_app": "Abra la aplicaci\u00f3n m\u00f3vil para configurar la integraci\u00f3n con Home Assistant. Consulte [los documentos] ({apps_url}) para obtener una lista de aplicaciones compatibles." + }, "step": { "confirm": { "title": "Aplicaci\u00f3n movil" diff --git a/homeassistant/components/moon/.translations/sensor.es-419.json b/homeassistant/components/moon/.translations/sensor.es-419.json index 71cfab736cb..89823dd2055 100644 --- a/homeassistant/components/moon/.translations/sensor.es-419.json +++ b/homeassistant/components/moon/.translations/sensor.es-419.json @@ -2,11 +2,6 @@ "state": { "first_quarter": "Cuarto creciente", "full_moon": "Luna llena", - "last_quarter": "Cuarto menguante", - "new_moon": "Luna nueva", - "waning_crescent": "Luna menguante", - "waning_gibbous": "Luna menguante gibosa", - "waxing_crescent": "Luna creciente", - "waxing_gibbous": "Luna creciente gibosa" + "last_quarter": "Cuarto menguante" } } \ No newline at end of file diff --git a/homeassistant/components/mqtt/.translations/hr.json b/homeassistant/components/mqtt/.translations/hr.json new file mode 100644 index 00000000000..b3c82fdd8db --- /dev/null +++ b/homeassistant/components/mqtt/.translations/hr.json @@ -0,0 +1,15 @@ +{ + "config": { + "step": { + "broker": { + "data": { + "password": "Lozinka", + "port": "Port", + "username": "Korisni\u010dko ime" + }, + "title": "MQTT" + } + }, + "title": "MQTT" + } +} \ No newline at end of file diff --git a/homeassistant/components/nest/.translations/hr.json b/homeassistant/components/nest/.translations/hr.json new file mode 100644 index 00000000000..b96a358f2f0 --- /dev/null +++ b/homeassistant/components/nest/.translations/hr.json @@ -0,0 +1,21 @@ +{ + "config": { + "error": { + "invalid_code": "Neispravan kod" + }, + "step": { + "init": { + "data": { + "flow_impl": "Pru\u017eatelj usluge" + }, + "title": "Pru\u017eatelj usluge autentifikacije" + }, + "link": { + "data": { + "code": "PIN kod" + } + } + }, + "title": "Nest" + } +} \ No newline at end of file diff --git a/homeassistant/components/notion/.translations/es-419.json b/homeassistant/components/notion/.translations/es-419.json new file mode 100644 index 00000000000..ad2f19b0668 --- /dev/null +++ b/homeassistant/components/notion/.translations/es-419.json @@ -0,0 +1,18 @@ +{ + "config": { + "error": { + "invalid_credentials": "Nombre de usuario o contrase\u00f1a inv\u00e1lidos", + "no_devices": "No se han encontrado dispositivos en la cuenta." + }, + "step": { + "user": { + "data": { + "password": "Contrase\u00f1a", + "username": "Nombre de usuario/direcci\u00f3n de correo electr\u00f3nico" + }, + "title": "Complete su informaci\u00f3n" + } + }, + "title": "Noci\u00f3n" + } +} \ No newline at end of file diff --git a/homeassistant/components/notion/.translations/hr.json b/homeassistant/components/notion/.translations/hr.json new file mode 100644 index 00000000000..b20317a236a --- /dev/null +++ b/homeassistant/components/notion/.translations/hr.json @@ -0,0 +1,19 @@ +{ + "config": { + "error": { + "identifier_exists": "Korisni\u010dko ime je ve\u0107 registrirano", + "invalid_credentials": "Neispravno korisni\u010dko ime ili lozinka", + "no_devices": "Nisu prona\u0111eni ure\u0111aji na ra\u010dunu" + }, + "step": { + "user": { + "data": { + "password": "Lozinka", + "username": "Korisni\u010dko ime/adresa e-po\u0161te" + }, + "title": "Ispunite svoje podatke" + } + }, + "title": "Pojam" + } +} \ No newline at end of file diff --git a/homeassistant/components/notion/.translations/pl.json b/homeassistant/components/notion/.translations/pl.json index 0c1fe674887..c35de9c535c 100644 --- a/homeassistant/components/notion/.translations/pl.json +++ b/homeassistant/components/notion/.translations/pl.json @@ -1,7 +1,7 @@ { "config": { "error": { - "identifier_exists": "Nazwa u\u017cytkownika jest ju\u017c zarejestrowana", + "identifier_exists": "Nazwa u\u017cytkownika ju\u017c zarejestrowana", "invalid_credentials": "Nieprawid\u0142owa nazwa u\u017cytkownika lub has\u0142o", "no_devices": "Nie znaleziono urz\u0105dze\u0144 na koncie" }, @@ -14,6 +14,6 @@ "title": "Wprowad\u017a swoje dane" } }, - "title": "Notion" + "title": "Poj\u0119cie" } } \ No newline at end of file diff --git a/homeassistant/components/onboarding/.translations/es-419.json b/homeassistant/components/onboarding/.translations/es-419.json new file mode 100644 index 00000000000..747074436d7 --- /dev/null +++ b/homeassistant/components/onboarding/.translations/es-419.json @@ -0,0 +1,7 @@ +{ + "area": { + "bedroom": "Habitaci\u00f3n", + "kitchen": "Cocina", + "living_room": "Sala" + } +} \ No newline at end of file diff --git a/homeassistant/components/onboarding/.translations/id.json b/homeassistant/components/onboarding/.translations/id.json new file mode 100644 index 00000000000..33e8a88a9ae --- /dev/null +++ b/homeassistant/components/onboarding/.translations/id.json @@ -0,0 +1,5 @@ +{ + "area": { + "kitchen": "Dapur" + } +} \ No newline at end of file diff --git a/homeassistant/components/openuv/.translations/hr.json b/homeassistant/components/openuv/.translations/hr.json new file mode 100644 index 00000000000..835929d26df --- /dev/null +++ b/homeassistant/components/openuv/.translations/hr.json @@ -0,0 +1,13 @@ +{ + "config": { + "step": { + "user": { + "data": { + "elevation": "Elevacija", + "latitude": "Zemljopisna \u0161irina", + "longitude": "Zemljopisna du\u017eina" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/plaato/.translations/es-419.json b/homeassistant/components/plaato/.translations/es-419.json new file mode 100644 index 00000000000..d63802984ef --- /dev/null +++ b/homeassistant/components/plaato/.translations/es-419.json @@ -0,0 +1,18 @@ +{ + "config": { + "abort": { + "not_internet_accessible": "La instancia de Home Assistant debe estar accesible desde Internet para recibir mensajes de Plaato Airlock.", + "one_instance_allowed": "Solo una instancia es necesaria." + }, + "create_entry": { + "default": "Para enviar eventos a Home Assistant, deber\u00e1 configurar la funci\u00f3n de webhook en Plaato Airlock. \n\n Complete la siguiente informaci\u00f3n: \n\n - URL: `{webhook_url}` \n - M\u00e9todo: POST \n\n Consulte [la documentaci\u00f3n]({docs_url}) para obtener m\u00e1s detalles." + }, + "step": { + "user": { + "description": "\u00bfEst\u00e1 seguro de que deseas configurar Plaato Airlock?", + "title": "Configurar el Webhook de Plaato" + } + }, + "title": "Plaato Airlock" + } +} \ No newline at end of file diff --git a/homeassistant/components/plaato/.translations/hr.json b/homeassistant/components/plaato/.translations/hr.json new file mode 100644 index 00000000000..680571040b1 --- /dev/null +++ b/homeassistant/components/plaato/.translations/hr.json @@ -0,0 +1,18 @@ +{ + "config": { + "abort": { + "not_internet_accessible": "Va\u0161 Home Assistant mora biti dostupan s interneta za primanje poruka od Plaato Airlocka.", + "one_instance_allowed": "Potrebna je samo jedna instanca." + }, + "create_entry": { + "default": "Za slanje doga\u0111aja kod ku\u0107nog pomo\u0107nika, morat \u0107ete postaviti zna\u010dajku webhook u Plaato Airlock.\n\nIspunite sljede\u0107e informacije:\n\n-URL: ' {webhook_url} '\n-Metoda: POST\n\nZa dodatne detalje pogledajte [dokumentaciju] ({docs_url})." + }, + "step": { + "user": { + "description": "Jeste li sigurni da \u017eelite postaviti Plaato Airlock?", + "title": "Postavljanje Plaato Webhook" + } + }, + "title": "Plaato Airlock" + } +} \ No newline at end of file diff --git a/homeassistant/components/plaato/.translations/pl.json b/homeassistant/components/plaato/.translations/pl.json index aa7eb5f29bc..aac48ee4774 100644 --- a/homeassistant/components/plaato/.translations/pl.json +++ b/homeassistant/components/plaato/.translations/pl.json @@ -9,7 +9,7 @@ }, "step": { "user": { - "description": "Czy chcesz skonfigurowa\u0107 Plaato Airlock?", + "description": "Czy na pewno chcesz skonfigurowa\u0107 Airlock Plaato?", "title": "Konfiguracja Plaato Webhook" } }, diff --git a/homeassistant/components/point/.translations/es-419.json b/homeassistant/components/point/.translations/es-419.json index c20e3350272..7436513ba6f 100644 --- a/homeassistant/components/point/.translations/es-419.json +++ b/homeassistant/components/point/.translations/es-419.json @@ -1,6 +1,8 @@ { "config": { "abort": { + "already_setup": "Solo puede configurar una cuenta Point.", + "authorize_url_fail": "Error desconocido al generar una URL de autorizaci\u00f3n.", "external_setup": "Punto configurado con \u00e9xito desde otro flujo." }, "error": { diff --git a/homeassistant/components/ps4/.translations/es-419.json b/homeassistant/components/ps4/.translations/es-419.json index 093ee552951..0f7066df007 100644 --- a/homeassistant/components/ps4/.translations/es-419.json +++ b/homeassistant/components/ps4/.translations/es-419.json @@ -25,6 +25,12 @@ }, "description": "Ingresa tu informaci\u00f3n de PlayStation 4. Para 'PIN', navegue hasta 'Configuraci\u00f3n' en su consola PlayStation 4. Luego navegue a 'Configuraci\u00f3n de conexi\u00f3n de la aplicaci\u00f3n m\u00f3vil' y seleccione 'Agregar dispositivo'. Ingrese el PIN que se muestra.", "title": "Playstation 4" + }, + "mode": { + "data": { + "mode": "Modo de configuraci\u00f3n" + }, + "title": "Playstation 4" } }, "title": "Playstation 4" diff --git a/homeassistant/components/season/.translations/sensor.es-419.json b/homeassistant/components/season/.translations/sensor.es-419.json index 65df6a58b10..09ad22740cd 100644 --- a/homeassistant/components/season/.translations/sensor.es-419.json +++ b/homeassistant/components/season/.translations/sensor.es-419.json @@ -2,7 +2,6 @@ "state": { "autumn": "Oto\u00f1o", "spring": "Primavera", - "summer": "Verano", - "winter": "Invierno" + "summer": "Verano" } } \ No newline at end of file diff --git a/homeassistant/components/sensor/.translations/season.hr.json b/homeassistant/components/sensor/.translations/season.hr.json new file mode 100644 index 00000000000..ff36d1ca66b --- /dev/null +++ b/homeassistant/components/sensor/.translations/season.hr.json @@ -0,0 +1,8 @@ +{ + "state": { + "autumn": "Jesen", + "spring": "Prolje\u0107e", + "summer": "Ljeto", + "winter": "Zima" + } +} \ No newline at end of file diff --git a/homeassistant/components/somfy/.translations/fr.json b/homeassistant/components/somfy/.translations/fr.json index 6afb01169cb..ba873c4f029 100644 --- a/homeassistant/components/somfy/.translations/fr.json +++ b/homeassistant/components/somfy/.translations/fr.json @@ -1,5 +1,10 @@ { "config": { + "abort": { + "already_setup": "Vous ne pouvez configurer qu'un seul compte Somfy.", + "authorize_url_timeout": "D\u00e9lai de g\u00e9n\u00e9ration d'url autoriser.", + "missing_configuration": "Le composant Somfy n'est pas configur\u00e9. Veuillez suivre la documentation." + }, "create_entry": { "default": "Authentifi\u00e9 avec succ\u00e8s avec Somfy." }, diff --git a/homeassistant/components/somfy/.translations/hr.json b/homeassistant/components/somfy/.translations/hr.json new file mode 100644 index 00000000000..3a904102076 --- /dev/null +++ b/homeassistant/components/somfy/.translations/hr.json @@ -0,0 +1,8 @@ +{ + "config": { + "create_entry": { + "default": "Uspje\u0161no autentificirano sa Somfy." + }, + "title": "Somfy" + } +} \ No newline at end of file diff --git a/homeassistant/components/sonos/.translations/hr.json b/homeassistant/components/sonos/.translations/hr.json new file mode 100644 index 00000000000..c91f9a78c29 --- /dev/null +++ b/homeassistant/components/sonos/.translations/hr.json @@ -0,0 +1,10 @@ +{ + "config": { + "step": { + "confirm": { + "title": "Sonos" + } + }, + "title": "Sonos" + } +} \ No newline at end of file diff --git a/homeassistant/components/tplink/.translations/es-419.json b/homeassistant/components/tplink/.translations/es-419.json index 1d9fb41fc8c..2832804113a 100644 --- a/homeassistant/components/tplink/.translations/es-419.json +++ b/homeassistant/components/tplink/.translations/es-419.json @@ -1,7 +1,12 @@ { "config": { + "abort": { + "no_devices_found": "No se encontraron dispositivos TP-Link en la red.", + "single_instance_allowed": "Solo es necesaria una \u00fanica configuraci\u00f3n." + }, "step": { "confirm": { + "description": "\u00bfDesea configurar dispositivos inteligentes TP-Link?", "title": "TP-Link Smart Home" } }, diff --git a/homeassistant/components/traccar/.translations/en.json b/homeassistant/components/traccar/.translations/en.json new file mode 100644 index 00000000000..a8804835278 --- /dev/null +++ b/homeassistant/components/traccar/.translations/en.json @@ -0,0 +1,18 @@ +{ + "config": { + "abort": { + "not_internet_accessible": "Your Home Assistant instance needs to be accessible from the internet to receive messages from Traccar.", + "one_instance_allowed": "Only a single instance is necessary." + }, + "create_entry": { + "default": "To send events to Home Assistant, you will need to setup the webhook feature in Traccar.\n\nUse the following url: `{webhook_url}`\n\nSee [the documentation]({docs_url}) for further details." + }, + "step": { + "user": { + "description": "Are you sure you want to set up Traccar?", + "title": "Set up Traccar" + } + }, + "title": "Traccar" + } +} \ No newline at end of file diff --git a/homeassistant/components/tradfri/.translations/es-419.json b/homeassistant/components/tradfri/.translations/es-419.json index 55016606e2d..4b3e1ed52d4 100644 --- a/homeassistant/components/tradfri/.translations/es-419.json +++ b/homeassistant/components/tradfri/.translations/es-419.json @@ -1,9 +1,11 @@ { "config": { "abort": { - "already_configured": "El Bridge ya est\u00e1 configurado" + "already_configured": "El Bridge ya est\u00e1 configurado", + "already_in_progress": "La configuraci\u00f3n del puente ya est\u00e1 en progreso." }, "error": { + "cannot_connect": "No se puede conectar a la puerta de enlace.", "invalid_key": "Error al registrarse con la clave proporcionada. Si esto sigue sucediendo, intente reiniciar el gateway.", "timeout": "Tiempo de espera para validar el c\u00f3digo." }, diff --git a/homeassistant/components/tradfri/.translations/hr.json b/homeassistant/components/tradfri/.translations/hr.json new file mode 100644 index 00000000000..b9b9cc6c0eb --- /dev/null +++ b/homeassistant/components/tradfri/.translations/hr.json @@ -0,0 +1,15 @@ +{ + "config": { + "abort": { + "already_in_progress": "Konfiguracija premosnice je ve\u0107 u tijeku." + }, + "step": { + "auth": { + "data": { + "host": "Host" + } + } + }, + "title": "IKEA TR\u00c5DFRI" + } +} \ No newline at end of file diff --git a/homeassistant/components/tradfri/.translations/pl.json b/homeassistant/components/tradfri/.translations/pl.json index a61a028f396..e3fcfc89c5b 100644 --- a/homeassistant/components/tradfri/.translations/pl.json +++ b/homeassistant/components/tradfri/.translations/pl.json @@ -2,7 +2,7 @@ "config": { "abort": { "already_configured": "Mostek jest ju\u017c skonfigurowany", - "already_in_progress": "Konfigurowanie mostka jest ju\u017c w toku." + "already_in_progress": "Konfiguracja mostka jest ju\u017c w toku." }, "error": { "cannot_connect": "Nie mo\u017cna po\u0142\u0105czy\u0107 si\u0119 z bram\u0105.", diff --git a/homeassistant/components/unifi/.translations/en.json b/homeassistant/components/unifi/.translations/en.json index c484bfbf09f..3686148fdb6 100644 --- a/homeassistant/components/unifi/.translations/en.json +++ b/homeassistant/components/unifi/.translations/en.json @@ -1,41 +1,26 @@ { "config": { - "title": "UniFi Controller", - "step": { - "user": { - "title": "Set up UniFi Controller", - "data": { - "host": "Host", - "username": "User name", - "password": "Password", - "port": "Port", - "site": "Site ID", - "verify_ssl": "Controller using proper certificate" - } - } + "abort": { + "already_configured": "Controller site is already configured", + "user_privilege": "User needs to be administrator" }, "error": { "faulty_credentials": "Bad user credentials", "service_unavailable": "No service available" }, - "abort": { - "already_configured": "Controller site is already configured", - "user_privilege": "User needs to be administrator" - } - }, - "options": { "step": { - "init": { - "data": {} - }, - "device_tracker": { + "user": { "data": { - "detection_time": "Time in seconds from last seen until considered away", - "track_clients": "Track network clients", - "track_devices": "Track network devices (Ubiquiti devices)", - "track_wired_clients": "Include wired network clients" - } + "host": "Host", + "password": "Password", + "port": "Port", + "site": "Site ID", + "username": "User name", + "verify_ssl": "Controller using proper certificate" + }, + "title": "Set up UniFi Controller" } - } + }, + "title": "UniFi Controller" } } \ No newline at end of file diff --git a/homeassistant/components/unifi/.translations/hr.json b/homeassistant/components/unifi/.translations/hr.json new file mode 100644 index 00000000000..94a064f34b4 --- /dev/null +++ b/homeassistant/components/unifi/.translations/hr.json @@ -0,0 +1,14 @@ +{ + "config": { + "step": { + "user": { + "data": { + "host": "Host", + "password": "Lozinka", + "port": "Port", + "username": "Korisni\u010dko ime" + } + } + } + } +} \ No newline at end of file diff --git a/homeassistant/components/upnp/.translations/hr.json b/homeassistant/components/upnp/.translations/hr.json new file mode 100644 index 00000000000..941f72f2e7d --- /dev/null +++ b/homeassistant/components/upnp/.translations/hr.json @@ -0,0 +1,9 @@ +{ + "config": { + "error": { + "few": "Nekoliko", + "one": "Jedan", + "other": "Ostalo" + } + } +} \ No newline at end of file diff --git a/homeassistant/components/wemo/.translations/es-419.json b/homeassistant/components/wemo/.translations/es-419.json new file mode 100644 index 00000000000..df390e73dd1 --- /dev/null +++ b/homeassistant/components/wemo/.translations/es-419.json @@ -0,0 +1,15 @@ +{ + "config": { + "abort": { + "no_devices_found": "No se encontraron dispositivos Wemo en la red.", + "single_instance_allowed": "Solo es posible una \u00fanica configuraci\u00f3n de Wemo." + }, + "step": { + "confirm": { + "description": "\u00bfDesea configurar Wemo?", + "title": "Wemo" + } + }, + "title": "Wemo" + } +} \ No newline at end of file diff --git a/homeassistant/components/wemo/.translations/hr.json b/homeassistant/components/wemo/.translations/hr.json new file mode 100644 index 00000000000..389bfbd3cb1 --- /dev/null +++ b/homeassistant/components/wemo/.translations/hr.json @@ -0,0 +1,5 @@ +{ + "config": { + "title": "Wemo" + } +} \ No newline at end of file diff --git a/homeassistant/components/wwlln/.translations/es-419.json b/homeassistant/components/wwlln/.translations/es-419.json new file mode 100644 index 00000000000..d185410a4ef --- /dev/null +++ b/homeassistant/components/wwlln/.translations/es-419.json @@ -0,0 +1,18 @@ +{ + "config": { + "error": { + "identifier_exists": "Lugar ya registrado" + }, + "step": { + "user": { + "data": { + "latitude": "Latitud", + "longitude": "Longitud", + "radius": "Radio (usando su sistema de unidad base)" + }, + "title": "Complete su informaci\u00f3n de ubicaci\u00f3n." + } + }, + "title": "Red Mundial de Localizaci\u00f3n de Rayos (WWLLN)" + } +} \ No newline at end of file diff --git a/homeassistant/components/wwlln/.translations/hr.json b/homeassistant/components/wwlln/.translations/hr.json new file mode 100644 index 00000000000..09ca1a0273f --- /dev/null +++ b/homeassistant/components/wwlln/.translations/hr.json @@ -0,0 +1,18 @@ +{ + "config": { + "error": { + "identifier_exists": "Lokacija je ve\u0107 registrirana" + }, + "step": { + "user": { + "data": { + "latitude": "Zemljopisna \u0161irina", + "longitude": "Zemljopisna du\u017eina", + "radius": "Radius (koriste\u0107i sustav osnovne jedinice)" + }, + "title": "Ispunite podatke o lokaciji." + } + }, + "title": "Svjetska mre\u017ea lokacija munje (WWLLN)" + } +} \ No newline at end of file diff --git a/homeassistant/components/wwlln/.translations/pl.json b/homeassistant/components/wwlln/.translations/pl.json index d233b485bd0..704c7baeecb 100644 --- a/homeassistant/components/wwlln/.translations/pl.json +++ b/homeassistant/components/wwlln/.translations/pl.json @@ -8,11 +8,11 @@ "data": { "latitude": "Szeroko\u015b\u0107 geograficzna", "longitude": "D\u0142ugo\u015b\u0107 geograficzna", - "radius": "Promie\u0144" + "radius": "Promie\u0144 (przy u\u017cyciu systemu jednostki bazowej)" }, - "title": "Wprowad\u017a dane o swojej lokalizacji." + "title": "Wpisz informacje o swojej lokalizacji." } }, - "title": "World Wide Lightning Location Network (WWLLN)" + "title": "\u015awiatowa sie\u0107 lokalizacji wy\u0142adowa\u0144 atmosferycznych (WWLLN)" } } \ No newline at end of file diff --git a/homeassistant/components/zone/.translations/hr.json b/homeassistant/components/zone/.translations/hr.json new file mode 100644 index 00000000000..8a9f543be0a --- /dev/null +++ b/homeassistant/components/zone/.translations/hr.json @@ -0,0 +1,21 @@ +{ + "config": { + "error": { + "name_exists": "Ime ve\u0107 postoji" + }, + "step": { + "init": { + "data": { + "icon": "Ikona", + "latitude": "Zemljopisna \u0161irina", + "longitude": "Zemljopisna du\u017eina", + "name": "Ime", + "passive": "Pasivno", + "radius": "Radijus" + }, + "title": "Definirajte parametre zone" + } + }, + "title": "Zona" + } +} \ No newline at end of file diff --git a/homeassistant/components/zwave/.translations/es-419.json b/homeassistant/components/zwave/.translations/es-419.json index 2e246fb9931..f2ca1a19aa4 100644 --- a/homeassistant/components/zwave/.translations/es-419.json +++ b/homeassistant/components/zwave/.translations/es-419.json @@ -4,6 +4,9 @@ "already_configured": "Z-Wave ya est\u00e1 configurado", "one_instance_only": "El componente solo admite una instancia de Z-Wave" }, + "error": { + "option_error": "La validaci\u00f3n de Z-Wave fall\u00f3. \u00bfEs correcta la ruta a la memoria USB?" + }, "step": { "user": { "data": { From 1e61d50fc52d6467565dde34b8d44905204a9093 Mon Sep 17 00:00:00 2001 From: Florian Klien Date: Tue, 27 Aug 2019 07:34:58 +0200 Subject: [PATCH 28/40] luci device-tracker dependency fix (#26215) * luci device-tracker dependency fix fixes issue #25758 * luci device-tracker fix, requirements_all --- homeassistant/components/luci/manifest.json | 3 ++- requirements_all.txt | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/luci/manifest.json b/homeassistant/components/luci/manifest.json index 27b6a2da59f..153f6b5aea6 100644 --- a/homeassistant/components/luci/manifest.json +++ b/homeassistant/components/luci/manifest.json @@ -3,7 +3,8 @@ "name": "Luci", "documentation": "https://www.home-assistant.io/components/luci", "requirements": [ - "openwrt-luci-rpc==1.1.0" + "openwrt-luci-rpc==1.1.0", + "packaging==19.1" ], "dependencies": [], "codeowners": ["@fbradyirl"] diff --git a/requirements_all.txt b/requirements_all.txt index 42982b34134..10f3cb190c6 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -894,6 +894,9 @@ openwrt-luci-rpc==1.1.0 # homeassistant.components.orvibo orvibo==1.1.1 +# homeassistant.components.luci +packaging==19.1 + # homeassistant.components.mqtt # homeassistant.components.shiftr paho-mqtt==1.4.0 From d156648c55e82ab833f37130e5f2f21c7543a1c6 Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Tue, 27 Aug 2019 21:06:14 +0200 Subject: [PATCH 29/40] deCONZ normalizes cover values to follow zigbee spec (#26240) --- homeassistant/components/deconz/cover.py | 44 +++--------------------- tests/components/deconz/test_cover.py | 6 ++-- 2 files changed, 8 insertions(+), 42 deletions(-) diff --git a/homeassistant/components/deconz/cover.py b/homeassistant/components/deconz/cover.py index caa46e10f99..be4088a5c86 100644 --- a/homeassistant/components/deconz/cover.py +++ b/homeassistant/components/deconz/cover.py @@ -14,8 +14,6 @@ from .const import COVER_TYPES, DAMPERS, NEW_LIGHT, WINDOW_COVERS from .deconz_device import DeconzDevice from .gateway import get_gateway_from_config_entry -ZIGBEE_SPEC = ["lumi.curtain"] - async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Old way of setting up deCONZ platforms.""" @@ -35,13 +33,8 @@ async def async_setup_entry(hass, config_entry, async_add_entities): entities = [] for light in lights: - if light.type in COVER_TYPES: - if light.modelid in ZIGBEE_SPEC: - entities.append(DeconzCoverZigbeeSpec(light, gateway)) - - else: - entities.append(DeconzCover(light, gateway)) + entities.append(DeconzCover(light, gateway)) async_add_entities(entities, True) @@ -69,14 +62,12 @@ class DeconzCover(DeconzDevice, CoverDevice): @property def current_cover_position(self): """Return the current position of the cover.""" - if self.is_closed: - return 0 - return int(self._device.brightness / 255 * 100) + return 100 - int(self._device.brightness / 255 * 100) @property def is_closed(self): """Return if the cover is closed.""" - return not self._device.state + return self._device.state @property def device_class(self): @@ -96,9 +87,9 @@ class DeconzCover(DeconzDevice, CoverDevice): position = kwargs[ATTR_POSITION] data = {"on": False} - if position > 0: + if position < 100: data["on"] = True - data["bri"] = int(position / 100 * 255) + data["bri"] = 255 - int(position / 100 * 255) await self._device.async_set_state(data) @@ -116,28 +107,3 @@ class DeconzCover(DeconzDevice, CoverDevice): """Stop cover.""" data = {"bri_inc": 0} await self._device.async_set_state(data) - - -class DeconzCoverZigbeeSpec(DeconzCover): - """Zigbee spec is the inverse of how deCONZ normally reports attributes.""" - - @property - def current_cover_position(self): - """Return the current position of the cover.""" - return 100 - int(self._device.brightness / 255 * 100) - - @property - def is_closed(self): - """Return if the cover is closed.""" - return self._device.state - - async def async_set_cover_position(self, **kwargs): - """Move the cover to a specific position.""" - position = kwargs[ATTR_POSITION] - data = {"on": False} - - if position < 100: - data["on"] = True - data["bri"] = 255 - int(position / 100 * 255) - - await self._device.async_set_state(data) diff --git a/tests/components/deconz/test_cover.py b/tests/components/deconz/test_cover.py index f264877b77a..7230ff4fb7b 100644 --- a/tests/components/deconz/test_cover.py +++ b/tests/components/deconz/test_cover.py @@ -16,7 +16,7 @@ SUPPORTED_COVERS = { "id": "Cover 1 id", "name": "Cover 1 name", "type": "Level controllable output", - "state": {"bri": 255, "reachable": True}, + "state": {"bri": 255, "on": False, "reachable": True}, "modelid": "Not zigbee spec", "uniqueid": "00:00:00:00:00:00:00:00-00", }, @@ -24,7 +24,7 @@ SUPPORTED_COVERS = { "id": "Cover 2 id", "name": "Cover 2 name", "type": "Window covering device", - "state": {"bri": 255, "reachable": True}, + "state": {"bri": 255, "on": True, "reachable": True}, "modelid": "lumi.curtain", }, } @@ -107,7 +107,7 @@ async def test_cover(hass): cover_1 = hass.states.get("cover.cover_1_name") assert cover_1 is not None - assert cover_1.state == "closed" + assert cover_1.state == "open" gateway.api.lights["1"].async_update({}) From bbc50498163391e50f3f98e395f64a893d1f34fc Mon Sep 17 00:00:00 2001 From: Johann Kellerman Date: Wed, 28 Aug 2019 09:21:21 +0200 Subject: [PATCH 30/40] SMA beta fix #26225 (#26244) --- homeassistant/components/sma/sensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/sma/sensor.py b/homeassistant/components/sma/sensor.py index b2692a37059..34aed146cf0 100644 --- a/homeassistant/components/sma/sensor.py +++ b/homeassistant/components/sma/sensor.py @@ -143,7 +143,6 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= hass_sensors.append(SMAsensor(sensor_def[name], sub_sensors)) used_sensors.append(name) used_sensors.extend(attr) - used_sensors = [sensor_def[s] for s in set(used_sensors)] if isinstance(config_sensors, list): if not config_sensors: # Use all sensors by default @@ -152,6 +151,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= for sensor in used_sensors: hass_sensors.append(SMAsensor(sensor_def[sensor], [])) + used_sensors = [sensor_def[s] for s in set(used_sensors)] async_add_entities(hass_sensors) # Init the SMA interface From 1c473487b18cef3660d32d1380ca79ca725501a3 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 28 Aug 2019 13:38:56 -0700 Subject: [PATCH 31/40] Bumped version to 0.98.0 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 4d2998b85b8..9a9b098aabb 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 98 -PATCH_VERSION = "0b2" +PATCH_VERSION = "0" __short_version__ = "{}.{}".format(MAJOR_VERSION, MINOR_VERSION) __version__ = "{}.{}".format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 6, 0) From 69ddca6f68415ebaa32f3e2e89f9d84d1d05b5e4 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 28 Aug 2019 13:43:45 -0700 Subject: [PATCH 32/40] Updated frontend to 20190828.0 --- 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 78f87639a99..fa6145a7af2 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/components/frontend", "requirements": [ - "home-assistant-frontend==20190825.0" + "home-assistant-frontend==20190828.0" ], "dependencies": [ "api", diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 873a5aaf31d..a1ffd515c5b 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -11,7 +11,7 @@ contextvars==2.4;python_version<"3.7" cryptography==2.7 distro==1.4.0 hass-nabucasa==0.17 -home-assistant-frontend==20190825.0 +home-assistant-frontend==20190828.0 importlib-metadata==0.19 jinja2>=2.10.1 netdisco==2.6.0 diff --git a/requirements_all.txt b/requirements_all.txt index 10f3cb190c6..e749340a8cb 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -624,7 +624,7 @@ hole==0.5.0 holidays==0.9.11 # homeassistant.components.frontend -home-assistant-frontend==20190825.0 +home-assistant-frontend==20190828.0 # homeassistant.components.zwave homeassistant-pyozw==0.1.4 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 96b82caf968..1aad0450390 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -176,7 +176,7 @@ hdate==0.9.0 holidays==0.9.11 # homeassistant.components.frontend -home-assistant-frontend==20190825.0 +home-assistant-frontend==20190828.0 # homeassistant.components.homekit_controller homekit[IP]==0.15.0 From 04d2dbb57366148cbf855bd224b7df390bd8c515 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 29 Aug 2019 12:32:15 -0700 Subject: [PATCH 33/40] Add translations --- .../components/adguard/.translations/fr.json | 11 ++++++++--- homeassistant/components/axis/.translations/fr.json | 1 + .../components/deconz/.translations/en.json | 11 +++++++++++ .../components/deconz/.translations/fr.json | 2 ++ .../components/life360/.translations/en.json | 1 + .../components/plaato/.translations/fr.json | 13 ++++++++++++- .../components/unifi/.translations/en.json | 12 ++++++++++++ homeassistant/components/wemo/.translations/fr.json | 5 +++++ 8 files changed, 52 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/adguard/.translations/fr.json b/homeassistant/components/adguard/.translations/fr.json index 7a58c396345..6543ddd50bc 100644 --- a/homeassistant/components/adguard/.translations/fr.json +++ b/homeassistant/components/adguard/.translations/fr.json @@ -1,13 +1,15 @@ { "config": { "abort": { - "existing_instance_updated": "La configuration existante a \u00e9t\u00e9 mise \u00e0 jour." + "existing_instance_updated": "La configuration existante a \u00e9t\u00e9 mise \u00e0 jour.", + "single_instance_allowed": "Une seule configuration d'AdGuard Home est autoris\u00e9e." }, "error": { "connection_error": "\u00c9chec de connexion." }, "step": { "hassio_confirm": { + "description": "Voulez-vous configurer Home Assistant pour qu'il se connecte \u00e0 AdGuard Home fourni par le module compl\u00e9mentaire Hass.io: {addon} ?", "title": "AdGuard Home via le module compl\u00e9mentaire Hass.io" }, "user": { @@ -16,8 +18,11 @@ "password": "Mot de passe", "port": "Port", "ssl": "AdGuard Home utilise un certificat SSL", - "username": "Nom d'utilisateur" - } + "username": "Nom d'utilisateur", + "verify_ssl": "AdGuard Home utilise un certificat appropri\u00e9" + }, + "description": "Configurez votre instance AdGuard Home pour permettre la surveillance et le contr\u00f4le.", + "title": "Liez votre AdGuard Home." } }, "title": "AdGuard Home" diff --git a/homeassistant/components/axis/.translations/fr.json b/homeassistant/components/axis/.translations/fr.json index e85fceaf463..24afb4a226c 100644 --- a/homeassistant/components/axis/.translations/fr.json +++ b/homeassistant/components/axis/.translations/fr.json @@ -8,6 +8,7 @@ }, "error": { "already_configured": "L'appareil est d\u00e9j\u00e0 configur\u00e9", + "already_in_progress": "Le flux de configuration de l'appareil est d\u00e9j\u00e0 en cours.", "device_unavailable": "L'appareil n'est pas disponible", "faulty_credentials": "Mauvaises informations d'identification de l'utilisateur" }, diff --git a/homeassistant/components/deconz/.translations/en.json b/homeassistant/components/deconz/.translations/en.json index dd8f1cc4026..57da3c706a0 100644 --- a/homeassistant/components/deconz/.translations/en.json +++ b/homeassistant/components/deconz/.translations/en.json @@ -40,5 +40,16 @@ } }, "title": "deCONZ Zigbee gateway" + }, + "options": { + "step": { + "async_step_deconz_devices": { + "data": { + "allow_clip_sensor": "Allow deCONZ CLIP sensors", + "allow_deconz_groups": "Allow deCONZ light groups" + }, + "description": "Configure visibility of deCONZ device types" + } + } } } \ No newline at end of file diff --git a/homeassistant/components/deconz/.translations/fr.json b/homeassistant/components/deconz/.translations/fr.json index 3d658ca00b0..9b98914314a 100644 --- a/homeassistant/components/deconz/.translations/fr.json +++ b/homeassistant/components/deconz/.translations/fr.json @@ -2,7 +2,9 @@ "config": { "abort": { "already_configured": "Ce pont est d\u00e9j\u00e0 configur\u00e9", + "already_in_progress": "Le flux de configuration pour le pont est d\u00e9j\u00e0 en cours.", "no_bridges": "Aucun pont deCONZ n'a \u00e9t\u00e9 d\u00e9couvert", + "not_deconz_bridge": "Pas un pont deCONZ", "one_instance_only": "Le composant prend uniquement en charge une instance deCONZ", "updated_instance": "Instance deCONZ mise \u00e0 jour avec la nouvelle adresse d'h\u00f4te" }, diff --git a/homeassistant/components/life360/.translations/en.json b/homeassistant/components/life360/.translations/en.json index 2c187ba0470..e6017339b73 100644 --- a/homeassistant/components/life360/.translations/en.json +++ b/homeassistant/components/life360/.translations/en.json @@ -10,6 +10,7 @@ "error": { "invalid_credentials": "Invalid credentials", "invalid_username": "Invalid username", + "unexpected": "Unexpected error communicating with Life360 server", "user_already_configured": "Account has already been configured" }, "step": { diff --git a/homeassistant/components/plaato/.translations/fr.json b/homeassistant/components/plaato/.translations/fr.json index 091c680be4c..d710886b84b 100644 --- a/homeassistant/components/plaato/.translations/fr.json +++ b/homeassistant/components/plaato/.translations/fr.json @@ -1,7 +1,18 @@ { "config": { "abort": { + "not_internet_accessible": "Votre instance de Home Assistant doit \u00eatre accessible depuis Internet pour recevoir les messages de Plaato Airlock.", "one_instance_allowed": "Une seule instance est n\u00e9cessaire." - } + }, + "create_entry": { + "default": "Pour envoyer des \u00e9v\u00e9nements \u00e0 Home Assistant, vous devez configurer la fonction Webhook dans Plaato Airlock. \n\n Remplissez les informations suivantes: \n\n - URL: ` {webhook_url} ` \n - M\u00e9thode: POST \n\n Voir [la documentation] ( {docs_url} ) pour plus de d\u00e9tails." + }, + "step": { + "user": { + "description": "\u00cates-vous s\u00fbr de vouloir installer le Plaato Airlock ?", + "title": "Configurer le Webhook Plaato" + } + }, + "title": "Plaato Airlock" } } \ No newline at end of file diff --git a/homeassistant/components/unifi/.translations/en.json b/homeassistant/components/unifi/.translations/en.json index 3686148fdb6..2025bad6246 100644 --- a/homeassistant/components/unifi/.translations/en.json +++ b/homeassistant/components/unifi/.translations/en.json @@ -22,5 +22,17 @@ } }, "title": "UniFi Controller" + }, + "options": { + "step": { + "device_tracker": { + "data": { + "detection_time": "Time in seconds from last seen until considered away", + "track_clients": "Track network clients", + "track_devices": "Track network devices (Ubiquiti devices)", + "track_wired_clients": "Include wired network clients" + } + } + } } } \ No newline at end of file diff --git a/homeassistant/components/wemo/.translations/fr.json b/homeassistant/components/wemo/.translations/fr.json index c1c8830cb25..08b55e2366a 100644 --- a/homeassistant/components/wemo/.translations/fr.json +++ b/homeassistant/components/wemo/.translations/fr.json @@ -1,7 +1,12 @@ { "config": { + "abort": { + "no_devices_found": "Aucun p\u00e9riph\u00e9rique Wemo trouv\u00e9 sur le r\u00e9seau.", + "single_instance_allowed": "Une seule configuration de Wemo est possible." + }, "step": { "confirm": { + "description": "Voulez-vous configurer Wemo?", "title": "Wemo" } }, From 5f850a7dc7b7452640d8d2d6ccb6f9377b18398b Mon Sep 17 00:00:00 2001 From: Eliseo Martelli Date: Thu, 29 Aug 2019 21:36:21 +0200 Subject: [PATCH 34/40] Update sensor.py (#26209) --- homeassistant/components/qbittorrent/sensor.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/qbittorrent/sensor.py b/homeassistant/components/qbittorrent/sensor.py index a257b0e317a..2900496a01e 100644 --- a/homeassistant/components/qbittorrent/sensor.py +++ b/homeassistant/components/qbittorrent/sensor.py @@ -41,7 +41,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( ) -async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): +def setup_platform(hass, config, add_entities, discovery_info=None): """Set up the qBittorrent sensors.""" from qbittorrent.client import Client, LoginRequired @@ -62,7 +62,7 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= sensor = QBittorrentSensor(sensor_type, client, name, LoginRequired) dev.append(sensor) - async_add_entities(dev, True) + add_entities(dev, True) def format_speed(speed): @@ -105,7 +105,7 @@ class QBittorrentSensor(Entity): """Return the unit of measurement of this entity, if any.""" return self._unit_of_measurement - async def async_update(self): + def update(self): """Get the latest data from qBittorrent and updates the state.""" try: data = self.client.sync() @@ -113,7 +113,6 @@ class QBittorrentSensor(Entity): except RequestException: _LOGGER.error("Connection lost") self._available = False - return except self._exception: _LOGGER.error("Invalid authentication") return From 069e762da0c81f3f7097156314968015f57300c2 Mon Sep 17 00:00:00 2001 From: SukramJ Date: Wed, 28 Aug 2019 22:38:20 +0200 Subject: [PATCH 35/40] Fix for 0.98: Don't update disabled entities (Homematic IP Cloud) (#26236) * Homematic IP Cloud Fix: Don't update disabled entities * Added enabled to entity.py * Update test for enabled * Update entity.py --- homeassistant/components/homematicip_cloud/device.py | 12 ++++++++++-- homeassistant/helpers/entity.py | 5 +++++ tests/helpers/test_entity.py | 2 ++ 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/homematicip_cloud/device.py b/homeassistant/components/homematicip_cloud/device.py index b086eaa29c7..71855d7c3f5 100644 --- a/homeassistant/components/homematicip_cloud/device.py +++ b/homeassistant/components/homematicip_cloud/device.py @@ -76,8 +76,16 @@ class HomematicipGenericDevice(Entity): def _async_device_changed(self, *args, **kwargs): """Handle device state changes.""" - _LOGGER.debug("Event %s (%s)", self.name, self._device.modelType) - self.async_schedule_update_ha_state() + # Don't update disabled entities + if self.enabled: + _LOGGER.debug("Event %s (%s)", self.name, self._device.modelType) + self.async_schedule_update_ha_state() + else: + _LOGGER.debug( + "Device Changed Event for %s (%s) not fired. Entity is disabled.", + self.name, + self._device.modelType, + ) @property def name(self) -> str: diff --git a/homeassistant/helpers/entity.py b/homeassistant/helpers/entity.py index bd96e1bafdb..91562b9046d 100644 --- a/homeassistant/helpers/entity.py +++ b/homeassistant/helpers/entity.py @@ -229,6 +229,11 @@ class Entity: # are used to perform a very specific function. Overwriting these may # produce undesirable effects in the entity's operation. + @property + def enabled(self): + """Return if the entity is enabled in the entity registry.""" + return self.registry_entry is None or not self.registry_entry.disabled + @callback def async_set_context(self, context): """Set the context the entity currently operates under.""" diff --git a/tests/helpers/test_entity.py b/tests/helpers/test_entity.py index 3c89a5c6537..18cedf1c46a 100644 --- a/tests/helpers/test_entity.py +++ b/tests/helpers/test_entity.py @@ -552,8 +552,10 @@ async def test_disabled_in_entity_registry(hass): await hass.async_block_till_done() assert entry2 != entry assert ent.registry_entry == entry2 + assert ent.enabled is True entry3 = registry.async_update_entity("hello.world", disabled_by="user") await hass.async_block_till_done() assert entry3 != entry2 assert ent.registry_entry == entry3 + assert ent.enabled is False From bb52e1736499fc995a5439fdd2b2a4d52511d261 Mon Sep 17 00:00:00 2001 From: "David F. Mulcahey" Date: Thu, 29 Aug 2019 15:44:53 -0400 Subject: [PATCH 36/40] Fix ZHA state restore by always restoring last seen on devices (#26271) * fix state restore by always restoring last seen * cleanup --- homeassistant/components/zha/core/gateway.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/zha/core/gateway.py b/homeassistant/components/zha/core/gateway.py index 9cf93b56581..3d8c3e8fd90 100644 --- a/homeassistant/components/zha/core/gateway.py +++ b/homeassistant/components/zha/core/gateway.py @@ -304,6 +304,8 @@ class ZHAGateway: manufacturer=zha_device.manufacturer, model=zha_device.model, ) + entry = self.zha_storage.async_get_or_create(zha_device) + zha_device.async_update_last_seen(entry.last_seen) return zha_device @callback @@ -356,10 +358,6 @@ class ZHAGateway: ) await self._async_device_joined(device, zha_device) - # This is real traffic from a device so lets update last seen on the entry - entry = self.zha_storage.async_get_or_create(zha_device) - zha_device.async_update_last_seen(entry.last_seen) - device_info = async_get_device_info( self._hass, zha_device, self.ha_device_registry ) From 5676f6fb86abbbaa6d34784cede1bc8b618a6d24 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 29 Aug 2019 13:06:34 -0700 Subject: [PATCH 37/40] Bumped version to 0.98.1 --- homeassistant/components/tuya/switch.py | 7 ++++++- homeassistant/const.py | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/tuya/switch.py b/homeassistant/components/tuya/switch.py index 9c021766637..a0d262aa085 100644 --- a/homeassistant/components/tuya/switch.py +++ b/homeassistant/components/tuya/switch.py @@ -26,11 +26,12 @@ class TuyaSwitch(TuyaDevice, SwitchDevice): """Init Tuya switch device.""" super().__init__(tuya) self.entity_id = ENTITY_ID_FORMAT.format(tuya.object_id()) + self._is_on = False @property def is_on(self): """Return true if switch is on.""" - return self.tuya.state() + return self._is_on def turn_on(self, **kwargs): """Turn the switch on.""" @@ -39,3 +40,7 @@ class TuyaSwitch(TuyaDevice, SwitchDevice): def turn_off(self, **kwargs): """Turn the device off.""" self.tuya.turn_off() + + def update(self): + """Update switch device.""" + self._is_on = self.tuya.state() diff --git a/homeassistant/const.py b/homeassistant/const.py index 9a9b098aabb..2f2546378db 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 98 -PATCH_VERSION = "0" +PATCH_VERSION = "1" __short_version__ = "{}.{}".format(MAJOR_VERSION, MINOR_VERSION) __version__ = "{}.{}".format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 6, 0) From 015adbbac0539cdcd8ceb7c7d6bbf838c1b0a2cf Mon Sep 17 00:00:00 2001 From: mbo18 Date: Thu, 29 Aug 2019 22:22:52 +0200 Subject: [PATCH 38/40] Fix missing DarkSky mdi icon (#26274) * Fix missing DarkSky mdi icon Fix mdi icon for DarkSky * fix icon * Update weather.py --- homeassistant/components/darksky/sensor.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/darksky/sensor.py b/homeassistant/components/darksky/sensor.py index e5886ae5e59..0f33935c66c 100644 --- a/homeassistant/components/darksky/sensor.py +++ b/homeassistant/components/darksky/sensor.py @@ -193,7 +193,7 @@ SENSOR_TYPES = { "%", "%", "%", - "mdi:weather-partlycloudy", + "mdi:weather-partly-cloudy", ["currently", "hourly", "daily"], ], "humidity": [ @@ -380,11 +380,11 @@ CONDITION_PICTURES = { "cloudy": ["/static/images/darksky/weather-cloudy.svg", "mdi:weather-cloudy"], "partly-cloudy-day": [ "/static/images/darksky/weather-partlycloudy.svg", - "mdi:weather-partlycloudy", + "mdi:weather-partly-cloudy", ], "partly-cloudy-night": [ "/static/images/darksky/weather-cloudy.svg", - "mdi:weather-partlycloudy", + "mdi:weather-partly-cloudy", ], } From 5413cbd19572a5b1c0bf7cc124c23de6c50d5471 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 29 Aug 2019 13:22:29 -0700 Subject: [PATCH 39/40] Fix partly cloudy (#26277) --- homeassistant/components/buienradar/sensor.py | 10 +++++----- homeassistant/components/mysensors/sensor.py | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/buienradar/sensor.py b/homeassistant/components/buienradar/sensor.py index 72da5164dab..841cc428bac 100644 --- a/homeassistant/components/buienradar/sensor.py +++ b/homeassistant/components/buienradar/sensor.py @@ -108,11 +108,11 @@ SENSOR_TYPES = { "rainchance_3d": ["Rainchance 3d", "%", "mdi:weather-pouring"], "rainchance_4d": ["Rainchance 4d", "%", "mdi:weather-pouring"], "rainchance_5d": ["Rainchance 5d", "%", "mdi:weather-pouring"], - "sunchance_1d": ["Sunchance 1d", "%", "mdi:weather-partlycloudy"], - "sunchance_2d": ["Sunchance 2d", "%", "mdi:weather-partlycloudy"], - "sunchance_3d": ["Sunchance 3d", "%", "mdi:weather-partlycloudy"], - "sunchance_4d": ["Sunchance 4d", "%", "mdi:weather-partlycloudy"], - "sunchance_5d": ["Sunchance 5d", "%", "mdi:weather-partlycloudy"], + "sunchance_1d": ["Sunchance 1d", "%", "mdi:weather-partly-cloudy"], + "sunchance_2d": ["Sunchance 2d", "%", "mdi:weather-partly-cloudy"], + "sunchance_3d": ["Sunchance 3d", "%", "mdi:weather-partly-cloudy"], + "sunchance_4d": ["Sunchance 4d", "%", "mdi:weather-partly-cloudy"], + "sunchance_5d": ["Sunchance 5d", "%", "mdi:weather-partly-cloudy"], "windforce_1d": ["Wind force 1d", "Bft", "mdi:weather-windy"], "windforce_2d": ["Wind force 2d", "Bft", "mdi:weather-windy"], "windforce_3d": ["Wind force 3d", "Bft", "mdi:weather-windy"], diff --git a/homeassistant/components/mysensors/sensor.py b/homeassistant/components/mysensors/sensor.py index 8eaf336e9ba..a7d1cad98fa 100644 --- a/homeassistant/components/mysensors/sensor.py +++ b/homeassistant/components/mysensors/sensor.py @@ -14,7 +14,7 @@ SENSORS = { "V_DIMMER": ["%", "mdi:percent"], "V_PERCENTAGE": ["%", "mdi:percent"], "V_PRESSURE": [None, "mdi:gauge"], - "V_FORECAST": [None, "mdi:weather-partlycloudy"], + "V_FORECAST": [None, "mdi:weather-partly-cloudy"], "V_RAIN": [None, "mdi:weather-rainy"], "V_RAINRATE": [None, "mdi:weather-rainy"], "V_WIND": [None, "mdi:weather-windy"], From 1ca2f1906af7095a1f656761391187acb61130ee Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Thu, 29 Aug 2019 23:04:01 +0200 Subject: [PATCH 40/40] UniFi - dont schedule updates on disabled entities (#26278) * Dont schedule updates on disabled entities * Use entity enabled since it is available --- homeassistant/components/unifi/device_tracker.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/unifi/device_tracker.py b/homeassistant/components/unifi/device_tracker.py index c8024808e39..4845e9222ce 100644 --- a/homeassistant/components/unifi/device_tracker.py +++ b/homeassistant/components/unifi/device_tracker.py @@ -150,7 +150,9 @@ def update_items(controller, async_add_entities, tracked): for client_id in controller.api.clients: - if client_id in tracked and tracked[client_id].entity_id: + if client_id in tracked: + if not tracked[client_id].enabled: + continue LOGGER.debug( "Updating UniFi tracked client %s (%s)", tracked[client_id].entity_id, @@ -183,7 +185,9 @@ def update_items(controller, async_add_entities, tracked): for device_id in controller.api.devices: - if device_id in tracked and tracked[device_id].entity_id: + if device_id in tracked: + if not tracked[device_id].enabled: + continue LOGGER.debug( "Updating UniFi tracked device %s (%s)", tracked[device_id].entity_id,