Skip to content

Commit 2efc75f

Browse files
Add base entity to Mill (home-assistant#134415)
1 parent a435fd1 commit 2efc75f

File tree

4 files changed

+93
-94
lines changed

4 files changed

+93
-94
lines changed

homeassistant/components/mill/climate.py

Lines changed: 17 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
SERVICE_SET_ROOM_TEMP,
4242
)
4343
from .coordinator import MillDataUpdateCoordinator
44+
from .entity import MillBaseEntity
4445

4546
SET_ROOM_TEMP_SCHEMA = vol.Schema(
4647
{
@@ -85,10 +86,9 @@ async def set_room_temp(service: ServiceCall) -> None:
8586
)
8687

8788

88-
class MillHeater(CoordinatorEntity[MillDataUpdateCoordinator], ClimateEntity):
89+
class MillHeater(MillBaseEntity, ClimateEntity):
8990
"""Representation of a Mill Thermostat device."""
9091

91-
_attr_has_entity_name = True
9292
_attr_hvac_modes = [HVACMode.HEAT, HVACMode.OFF]
9393
_attr_max_temp = MAX_TEMP
9494
_attr_min_temp = MIN_TEMP
@@ -102,24 +102,13 @@ class MillHeater(CoordinatorEntity[MillDataUpdateCoordinator], ClimateEntity):
102102
_attr_temperature_unit = UnitOfTemperature.CELSIUS
103103

104104
def __init__(
105-
self, coordinator: MillDataUpdateCoordinator, heater: mill.Heater
105+
self, coordinator: MillDataUpdateCoordinator, device: mill.Heater
106106
) -> None:
107107
"""Initialize the thermostat."""
108108

109-
super().__init__(coordinator)
110-
111-
self._available = False
112-
113-
self._id = heater.device_id
114-
self._attr_unique_id = heater.device_id
115-
self._attr_device_info = DeviceInfo(
116-
identifiers={(DOMAIN, heater.device_id)},
117-
manufacturer=MANUFACTURER,
118-
model=heater.model,
119-
name=heater.name,
120-
)
121-
122-
self._update_attr(heater)
109+
super().__init__(coordinator, device)
110+
self._attr_unique_id = device.device_id
111+
self._update_attr(device)
123112

124113
async def async_set_temperature(self, **kwargs: Any) -> None:
125114
"""Set new target temperature."""
@@ -143,36 +132,25 @@ async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
143132
)
144133
await self.coordinator.async_request_refresh()
145134

