mirror of
https://github.com/home-assistant/core.git
synced 2025-07-24 21:57:51 +00:00
2025.7.3 (#149024)
This commit is contained in:
commit
456f992b7e
@ -8,5 +8,5 @@
|
|||||||
"iot_class": "cloud_polling",
|
"iot_class": "cloud_polling",
|
||||||
"loggers": ["aioamazondevices"],
|
"loggers": ["aioamazondevices"],
|
||||||
"quality_scale": "bronze",
|
"quality_scale": "bronze",
|
||||||
"requirements": ["aioamazondevices==3.2.10"]
|
"requirements": ["aioamazondevices==3.5.0"]
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
"documentation": "https://www.home-assistant.io/integrations/dlna_dmr",
|
"documentation": "https://www.home-assistant.io/integrations/dlna_dmr",
|
||||||
"iot_class": "local_push",
|
"iot_class": "local_push",
|
||||||
"loggers": ["async_upnp_client"],
|
"loggers": ["async_upnp_client"],
|
||||||
"requirements": ["async-upnp-client==0.44.0", "getmac==0.9.5"],
|
"requirements": ["async-upnp-client==0.45.0", "getmac==0.9.5"],
|
||||||
"ssdp": [
|
"ssdp": [
|
||||||
{
|
{
|
||||||
"deviceType": "urn:schemas-upnp-org:device:MediaRenderer:1",
|
"deviceType": "urn:schemas-upnp-org:device:MediaRenderer:1",
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"dependencies": ["ssdp"],
|
"dependencies": ["ssdp"],
|
||||||
"documentation": "https://www.home-assistant.io/integrations/dlna_dms",
|
"documentation": "https://www.home-assistant.io/integrations/dlna_dms",
|
||||||
"iot_class": "local_polling",
|
"iot_class": "local_polling",
|
||||||
"requirements": ["async-upnp-client==0.44.0"],
|
"requirements": ["async-upnp-client==0.45.0"],
|
||||||
"ssdp": [
|
"ssdp": [
|
||||||
{
|
{
|
||||||
"deviceType": "urn:schemas-upnp-org:device:MediaServer:1",
|
"deviceType": "urn:schemas-upnp-org:device:MediaServer:1",
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"iot_class": "local_polling",
|
"iot_class": "local_polling",
|
||||||
"loggers": ["pyenphase"],
|
"loggers": ["pyenphase"],
|
||||||
"quality_scale": "platinum",
|
"quality_scale": "platinum",
|
||||||
"requirements": ["pyenphase==2.2.1"],
|
"requirements": ["pyenphase==2.2.2"],
|
||||||
"zeroconf": [
|
"zeroconf": [
|
||||||
{
|
{
|
||||||
"type": "_enphase-envoy._tcp.local."
|
"type": "_enphase-envoy._tcp.local."
|
||||||
|
@ -20,5 +20,5 @@
|
|||||||
"documentation": "https://www.home-assistant.io/integrations/frontend",
|
"documentation": "https://www.home-assistant.io/integrations/frontend",
|
||||||
"integration_type": "system",
|
"integration_type": "system",
|
||||||
"quality_scale": "internal",
|
"quality_scale": "internal",
|
||||||
"requirements": ["home-assistant-frontend==20250702.2"]
|
"requirements": ["home-assistant-frontend==20250702.3"]
|
||||||
}
|
}
|
||||||
|
@ -7,5 +7,5 @@
|
|||||||
"integration_type": "service",
|
"integration_type": "service",
|
||||||
"iot_class": "cloud_polling",
|
"iot_class": "cloud_polling",
|
||||||
"loggers": ["dacite", "gios"],
|
"loggers": ["dacite", "gios"],
|
||||||
"requirements": ["gios==6.1.0"]
|
"requirements": ["gios==6.1.2"]
|
||||||
}
|
}
|
||||||
|
@ -306,6 +306,11 @@ class WebRTCProvider(CameraWebRTCProvider):
|
|||||||
await self.teardown()
|
await self.teardown()
|
||||||
raise HomeAssistantError("Camera has no stream source")
|
raise HomeAssistantError("Camera has no stream source")
|
||||||
|
|
||||||
|
if camera.platform.platform_name == "generic":
|
||||||
|
# This is a workaround to use ffmpeg for generic cameras
|
||||||
|
# A proper fix will be added in the future together with supporting multiple streams per camera
|
||||||
|
stream_source = "ffmpeg:" + stream_source
|
||||||
|
|
||||||
if not self.async_is_supported(stream_source):
|
if not self.async_is_supported(stream_source):
|
||||||
await self.teardown()
|
await self.teardown()
|
||||||
raise HomeAssistantError("Stream source is not supported by go2rtc")
|
raise HomeAssistantError("Stream source is not supported by go2rtc")
|
||||||
|
@ -113,9 +113,7 @@ class HomematicipHAP:
|
|||||||
|
|
||||||
self._ws_close_requested = False
|
self._ws_close_requested = False
|
||||||
self._ws_connection_closed = asyncio.Event()
|
self._ws_connection_closed = asyncio.Event()
|
||||||
self._retry_task: asyncio.Task | None = None
|
self._get_state_task: asyncio.Task | None = None
|
||||||
self._tries = 0
|
|
||||||
self._accesspoint_connected = True
|
|
||||||
self.hmip_device_by_entity_id: dict[str, Any] = {}
|
self.hmip_device_by_entity_id: dict[str, Any] = {}
|
||||||
self.reset_connection_listener: Callable | None = None
|
self.reset_connection_listener: Callable | None = None
|
||||||
|
|
||||||
@ -161,17 +159,8 @@ class HomematicipHAP:
|
|||||||
"""
|
"""
|
||||||
if not self.home.connected:
|
if not self.home.connected:
|
||||||
_LOGGER.error("HMIP access point has lost connection with the cloud")
|
_LOGGER.error("HMIP access point has lost connection with the cloud")
|
||||||
self._accesspoint_connected = False
|
self._ws_connection_closed.set()
|
||||||
self.set_all_to_unavailable()
|
self.set_all_to_unavailable()
|
||||||
elif not self._accesspoint_connected:
|
|
||||||
# Now the HOME_CHANGED event has fired indicating the access
|
|
||||||
# point has reconnected to the cloud again.
|
|
||||||
# Explicitly getting an update as entity states might have
|
|
||||||
# changed during access point disconnect."""
|
|
||||||
|
|
||||||
job = self.hass.async_create_task(self.get_state())
|
|
||||||
job.add_done_callback(self.get_state_finished)
|
|
||||||
self._accesspoint_connected = True
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_create_entity(self, *args, **kwargs) -> None:
|
def async_create_entity(self, *args, **kwargs) -> None:
|
||||||
@ -185,20 +174,43 @@ class HomematicipHAP:
|
|||||||
await asyncio.sleep(30)
|
await asyncio.sleep(30)
|
||||||
await self.hass.config_entries.async_reload(self.config_entry.entry_id)
|
await self.hass.config_entries.async_reload(self.config_entry.entry_id)
|
||||||
|
|
||||||
|
async def _try_get_state(self) -> None:
|
||||||
|
"""Call get_state in a loop until no error occurs, using exponential backoff on error."""
|
||||||
|
|
||||||
|
# Wait until WebSocket connection is established.
|
||||||
|
while not self.home.websocket_is_connected():
|
||||||
|
await asyncio.sleep(2)
|
||||||
|
|
||||||
|
delay = 8
|
||||||
|
max_delay = 1500
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
await self.get_state()
|
||||||
|
break
|
||||||
|
except HmipConnectionError as err:
|
||||||
|
_LOGGER.warning(
|
||||||
|
"Get_state failed, retrying in %s seconds: %s", delay, err
|
||||||
|
)
|
||||||
|
await asyncio.sleep(delay)
|
||||||
|
delay = min(delay * 2, max_delay)
|
||||||
|
|
||||||
async def get_state(self) -> None:
|
async def get_state(self) -> None:
|
||||||
"""Update HMIP state and tell Home Assistant."""
|
"""Update HMIP state and tell Home Assistant."""
|
||||||
await self.home.get_current_state_async()
|
await self.home.get_current_state_async()
|
||||||
self.update_all()
|
self.update_all()
|
||||||
|
|
||||||
def get_state_finished(self, future) -> None:
|
def get_state_finished(self, future) -> None:
|
||||||
"""Execute when get_state coroutine has finished."""
|
"""Execute when try_get_state coroutine has finished."""
|
||||||
try:
|
try:
|
||||||
future.result()
|
future.result()
|
||||||
except HmipConnectionError:
|
except Exception as err: # noqa: BLE001
|
||||||
# Somehow connection could not recover. Will disconnect and
|
_LOGGER.error(
|
||||||
# so reconnect loop is taking over.
|
"Error updating state after HMIP access point reconnect: %s", err
|
||||||
_LOGGER.error("Updating state after HMIP access point reconnect failed")
|
)
|
||||||
self.hass.async_create_task(self.home.disable_events())
|
else:
|
||||||
|
_LOGGER.info(
|
||||||
|
"Updating state after HMIP access point reconnect finished successfully",
|
||||||
|
)
|
||||||
|
|
||||||
def set_all_to_unavailable(self) -> None:
|
def set_all_to_unavailable(self) -> None:
|
||||||
"""Set all devices to unavailable and tell Home Assistant."""
|
"""Set all devices to unavailable and tell Home Assistant."""
|
||||||
@ -222,8 +234,8 @@ class HomematicipHAP:
|
|||||||
async def async_reset(self) -> bool:
|
async def async_reset(self) -> bool:
|
||||||
"""Close the websocket connection."""
|
"""Close the websocket connection."""
|
||||||
self._ws_close_requested = True
|
self._ws_close_requested = True
|
||||||
if self._retry_task is not None:
|
if self._get_state_task is not None:
|
||||||
self._retry_task.cancel()
|
self._get_state_task.cancel()
|
||||||
await self.home.disable_events_async()
|
await self.home.disable_events_async()
|
||||||
_LOGGER.debug("Closed connection to HomematicIP cloud server")
|
_LOGGER.debug("Closed connection to HomematicIP cloud server")
|
||||||
await self.hass.config_entries.async_unload_platforms(
|
await self.hass.config_entries.async_unload_platforms(
|
||||||
@ -247,7 +259,9 @@ class HomematicipHAP:
|
|||||||
"""Handle websocket connected."""
|
"""Handle websocket connected."""
|
||||||
_LOGGER.info("Websocket connection to HomematicIP Cloud established")
|
_LOGGER.info("Websocket connection to HomematicIP Cloud established")
|
||||||
if self._ws_connection_closed.is_set():
|
if self._ws_connection_closed.is_set():
|
||||||
await self.get_state()
|
self._get_state_task = self.hass.async_create_task(self._try_get_state())
|
||||||
|
self._get_state_task.add_done_callback(self.get_state_finished)
|
||||||
|
|
||||||
self._ws_connection_closed.clear()
|
self._ws_connection_closed.clear()
|
||||||
|
|
||||||
async def ws_disconnected_handler(self) -> None:
|
async def ws_disconnected_handler(self) -> None:
|
||||||
@ -256,11 +270,12 @@ class HomematicipHAP:
|
|||||||
self._ws_connection_closed.set()
|
self._ws_connection_closed.set()
|
||||||
|
|
||||||
async def ws_reconnected_handler(self, reason: str) -> None:
|
async def ws_reconnected_handler(self, reason: str) -> None:
|
||||||
"""Handle websocket reconnection."""
|
"""Handle websocket reconnection. Is called when Websocket tries to reconnect."""
|
||||||
_LOGGER.info(
|
_LOGGER.info(
|
||||||
"Websocket connection to HomematicIP Cloud re-established due to reason: %s",
|
"Websocket connection to HomematicIP Cloud trying to reconnect due to reason: %s",
|
||||||
reason,
|
reason,
|
||||||
)
|
)
|
||||||
|
|
||||||
self._ws_connection_closed.set()
|
self._ws_connection_closed.set()
|
||||||
|
|
||||||
async def get_hap(
|
async def get_hap(
|
||||||
|
@ -6,5 +6,5 @@
|
|||||||
"documentation": "https://www.home-assistant.io/integrations/homematicip_cloud",
|
"documentation": "https://www.home-assistant.io/integrations/homematicip_cloud",
|
||||||
"iot_class": "cloud_push",
|
"iot_class": "cloud_push",
|
||||||
"loggers": ["homematicip"],
|
"loggers": ["homematicip"],
|
||||||
"requirements": ["homematicip==2.0.6"]
|
"requirements": ["homematicip==2.0.7"]
|
||||||
}
|
}
|
||||||
|
@ -98,6 +98,12 @@ def validate_sensor_state_and_device_class_config(config: ConfigType) -> ConfigT
|
|||||||
f"together with state class `{state_class}`"
|
f"together with state class `{state_class}`"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
unit_of_measurement: str | None
|
||||||
|
if (
|
||||||
|
unit_of_measurement := config.get(CONF_UNIT_OF_MEASUREMENT)
|
||||||
|
) is not None and not unit_of_measurement.strip():
|
||||||
|
config.pop(CONF_UNIT_OF_MEASUREMENT)
|
||||||
|
|
||||||
# Only allow `options` to be set for `enum` sensors
|
# Only allow `options` to be set for `enum` sensors
|
||||||
# to limit the possible sensor values
|
# to limit the possible sensor values
|
||||||
if (options := config.get(CONF_OPTIONS)) is not None:
|
if (options := config.get(CONF_OPTIONS)) is not None:
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
"samsungctl[websocket]==0.7.1",
|
"samsungctl[websocket]==0.7.1",
|
||||||
"samsungtvws[async,encrypted]==2.7.2",
|
"samsungtvws[async,encrypted]==2.7.2",
|
||||||
"wakeonlan==3.1.0",
|
"wakeonlan==3.1.0",
|
||||||
"async-upnp-client==0.44.0"
|
"async-upnp-client==0.45.0"
|
||||||
],
|
],
|
||||||
"ssdp": [
|
"ssdp": [
|
||||||
{
|
{
|
||||||
|
@ -868,8 +868,8 @@ RPC_SENSORS: Final = {
|
|||||||
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
|
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
|
||||||
device_class=SensorDeviceClass.CURRENT,
|
device_class=SensorDeviceClass.CURRENT,
|
||||||
state_class=SensorStateClass.MEASUREMENT,
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
available=lambda status: (status and status["n_current"]) is not None,
|
removal_condition=lambda _config, status, key: status[key].get("n_current")
|
||||||
removal_condition=lambda _config, status, _key: "n_current" not in status,
|
is None,
|
||||||
entity_registry_enabled_default=False,
|
entity_registry_enabled_default=False,
|
||||||
),
|
),
|
||||||
"total_current": RpcSensorDescription(
|
"total_current": RpcSensorDescription(
|
||||||
|
@ -30,5 +30,5 @@
|
|||||||
"iot_class": "cloud_push",
|
"iot_class": "cloud_push",
|
||||||
"loggers": ["pysmartthings"],
|
"loggers": ["pysmartthings"],
|
||||||
"quality_scale": "bronze",
|
"quality_scale": "bronze",
|
||||||
"requirements": ["pysmartthings==3.2.7"]
|
"requirements": ["pysmartthings==3.2.8"]
|
||||||
}
|
}
|
||||||
|
@ -72,7 +72,7 @@ class SonosFavorites(SonosHouseholdCoordinator):
|
|||||||
"""Process the event payload in an async lock and update entities."""
|
"""Process the event payload in an async lock and update entities."""
|
||||||
event_id = event.variables["favorites_update_id"]
|
event_id = event.variables["favorites_update_id"]
|
||||||
container_ids = event.variables["container_update_i_ds"]
|
container_ids = event.variables["container_update_i_ds"]
|
||||||
if not (match := re.search(r"FV:2,(\d+)", container_ids)):
|
if not container_ids or not (match := re.search(r"FV:2,(\d+)", container_ids)):
|
||||||
return
|
return
|
||||||
|
|
||||||
container_id = int(match.groups()[0])
|
container_id = int(match.groups()[0])
|
||||||
|
@ -8,5 +8,5 @@
|
|||||||
"iot_class": "local_push",
|
"iot_class": "local_push",
|
||||||
"loggers": ["async_upnp_client"],
|
"loggers": ["async_upnp_client"],
|
||||||
"quality_scale": "internal",
|
"quality_scale": "internal",
|
||||||
"requirements": ["async-upnp-client==0.44.0"]
|
"requirements": ["async-upnp-client==0.45.0"]
|
||||||
}
|
}
|
||||||
|
@ -41,5 +41,5 @@
|
|||||||
"iot_class": "local_push",
|
"iot_class": "local_push",
|
||||||
"loggers": ["switchbot"],
|
"loggers": ["switchbot"],
|
||||||
"quality_scale": "gold",
|
"quality_scale": "gold",
|
||||||
"requirements": ["PySwitchbot==0.68.1"]
|
"requirements": ["PySwitchbot==0.68.2"]
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ class SyncthruCoordinator(DataUpdateCoordinator[SyncThru]):
|
|||||||
hass,
|
hass,
|
||||||
_LOGGER,
|
_LOGGER,
|
||||||
name=DOMAIN,
|
name=DOMAIN,
|
||||||
|
config_entry=entry,
|
||||||
update_interval=timedelta(seconds=30),
|
update_interval=timedelta(seconds=30),
|
||||||
)
|
)
|
||||||
self.syncthru = SyncThru(
|
self.syncthru = SyncThru(
|
||||||
|
@ -7,5 +7,5 @@
|
|||||||
"documentation": "https://www.home-assistant.io/integrations/tesla_fleet",
|
"documentation": "https://www.home-assistant.io/integrations/tesla_fleet",
|
||||||
"iot_class": "cloud_polling",
|
"iot_class": "cloud_polling",
|
||||||
"loggers": ["tesla-fleet-api"],
|
"loggers": ["tesla-fleet-api"],
|
||||||
"requirements": ["tesla-fleet-api==1.2.0"]
|
"requirements": ["tesla-fleet-api==1.2.2"]
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@ from homeassistant.core import HomeAssistant
|
|||||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||||
|
|
||||||
from . import TeslemetryConfigEntry
|
from . import TeslemetryConfigEntry
|
||||||
from .entity import TeslemetryVehiclePollingEntity
|
from .entity import TeslemetryVehicleStreamEntity
|
||||||
from .helpers import handle_command, handle_vehicle_command
|
from .helpers import handle_command, handle_vehicle_command
|
||||||
from .models import TeslemetryVehicleData
|
from .models import TeslemetryVehicleData
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ async def async_setup_entry(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class TeslemetryButtonEntity(TeslemetryVehiclePollingEntity, ButtonEntity):
|
class TeslemetryButtonEntity(TeslemetryVehicleStreamEntity, ButtonEntity):
|
||||||
"""Base class for Teslemetry buttons."""
|
"""Base class for Teslemetry buttons."""
|
||||||
|
|
||||||
api: Vehicle
|
api: Vehicle
|
||||||
|
@ -6,5 +6,5 @@
|
|||||||
"documentation": "https://www.home-assistant.io/integrations/teslemetry",
|
"documentation": "https://www.home-assistant.io/integrations/teslemetry",
|
||||||
"iot_class": "cloud_polling",
|
"iot_class": "cloud_polling",
|
||||||
"loggers": ["tesla-fleet-api"],
|
"loggers": ["tesla-fleet-api"],
|
||||||
"requirements": ["tesla-fleet-api==1.2.0", "teslemetry-stream==0.7.9"]
|
"requirements": ["tesla-fleet-api==1.2.2", "teslemetry-stream==0.7.9"]
|
||||||
}
|
}
|
||||||
|
@ -6,5 +6,5 @@
|
|||||||
"documentation": "https://www.home-assistant.io/integrations/tessie",
|
"documentation": "https://www.home-assistant.io/integrations/tessie",
|
||||||
"iot_class": "cloud_polling",
|
"iot_class": "cloud_polling",
|
||||||
"loggers": ["tessie", "tesla-fleet-api"],
|
"loggers": ["tessie", "tesla-fleet-api"],
|
||||||
"requirements": ["tessie-api==0.1.1", "tesla-fleet-api==1.2.0"]
|
"requirements": ["tessie-api==0.1.1", "tesla-fleet-api==1.2.2"]
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
"integration_type": "device",
|
"integration_type": "device",
|
||||||
"iot_class": "local_polling",
|
"iot_class": "local_polling",
|
||||||
"loggers": ["async_upnp_client"],
|
"loggers": ["async_upnp_client"],
|
||||||
"requirements": ["async-upnp-client==0.44.0", "getmac==0.9.5"],
|
"requirements": ["async-upnp-client==0.45.0", "getmac==0.9.5"],
|
||||||
"ssdp": [
|
"ssdp": [
|
||||||
{
|
{
|
||||||
"st": "urn:schemas-upnp-org:device:InternetGatewayDevice:1"
|
"st": "urn:schemas-upnp-org:device:InternetGatewayDevice:1"
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
},
|
},
|
||||||
"iot_class": "local_push",
|
"iot_class": "local_push",
|
||||||
"loggers": ["async_upnp_client", "yeelight"],
|
"loggers": ["async_upnp_client", "yeelight"],
|
||||||
"requirements": ["yeelight==0.7.16", "async-upnp-client==0.44.0"],
|
"requirements": ["yeelight==0.7.16", "async-upnp-client==0.45.0"],
|
||||||
"zeroconf": [
|
"zeroconf": [
|
||||||
{
|
{
|
||||||
"type": "_miio._udp.local.",
|
"type": "_miio._udp.local.",
|
||||||
|
@ -25,7 +25,7 @@ if TYPE_CHECKING:
|
|||||||
APPLICATION_NAME: Final = "HomeAssistant"
|
APPLICATION_NAME: Final = "HomeAssistant"
|
||||||
MAJOR_VERSION: Final = 2025
|
MAJOR_VERSION: Final = 2025
|
||||||
MINOR_VERSION: Final = 7
|
MINOR_VERSION: Final = 7
|
||||||
PATCH_VERSION: Final = "2"
|
PATCH_VERSION: Final = "3"
|
||||||
__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, 13, 2)
|
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 13, 2)
|
||||||
|
@ -13,7 +13,7 @@ aiozoneinfo==0.2.3
|
|||||||
annotatedyaml==0.4.5
|
annotatedyaml==0.4.5
|
||||||
astral==2.2
|
astral==2.2
|
||||||
async-interrupt==1.2.2
|
async-interrupt==1.2.2
|
||||||
async-upnp-client==0.44.0
|
async-upnp-client==0.45.0
|
||||||
atomicwrites-homeassistant==1.4.1
|
atomicwrites-homeassistant==1.4.1
|
||||||
attrs==25.3.0
|
attrs==25.3.0
|
||||||
audioop-lts==0.2.1
|
audioop-lts==0.2.1
|
||||||
@ -38,7 +38,7 @@ habluetooth==3.49.0
|
|||||||
hass-nabucasa==0.106.0
|
hass-nabucasa==0.106.0
|
||||||
hassil==2.2.3
|
hassil==2.2.3
|
||||||
home-assistant-bluetooth==1.13.1
|
home-assistant-bluetooth==1.13.1
|
||||||
home-assistant-frontend==20250702.2
|
home-assistant-frontend==20250702.3
|
||||||
home-assistant-intents==2025.6.23
|
home-assistant-intents==2025.6.23
|
||||||
httpx==0.28.1
|
httpx==0.28.1
|
||||||
ifaddr==0.2.0
|
ifaddr==0.2.0
|
||||||
|
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "homeassistant"
|
name = "homeassistant"
|
||||||
version = "2025.7.2"
|
version = "2025.7.3"
|
||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
license-files = ["LICENSE*", "homeassistant/backports/LICENSE*"]
|
license-files = ["LICENSE*", "homeassistant/backports/LICENSE*"]
|
||||||
description = "Open-source home automation platform running on Python 3."
|
description = "Open-source home automation platform running on Python 3."
|
||||||
|
18
requirements_all.txt
generated
18
requirements_all.txt
generated
@ -84,7 +84,7 @@ PyQRCode==1.2.1
|
|||||||
PyRMVtransport==0.3.3
|
PyRMVtransport==0.3.3
|
||||||
|
|
||||||
# homeassistant.components.switchbot
|
# homeassistant.components.switchbot
|
||||||
PySwitchbot==0.68.1
|
PySwitchbot==0.68.2
|
||||||
|
|
||||||
# homeassistant.components.switchmate
|
# homeassistant.components.switchmate
|
||||||
PySwitchmate==0.5.1
|
PySwitchmate==0.5.1
|
||||||
@ -185,7 +185,7 @@ aioairzone-cloud==0.6.12
|
|||||||
aioairzone==1.0.0
|
aioairzone==1.0.0
|
||||||
|
|
||||||
# homeassistant.components.alexa_devices
|
# homeassistant.components.alexa_devices
|
||||||
aioamazondevices==3.2.10
|
aioamazondevices==3.5.0
|
||||||
|
|
||||||
# homeassistant.components.ambient_network
|
# homeassistant.components.ambient_network
|
||||||
# homeassistant.components.ambient_station
|
# homeassistant.components.ambient_station
|
||||||
@ -527,7 +527,7 @@ asmog==0.0.6
|
|||||||
# homeassistant.components.ssdp
|
# homeassistant.components.ssdp
|
||||||
# homeassistant.components.upnp
|
# homeassistant.components.upnp
|
||||||
# homeassistant.components.yeelight
|
# homeassistant.components.yeelight
|
||||||
async-upnp-client==0.44.0
|
async-upnp-client==0.45.0
|
||||||
|
|
||||||
# homeassistant.components.arve
|
# homeassistant.components.arve
|
||||||
asyncarve==0.1.1
|
asyncarve==0.1.1
|
||||||
@ -1020,7 +1020,7 @@ georss-qld-bushfire-alert-client==0.8
|
|||||||
getmac==0.9.5
|
getmac==0.9.5
|
||||||
|
|
||||||
# homeassistant.components.gios
|
# homeassistant.components.gios
|
||||||
gios==6.1.0
|
gios==6.1.2
|
||||||
|
|
||||||
# homeassistant.components.gitter
|
# homeassistant.components.gitter
|
||||||
gitterpy==0.1.7
|
gitterpy==0.1.7
|
||||||
@ -1168,13 +1168,13 @@ hole==0.8.0
|
|||||||
holidays==0.75
|
holidays==0.75
|
||||||
|
|
||||||
# homeassistant.components.frontend
|
# homeassistant.components.frontend
|
||||||
home-assistant-frontend==20250702.2
|
home-assistant-frontend==20250702.3
|
||||||
|
|
||||||
# homeassistant.components.conversation
|
# homeassistant.components.conversation
|
||||||
home-assistant-intents==2025.6.23
|
home-assistant-intents==2025.6.23
|
||||||
|
|
||||||
# homeassistant.components.homematicip_cloud
|
# homeassistant.components.homematicip_cloud
|
||||||
homematicip==2.0.6
|
homematicip==2.0.7
|
||||||
|
|
||||||
# homeassistant.components.horizon
|
# homeassistant.components.horizon
|
||||||
horimote==0.4.1
|
horimote==0.4.1
|
||||||
@ -1962,7 +1962,7 @@ pyeiscp==0.0.7
|
|||||||
pyemoncms==0.1.1
|
pyemoncms==0.1.1
|
||||||
|
|
||||||
# homeassistant.components.enphase_envoy
|
# homeassistant.components.enphase_envoy
|
||||||
pyenphase==2.2.1
|
pyenphase==2.2.2
|
||||||
|
|
||||||
# homeassistant.components.envisalink
|
# homeassistant.components.envisalink
|
||||||
pyenvisalink==4.7
|
pyenvisalink==4.7
|
||||||
@ -2348,7 +2348,7 @@ pysmappee==0.2.29
|
|||||||
pysmarlaapi==0.9.0
|
pysmarlaapi==0.9.0
|
||||||
|
|
||||||
# homeassistant.components.smartthings
|
# homeassistant.components.smartthings
|
||||||
pysmartthings==3.2.7
|
pysmartthings==3.2.8
|
||||||
|
|
||||||
# homeassistant.components.smarty
|
# homeassistant.components.smarty
|
||||||
pysmarty2==0.10.2
|
pysmarty2==0.10.2
|
||||||
@ -2904,7 +2904,7 @@ temperusb==1.6.1
|
|||||||
# homeassistant.components.tesla_fleet
|
# homeassistant.components.tesla_fleet
|
||||||
# homeassistant.components.teslemetry
|
# homeassistant.components.teslemetry
|
||||||
# homeassistant.components.tessie
|
# homeassistant.components.tessie
|
||||||
tesla-fleet-api==1.2.0
|
tesla-fleet-api==1.2.2
|
||||||
|
|
||||||
# homeassistant.components.powerwall
|
# homeassistant.components.powerwall
|
||||||
tesla-powerwall==0.5.2
|
tesla-powerwall==0.5.2
|
||||||
|
18
requirements_test_all.txt
generated
18
requirements_test_all.txt
generated
@ -81,7 +81,7 @@ PyQRCode==1.2.1
|
|||||||
PyRMVtransport==0.3.3
|
PyRMVtransport==0.3.3
|
||||||
|
|
||||||
# homeassistant.components.switchbot
|
# homeassistant.components.switchbot
|
||||||
PySwitchbot==0.68.1
|
PySwitchbot==0.68.2
|
||||||
|
|
||||||
# homeassistant.components.syncthru
|
# homeassistant.components.syncthru
|
||||||
PySyncThru==0.8.0
|
PySyncThru==0.8.0
|
||||||
@ -173,7 +173,7 @@ aioairzone-cloud==0.6.12
|
|||||||
aioairzone==1.0.0
|
aioairzone==1.0.0
|
||||||
|
|
||||||
# homeassistant.components.alexa_devices
|
# homeassistant.components.alexa_devices
|
||||||
aioamazondevices==3.2.10
|
aioamazondevices==3.5.0
|
||||||
|
|
||||||
# homeassistant.components.ambient_network
|
# homeassistant.components.ambient_network
|
||||||
# homeassistant.components.ambient_station
|
# homeassistant.components.ambient_station
|
||||||
@ -491,7 +491,7 @@ arcam-fmj==1.8.1
|
|||||||
# homeassistant.components.ssdp
|
# homeassistant.components.ssdp
|
||||||
# homeassistant.components.upnp
|
# homeassistant.components.upnp
|
||||||
# homeassistant.components.yeelight
|
# homeassistant.components.yeelight
|
||||||
async-upnp-client==0.44.0
|
async-upnp-client==0.45.0
|
||||||
|
|
||||||
# homeassistant.components.arve
|
# homeassistant.components.arve
|
||||||
asyncarve==0.1.1
|
asyncarve==0.1.1
|
||||||
@ -890,7 +890,7 @@ georss-qld-bushfire-alert-client==0.8
|
|||||||
getmac==0.9.5
|
getmac==0.9.5
|
||||||
|
|
||||||
# homeassistant.components.gios
|
# homeassistant.components.gios
|
||||||
gios==6.1.0
|
gios==6.1.2
|
||||||
|
|
||||||
# homeassistant.components.glances
|
# homeassistant.components.glances
|
||||||
glances-api==0.8.0
|
glances-api==0.8.0
|
||||||
@ -1017,13 +1017,13 @@ hole==0.8.0
|
|||||||
holidays==0.75
|
holidays==0.75
|
||||||
|
|
||||||
# homeassistant.components.frontend
|
# homeassistant.components.frontend
|
||||||
home-assistant-frontend==20250702.2
|
home-assistant-frontend==20250702.3
|
||||||
|
|
||||||
# homeassistant.components.conversation
|
# homeassistant.components.conversation
|
||||||
home-assistant-intents==2025.6.23
|
home-assistant-intents==2025.6.23
|
||||||
|
|
||||||
# homeassistant.components.homematicip_cloud
|
# homeassistant.components.homematicip_cloud
|
||||||
homematicip==2.0.6
|
homematicip==2.0.7
|
||||||
|
|
||||||
# homeassistant.components.remember_the_milk
|
# homeassistant.components.remember_the_milk
|
||||||
httplib2==0.20.4
|
httplib2==0.20.4
|
||||||
@ -1637,7 +1637,7 @@ pyeiscp==0.0.7
|
|||||||
pyemoncms==0.1.1
|
pyemoncms==0.1.1
|
||||||
|
|
||||||
# homeassistant.components.enphase_envoy
|
# homeassistant.components.enphase_envoy
|
||||||
pyenphase==2.2.1
|
pyenphase==2.2.2
|
||||||
|
|
||||||
# homeassistant.components.everlights
|
# homeassistant.components.everlights
|
||||||
pyeverlights==0.1.0
|
pyeverlights==0.1.0
|
||||||
@ -1951,7 +1951,7 @@ pysmappee==0.2.29
|
|||||||
pysmarlaapi==0.9.0
|
pysmarlaapi==0.9.0
|
||||||
|
|
||||||
# homeassistant.components.smartthings
|
# homeassistant.components.smartthings
|
||||||
pysmartthings==3.2.7
|
pysmartthings==3.2.8
|
||||||
|
|
||||||
# homeassistant.components.smarty
|
# homeassistant.components.smarty
|
||||||
pysmarty2==0.10.2
|
pysmarty2==0.10.2
|
||||||
@ -2390,7 +2390,7 @@ temperusb==1.6.1
|
|||||||
# homeassistant.components.tesla_fleet
|
# homeassistant.components.tesla_fleet
|
||||||
# homeassistant.components.teslemetry
|
# homeassistant.components.teslemetry
|
||||||
# homeassistant.components.tessie
|
# homeassistant.components.tessie
|
||||||
tesla-fleet-api==1.2.0
|
tesla-fleet-api==1.2.2
|
||||||
|
|
||||||
# homeassistant.components.powerwall
|
# homeassistant.components.powerwall
|
||||||
tesla-powerwall==0.5.2
|
tesla-powerwall==0.5.2
|
||||||
|
@ -670,3 +670,32 @@ async def test_async_get_image(
|
|||||||
HomeAssistantError, match="Stream source is not supported by go2rtc"
|
HomeAssistantError, match="Stream source is not supported by go2rtc"
|
||||||
):
|
):
|
||||||
await async_get_image(hass, camera.entity_id)
|
await async_get_image(hass, camera.entity_id)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.usefixtures("init_integration")
|
||||||
|
async def test_generic_workaround(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
init_test_integration: MockCamera,
|
||||||
|
rest_client: AsyncMock,
|
||||||
|
) -> None:
|
||||||
|
"""Test workaround for generic integration cameras."""
|
||||||
|
camera = init_test_integration
|
||||||
|
assert isinstance(camera._webrtc_provider, WebRTCProvider)
|
||||||
|
|
||||||
|
image_bytes = load_fixture_bytes("snapshot.jpg", DOMAIN)
|
||||||
|
|
||||||
|
rest_client.get_jpeg_snapshot.return_value = image_bytes
|
||||||
|
camera.set_stream_source("https://my_stream_url.m3u8")
|
||||||
|
|
||||||
|
with patch.object(camera.platform, "platform_name", "generic"):
|
||||||
|
image = await async_get_image(hass, camera.entity_id)
|
||||||
|
assert image.content == image_bytes
|
||||||
|
|
||||||
|
rest_client.streams.add.assert_called_once_with(
|
||||||
|
camera.entity_id,
|
||||||
|
[
|
||||||
|
"ffmpeg:https://my_stream_url.m3u8",
|
||||||
|
f"ffmpeg:{camera.entity_id}#audio=opus#query=log_level=debug",
|
||||||
|
f"ffmpeg:{camera.entity_id}#video=mjpeg",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
@ -195,9 +195,14 @@ async def test_hap_reconnected(
|
|||||||
ha_state = hass.states.get(entity_id)
|
ha_state = hass.states.get(entity_id)
|
||||||
assert ha_state.state == STATE_UNAVAILABLE
|
assert ha_state.state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
mock_hap._accesspoint_connected = False
|
with patch(
|
||||||
await async_manipulate_test_data(hass, mock_hap.home, "connected", True)
|
"homeassistant.components.homematicip_cloud.hap.AsyncHome.websocket_is_connected",
|
||||||
await hass.async_block_till_done()
|
return_value=True,
|
||||||
|
):
|
||||||
|
await async_manipulate_test_data(hass, mock_hap.home, "connected", True)
|
||||||
|
await mock_hap.ws_connected_handler()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
ha_state = hass.states.get(entity_id)
|
ha_state = hass.states.get(entity_id)
|
||||||
assert ha_state.state == STATE_ON
|
assert ha_state.state == STATE_ON
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"""Test HomematicIP Cloud accesspoint."""
|
"""Test HomematicIP Cloud accesspoint."""
|
||||||
|
|
||||||
from unittest.mock import AsyncMock, Mock, patch
|
from unittest.mock import AsyncMock, MagicMock, Mock, patch
|
||||||
|
|
||||||
from homematicip.auth import Auth
|
from homematicip.auth import Auth
|
||||||
from homematicip.connection.connection_context import ConnectionContext
|
from homematicip.connection.connection_context import ConnectionContext
|
||||||
@ -242,7 +242,14 @@ async def test_get_state_after_disconnect(
|
|||||||
hap = HomematicipHAP(hass, hmip_config_entry)
|
hap = HomematicipHAP(hass, hmip_config_entry)
|
||||||
assert hap
|
assert hap
|
||||||
|
|
||||||
with patch.object(hap, "get_state") as mock_get_state:
|
simple_mock_home = AsyncMock(spec=AsyncHome, autospec=True)
|
||||||
|
hap.home = simple_mock_home
|
||||||
|
hap.home.websocket_is_connected = Mock(side_effect=[False, True])
|
||||||
|
|
||||||
|
with (
|
||||||
|
patch("asyncio.sleep", new=AsyncMock()) as mock_sleep,
|
||||||
|
patch.object(hap, "get_state") as mock_get_state,
|
||||||
|
):
|
||||||
assert not hap._ws_connection_closed.is_set()
|
assert not hap._ws_connection_closed.is_set()
|
||||||
|
|
||||||
await hap.ws_connected_handler()
|
await hap.ws_connected_handler()
|
||||||
@ -250,8 +257,54 @@ async def test_get_state_after_disconnect(
|
|||||||
|
|
||||||
await hap.ws_disconnected_handler()
|
await hap.ws_disconnected_handler()
|
||||||
assert hap._ws_connection_closed.is_set()
|
assert hap._ws_connection_closed.is_set()
|
||||||
await hap.ws_connected_handler()
|
with patch(
|
||||||
mock_get_state.assert_called_once()
|
"homeassistant.components.homematicip_cloud.hap.AsyncHome.websocket_is_connected",
|
||||||
|
return_value=True,
|
||||||
|
):
|
||||||
|
await hap.ws_connected_handler()
|
||||||
|
mock_get_state.assert_called_once()
|
||||||
|
|
||||||
|
assert not hap._ws_connection_closed.is_set()
|
||||||
|
hap.home.websocket_is_connected.assert_called()
|
||||||
|
mock_sleep.assert_awaited_with(2)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_try_get_state_exponential_backoff() -> None:
|
||||||
|
"""Test _try_get_state waits for websocket connection."""
|
||||||
|
|
||||||
|
# Arrange: Create instance and mock home
|
||||||
|
hap = HomematicipHAP(MagicMock(), MagicMock())
|
||||||
|
hap.home = MagicMock()
|
||||||
|
hap.home.websocket_is_connected = Mock(return_value=True)
|
||||||
|
|
||||||
|
hap.get_state = AsyncMock(
|
||||||
|
side_effect=[HmipConnectionError, HmipConnectionError, True]
|
||||||
|
)
|
||||||
|
|
||||||
|
with patch("asyncio.sleep", new=AsyncMock()) as mock_sleep:
|
||||||
|
await hap._try_get_state()
|
||||||
|
|
||||||
|
assert mock_sleep.mock_calls[0].args[0] == 8
|
||||||
|
assert mock_sleep.mock_calls[1].args[0] == 16
|
||||||
|
assert hap.get_state.call_count == 3
|
||||||
|
|
||||||
|
|
||||||
|
async def test_try_get_state_handle_exception() -> None:
|
||||||
|
"""Test _try_get_state handles exceptions."""
|
||||||
|
# Arrange: Create instance and mock home
|
||||||
|
hap = HomematicipHAP(MagicMock(), MagicMock())
|
||||||
|
hap.home = MagicMock()
|
||||||
|
|
||||||
|
expected_exception = Exception("Connection error")
|
||||||
|
future = AsyncMock()
|
||||||
|
future.result = Mock(side_effect=expected_exception)
|
||||||
|
|
||||||
|
with patch("homeassistant.components.homematicip_cloud.hap._LOGGER") as mock_logger:
|
||||||
|
hap.get_state_finished(future)
|
||||||
|
|
||||||
|
mock_logger.error.assert_called_once_with(
|
||||||
|
"Error updating state after HMIP access point reconnect: %s", expected_exception
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_async_connect(
|
async def test_async_connect(
|
||||||
|
@ -924,6 +924,30 @@ async def test_invalid_unit_of_measurement(
|
|||||||
"device_class": None,
|
"device_class": None,
|
||||||
"unit_of_measurement": None,
|
"unit_of_measurement": None,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Test 4",
|
||||||
|
"state_topic": "test-topic",
|
||||||
|
"device_class": "ph",
|
||||||
|
"unit_of_measurement": "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Test 5",
|
||||||
|
"state_topic": "test-topic",
|
||||||
|
"device_class": "ph",
|
||||||
|
"unit_of_measurement": " ",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Test 6",
|
||||||
|
"state_topic": "test-topic",
|
||||||
|
"device_class": None,
|
||||||
|
"unit_of_measurement": "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Test 7",
|
||||||
|
"state_topic": "test-topic",
|
||||||
|
"device_class": None,
|
||||||
|
"unit_of_measurement": " ",
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -936,10 +960,25 @@ async def test_valid_device_class_and_uom(
|
|||||||
await mqtt_mock_entry()
|
await mqtt_mock_entry()
|
||||||
|
|
||||||
state = hass.states.get("sensor.test_1")
|
state = hass.states.get("sensor.test_1")
|
||||||
|
assert state is not None
|
||||||
assert state.attributes["device_class"] == "temperature"
|
assert state.attributes["device_class"] == "temperature"
|
||||||
state = hass.states.get("sensor.test_2")
|
state = hass.states.get("sensor.test_2")
|
||||||
|
assert state is not None
|
||||||
assert "device_class" not in state.attributes
|
assert "device_class" not in state.attributes
|
||||||
state = hass.states.get("sensor.test_3")
|
state = hass.states.get("sensor.test_3")
|
||||||
|
assert state is not None
|
||||||
|
assert "device_class" not in state.attributes
|
||||||
|
state = hass.states.get("sensor.test_4")
|
||||||
|
assert state is not None
|
||||||
|
assert state.attributes["device_class"] == "ph"
|
||||||
|
state = hass.states.get("sensor.test_5")
|
||||||
|
assert state is not None
|
||||||
|
assert state.attributes["device_class"] == "ph"
|
||||||
|
state = hass.states.get("sensor.test_6")
|
||||||
|
assert state is not None
|
||||||
|
assert "device_class" not in state.attributes
|
||||||
|
state = hass.states.get("sensor.test_7")
|
||||||
|
assert state is not None
|
||||||
assert "device_class" not in state.attributes
|
assert "device_class" not in state.attributes
|
||||||
|
|
||||||
|
|
||||||
|
@ -151,7 +151,7 @@
|
|||||||
"c_pf": 0.72,
|
"c_pf": 0.72,
|
||||||
"c_voltage": 230.2,
|
"c_voltage": 230.2,
|
||||||
"id": 0,
|
"id": 0,
|
||||||
"n_current": null,
|
"n_current": 3.124,
|
||||||
"total_act_power": 2413.825,
|
"total_act_power": 2413.825,
|
||||||
"total_aprt_power": 2525.779,
|
"total_aprt_power": 2525.779,
|
||||||
"total_current": 11.116,
|
"total_current": 11.116,
|
||||||
|
@ -4303,6 +4303,62 @@
|
|||||||
'state': '230.2',
|
'state': '230.2',
|
||||||
})
|
})
|
||||||
# ---
|
# ---
|
||||||
|
# name: test_shelly_pro_3em[sensor.test_name_phase_n_current-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': dict({
|
||||||
|
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||||
|
}),
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'config_subentry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'sensor',
|
||||||
|
'entity_category': None,
|
||||||
|
'entity_id': 'sensor.test_name_phase_n_current',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
'sensor': dict({
|
||||||
|
'suggested_display_precision': 2,
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
'original_device_class': <SensorDeviceClass.CURRENT: 'current'>,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': 'Phase N current',
|
||||||
|
'platform': 'shelly',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'suggested_object_id': None,
|
||||||
|
'supported_features': 0,
|
||||||
|
'translation_key': None,
|
||||||
|
'unique_id': '123456789ABC-em:0-n_current',
|
||||||
|
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_shelly_pro_3em[sensor.test_name_phase_n_current-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'device_class': 'current',
|
||||||
|
'friendly_name': 'Test name Phase N current',
|
||||||
|
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||||
|
'unit_of_measurement': <UnitOfElectricCurrent.AMPERE: 'A'>,
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'sensor.test_name_phase_n_current',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': '3.124',
|
||||||
|
})
|
||||||
|
# ---
|
||||||
# name: test_shelly_pro_3em[sensor.test_name_rssi-entry]
|
# name: test_shelly_pro_3em[sensor.test_name_rssi-entry]
|
||||||
EntityRegistryEntrySnapshot({
|
EntityRegistryEntrySnapshot({
|
||||||
'aliases': set({
|
'aliases': set({
|
||||||
|
Loading…
x
Reference in New Issue
Block a user