This commit is contained in:
Franck Nijhof 2025-04-25 09:47:05 +02:00 committed by GitHub
commit 360bffa3a9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 315 additions and 96 deletions

View File

@ -6,5 +6,5 @@
"documentation": "https://www.home-assistant.io/integrations/chacon_dio",
"iot_class": "cloud_push",
"loggers": ["dio_chacon_api"],
"requirements": ["dio-chacon-wifi-api==1.2.1"]
"requirements": ["dio-chacon-wifi-api==1.2.2"]
}

View File

@ -241,9 +241,7 @@ class HomeConnectCoordinator(
appliance_data = await self._get_appliance_data(
appliance_info, self.data.get(appliance_info.ha_id)
)
if event_message_ha_id in self.data:
self.data[event_message_ha_id].update(appliance_data)
else:
if event_message_ha_id not in self.data:
self.data[event_message_ha_id] = appliance_data
for listener, context in self._special_listeners.values():
if (

View File

@ -17,7 +17,6 @@ from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from .common import setup_home_connect_entry
from .const import (
APPLIANCES_WITH_PROGRAMS,
AVAILABLE_MAPS_ENUM,
BEAN_AMOUNT_OPTIONS,
BEAN_CONTAINER_OPTIONS,
@ -313,7 +312,7 @@ def _get_entities_for_appliance(
HomeConnectProgramSelectEntity(entry.runtime_data, appliance, desc)
for desc in PROGRAM_SELECT_ENTITY_DESCRIPTIONS
]
if appliance.info.type in APPLIANCES_WITH_PROGRAMS
if appliance.programs
else []
),
*[

View File

@ -14,6 +14,6 @@
"documentation": "https://www.home-assistant.io/integrations/homekit_controller",
"iot_class": "local_push",
"loggers": ["aiohomekit", "commentjson"],
"requirements": ["aiohomekit==3.2.13"],
"requirements": ["aiohomekit==3.2.14"],
"zeroconf": ["_hap._tcp.local.", "_hap._udp.local."]
}

View File

@ -2,6 +2,7 @@
from __future__ import annotations
from datetime import timedelta
import logging
from typing import Any
@ -120,6 +121,8 @@ SERVICE_PLAY_PRESET_SCHEMA = cv.make_entity_service_schema(
)
RETRY_POLL_MAXIMUM = 3
SCAN_INTERVAL = timedelta(seconds=5)
PARALLEL_UPDATES = 1
async def async_setup_entry(

View File

@ -40,7 +40,7 @@ ATTR_NEXT_RAIN_DT_REF = "forecast_time_ref"
CONDITION_CLASSES: dict[str, list[str]] = {
ATTR_CONDITION_CLEAR_NIGHT: ["Nuit Claire", "Nuit claire"],
ATTR_CONDITION_CLEAR_NIGHT: ["Nuit Claire", "Nuit claire", "Ciel clair"],
ATTR_CONDITION_CLOUDY: ["Très nuageux", "Couvert"],
ATTR_CONDITION_FOG: [
"Brume ou bancs de brouillard",
@ -48,9 +48,10 @@ CONDITION_CLASSES: dict[str, list[str]] = {
"Brouillard",
"Brouillard givrant",
"Bancs de Brouillard",
"Brouillard dense",
],
ATTR_CONDITION_HAIL: ["Risque de grêle", "Risque de grèle"],
ATTR_CONDITION_LIGHTNING: ["Risque d'orages", "Orages"],
ATTR_CONDITION_LIGHTNING: ["Risque d'orages", "Orages", "Orage avec grêle"],
ATTR_CONDITION_LIGHTNING_RAINY: [
"Pluie orageuses",
"Pluies orageuses",
@ -62,6 +63,7 @@ CONDITION_CLASSES: dict[str, list[str]] = {
"Éclaircies",
"Eclaircies",
"Peu nuageux",
"Variable",
],
ATTR_CONDITION_POURING: ["Pluie forte"],
ATTR_CONDITION_RAINY: [
@ -74,6 +76,7 @@ CONDITION_CLASSES: dict[str, list[str]] = {
"Pluie modérée",
"Pluie / Averses",
"Averses",
"Averses faibles",
"Pluie",
],
ATTR_CONDITION_SNOWY: [
@ -81,6 +84,8 @@ CONDITION_CLASSES: dict[str, list[str]] = {
"Neige",
"Averses de neige",
"Neige forte",
"Neige faible",
"Averses de neige faible",
"Quelques flocons",
],
ATTR_CONDITION_SNOWY_RAINY: ["Pluie et neige", "Pluie verglaçante"],

View File

@ -84,8 +84,10 @@
"options": {
"apparent_power": "[%key:component::sensor::entity_component::apparent_power::name%]",
"aqi": "[%key:component::sensor::entity_component::aqi::name%]",
"area": "[%key:component::sensor::entity_component::area::name%]",
"atmospheric_pressure": "[%key:component::sensor::entity_component::atmospheric_pressure::name%]",
"battery": "[%key:component::sensor::entity_component::battery::name%]",
"blood_glucose_concentration": "[%key:component::sensor::entity_component::blood_glucose_concentration::name%]",
"carbon_dioxide": "[%key:component::sensor::entity_component::carbon_dioxide::name%]",
"carbon_monoxide": "[%key:component::sensor::entity_component::carbon_monoxide::name%]",
"conductivity": "[%key:component::sensor::entity_component::conductivity::name%]",

View File

@ -30,5 +30,5 @@
"iot_class": "cloud_push",
"loggers": ["pysmartthings"],
"quality_scale": "bronze",
"requirements": ["pysmartthings==3.0.4"]
"requirements": ["pysmartthings==3.0.5"]
}

View File

@ -3,7 +3,6 @@
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME, Platform
from homeassistant.core import HomeAssistant
from .const import DOMAIN
from .coordinator import VodafoneConfigEntry, VodafoneStationRouter
PLATFORMS = [Platform.BUTTON, Platform.DEVICE_TRACKER, Platform.SENSOR]
@ -36,7 +35,6 @@ async def async_unload_entry(hass: HomeAssistant, entry: VodafoneConfigEntry) ->
coordinator = entry.runtime_data
await coordinator.api.logout()
await coordinator.api.close()
hass.data[DOMAIN].pop(entry.entry_id)
return unload_ok

View File

@ -25,7 +25,7 @@ if TYPE_CHECKING:
APPLICATION_NAME: Final = "HomeAssistant"
MAJOR_VERSION: Final = 2025
MINOR_VERSION: Final = 4
PATCH_VERSION: Final = "3"
PATCH_VERSION: Final = "4"
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 13, 0)

View File

@ -1,10 +1,10 @@
[build-system]
requires = ["setuptools==77.0.3"]
requires = ["setuptools==78.1.1"]
build-backend = "setuptools.build_meta"
[project]
name = "homeassistant"
version = "2025.4.3"
version = "2025.4.4"
license = "Apache-2.0"
license-files = ["LICENSE*", "homeassistant/backports/LICENSE*"]
description = "Open-source home automation platform running on Python 3."

6
requirements_all.txt generated
View File

@ -267,7 +267,7 @@ aiohasupervisor==0.3.0
aiohomeconnect==0.16.3
# homeassistant.components.homekit_controller
aiohomekit==3.2.13
aiohomekit==3.2.14
# homeassistant.components.mcp_server
aiohttp_sse==2.2.0
@ -784,7 +784,7 @@ devolo-home-control-api==0.18.3
devolo-plc-api==1.5.1
# homeassistant.components.chacon_dio
dio-chacon-wifi-api==1.2.1
dio-chacon-wifi-api==1.2.2
# homeassistant.components.directv
directv==0.4.0
@ -2319,7 +2319,7 @@ pysma==0.7.5
pysmappee==0.2.29
# homeassistant.components.smartthings
pysmartthings==3.0.4
pysmartthings==3.0.5
# homeassistant.components.smarty
pysmarty2==0.10.2

View File

@ -252,7 +252,7 @@ aiohasupervisor==0.3.0
aiohomeconnect==0.16.3
# homeassistant.components.homekit_controller
aiohomekit==3.2.13
aiohomekit==3.2.14
# homeassistant.components.mcp_server
aiohttp_sse==2.2.0
@ -675,7 +675,7 @@ devolo-home-control-api==0.18.3
devolo-plc-api==1.5.1
# homeassistant.components.chacon_dio
dio-chacon-wifi-api==1.2.1
dio-chacon-wifi-api==1.2.2
# homeassistant.components.directv
directv==0.4.0
@ -1889,7 +1889,7 @@ pysma==0.7.5
pysmappee==0.2.29
# homeassistant.components.smartthings
pysmartthings==3.0.4
pysmartthings==3.0.5
# homeassistant.components.smarty
pysmarty2==0.10.2

View File

@ -191,7 +191,6 @@ EXCEPTIONS = {
"enocean", # https://github.com/kipe/enocean/pull/142
"imutils", # https://github.com/PyImageSearch/imutils/pull/292
"iso4217", # Public domain
"jaraco.itertools", # MIT - https://github.com/jaraco/jaraco.itertools/issues/21
"kiwiki_client", # https://github.com/c7h/kiwiki_client/pull/6
"ld2410-ble", # https://github.com/930913/ld2410-ble/pull/7
"maxcube-api", # https://github.com/uebelack/python-maxcube-api/pull/48
@ -205,6 +204,11 @@ EXCEPTIONS = {
"repoze.lru",
"sharp_aquos_rc", # https://github.com/jmoore987/sharp_aquos_rc/pull/14
"tapsaff", # https://github.com/bazwilliams/python-taps-aff/pull/5
# ---
# https://github.com/jaraco/skeleton/pull/170
# https://github.com/jaraco/skeleton/pull/171
"jaraco.itertools", # MIT - https://github.com/jaraco/jaraco.itertools/issues/21
"setuptools", # MIT
}
TODO = {

View File

@ -181,5 +181,29 @@
}
]
}
},
"Hood": {
"data": {
"programs": [
{
"key": "Cooking.Common.Program.Hood.Automatic",
"constraints": {
"execution": "selectandstart"
}
},
{
"key": "Cooking.Common.Program.Hood.Venting",
"constraints": {
"execution": "selectandstart"
}
},
{
"key": "Cooking.Common.Program.Hood.DelayedShutOff",
"constraints": {
"execution": "selectandstart"
}
}
]
}
}
}

View File

@ -90,6 +90,9 @@
'ha_id': 'BOSCH-HCS000000-D00000000004',
'name': 'Hood',
'programs': list([
'Cooking.Common.Program.Hood.Automatic',
'Cooking.Common.Program.Hood.Venting',
'Cooking.Common.Program.Hood.DelayedShutOff',
]),
'settings': dict({
'BSH.Common.Setting.AmbientLightBrightness': 70,

View File

@ -11,6 +11,7 @@ from aiohomeconnect.model import (
EventMessage,
EventType,
HomeAppliance,
StatusKey,
)
from aiohomeconnect.model.error import HomeConnectApiError
import pytest
@ -115,9 +116,19 @@ async def test_paired_depaired_devices_flow(
assert entity_registry.async_get(entity_entry.entity_id)
@pytest.mark.parametrize("appliance", ["Washer"], indirect=True)
@pytest.mark.parametrize(
("appliance", "keys_to_check"),
[
(
"Washer",
(StatusKey.BSH_COMMON_REMOTE_CONTROL_ACTIVE,),
)
],
indirect=["appliance"],
)
async def test_connected_devices(
appliance: HomeAppliance,
keys_to_check: tuple,
hass: HomeAssistant,
config_entry: MockConfigEntry,
integration_setup: Callable[[MagicMock], Awaitable[bool]],
@ -148,7 +159,17 @@ async def test_connected_devices(
device = device_registry.async_get_device(identifiers={(DOMAIN, appliance.ha_id)})
assert device
entity_entries = entity_registry.entities.get_entries_for_device_id(device.id)
assert entity_registry.async_get_entity_id(
Platform.BINARY_SENSOR,
DOMAIN,
f"{appliance.ha_id}-{EventKey.BSH_COMMON_APPLIANCE_CONNECTED}",
)
for key in keys_to_check:
assert not entity_registry.async_get_entity_id(
Platform.BINARY_SENSOR,
DOMAIN,
f"{appliance.ha_id}-{key}",
)
await client.add_events(
[
@ -161,10 +182,12 @@ async def test_connected_devices(
)
await hass.async_block_till_done()
device = device_registry.async_get_device(identifiers={(DOMAIN, appliance.ha_id)})
assert device
new_entity_entries = entity_registry.entities.get_entries_for_device_id(device.id)
assert len(new_entity_entries) > len(entity_entries)
for key in (*keys_to_check, EventKey.BSH_COMMON_APPLIANCE_CONNECTED):
assert entity_registry.async_get_entity_id(
Platform.BINARY_SENSOR,
DOMAIN,
f"{appliance.ha_id}-{key}",
)
@pytest.mark.usefixtures("entity_registry_enabled_by_default")

View File

@ -99,9 +99,19 @@ async def test_paired_depaired_devices_flow(
assert entity_registry.async_get(entity_entry.entity_id)
@pytest.mark.parametrize("appliance", ["Washer"], indirect=True)
@pytest.mark.parametrize(
("appliance", "keys_to_check"),
[
(
"Washer",
(CommandKey.BSH_COMMON_PAUSE_PROGRAM,),
)
],
indirect=["appliance"],
)
async def test_connected_devices(
appliance: HomeAppliance,
keys_to_check: tuple,
hass: HomeAssistant,
config_entry: MockConfigEntry,
integration_setup: Callable[[MagicMock], Awaitable[bool]],
@ -116,7 +126,7 @@ async def test_connected_devices(
not be obtained while disconnected and once connected, the entities are added.
"""
get_available_commands_original_mock = client.get_available_commands
get_available_programs_mock = client.get_available_programs
get_all_programs_mock = client.get_all_programs
async def get_available_commands_side_effect(ha_id: str):
if ha_id == appliance.ha_id:
@ -125,28 +135,36 @@ async def test_connected_devices(
)
return await get_available_commands_original_mock.side_effect(ha_id)
async def get_available_programs_side_effect(ha_id: str):
async def get_all_programs_side_effect(ha_id: str):
if ha_id == appliance.ha_id:
raise HomeConnectApiError(
"SDK.Error.HomeAppliance.Connection.Initialization.Failed"
)
return await get_available_programs_mock.side_effect(ha_id)
return await get_all_programs_mock.side_effect(ha_id)
client.get_available_commands = AsyncMock(
side_effect=get_available_commands_side_effect
)
client.get_available_programs = AsyncMock(
side_effect=get_available_programs_side_effect
)
client.get_all_programs = AsyncMock(side_effect=get_all_programs_side_effect)
assert config_entry.state == ConfigEntryState.NOT_LOADED
assert await integration_setup(client)
assert config_entry.state == ConfigEntryState.LOADED
client.get_available_commands = get_available_commands_original_mock
client.get_available_programs = get_available_programs_mock
client.get_all_programs = get_all_programs_mock
device = device_registry.async_get_device(identifiers={(DOMAIN, appliance.ha_id)})
assert device
entity_entries = entity_registry.entities.get_entries_for_device_id(device.id)
assert entity_registry.async_get_entity_id(
Platform.BUTTON,
DOMAIN,
f"{appliance.ha_id}-StopProgram",
)
for key in keys_to_check:
assert not entity_registry.async_get_entity_id(
Platform.BUTTON,
DOMAIN,
f"{appliance.ha_id}-{key}",
)
await client.add_events(
[
@ -159,10 +177,12 @@ async def test_connected_devices(
)
await hass.async_block_till_done()
device = device_registry.async_get_device(identifiers={(DOMAIN, appliance.ha_id)})
assert device
new_entity_entries = entity_registry.entities.get_entries_for_device_id(device.id)
assert len(new_entity_entries) > len(entity_entries)
for key in (*keys_to_check, "StopProgram"):
assert entity_registry.async_get_entity_id(
Platform.BUTTON,
DOMAIN,
f"{appliance.ha_id}-{key}",
)
@pytest.mark.parametrize("appliance", ["Washer"], indirect=True)

View File

@ -119,9 +119,19 @@ async def test_paired_depaired_devices_flow(
assert entity_registry.async_get(entity_entry.entity_id)
@pytest.mark.parametrize("appliance", ["Hood"], indirect=True)
@pytest.mark.parametrize(
("appliance", "keys_to_check"),
[
(
"Hood",
(SettingKey.COOKING_COMMON_LIGHTING,),
)
],
indirect=["appliance"],
)
async def test_connected_devices(
appliance: HomeAppliance,
keys_to_check: tuple,
hass: HomeAssistant,
config_entry: MockConfigEntry,
integration_setup: Callable[[MagicMock], Awaitable[bool]],
@ -136,7 +146,6 @@ async def test_connected_devices(
not be obtained while disconnected and once connected, the entities are added.
"""
get_settings_original_mock = client.get_settings
get_available_programs_mock = client.get_available_programs
async def get_settings_side_effect(ha_id: str):
if ha_id == appliance.ha_id:
@ -145,26 +154,20 @@ async def test_connected_devices(
)
return await get_settings_original_mock.side_effect(ha_id)
async def get_available_programs_side_effect(ha_id: str):
if ha_id == appliance.ha_id:
raise HomeConnectApiError(
"SDK.Error.HomeAppliance.Connection.Initialization.Failed"
)
return await get_available_programs_mock.side_effect(ha_id)
client.get_settings = AsyncMock(side_effect=get_settings_side_effect)
client.get_available_programs = AsyncMock(
side_effect=get_available_programs_side_effect
)
assert config_entry.state == ConfigEntryState.NOT_LOADED
assert await integration_setup(client)
assert config_entry.state == ConfigEntryState.LOADED
client.get_settings = get_settings_original_mock
client.get_available_programs = get_available_programs_mock
device = device_registry.async_get_device(identifiers={(DOMAIN, appliance.ha_id)})
assert device
entity_entries = entity_registry.entities.get_entries_for_device_id(device.id)
for key in keys_to_check:
assert not entity_registry.async_get_entity_id(
Platform.LIGHT,
DOMAIN,
f"{appliance.ha_id}-{key}",
)
await client.add_events(
[
@ -177,10 +180,12 @@ async def test_connected_devices(
)
await hass.async_block_till_done()
device = device_registry.async_get_device(identifiers={(DOMAIN, appliance.ha_id)})
assert device
new_entity_entries = entity_registry.entities.get_entries_for_device_id(device.id)
assert len(new_entity_entries) > len(entity_entries)
for key in keys_to_check:
assert entity_registry.async_get_entity_id(
Platform.LIGHT,
DOMAIN,
f"{appliance.ha_id}-{key}",
)
@pytest.mark.parametrize("appliance", ["Hood"], indirect=True)

View File

@ -135,9 +135,21 @@ async def test_paired_depaired_devices_flow(
assert entity_registry.async_get(entity_entry.entity_id)
@pytest.mark.parametrize("appliance", ["FridgeFreezer"], indirect=True)
@pytest.mark.parametrize(
("appliance", "keys_to_check"),
[
(
"FridgeFreezer",
(
SettingKey.REFRIGERATION_FRIDGE_FREEZER_SETPOINT_TEMPERATURE_REFRIGERATOR,
),
)
],
indirect=["appliance"],
)
async def test_connected_devices(
appliance: HomeAppliance,
keys_to_check: tuple,
hass: HomeAssistant,
config_entry: MockConfigEntry,
integration_setup: Callable[[MagicMock], Awaitable[bool]],
@ -168,7 +180,12 @@ async def test_connected_devices(
device = device_registry.async_get_device(identifiers={(DOMAIN, appliance.ha_id)})
assert device
entity_entries = entity_registry.entities.get_entries_for_device_id(device.id)
for key in keys_to_check:
assert not entity_registry.async_get_entity_id(
Platform.NUMBER,
DOMAIN,
f"{appliance.ha_id}-{key}",
)
await client.add_events(
[
@ -181,10 +198,12 @@ async def test_connected_devices(
)
await hass.async_block_till_done()
device = device_registry.async_get_device(identifiers={(DOMAIN, appliance.ha_id)})
assert device
new_entity_entries = entity_registry.entities.get_entries_for_device_id(device.id)
assert len(new_entity_entries) > len(entity_entries)
for key in keys_to_check:
assert entity_registry.async_get_entity_id(
Platform.NUMBER,
DOMAIN,
f"{appliance.ha_id}-{key}",
)
@pytest.mark.parametrize("appliance", ["FridgeFreezer"], indirect=True)

View File

@ -20,6 +20,7 @@ from aiohomeconnect.model import (
)
from aiohomeconnect.model.error import (
ActiveProgramNotSetError,
HomeConnectApiError,
HomeConnectError,
SelectedProgramNotSetError,
TooManyRequestsError,
@ -138,9 +139,23 @@ async def test_paired_depaired_devices_flow(
assert entity_registry.async_get(entity_entry.entity_id)
@pytest.mark.parametrize("appliance", ["Washer"], indirect=True)
@pytest.mark.parametrize(
("appliance", "keys_to_check"),
[
(
"Hood",
(
EventKey.BSH_COMMON_ROOT_ACTIVE_PROGRAM,
EventKey.BSH_COMMON_ROOT_SELECTED_PROGRAM,
SettingKey.COOKING_HOOD_COLOR_TEMPERATURE,
),
)
],
indirect=["appliance"],
)
async def test_connected_devices(
appliance: HomeAppliance,
keys_to_check: tuple,
hass: HomeAssistant,
config_entry: MockConfigEntry,
integration_setup: Callable[[MagicMock], Awaitable[bool]],
@ -154,13 +169,39 @@ async def test_connected_devices(
Specifically those devices whose settings, status, etc. could
not be obtained while disconnected and once connected, the entities are added.
"""
get_settings_original_mock = client.get_settings
get_all_programs_mock = client.get_all_programs
async def get_settings_side_effect(ha_id: str):
if ha_id == appliance.ha_id:
raise HomeConnectApiError(
"SDK.Error.HomeAppliance.Connection.Initialization.Failed"
)
return await get_settings_original_mock.side_effect(ha_id)
async def get_all_programs_side_effect(ha_id: str):
if ha_id == appliance.ha_id:
raise HomeConnectApiError(
"SDK.Error.HomeAppliance.Connection.Initialization.Failed"
)
return await get_all_programs_mock.side_effect(ha_id)
client.get_settings = AsyncMock(side_effect=get_settings_side_effect)
client.get_all_programs = AsyncMock(side_effect=get_all_programs_side_effect)
assert config_entry.state == ConfigEntryState.NOT_LOADED
assert await integration_setup(client)
assert config_entry.state == ConfigEntryState.LOADED
client.get_settings = get_settings_original_mock
client.get_all_programs = get_all_programs_mock
device = device_registry.async_get_device(identifiers={(DOMAIN, appliance.ha_id)})
assert device
for key in keys_to_check:
assert not entity_registry.async_get_entity_id(
Platform.SELECT,
DOMAIN,
f"{appliance.ha_id}-{key}",
)
await client.add_events(
[
@ -173,10 +214,12 @@ async def test_connected_devices(
)
await hass.async_block_till_done()
device = device_registry.async_get_device(identifiers={(DOMAIN, appliance.ha_id)})
assert device
entity_entries = entity_registry.entities.get_entries_for_device_id(device.id)
assert entity_entries
for key in keys_to_check:
assert entity_registry.async_get_entity_id(
Platform.SELECT,
DOMAIN,
f"{appliance.ha_id}-{key}",
)
@pytest.mark.parametrize("appliance", ["Washer"], indirect=True)

View File

@ -154,9 +154,19 @@ async def test_paired_depaired_devices_flow(
assert entity_registry.async_get(entity_entry.entity_id)
@pytest.mark.parametrize("appliance", ["Washer"], indirect=True)
@pytest.mark.parametrize(
("appliance", "keys_to_check"),
[
(
"Washer",
(StatusKey.BSH_COMMON_OPERATION_STATE,),
)
],
indirect=["appliance"],
)
async def test_connected_devices(
appliance: HomeAppliance,
keys_to_check: tuple,
hass: HomeAssistant,
config_entry: MockConfigEntry,
integration_setup: Callable[[MagicMock], Awaitable[bool]],
@ -187,7 +197,12 @@ async def test_connected_devices(
device = device_registry.async_get_device(identifiers={(DOMAIN, appliance.ha_id)})
assert device
entity_entries = entity_registry.entities.get_entries_for_device_id(device.id)
for key in keys_to_check:
assert not entity_registry.async_get_entity_id(
Platform.SENSOR,
DOMAIN,
f"{appliance.ha_id}-{key}",
)
await client.add_events(
[
@ -200,10 +215,12 @@ async def test_connected_devices(
)
await hass.async_block_till_done()
device = device_registry.async_get_device(identifiers={(DOMAIN, appliance.ha_id)})
assert device
new_entity_entries = entity_registry.entities.get_entries_for_device_id(device.id)
assert len(new_entity_entries) > len(entity_entries)
for key in keys_to_check:
assert entity_registry.async_get_entity_id(
Platform.SENSOR,
DOMAIN,
f"{appliance.ha_id}-{key}",
)
@pytest.mark.parametrize("appliance", [TEST_HC_APP], indirect=True)

View File

@ -147,9 +147,23 @@ async def test_paired_depaired_devices_flow(
assert entity_registry.async_get(entity_entry.entity_id)
@pytest.mark.parametrize("appliance", ["Washer"], indirect=True)
@pytest.mark.parametrize(
("appliance", "keys_to_check"),
[
(
"Washer",
(
SettingKey.BSH_COMMON_POWER_STATE,
SettingKey.BSH_COMMON_CHILD_LOCK,
"Program Cotton",
),
)
],
indirect=["appliance"],
)
async def test_connected_devices(
appliance: HomeAppliance,
keys_to_check: tuple,
hass: HomeAssistant,
config_entry: MockConfigEntry,
integration_setup: Callable[[MagicMock], Awaitable[bool]],
@ -164,7 +178,7 @@ async def test_connected_devices(
not be obtained while disconnected and once connected, the entities are added.
"""
get_settings_original_mock = client.get_settings
get_available_programs_mock = client.get_available_programs
get_all_programs_mock = client.get_all_programs
async def get_settings_side_effect(ha_id: str):
if ha_id == appliance.ha_id:
@ -173,26 +187,29 @@ async def test_connected_devices(
)
return await get_settings_original_mock.side_effect(ha_id)
async def get_available_programs_side_effect(ha_id: str):
async def get_all_programs_side_effect(ha_id: str):
if ha_id == appliance.ha_id:
raise HomeConnectApiError(
"SDK.Error.HomeAppliance.Connection.Initialization.Failed"
)
return await get_available_programs_mock.side_effect(ha_id)
return await get_all_programs_mock.side_effect(ha_id)
client.get_settings = AsyncMock(side_effect=get_settings_side_effect)
client.get_available_programs = AsyncMock(
side_effect=get_available_programs_side_effect
)
client.get_all_programs = AsyncMock(side_effect=get_all_programs_side_effect)
assert config_entry.state == ConfigEntryState.NOT_LOADED
assert await integration_setup(client)
assert config_entry.state == ConfigEntryState.LOADED
client.get_settings = get_settings_original_mock
client.get_available_programs = get_available_programs_mock
client.get_all_programs = get_all_programs_mock
device = device_registry.async_get_device(identifiers={(DOMAIN, appliance.ha_id)})
assert device
entity_entries = entity_registry.entities.get_entries_for_device_id(device.id)
for key in keys_to_check:
assert not entity_registry.async_get_entity_id(
Platform.SWITCH,
DOMAIN,
f"{appliance.ha_id}-{key}",
)
await client.add_events(
[
@ -205,10 +222,12 @@ async def test_connected_devices(
)
await hass.async_block_till_done()
device = device_registry.async_get_device(identifiers={(DOMAIN, appliance.ha_id)})
assert device
new_entity_entries = entity_registry.entities.get_entries_for_device_id(device.id)
assert len(new_entity_entries) > len(entity_entries)
for key in keys_to_check:
assert entity_registry.async_get_entity_id(
Platform.SWITCH,
DOMAIN,
f"{appliance.ha_id}-{key}",
)
@pytest.mark.usefixtures("entity_registry_enabled_by_default")

View File

@ -113,9 +113,19 @@ async def test_paired_depaired_devices_flow(
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
@pytest.mark.parametrize("appliance", ["Oven"], indirect=True)
@pytest.mark.parametrize(
("appliance", "keys_to_check"),
[
(
"Oven",
(SettingKey.BSH_COMMON_ALARM_CLOCK,),
)
],
indirect=["appliance"],
)
async def test_connected_devices(
appliance: HomeAppliance,
keys_to_check: tuple,
hass: HomeAssistant,
config_entry: MockConfigEntry,
integration_setup: Callable[[MagicMock], Awaitable[bool]],
@ -146,7 +156,12 @@ async def test_connected_devices(
device = device_registry.async_get_device(identifiers={(DOMAIN, appliance.ha_id)})
assert device
entity_entries = entity_registry.entities.get_entries_for_device_id(device.id)
for key in keys_to_check:
assert not entity_registry.async_get_entity_id(
Platform.TIME,
DOMAIN,
f"{appliance.ha_id}-{key}",
)
await client.add_events(
[
@ -159,10 +174,12 @@ async def test_connected_devices(
)
await hass.async_block_till_done()
device = device_registry.async_get_device(identifiers={(DOMAIN, appliance.ha_id)})
assert device
new_entity_entries = entity_registry.entities.get_entries_for_device_id(device.id)
assert len(new_entity_entries) > len(entity_entries)
for key in keys_to_check:
assert entity_registry.async_get_entity_id(
Platform.TIME,
DOMAIN,
f"{appliance.ha_id}-{key}",
)
@pytest.mark.usefixtures("entity_registry_enabled_by_default")

View File

@ -5,7 +5,7 @@ from datetime import UTC, datetime
from aiovodafone import VodafoneStationDevice
import pytest
from homeassistant.components.vodafone_station import DOMAIN
from homeassistant.components.vodafone_station.const import DOMAIN
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME
from .const import DEVICE_1_HOST, DEVICE_1_MAC, DEVICE_2_MAC

View File

@ -3,6 +3,8 @@
from unittest.mock import AsyncMock
from homeassistant.components.device_tracker import CONF_CONSIDER_HOME
from homeassistant.components.vodafone_station.const import DOMAIN
from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResultType
@ -31,3 +33,21 @@ async def test_reload_config_entry_with_options(
assert result["data"] == {
CONF_CONSIDER_HOME: 37,
}
async def test_unload_entry(
hass: HomeAssistant,
mock_vodafone_station_router: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test unloading the config entry."""
await setup_integration(hass, mock_config_entry)
assert len(hass.config_entries.async_entries(DOMAIN)) == 1
assert mock_config_entry.state is ConfigEntryState.LOADED
assert await hass.config_entries.async_unload(mock_config_entry.entry_id)
await hass.async_block_till_done()
assert mock_config_entry.state is ConfigEntryState.NOT_LOADED
assert not hass.data.get(DOMAIN)