1
mirror of https://github.com/home-assistant/core synced 2024-08-02 23:40:32 +02:00
ha-core/homeassistant/components/solax/sensor.py
Petru Paler 6d7ad8903f
Energy support for Solax inverters (#54654)
Co-authored-by: Franck Nijhof <frenck@frenck.nl>
2021-08-17 10:19:44 +02:00

153 lines
4.4 KiB
Python

"""Support for Solax inverter via local API."""
import asyncio
from datetime import timedelta
from solax import real_time_api
from solax.inverter import InverterError
import voluptuous as vol
from homeassistant.components.sensor import (
PLATFORM_SCHEMA,
STATE_CLASS_MEASUREMENT,
STATE_CLASS_TOTAL_INCREASING,
SensorEntity,
)
from homeassistant.const import (
CONF_IP_ADDRESS,
CONF_PORT,
DEVICE_CLASS_BATTERY,
DEVICE_CLASS_CURRENT,
DEVICE_CLASS_ENERGY,
DEVICE_CLASS_POWER,
DEVICE_CLASS_TEMPERATURE,
DEVICE_CLASS_VOLTAGE,
TEMP_CELSIUS,
)
from homeassistant.exceptions import PlatformNotReady
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.event import async_track_time_interval
DEFAULT_PORT = 80
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
vol.Required(CONF_IP_ADDRESS): cv.string,
vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
}
)
SCAN_INTERVAL = timedelta(seconds=30)
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Platform setup."""
api = await real_time_api(config[CONF_IP_ADDRESS], config[CONF_PORT])
endpoint = RealTimeDataEndpoint(hass, api)
resp = await api.get_data()
serial = resp.serial_number
hass.async_add_job(endpoint.async_refresh)
async_track_time_interval(hass, endpoint.async_refresh, SCAN_INTERVAL)
devices = []
for sensor, (idx, unit) in api.inverter.sensor_map().items():
device_class = state_class = None
if unit == "C":
device_class = DEVICE_CLASS_TEMPERATURE
state_class = STATE_CLASS_MEASUREMENT
unit = TEMP_CELSIUS
elif unit == "kWh":
device_class = DEVICE_CLASS_ENERGY
state_class = STATE_CLASS_TOTAL_INCREASING
elif unit == "V":
device_class = DEVICE_CLASS_VOLTAGE
state_class = STATE_CLASS_MEASUREMENT
elif unit == "A":
device_class = DEVICE_CLASS_CURRENT
state_class = STATE_CLASS_MEASUREMENT
elif unit == "W":
device_class = DEVICE_CLASS_POWER
state_class = STATE_CLASS_MEASUREMENT
elif unit == "%":
device_class = DEVICE_CLASS_BATTERY
state_class = STATE_CLASS_MEASUREMENT
uid = f"{serial}-{idx}"
devices.append(Inverter(uid, serial, sensor, unit, state_class, device_class))
endpoint.sensors = devices
async_add_entities(devices)
class RealTimeDataEndpoint:
"""Representation of a Sensor."""
def __init__(self, hass, api):
"""Initialize the sensor."""
self.hass = hass
self.api = api
self.ready = asyncio.Event()
self.sensors = []
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."""
def __init__(
self,
uid,
serial,
key,
unit,
state_class=None,
device_class=None,
):
"""Initialize an inverter sensor."""
self.uid = uid
self.serial = serial
self.key = key
self.value = None
self.unit = unit
self._attr_state_class = state_class
self._attr_device_class = device_class
@property
def native_value(self):
"""State of this inverter attribute."""
return self.value
@property
def unique_id(self):
"""Return unique id."""
return self.uid
@property
def name(self):
"""Name of this inverter attribute."""
return f"Solax {self.serial} {self.key}"
@property
def native_unit_of_measurement(self):
"""Return the unit of measurement."""
return self.unit
@property
def should_poll(self):
"""No polling needed."""
return False