mirror of
https://github.com/home-assistant/core.git
synced 2025-06-06 22:27:12 +00:00

Update sensor.py Units.NONE is used for text entities which are not measurements. Marking them so breaks their history.
193 lines
6.0 KiB
Python
193 lines
6.0 KiB
Python
"""Support for Solax inverter via local API."""
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
from datetime import timedelta
|
|
|
|
from solax import RealTimeAPI
|
|
from solax.discovery import InverterError
|
|
from solax.units import Units
|
|
|
|
from homeassistant.components.sensor import (
|
|
SensorDeviceClass,
|
|
SensorEntity,
|
|
SensorEntityDescription,
|
|
SensorStateClass,
|
|
)
|
|
from homeassistant.config_entries import ConfigEntry
|
|
from homeassistant.const import (
|
|
PERCENTAGE,
|
|
UnitOfElectricCurrent,
|
|
UnitOfElectricPotential,
|
|
UnitOfEnergy,
|
|
UnitOfFrequency,
|
|
UnitOfPower,
|
|
UnitOfTemperature,
|
|
)
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.exceptions import PlatformNotReady
|
|
from homeassistant.helpers.entity import DeviceInfo
|
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
|
from homeassistant.helpers.event import async_track_time_interval
|
|
|
|
from .const import DOMAIN, MANUFACTURER
|
|
|
|
DEFAULT_PORT = 80
|
|
SCAN_INTERVAL = timedelta(seconds=30)
|
|
|
|
|
|
SENSOR_DESCRIPTIONS: dict[tuple[Units, bool], SensorEntityDescription] = {
|
|
(Units.C, False): SensorEntityDescription(
|
|
key=f"{Units.C}_{False}",
|
|
device_class=SensorDeviceClass.TEMPERATURE,
|
|
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
|
state_class=SensorStateClass.MEASUREMENT,
|
|
),
|
|
(Units.KWH, False): SensorEntityDescription(
|
|
key=f"{Units.KWH}_{False}",
|
|
device_class=SensorDeviceClass.ENERGY,
|
|
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
|
|
state_class=SensorStateClass.MEASUREMENT,
|
|
),
|
|
(Units.KWH, True): SensorEntityDescription(
|
|
key=f"{Units.KWH}_{True}",
|
|
device_class=SensorDeviceClass.ENERGY,
|
|
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
|
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
|
),
|
|
(Units.V, False): SensorEntityDescription(
|
|
key=f"{Units.V}_{False}",
|
|
device_class=SensorDeviceClass.VOLTAGE,
|
|
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
|
|
state_class=SensorStateClass.MEASUREMENT,
|
|
),
|
|
(Units.A, False): SensorEntityDescription(
|
|
key=f"{Units.A}_{False}",
|
|
device_class=SensorDeviceClass.CURRENT,
|
|
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
|
|
state_class=SensorStateClass.MEASUREMENT,
|
|
),
|
|
(Units.W, False): SensorEntityDescription(
|
|
key=f"{Units.W}_{False}",
|
|
device_class=SensorDeviceClass.POWER,
|
|
native_unit_of_measurement=UnitOfPower.WATT,
|
|
state_class=SensorStateClass.MEASUREMENT,
|
|
),
|
|
(Units.PERCENT, False): SensorEntityDescription(
|
|
key=f"{Units.PERCENT}_{False}",
|
|
device_class=SensorDeviceClass.BATTERY,
|
|
native_unit_of_measurement=PERCENTAGE,
|
|
state_class=SensorStateClass.MEASUREMENT,
|
|
),
|
|
(Units.HZ, False): SensorEntityDescription(
|
|
key=f"{Units.HZ}_{False}",
|
|
device_class=SensorDeviceClass.FREQUENCY,
|
|
native_unit_of_measurement=UnitOfFrequency.HERTZ,
|
|
state_class=SensorStateClass.MEASUREMENT,
|
|
),
|
|
(Units.NONE, False): SensorEntityDescription(
|
|
key=f"{Units.NONE}_{False}",
|
|
),
|
|
}
|
|
|
|
|
|
async def async_setup_entry(
|
|
hass: HomeAssistant,
|
|
entry: ConfigEntry,
|
|
async_add_entities: AddEntitiesCallback,
|
|
) -> None:
|
|
"""Entry setup."""
|
|
api: RealTimeAPI = hass.data[DOMAIN][entry.entry_id]
|
|
resp = await api.get_data()
|
|
serial = resp.serial_number
|
|
version = resp.version
|
|
endpoint = RealTimeDataEndpoint(hass, api)
|
|
hass.async_add_job(endpoint.async_refresh)
|
|
async_track_time_interval(hass, endpoint.async_refresh, SCAN_INTERVAL)
|
|
devices = []
|
|
for sensor, (idx, measurement) in api.inverter.sensor_map().items():
|
|
description = SENSOR_DESCRIPTIONS[(measurement.unit, measurement.is_monotonic)]
|
|
|
|
uid = f"{serial}-{idx}"
|
|
devices.append(
|
|
Inverter(
|
|
api.inverter.manufacturer,
|
|
uid,
|
|
serial,
|
|
version,
|
|
sensor,
|
|
description.native_unit_of_measurement,
|
|
description.state_class,
|
|
description.device_class,
|
|
)
|
|
)
|
|
endpoint.sensors = devices
|
|
async_add_entities(devices)
|
|
|
|
|
|
class RealTimeDataEndpoint:
|
|
"""Representation of a Sensor."""
|
|
|
|
def __init__(self, hass: HomeAssistant, api: RealTimeAPI) -> None:
|
|
"""Initialize the sensor."""
|
|
self.hass = hass
|
|
self.api = api
|
|
self.ready = asyncio.Event()
|
|
self.sensors: list[Inverter] = []
|
|
|
|
async def async_refresh(self, now=None):
|
|
"""Fetch new state data for the sensor.
|
|
|
|
This is the only method that should fetch new data for Home Assistant.
|
|
"""
|
|
try:
|
|
api_response = await self.api.get_data()
|
|
self.ready.set()
|
|
except InverterError as err:
|
|
if now is not None:
|
|
self.ready.clear()
|
|
return
|
|
raise PlatformNotReady from err
|
|
data = api_response.data
|
|
for sensor in self.sensors:
|
|
if sensor.key in data:
|
|
sensor.value = data[sensor.key]
|
|
sensor.async_schedule_update_ha_state()
|
|
|
|
|
|
class Inverter(SensorEntity):
|
|
"""Class for a sensor."""
|
|
|
|
_attr_should_poll = False
|
|
|
|
def __init__(
|
|
self,
|
|
manufacturer,
|
|
uid,
|
|
serial,
|
|
version,
|
|
key,
|
|
unit,
|
|
state_class=None,
|
|
device_class=None,
|
|
):
|
|
"""Initialize an inverter sensor."""
|
|
self._attr_unique_id = uid
|
|
self._attr_name = f"{manufacturer} {serial} {key}"
|
|
self._attr_native_unit_of_measurement = unit
|
|
self._attr_state_class = state_class
|
|
self._attr_device_class = device_class
|
|
self._attr_device_info = DeviceInfo(
|
|
identifiers={(DOMAIN, serial)},
|
|
manufacturer=MANUFACTURER,
|
|
name=f"{manufacturer} {serial}",
|
|
sw_version=version,
|
|
)
|
|
self.key = key
|
|
self.value = None
|
|
|
|
@property
|
|
def native_value(self):
|
|
"""State of this inverter attribute."""
|
|
return self.value
|