Add Sensor for Refoss Integration (#116965)
Co-authored-by: Robert Resch <robert@resch.dev>pull/120016/head^2
parent
1eb8b5a27c
commit
3224224bf8
|
@ -1110,6 +1110,7 @@ omit =
|
|||
homeassistant/components/refoss/bridge.py
|
||||
homeassistant/components/refoss/coordinator.py
|
||||
homeassistant/components/refoss/entity.py
|
||||
homeassistant/components/refoss/sensor.py
|
||||
homeassistant/components/refoss/switch.py
|
||||
homeassistant/components/refoss/util.py
|
||||
homeassistant/components/rejseplanen/sensor.py
|
||||
|
|
|
@ -15,6 +15,7 @@ from .const import COORDINATORS, DATA_DISCOVERY_SERVICE, DISCOVERY_SCAN_INTERVAL
|
|||
from .util import refoss_discovery_server
|
||||
|
||||
PLATFORMS: Final = [
|
||||
Platform.SENSOR,
|
||||
Platform.SWITCH,
|
||||
]
|
||||
|
||||
|
|
|
@ -19,3 +19,14 @@ DOMAIN = "refoss"
|
|||
COORDINATOR = "coordinator"
|
||||
|
||||
MAX_ERRORS = 2
|
||||
|
||||
CHANNEL_DISPLAY_NAME: dict[str, dict[int, str]] = {
|
||||
"em06": {
|
||||
1: "A1",
|
||||
2: "B1",
|
||||
3: "C1",
|
||||
4: "A2",
|
||||
5: "B2",
|
||||
6: "C2",
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,11 +18,6 @@ class RefossEntity(CoordinatorEntity[RefossDataUpdateCoordinator]):
|
|||
|
||||
mac = coordinator.device.mac
|
||||
self.channel_id = channel
|
||||
if channel == 0:
|
||||
self._attr_name = None
|
||||
else:
|
||||
self._attr_name = str(channel)
|
||||
|
||||
self._attr_unique_id = f"{mac}_{channel}"
|
||||
self._attr_device_info = DeviceInfo(
|
||||
connections={(CONNECTION_NETWORK_MAC, mac)},
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
"""Support for refoss sensors."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
|
||||
from refoss_ha.controller.electricity import ElectricityXMix
|
||||
|
||||
from homeassistant.components.sensor import (
|
||||
SensorDeviceClass,
|
||||
SensorEntity,
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import (
|
||||
UnitOfElectricCurrent,
|
||||
UnitOfElectricPotential,
|
||||
UnitOfEnergy,
|
||||
UnitOfPower,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.typing import StateType
|
||||
|
||||
from .bridge import RefossDataUpdateCoordinator
|
||||
from .const import (
|
||||
CHANNEL_DISPLAY_NAME,
|
||||
COORDINATORS,
|
||||
DISPATCH_DEVICE_DISCOVERED,
|
||||
DOMAIN,
|
||||
)
|
||||
from .entity import RefossEntity
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class RefossSensorEntityDescription(SensorEntityDescription):
|
||||
"""Describes Refoss sensor entity."""
|
||||
|
||||
subkey: str | None = None
|
||||
fn: Callable[[float], float] | None = None
|
||||
|
||||
|
||||
SENSORS: dict[str, tuple[RefossSensorEntityDescription, ...]] = {
|
||||
"em06": (
|
||||
RefossSensorEntityDescription(
|
||||
key="power",
|
||||
translation_key="power",
|
||||
device_class=SensorDeviceClass.POWER,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfPower.WATT,
|
||||
suggested_display_precision=2,
|
||||
subkey="power",
|
||||
fn=lambda x: x / 1000.0,
|
||||
),
|
||||
RefossSensorEntityDescription(
|
||||
key="voltage",
|
||||
translation_key="voltage",
|
||||
device_class=SensorDeviceClass.VOLTAGE,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfElectricPotential.MILLIVOLT,
|
||||
suggested_display_precision=2,
|
||||
suggested_unit_of_measurement=UnitOfElectricPotential.VOLT,
|
||||
subkey="voltage",
|
||||
),
|
||||
RefossSensorEntityDescription(
|
||||
key="current",
|
||||
translation_key="current",
|
||||
device_class=SensorDeviceClass.CURRENT,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfElectricCurrent.MILLIAMPERE,
|
||||
suggested_display_precision=2,
|
||||
suggested_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
|
||||
subkey="current",
|
||||
),
|
||||
RefossSensorEntityDescription(
|
||||
key="factor",
|
||||
translation_key="power_factor",
|
||||
device_class=SensorDeviceClass.POWER_FACTOR,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
suggested_display_precision=2,
|
||||
subkey="factor",
|
||||
),
|
||||
RefossSensorEntityDescription(
|
||||
key="energy",
|
||||
translation_key="this_month_energy",
|
||||
device_class=SensorDeviceClass.ENERGY,
|
||||
state_class=SensorStateClass.TOTAL,
|
||||
native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
|
||||
suggested_display_precision=2,
|
||||
subkey="mConsume",
|
||||
fn=lambda x: x if x > 0 else 0,
|
||||
),
|
||||
RefossSensorEntityDescription(
|
||||
key="energy_returned",
|
||||
translation_key="this_month_energy_returned",
|
||||
device_class=SensorDeviceClass.ENERGY,
|
||||
state_class=SensorStateClass.TOTAL,
|
||||
native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
|
||||
suggested_display_precision=2,
|
||||
subkey="mConsume",
|
||||
fn=lambda x: abs(x) if x < 0 else 0,
|
||||
),
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the Refoss device from a config entry."""
|
||||
|
||||
@callback
|
||||
def init_device(coordinator):
|
||||
"""Register the device."""
|
||||
device = coordinator.device
|
||||
|
||||
if not isinstance(device, ElectricityXMix):
|
||||
return
|
||||
descriptions = SENSORS.get(device.device_type)
|
||||
new_entities = []
|
||||
for channel in device.channels:
|
||||
for description in descriptions:
|
||||
entity = RefossSensor(
|
||||
coordinator=coordinator,
|
||||
channel=channel,
|
||||
description=description,
|
||||
)
|
||||
new_entities.append(entity)
|
||||
|
||||
async_add_entities(new_entities)
|
||||
|
||||
for coordinator in hass.data[DOMAIN][COORDINATORS]:
|
||||
init_device(coordinator)
|
||||
|
||||
config_entry.async_on_unload(
|
||||
async_dispatcher_connect(hass, DISPATCH_DEVICE_DISCOVERED, init_device)
|
||||
)
|
||||
|
||||
|
||||
class RefossSensor(RefossEntity, SensorEntity):
|
||||
"""Refoss Sensor Device."""
|
||||
|
||||
entity_description: RefossSensorEntityDescription
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: RefossDataUpdateCoordinator,
|
||||
channel: int,
|
||||
description: RefossSensorEntityDescription,
|
||||
) -> None:
|
||||
"""Init Refoss sensor."""
|
||||
super().__init__(coordinator, channel)
|
||||
self.entity_description = description
|
||||
self._attr_unique_id = f"{super().unique_id}{description.key}"
|
||||
device_type = coordinator.device.device_type
|
||||
channel_name = CHANNEL_DISPLAY_NAME[device_type][channel]
|
||||
self._attr_translation_placeholders = {"channel_name": channel_name}
|
||||
|
||||
@property
|
||||
def native_value(self) -> StateType:
|
||||
"""Return the native value."""
|
||||
value = self.coordinator.device.get_value(
|
||||
self.channel_id, self.entity_description.subkey
|
||||
)
|
||||
if value is None:
|
||||
return None
|
||||
if self.entity_description.fn is not None:
|
||||
return self.entity_description.fn(value)
|
||||
return value
|
|
@ -9,5 +9,27 @@
|
|||
"single_instance_allowed": "[%key:common::config_flow::abort::single_instance_allowed%]",
|
||||
"no_devices_found": "[%key:common::config_flow::abort::no_devices_found%]"
|
||||
}
|
||||
},
|
||||
"entity": {
|
||||
"sensor": {
|
||||
"power": {
|
||||
"name": "{channel_name} power"
|
||||
},
|
||||
"voltage": {
|
||||
"name": "{channel_name} voltage"
|
||||
},
|
||||
"current": {
|
||||
"name": "{channel_name} current"
|
||||
},
|
||||
"power_factor": {
|
||||
"name": "{channel_name} power factor"
|
||||
},
|
||||
"this_month_energy": {
|
||||
"name": "{channel_name} this month energy"
|
||||
},
|
||||
"this_month_energy_returned": {
|
||||
"name": "{channel_name} this month energy returned"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ from homeassistant.core import HomeAssistant, callback
|
|||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from .bridge import RefossDataUpdateCoordinator
|
||||
from .const import COORDINATORS, DISPATCH_DEVICE_DISCOVERED, DOMAIN
|
||||
from .entity import RefossEntity
|
||||
|
||||
|
@ -48,6 +49,15 @@ async def async_setup_entry(
|
|||
class RefossSwitch(RefossEntity, SwitchEntity):
|
||||
"""Refoss Switch Device."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: RefossDataUpdateCoordinator,
|
||||
channel: int,
|
||||
) -> None:
|
||||
"""Init Refoss switch."""
|
||||
super().__init__(coordinator, channel)
|
||||
self._attr_name = str(channel)
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool | None:
|
||||
"""Return true if switch is on."""
|
||||
|
|
Loading…
Reference in New Issue