Skip to content
Merged

0.116.3 #41877

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions azure-pipelines-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,10 @@ stages:
docker run --rm --privileged \
-v ~/.docker:/root/.docker \
-v /run/docker.sock:/run/docker.sock:rw \
-v $(pwd):/data:ro \
homeassistant/amd64-builder:$(versionBuilder) \
--homeassistant-machine "$(homeassistantRelease)=$(buildMachine)" \
-r https://github.com/home-assistant/hassio-homeassistant \
-t machine --docker-hub homeassistant
-t /data --docker-hub homeassistant
displayName: 'Build Release'

- stage: 'Publish'
Expand Down
1 change: 1 addition & 0 deletions homeassistant/components/hassio/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ async def _handle(

return await self._command_proxy(path, request)

delete = _handle
get = _handle
post = _handle

Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/kef/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"name": "KEF",
"documentation": "https://www.home-assistant.io/integrations/kef",
"codeowners": ["@basnijholt"],
"requirements": ["aiokef==0.2.13", "getmac==0.8.2"]
"requirements": ["aiokef==0.2.16", "getmac==0.8.2"]
}
26 changes: 14 additions & 12 deletions homeassistant/components/kef/media_player.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""Platform for the KEF Wireless Speakers."""

import asyncio
from datetime import timedelta
from functools import partial
import ipaddress
Expand Down Expand Up @@ -164,7 +163,11 @@ def add_service(name, which, option):
dtype = type(options[0]) # int or float
platform.async_register_entity_service(
name,
{vol.Required(option): vol.All(vol.Coerce(dtype), vol.In(options))},
{
vol.Required(option): vol.All(
vol.Coerce(float), vol.Coerce(dtype), vol.In(options)
)
},
f"set_{which}",
)

Expand Down Expand Up @@ -365,17 +368,16 @@ async def update_dsp(self, _=None) -> None:
# The LSX is able to respond when off the LS50 has to be on.
return

(mode, *rest) = await asyncio.gather(
self._speaker.get_mode(),
self._speaker.get_desk_db(),
self._speaker.get_wall_db(),
self._speaker.get_treble_db(),
self._speaker.get_high_hz(),
self._speaker.get_low_hz(),
self._speaker.get_sub_db(),
mode = await self._speaker.get_mode()
self._dsp = dict(
desk_db=await self._speaker.get_desk_db(),
wall_db=await self._speaker.get_wall_db(),
treble_db=await self._speaker.get_treble_db(),
high_hz=await self._speaker.get_high_hz(),
low_hz=await self._speaker.get_low_hz(),
sub_db=await self._speaker.get_sub_db(),
**mode._asdict(),
)
keys = ["desk_db", "wall_db", "treble_db", "high_hz", "low_hz", "sub_db"]
self._dsp = dict(zip(keys, rest), **mode._asdict())

async def async_added_to_hass(self):
"""Subscribe to DSP updates."""
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/netatmo/data_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
HOMEDATA_DATA_CLASS_NAME: 900,
HOMESTATUS_DATA_CLASS_NAME: 300,
CAMERA_DATA_CLASS_NAME: 900,
WEATHERSTATION_DATA_CLASS_NAME: 300,
WEATHERSTATION_DATA_CLASS_NAME: 600,
HOMECOACH_DATA_CLASS_NAME: 300,
PUBLICDATA_DATA_CLASS_NAME: 600,
}
Expand Down
4 changes: 2 additions & 2 deletions homeassistant/components/omnilogic/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ def state(self):
unit_of_measurement = self._unit

if self._unit_type == "Metric":
salt_return = round(salt_return / 1000, 2)
salt_return = round(int(salt_return) / 1000, 2)
unit_of_measurement = f"{MASS_GRAMS}/{VOLUME_LITERS}"

self._unit = unit_of_measurement
Expand Down Expand Up @@ -279,7 +279,7 @@ def state(self):
"icon": "mdi:speedometer",
"unit": PERCENTAGE,
"guard_condition": [
{"Type": "FMT_SINGLE_SPEED"},
{"Filter-Type": "FMT_SINGLE_SPEED"},
],
},
],
Expand Down
3 changes: 1 addition & 2 deletions homeassistant/components/shelly/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def shelly_naming(self, block, entity_type: str):
return f"{entity_name} {self.description.name}"

channels = 0
mode = "relays"
mode = block.type + "s"
if "num_outputs" in self.wrapper.device.shelly:
channels = self.wrapper.device.shelly["num_outputs"]
if (
Expand All @@ -38,7 +38,6 @@ def shelly_naming(self, block, entity_type: str):
channels = 1
if block.type == "emeter" and "num_emeters" in self.wrapper.device.shelly:
channels = self.wrapper.device.shelly["num_emeters"]
mode = "emeters"
if channels > 1 and block.type != "device":
# Shelly EM (SHEM) with firmware v1.8.1 doesn't have "name" key; will be fixed in next firmware release
if "name" in self.wrapper.device.settings[mode][int(block.channel)]:
Expand Down
34 changes: 21 additions & 13 deletions homeassistant/components/simplisafe/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
)
import voluptuous as vol

from homeassistant.config_entries import SOURCE_IMPORT
from homeassistant.config_entries import SOURCE_IMPORT, SOURCE_REAUTH
from homeassistant.const import (
ATTR_CODE,
CONF_CODE,
Expand Down Expand Up @@ -365,8 +365,7 @@ async def async_unload_entry(hass, entry):

async def async_update_options(hass, config_entry):
"""Handle an options update."""
simplisafe = hass.data[DOMAIN][DATA_CLIENT][config_entry.entry_id]
simplisafe.options = config_entry.options
await hass.config_entries.async_reload(config_entry.entry_id)


class SimpliSafeWebsocket:
Expand Down Expand Up @@ -530,17 +529,26 @@ async def update_system(system):
for result in results:
if isinstance(result, InvalidCredentialsError):
if self._emergency_refresh_token_used:
LOGGER.error(
"Token disconnected or invalid. Please re-auth the "
"SimpliSafe integration in HASS"
)
self._hass.async_create_task(
self._hass.config_entries.flow.async_init(
DOMAIN,
context={"source": "reauth"},
data=self._config_entry.data,
matching_flows = [
flow
for flow in self._hass.config_entries.flow.async_progress()
if flow["context"].get("source") == SOURCE_REAUTH
and flow["context"].get("unique_id")
== self._config_entry.unique_id
]

if not matching_flows:
self._hass.async_create_task(
self._hass.config_entries.flow.async_init(
DOMAIN,
context={
"source": SOURCE_REAUTH,
"unique_id": self._config_entry.unique_id,
},
data=self._config_entry.data,
)
)
)

return

LOGGER.warning("SimpliSafe cloud error; trying stored refresh token")
Expand Down
14 changes: 12 additions & 2 deletions homeassistant/components/synology_dsm/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
from typing import Dict

from synology_dsm.api.surveillance_station import SynoSurveillanceStation
from synology_dsm.api.surveillance_station.camera import SynoCamera

from homeassistant.components.camera import SUPPORT_STREAM, Camera
from homeassistant.config_entries import ConfigEntry
from homeassistant.helpers.typing import HomeAssistantType

from . import SynologyDSMEntity
from . import SynoApi, SynologyDSMEntity
from .const import (
DOMAIN,
ENTITY_CLASS,
Expand Down Expand Up @@ -40,7 +41,7 @@ async def async_setup_entry(
class SynoDSMCamera(SynologyDSMEntity, Camera):
"""Representation a Synology camera."""

def __init__(self, api, camera):
def __init__(self, api: SynoApi, camera: SynoCamera):
"""Initialize a Synology camera."""
super().__init__(
api,
Expand Down Expand Up @@ -69,6 +70,11 @@ def device_info(self) -> Dict[str, any]:
),
}

@property
def available(self) -> bool:
"""Return the availability of the camera."""
return self._camera.is_enabled

@property
def supported_features(self) -> int:
"""Return supported features of this camera."""
Expand All @@ -86,10 +92,14 @@ def motion_detection_enabled(self):

def camera_image(self) -> bytes:
"""Return bytes of camera image."""
if not self.available:
return None
return self._api.surveillance_station.get_camera_image(self._camera.id)

async def stream_source(self) -> str:
"""Return the source of the stream."""
if not self.available:
return None
return self._camera.live_view.rtsp

def enable_motion_detection(self):
Expand Down
21 changes: 14 additions & 7 deletions homeassistant/components/websocket_api/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,13 +257,20 @@ async def handle_render_template(hass, connection, msg):
timeout = msg.get("timeout")
info = None

if timeout and await template.async_render_will_timeout(timeout):
connection.send_error(
msg["id"],
const.ERR_TEMPLATE_ERROR,
f"Exceeded maximum execution time of {timeout}s",
)
return
if timeout:
try:
timed_out = await template.async_render_will_timeout(timeout)
except TemplateError as ex:
connection.send_error(msg["id"], const.ERR_TEMPLATE_ERROR, str(ex))
return

if timed_out:
connection.send_error(
msg["id"],
const.ERR_TEMPLATE_ERROR,
f"Exceeded maximum execution time of {timeout}s",
)
return

@callback
def _template_listener(event, updates):
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/const.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Constants used by Home Assistant components."""
MAJOR_VERSION = 0
MINOR_VERSION = 116
PATCH_VERSION = "2"
PATCH_VERSION = "3"
__short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}"
__version__ = f"{__short_version__}.{PATCH_VERSION}"
REQUIRED_PYTHON_VER = (3, 7, 1)
Expand Down
4 changes: 1 addition & 3 deletions homeassistant/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
"""The exceptions used by Home Assistant."""
from typing import TYPE_CHECKING, Optional

