Add boost switch to Smarty (#129466)

This commit is contained in:
Marco 2024-11-01 06:08:55 -04:00 committed by GitHub
parent b626c9b450
commit 3b28bf07d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 203 additions and 1 deletions

View File

@ -30,7 +30,7 @@ CONFIG_SCHEMA = vol.Schema(
extra=vol.ALLOW_EXTRA,
)
PLATFORMS = [Platform.BINARY_SENSOR, Platform.FAN, Platform.SENSOR]
PLATFORMS = [Platform.BINARY_SENSOR, Platform.FAN, Platform.SENSOR, Platform.SWITCH]
async def async_setup(hass: HomeAssistant, hass_config: ConfigType) -> bool:

View File

@ -61,6 +61,11 @@
"filter_days_left": {
"name": "Filter days left"
}
},
"switch": {
"boost": {
"name": "Boost"
}
}
}
}

View File

@ -0,0 +1,90 @@
"""Platform to control a Salda Smarty XP/XV ventilation unit."""
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
import logging
from typing import Any
from pysmarty2 import Smarty
from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .coordinator import SmartyConfigEntry, SmartyCoordinator
from .entity import SmartyEntity
_LOGGER = logging.getLogger(__name__)
@dataclass(frozen=True, kw_only=True)
class SmartySwitchDescription(SwitchEntityDescription):
"""Class describing Smarty switch."""
is_on_fn: Callable[[Smarty], bool]
turn_on_fn: Callable[[Smarty], bool | None]
turn_off_fn: Callable[[Smarty], bool | None]
ENTITIES: tuple[SmartySwitchDescription, ...] = (
SmartySwitchDescription(
key="boost",
translation_key="boost",
is_on_fn=lambda smarty: smarty.boost,
turn_on_fn=lambda smarty: smarty.enable_boost(),
turn_off_fn=lambda smarty: smarty.disable_boost(),
),
)
async def async_setup_entry(
hass: HomeAssistant,
entry: SmartyConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the Smarty Switch Platform."""
coordinator = entry.runtime_data
async_add_entities(
SmartySwitch(coordinator, description) for description in ENTITIES
)
class SmartySwitch(SmartyEntity, SwitchEntity):
"""Representation of a Smarty Switch."""
entity_description: SmartySwitchDescription
def __init__(
self,
coordinator: SmartyCoordinator,
entity_description: SmartySwitchDescription,
) -> None:
"""Initialize the entity."""
super().__init__(coordinator)
self.entity_description = entity_description
self._attr_unique_id = (
f"{coordinator.config_entry.entry_id}_{entity_description.key}"
)
@property
def is_on(self) -> bool:
"""Return the state of the switch."""
return self.entity_description.is_on_fn(self.coordinator.client)
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the switch on."""
await self.hass.async_add_executor_job(
self.entity_description.turn_on_fn, self.coordinator.client
)
await self.coordinator.async_refresh()
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the switch off."""
await self.hass.async_add_executor_job(
self.entity_description.turn_off_fn, self.coordinator.client
)
await self.coordinator.async_refresh()

View File

@ -40,6 +40,8 @@ def mock_smarty() -> Generator[AsyncMock]:
client.warning = False
client.alarm = False
client.boost = False
client.enable_boost.return_value = True
client.disable_boost.return_value = True
client.supply_air_temperature = 20
client.extract_air_temperature = 23
client.outdoor_air_temperature = 24

View File

@ -0,0 +1,47 @@
# serializer version: 1
# name: test_all_entities[switch.mock_title_boost-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'switch',
'entity_category': None,
'entity_id': 'switch.mock_title_boost',
'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': 'Boost',
'platform': 'smarty',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'boost',
'unique_id': '01JAZ5DPW8C62D620DGYNG2R8H_boost',
'unit_of_measurement': None,
})
# ---
# name: test_all_entities[switch.mock_title_boost-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'friendly_name': 'Mock Title Boost',
}),
'context': <ANY>,
'entity_id': 'switch.mock_title_boost',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': 'off',
})
# ---

View File

@ -0,0 +1,58 @@
"""Tests for the Smarty switch platform."""
from unittest.mock import AsyncMock, patch
from syrupy import SnapshotAssertion
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
from homeassistant.const import (
ATTR_ENTITY_ID,
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
Platform,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from . import setup_integration
from tests.common import MockConfigEntry, snapshot_platform
async def test_all_entities(
hass: HomeAssistant,
snapshot: SnapshotAssertion,
mock_smarty: AsyncMock,
mock_config_entry: MockConfigEntry,
entity_registry: er.EntityRegistry,
) -> None:
"""Test all entities."""
with patch("homeassistant.components.smarty.PLATFORMS", [Platform.SWITCH]):
await setup_integration(hass, mock_config_entry)
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
async def test_setting_value(
hass: HomeAssistant,
mock_smarty: AsyncMock,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test setting value."""
await setup_integration(hass, mock_config_entry)
await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_ON,
target={ATTR_ENTITY_ID: "switch.mock_title_boost"},
blocking=True,
)
mock_smarty.enable_boost.assert_called_once_with()
await hass.services.async_call(
SWITCH_DOMAIN,
SERVICE_TURN_OFF,
target={ATTR_ENTITY_ID: "switch.mock_title_boost"},
blocking=True,
)
mock_smarty.disable_boost.assert_called_once_with()