mirror of
https://github.com/home-assistant/core.git
synced 2025-07-16 17:57:11 +00:00
Palazzetti integration (#128259)
Co-authored-by: Joostlek <joostlek@outlook.com>
This commit is contained in:
parent
80202f33cb
commit
8eb68b54d9
@ -1091,6 +1091,8 @@ build.json @home-assistant/supervisor
|
|||||||
/tests/components/ovo_energy/ @timmo001
|
/tests/components/ovo_energy/ @timmo001
|
||||||
/homeassistant/components/p1_monitor/ @klaasnicolaas
|
/homeassistant/components/p1_monitor/ @klaasnicolaas
|
||||||
/tests/components/p1_monitor/ @klaasnicolaas
|
/tests/components/p1_monitor/ @klaasnicolaas
|
||||||
|
/homeassistant/components/palazzetti/ @dotvav
|
||||||
|
/tests/components/palazzetti/ @dotvav
|
||||||
/homeassistant/components/panel_custom/ @home-assistant/frontend
|
/homeassistant/components/panel_custom/ @home-assistant/frontend
|
||||||
/tests/components/panel_custom/ @home-assistant/frontend
|
/tests/components/panel_custom/ @home-assistant/frontend
|
||||||
/homeassistant/components/peco/ @IceBotYT
|
/homeassistant/components/peco/ @IceBotYT
|
||||||
|
27
homeassistant/components/palazzetti/__init__.py
Normal file
27
homeassistant/components/palazzetti/__init__.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
"""The Palazzetti integration."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from homeassistant.const import Platform
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
|
from .coordinator import PalazzettiConfigEntry, PalazzettiDataUpdateCoordinator
|
||||||
|
|
||||||
|
PLATFORMS: list[Platform] = [Platform.CLIMATE]
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(hass: HomeAssistant, entry: PalazzettiConfigEntry) -> bool:
|
||||||
|
"""Set up Palazzetti from a config entry."""
|
||||||
|
|
||||||
|
coordinator = PalazzettiDataUpdateCoordinator(hass)
|
||||||
|
|
||||||
|
await coordinator.async_config_entry_first_refresh()
|
||||||
|
entry.runtime_data = coordinator
|
||||||
|
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
async def async_unload_entry(hass: HomeAssistant, entry: PalazzettiConfigEntry) -> bool:
|
||||||
|
"""Unload a config entry."""
|
||||||
|
|
||||||
|
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
160
homeassistant/components/palazzetti/climate.py
Normal file
160
homeassistant/components/palazzetti/climate.py
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
"""Support for Palazzetti climates."""
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from pypalazzetti.exceptions import CommunicationError, ValidationError
|
||||||
|
|
||||||
|
from homeassistant.components.climate import (
|
||||||
|
ClimateEntity,
|
||||||
|
ClimateEntityFeature,
|
||||||
|
HVACMode,
|
||||||
|
)
|
||||||
|
from homeassistant.const import ATTR_TEMPERATURE, UnitOfTemperature
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||||
|
from homeassistant.helpers import device_registry as dr
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
|
|
||||||
|
from . import PalazzettiConfigEntry
|
||||||
|
from .const import DOMAIN, FAN_AUTO, FAN_HIGH, FAN_MODES, FAN_SILENT, PALAZZETTI
|
||||||
|
from .coordinator import PalazzettiDataUpdateCoordinator
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entry: PalazzettiConfigEntry,
|
||||||
|
async_add_entities: AddEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
|
"""Set up Palazzetti climates based on a config entry."""
|
||||||
|
async_add_entities([PalazzettiClimateEntity(entry.runtime_data)])
|
||||||
|
|
||||||
|
|
||||||
|
class PalazzettiClimateEntity(
|
||||||
|
CoordinatorEntity[PalazzettiDataUpdateCoordinator], ClimateEntity
|
||||||
|
):
|
||||||
|
"""Defines a Palazzetti climate."""
|
||||||
|
|
||||||
|
_attr_has_entity_name = True
|
||||||
|
_attr_name = None
|
||||||
|
_attr_translation_key = DOMAIN
|
||||||
|
_attr_target_temperature_step = 1.0
|
||||||
|
_attr_temperature_unit = UnitOfTemperature.CELSIUS
|
||||||
|
_attr_supported_features = (
|
||||||
|
ClimateEntityFeature.TARGET_TEMPERATURE
|
||||||
|
| ClimateEntityFeature.FAN_MODE
|
||||||
|
| ClimateEntityFeature.TURN_ON
|
||||||
|
| ClimateEntityFeature.TURN_OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
def __init__(self, coordinator: PalazzettiDataUpdateCoordinator) -> None:
|
||||||
|
"""Initialize Palazzetti climate."""
|
||||||
|
super().__init__(coordinator)
|
||||||
|
client = coordinator.client
|
||||||
|
mac = coordinator.config_entry.unique_id
|
||||||
|
assert mac is not None
|
||||||
|
self._attr_unique_id = mac
|
||||||
|
self._attr_device_info = dr.DeviceInfo(
|
||||||
|
connections={(dr.CONNECTION_NETWORK_MAC, mac)},
|
||||||
|
name=client.name,
|
||||||
|
manufacturer=PALAZZETTI,
|
||||||
|
sw_version=client.sw_version,
|
||||||
|
hw_version=client.hw_version,
|
||||||
|
)
|
||||||
|
self._attr_hvac_modes = [HVACMode.HEAT, HVACMode.OFF]
|
||||||
|
self._attr_min_temp = client.target_temperature_min
|
||||||
|
self._attr_max_temp = client.target_temperature_max
|
||||||
|
self._attr_fan_modes = list(
|
||||||
|
map(str, range(client.fan_speed_min, client.fan_speed_max + 1))
|
||||||
|
)
|
||||||
|
if client.has_fan_silent:
|
||||||
|
self._attr_fan_modes.insert(0, FAN_SILENT)
|
||||||
|
if client.has_fan_high:
|
||||||
|
self._attr_fan_modes.append(FAN_HIGH)
|
||||||
|
if client.has_fan_auto:
|
||||||
|
self._attr_fan_modes.append(FAN_AUTO)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def available(self) -> bool:
|
||||||
|
"""Is the entity available."""
|
||||||
|
return super().available and self.coordinator.client.connected
|
||||||
|
|
||||||
|
@property
|
||||||
|
def hvac_mode(self) -> HVACMode:
|
||||||
|
"""Return hvac operation ie. heat or off mode."""
|
||||||
|
is_heating = bool(self.coordinator.client.is_heating)
|
||||||
|
return HVACMode.HEAT if is_heating else HVACMode.OFF
|
||||||
|
|
||||||
|
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||||
|
"""Set new target hvac mode."""
|
||||||
|
try:
|
||||||
|
await self.coordinator.client.set_on(hvac_mode != HVACMode.OFF)
|
||||||
|
except CommunicationError as err:
|
||||||
|
raise HomeAssistantError(
|
||||||
|
translation_domain=DOMAIN, translation_key="cannot_connect"
|
||||||
|
) from err
|
||||||
|
except ValidationError as err:
|
||||||
|
raise ServiceValidationError(
|
||||||
|
translation_domain=DOMAIN, translation_key="on_off_not_available"
|
||||||
|
) from err
|
||||||
|
await self.coordinator.async_refresh()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def current_temperature(self) -> float | None:
|
||||||
|
"""Return current temperature."""
|
||||||
|
return self.coordinator.client.room_temperature
|
||||||
|
|
||||||
|
@property
|
||||||
|
def target_temperature(self) -> int | None:
|
||||||
|
"""Return the temperature."""
|
||||||
|
return self.coordinator.client.target_temperature
|
||||||
|
|
||||||
|
async def async_set_temperature(self, **kwargs: Any) -> None:
|
||||||
|
"""Set new temperature."""
|
||||||
|
temperature = int(kwargs[ATTR_TEMPERATURE])
|
||||||
|
try:
|
||||||
|
await self.coordinator.client.set_target_temperature(temperature)
|
||||||
|
except CommunicationError as err:
|
||||||
|
raise HomeAssistantError(
|
||||||
|
translation_domain=DOMAIN, translation_key="cannot_connect"
|
||||||
|
) from err
|
||||||
|
except ValidationError as err:
|
||||||
|
raise ServiceValidationError(
|
||||||
|
translation_domain=DOMAIN,
|
||||||
|
translation_key="invalid_target_temperature",
|
||||||
|
translation_placeholders={
|
||||||
|
"value": str(temperature),
|
||||||
|
},
|
||||||
|
) from err
|
||||||
|
await self.coordinator.async_refresh()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def fan_mode(self) -> str | None:
|
||||||
|
"""Return the fan mode."""
|
||||||
|
api_state = self.coordinator.client.fan_speed
|
||||||
|
return FAN_MODES[api_state]
|
||||||
|
|
||||||
|
async def async_set_fan_mode(self, fan_mode: str) -> None:
|
||||||
|
"""Set new fan mode."""
|
||||||
|
try:
|
||||||
|
if fan_mode == FAN_SILENT:
|
||||||
|
await self.coordinator.client.set_fan_silent()
|
||||||
|
elif fan_mode == FAN_HIGH:
|
||||||
|
await self.coordinator.client.set_fan_high()
|
||||||
|
elif fan_mode == FAN_AUTO:
|
||||||
|
await self.coordinator.client.set_fan_auto()
|
||||||
|
else:
|
||||||
|
await self.coordinator.client.set_fan_speed(FAN_MODES.index(fan_mode))
|
||||||
|
except CommunicationError as err:
|
||||||
|
raise HomeAssistantError(
|
||||||
|
translation_domain=DOMAIN, translation_key="cannot_connect"
|
||||||
|
) from err
|
||||||
|
except ValidationError as err:
|
||||||
|
raise ServiceValidationError(
|
||||||
|
translation_domain=DOMAIN,
|
||||||
|
translation_key="invalid_fan_mode",
|
||||||
|
translation_placeholders={
|
||||||
|
"value": fan_mode,
|
||||||
|
},
|
||||||
|
) from err
|
||||||
|
await self.coordinator.async_refresh()
|
50
homeassistant/components/palazzetti/config_flow.py
Normal file
50
homeassistant/components/palazzetti/config_flow.py
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
"""Config flow for Palazzetti."""
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from pypalazzetti.client import PalazzettiClient
|
||||||
|
from pypalazzetti.exceptions import CommunicationError
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant.config_entries import ConfigFlow, ConfigFlowResult
|
||||||
|
from homeassistant.const import CONF_HOST
|
||||||
|
from homeassistant.helpers import device_registry as dr
|
||||||
|
|
||||||
|
from .const import DOMAIN, LOGGER
|
||||||
|
|
||||||
|
|
||||||
|
class PalazzettiConfigFlow(ConfigFlow, domain=DOMAIN):
|
||||||
|
"""Palazzetti config flow."""
|
||||||
|
|
||||||
|
async def async_step_user(
|
||||||
|
self, user_input: dict[str, Any] | None = None
|
||||||
|
) -> ConfigFlowResult:
|
||||||
|
"""User configuration step."""
|
||||||
|
errors: dict[str, str] = {}
|
||||||
|
if user_input is not None:
|
||||||
|
host = user_input[CONF_HOST]
|
||||||
|
client = PalazzettiClient(hostname=host)
|
||||||
|
try:
|
||||||
|
await client.connect()
|
||||||
|
except CommunicationError:
|
||||||
|
LOGGER.exception("Communication error")
|
||||||
|
errors["base"] = "cannot_connect"
|
||||||
|
else:
|
||||||
|
formatted_mac = dr.format_mac(client.mac)
|
||||||
|
|
||||||
|
# Assign a unique ID to the flow
|
||||||
|
await self.async_set_unique_id(formatted_mac)
|
||||||
|
|
||||||
|
# Abort the flow if a config entry with the same unique ID exists
|
||||||
|
self._abort_if_unique_id_configured()
|
||||||
|
|
||||||
|
return self.async_create_entry(
|
||||||
|
title=client.name,
|
||||||
|
data=user_input,
|
||||||
|
)
|
||||||
|
|
||||||
|
return self.async_show_form(
|
||||||
|
step_id="user",
|
||||||
|
data_schema=vol.Schema({vol.Required(CONF_HOST): str}),
|
||||||
|
errors=errors,
|
||||||
|
)
|
19
homeassistant/components/palazzetti/const.py
Normal file
19
homeassistant/components/palazzetti/const.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
"""Constants for the Palazzetti integration."""
|
||||||
|
|
||||||
|
from datetime import timedelta
|
||||||
|
import logging
|
||||||
|
from typing import Final
|
||||||
|
|
||||||
|
DOMAIN: Final = "palazzetti"
|
||||||
|
PALAZZETTI: Final = "Palazzetti"
|
||||||
|
LOGGER = logging.getLogger(__package__)
|
||||||
|
SCAN_INTERVAL = timedelta(seconds=30)
|
||||||
|
ON_OFF_NOT_AVAILABLE = "on_off_not_available"
|
||||||
|
ERROR_INVALID_FAN_MODE = "invalid_fan_mode"
|
||||||
|
ERROR_INVALID_TARGET_TEMPERATURE = "invalid_target_temperature"
|
||||||
|
ERROR_CANNOT_CONNECT = "cannot_connect"
|
||||||
|
|
||||||
|
FAN_SILENT: Final = "silent"
|
||||||
|
FAN_HIGH: Final = "high"
|
||||||
|
FAN_AUTO: Final = "auto"
|
||||||
|
FAN_MODES: Final = [FAN_SILENT, "1", "2", "3", "4", "5", FAN_HIGH, FAN_AUTO]
|
47
homeassistant/components/palazzetti/coordinator.py
Normal file
47
homeassistant/components/palazzetti/coordinator.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
"""Helpers to help coordinate updates."""
|
||||||
|
|
||||||
|
from pypalazzetti.client import PalazzettiClient
|
||||||
|
from pypalazzetti.exceptions import CommunicationError, ValidationError
|
||||||
|
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
|
from homeassistant.const import CONF_HOST
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||||
|
|
||||||
|
from .const import DOMAIN, LOGGER, SCAN_INTERVAL
|
||||||
|
|
||||||
|
type PalazzettiConfigEntry = ConfigEntry[PalazzettiDataUpdateCoordinator]
|
||||||
|
|
||||||
|
|
||||||
|
class PalazzettiDataUpdateCoordinator(DataUpdateCoordinator[None]):
|
||||||
|
"""Class to manage fetching Palazzetti data from a Palazzetti hub."""
|
||||||
|
|
||||||
|
config_entry: PalazzettiConfigEntry
|
||||||
|
client: PalazzettiClient
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
hass: HomeAssistant,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize global Palazzetti data updater."""
|
||||||
|
super().__init__(
|
||||||
|
hass,
|
||||||
|
LOGGER,
|
||||||
|
name=DOMAIN,
|
||||||
|
update_interval=SCAN_INTERVAL,
|
||||||
|
)
|
||||||
|
self.client = PalazzettiClient(self.config_entry.data[CONF_HOST])
|
||||||
|
|
||||||
|
async def _async_setup(self) -> None:
|
||||||
|
try:
|
||||||
|
await self.client.connect()
|
||||||
|
await self.client.update_state()
|
||||||
|
except (CommunicationError, ValidationError) as err:
|
||||||
|
raise UpdateFailed(f"Error communicating with the API: {err}") from err
|
||||||
|
|
||||||
|
async def _async_update_data(self) -> None:
|
||||||
|
"""Fetch data from Palazzetti."""
|
||||||
|
try:
|
||||||
|
await self.client.update_state()
|
||||||
|
except (CommunicationError, ValidationError) as err:
|
||||||
|
raise UpdateFailed(f"Error communicating with the API: {err}") from err
|
10
homeassistant/components/palazzetti/manifest.json
Normal file
10
homeassistant/components/palazzetti/manifest.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"domain": "palazzetti",
|
||||||
|
"name": "Palazzetti",
|
||||||
|
"codeowners": ["@dotvav"],
|
||||||
|
"config_flow": true,
|
||||||
|
"documentation": "https://www.home-assistant.io/integrations/palazzetti",
|
||||||
|
"integration_type": "device",
|
||||||
|
"iot_class": "local_polling",
|
||||||
|
"requirements": ["pypalazzetti==0.1.6"]
|
||||||
|
}
|
49
homeassistant/components/palazzetti/strings.json
Normal file
49
homeassistant/components/palazzetti/strings.json
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"step": {
|
||||||
|
"user": {
|
||||||
|
"data": {
|
||||||
|
"host": "[%key:common::config_flow::data::host%]"
|
||||||
|
},
|
||||||
|
"data_description": {
|
||||||
|
"host": "The host name or the IP address of the Palazzetti CBox"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"abort": {
|
||||||
|
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"exceptions": {
|
||||||
|
"on_off_not_available": {
|
||||||
|
"message": "The appliance cannot be turned on or off."
|
||||||
|
},
|
||||||
|
"invalid_fan_mode": {
|
||||||
|
"message": "Fan mode {value} is invalid."
|
||||||
|
},
|
||||||
|
"invalid_target_temperatures": {
|
||||||
|
"message": "Target temperature {value} is invalid."
|
||||||
|
},
|
||||||
|
"cannot_connect": {
|
||||||
|
"message": "Could not connect to the device."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"entity": {
|
||||||
|
"climate": {
|
||||||
|
"palazzetti": {
|
||||||
|
"state_attributes": {
|
||||||
|
"fan_mode": {
|
||||||
|
"state": {
|
||||||
|
"silent": "Silent",
|
||||||
|
"auto": "Auto",
|
||||||
|
"high": "High"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -439,6 +439,7 @@ FLOWS = {
|
|||||||
"ovo_energy",
|
"ovo_energy",
|
||||||
"owntracks",
|
"owntracks",
|
||||||
"p1_monitor",
|
"p1_monitor",
|
||||||
|
"palazzetti",
|
||||||
"panasonic_viera",
|
"panasonic_viera",
|
||||||
"peco",
|
"peco",
|
||||||
"pegel_online",
|
"pegel_online",
|
||||||
|
@ -4530,6 +4530,12 @@
|
|||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"iot_class": "local_polling"
|
"iot_class": "local_polling"
|
||||||
},
|
},
|
||||||
|
"palazzetti": {
|
||||||
|
"name": "Palazzetti",
|
||||||
|
"integration_type": "device",
|
||||||
|
"config_flow": true,
|
||||||
|
"iot_class": "local_polling"
|
||||||
|
},
|
||||||
"panasonic": {
|
"panasonic": {
|
||||||
"name": "Panasonic",
|
"name": "Panasonic",
|
||||||
"integrations": {
|
"integrations": {
|
||||||
|
@ -2142,6 +2142,9 @@ pyoverkiz==1.14.1
|
|||||||
# homeassistant.components.onewire
|
# homeassistant.components.onewire
|
||||||
pyownet==0.10.0.post1
|
pyownet==0.10.0.post1
|
||||||
|
|
||||||
|
# homeassistant.components.palazzetti
|
||||||
|
pypalazzetti==0.1.6
|
||||||
|
|
||||||
# homeassistant.components.elv
|
# homeassistant.components.elv
|
||||||
pypca==0.0.7
|
pypca==0.0.7
|
||||||
|
|
||||||
|
@ -1729,6 +1729,9 @@ pyoverkiz==1.14.1
|
|||||||
# homeassistant.components.onewire
|
# homeassistant.components.onewire
|
||||||
pyownet==0.10.0.post1
|
pyownet==0.10.0.post1
|
||||||
|
|
||||||
|
# homeassistant.components.palazzetti
|
||||||
|
pypalazzetti==0.1.6
|
||||||
|
|
||||||
# homeassistant.components.lcn
|
# homeassistant.components.lcn
|
||||||
pypck==0.7.24
|
pypck==0.7.24
|
||||||
|
|
||||||
|
13
tests/components/palazzetti/__init__.py
Normal file
13
tests/components/palazzetti/__init__.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
"""Tests for the Palazzetti integration."""
|
||||||
|
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
|
async def setup_integration(hass: HomeAssistant, config_entry: MockConfigEntry) -> None:
|
||||||
|
"""Fixture for setting up the component."""
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
await hass.config_entries.async_setup(config_entry.entry_id)
|
||||||
|
await hass.async_block_till_done()
|
74
tests/components/palazzetti/conftest.py
Normal file
74
tests/components/palazzetti/conftest.py
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
"""Fixtures for Palazzetti integration tests."""
|
||||||
|
|
||||||
|
from collections.abc import Generator
|
||||||
|
from unittest.mock import AsyncMock, patch
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.components.palazzetti.const import DOMAIN
|
||||||
|
from homeassistant.const import CONF_HOST
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_setup_entry() -> Generator[AsyncMock]:
|
||||||
|
"""Override async_setup_entry."""
|
||||||
|
with patch(
|
||||||
|
"homeassistant.components.palazzetti.async_setup_entry",
|
||||||
|
return_value=True,
|
||||||
|
) as mock_setup_entry:
|
||||||
|
yield mock_setup_entry
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_config_entry() -> MockConfigEntry:
|
||||||
|
"""Return the default mocked config entry."""
|
||||||
|
return MockConfigEntry(
|
||||||
|
title="palazzetti",
|
||||||
|
domain=DOMAIN,
|
||||||
|
data={CONF_HOST: "127.0.0.1"},
|
||||||
|
unique_id="11:22:33:44:55:66",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def mock_palazzetti_client() -> Generator[AsyncMock]:
|
||||||
|
"""Return a mocked PalazzettiClient."""
|
||||||
|
with (
|
||||||
|
patch(
|
||||||
|
"homeassistant.components.palazzetti.coordinator.PalazzettiClient",
|
||||||
|
autospec=True,
|
||||||
|
) as client,
|
||||||
|
patch(
|
||||||
|
"homeassistant.components.palazzetti.config_flow.PalazzettiClient",
|
||||||
|
new=client,
|
||||||
|
),
|
||||||
|
):
|
||||||
|
mock_client = client.return_value
|
||||||
|
mock_client.mac = "11:22:33:44:55:66"
|
||||||
|
mock_client.name = "Stove"
|
||||||
|
mock_client.sw_version = "0.0.0"
|
||||||
|
mock_client.hw_version = "1.1.1"
|
||||||
|
mock_client.fan_speed_min = 1
|
||||||
|
mock_client.fan_speed_max = 5
|
||||||
|
mock_client.has_fan_silent = True
|
||||||
|
mock_client.has_fan_high = True
|
||||||
|
mock_client.has_fan_auto = True
|
||||||
|
mock_client.has_on_off_switch = True
|
||||||
|
mock_client.connected = True
|
||||||
|
mock_client.is_heating = True
|
||||||
|
mock_client.room_temperature = 18
|
||||||
|
mock_client.target_temperature = 21
|
||||||
|
mock_client.target_temperature_min = 5
|
||||||
|
mock_client.target_temperature_max = 50
|
||||||
|
mock_client.fan_speed = 3
|
||||||
|
mock_client.connect.return_value = True
|
||||||
|
mock_client.update_state.return_value = True
|
||||||
|
mock_client.set_on.return_value = True
|
||||||
|
mock_client.set_target_temperature.return_value = True
|
||||||
|
mock_client.set_fan_speed.return_value = True
|
||||||
|
mock_client.set_fan_silent.return_value = True
|
||||||
|
mock_client.set_fan_high.return_value = True
|
||||||
|
mock_client.set_fan_auto.return_value = True
|
||||||
|
yield mock_client
|
86
tests/components/palazzetti/snapshots/test_climate.ambr
Normal file
86
tests/components/palazzetti/snapshots/test_climate.ambr
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
# serializer version: 1
|
||||||
|
# name: test_all_entities[climate.stove-entry]
|
||||||
|
EntityRegistryEntrySnapshot({
|
||||||
|
'aliases': set({
|
||||||
|
}),
|
||||||
|
'area_id': None,
|
||||||
|
'capabilities': dict({
|
||||||
|
'fan_modes': list([
|
||||||
|
'silent',
|
||||||
|
'1',
|
||||||
|
'2',
|
||||||
|
'3',
|
||||||
|
'4',
|
||||||
|
'5',
|
||||||
|
'high',
|
||||||
|
'auto',
|
||||||
|
]),
|
||||||
|
'hvac_modes': list([
|
||||||
|
<HVACMode.HEAT: 'heat'>,
|
||||||
|
<HVACMode.OFF: 'off'>,
|
||||||
|
]),
|
||||||
|
'max_temp': 50,
|
||||||
|
'min_temp': 5,
|
||||||
|
'target_temp_step': 1.0,
|
||||||
|
}),
|
||||||
|
'config_entry_id': <ANY>,
|
||||||
|
'device_class': None,
|
||||||
|
'device_id': <ANY>,
|
||||||
|
'disabled_by': None,
|
||||||
|
'domain': 'climate',
|
||||||
|
'entity_category': None,
|
||||||
|
'entity_id': 'climate.stove',
|
||||||
|
'has_entity_name': True,
|
||||||
|
'hidden_by': None,
|
||||||
|
'icon': None,
|
||||||
|
'id': <ANY>,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'name': None,
|
||||||
|
'options': dict({
|
||||||
|
}),
|
||||||
|
'original_device_class': None,
|
||||||
|
'original_icon': None,
|
||||||
|
'original_name': None,
|
||||||
|
'platform': 'palazzetti',
|
||||||
|
'previous_unique_id': None,
|
||||||
|
'supported_features': <ClimateEntityFeature: 393>,
|
||||||
|
'translation_key': 'palazzetti',
|
||||||
|
'unique_id': '11:22:33:44:55:66',
|
||||||
|
'unit_of_measurement': None,
|
||||||
|
})
|
||||||
|
# ---
|
||||||
|
# name: test_all_entities[climate.stove-state]
|
||||||
|
StateSnapshot({
|
||||||
|
'attributes': ReadOnlyDict({
|
||||||
|
'current_temperature': 18,
|
||||||
|
'fan_mode': '3',
|
||||||
|
'fan_modes': list([
|
||||||
|
'silent',
|
||||||
|
'1',
|
||||||
|
'2',
|
||||||
|
'3',
|
||||||
|
'4',
|
||||||
|
'5',
|
||||||
|
'high',
|
||||||
|
'auto',
|
||||||
|
]),
|
||||||
|
'friendly_name': 'Stove',
|
||||||
|
'hvac_modes': list([
|
||||||
|
<HVACMode.HEAT: 'heat'>,
|
||||||
|
<HVACMode.OFF: 'off'>,
|
||||||
|
]),
|
||||||
|
'max_temp': 50,
|
||||||
|
'min_temp': 5,
|
||||||
|
'supported_features': <ClimateEntityFeature: 393>,
|
||||||
|
'target_temp_step': 1.0,
|
||||||
|
'temperature': 21,
|
||||||
|
}),
|
||||||
|
'context': <ANY>,
|
||||||
|
'entity_id': 'climate.stove',
|
||||||
|
'last_changed': <ANY>,
|
||||||
|
'last_reported': <ANY>,
|
||||||
|
'last_updated': <ANY>,
|
||||||
|
'state': 'heat',
|
||||||
|
})
|
||||||
|
# ---
|
33
tests/components/palazzetti/snapshots/test_init.ambr
Normal file
33
tests/components/palazzetti/snapshots/test_init.ambr
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
# serializer version: 1
|
||||||
|
# name: test_device
|
||||||
|
DeviceRegistryEntrySnapshot({
|
||||||
|
'area_id': None,
|
||||||
|
'config_entries': <ANY>,
|
||||||
|
'configuration_url': None,
|
||||||
|
'connections': set({
|
||||||
|
tuple(
|
||||||
|
'mac',
|
||||||
|
'11:22:33:44:55:66',
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
'disabled_by': None,
|
||||||
|
'entry_type': None,
|
||||||
|
'hw_version': '1.1.1',
|
||||||
|
'id': <ANY>,
|
||||||
|
'identifiers': set({
|
||||||
|
}),
|
||||||
|
'is_new': False,
|
||||||
|
'labels': set({
|
||||||
|
}),
|
||||||
|
'manufacturer': 'Palazzetti',
|
||||||
|
'model': None,
|
||||||
|
'model_id': None,
|
||||||
|
'name': 'Stove',
|
||||||
|
'name_by_user': None,
|
||||||
|
'primary_config_entry': <ANY>,
|
||||||
|
'serial_number': None,
|
||||||
|
'suggested_area': None,
|
||||||
|
'sw_version': '0.0.0',
|
||||||
|
'via_device_id': None,
|
||||||
|
})
|
||||||
|
# ---
|
174
tests/components/palazzetti/test_climate.py
Normal file
174
tests/components/palazzetti/test_climate.py
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
"""Tests for the Palazzetti climate platform."""
|
||||||
|
|
||||||
|
from unittest.mock import AsyncMock, patch
|
||||||
|
|
||||||
|
from pypalazzetti.exceptions import CommunicationError, ValidationError
|
||||||
|
import pytest
|
||||||
|
from syrupy import SnapshotAssertion
|
||||||
|
|
||||||
|
from homeassistant.components.climate import (
|
||||||
|
ATTR_FAN_MODE,
|
||||||
|
ATTR_HVAC_MODE,
|
||||||
|
DOMAIN as CLIMATE_DOMAIN,
|
||||||
|
SERVICE_SET_FAN_MODE,
|
||||||
|
SERVICE_SET_HVAC_MODE,
|
||||||
|
SERVICE_SET_TEMPERATURE,
|
||||||
|
HVACMode,
|
||||||
|
)
|
||||||
|
from homeassistant.components.palazzetti.const import FAN_AUTO, FAN_HIGH, FAN_SILENT
|
||||||
|
from homeassistant.const import ATTR_ENTITY_ID, ATTR_TEMPERATURE, Platform
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||||
|
from homeassistant.helpers import entity_registry as er
|
||||||
|
|
||||||
|
from . import setup_integration
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry, snapshot_platform
|
||||||
|
|
||||||
|
ENTITY_ID = "climate.stove"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_all_entities(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
snapshot: SnapshotAssertion,
|
||||||
|
mock_palazzetti_client: AsyncMock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
entity_registry: er.EntityRegistry,
|
||||||
|
) -> None:
|
||||||
|
"""Test all entities."""
|
||||||
|
with patch("homeassistant.components.palazzetti.PLATFORMS", [Platform.CLIMATE]):
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
|
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_async_set_data(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_palazzetti_client: AsyncMock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
) -> None:
|
||||||
|
"""Test setting climate data via service call."""
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
|
# Set HVAC Mode: Success
|
||||||
|
await hass.services.async_call(
|
||||||
|
CLIMATE_DOMAIN,
|
||||||
|
SERVICE_SET_HVAC_MODE,
|
||||||
|
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_HVAC_MODE: HVACMode.HEAT},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
mock_palazzetti_client.set_on.assert_called_once_with(True)
|
||||||
|
mock_palazzetti_client.set_on.reset_mock()
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
CLIMATE_DOMAIN,
|
||||||
|
SERVICE_SET_HVAC_MODE,
|
||||||
|
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_HVAC_MODE: HVACMode.OFF},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
mock_palazzetti_client.set_on.assert_called_once_with(False)
|
||||||
|
mock_palazzetti_client.set_on.reset_mock()
|
||||||
|
|
||||||
|
# Set HVAC Mode: Error
|
||||||
|
mock_palazzetti_client.set_on.side_effect = CommunicationError()
|
||||||
|
with pytest.raises(HomeAssistantError):
|
||||||
|
await hass.services.async_call(
|
||||||
|
CLIMATE_DOMAIN,
|
||||||
|
SERVICE_SET_HVAC_MODE,
|
||||||
|
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_HVAC_MODE: HVACMode.HEAT},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
mock_palazzetti_client.set_on.side_effect = ValidationError()
|
||||||
|
with pytest.raises(ServiceValidationError):
|
||||||
|
await hass.services.async_call(
|
||||||
|
CLIMATE_DOMAIN,
|
||||||
|
SERVICE_SET_HVAC_MODE,
|
||||||
|
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_HVAC_MODE: HVACMode.HEAT},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Set Temperature: Success
|
||||||
|
await hass.services.async_call(
|
||||||
|
CLIMATE_DOMAIN,
|
||||||
|
SERVICE_SET_TEMPERATURE,
|
||||||
|
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_TEMPERATURE: 22},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
mock_palazzetti_client.set_target_temperature.assert_called_once_with(22)
|
||||||
|
mock_palazzetti_client.set_target_temperature.reset_mock()
|
||||||
|
|
||||||
|
# Set Temperature: Error
|
||||||
|
mock_palazzetti_client.set_target_temperature.side_effect = CommunicationError()
|
||||||
|
with pytest.raises(HomeAssistantError):
|
||||||
|
await hass.services.async_call(
|
||||||
|
CLIMATE_DOMAIN,
|
||||||
|
SERVICE_SET_TEMPERATURE,
|
||||||
|
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_TEMPERATURE: 22},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
mock_palazzetti_client.set_target_temperature.side_effect = ValidationError()
|
||||||
|
with pytest.raises(ServiceValidationError):
|
||||||
|
await hass.services.async_call(
|
||||||
|
CLIMATE_DOMAIN,
|
||||||
|
SERVICE_SET_TEMPERATURE,
|
||||||
|
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_TEMPERATURE: 22},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Set Fan Mode: Success
|
||||||
|
await hass.services.async_call(
|
||||||
|
CLIMATE_DOMAIN,
|
||||||
|
SERVICE_SET_FAN_MODE,
|
||||||
|
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_FAN_MODE: FAN_SILENT},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
mock_palazzetti_client.set_fan_silent.assert_called_once()
|
||||||
|
mock_palazzetti_client.set_fan_silent.reset_mock()
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
CLIMATE_DOMAIN,
|
||||||
|
SERVICE_SET_FAN_MODE,
|
||||||
|
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_FAN_MODE: FAN_HIGH},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
mock_palazzetti_client.set_fan_high.assert_called_once()
|
||||||
|
mock_palazzetti_client.set_fan_high.reset_mock()
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
CLIMATE_DOMAIN,
|
||||||
|
SERVICE_SET_FAN_MODE,
|
||||||
|
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_FAN_MODE: FAN_AUTO},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
mock_palazzetti_client.set_fan_auto.assert_called_once()
|
||||||
|
mock_palazzetti_client.set_fan_auto.reset_mock()
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
CLIMATE_DOMAIN,
|
||||||
|
SERVICE_SET_FAN_MODE,
|
||||||
|
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_FAN_MODE: "3"},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
mock_palazzetti_client.set_fan_speed.assert_called_once_with(3)
|
||||||
|
mock_palazzetti_client.set_fan_speed.reset_mock()
|
||||||
|
|
||||||
|
# Set Fan Mode: Error
|
||||||
|
mock_palazzetti_client.set_fan_speed.side_effect = CommunicationError()
|
||||||
|
with pytest.raises(HomeAssistantError):
|
||||||
|
await hass.services.async_call(
|
||||||
|
CLIMATE_DOMAIN,
|
||||||
|
SERVICE_SET_FAN_MODE,
|
||||||
|
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_FAN_MODE: 3},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
mock_palazzetti_client.set_fan_speed.side_effect = ValidationError()
|
||||||
|
with pytest.raises(ServiceValidationError):
|
||||||
|
await hass.services.async_call(
|
||||||
|
CLIMATE_DOMAIN,
|
||||||
|
SERVICE_SET_FAN_MODE,
|
||||||
|
{ATTR_ENTITY_ID: ENTITY_ID, ATTR_FAN_MODE: 3},
|
||||||
|
blocking=True,
|
||||||
|
)
|
94
tests/components/palazzetti/test_config_flow.py
Normal file
94
tests/components/palazzetti/test_config_flow.py
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
"""Test the Palazzetti config flow."""
|
||||||
|
|
||||||
|
from unittest.mock import AsyncMock
|
||||||
|
|
||||||
|
from pypalazzetti.exceptions import CommunicationError
|
||||||
|
|
||||||
|
from homeassistant.components.palazzetti.const import DOMAIN
|
||||||
|
from homeassistant.config_entries import SOURCE_USER
|
||||||
|
from homeassistant.const import CONF_HOST
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.data_entry_flow import FlowResultType
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
|
async def test_full_user_flow(
|
||||||
|
hass: HomeAssistant, mock_palazzetti_client: AsyncMock, mock_setup_entry: AsyncMock
|
||||||
|
) -> None:
|
||||||
|
"""Test the full user configuration flow."""
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={"source": SOURCE_USER}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] is FlowResultType.FORM
|
||||||
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
user_input={CONF_HOST: "192.168.1.1"},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||||
|
assert result["title"] == "Stove"
|
||||||
|
assert result["data"] == {CONF_HOST: "192.168.1.1"}
|
||||||
|
assert result["result"].unique_id == "11:22:33:44:55:66"
|
||||||
|
assert len(mock_palazzetti_client.connect.mock_calls) > 0
|
||||||
|
|
||||||
|
|
||||||
|
async def test_invalid_host(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_palazzetti_client: AsyncMock,
|
||||||
|
mock_setup_entry: AsyncMock,
|
||||||
|
) -> None:
|
||||||
|
"""Test cannot connect error."""
|
||||||
|
|
||||||
|
mock_palazzetti_client.connect.side_effect = CommunicationError()
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN, context={"source": SOURCE_USER}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] is FlowResultType.FORM
|
||||||
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
user_input={CONF_HOST: "192.168.1.1"},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] is FlowResultType.FORM
|
||||||
|
assert result["errors"] == {"base": "cannot_connect"}
|
||||||
|
|
||||||
|
mock_palazzetti_client.connect.side_effect = None
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
user_input={CONF_HOST: "192.168.1.1"},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] is FlowResultType.CREATE_ENTRY
|
||||||
|
|
||||||
|
|
||||||
|
async def test_duplicate(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_palazzetti_client: AsyncMock,
|
||||||
|
mock_setup_entry: AsyncMock,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
) -> None:
|
||||||
|
"""Test duplicate flow."""
|
||||||
|
mock_config_entry.add_to_hass(hass)
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_init(
|
||||||
|
DOMAIN,
|
||||||
|
context={"source": SOURCE_USER},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] is FlowResultType.FORM
|
||||||
|
assert result["step_id"] == "user"
|
||||||
|
|
||||||
|
result = await hass.config_entries.flow.async_configure(
|
||||||
|
result["flow_id"],
|
||||||
|
{CONF_HOST: "192.168.1.1"},
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result["type"] is FlowResultType.ABORT
|
||||||
|
assert result["reason"] == "already_configured"
|
46
tests/components/palazzetti/test_init.py
Normal file
46
tests/components/palazzetti/test_init.py
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
"""Tests for the Palazzetti integration."""
|
||||||
|
|
||||||
|
from unittest.mock import AsyncMock
|
||||||
|
|
||||||
|
from syrupy import SnapshotAssertion
|
||||||
|
|
||||||
|
from homeassistant.config_entries import ConfigEntryState
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.helpers import device_registry as dr
|
||||||
|
|
||||||
|
from . import setup_integration
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
|
async def test_load_unload_config_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
mock_palazzetti_client: AsyncMock,
|
||||||
|
) -> None:
|
||||||
|
"""Test the Palazzetti configuration entry loading/unloading."""
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
|
assert mock_config_entry.state is ConfigEntryState.LOADED
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
async def test_device(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
mock_config_entry: MockConfigEntry,
|
||||||
|
mock_palazzetti_client: AsyncMock,
|
||||||
|
snapshot: SnapshotAssertion,
|
||||||
|
device_registry: dr.DeviceRegistry,
|
||||||
|
) -> None:
|
||||||
|
"""Test the device information."""
|
||||||
|
await setup_integration(hass, mock_config_entry)
|
||||||
|
|
||||||
|
device = device_registry.async_get_device(
|
||||||
|
connections={(dr.CONNECTION_NETWORK_MAC, "11:22:33:44:55:66")}
|
||||||
|
)
|
||||||
|
assert device is not None
|
||||||
|
assert device == snapshot
|
Loading…
x
Reference in New Issue
Block a user