import jinja2

if TYPE_CHECKING:
from .core import Context # noqa: F401 pylint: disable=unused-import

Expand All @@ -22,7 +20,7 @@ class NoEntitySpecifiedError(HomeAssistantError):
class TemplateError(HomeAssistantError):
"""Error during template rendering."""

def __init__(self, exception: jinja2.TemplateError) -> None:
def __init__(self, exception: Exception) -> None:
"""Init the error."""
super().__init__(f"{exception.__class__.__name__}: {exception}")

Expand Down
17 changes: 17 additions & 0 deletions homeassistant/helpers/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,9 @@ def async_track_state_change_event(
care about the state change events so we can
do a fast dict lookup to route events.
"""
entity_ids = _async_string_to_lower_list(entity_ids)
if not entity_ids:
return _remove_empty_listener

entity_callbacks = hass.data.setdefault(TRACK_STATE_CHANGE_CALLBACKS, {})

Expand Down Expand Up @@ -277,6 +280,11 @@ def remove_listener() -> None:
return remove_listener


@callback
def _remove_empty_listener() -> None:
"""Remove a listener that does nothing."""


@callback
def _async_remove_indexed_listeners(
hass: HomeAssistant,
Expand Down Expand Up @@ -309,6 +317,9 @@ def async_track_entity_registry_updated_event(

Similar to async_track_state_change_event.
"""
entity_ids = _async_string_to_lower_list(entity_ids)
if not entity_ids:
return _remove_empty_listener

entity_callbacks = hass.data.setdefault(TRACK_ENTITY_REGISTRY_UPDATED_CALLBACKS, {})

Expand Down Expand Up @@ -381,6 +392,9 @@ def async_track_state_added_domain(
action: Callable[[Event], Any],
) -> Callable[[], None]:
"""Track state change events when an entity is added to domains."""
domains = _async_string_to_lower_list(domains)
if not domains:
return _remove_empty_listener

domain_callbacks = hass.data.setdefault(TRACK_STATE_ADDED_DOMAIN_CALLBACKS, {})

Expand Down Expand Up @@ -424,6 +438,9 @@ def async_track_state_removed_domain(
action: Callable[[Event], Any],
) -> Callable[[], None]:
"""Track state change events when an entity is removed from domains."""
domains = _async_string_to_lower_list(domains)
if not domains:
return _remove_empty_listener

domain_callbacks = hass.data.setdefault(TRACK_STATE_REMOVED_DOMAIN_CALLBACKS, {})

Expand Down
2 changes: 1 addition & 1 deletion homeassistant/helpers/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ def async_render(self, variables: TemplateVarsType = None, **kwargs: Any) -> str

try:
return compiled.render(kwargs).strip()
except jinja2.TemplateError as err:
except Exception as err: # pylint: disable=broad-except
raise TemplateError(err) from err

async def async_render_will_timeout(
Expand Down
34 changes: 34 additions & 0 deletions machine/intel-nuc
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
ARG BUILD_VERSION
FROM homeassistant/amd64-homeassistant:$BUILD_VERSION

RUN apk --no-cache add \
libva-intel-driver \
usbutils

##
# Build libcec for HDMI-CEC
ARG LIBCEC_VERSION=6.0.2
RUN apk add --no-cache \
eudev-libs \
p8-platform \
&& apk add --no-cache --virtual .build-dependencies \
build-base \
cmake \
eudev-dev \
swig \
p8-platform-dev \
linux-headers \
&& git clone --depth 1 -b libcec-${LIBCEC_VERSION} https://github.com/Pulse-Eight/libcec /usr/src/libcec \
&& cd /usr/src/libcec \
&& mkdir -p /usr/src/libcec/build \
&& cd /usr/src/libcec/build \
&& cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr/local \
-DPYTHON_LIBRARY="/usr/local/lib/libpython3.8.so" \
-DPYTHON_INCLUDE_DIR="/usr/local/include/python3.8" \
-DHAVE_LINUX_API=1 \
.. \
&& make -j$(nproc) \
&& make install \
&& echo "cec" > "/usr/local/lib/python3.8/site-packages/cec.pth" \
&& apk del .build-dependencies \
&& rm -rf /usr/src/libcec*
Loading