From 8259ce986858d4135a1f024bbd63a5e1f45d6ad2 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Mon, 11 Jul 2022 10:49:06 +0200 Subject: [PATCH 01/22] Migrate ecobee to native_* (#74043) --- homeassistant/components/ecobee/weather.py | 43 +++++++++++----------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/homeassistant/components/ecobee/weather.py b/homeassistant/components/ecobee/weather.py index 1c330ceb4e2..aca4dcdf2f5 100644 --- a/homeassistant/components/ecobee/weather.py +++ b/homeassistant/components/ecobee/weather.py @@ -7,20 +7,24 @@ from pyecobee.const import ECOBEE_STATE_UNKNOWN from homeassistant.components.weather import ( ATTR_FORECAST_CONDITION, - ATTR_FORECAST_TEMP, - ATTR_FORECAST_TEMP_LOW, + ATTR_FORECAST_NATIVE_TEMP, + ATTR_FORECAST_NATIVE_TEMP_LOW, + ATTR_FORECAST_NATIVE_WIND_SPEED, ATTR_FORECAST_TIME, ATTR_FORECAST_WIND_BEARING, - ATTR_FORECAST_WIND_SPEED, WeatherEntity, ) from homeassistant.config_entries import ConfigEntry -from homeassistant.const import PRESSURE_HPA, PRESSURE_INHG, TEMP_FAHRENHEIT +from homeassistant.const import ( + LENGTH_METERS, + PRESSURE_HPA, + SPEED_METERS_PER_SECOND, + TEMP_FAHRENHEIT, +) from homeassistant.core import HomeAssistant from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.util import dt as dt_util -from homeassistant.util.pressure import convert as pressure_convert from .const import ( DOMAIN, @@ -49,6 +53,11 @@ async def async_setup_entry( class EcobeeWeather(WeatherEntity): """Representation of Ecobee weather data.""" + _attr_native_pressure_unit = PRESSURE_HPA + _attr_native_temperature_unit = TEMP_FAHRENHEIT + _attr_native_visibility_unit = LENGTH_METERS + _attr_native_wind_speed_unit = SPEED_METERS_PER_SECOND + def __init__(self, data, name, index): """Initialize the Ecobee weather platform.""" self.data = data @@ -101,7 +110,7 @@ class EcobeeWeather(WeatherEntity): return None @property - def temperature(self): + def native_temperature(self): """Return the temperature.""" try: return float(self.get_forecast(0, "temperature")) / 10 @@ -109,18 +118,10 @@ class EcobeeWeather(WeatherEntity): return None @property - def temperature_unit(self): - """Return the unit of measurement.""" - return TEMP_FAHRENHEIT - - @property - def pressure(self): + def native_pressure(self): """Return the pressure.""" try: pressure = self.get_forecast(0, "pressure") - if not self.hass.config.units.is_metric: - pressure = pressure_convert(pressure, PRESSURE_HPA, PRESSURE_INHG) - return round(pressure, 2) return round(pressure) except ValueError: return None @@ -134,15 +135,15 @@ class EcobeeWeather(WeatherEntity): return None @property - def visibility(self): + def native_visibility(self): """Return the visibility.""" try: - return int(self.get_forecast(0, "visibility")) / 1000 + return int(self.get_forecast(0, "visibility")) except ValueError: return None @property - def wind_speed(self): + def native_wind_speed(self): """Return the wind speed.""" try: return int(self.get_forecast(0, "windSpeed")) @@ -202,13 +203,13 @@ def _process_forecast(json): json["weatherSymbol"] ] if json["tempHigh"] != ECOBEE_STATE_UNKNOWN: - forecast[ATTR_FORECAST_TEMP] = float(json["tempHigh"]) / 10 + forecast[ATTR_FORECAST_NATIVE_TEMP] = float(json["tempHigh"]) / 10 if json["tempLow"] != ECOBEE_STATE_UNKNOWN: - forecast[ATTR_FORECAST_TEMP_LOW] = float(json["tempLow"]) / 10 + forecast[ATTR_FORECAST_NATIVE_TEMP_LOW] = float(json["tempLow"]) / 10 if json["windBearing"] != ECOBEE_STATE_UNKNOWN: forecast[ATTR_FORECAST_WIND_BEARING] = int(json["windBearing"]) if json["windSpeed"] != ECOBEE_STATE_UNKNOWN: - forecast[ATTR_FORECAST_WIND_SPEED] = int(json["windSpeed"]) + forecast[ATTR_FORECAST_NATIVE_WIND_SPEED] = int(json["windSpeed"]) except (ValueError, IndexError, KeyError): return None From 5e7174a5f4949a8ca8fd7a76920cb56386930de3 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Mon, 11 Jul 2022 10:58:57 +0200 Subject: [PATCH 02/22] Migrate homematicip_cloud to native_* (#74385) --- .../components/homematicip_cloud/weather.py | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/homeassistant/components/homematicip_cloud/weather.py b/homeassistant/components/homematicip_cloud/weather.py index 985754a8417..3acbae95441 100644 --- a/homeassistant/components/homematicip_cloud/weather.py +++ b/homeassistant/components/homematicip_cloud/weather.py @@ -22,7 +22,7 @@ from homeassistant.components.weather import ( WeatherEntity, ) from homeassistant.config_entries import ConfigEntry -from homeassistant.const import TEMP_CELSIUS +from homeassistant.const import SPEED_KILOMETERS_PER_HOUR, TEMP_CELSIUS from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -71,6 +71,9 @@ async def async_setup_entry( class HomematicipWeatherSensor(HomematicipGenericEntity, WeatherEntity): """Representation of the HomematicIP weather sensor plus & basic.""" + _attr_native_temperature_unit = TEMP_CELSIUS + _attr_native_wind_speed_unit = SPEED_KILOMETERS_PER_HOUR + def __init__(self, hap: HomematicipHAP, device) -> None: """Initialize the weather sensor.""" super().__init__(hap, device) @@ -81,22 +84,17 @@ class HomematicipWeatherSensor(HomematicipGenericEntity, WeatherEntity): return self._device.label @property - def temperature(self) -> float: + def native_temperature(self) -> float: """Return the platform temperature.""" return self._device.actualTemperature - @property - def temperature_unit(self) -> str: - """Return the unit of measurement.""" - return TEMP_CELSIUS - @property def humidity(self) -> int: """Return the humidity.""" return self._device.humidity @property - def wind_speed(self) -> float: + def native_wind_speed(self) -> float: """Return the wind speed.""" return self._device.windSpeed @@ -129,6 +127,9 @@ class HomematicipWeatherSensorPro(HomematicipWeatherSensor): class HomematicipHomeWeather(HomematicipGenericEntity, WeatherEntity): """Representation of the HomematicIP home weather.""" + _attr_native_temperature_unit = TEMP_CELSIUS + _attr_native_wind_speed_unit = SPEED_KILOMETERS_PER_HOUR + def __init__(self, hap: HomematicipHAP) -> None: """Initialize the home weather.""" hap.home.modelType = "HmIP-Home-Weather" @@ -145,22 +146,17 @@ class HomematicipHomeWeather(HomematicipGenericEntity, WeatherEntity): return f"Weather {self._home.location.city}" @property - def temperature(self) -> float: + def native_temperature(self) -> float: """Return the temperature.""" return self._device.weather.temperature - @property - def temperature_unit(self) -> str: - """Return the unit of measurement.""" - return TEMP_CELSIUS - @property def humidity(self) -> int: """Return the humidity.""" return self._device.weather.humidity @property - def wind_speed(self) -> float: + def native_wind_speed(self) -> float: """Return the wind speed.""" return round(self._device.weather.windSpeed, 1) From cc79c3d6e126d07210c95bb48aaed64be5689a98 Mon Sep 17 00:00:00 2001 From: Ludovico de Nittis Date: Mon, 11 Jul 2022 16:51:10 +0200 Subject: [PATCH 03/22] Update pyialarm to 2.2.0 (#74874) --- homeassistant/components/ialarm/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/ialarm/manifest.json b/homeassistant/components/ialarm/manifest.json index 60ecb9da74a..00a0cba9a27 100644 --- a/homeassistant/components/ialarm/manifest.json +++ b/homeassistant/components/ialarm/manifest.json @@ -2,7 +2,7 @@ "domain": "ialarm", "name": "Antifurto365 iAlarm", "documentation": "https://www.home-assistant.io/integrations/ialarm", - "requirements": ["pyialarm==1.9.0"], + "requirements": ["pyialarm==2.2.0"], "codeowners": ["@RyuzakiKK"], "config_flow": true, "iot_class": "local_polling", diff --git a/requirements_all.txt b/requirements_all.txt index deb6ce80558..6bb80d139ae 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1553,7 +1553,7 @@ pyhomematic==0.1.77 pyhomeworks==0.0.6 # homeassistant.components.ialarm -pyialarm==1.9.0 +pyialarm==2.2.0 # homeassistant.components.icloud pyicloud==1.0.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 64087216db2..819b03b2229 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1047,7 +1047,7 @@ pyhiveapi==0.5.13 pyhomematic==0.1.77 # homeassistant.components.ialarm -pyialarm==1.9.0 +pyialarm==2.2.0 # homeassistant.components.icloud pyicloud==1.0.0 From d31a0c8dcadde568e5518ced19e7cf51a568b0c5 Mon Sep 17 00:00:00 2001 From: Alexei Chetroi Date: Sun, 10 Jul 2022 13:35:45 -0400 Subject: [PATCH 04/22] Correctly handle device triggers for missing ZHA devices (#74894) --- homeassistant/components/zha/core/helpers.py | 2 +- tests/components/zha/test_device_trigger.py | 38 ++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/zha/core/helpers.py b/homeassistant/components/zha/core/helpers.py index 390ef290dc2..b60f61b1e8e 100644 --- a/homeassistant/components/zha/core/helpers.py +++ b/homeassistant/components/zha/core/helpers.py @@ -170,7 +170,7 @@ def async_get_zha_device(hass: HomeAssistant, device_id: str) -> ZHADevice: device_registry = dr.async_get(hass) registry_device = device_registry.async_get(device_id) if not registry_device: - raise ValueError(f"Device id `{device_id}` not found in registry.") + raise KeyError(f"Device id `{device_id}` not found in registry.") zha_gateway: ZHAGateway = hass.data[DATA_ZHA][DATA_ZHA_GATEWAY] ieee_address = list(list(registry_device.identifiers)[0])[1] ieee = zigpy.types.EUI64.convert(ieee_address) diff --git a/tests/components/zha/test_device_trigger.py b/tests/components/zha/test_device_trigger.py index 1f5fa467a93..8e19fe5b637 100644 --- a/tests/components/zha/test_device_trigger.py +++ b/tests/components/zha/test_device_trigger.py @@ -370,3 +370,41 @@ async def test_exception_bad_trigger(hass, mock_devices, calls, caplog): ) await hass.async_block_till_done() assert "Invalid config for [automation]" in caplog.text + + +async def test_exception_no_device(hass, mock_devices, calls, caplog): + """Test for exception on event triggers firing.""" + + zigpy_device, zha_device = mock_devices + + zigpy_device.device_automation_triggers = { + (SHAKEN, SHAKEN): {COMMAND: COMMAND_SHAKE}, + (DOUBLE_PRESS, DOUBLE_PRESS): {COMMAND: COMMAND_DOUBLE}, + (SHORT_PRESS, SHORT_PRESS): {COMMAND: COMMAND_SINGLE}, + (LONG_PRESS, LONG_PRESS): {COMMAND: COMMAND_HOLD}, + (LONG_RELEASE, LONG_RELEASE): {COMMAND: COMMAND_HOLD}, + } + + await async_setup_component( + hass, + automation.DOMAIN, + { + automation.DOMAIN: [ + { + "trigger": { + "device_id": "no_such_device_id", + "domain": "zha", + "platform": "device", + "type": "junk", + "subtype": "junk", + }, + "action": { + "service": "test.automation", + "data": {"message": "service called"}, + }, + } + ] + }, + ) + await hass.async_block_till_done() + assert "Invalid config for [automation]" in caplog.text From 3f53022b50db4171fbfca3f97f49ee393f2dbadd Mon Sep 17 00:00:00 2001 From: henryptung Date: Mon, 11 Jul 2022 02:33:28 -0700 Subject: [PATCH 05/22] Remove pip --prefix workaround (#74922) Remove --prefix workaround See discussion in https://github.com/home-assistant/core/issues/74405. This workaround is no longer needed on pip >= 21.0 and actively causes problems for pip >= 21.3. --- homeassistant/util/package.py | 3 --- tests/util/test_package.py | 3 +-- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/homeassistant/util/package.py b/homeassistant/util/package.py index aad93e37542..18ab43967ec 100644 --- a/homeassistant/util/package.py +++ b/homeassistant/util/package.py @@ -89,9 +89,6 @@ def install_package( # This only works if not running in venv args += ["--user"] env["PYTHONUSERBASE"] = os.path.abspath(target) - # Workaround for incompatible prefix setting - # See http://stackoverflow.com/a/4495175 - args += ["--prefix="] _LOGGER.debug("Running pip command: args=%s", args) with Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE, env=env) as process: _, stderr = process.communicate() diff --git a/tests/util/test_package.py b/tests/util/test_package.py index d6b7402a5b6..7ab087f1463 100644 --- a/tests/util/test_package.py +++ b/tests/util/test_package.py @@ -137,7 +137,6 @@ def test_install_target(mock_sys, mock_popen, mock_env_copy, mock_venv): "--quiet", TEST_NEW_REQ, "--user", - "--prefix=", ] assert package.install_package(TEST_NEW_REQ, False, target=target) @@ -156,7 +155,7 @@ def test_install_target_venv(mock_sys, mock_popen, mock_env_copy, mock_venv): def test_install_error(caplog, mock_sys, mock_popen, mock_venv): - """Test an install with a target.""" + """Test an install that errors out.""" caplog.set_level(logging.WARNING) mock_popen.return_value.returncode = 1 assert not package.install_package(TEST_NEW_REQ) From 4d81d056da889247407c896b8bc220f187e12a8d Mon Sep 17 00:00:00 2001 From: Markus Date: Mon, 11 Jul 2022 10:49:31 +0200 Subject: [PATCH 06/22] Fix Pyload request content type headers (#74957) --- homeassistant/components/pyload/sensor.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/homeassistant/components/pyload/sensor.py b/homeassistant/components/pyload/sensor.py index e4bbf7df3d2..81e1a02408a 100644 --- a/homeassistant/components/pyload/sensor.py +++ b/homeassistant/components/pyload/sensor.py @@ -4,7 +4,6 @@ from __future__ import annotations from datetime import timedelta import logging -from aiohttp.hdrs import CONTENT_TYPE import requests import voluptuous as vol @@ -144,7 +143,7 @@ class PyLoadAPI: """Initialize pyLoad API and set headers needed later.""" self.api_url = api_url self.status = None - self.headers = {CONTENT_TYPE: CONTENT_TYPE_JSON} + self.headers = {"Content-Type": CONTENT_TYPE_JSON} if username is not None and password is not None: self.payload = {"username": username, "password": password} From c45313e9dec151f951f2d2f5aec9bb49518a4cf7 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 11 Jul 2022 23:46:55 +0200 Subject: [PATCH 07/22] JSON serialize NamedTuple subclasses with aiohttp (#74971) --- homeassistant/helpers/aiohttp_client.py | 4 ++-- tests/helpers/test_aiohttp_client.py | 11 +++++++++++ tests/helpers/test_json.py | 22 ++++++++++++++++++++++ tests/test_util/aiohttp.py | 2 +- 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/homeassistant/helpers/aiohttp_client.py b/homeassistant/helpers/aiohttp_client.py index 2e56698db41..2ef96091d15 100644 --- a/homeassistant/helpers/aiohttp_client.py +++ b/homeassistant/helpers/aiohttp_client.py @@ -14,7 +14,6 @@ from aiohttp import web from aiohttp.hdrs import CONTENT_TYPE, USER_AGENT from aiohttp.web_exceptions import HTTPBadGateway, HTTPGatewayTimeout import async_timeout -import orjson from homeassistant import config_entries from homeassistant.const import EVENT_HOMEASSISTANT_CLOSE, __version__ @@ -23,6 +22,7 @@ from homeassistant.loader import bind_hass from homeassistant.util import ssl as ssl_util from .frame import warn_use +from .json import json_dumps DATA_CONNECTOR = "aiohttp_connector" DATA_CONNECTOR_NOTVERIFY = "aiohttp_connector_notverify" @@ -98,7 +98,7 @@ def _async_create_clientsession( """Create a new ClientSession with kwargs, i.e. for cookies.""" clientsession = aiohttp.ClientSession( connector=_async_get_connector(hass, verify_ssl), - json_serialize=lambda x: orjson.dumps(x).decode("utf-8"), + json_serialize=json_dumps, **kwargs, ) # Prevent packages accidentally overriding our default headers diff --git a/tests/helpers/test_aiohttp_client.py b/tests/helpers/test_aiohttp_client.py index 599b2c6984e..1ffb4267167 100644 --- a/tests/helpers/test_aiohttp_client.py +++ b/tests/helpers/test_aiohttp_client.py @@ -19,6 +19,7 @@ from homeassistant.const import ( ) from homeassistant.core import EVENT_HOMEASSISTANT_CLOSE import homeassistant.helpers.aiohttp_client as client +from homeassistant.util.color import RGBColor from tests.common import MockConfigEntry @@ -215,6 +216,16 @@ async def test_async_aiohttp_proxy_stream_client_err(aioclient_mock, camera_clie assert resp.status == 502 +async def test_sending_named_tuple(hass, aioclient_mock): + """Test sending a named tuple in json.""" + resp = aioclient_mock.post("http://127.0.0.1/rgb", json={"rgb": RGBColor(4, 3, 2)}) + session = client.async_create_clientsession(hass) + resp = await session.post("http://127.0.0.1/rgb", json={"rgb": RGBColor(4, 3, 2)}) + assert resp.status == 200 + await resp.json() == {"rgb": RGBColor(4, 3, 2)} + aioclient_mock.mock_calls[0][2]["rgb"] == RGBColor(4, 3, 2) + + async def test_client_session_immutable_headers(hass): """Test we can't mutate headers.""" session = client.async_get_clientsession(hass) diff --git a/tests/helpers/test_json.py b/tests/helpers/test_json.py index 54c488690fa..1e85338f152 100644 --- a/tests/helpers/test_json.py +++ b/tests/helpers/test_json.py @@ -2,6 +2,7 @@ import datetime import json import time +from typing import NamedTuple import pytest @@ -13,6 +14,7 @@ from homeassistant.helpers.json import ( json_dumps_sorted, ) from homeassistant.util import dt as dt_util +from homeassistant.util.color import RGBColor @pytest.mark.parametrize("encoder", (JSONEncoder, ExtendedJSONEncoder)) @@ -96,3 +98,23 @@ def test_json_dumps_tuple_subclass(): tt = time.struct_time((1999, 3, 17, 32, 44, 55, 2, 76, 0)) assert json_dumps(tt) == "[1999,3,17,32,44,55,2,76,0]" + + +def test_json_dumps_named_tuple_subclass(): + """Test the json dumps a tuple subclass.""" + + class NamedTupleSubclass(NamedTuple): + """A NamedTuple subclass.""" + + name: str + + nts = NamedTupleSubclass("a") + + assert json_dumps(nts) == '["a"]' + + +def test_json_dumps_rgb_color_subclass(): + """Test the json dumps of RGBColor.""" + rgb = RGBColor(4, 2, 1) + + assert json_dumps(rgb) == "[4,2,1]" diff --git a/tests/test_util/aiohttp.py b/tests/test_util/aiohttp.py index 9ed47109210..4ed81a3a577 100644 --- a/tests/test_util/aiohttp.py +++ b/tests/test_util/aiohttp.py @@ -111,7 +111,7 @@ class AiohttpClientMocker: def create_session(self, loop): """Create a ClientSession that is bound to this mocker.""" - session = ClientSession(loop=loop) + session = ClientSession(loop=loop, json_serialize=json_dumps) # Setting directly on `session` will raise deprecation warning object.__setattr__(session, "_request", self.match_request) return session From a34e72f3a185e27a2af31da75106cdd374aaad15 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Mon, 11 Jul 2022 14:38:08 +0200 Subject: [PATCH 08/22] Fix mix of aiohttp and requests in ClickSend TTS (#74985) --- homeassistant/components/clicksend_tts/notify.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/homeassistant/components/clicksend_tts/notify.py b/homeassistant/components/clicksend_tts/notify.py index 712787c34e6..8026c8e150b 100644 --- a/homeassistant/components/clicksend_tts/notify.py +++ b/homeassistant/components/clicksend_tts/notify.py @@ -3,7 +3,6 @@ from http import HTTPStatus import json import logging -from aiohttp.hdrs import CONTENT_TYPE import requests import voluptuous as vol @@ -20,7 +19,7 @@ _LOGGER = logging.getLogger(__name__) BASE_API_URL = "https://rest.clicksend.com/v3" -HEADERS = {CONTENT_TYPE: CONTENT_TYPE_JSON} +HEADERS = {"Content-Type": CONTENT_TYPE_JSON} CONF_LANGUAGE = "language" CONF_VOICE = "voice" From f738d39ad9f491581d8116f7d0f6fce49bdac8dc Mon Sep 17 00:00:00 2001 From: Phil Bruckner Date: Tue, 12 Jul 2022 01:42:33 -0500 Subject: [PATCH 09/22] Do not spam log when Life360 member location is missing (#75029) --- homeassistant/components/life360/__init__.py | 6 +- .../components/life360/coordinator.py | 62 +++++++++++++++---- 2 files changed, 54 insertions(+), 14 deletions(-) diff --git a/homeassistant/components/life360/__init__.py b/homeassistant/components/life360/__init__.py index 4527f6ac298..d05a9ec400b 100644 --- a/homeassistant/components/life360/__init__.py +++ b/homeassistant/components/life360/__init__.py @@ -37,7 +37,7 @@ from .const import ( SHOW_DRIVING, SHOW_MOVING, ) -from .coordinator import Life360DataUpdateCoordinator +from .coordinator import Life360DataUpdateCoordinator, MissingLocReason PLATFORMS = [Platform.DEVICE_TRACKER] @@ -128,6 +128,10 @@ class IntegData: coordinators: dict[str, Life360DataUpdateCoordinator] = field( init=False, default_factory=dict ) + # member_id: missing location reason + missing_loc_reason: dict[str, MissingLocReason] = field( + init=False, default_factory=dict + ) # member_id: ConfigEntry.entry_id tracked_members: dict[str, str] = field(init=False, default_factory=dict) logged_circles: list[str] = field(init=False, default_factory=list) diff --git a/homeassistant/components/life360/coordinator.py b/homeassistant/components/life360/coordinator.py index dc7fdb73a8c..05eecd43cdc 100644 --- a/homeassistant/components/life360/coordinator.py +++ b/homeassistant/components/life360/coordinator.py @@ -2,8 +2,10 @@ from __future__ import annotations +from contextlib import suppress from dataclasses import dataclass, field from datetime import datetime +from enum import Enum from typing import Any from life360 import Life360, Life360Error, LoginError @@ -33,6 +35,13 @@ from .const import ( ) +class MissingLocReason(Enum): + """Reason member location information is missing.""" + + VAGUE_ERROR_REASON = "vague error reason" + EXPLICIT_ERROR_REASON = "explicit error reason" + + @dataclass class Life360Place: """Life360 Place data.""" @@ -99,6 +108,7 @@ class Life360DataUpdateCoordinator(DataUpdateCoordinator): max_retries=COMM_MAX_RETRIES, authorization=entry.data[CONF_AUTHORIZATION], ) + self._missing_loc_reason = hass.data[DOMAIN].missing_loc_reason async def _retrieve_data(self, func: str, *args: Any) -> list[dict[str, Any]]: """Get data from Life360.""" @@ -141,10 +151,7 @@ class Life360DataUpdateCoordinator(DataUpdateCoordinator): if not int(member["features"]["shareLocation"]): continue - # Note that member may be in more than one circle. If that's the case just - # go ahead and process the newly retrieved data (overwriting the older - # data), since it might be slightly newer than what was retrieved while - # processing another circle. + member_id = member["id"] first = member["firstName"] last = member["lastName"] @@ -153,16 +160,45 @@ class Life360DataUpdateCoordinator(DataUpdateCoordinator): else: name = first or last - loc = member["location"] - if not loc: - if err_msg := member["issues"]["title"]: - if member["issues"]["dialog"]: - err_msg += f": {member['issues']['dialog']}" - else: - err_msg = "Location information missing" - LOGGER.error("%s: %s", name, err_msg) + cur_missing_reason = self._missing_loc_reason.get(member_id) + + # Check if location information is missing. This can happen if server + # has not heard from member's device in a long time (e.g., has been off + # for a long time, or has lost service, etc.) + if loc := member["location"]: + with suppress(KeyError): + del self._missing_loc_reason[member_id] + else: + if explicit_reason := member["issues"]["title"]: + if extended_reason := member["issues"]["dialog"]: + explicit_reason += f": {extended_reason}" + # Note that different Circles can report missing location in + # different ways. E.g., one might report an explicit reason and + # another does not. If a vague reason has already been logged but a + # more explicit reason is now available, log that, too. + if ( + cur_missing_reason is None + or cur_missing_reason == MissingLocReason.VAGUE_ERROR_REASON + and explicit_reason + ): + if explicit_reason: + self._missing_loc_reason[ + member_id + ] = MissingLocReason.EXPLICIT_ERROR_REASON + err_msg = explicit_reason + else: + self._missing_loc_reason[ + member_id + ] = MissingLocReason.VAGUE_ERROR_REASON + err_msg = "Location information missing" + LOGGER.error("%s: %s", name, err_msg) continue + # Note that member may be in more than one circle. If that's the case + # just go ahead and process the newly retrieved data (overwriting the + # older data), since it might be slightly newer than what was retrieved + # while processing another circle. + place = loc["name"] or None if place: @@ -179,7 +215,7 @@ class Life360DataUpdateCoordinator(DataUpdateCoordinator): if self._hass.config.units.is_metric: speed = convert(speed, LENGTH_MILES, LENGTH_KILOMETERS) - data.members[member["id"]] = Life360Member( + data.members[member_id] = Life360Member( address, dt_util.utc_from_timestamp(int(loc["since"])), bool(int(loc["charge"])), From bdc4171e3795244f89501b6243a357f89422c3f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Skytt=C3=A4?= Date: Tue, 12 Jul 2022 01:35:45 +0300 Subject: [PATCH 10/22] Upgrade huawei-lte-api to 1.6.1 (#75030) --- homeassistant/components/huawei_lte/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/huawei_lte/manifest.json b/homeassistant/components/huawei_lte/manifest.json index dd0382d5f55..c1b15d57620 100644 --- a/homeassistant/components/huawei_lte/manifest.json +++ b/homeassistant/components/huawei_lte/manifest.json @@ -4,7 +4,7 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/huawei_lte", "requirements": [ - "huawei-lte-api==1.6.0", + "huawei-lte-api==1.6.1", "stringcase==1.2.0", "url-normalize==1.4.1" ], diff --git a/requirements_all.txt b/requirements_all.txt index 6bb80d139ae..e20a7fa830e 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -846,7 +846,7 @@ horimote==0.4.1 httplib2==0.20.4 # homeassistant.components.huawei_lte -huawei-lte-api==1.6.0 +huawei-lte-api==1.6.1 # homeassistant.components.huisbaasje huisbaasje-client==0.1.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 819b03b2229..8eebc524bef 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -610,7 +610,7 @@ homepluscontrol==0.0.5 httplib2==0.20.4 # homeassistant.components.huawei_lte -huawei-lte-api==1.6.0 +huawei-lte-api==1.6.1 # homeassistant.components.huisbaasje huisbaasje-client==0.1.0 From 620d2ed8fd19f1baf2db09571ad731f7790e1d73 Mon Sep 17 00:00:00 2001 From: Gabe Cook Date: Tue, 12 Jul 2022 09:06:38 -0500 Subject: [PATCH 11/22] Fix Ruckus Unleashed SSH connection failures (#75032) --- .../components/ruckus_unleashed/__init__.py | 7 +++---- .../components/ruckus_unleashed/config_flow.py | 14 +++++++------- .../components/ruckus_unleashed/coordinator.py | 4 +--- .../components/ruckus_unleashed/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/ruckus_unleashed/test_init.py | 4 ++-- 7 files changed, 16 insertions(+), 19 deletions(-) diff --git a/homeassistant/components/ruckus_unleashed/__init__.py b/homeassistant/components/ruckus_unleashed/__init__.py index 2c8c8bb108d..62ed4949e05 100644 --- a/homeassistant/components/ruckus_unleashed/__init__.py +++ b/homeassistant/components/ruckus_unleashed/__init__.py @@ -29,8 +29,7 @@ from .coordinator import RuckusUnleashedDataUpdateCoordinator async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Set up Ruckus Unleashed from a config entry.""" try: - ruckus = await hass.async_add_executor_job( - Ruckus, + ruckus = await Ruckus.create( entry.data[CONF_HOST], entry.data[CONF_USERNAME], entry.data[CONF_PASSWORD], @@ -42,10 +41,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: await coordinator.async_config_entry_first_refresh() - system_info = await hass.async_add_executor_job(ruckus.system_info) + system_info = await ruckus.system_info() registry = device_registry.async_get(hass) - ap_info = await hass.async_add_executor_job(ruckus.ap_info) + ap_info = await ruckus.ap_info() for device in ap_info[API_AP][API_ID].values(): registry.async_get_or_create( config_entry_id=entry.entry_id, diff --git a/homeassistant/components/ruckus_unleashed/config_flow.py b/homeassistant/components/ruckus_unleashed/config_flow.py index 7d34e620a13..4adf245c3de 100644 --- a/homeassistant/components/ruckus_unleashed/config_flow.py +++ b/homeassistant/components/ruckus_unleashed/config_flow.py @@ -21,22 +21,24 @@ DATA_SCHEMA = vol.Schema( ) -def validate_input(hass: core.HomeAssistant, data): +async def validate_input(hass: core.HomeAssistant, data): """Validate the user input allows us to connect. Data has the keys from DATA_SCHEMA with values provided by the user. """ try: - ruckus = Ruckus(data[CONF_HOST], data[CONF_USERNAME], data[CONF_PASSWORD]) + ruckus = await Ruckus.create( + data[CONF_HOST], data[CONF_USERNAME], data[CONF_PASSWORD] + ) except AuthenticationError as error: raise InvalidAuth from error except ConnectionError as error: raise CannotConnect from error - mesh_name = ruckus.mesh_name() + mesh_name = await ruckus.mesh_name() - system_info = ruckus.system_info() + system_info = await ruckus.system_info() try: host_serial = system_info[API_SYSTEM_OVERVIEW][API_SERIAL] except KeyError as error: @@ -58,9 +60,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): errors = {} if user_input is not None: try: - info = await self.hass.async_add_executor_job( - validate_input, self.hass, user_input - ) + info = await validate_input(self.hass, user_input) except CannotConnect: errors["base"] = "cannot_connect" except InvalidAuth: diff --git a/homeassistant/components/ruckus_unleashed/coordinator.py b/homeassistant/components/ruckus_unleashed/coordinator.py index 8b80eaae0da..e84b79ef843 100644 --- a/homeassistant/components/ruckus_unleashed/coordinator.py +++ b/homeassistant/components/ruckus_unleashed/coordinator.py @@ -37,9 +37,7 @@ class RuckusUnleashedDataUpdateCoordinator(DataUpdateCoordinator): async def _fetch_clients(self) -> dict: """Fetch clients from the API and format them.""" - clients = await self.hass.async_add_executor_job( - self.ruckus.current_active_clients - ) + clients = await self.ruckus.current_active_clients() return {e[API_MAC]: e for e in clients[API_CURRENT_ACTIVE_CLIENTS][API_CLIENTS]} async def _async_update_data(self) -> dict: diff --git a/homeassistant/components/ruckus_unleashed/manifest.json b/homeassistant/components/ruckus_unleashed/manifest.json index f010d340147..a6b2ad0271c 100644 --- a/homeassistant/components/ruckus_unleashed/manifest.json +++ b/homeassistant/components/ruckus_unleashed/manifest.json @@ -3,7 +3,7 @@ "name": "Ruckus Unleashed", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/ruckus_unleashed", - "requirements": ["pyruckus==0.12"], + "requirements": ["pyruckus==0.16"], "codeowners": ["@gabe565"], "iot_class": "local_polling", "loggers": ["pexpect", "pyruckus"] diff --git a/requirements_all.txt b/requirements_all.txt index e20a7fa830e..df753662c8a 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1780,7 +1780,7 @@ pyrisco==0.3.1 pyrituals==0.0.6 # homeassistant.components.ruckus_unleashed -pyruckus==0.12 +pyruckus==0.16 # homeassistant.components.sabnzbd pysabnzbd==1.1.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 8eebc524bef..7c0eaa25b14 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1211,7 +1211,7 @@ pyrisco==0.3.1 pyrituals==0.0.6 # homeassistant.components.ruckus_unleashed -pyruckus==0.12 +pyruckus==0.16 # homeassistant.components.sabnzbd pysabnzbd==1.1.1 diff --git a/tests/components/ruckus_unleashed/test_init.py b/tests/components/ruckus_unleashed/test_init.py index e9ac9ec7cd8..d72856aa542 100644 --- a/tests/components/ruckus_unleashed/test_init.py +++ b/tests/components/ruckus_unleashed/test_init.py @@ -31,7 +31,7 @@ async def test_setup_entry_login_error(hass): """Test entry setup failed due to login error.""" entry = mock_config_entry() with patch( - "homeassistant.components.ruckus_unleashed.Ruckus", + "homeassistant.components.ruckus_unleashed.Ruckus.connect", side_effect=AuthenticationError, ): entry.add_to_hass(hass) @@ -45,7 +45,7 @@ async def test_setup_entry_connection_error(hass): """Test entry setup failed due to connection error.""" entry = mock_config_entry() with patch( - "homeassistant.components.ruckus_unleashed.Ruckus", + "homeassistant.components.ruckus_unleashed.Ruckus.connect", side_effect=ConnectionError, ): entry.add_to_hass(hass) From 51a4c9856219746bf6257dd9675a115d1f80410e Mon Sep 17 00:00:00 2001 From: Thijs W Date: Tue, 12 Jul 2022 12:03:26 +0200 Subject: [PATCH 12/22] Bump afsapi to 0.2.6 (#75041) --- homeassistant/components/frontier_silicon/manifest.json | 2 +- homeassistant/components/frontier_silicon/media_player.py | 7 +++++-- requirements_all.txt | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/frontier_silicon/manifest.json b/homeassistant/components/frontier_silicon/manifest.json index 12fb5145aa0..b04d68e672d 100644 --- a/homeassistant/components/frontier_silicon/manifest.json +++ b/homeassistant/components/frontier_silicon/manifest.json @@ -2,7 +2,7 @@ "domain": "frontier_silicon", "name": "Frontier Silicon", "documentation": "https://www.home-assistant.io/integrations/frontier_silicon", - "requirements": ["afsapi==0.2.5"], + "requirements": ["afsapi==0.2.6"], "codeowners": ["@wlcrs"], "iot_class": "local_polling" } diff --git a/homeassistant/components/frontier_silicon/media_player.py b/homeassistant/components/frontier_silicon/media_player.py index 61dc6e69726..b16374c0bc0 100644 --- a/homeassistant/components/frontier_silicon/media_player.py +++ b/homeassistant/components/frontier_silicon/media_player.py @@ -179,11 +179,14 @@ class AFSAPIDevice(MediaPlayerEntity): self._attr_media_artist = await afsapi.get_play_artist() self._attr_media_album_name = await afsapi.get_play_album() - self._attr_source = (await afsapi.get_mode()).label + radio_mode = await afsapi.get_mode() + self._attr_source = radio_mode.label if radio_mode is not None else None self._attr_is_volume_muted = await afsapi.get_mute() self._attr_media_image_url = await afsapi.get_play_graphic() - self._attr_sound_mode = (await afsapi.get_eq_preset()).label + + eq_preset = await afsapi.get_eq_preset() + self._attr_sound_mode = eq_preset.label if eq_preset is not None else None volume = await self.fs_device.get_volume() diff --git a/requirements_all.txt b/requirements_all.txt index df753662c8a..bc734b22445 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -89,7 +89,7 @@ adguardhome==0.5.1 advantage_air==0.3.1 # homeassistant.components.frontier_silicon -afsapi==0.2.5 +afsapi==0.2.6 # homeassistant.components.agent_dvr agent-py==0.0.23 From 5c882429d48874f0e24a0f1670cb286e16ce7257 Mon Sep 17 00:00:00 2001 From: hahn-th Date: Tue, 12 Jul 2022 15:31:04 +0200 Subject: [PATCH 13/22] Bump homematicip to 1.0.4 (#75053) --- homeassistant/components/homematicip_cloud/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/homematicip_cloud/manifest.json b/homeassistant/components/homematicip_cloud/manifest.json index 40f7e67fd07..f6fb9f3e739 100644 --- a/homeassistant/components/homematicip_cloud/manifest.json +++ b/homeassistant/components/homematicip_cloud/manifest.json @@ -3,7 +3,7 @@ "name": "HomematicIP Cloud", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/homematicip_cloud", - "requirements": ["homematicip==1.0.3"], + "requirements": ["homematicip==1.0.4"], "codeowners": [], "quality_scale": "platinum", "iot_class": "cloud_push", diff --git a/requirements_all.txt b/requirements_all.txt index bc734b22445..5d99a060bea 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -834,7 +834,7 @@ home-assistant-frontend==20220707.0 homeconnect==0.7.1 # homeassistant.components.homematicip_cloud -homematicip==1.0.3 +homematicip==1.0.4 # homeassistant.components.home_plus_control homepluscontrol==0.0.5 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 7c0eaa25b14..790814dfe0f 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -601,7 +601,7 @@ home-assistant-frontend==20220707.0 homeconnect==0.7.1 # homeassistant.components.homematicip_cloud -homematicip==1.0.3 +homematicip==1.0.4 # homeassistant.components.home_plus_control homepluscontrol==0.0.5 From 55ae0228a93be4e5e3c1ee803988aea78947c5f8 Mon Sep 17 00:00:00 2001 From: mkmer Date: Wed, 13 Jul 2022 02:46:32 -0400 Subject: [PATCH 14/22] Bump AIOAladdinConnect to 0.1.23 (#75065) --- homeassistant/components/aladdin_connect/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/aladdin_connect/manifest.json b/homeassistant/components/aladdin_connect/manifest.json index 3a9e295a08f..bdf906ad200 100644 --- a/homeassistant/components/aladdin_connect/manifest.json +++ b/homeassistant/components/aladdin_connect/manifest.json @@ -2,7 +2,7 @@ "domain": "aladdin_connect", "name": "Aladdin Connect", "documentation": "https://www.home-assistant.io/integrations/aladdin_connect", - "requirements": ["AIOAladdinConnect==0.1.21"], + "requirements": ["AIOAladdinConnect==0.1.23"], "codeowners": ["@mkmer"], "iot_class": "cloud_polling", "loggers": ["aladdin_connect"], diff --git a/requirements_all.txt b/requirements_all.txt index 5d99a060bea..89a25bd31d8 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -5,7 +5,7 @@ AEMET-OpenData==0.2.1 # homeassistant.components.aladdin_connect -AIOAladdinConnect==0.1.21 +AIOAladdinConnect==0.1.23 # homeassistant.components.adax Adax-local==0.1.4 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 790814dfe0f..ba4e19393dd 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -7,7 +7,7 @@ AEMET-OpenData==0.2.1 # homeassistant.components.aladdin_connect -AIOAladdinConnect==0.1.21 +AIOAladdinConnect==0.1.23 # homeassistant.components.adax Adax-local==0.1.4 From 06e7f718913b483d012257435038b3f6819ea082 Mon Sep 17 00:00:00 2001 From: Tom Harris Date: Wed, 13 Jul 2022 02:56:08 -0400 Subject: [PATCH 15/22] Fix Insteon thermostat issues (#75079) --- homeassistant/components/insteon/climate.py | 2 +- homeassistant/components/insteon/manifest.json | 4 ++-- requirements_all.txt | 4 ++-- requirements_test_all.txt | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/insteon/climate.py b/homeassistant/components/insteon/climate.py index 97e21a02f6f..29c127ba0c7 100644 --- a/homeassistant/components/insteon/climate.py +++ b/homeassistant/components/insteon/climate.py @@ -86,7 +86,7 @@ class InsteonClimateEntity(InsteonEntity, ClimateEntity): @property def temperature_unit(self) -> str: """Return the unit of measurement.""" - if self._insteon_device.properties[CELSIUS].value: + if self._insteon_device.configuration[CELSIUS].value: return TEMP_CELSIUS return TEMP_FAHRENHEIT diff --git a/homeassistant/components/insteon/manifest.json b/homeassistant/components/insteon/manifest.json index 1be077a6b38..c48d502c16e 100644 --- a/homeassistant/components/insteon/manifest.json +++ b/homeassistant/components/insteon/manifest.json @@ -4,8 +4,8 @@ "documentation": "https://www.home-assistant.io/integrations/insteon", "dependencies": ["http", "websocket_api"], "requirements": [ - "pyinsteon==1.1.1", - "insteon-frontend-home-assistant==0.1.1" + "pyinsteon==1.1.3", + "insteon-frontend-home-assistant==0.2.0" ], "codeowners": ["@teharris1"], "dhcp": [ diff --git a/requirements_all.txt b/requirements_all.txt index 89a25bd31d8..c980c6ca7db 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -891,7 +891,7 @@ influxdb-client==1.24.0 influxdb==5.3.1 # homeassistant.components.insteon -insteon-frontend-home-assistant==0.1.1 +insteon-frontend-home-assistant==0.2.0 # homeassistant.components.intellifire intellifire4py==2.0.1 @@ -1559,7 +1559,7 @@ pyialarm==2.2.0 pyicloud==1.0.0 # homeassistant.components.insteon -pyinsteon==1.1.1 +pyinsteon==1.1.3 # homeassistant.components.intesishome pyintesishome==1.8.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index ba4e19393dd..04de268790f 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -634,7 +634,7 @@ influxdb-client==1.24.0 influxdb==5.3.1 # homeassistant.components.insteon -insteon-frontend-home-assistant==0.1.1 +insteon-frontend-home-assistant==0.2.0 # homeassistant.components.intellifire intellifire4py==2.0.1 @@ -1053,7 +1053,7 @@ pyialarm==2.2.0 pyicloud==1.0.0 # homeassistant.components.insteon -pyinsteon==1.1.1 +pyinsteon==1.1.3 # homeassistant.components.ipma pyipma==2.0.5 From 98c3bc56b50fea9e30bae5e7955785d51a819fff Mon Sep 17 00:00:00 2001 From: Artem Draft Date: Wed, 13 Jul 2022 10:12:50 +0300 Subject: [PATCH 16/22] Fix missing ordered states in universal media player (#75099) --- homeassistant/components/universal/media_player.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/homeassistant/components/universal/media_player.py b/homeassistant/components/universal/media_player.py index f33db3827af..352703f8f9b 100644 --- a/homeassistant/components/universal/media_player.py +++ b/homeassistant/components/universal/media_player.py @@ -69,11 +69,13 @@ from homeassistant.const import ( SERVICE_VOLUME_MUTE, SERVICE_VOLUME_SET, SERVICE_VOLUME_UP, + STATE_BUFFERING, STATE_IDLE, STATE_OFF, STATE_ON, STATE_PAUSED, STATE_PLAYING, + STATE_STANDBY, STATE_UNAVAILABLE, STATE_UNKNOWN, ) @@ -101,8 +103,10 @@ STATES_ORDER = [ STATE_UNAVAILABLE, STATE_OFF, STATE_IDLE, + STATE_STANDBY, STATE_ON, STATE_PAUSED, + STATE_BUFFERING, STATE_PLAYING, ] ATTRS_SCHEMA = cv.schema_with_slug_keys(cv.string) From b105b0fbcbe9f5ac32fbcfa4c70570b7812e128e Mon Sep 17 00:00:00 2001 From: Joakim Plate Date: Wed, 13 Jul 2022 22:05:43 +0200 Subject: [PATCH 17/22] Make sure device tuple is a list on save (#75103) --- homeassistant/components/rfxtrx/config_flow.py | 2 +- tests/components/rfxtrx/test_config_flow.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/rfxtrx/config_flow.py b/homeassistant/components/rfxtrx/config_flow.py index 61d01b8d533..508ca9a7037 100644 --- a/homeassistant/components/rfxtrx/config_flow.py +++ b/homeassistant/components/rfxtrx/config_flow.py @@ -199,7 +199,7 @@ class OptionsFlow(config_entries.OptionsFlow): if not errors: devices = {} device = { - CONF_DEVICE_ID: device_id, + CONF_DEVICE_ID: list(device_id), } devices[self._selected_device_event_code] = device diff --git a/tests/components/rfxtrx/test_config_flow.py b/tests/components/rfxtrx/test_config_flow.py index 2c695d71d2e..eaa7f1c79a1 100644 --- a/tests/components/rfxtrx/test_config_flow.py +++ b/tests/components/rfxtrx/test_config_flow.py @@ -867,6 +867,9 @@ async def test_options_configure_rfy_cover_device(hass): entry.data["devices"]["0C1a0000010203010000000000"]["venetian_blind_mode"] == "EU" ) + assert isinstance( + entry.data["devices"]["0C1a0000010203010000000000"]["device_id"], list + ) device_registry = dr.async_get(hass) device_entries = dr.async_entries_for_config_entry(device_registry, entry.entry_id) @@ -904,6 +907,9 @@ async def test_options_configure_rfy_cover_device(hass): entry.data["devices"]["0C1a0000010203010000000000"]["venetian_blind_mode"] == "EU" ) + assert isinstance( + entry.data["devices"]["0C1a0000010203010000000000"]["device_id"], list + ) def test_get_serial_by_id_no_dir(): From 9e99ea68fbf9eb7bc4dd5cafc51e72eb6fc8a57b Mon Sep 17 00:00:00 2001 From: kingy444 Date: Thu, 14 Jul 2022 06:06:32 +1000 Subject: [PATCH 18/22] Fix Powerview top shade open position (#75110) --- .../hunterdouglas_powerview/cover.py | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/hunterdouglas_powerview/cover.py b/homeassistant/components/hunterdouglas_powerview/cover.py index 3f7d04f5b87..7c4c90a2132 100644 --- a/homeassistant/components/hunterdouglas_powerview/cover.py +++ b/homeassistant/components/hunterdouglas_powerview/cover.py @@ -455,14 +455,6 @@ class PowerViewShadeTDBUTop(PowerViewShadeTDBU): super().__init__(coordinator, device_info, room_name, shade, name) self._attr_unique_id = f"{self._shade.id}_top" self._attr_name = f"{self._shade_name} Top" - # these shades share a class in parent API - # override open position for top shade - self._shade.open_position = { - ATTR_POSITION1: MIN_POSITION, - ATTR_POSITION2: MAX_POSITION, - ATTR_POSKIND1: POS_KIND_PRIMARY, - ATTR_POSKIND2: POS_KIND_SECONDARY, - } @property def should_poll(self) -> bool: @@ -485,6 +477,21 @@ class PowerViewShadeTDBUTop(PowerViewShadeTDBU): # these need to be inverted to report state correctly in HA return hd_position_to_hass(self.positions.secondary, MAX_POSITION) + @property + def open_position(self) -> PowerviewShadeMove: + """Return the open position and required additional positions.""" + # these shades share a class in parent API + # override open position for top shade + return PowerviewShadeMove( + { + ATTR_POSITION1: MIN_POSITION, + ATTR_POSITION2: MAX_POSITION, + ATTR_POSKIND1: POS_KIND_PRIMARY, + ATTR_POSKIND2: POS_KIND_SECONDARY, + }, + {}, + ) + @callback def _clamp_cover_limit(self, target_hass_position: int) -> int: """Dont allow a cover to go into an impossbile position.""" From 89e87119f27f9175801584011de733ce2a57cdf7 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 13 Jul 2022 17:13:09 -0400 Subject: [PATCH 19/22] Bump ZHA dependencies (#75133) --- homeassistant/components/zha/manifest.json | 4 ++-- requirements_all.txt | 4 ++-- requirements_test_all.txt | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/zha/manifest.json b/homeassistant/components/zha/manifest.json index 78aea7c9fb6..769254511a7 100644 --- a/homeassistant/components/zha/manifest.json +++ b/homeassistant/components/zha/manifest.json @@ -4,7 +4,7 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/zha", "requirements": [ - "bellows==0.31.0", + "bellows==0.31.1", "pyserial==3.5", "pyserial-asyncio==0.6", "zha-quirks==0.0.77", @@ -12,7 +12,7 @@ "zigpy==0.47.2", "zigpy-xbee==0.15.0", "zigpy-zigate==0.9.0", - "zigpy-znp==0.8.0" + "zigpy-znp==0.8.1" ], "usb": [ { diff --git a/requirements_all.txt b/requirements_all.txt index c980c6ca7db..01e309e7b6a 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -393,7 +393,7 @@ beautifulsoup4==4.11.1 # beewi_smartclim==0.0.10 # homeassistant.components.zha -bellows==0.31.0 +bellows==0.31.1 # homeassistant.components.bmw_connected_drive bimmer_connected==0.9.6 @@ -2516,7 +2516,7 @@ zigpy-xbee==0.15.0 zigpy-zigate==0.9.0 # homeassistant.components.zha -zigpy-znp==0.8.0 +zigpy-znp==0.8.1 # homeassistant.components.zha zigpy==0.47.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 04de268790f..9900ef878b4 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -308,7 +308,7 @@ base36==0.1.1 beautifulsoup4==4.11.1 # homeassistant.components.zha -bellows==0.31.0 +bellows==0.31.1 # homeassistant.components.bmw_connected_drive bimmer_connected==0.9.6 @@ -1677,7 +1677,7 @@ zigpy-xbee==0.15.0 zigpy-zigate==0.9.0 # homeassistant.components.zha -zigpy-znp==0.8.0 +zigpy-znp==0.8.1 # homeassistant.components.zha zigpy==0.47.2 From f052c3ca7469d94e21881b96aac75300fa4bc915 Mon Sep 17 00:00:00 2001 From: Aaron Bach Date: Wed, 13 Jul 2022 12:52:13 -0600 Subject: [PATCH 20/22] Ensure SimpliSafe diagnostics redact the `code` option (#75137) --- homeassistant/components/simplisafe/diagnostics.py | 3 ++- tests/components/simplisafe/conftest.py | 4 +++- tests/components/simplisafe/test_diagnostics.py | 4 +++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/simplisafe/diagnostics.py b/homeassistant/components/simplisafe/diagnostics.py index dac89715c10..cd6e4ca52be 100644 --- a/homeassistant/components/simplisafe/diagnostics.py +++ b/homeassistant/components/simplisafe/diagnostics.py @@ -5,7 +5,7 @@ from typing import Any from homeassistant.components.diagnostics import async_redact_data from homeassistant.config_entries import ConfigEntry -from homeassistant.const import CONF_ADDRESS, CONF_LOCATION +from homeassistant.const import CONF_ADDRESS, CONF_CODE, CONF_LOCATION from homeassistant.core import HomeAssistant from . import SimpliSafe @@ -23,6 +23,7 @@ CONF_WIFI_SSID = "wifi_ssid" TO_REDACT = { CONF_ADDRESS, + CONF_CODE, CONF_CREDIT_CARD, CONF_EXPIRES, CONF_LOCATION, diff --git a/tests/components/simplisafe/conftest.py b/tests/components/simplisafe/conftest.py index 56967ac24c5..82bd04a7349 100644 --- a/tests/components/simplisafe/conftest.py +++ b/tests/components/simplisafe/conftest.py @@ -43,7 +43,9 @@ def api_fixture(api_auth_state, data_subscription, system_v3, websocket): @pytest.fixture(name="config_entry") def config_entry_fixture(hass, config, unique_id): """Define a config entry.""" - entry = MockConfigEntry(domain=DOMAIN, unique_id=unique_id, data=config) + entry = MockConfigEntry( + domain=DOMAIN, unique_id=unique_id, data=config, options={CONF_CODE: "1234"} + ) entry.add_to_hass(hass) return entry diff --git a/tests/components/simplisafe/test_diagnostics.py b/tests/components/simplisafe/test_diagnostics.py index 13d5c778e89..446d9d5e9e3 100644 --- a/tests/components/simplisafe/test_diagnostics.py +++ b/tests/components/simplisafe/test_diagnostics.py @@ -8,7 +8,9 @@ async def test_entry_diagnostics(hass, config_entry, hass_client, setup_simplisa """Test config entry diagnostics.""" assert await get_diagnostics_for_config_entry(hass, hass_client, config_entry) == { "entry": { - "options": {}, + "options": { + "code": REDACTED, + }, }, "subscription_data": { "system_123": { From 1555f706e5a12e17c25c7a9dee637073af0e389e Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 13 Jul 2022 14:12:53 -0700 Subject: [PATCH 21/22] Block bad pubnub version (#75138) --- homeassistant/package_constraints.txt | 4 ++++ script/gen_requirements_all.py | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index ad03978c6ef..167fe546b35 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -114,3 +114,7 @@ backoff<2.0 # Breaking change in version # https://github.com/samuelcolvin/pydantic/issues/4092 pydantic!=1.9.1 + +# Breaks asyncio +# https://github.com/pubnub/python/issues/130 +pubnub!=6.4.0 diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index 11e88976e83..7b000a30be2 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -132,6 +132,10 @@ backoff<2.0 # Breaking change in version # https://github.com/samuelcolvin/pydantic/issues/4092 pydantic!=1.9.1 + +# Breaks asyncio +# https://github.com/pubnub/python/issues/130 +pubnub!=6.4.0 """ IGNORE_PRE_COMMIT_HOOK_ID = ( From 533ae85a4984468cb66a0630ab227e141b91bb5c Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 13 Jul 2022 14:14:13 -0700 Subject: [PATCH 22/22] Bumped version to 2022.7.4 --- homeassistant/const.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 7f5cf999b96..9db438feeb3 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -7,7 +7,7 @@ from .backports.enum import StrEnum MAJOR_VERSION: Final = 2022 MINOR_VERSION: Final = 7 -PATCH_VERSION: Final = "3" +PATCH_VERSION: Final = "4" __short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__: Final = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 9, 0) diff --git a/pyproject.toml b/pyproject.toml index c86fc6b26f0..b7f75f9a008 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "homeassistant" -version = "2022.7.3" +version = "2022.7.4" license = {text = "Apache-2.0"} description = "Open-source home automation platform running on Python 3." readme = "README.rst"