Merge pull request #68159 from home-assistant/rc

This commit is contained in:
Paulus Schoutsen
2022-03-15 00:11:48 -07:00
committed by GitHub
20 changed files with 104 additions and 37 deletions

View File

@@ -52,6 +52,7 @@ from .const import (
DATA_AMCREST,
DEVICES,
DOMAIN,
RESOLUTION_LIST,
SERVICE_EVENT,
SERVICE_UPDATE,
)
@@ -76,8 +77,6 @@ RECHECK_INTERVAL = timedelta(minutes=1)
NOTIFICATION_ID = "amcrest_notification"
NOTIFICATION_TITLE = "Amcrest Camera Setup"
RESOLUTION_LIST = {"high": 0, "low": 1}
SCAN_INTERVAL = timedelta(seconds=10)
AUTHENTICATION_LIST = {"basic": "basic"}

View File

@@ -35,6 +35,7 @@ from .const import (
DATA_AMCREST,
DEVICES,
DOMAIN,
RESOLUTION_TO_STREAM,
SERVICE_UPDATE,
SNAPSHOT_TIMEOUT,
)
@@ -533,13 +534,14 @@ class AmcrestCam(Camera):
return
async def _async_get_video(self) -> bool:
stream = {0: "Main", 1: "Extra"}
return await self._api.async_is_video_enabled(
channel=0, stream=stream[self._resolution]
channel=0, stream=RESOLUTION_TO_STREAM[self._resolution]
)
async def _async_set_video(self, enable: bool) -> None:
await self._api.async_set_video_enabled(enable, channel=0)
await self._api.async_set_video_enabled(
enable, channel=0, stream=RESOLUTION_TO_STREAM[self._resolution]
)
async def _async_enable_video(self, enable: bool) -> None:
"""Enable or disable camera video stream."""
@@ -548,7 +550,7 @@ class AmcrestCam(Camera):
# recording on if video stream is being turned off.
if self.is_recording and not enable:
await self._async_enable_recording(False)
await self._async_change_setting(enable, "video", "is_streaming")
await self._async_change_setting(enable, "video", "_attr_is_streaming")
if self._control_light:
await self._async_change_light()
@@ -585,10 +587,14 @@ class AmcrestCam(Camera):
)
async def _async_get_audio(self) -> bool:
return await self._api.async_audio_enabled
return await self._api.async_is_audio_enabled(
channel=0, stream=RESOLUTION_TO_STREAM[self._resolution]
)
async def _async_set_audio(self, enable: bool) -> None:
await self._api.async_set_audio_enabled(enable)
await self._api.async_set_audio_enabled(
enable, channel=0, stream=RESOLUTION_TO_STREAM[self._resolution]
)
async def _async_enable_audio(self, enable: bool) -> None:
"""Enable or disable audio stream."""

View File

@@ -13,3 +13,6 @@ SNAPSHOT_TIMEOUT = 20
SERVICE_EVENT = "event"
SERVICE_UPDATE = "update"
RESOLUTION_LIST = {"high": 0, "low": 1}
RESOLUTION_TO_STREAM = {0: "Main", 1: "Extra"}

View File

@@ -2,7 +2,7 @@
"domain": "amcrest",
"name": "Amcrest",
"documentation": "https://www.home-assistant.io/integrations/amcrest",
"requirements": ["amcrest==1.9.4"],
"requirements": ["amcrest==1.9.7"],
"dependencies": ["ffmpeg"],
"codeowners": ["@flacjacket"],
"iot_class": "local_polling",

View File

@@ -12,7 +12,7 @@ from homeassistant.components import zeroconf
from homeassistant.const import CONF_HOST, CONF_NAME, CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import callback
from homeassistant.data_entry_flow import FlowResult
from homeassistant.util.network import is_link_local
from homeassistant.util.network import is_ipv4_address, is_link_local
from .const import CONF_EVENTS, DOMAIN, DOORBIRD_OUI
from .util import get_mac_address_from_doorstation_info
@@ -103,6 +103,8 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
return self.async_abort(reason="not_doorbird_device")
if is_link_local(ip_address(host)):
return self.async_abort(reason="link_local_address")
if not is_ipv4_address(host):
return self.async_abort(reason="not_ipv4_address")
await self.async_set_unique_id(macaddress)
self._abort_if_unique_id_configured(updates={CONF_HOST: host})

View File

