Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2022.4.3 #69935

Merged
merged 21 commits into from
Apr 12, 2022
Merged

2022.4.3 #69935

Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
094c185
Update xknx to 0.20.2 (RC) (#69859)
marvin-w Apr 11, 2022
85bc863
Fix profiler object growth logging test (#69211)
bdraco Apr 3, 2022
8bd07bc
Handle Squeezebox media ids that are not URLs (#69696)
rajlaud Apr 12, 2022
49bf1d6
Add diagnostics support for ZHA (#69756)
dmulcahey Apr 12, 2022
fd8fb59
Bump devolo-home-control-api to 0.18.1 (#69840)
Shutgun Apr 12, 2022
71fb2d0
Fix #69694 (#69850)
iMicknl Apr 11, 2022
aeb8dc2
Fix google calendar timestamp out of range (#69863)
allenporter Apr 11, 2022
9607dfe
Use quickplay when casting splash for mediaplayer.turn_on (#69866)
emontnemery Apr 12, 2022
84d8a78
Motion blinds fix set absolute position service (#69873)
starkillerOG Apr 11, 2022
ba16156
Bump zigpy to 0.44.2 and and zha-quirks to 0.0.72 (#69879)
puddly Apr 11, 2022
242bd92
Handle add-on issues (#69897)
ludeeus Apr 12, 2022
f5bb9e6
Fix unique id in SamsungTV config flow (#69899)
epenet Apr 12, 2022
ec541ca
Bump renault-api to 0.1.11 (#69900)
epenet Apr 12, 2022
e49da79
Fix climate HVAC device condition (#69908)
frenck Apr 12, 2022
fee80a9
Fix adjusting 5-minute statistics (#69921)
emontnemery Apr 12, 2022
27721d5
Fix adjusting statistics in ft³ (#69913)
emontnemery Apr 12, 2022
8a8ee3c
Downgrade ZHA dependency zigpy-deconz from 0.15.0 to 0.14.0 (#69927)
puddly Apr 12, 2022
cc6afdb
Bumped version to 2022.4.3
balloob Apr 12, 2022
51bfe53
Fix fibaro light state for rgb lights and HC3 (#69884)
rappenze Apr 12, 2022
a543160
Not all music are URLs (#69936)
balloob Apr 12, 2022
25fc64a
Guard against non http schemes (#69938)
balloob Apr 12, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion homeassistant/components/cast/media_player.py
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,8 @@ def turn_on(self):

# The only way we can turn the Chromecast is on is by launching an app
if self._chromecast.cast_type == pychromecast.const.CAST_TYPE_CHROMECAST:
self._chromecast.play_media(CAST_SPLASH, "image/png")
app_data = {"media_id": CAST_SPLASH, "media_type": "image/png"}
quick_play(self._chromecast, "default_media_receiver", app_data)
else:
self._chromecast.start_app(pychromecast.config.APP_MEDIA_RECEIVER)

Expand Down
16 changes: 10 additions & 6 deletions homeassistant/components/climate/device_condition.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,19 @@ def async_condition_from_config(
hass: HomeAssistant, config: ConfigType
) -> condition.ConditionCheckerType:
"""Create a function to test a device condition."""
if config[CONF_TYPE] == "is_hvac_mode":
attribute = const.ATTR_HVAC_MODE
else:
attribute = const.ATTR_PRESET_MODE

def test_is_state(hass: HomeAssistant, variables: TemplateVarsType) -> bool:
"""Test if an entity is a certain state."""
state = hass.states.get(config[ATTR_ENTITY_ID])
return state.attributes.get(attribute) == config[attribute] if state else False
if (state := hass.states.get(config[ATTR_ENTITY_ID])) is None:
return False

if config[CONF_TYPE] == "is_hvac_mode":
return state.state == config[const.ATTR_HVAC_MODE]

return (
state.attributes.get(const.ATTR_PRESET_MODE)
== config[const.ATTR_PRESET_MODE]
)

return test_is_state

Expand Down
16 changes: 9 additions & 7 deletions homeassistant/components/devolo_home_control/binary_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ def __init__(
self, homecontrol: HomeControl, device_instance: Zwave, element_uid: str
) -> None:
"""Initialize a devolo binary sensor."""
self._binary_sensor_property = device_instance.binary_sensor_property.get(
self._binary_sensor_property = device_instance.binary_sensor_property[
element_uid
)
]

super().__init__(
homecontrol=homecontrol,
Expand All @@ -82,10 +82,12 @@ def __init__(
)

if self._attr_device_class is None:
if device_instance.binary_sensor_property.get(element_uid).sub_type != "":
self._attr_name += f" {device_instance.binary_sensor_property.get(element_uid).sub_type}"
if device_instance.binary_sensor_property[element_uid].sub_type != "":
self._attr_name += (
f" {device_instance.binary_sensor_property[element_uid].sub_type}"
)
else:
self._attr_name += f" {device_instance.binary_sensor_property.get(element_uid).sensor_type}"
self._attr_name += f" {device_instance.binary_sensor_property[element_uid].sensor_type}"

self._value = self._binary_sensor_property.state

Expand Down Expand Up @@ -114,9 +116,9 @@ def __init__(
key: int,
) -> None:
"""Initialize a devolo remote control."""
self._remote_control_property = device_instance.remote_control_property.get(
self._remote_control_property = device_instance.remote_control_property[
element_uid
)
]

super().__init__(
homecontrol=homecontrol,
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/devolo_home_control/cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def __init__(
@property
def current_cover_position(self) -> int:
"""Return the current position. 0 is closed. 100 is open."""
return self._value
return int(self._value)

@property
def is_closed(self) -> bool:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def __init__(

self.subscriber: Subscriber | None = None
self.sync_callback = self._sync
self._value: int
self._value: float

async def async_added_to_hass(self) -> None:
"""Call when entity is added to hass."""
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/devolo_home_control/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"domain": "devolo_home_control",
"name": "devolo Home Control",
"documentation": "https://www.home-assistant.io/integrations/devolo_home_control",
"requirements": ["devolo-home-control-api==0.17.4"],
"requirements": ["devolo-home-control-api==0.18.1"],
"after_dependencies": ["zeroconf"],
"config_flow": true,
"codeowners": ["@2Fake", "@Shutgun"],
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/devolo_home_control/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class DevoloMultiLevelDeviceEntity(DevoloDeviceEntity, SensorEntity):
"""Abstract representation of a multi level sensor within devolo Home Control."""

@property
def native_value(self) -> int:
def native_value(self) -> float:
"""Return the state of the sensor."""
return self._value

Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/devolo_home_control/siren.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ def __init__(
)
self._attr_available_tones = [
*range(
self._multi_level_switch_property.min,
self._multi_level_switch_property.max + 1,
int(self._multi_level_switch_property.min),
int(self._multi_level_switch_property.max) + 1,
)
]
self._attr_supported_features = (
Expand Down
6 changes: 3 additions & 3 deletions homeassistant/components/devolo_home_control/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ def __init__(
device_instance=device_instance,
element_uid=element_uid,
)
self._binary_switch_property = self._device_instance.binary_switch_property.get(
self._attr_unique_id
)
self._binary_switch_property = self._device_instance.binary_switch_property[
self._attr_unique_id # type: ignore[index]
]
self._attr_is_on = self._binary_switch_property.state

def turn_on(self, **kwargs: Any) -> None:
Expand Down
6 changes: 4 additions & 2 deletions homeassistant/components/google/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,9 +193,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
session = config_entry_oauth2_flow.OAuth2Session(hass, entry, implementation)
# Force a token refresh to fix a bug where tokens were persisted with
# expires_in (relative time delta) and expires_at (absolute time) swapped.
if session.token["expires_at"] >= datetime(2070, 1, 1).timestamp():
# A google session token typically only lasts a few days between refresh.
now = datetime.now()
if session.token["expires_at"] >= (now + timedelta(days=365)).timestamp():
session.token["expires_in"] = 0
session.token["expires_at"] = datetime.now().timestamp()
session.token["expires_at"] = now.timestamp()
try:
await session.async_ensure_token_valid()
except aiohttp.ClientResponseError as err:
Expand Down
30 changes: 21 additions & 9 deletions homeassistant/components/hassio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -711,7 +711,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
dev_reg = await async_get_registry(hass)
coordinator = HassioDataUpdateCoordinator(hass, entry, dev_reg)
hass.data[ADDONS_COORDINATOR] = coordinator
await coordinator.async_refresh()
await coordinator.async_config_entry_first_refresh()

hass.config_entries.async_setup_platforms(entry, PLATFORMS)

Expand Down Expand Up @@ -848,8 +848,8 @@ async def _async_update_data(self) -> dict[str, Any]:
new_data[DATA_KEY_ADDONS] = {
addon[ATTR_SLUG]: {
**addon,
**((addons_stats or {}).get(addon[ATTR_SLUG], {})),
ATTR_AUTO_UPDATE: addons_info.get(addon[ATTR_SLUG], {}).get(
**((addons_stats or {}).get(addon[ATTR_SLUG]) or {}),
ATTR_AUTO_UPDATE: (addons_info.get(addon[ATTR_SLUG]) or {}).get(
ATTR_AUTO_UPDATE, False
),
ATTR_CHANGELOG: (addons_changelogs or {}).get(addon[ATTR_SLUG]),
Expand Down Expand Up @@ -952,15 +952,27 @@ async def force_data_refresh(self) -> None:

async def _update_addon_stats(self, slug):
"""Update single addon stats."""
stats = await self.hassio.get_addon_stats(slug)
return (slug, stats)
try:
stats = await self.hassio.get_addon_stats(slug)
return (slug, stats)
except HassioAPIError as err:
_LOGGER.warning("Could not fetch stats for %s: %s", slug, err)
return (slug, None)

async def _update_addon_changelog(self, slug):
"""Return the changelog for an add-on."""
changelog = await self.hassio.get_addon_changelog(slug)
return (slug, changelog)
try:
changelog = await self.hassio.get_addon_changelog(slug)
return (slug, changelog)
except HassioAPIError as err:
_LOGGER.warning("Could not fetch changelog for %s: %s", slug, err)
return (slug, None)

async def _update_addon_info(self, slug):
"""Return the info for an add-on."""
info = await self.hassio.get_addon_info(slug)
return (slug, info)
try:
info = await self.hassio.get_addon_info(slug)
return (slug, info)
except HassioAPIError as err:
_LOGGER.warning("Could not fetch info for %s: %s", slug, err)
return (slug, None)
6 changes: 0 additions & 6 deletions homeassistant/components/knx/climate.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,9 +296,3 @@ async def async_added_to_hass(self) -> None:
await super().async_added_to_hass()
if self._device.mode is not None:
self._device.mode.register_device_updated_cb(self.after_update_callback)

async def async_will_remove_from_hass(self) -> None:
"""Disconnect device object when removed."""
await super().async_will_remove_from_hass()
if self._device.mode is not None:
self._device.mode.unregister_device_updated_cb(self.after_update_callback)
3 changes: 2 additions & 1 deletion homeassistant/components/knx/knx_entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,5 @@ async def async_added_to_hass(self) -> None:

async def async_will_remove_from_hass(self) -> None:
"""Disconnect device object when removed."""
self._device.unregister_device_updated_cb(self.after_update_callback)
# will also remove callbacks
self._device.shutdown()
2 changes: 1 addition & 1 deletion homeassistant/components/knx/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "KNX",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/knx",
"requirements": ["xknx==0.20.1"],
"requirements": ["xknx==0.20.2"],
"codeowners": ["@Julius2342", "@farmio", "@marvin-w"],
"quality_scale": "silver",
"iot_class": "local_push",
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/motion_blinds/cover.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ async def async_setup_entry(
platform.async_register_entity_service(
SERVICE_SET_ABSOLUTE_POSITION,
SET_ABSOLUTE_POSITION_SCHEMA,
SERVICE_SET_ABSOLUTE_POSITION,
"async_set_absolute_position",
)


Expand Down
3 changes: 1 addition & 2 deletions homeassistant/components/overkiz/select.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ def _select_option_open_closed_pedestrian(
OverkizCommandParam.CLOSED: OverkizCommand.CLOSE,
OverkizCommandParam.OPEN: OverkizCommand.OPEN,
OverkizCommandParam.PEDESTRIAN: OverkizCommand.SET_PEDESTRIAN_POSITION,
}[OverkizCommandParam(option)],
None,
}[OverkizCommandParam(option)]
)


Expand Down
60 changes: 45 additions & 15 deletions homeassistant/components/recorder/statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import os
import re
from statistics import mean
from typing import TYPE_CHECKING, Any, Literal
from typing import TYPE_CHECKING, Any, Literal, overload

from sqlalchemy import bindparam, func
from sqlalchemy.exc import SQLAlchemyError, StatementError
Expand Down Expand Up @@ -125,9 +125,9 @@
STATISTICS_SHORT_TERM_BAKERY = "recorder_statistics_short_term_bakery"


# Convert pressure and temperature statistics from the native unit used for statistics
# to the units configured by the user
UNIT_CONVERSIONS = {
# Convert pressure, temperature and volume statistics from the normalized unit used for
# statistics to the unit configured by the user
STATISTIC_UNIT_TO_DISPLAY_UNIT_CONVERSIONS = {
PRESSURE_PA: lambda x, units: pressure_util.convert(
x, PRESSURE_PA, units.pressure_unit
)
Expand All @@ -145,6 +145,17 @@
else None,
}

# Convert volume statistics from the display unit configured by the user
# to the normalized unit used for statistics
# This is used to support adjusting statistics in the display unit
DISPLAY_UNIT_TO_STATISTIC_UNIT_CONVERSIONS: dict[
str, Callable[[float, UnitSystem], float]
] = {
VOLUME_CUBIC_FEET: lambda x, units: volume_util.convert(
x, _configured_unit(VOLUME_CUBIC_METERS, units), VOLUME_CUBIC_METERS
),
}

_LOGGER = logging.getLogger(__name__)


Expand Down Expand Up @@ -721,7 +732,17 @@ def get_metadata(
)


@overload
def _configured_unit(unit: None, units: UnitSystem) -> None:
...


@overload
def _configured_unit(unit: str, units: UnitSystem) -> str:
...


def _configured_unit(unit: str | None, units: UnitSystem) -> str | None:
"""Return the pressure and temperature units configured by the user."""
if unit == PRESSURE_PA:
return units.pressure_unit
Expand Down Expand Up @@ -1163,7 +1184,7 @@ def no_conversion(val: Any, _: Any) -> float | None:
statistic_id = metadata[meta_id]["statistic_id"]
convert: Callable[[Any, Any], float | None]
if convert_units:
convert = UNIT_CONVERSIONS.get(unit, lambda x, units: x) # type: ignore[arg-type,no-any-return]
convert = STATISTIC_UNIT_TO_DISPLAY_UNIT_CONVERSIONS.get(unit, lambda x, units: x) # type: ignore[arg-type,no-any-return]
else:
convert = no_conversion
ent_results = result[meta_id]
Expand Down Expand Up @@ -1323,17 +1344,26 @@ def adjust_statistics(
if statistic_id not in metadata:
return True

tables: tuple[type[Statistics | StatisticsShortTerm], ...] = (
Statistics,
units = instance.hass.config.units
statistic_unit = metadata[statistic_id][1]["unit_of_measurement"]
display_unit = _configured_unit(statistic_unit, units)
convert = DISPLAY_UNIT_TO_STATISTIC_UNIT_CONVERSIONS.get(display_unit, lambda x, units: x) # type: ignore[arg-type]
sum_adjustment = convert(sum_adjustment, units)

_adjust_sum_statistics(
session,
StatisticsShortTerm,
metadata[statistic_id][0],
start_time,
sum_adjustment,
)

_adjust_sum_statistics(
session,
Statistics,
metadata[statistic_id][0],
start_time.replace(minute=0),
sum_adjustment,
)
for table in tables:
_adjust_sum_statistics(
session,
table,
metadata[statistic_id][0],
start_time,
sum_adjustment,
)

return True
2 changes: 1 addition & 1 deletion homeassistant/components/renault/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "Renault",
"config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/renault",
"requirements": ["renault-api==0.1.10"],
"requirements": ["renault-api==0.1.11"],
"codeowners": ["@epenet"],
"iot_class": "cloud_polling",
"loggers": ["renault_api"],
Expand Down
5 changes: 2 additions & 3 deletions homeassistant/components/samsungtv/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,9 +363,8 @@ def _async_update_existing_matching_entry(
if not entry:
return None
entry_kw_args: dict = {}
if (
self.unique_id
and entry.unique_id is None
if self.unique_id and (
entry.unique_id is None
or (is_unique_match and self.unique_id != entry.unique_id)
):
entry_kw_args["unique_id"] = self.unique_id
Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/squeezebox/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@
PLAYER_DISCOVERY_UNSUB = "player_discovery_unsub"
DISCOVERY_TASK = "discovery_task"
DEFAULT_PORT = 9000
SQUEEZEBOX_SOURCE_STRINGS = ("source:", "wavin:", "spotify:")