mirror of
https://github.com/home-assistant/core.git
synced 2025-04-24 01:08:12 +00:00
Replace climate fan speed 'silent' with a button (#135075)
This commit is contained in:
parent
fc6695b05c
commit
e1ffd9380d
@ -7,7 +7,12 @@ from homeassistant.core import HomeAssistant
|
||||
|
||||
from .coordinator import PalazzettiConfigEntry, PalazzettiDataUpdateCoordinator
|
||||
|
||||
PLATFORMS: list[Platform] = [Platform.CLIMATE, Platform.NUMBER, Platform.SENSOR]
|
||||
PLATFORMS: list[Platform] = [
|
||||
Platform.BUTTON,
|
||||
Platform.CLIMATE,
|
||||
Platform.NUMBER,
|
||||
Platform.SENSOR,
|
||||
]
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, entry: PalazzettiConfigEntry) -> bool:
|
||||
|
52
homeassistant/components/palazzetti/button.py
Normal file
52
homeassistant/components/palazzetti/button.py
Normal file
@ -0,0 +1,52 @@
|
||||
"""Support for Palazzetti buttons."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pypalazzetti.exceptions import CommunicationError
|
||||
|
||||
from homeassistant.components.button import ButtonEntity
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import PalazzettiConfigEntry
|
||||
from .const import DOMAIN
|
||||
from .coordinator import PalazzettiDataUpdateCoordinator
|
||||
from .entity import PalazzettiEntity
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: PalazzettiConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Palazzetti button platform."""
|
||||
|
||||
coordinator = config_entry.runtime_data
|
||||
if coordinator.client.has_fan_silent:
|
||||
async_add_entities([PalazzettiSilentButtonEntity(coordinator)])
|
||||
|
||||
|
||||
class PalazzettiSilentButtonEntity(PalazzettiEntity, ButtonEntity):
|
||||
"""Representation of a Palazzetti Silent button."""
|
||||
|
||||
_attr_translation_key = "silent"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: PalazzettiDataUpdateCoordinator,
|
||||
) -> None:
|
||||
"""Initialize a Palazzetti Silent button."""
|
||||
super().__init__(coordinator)
|
||||
self._attr_unique_id = f"{coordinator.config_entry.unique_id}-silent"
|
||||
|
||||
async def async_press(self) -> None:
|
||||
"""Press the button."""
|
||||
try:
|
||||
await self.coordinator.client.set_fan_silent()
|
||||
except CommunicationError as err:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN, translation_key="cannot_connect"
|
||||
) from err
|
||||
|
||||
await self.coordinator.async_request_refresh()
|
@ -16,7 +16,7 @@ from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import PalazzettiConfigEntry
|
||||
from .const import DOMAIN, FAN_AUTO, FAN_HIGH, FAN_MODES, FAN_SILENT
|
||||
from .const import DOMAIN, FAN_AUTO, FAN_HIGH, FAN_MODES
|
||||
from .coordinator import PalazzettiDataUpdateCoordinator
|
||||
from .entity import PalazzettiEntity
|
||||
|
||||
@ -57,8 +57,6 @@ class PalazzettiClimateEntity(PalazzettiEntity, ClimateEntity):
|
||||
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:
|
||||
@ -130,9 +128,7 @@ class PalazzettiClimateEntity(PalazzettiEntity, ClimateEntity):
|
||||
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:
|
||||
if fan_mode == FAN_HIGH:
|
||||
await self.coordinator.client.set_fan_high()
|
||||
elif fan_mode == FAN_AUTO:
|
||||
await self.coordinator.client.set_fan_auto()
|
||||
|
@ -18,7 +18,7 @@ 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]
|
||||
FAN_MODES: Final = ["0", "1", "2", "3", "4", "5", FAN_HIGH, FAN_AUTO]
|
||||
|
||||
STATUS_TO_HA: Final[dict[StateType, str]] = {
|
||||
0: "off",
|
||||
|
9
homeassistant/components/palazzetti/icons.json
Normal file
9
homeassistant/components/palazzetti/icons.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"entity": {
|
||||
"button": {
|
||||
"silent": {
|
||||
"default": "mdi:volume-mute"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -67,9 +67,7 @@ rules:
|
||||
entity-translations: done
|
||||
exception-translations: done
|
||||
icon-translations:
|
||||
status: exempt
|
||||
comment: |
|
||||
This integration does not have custom icons.
|
||||
status: done
|
||||
reconfiguration-flow: todo
|
||||
repair-issues:
|
||||
status: exempt
|
||||
|
@ -38,6 +38,11 @@
|
||||
}
|
||||
},
|
||||
"entity": {
|
||||
"button": {
|
||||
"silent": {
|
||||
"name": "Silent"
|
||||
}
|
||||
},
|
||||
"climate": {
|
||||
"palazzetti": {
|
||||
"state_attributes": {
|
||||
|
47
tests/components/palazzetti/snapshots/test_button.ambr
Normal file
47
tests/components/palazzetti/snapshots/test_button.ambr
Normal file
@ -0,0 +1,47 @@
|
||||
# serializer version: 1
|
||||
# name: test_all_entities[button.stove_silent-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'button',
|
||||
'entity_category': None,
|
||||
'entity_id': 'button.stove_silent',
|
||||
'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': 'Silent',
|
||||
'platform': 'palazzetti',
|
||||
'previous_unique_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'silent',
|
||||
'unique_id': '11:22:33:44:55:66-silent',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[button.stove_silent-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Stove Silent',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'button.stove_silent',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
@ -6,7 +6,6 @@
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'fan_modes': list([
|
||||
'silent',
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
@ -56,7 +55,6 @@
|
||||
'current_temperature': 18,
|
||||
'fan_mode': '3',
|
||||
'fan_modes': list([
|
||||
'silent',
|
||||
'1',
|
||||
'2',
|
||||
'3',
|
||||
|
69
tests/components/palazzetti/test_button.py
Normal file
69
tests/components/palazzetti/test_button.py
Normal file
@ -0,0 +1,69 @@
|
||||
"""Tests for the Palazzetti button platform."""
|
||||
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from pypalazzetti.exceptions import CommunicationError
|
||||
import pytest
|
||||
from syrupy import SnapshotAssertion
|
||||
|
||||
from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN, SERVICE_PRESS
|
||||
from homeassistant.const import ATTR_ENTITY_ID, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from . import setup_integration
|
||||
|
||||
from tests.common import MockConfigEntry, snapshot_platform
|
||||
|
||||
ENTITY_ID = "button.stove_silent"
|
||||
|
||||
|
||||
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.BUTTON]):
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
|
||||
|
||||
async def test_async_press(
|
||||
hass: HomeAssistant,
|
||||
mock_palazzetti_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test pressing via service call."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
await hass.services.async_call(
|
||||
BUTTON_DOMAIN,
|
||||
SERVICE_PRESS,
|
||||
{ATTR_ENTITY_ID: ENTITY_ID},
|
||||
blocking=True,
|
||||
)
|
||||
mock_palazzetti_client.set_fan_silent.assert_called_once()
|
||||
|
||||
|
||||
async def test_async_press_error(
|
||||
hass: HomeAssistant,
|
||||
mock_palazzetti_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
) -> None:
|
||||
"""Test pressing with error via service call."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
mock_palazzetti_client.set_fan_silent.side_effect = CommunicationError()
|
||||
error_message = "Could not connect to the device"
|
||||
with pytest.raises(HomeAssistantError, match=error_message):
|
||||
await hass.services.async_call(
|
||||
BUTTON_DOMAIN,
|
||||
SERVICE_PRESS,
|
||||
{ATTR_ENTITY_ID: ENTITY_ID},
|
||||
blocking=True,
|
||||
)
|
@ -15,7 +15,7 @@ from homeassistant.components.climate import (
|
||||
SERVICE_SET_TEMPERATURE,
|
||||
HVACMode,
|
||||
)
|
||||
from homeassistant.components.palazzetti.const import FAN_AUTO, FAN_HIGH, FAN_SILENT
|
||||
from homeassistant.components.palazzetti.const import FAN_AUTO, FAN_HIGH
|
||||
from homeassistant.const import ATTR_ENTITY_ID, ATTR_TEMPERATURE, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
|
||||
@ -118,15 +118,6 @@ async def test_async_set_data(
|
||||
)
|
||||
|
||||
# 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,
|
||||
|
@ -49,7 +49,7 @@ async def test_async_set_data(
|
||||
blocking=True,
|
||||
)
|
||||
mock_palazzetti_client.set_power_mode.assert_called_once_with(1)
|
||||
mock_palazzetti_client.set_on.reset_mock()
|
||||
mock_palazzetti_client.set_power_mode.reset_mock()
|
||||
|
||||
# Set value: Error
|
||||
mock_palazzetti_client.set_power_mode.side_effect = CommunicationError()
|
||||
@ -60,7 +60,7 @@ async def test_async_set_data(
|
||||
{ATTR_ENTITY_ID: ENTITY_ID, "value": 1},
|
||||
blocking=True,
|
||||
)
|
||||
mock_palazzetti_client.set_on.reset_mock()
|
||||
mock_palazzetti_client.set_power_mode.reset_mock()
|
||||
|
||||
mock_palazzetti_client.set_power_mode.side_effect = ValidationError()
|
||||
with pytest.raises(ServiceValidationError):
|
||||
|
Loading…
x
Reference in New Issue
Block a user