@@ -3,7 +3,8 @@
"abort": {
"already_configured": "Device is already configured",
"link_local_address": "Link local addresses are not supported",
"not_doorbird_device": "This device is not a DoorBird"
"not_doorbird_device": "This device is not a DoorBird",
"not_ipv4_address": "Only IPv4 addresess are supported"
},
"error": {
"cannot_connect": "Failed to connect",

View File

@@ -3,7 +3,7 @@
"name": "Home Assistant Frontend",
"documentation": "https://www.home-assistant.io/integrations/frontend",
"requirements": [
"home-assistant-frontend==20220301.1"
"home-assistant-frontend==20220301.2"
],
"dependencies": [
"api",

View File

@@ -4,7 +4,7 @@
"documentation": "https://www.home-assistant.io/integrations/home_connect",
"dependencies": ["http"],
"codeowners": ["@DavidMStraub"],
"requirements": ["homeconnect==0.6.3"],
"requirements": ["homeconnect==0.7.0"],
"config_flow": true,
"iot_class": "cloud_push",
"loggers": ["homeconnect"]

View File

@@ -2,7 +2,7 @@
"domain": "isy994",
"name": "Universal Devices ISY994",
"documentation": "https://www.home-assistant.io/integrations/isy994",
"requirements": ["pyisy==3.0.1"],
"requirements": ["pyisy==3.0.5"],
"codeowners": ["@bdraco", "@shbatm"],
"config_flow": true,
"ssdp": [

View File

@@ -135,6 +135,13 @@ DEFAULT_KEEPALIVE = 60
DEFAULT_PROTOCOL = PROTOCOL_311
DEFAULT_TLS_PROTOCOL = "auto"
DEFAULT_VALUES = {
CONF_PORT: DEFAULT_PORT,
CONF_WILL_MESSAGE: DEFAULT_WILL,
CONF_BIRTH_MESSAGE: DEFAULT_BIRTH,
CONF_DISCOVERY: DEFAULT_DISCOVERY,
}
ATTR_TOPIC_TEMPLATE = "topic_template"
ATTR_PAYLOAD_TEMPLATE = "payload_template"
@@ -190,7 +197,7 @@ CONFIG_SCHEMA_BASE = vol.Schema(
vol.Coerce(int), vol.Range(min=15)
),
vol.Optional(CONF_BROKER): cv.string,
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
vol.Optional(CONF_PORT): cv.port,
vol.Optional(CONF_USERNAME): cv.string,
vol.Optional(CONF_PASSWORD): cv.string,
vol.Optional(CONF_CERTIFICATE): vol.Any("auto", cv.isfile),
@@ -207,9 +214,9 @@ CONFIG_SCHEMA_BASE = vol.Schema(
vol.Optional(CONF_PROTOCOL, default=DEFAULT_PROTOCOL): vol.All(
cv.string, vol.In([PROTOCOL_31, PROTOCOL_311])
),
vol.Optional(CONF_WILL_MESSAGE, default=DEFAULT_WILL): MQTT_WILL_BIRTH_SCHEMA,
vol.Optional(CONF_BIRTH_MESSAGE, default=DEFAULT_BIRTH): MQTT_WILL_BIRTH_SCHEMA,
vol.Optional(CONF_DISCOVERY, default=DEFAULT_DISCOVERY): cv.boolean,
vol.Optional(CONF_WILL_MESSAGE): MQTT_WILL_BIRTH_SCHEMA,
vol.Optional(CONF_BIRTH_MESSAGE): MQTT_WILL_BIRTH_SCHEMA,
vol.Optional(CONF_DISCOVERY): cv.boolean,
# discovery_prefix must be a valid publish topic because if no
# state topic is specified, it will be created with the given prefix.
vol.Optional(
@@ -613,6 +620,8 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
def _merge_config(entry, conf):
"""Merge configuration.yaml config with config entry."""
# Base config on default values
conf = {**DEFAULT_VALUES, **conf}
return {**conf, **entry.data}
@@ -632,6 +641,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
override,
)
# Merge the configuration values from configuration.yaml
conf = _merge_config(entry, conf)
hass.data[DATA_MQTT] = MQTT(

View File

@@ -10,7 +10,7 @@ from samsungctl import Remote
from samsungctl.exceptions import AccessDenied, ConnectionClosed, UnhandledResponse
from samsungtvws import SamsungTVWS
from samsungtvws.exceptions import ConnectionFailure, HttpApiError
from websocket import WebSocketException
from websocket import WebSocketException, WebSocketTimeoutException
from homeassistant.const import (
CONF_HOST,
@@ -318,8 +318,8 @@ class SamsungTVWSBridge(SamsungTVBridge):
def _get_app_list(self) -> dict[str, str] | None:
"""Get installed app list."""
if self._app_list is None:
if remote := self._get_remote():
if self._app_list is None and (remote := self._get_remote()):
with contextlib.suppress(WebSocketTimeoutException):
raw_app_list: list[dict[str, str]] = remote.app_list()
self._app_list = {
app["name"]: app["appId"]

View File

@@ -174,6 +174,7 @@ SENSORS: Final = {
value=lambda value: round(value / 1000, 2),
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
available=lambda block: cast(int, block.energy) != -1,
),
("emeter", "energyReturned"): BlockSensorDescription(
key="emeter|energyReturned",
@@ -182,6 +183,7 @@ SENSORS: Final = {
value=lambda value: round(value / 1000, 2),
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
available=lambda block: cast(int, block.energyReturned) != -1,
),
("light", "energy"): BlockSensorDescription(
key="light|energy",

View File

@@ -79,6 +79,7 @@ class SomfyShade(RestoreEntity, CoverEntity):
self._attr_unique_id = target_id
self._attr_name = name
self._reverse = reverse
self._attr_is_closed = None
self._attr_device_class = device_class
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, self._target_id)},

View File

@@ -7,7 +7,7 @@ from .backports.enum import StrEnum
MAJOR_VERSION: Final = 2022
MINOR_VERSION: Final = 3
PATCH_VERSION: Final = "4"
PATCH_VERSION: Final = "5"
__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)

View File

@@ -14,7 +14,7 @@ certifi>=2021.5.30
ciso8601==2.2.0
cryptography==35.0.0
hass-nabucasa==0.54.0
home-assistant-frontend==20220301.1
home-assistant-frontend==20220301.2
httpx==0.21.3
ifaddr==0.1.7
jinja2==3.0.3

View File

@@ -311,7 +311,7 @@ amberelectric==1.0.3
ambiclimate==0.2.1
# homeassistant.components.amcrest
amcrest==1.9.4
amcrest==1.9.7
# homeassistant.components.androidtv
androidtv[async]==0.0.63
@@ -843,13 +843,13 @@ hole==0.7.0
holidays==0.13
# homeassistant.components.frontend
home-assistant-frontend==20220301.1
home-assistant-frontend==20220301.2
# homeassistant.components.zwave
# homeassistant-pyozw==0.1.10
# homeassistant.components.home_connect
homeconnect==0.6.3
homeconnect==0.7.0
# homeassistant.components.homematicip_cloud
homematicip==1.0.2
@@ -1610,7 +1610,7 @@ pyirishrail==0.0.2
pyiss==1.0.1
# homeassistant.components.isy994
pyisy==3.0.1
pyisy==3.0.5
# homeassistant.components.itach
pyitachip2ir==0.0.7

View File

@@ -553,13 +553,13 @@ hole==0.7.0
holidays==0.13
# homeassistant.components.frontend
home-assistant-frontend==20220301.1
home-assistant-frontend==20220301.2
# homeassistant.components.zwave
# homeassistant-pyozw==0.1.10
# homeassistant.components.home_connect
homeconnect==0.6.3
homeconnect==0.7.0
# homeassistant.components.homematicip_cloud
homematicip==1.0.2
@@ -1015,7 +1015,7 @@ pyiqvia==2021.11.0
pyiss==1.0.1
# homeassistant.components.isy994
pyisy==3.0.1
pyisy==3.0.5
# homeassistant.components.kira
pykira==0.1.1

View File

@@ -1,6 +1,6 @@
[metadata]
name = homeassistant
version = 2022.3.4
version = 2022.3.5
author = The Home Assistant Authors
author_email = hello@home-assistant.io
license = Apache-2.0

View File

@@ -116,6 +116,54 @@ async def test_form_zeroconf_link_local_ignored(hass):
assert result["reason"] == "link_local_address"
async def test_form_zeroconf_ipv4_address(hass):
"""Test we abort and update the ip address from zeroconf with an ipv4 address."""
config_entry = MockConfigEntry(
domain=DOMAIN,
unique_id="1CCAE3AAAAAA",
data=VALID_CONFIG,
options={CONF_EVENTS: ["event1", "event2", "event3"]},
)
config_entry.add_to_hass(hass)
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_ZEROCONF},
data=zeroconf.ZeroconfServiceInfo(
host="4.4.4.4",
addresses=["4.4.4.4"],
hostname="mock_hostname",
name="Doorstation - abc123._axis-video._tcp.local.",
port=None,
properties={"macaddress": "1CCAE3AAAAAA"},
type="mock_type",
),
)
assert result["type"] == "abort"
assert result["reason"] == "already_configured"
assert config_entry.data[CONF_HOST] == "4.4.4.4"
async def test_form_zeroconf_non_ipv4_ignored(hass):
"""Test we abort when we get a non ipv4 address via zeroconf."""
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_ZEROCONF},
data=zeroconf.ZeroconfServiceInfo(
host="fd00::b27c:63bb:cc85:4ea0",
addresses=["fd00::b27c:63bb:cc85:4ea0"],
hostname="mock_hostname",
name="Doorstation - abc123._axis-video._tcp.local.",
port=None,
properties={"macaddress": "1CCAE3DOORBIRD"},
type="mock_type",
),
)
assert result["type"] == "abort"
assert result["reason"] == "not_ipv4_address"
async def test_form_zeroconf_correct_oui(hass):
"""Test we can setup from zeroconf with the correct OUI source."""
doorbirdapi = _get_mock_doorbirdapi_return_values(

View File

@@ -1,12 +1,11 @@
"""Tests for Efergy integration."""
from unittest.mock import AsyncMock, patch
from pyefergy import Efergy, exceptions
from pyefergy import exceptions
from homeassistant.components.efergy import DOMAIN
from homeassistant.const import CONF_API_KEY
from homeassistant.core import HomeAssistant
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.setup import async_setup_component
from tests.common import MockConfigEntry, load_fixture
@@ -56,10 +55,6 @@ async def mock_responses(
):
"""Mock responses from Efergy."""
base_url = "https://engage.efergy.com/mobile_proxy/"
api = Efergy(
token, session=async_get_clientsession(hass), utc_offset="America/New_York"
)
assert api._utc_offset == 300
if error:
aioclient_mock.get(
f"{base_url}getInstant?token={token}",