146-
@property
147-
def available(self) -> bool:
148-
"""Return True if entity is available."""
149-
return super().available and self._available
150-
151-
@callback
152-
def _handle_coordinator_update(self) -> None:
153-
"""Handle updated data from the coordinator."""
154-
self._update_attr(self.coordinator.data[self._id])
155-
self.async_write_ha_state()
156-
157135
@callback
158-
def _update_attr(self, heater):
159-
self._available = heater.available
136+
def _update_attr(self, device: mill.Heater) -> None:
137+
self._available = device.available
160138
self._attr_extra_state_attributes = {
161-
"open_window": heater.open_window,
162-
"controlled_by_tibber": heater.tibber_control,
139+
"open_window": device.open_window,
140+
"controlled_by_tibber": device.tibber_control,
163141
}
164-
if heater.room_name:
165-
self._attr_extra_state_attributes["room"] = heater.room_name
166-
self._attr_extra_state_attributes["avg_room_temp"] = heater.room_avg_temp
142+
if device.room_name:
143+
self._attr_extra_state_attributes["room"] = device.room_name
144+
self._attr_extra_state_attributes["avg_room_temp"] = device.room_avg_temp
167145
else:
168146
self._attr_extra_state_attributes["room"] = "Independent device"
169-
self._attr_target_temperature = heater.set_temp
170-
self._attr_current_temperature = heater.current_temp
171-
if heater.is_heating:
147+
self._attr_target_temperature = device.set_temp
148+
self._attr_current_temperature = device.current_temp
149+
if device.is_heating:
172150
self._attr_hvac_action = HVACAction.HEATING
173151
else:
174152
self._attr_hvac_action = HVACAction.IDLE
175-
if heater.power_status:
153+
if device.power_status:
176154
self._attr_hvac_mode = HVACMode.HEAT
177155
else:
178156
self._attr_hvac_mode = HVACMode.OFF
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
"""Base entity for Mill devices."""
2+
3+
from __future__ import annotations
4+
5+
from abc import abstractmethod
6+
7+
from mill import Heater, MillDevice
8+
9+
from homeassistant.core import callback
10+
from homeassistant.helpers.device_registry import DeviceInfo
11+
from homeassistant.helpers.update_coordinator import CoordinatorEntity
12+
13+
from .const import DOMAIN, MANUFACTURER
14+
from .coordinator import MillDataUpdateCoordinator
15+
16+
17+
class MillBaseEntity(CoordinatorEntity[MillDataUpdateCoordinator]):
18+
"""Representation of a Mill number device."""
19+
20+
_attr_has_entity_name = True
21+
22+
def __init__(
23+
self,
24+
coordinator: MillDataUpdateCoordinator,
25+
mill_device: MillDevice,
26+
) -> None:
27+
"""Initialize the number."""
28+
super().__init__(coordinator)
29+
30+
self._id = mill_device.device_id
31+
self._available = False
32+
self._attr_device_info = DeviceInfo(
33+
identifiers={(DOMAIN, mill_device.device_id)},
34+
name=mill_device.name,
35+
manufacturer=MANUFACTURER,
36+
model=mill_device.model,
37+
)
38+
self._update_attr(mill_device)
39+
40+
@callback
41+
def _handle_coordinator_update(self) -> None:
42+
"""Handle updated data from the coordinator."""
43+
self._update_attr(self.coordinator.data[self._id])
44+
self.async_write_ha_state()
45+
46+
@abstractmethod
47+
@callback
48+
def _update_attr(self, device: MillDevice | Heater) -> None:
49+
"""Update the attribute of the entity."""
50+
51+
@property
52+
def available(self) -> bool:
53+
"""Return True if entity is available."""
54+
return super().available and self._available

homeassistant/components/mill/number.py

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,11 @@
88
from homeassistant.config_entries import ConfigEntry
99
from homeassistant.const import CONF_USERNAME, UnitOfPower
1010
from homeassistant.core import HomeAssistant, callback
11-
from homeassistant.helpers.device_registry import DeviceInfo
1211
from homeassistant.helpers.entity_platform import AddEntitiesCallback
13-
from homeassistant.helpers.update_coordinator import CoordinatorEntity
1412

15-
from .const import CLOUD, CONNECTION_TYPE, DOMAIN, MANUFACTURER
13+
from .const import CLOUD, CONNECTION_TYPE, DOMAIN
1614
from .coordinator import MillDataUpdateCoordinator
15+
from .entity import MillBaseEntity
1716

1817

