mirror of
https://github.com/home-assistant/core.git
synced 2025-07-16 09:47:13 +00:00
Merge pull request #66161 from home-assistant/rc
This commit is contained in:
commit
a96b91d120
@ -2,7 +2,7 @@
|
|||||||
"domain": "amcrest",
|
"domain": "amcrest",
|
||||||
"name": "Amcrest",
|
"name": "Amcrest",
|
||||||
"documentation": "https://www.home-assistant.io/integrations/amcrest",
|
"documentation": "https://www.home-assistant.io/integrations/amcrest",
|
||||||
"requirements": ["amcrest==1.9.3"],
|
"requirements": ["amcrest==1.9.4"],
|
||||||
"dependencies": ["ffmpeg"],
|
"dependencies": ["ffmpeg"],
|
||||||
"codeowners": ["@flacjacket"],
|
"codeowners": ["@flacjacket"],
|
||||||
"iot_class": "local_polling"
|
"iot_class": "local_polling"
|
||||||
|
@ -155,7 +155,8 @@ class FritzBoxTools(update_coordinator.DataUpdateCoordinator):
|
|||||||
self.hass = hass
|
self.hass = hass
|
||||||
self.host = host
|
self.host = host
|
||||||
self.mesh_role = MeshRoles.NONE
|
self.mesh_role = MeshRoles.NONE
|
||||||
self.device_is_router: bool = True
|
self.device_conn_type: str | None = None
|
||||||
|
self.device_is_router: bool = False
|
||||||
self.password = password
|
self.password = password
|
||||||
self.port = port
|
self.port = port
|
||||||
self.username = username
|
self.username = username
|
||||||
@ -213,7 +214,15 @@ class FritzBoxTools(update_coordinator.DataUpdateCoordinator):
|
|||||||
self._current_firmware = info.get("NewSoftwareVersion")
|
self._current_firmware = info.get("NewSoftwareVersion")
|
||||||
|
|
||||||
self._update_available, self._latest_firmware = self._update_device_info()
|
self._update_available, self._latest_firmware = self._update_device_info()
|
||||||
self.device_is_router = "WANIPConn1" in self.connection.services
|
if "Layer3Forwarding1" in self.connection.services:
|
||||||
|
if connection_type := self.connection.call_action(
|
||||||
|
"Layer3Forwarding1", "GetDefaultConnectionService"
|
||||||
|
).get("NewDefaultConnectionService"):
|
||||||
|
# Return NewDefaultConnectionService sample: "1.WANPPPConnection.1"
|
||||||
|
self.device_conn_type = connection_type[2:][:-2]
|
||||||
|
self.device_is_router = self.connection.call_action(
|
||||||
|
self.device_conn_type, "GetInfo"
|
||||||
|
).get("NewEnable")
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
async def _async_update_data(self) -> None:
|
async def _async_update_data(self) -> None:
|
||||||
|
@ -25,6 +25,7 @@ async def async_get_config_entry_diagnostics(
|
|||||||
"current_firmware": avm_wrapper.current_firmware,
|
"current_firmware": avm_wrapper.current_firmware,
|
||||||
"latest_firmware": avm_wrapper.latest_firmware,
|
"latest_firmware": avm_wrapper.latest_firmware,
|
||||||
"update_available": avm_wrapper.update_available,
|
"update_available": avm_wrapper.update_available,
|
||||||
|
"connection_type": avm_wrapper.device_conn_type,
|
||||||
"is_router": avm_wrapper.device_is_router,
|
"is_router": avm_wrapper.device_is_router,
|
||||||
"mesh_role": avm_wrapper.mesh_role,
|
"mesh_role": avm_wrapper.mesh_role,
|
||||||
"last_update success": avm_wrapper.last_update_success,
|
"last_update success": avm_wrapper.last_update_success,
|
||||||
|
@ -81,16 +81,12 @@ def port_entities_list(
|
|||||||
|
|
||||||
_LOGGER.debug("Setting up %s switches", SWITCH_TYPE_PORTFORWARD)
|
_LOGGER.debug("Setting up %s switches", SWITCH_TYPE_PORTFORWARD)
|
||||||
entities_list: list[FritzBoxPortSwitch] = []
|
entities_list: list[FritzBoxPortSwitch] = []
|
||||||
connection_type = avm_wrapper.get_default_connection()
|
if not avm_wrapper.device_conn_type:
|
||||||
if not connection_type:
|
|
||||||
_LOGGER.debug("The FRITZ!Box has no %s options", SWITCH_TYPE_PORTFORWARD)
|
_LOGGER.debug("The FRITZ!Box has no %s options", SWITCH_TYPE_PORTFORWARD)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
# Return NewDefaultConnectionService sample: "1.WANPPPConnection.1"
|
|
||||||
con_type: str = connection_type["NewDefaultConnectionService"][2:][:-2]
|
|
||||||
|
|
||||||
# Query port forwardings and setup a switch for each forward for the current device
|
# Query port forwardings and setup a switch for each forward for the current device
|
||||||
resp = avm_wrapper.get_num_port_mapping(con_type)
|
resp = avm_wrapper.get_num_port_mapping(avm_wrapper.device_conn_type)
|
||||||
if not resp:
|
if not resp:
|
||||||
_LOGGER.debug("The FRITZ!Box has no %s options", SWITCH_TYPE_DEFLECTION)
|
_LOGGER.debug("The FRITZ!Box has no %s options", SWITCH_TYPE_DEFLECTION)
|
||||||
return []
|
return []
|
||||||
@ -107,7 +103,7 @@ def port_entities_list(
|
|||||||
|
|
||||||
for i in range(port_forwards_count):
|
for i in range(port_forwards_count):
|
||||||
|
|
||||||
portmap = avm_wrapper.get_port_mapping(con_type, i)
|
portmap = avm_wrapper.get_port_mapping(avm_wrapper.device_conn_type, i)
|
||||||
if not portmap:
|
if not portmap:
|
||||||
_LOGGER.debug("The FRITZ!Box has no %s options", SWITCH_TYPE_DEFLECTION)
|
_LOGGER.debug("The FRITZ!Box has no %s options", SWITCH_TYPE_DEFLECTION)
|
||||||
continue
|
continue
|
||||||
@ -133,7 +129,7 @@ def port_entities_list(
|
|||||||
portmap,
|
portmap,
|
||||||
port_name,
|
port_name,
|
||||||
i,
|
i,
|
||||||
con_type,
|
avm_wrapper.device_conn_type,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ class GenericCamera(Camera):
|
|||||||
if self._stream_source is not None:
|
if self._stream_source is not None:
|
||||||
self._stream_source.hass = hass
|
self._stream_source.hass = hass
|
||||||
self._limit_refetch = device_info[CONF_LIMIT_REFETCH_TO_URL_CHANGE]
|
self._limit_refetch = device_info[CONF_LIMIT_REFETCH_TO_URL_CHANGE]
|
||||||
self._attr_frames_interval = 1 / device_info[CONF_FRAMERATE]
|
self._attr_frame_interval = 1 / device_info[CONF_FRAMERATE]
|
||||||
self._supported_features = SUPPORT_STREAM if self._stream_source else 0
|
self._supported_features = SUPPORT_STREAM if self._stream_source else 0
|
||||||
self.content_type = device_info[CONF_CONTENT_TYPE]
|
self.content_type = device_info[CONF_CONTENT_TYPE]
|
||||||
self.verify_ssl = device_info[CONF_VERIFY_SSL]
|
self.verify_ssl = device_info[CONF_VERIFY_SSL]
|
||||||
|
@ -577,6 +577,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||||||
websocket_api.async_register_command(hass, websocket_subscribe)
|
websocket_api.async_register_command(hass, websocket_subscribe)
|
||||||
websocket_api.async_register_command(hass, websocket_remove_device)
|
websocket_api.async_register_command(hass, websocket_remove_device)
|
||||||
websocket_api.async_register_command(hass, websocket_mqtt_info)
|
websocket_api.async_register_command(hass, websocket_mqtt_info)
|
||||||
|
debug_info.initialize(hass)
|
||||||
|
|
||||||
if conf is None:
|
if conf is None:
|
||||||
# If we have a config entry, setup is done by that config entry.
|
# If we have a config entry, setup is done by that config entry.
|
||||||
@ -595,8 +596,6 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
debug_info.initialize(hass)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"name": "SimpliSafe",
|
"name": "SimpliSafe",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/simplisafe",
|
"documentation": "https://www.home-assistant.io/integrations/simplisafe",
|
||||||
"requirements": ["simplisafe-python==2022.02.0"],
|
"requirements": ["simplisafe-python==2022.02.1"],
|
||||||
"codeowners": ["@bachya"],
|
"codeowners": ["@bachya"],
|
||||||
"iot_class": "cloud_polling",
|
"iot_class": "cloud_polling",
|
||||||
"dhcp": [
|
"dhcp": [
|
||||||
|
@ -33,7 +33,7 @@ from homeassistant.const import (
|
|||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
|
|
||||||
from .const import CONF_DEVICE_TOKEN
|
from .const import CONF_DEVICE_TOKEN, DOMAIN, SYSTEM_LOADED
|
||||||
|
|
||||||
LOGGER = logging.getLogger(__name__)
|
LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -218,6 +218,11 @@ class SynoApi:
|
|||||||
)
|
)
|
||||||
self.surveillance_station = self.dsm.surveillance_station
|
self.surveillance_station = self.dsm.surveillance_station
|
||||||
|
|
||||||
|
def _set_system_loaded(self, state: bool = False) -> None:
|
||||||
|
"""Set system loaded flag."""
|
||||||
|
dsm_device = self._hass.data[DOMAIN].get(self.information.serial)
|
||||||
|
dsm_device[SYSTEM_LOADED] = state
|
||||||
|
|
||||||
async def _syno_api_executer(self, api_call: Callable) -> None:
|
async def _syno_api_executer(self, api_call: Callable) -> None:
|
||||||
"""Synology api call wrapper."""
|
"""Synology api call wrapper."""
|
||||||
try:
|
try:
|
||||||
@ -231,10 +236,12 @@ class SynoApi:
|
|||||||
async def async_reboot(self) -> None:
|
async def async_reboot(self) -> None:
|
||||||
"""Reboot NAS."""
|
"""Reboot NAS."""
|
||||||
await self._syno_api_executer(self.system.reboot)
|
await self._syno_api_executer(self.system.reboot)
|
||||||
|
self._set_system_loaded()
|
||||||
|
|
||||||
async def async_shutdown(self) -> None:
|
async def async_shutdown(self) -> None:
|
||||||
"""Shutdown NAS."""
|
"""Shutdown NAS."""
|
||||||
await self._syno_api_executer(self.system.shutdown)
|
await self._syno_api_executer(self.system.shutdown)
|
||||||
|
self._set_system_loaded()
|
||||||
|
|
||||||
async def async_unload(self) -> None:
|
async def async_unload(self) -> None:
|
||||||
"""Stop interacting with the NAS and prepare for removal from hass."""
|
"""Stop interacting with the NAS and prepare for removal from hass."""
|
||||||
|
@ -15,7 +15,6 @@ from .const import (
|
|||||||
SERVICE_SHUTDOWN,
|
SERVICE_SHUTDOWN,
|
||||||
SERVICES,
|
SERVICES,
|
||||||
SYNO_API,
|
SYNO_API,
|
||||||
SYSTEM_LOADED,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
LOGGER = logging.getLogger(__name__)
|
LOGGER = logging.getLogger(__name__)
|
||||||
@ -57,7 +56,6 @@ async def async_setup_services(hass: HomeAssistant) -> None:
|
|||||||
)
|
)
|
||||||
dsm_api: SynoApi = dsm_device[SYNO_API]
|
dsm_api: SynoApi = dsm_device[SYNO_API]
|
||||||
try:
|
try:
|
||||||
dsm_device[SYSTEM_LOADED] = False
|
|
||||||
await getattr(dsm_api, f"async_{call.service}")()
|
await getattr(dsm_api, f"async_{call.service}")()
|
||||||
except SynologyDSMException as ex:
|
except SynologyDSMException as ex:
|
||||||
LOGGER.error(
|
LOGGER.error(
|
||||||
|
@ -7,7 +7,7 @@ from .backports.enum import StrEnum
|
|||||||
|
|
||||||
MAJOR_VERSION: Final = 2022
|
MAJOR_VERSION: Final = 2022
|
||||||
MINOR_VERSION: Final = 2
|
MINOR_VERSION: Final = 2
|
||||||
PATCH_VERSION: Final = "4"
|
PATCH_VERSION: Final = "5"
|
||||||
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
||||||
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
|
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
|
||||||
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 9, 0)
|
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 9, 0)
|
||||||
|
@ -308,7 +308,7 @@ amberelectric==1.0.3
|
|||||||
ambiclimate==0.2.1
|
ambiclimate==0.2.1
|
||||||
|
|
||||||
# homeassistant.components.amcrest
|
# homeassistant.components.amcrest
|
||||||
amcrest==1.9.3
|
amcrest==1.9.4
|
||||||
|
|
||||||
# homeassistant.components.androidtv
|
# homeassistant.components.androidtv
|
||||||
androidtv[async]==0.0.63
|
androidtv[async]==0.0.63
|
||||||
@ -2190,7 +2190,7 @@ simplehound==0.3
|
|||||||
simplepush==1.1.4
|
simplepush==1.1.4
|
||||||
|
|
||||||
# homeassistant.components.simplisafe
|
# homeassistant.components.simplisafe
|
||||||
simplisafe-python==2022.02.0
|
simplisafe-python==2022.02.1
|
||||||
|
|
||||||
# homeassistant.components.sisyphus
|
# homeassistant.components.sisyphus
|
||||||
sisyphus-control==3.1.2
|
sisyphus-control==3.1.2
|
||||||
|
@ -1337,7 +1337,7 @@ sharkiqpy==0.1.8
|
|||||||
simplehound==0.3
|
simplehound==0.3
|
||||||
|
|
||||||
# homeassistant.components.simplisafe
|
# homeassistant.components.simplisafe
|
||||||
simplisafe-python==2022.02.0
|
simplisafe-python==2022.02.1
|
||||||
|
|
||||||
# homeassistant.components.slack
|
# homeassistant.components.slack
|
||||||
slackclient==2.5.0
|
slackclient==2.5.0
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[metadata]
|
[metadata]
|
||||||
name = homeassistant
|
name = homeassistant
|
||||||
version = 2022.2.4
|
version = 2022.2.5
|
||||||
author = The Home Assistant Authors
|
author = The Home Assistant Authors
|
||||||
author_email = hello@home-assistant.io
|
author_email = hello@home-assistant.io
|
||||||
license = Apache-2.0
|
license = Apache-2.0
|
||||||
|
@ -9,6 +9,7 @@ import pytest
|
|||||||
import respx
|
import respx
|
||||||
|
|
||||||
from homeassistant import config as hass_config
|
from homeassistant import config as hass_config
|
||||||
|
from homeassistant.components.camera import async_get_mjpeg_stream
|
||||||
from homeassistant.components.generic import DOMAIN
|
from homeassistant.components.generic import DOMAIN
|
||||||
from homeassistant.components.websocket_api.const import TYPE_RESULT
|
from homeassistant.components.websocket_api.const import TYPE_RESULT
|
||||||
from homeassistant.const import SERVICE_RELOAD
|
from homeassistant.const import SERVICE_RELOAD
|
||||||
@ -515,3 +516,29 @@ async def test_no_still_image_url(hass, hass_client):
|
|||||||
mock_stream.async_get_image.assert_called_once()
|
mock_stream.async_get_image.assert_called_once()
|
||||||
assert resp.status == HTTPStatus.OK
|
assert resp.status == HTTPStatus.OK
|
||||||
assert await resp.read() == b"stream_keyframe_image"
|
assert await resp.read() == b"stream_keyframe_image"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_frame_interval_property(hass):
|
||||||
|
"""Test that the frame interval is calculated and returned correctly."""
|
||||||
|
|
||||||
|
await async_setup_component(
|
||||||
|
hass,
|
||||||
|
"camera",
|
||||||
|
{
|
||||||
|
"camera": {
|
||||||
|
"name": "config_test",
|
||||||
|
"platform": "generic",
|
||||||
|
"stream_source": "rtsp://example.com:554/rtsp/",
|
||||||
|
"framerate": 5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
request = Mock()
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.camera.async_get_still_stream"
|
||||||
|
) as mock_get_stream:
|
||||||
|
await async_get_mjpeg_stream(hass, request, "camera.config_test")
|
||||||
|
|
||||||
|
assert mock_get_stream.call_args_list[0][0][3] == pytest.approx(0.2)
|
||||||
|
@ -663,10 +663,10 @@ async def test_sensors_unreachable(hass, mock_config_entry_data, mock_config_ent
|
|||||||
entry = mock_config_entry
|
entry = mock_config_entry
|
||||||
entry.data = mock_config_entry_data
|
entry.data = mock_config_entry_data
|
||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
utcnow = dt_util.utcnow()
|
|
||||||
|
|
||||||
await hass.config_entries.async_setup(entry.entry_id)
|
await hass.config_entries.async_setup(entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
utcnow = dt_util.utcnow() # Time after the integration is setup
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
hass.states.get(
|
hass.states.get(
|
||||||
@ -717,7 +717,7 @@ async def test_api_disabled(hass, mock_config_entry_data, mock_config_entry):
|
|||||||
|
|
||||||
await hass.config_entries.async_setup(entry.entry_id)
|
await hass.config_entries.async_setup(entry.entry_id)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
utcnow = dt_util.utcnow()
|
utcnow = dt_util.utcnow() # Time after the integration is setup
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
hass.states.get(
|
hass.states.get(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user