Skip to content

Commit

Permalink
Add sensors for external probes (#8)
Browse files Browse the repository at this point in the history
Expose the external probe temperature for any thermostats with one enabled.

Sensors are disabled/hidden by default if the external probe is not enabled.

Fixes #7
  • Loading branch information
tonyroberts authored Nov 14, 2023
1 parent b5c2b72 commit 91fff6c
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 22 deletions.
75 changes: 56 additions & 19 deletions custom_components/wundasmart/sensor.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Support for WundaSmart sensors."""
from __future__ import annotations
from dataclasses import dataclass, asdict
import itertools

from homeassistant.core import HomeAssistant, callback
Expand Down Expand Up @@ -29,32 +30,48 @@ def _number_or_none(x):
return None


ROOM_SENSORS: list[SensorEntityDescription] = [
SensorEntityDescription(
@dataclass
class WundaSensorDescription(SensorEntityDescription):
available: bool | callable = True
default: float | None = None


ROOM_SENSORS: list[WundaSensorDescription] = [
WundaSensorDescription(
key="temp",
name="Temperature",
icon="mdi:thermometer",
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
WundaSensorDescription(
key="rh",
name="Humidity",
icon="mdi:water-percent",
native_unit_of_measurement=PERCENTAGE,
device_class=SensorDeviceClass.HUMIDITY,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
WundaSensorDescription(
key="temp_ext",
name="External Probe Temperature",
icon="mdi:thermometer",
available=lambda state: bool(int(state.get("ext", 0))),
default=0.0,
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
),
WundaSensorDescription(
key="bat",
name="Battery Level",
icon=lambda x: icon_for_battery_level(_number_or_none(x)),
native_unit_of_measurement=PERCENTAGE,
device_class=SensorDeviceClass.HUMIDITY,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
WundaSensorDescription(
key="sig",
name="Signal Level",
icon=lambda x: icon_for_signal_level(_number_or_none(x)),
Expand All @@ -64,52 +81,52 @@ def _number_or_none(x):
)
]

TRV_SENSORS: list[SensorEntityDescription] = [
SensorEntityDescription(
TRV_SENSORS: list[WundaSensorDescription] = [
WundaSensorDescription(
key="vtemp",
name="Temperature",
icon="mdi:thermometer",
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
device_class=SensorDeviceClass.TEMPERATURE,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
WundaSensorDescription(
key="bat",
name="Battery Level",
icon=lambda x: icon_for_battery_level(_number_or_none(x)),
native_unit_of_measurement=PERCENTAGE,
device_class=SensorDeviceClass.HUMIDITY,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
WundaSensorDescription(
key="sig",
name="Signal Level",
icon=lambda x: icon_for_signal_level(_number_or_none(x)),
native_unit_of_measurement=PERCENTAGE,
device_class=SensorDeviceClass.HUMIDITY,
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
WundaSensorDescription(
key="vpos",
name="Position",
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
WundaSensorDescription(
key="vpos_min",
name="Position Min",
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
WundaSensorDescription(
key="vpos_range",
name="Position Range",
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
WundaSensorDescription(
key="downforce",
name="Downforce",
state_class=SensorStateClass.MEASUREMENT,
),
SensorEntityDescription(
WundaSensorDescription(
key="trv_range",
name="TRV Range",
state_class=SensorStateClass.MEASUREMENT,
Expand Down Expand Up @@ -185,28 +202,48 @@ def __init__(
wunda_id: str,
name: str,
coordinator: WundasmartDataUpdateCoordinator,
description: SensorEntityDescription,
description: WundaSensorDescription,
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator)
self._wunda_id = wunda_id
self._coordinator = coordinator
self._attr_name = name

if (device_sn := coordinator.device_sn) is not None:
self._attr_unique_id = f"{device_sn}.{wunda_id}.{description.key}"
self._attr_device_info = coordinator.device_info

self.entity_description = description
self._coordinator = coordinator
self.entity_description = self.__update_description_defaults(description)

# Update with initial state
self.__update_state()

@property
def available(self):
return self.__is_available(self.entity_description)

def __is_available(self, description: WundaSensorDescription):
if callable(description.available):
device = self.coordinator.data.get(self._wunda_id, {})
state = device.get("state", {})
return description.available(state)
return description.available

def __update_description_defaults(self, description: WundaSensorDescription):
kwargs = asdict(description)
available = self.__is_available(description)
kwargs["entity_registry_enabled_default"] = available
kwargs["entity_registry_visible_default"] = available
return WundaSensorDescription(**kwargs)

def __update_state(self):
device = self.coordinator.data.get(self._wunda_id, {})
state = device.get("state", {})
self._attr_available = True
self._attr_native_value = state.get(self.entity_description.key)
value = state.get(self.entity_description.key)
if not value and self.entity_description.default is not None:
value = self.entity_description.default
self._attr_native_value = value

@callback
def _handle_coordinator_update(self) -> None:
Expand Down
6 changes: 3 additions & 3 deletions tests/fixtures/test_get_devices1.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
"v": "1.8",
"temp": "17.8",
"rh": "66.57",
"temp_ext": "",
"ext": "0",
"temp_ext": "18.0",
"ext": "1",
"bat": "100",
"sig": "88",
"alarm": "0"
Expand Down Expand Up @@ -55,7 +55,7 @@
"t_norm": "19.00",
"t_hi": "21.00",
"heat": "4",
"temp_pre": "0",
"temp_pre": "4",
"prg": "1",
"lock": "0",
"temp": "0.00",
Expand Down
4 changes: 4 additions & 0 deletions tests/test_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ async def test_sensors(hass: HomeAssistant, config):
assert trv_signal_state.state == "88"
assert trv_signal_state.attributes["icon"] == "mdi:signal-cellular-3"

ext_temp_state = hass.states.get("sensor.test_room_external_probe_temperature")
assert ext_temp_state
assert ext_temp_state.state == "18.0"

coordinator: DataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
assert coordinator

Expand Down

0 comments on commit 91fff6c

Please sign in to comment.