Add Plugwise number platform (#74655)
parent
b7a6f4e220
commit
34f1d5e094
|
@ -25,8 +25,9 @@ UNIT_LUMEN: Final = "lm"
|
|||
PLATFORMS_GATEWAY: Final[list[str]] = [
|
||||
Platform.BINARY_SENSOR,
|
||||
Platform.CLIMATE,
|
||||
Platform.SENSOR,
|
||||
Platform.NUMBER,
|
||||
Platform.SELECT,
|
||||
Platform.SENSOR,
|
||||
Platform.SWITCH,
|
||||
]
|
||||
ZEROCONF_MAP: Final[dict[str, str]] = {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"domain": "plugwise",
|
||||
"name": "Plugwise",
|
||||
"documentation": "https://www.home-assistant.io/integrations/plugwise",
|
||||
"requirements": ["plugwise==0.18.5"],
|
||||
"requirements": ["plugwise==0.18.6"],
|
||||
"codeowners": ["@CoMPaTech", "@bouwew", "@brefra", "@frenck"],
|
||||
"zeroconf": ["_plugwise._tcp.local."],
|
||||
"config_flow": true,
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
"""Number platform for Plugwise integration."""
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Awaitable, Callable
|
||||
from dataclasses import dataclass
|
||||
|
||||
from plugwise import Smile
|
||||
|
||||
from homeassistant.components.number import (
|
||||
NumberDeviceClass,
|
||||
NumberEntity,
|
||||
NumberEntityDescription,
|
||||
NumberMode,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import TEMP_CELSIUS
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity import EntityCategory
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .const import DOMAIN
|
||||
from .coordinator import PlugwiseDataUpdateCoordinator
|
||||
from .entity import PlugwiseEntity
|
||||
|
||||
|
||||
@dataclass
|
||||
class PlugwiseEntityDescriptionMixin:
|
||||
"""Mixin values for Plugwse entities."""
|
||||
|
||||
command: Callable[[Smile, float], Awaitable[None]]
|
||||
|
||||
|
||||
@dataclass
|
||||
class PlugwiseNumberEntityDescription(
|
||||
NumberEntityDescription, PlugwiseEntityDescriptionMixin
|
||||
):
|
||||
"""Class describing Plugwise Number entities."""
|
||||
|
||||
|
||||
NUMBER_TYPES = (
|
||||
PlugwiseNumberEntityDescription(
|
||||
key="maximum_boiler_temperature",
|
||||
command=lambda api, value: api.set_max_boiler_temperature(value),
|
||||
device_class=NumberDeviceClass.TEMPERATURE,
|
||||
name="Maximum Boiler Temperature Setpoint",
|
||||
entity_category=EntityCategory.CONFIG,
|
||||
native_unit_of_measurement=TEMP_CELSIUS,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Plugwise number platform."""
|
||||
|
||||
coordinator: PlugwiseDataUpdateCoordinator = hass.data[DOMAIN][
|
||||
config_entry.entry_id
|
||||
]
|
||||
|
||||
entities: list[PlugwiseNumberEntity] = []
|
||||
for device_id, device in coordinator.data.devices.items():
|
||||
for description in NUMBER_TYPES:
|
||||
if description.key in device:
|
||||
entities.append(
|
||||
PlugwiseNumberEntity(coordinator, device_id, description)
|
||||
)
|
||||
|
||||
async_add_entities(entities)
|
||||
|
||||
|
||||
class PlugwiseNumberEntity(PlugwiseEntity, NumberEntity):
|
||||
"""Representation of a Plugwise number."""
|
||||
|
||||
entity_description: PlugwiseNumberEntityDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: PlugwiseDataUpdateCoordinator,
|
||||
device_id: str,
|
||||
description: PlugwiseNumberEntityDescription,
|
||||
) -> None:
|
||||
"""Initiate Plugwise Number."""
|
||||
super().__init__(coordinator, device_id)
|
||||
self.entity_description = description
|
||||
self._attr_unique_id = f"{device_id}-{description.key}"
|
||||
self._attr_name = (f"{self.device['name']} {description.name}").lstrip()
|
||||
self._attr_mode = NumberMode.BOX
|
||||
|
||||
@property
|
||||
def native_step(self) -> float:
|
||||
"""Return the setpoint step value."""
|
||||
return max(self.device["resolution"], 1)
|
||||
|
||||
@property
|
||||
def native_value(self) -> float:
|
||||
"""Return the present setpoint value."""
|
||||
return self.device[self.entity_description.key]
|
||||
|
||||
@property
|
||||
def native_min_value(self) -> float:
|
||||
"""Return the setpoint min. value."""
|
||||
return self.device["lower_bound"]
|
||||
|
||||
@property
|
||||
def native_max_value(self) -> float:
|
||||
"""Return the setpoint max. value."""
|
||||
return self.device["upper_bound"]
|
||||
|
||||
async def async_set_native_value(self, value: float) -> None:
|
||||
"""Change to the new setpoint value."""
|
||||
await self.entity_description.command(self.coordinator.api, value)
|
||||
await self.coordinator.async_request_refresh()
|
|
@ -1254,7 +1254,7 @@ plexauth==0.0.6
|
|||
plexwebsocket==0.0.13
|
||||
|
||||
# homeassistant.components.plugwise
|
||||
plugwise==0.18.5
|
||||
plugwise==0.18.6
|
||||
|
||||
# homeassistant.components.plum_lightpad
|
||||
plumlightpad==0.0.11
|
||||
|
|
|
@ -862,7 +862,7 @@ plexauth==0.0.6
|
|||
plexwebsocket==0.0.13
|
||||
|
||||
# homeassistant.components.plugwise
|
||||
plugwise==0.18.5
|
||||
plugwise==0.18.6
|
||||
|
||||
# homeassistant.components.plum_lightpad
|
||||
plumlightpad==0.0.11
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
"model": "Generic heater",
|
||||
"name": "OpenTherm",
|
||||
"vendor": "Techneco",
|
||||
"lower_bound": 0.0,
|
||||
"upper_bound": 100.0,
|
||||
"resolution": 1.0,
|
||||
"maximum_boiler_temperature": 60.0,
|
||||
"binary_sensors": {
|
||||
"dhw_state": false,
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
"""Tests for the Plugwise Number integration."""
|
||||
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from homeassistant.components.number import (
|
||||
ATTR_VALUE,
|
||||
DOMAIN as NUMBER_DOMAIN,
|
||||
SERVICE_SET_VALUE,
|
||||
)
|
||||
from homeassistant.const import ATTR_ENTITY_ID
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
|
||||
async def test_anna_number_entities(
|
||||
hass: HomeAssistant, mock_smile_anna: MagicMock, init_integration: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test creation of a number."""
|
||||
state = hass.states.get("number.opentherm_maximum_boiler_temperature_setpoint")
|
||||
assert state
|
||||
assert float(state.state) == 60.0
|
||||
|
||||
|
||||
async def test_anna_max_boiler_temp_change(
|
||||
hass: HomeAssistant, mock_smile_anna: MagicMock, init_integration: MockConfigEntry
|
||||
) -> None:
|
||||
"""Test changing of number entities."""
|
||||
await hass.services.async_call(
|
||||
NUMBER_DOMAIN,
|
||||
SERVICE_SET_VALUE,
|
||||
{
|
||||
ATTR_ENTITY_ID: "number.opentherm_maximum_boiler_temperature_setpoint",
|
||||
ATTR_VALUE: 65,
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
|
||||
assert mock_smile_anna.set_max_boiler_temperature.call_count == 1
|
||||
mock_smile_anna.set_max_boiler_temperature.assert_called_with(65)
|
Loading…
Reference in New Issue