Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add myuplink specific sensor descriptions #109867

Merged
97 changes: 92 additions & 5 deletions homeassistant/components/myuplink/sensor.py
Expand Up @@ -22,7 +22,7 @@
from .const import DOMAIN
from .entity import MyUplinkEntity

DEVICE_POINT_DESCRIPTIONS = {
DEVICE_POINT_UNIT_DESCRIPTIONS: dict[str, SensorEntityDescription] = {
"°C": SensorEntityDescription(
key="celsius",
device_class=SensorDeviceClass.TEMPERATURE,
Expand All @@ -43,6 +43,55 @@
),
}

UNIQUE_PARAMETER_DESCRIPTIONS: dict[str, SensorEntityDescription] = {}
MartinHjelmare marked this conversation as resolved.
Show resolved Hide resolved

CATEGORY_BASED_DESCRIPTIONS: dict[str, dict[str, SensorEntityDescription]] = {
"NIBEF": {
"43108": SensorEntityDescription(
key="fan_mode",
icon="mdi:fan",
),
"43427": SensorEntityDescription(
key="status_compressor",
device_class=SensorDeviceClass.ENUM,
icon="mdi:heat-pump-outline",
),
"49993": SensorEntityDescription(
key="elect_add",
device_class=SensorDeviceClass.ENUM,
icon="mdi:heat-wave",
),
"49994": SensorEntityDescription(
key="priority",
device_class=SensorDeviceClass.ENUM,
icon="mdi:priority-high",
),
},
"NIBE": {},
}


def get_description(device_point: DevicePoint) -> SensorEntityDescription | None:
"""Get description for a device point.

Priorities:
1. Category specific prefix e.g "NIBEF"
2. Global parameter_id e.g. "12345"
3. Global parameter_unit e.g. "°C"
4. Default to None
"""
description = None
prefix, _, _ = device_point.category.partition(" ")
description = CATEGORY_BASED_DESCRIPTIONS.get(prefix, {}).get(
device_point.parameter_id
)
if description is None:
description = UNIQUE_PARAMETER_DESCRIPTIONS.get(device_point.parameter_id)
if description is None:
description = DEVICE_POINT_UNIT_DESCRIPTIONS.get(device_point.parameter_unit)

return description


async def async_setup_entry(
hass: HomeAssistant,
Expand All @@ -56,14 +105,20 @@ async def async_setup_entry(
# Setup device point sensors
for device_id, point_data in coordinator.data.points.items():
for point_id, device_point in point_data.items():
description = get_description(device_point)
entity_class = MyUplinkDevicePointSensor
if (
description is not None
and description.device_class == SensorDeviceClass.ENUM
):
entity_class = MyUplinkEnumSensor

entities.append(
MyUplinkDevicePointSensor(
entity_class(
coordinator=coordinator,
device_id=device_id,
device_point=device_point,
entity_description=DEVICE_POINT_DESCRIPTIONS.get(
device_point.parameter_unit
),
entity_description=description,
unique_id_suffix=point_id,
)
)
Expand Down Expand Up @@ -102,4 +157,36 @@ def __init__(
def native_value(self) -> StateType:
"""Sensor state value."""
device_point = self.coordinator.data.points[self.device_id][self.point_id]
if device_point.value == -32768:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this check mean?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Normally the API will not include device_point that are permanently unavailable. The API will return -32768 if data is temporarily unavailable. I.e. "Unknown" with HA terminolgy. It happens on two data_points in my F730. I think it is better to show "Unknown" than showing -32768.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That constant kind of needs to be defined in the library, but it at least need a constant defined for it here.

return None
return device_point.value # type: ignore[no-any-return]


class MyUplinkEnumSensor(MyUplinkDevicePointSensor):
"""Representation of a myUplink device point sensor for ENUM device_class."""

def __init__(
self,
coordinator: MyUplinkDataCoordinator,
device_id: str,
device_point: DevicePoint,
entity_description: SensorEntityDescription | None,
unique_id_suffix: str,
) -> None:
"""Initialize the sensor."""
super().__init__(
coordinator=coordinator,
device_id=device_id,
device_point=device_point,
entity_description=entity_description,
unique_id_suffix=unique_id_suffix,
)

self._attr_options = [x["text"].capitalize() for x in device_point.enum_values]
self.options_map = {x["value"]: x["text"] for x in device_point.enum_values}

@property
def native_value(self) -> str:
"""Sensor state value for enum sensor."""
device_point = self.coordinator.data.points[self.device_id][self.point_id]
return self.options_map[str(int(device_point.value))].capitalize() # type: ignore[no-any-return]
elupus marked this conversation as resolved.
Show resolved Hide resolved
astrandb marked this conversation as resolved.
Show resolved Hide resolved