Skip to content

Commit f07991d

Browse files
authored
Add boot and energy sensor to MyStrom Switch (home-assistant#155132)
1 parent 872fef1 commit f07991d

File tree

2 files changed

+101
-11
lines changed

2 files changed

+101
-11
lines changed

homeassistant/components/mystrom/sensor.py

Lines changed: 95 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
from collections.abc import Callable
66
from dataclasses import dataclass
7+
from datetime import datetime, timedelta
8+
from typing import Any
79

810
from pymystrom.switch import MyStromSwitch
911

@@ -13,10 +15,16 @@
1315
SensorEntityDescription,
1416
SensorStateClass,
1517
)
16-
from homeassistant.const import UnitOfPower, UnitOfTemperature
18+
from homeassistant.const import (
19+
EntityCategory,
20+
UnitOfEnergy,
21+
UnitOfPower,
22+
UnitOfTemperature,
23+
)
1724
from homeassistant.core import HomeAssistant
1825
from homeassistant.helpers.device_registry import DeviceInfo
1926
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
27+
from homeassistant.util.dt import utcnow
2028

2129
from .const import DOMAIN, MANUFACTURER
2230
from .models import MyStromConfigEntry
@@ -44,6 +52,15 @@ class MyStromSwitchSensorEntityDescription(SensorEntityDescription):
4452
native_unit_of_measurement=UnitOfPower.WATT,
4553
value_fn=lambda device: device.consumption,
4654
),
55+
MyStromSwitchSensorEntityDescription(
56+
key="energy_since_boot",
57+
translation_key="energy_since_boot",
58+
device_class=SensorDeviceClass.ENERGY,
59+
state_class=SensorStateClass.TOTAL_INCREASING,
60+
native_unit_of_measurement=UnitOfEnergy.JOULE,
61+
suggested_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
62+
value_fn=lambda device: device.energy_since_boot,
63+
),
4764
MyStromSwitchSensorEntityDescription(
4865
key="temperature",
4966
device_class=SensorDeviceClass.TEMPERATURE,
@@ -62,39 +79,106 @@ async def async_setup_entry(
6279
"""Set up the myStrom entities."""
6380
device: MyStromSwitch = entry.runtime_data.device
6481

65-
async_add_entities(
82+
entities: list[MyStromSensorBase] = [
6683
MyStromSwitchSensor(device, entry.title, description)
6784
for description in SENSOR_TYPES
6885
if description.value_fn(device) is not None
69-
)
86+
]
7087

88+
if device.time_since_boot is not None:
89+
entities.append(MyStromSwitchUptimeSensor(device, entry.title))
7190

72-
class MyStromSwitchSensor(SensorEntity):
73-
"""Representation of the consumption or temperature of a myStrom switch/plug."""
91+
async_add_entities(entities)
7492

75-
entity_description: MyStromSwitchSensorEntityDescription
93+
94+
class MyStromSensorBase(SensorEntity):
95+
"""Base class for myStrom sensors."""
7696

7797
_attr_has_entity_name = True
7898

7999
def __init__(
80100
self,
81101
device: MyStromSwitch,
82102
name: str,
83-
description: MyStromSwitchSensorEntityDescription,
103+
key: str,
84104
) -> None:
85105
"""Initialize the sensor."""
86-
self.device = device
87-
self.entity_description = description
88-
89-
self._attr_unique_id = f"{device.mac}-{description.key}"
106+
self._attr_unique_id = f"{device.mac}-{key}"
90107
self._attr_device_info = DeviceInfo(
91108
identifiers={(DOMAIN, device.mac)},
92109
name=name,
93110
manufacturer=MANUFACTURER,
94111
sw_version=device.firmware,
95112
)
96113

114+
115+
class MyStromSwitchSensor(MyStromSensorBase):
116+
"""Representation of the consumption or temperature of a myStrom switch/plug."""
117+
118+
entity_description: MyStromSwitchSensorEntityDescription
119+
120+
def __init__(
121+
self,
122+
device: MyStromSwitch,
123+
name: str,
124+
description: MyStromSwitchSensorEntityDescription,
125+
) -> None:
126+
"""Initialize the sensor."""
127+
super().__init__(device, name, description.key)
128+
self.device = device
129+
self.entity_description = description
130+
97131
@property
98132
def native_value(self) -> float | None:
99133
"""Return the value of the sensor."""
100134
return self.entity_description.value_fn(self.device)
135+
136+
137+
class MyStromSwitchUptimeSensor(MyStromSensorBase):
138+
"""Representation of a MyStrom Switch uptime sensor."""
139+
140+
entity_description = SensorEntityDescription(
141+
key="time_since_boot",
142+
device_class=SensorDeviceClass.TIMESTAMP,
143+
entity_category=EntityCategory.DIAGNOSTIC,
144+
translation_key="time_since_boot",
145+
)
146+
147+
def __init__(
148+
self,
149+
device: MyStromSwitch,
150+
name: str,
151+
) -> None:
152+
"""Initialize the uptime sensor."""
153+
super().__init__(device, name, self.entity_description.key)
154+
self.device = device
155+
self._last_value: datetime | None = None
156+
self._last_attributes: dict[str, Any] = {}
157+
158+
@property
159+
def native_value(self) -> datetime | None:
160+
"""Return the uptime of the device as a datetime."""
161+
162+
if self.device.time_since_boot is None or self.device.boot_id is None:
163+
return None
164+
165+
# Return cached value if boot_id hasn't changed
166+
if (
167+
self._last_value is not None
168+
and self._last_attributes.get("boot_id") == self.device.boot_id
169+
):
170+
return self._last_value
171+
172+
self._last_value = utcnow() - timedelta(seconds=self.device.time_since_boot)
173+
174+
return self._last_value
175+
176+
@property
177+
def extra_state_attributes(self) -> dict[str, Any]:
178+
"""Return the optional state attributes."""
179+
180+
self._last_attributes = {
181+
"boot_id": self.device.boot_id,
182+
}
183+
184+
return self._last_attributes

homeassistant/components/mystrom/strings.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,12 @@
2222
"sensor": {
2323
"avg_consumption": {
2424
"name": "Average consumption"
25+
},
26+
"energy_since_boot": {
27+
"name": "Energy since boot"
28+
},
29+
"time_since_boot": {
30+
"name": "Last restart"
2531
}
2632
}
2733
}

0 commit comments

Comments
 (0)