1918
async def async_setup_entry(
@@ -31,11 +30,10 @@ async def async_setup_entry(
3130
)
3231

3332

34-
class MillNumber(CoordinatorEntity[MillDataUpdateCoordinator], NumberEntity):
33+
class MillNumber(MillBaseEntity, NumberEntity):
3534
"""Representation of a Mill number device."""
3635

3736
_attr_device_class = NumberDeviceClass.POWER
38-
_attr_has_entity_name = True
3937
_attr_native_max_value = 2000
4038
_attr_native_min_value = 0
4139
_attr_native_step = 1
@@ -47,37 +45,17 @@ def __init__(
4745
mill_device: MillDevice,
4846
) -> None:
4947
"""Initialize the number."""
50-
super().__init__(coordinator)
51-
52-
self._id = mill_device.device_id
53-
self._available = False
48+
super().__init__(coordinator, mill_device)
5449
self._attr_unique_id = f"{mill_device.device_id}_max_heating_power"
55-
self._attr_device_info = DeviceInfo(
56-
identifiers={(DOMAIN, mill_device.device_id)},
57-
name=mill_device.name,
58-
manufacturer=MANUFACTURER,
59-
model=mill_device.model,
60-
)
6150
self._update_attr(mill_device)
6251

63-
@callback
64-
def _handle_coordinator_update(self) -> None:
65-
"""Handle updated data from the coordinator."""
66-
self._update_attr(self.coordinator.data[self._id])
67-
self.async_write_ha_state()
68-
6952
@callback
7053
def _update_attr(self, device: MillDevice) -> None:
7154
self._attr_native_value = device.data["deviceSettings"]["reported"].get(
7255
"max_heater_power"
7356
)
7457
self._available = device.available and self._attr_native_value is not None
7558

76-
@property
77-
def available(self) -> bool:
78-
"""Return True if entity is available."""
79-
return super().available and self._available
80-
8159
async def async_set_native_value(self, value: float) -> None:
8260
"""Set new value."""
8361
await self.coordinator.mill_data_connection.max_heating_power(self._id, value)

homeassistant/components/mill/sensor.py

Lines changed: 18 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from homeassistant.core import HomeAssistant, callback
2626
from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo
2727
from homeassistant.helpers.entity_platform import AddEntitiesCallback
28+
from homeassistant.helpers.typing import StateType
2829
from homeassistant.helpers.update_coordinator import CoordinatorEntity
2930

3031
from .const import (
@@ -41,6 +42,8 @@
4142
TEMPERATURE,
4243
TVOC,
4344
)
45+
from .coordinator import MillDataUpdateCoordinator
46+
from .entity import MillBaseEntity
4447

4548
HEATER_SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
4649
SensorEntityDescription(
@@ -179,50 +182,36 @@ async def async_setup_entry(
179182
async_add_entities(entities)
180183

181184

182-
class MillSensor(CoordinatorEntity, SensorEntity):
185+
class MillSensor(MillBaseEntity, SensorEntity):
183186
"""Representation of a Mill Sensor device."""
184187

185-
_attr_has_entity_name = True
186-
187-
def __init__(self, coordinator, entity_description, mill_device):
188+
def __init__(
189+
self,
190+
coordinator: MillDataUpdateCoordinator,
191+
entity_description: SensorEntityDescription,
192+
mill_device: mill.Socket | mill.Heater,
193+
) -> None:
188194
"""Initialize the sensor."""
189-
super().__init__(coordinator)
190-
191-
self._id = mill_device.device_id
195+
super().__init__(coordinator, mill_device)
192196
self.entity_description = entity_description
193-
self._available = False
194197
self._attr_unique_id = f"{mill_device.device_id}_{entity_description.key}"
195-
self._attr_device_info = DeviceInfo(
196-
identifiers={(DOMAIN, mill_device.device_id)},
197-
name=mill_device.name,
198-
manufacturer=MANUFACTURER,
199-
model=mill_device.model,
200-
)
201-
self._update_attr(mill_device)
202-
203-
@callback
204-
def _handle_coordinator_update(self) -> None:
205-
"""Handle updated data from the coordinator."""
206-
self._update_attr(self.coordinator.data[self._id])
207-
self.async_write_ha_state()
208-
209-
@property
210-
def available(self) -> bool:
211-
"""Return True if entity is available."""
212-
return super().available and self._available
213198

214199
@callback
215200
def _update_attr(self, device):
216201
self._available = device.available
217202
self._attr_native_value = getattr(device, self.entity_description.key)
218203

219204

220-
class LocalMillSensor(CoordinatorEntity, SensorEntity):
205+
class LocalMillSensor(CoordinatorEntity[MillDataUpdateCoordinator], SensorEntity):
221206
"""Representation of a Mill Sensor device."""
222207

223208
_attr_has_entity_name = True
224209

225-
def __init__(self, coordinator, entity_description):
210+
def __init__(
211+
self,
212+
coordinator: MillDataUpdateCoordinator,
213+
entity_description: SensorEntityDescription,
214+
) -> None:
226215
"""Initialize the sensor."""
227216
super().__init__(coordinator)
228217

@@ -239,6 +228,6 @@ def __init__(self, coordinator, entity_description):
239228
)
240229

241230
@property
242-
def native_value(self):
231+
def native_value(self) -> StateType:
243232
"""Return the native value of the sensor."""
244233
return self.coordinator.data[self.entity_description.key]

0 commit comments

Comments
 (0)