diff --git a/homeassistant/components/solarlog/const.py b/homeassistant/components/solarlog/const.py index 0d989642d07..a339f5c873d 100644 --- a/homeassistant/components/solarlog/const.py +++ b/homeassistant/components/solarlog/const.py @@ -1,7 +1,20 @@ """Constants for the Solar-Log integration.""" +from __future__ import annotations + +from dataclasses import dataclass from datetime import timedelta +from homeassistant.components.sensor import ( + STATE_CLASS_MEASUREMENT, + STATE_CLASS_TOTAL_INCREASING, + SensorEntityDescription, +) from homeassistant.const import ( + DEVICE_CLASS_ENERGY, + DEVICE_CLASS_POWER, + DEVICE_CLASS_POWER_FACTOR, + DEVICE_CLASS_TIMESTAMP, + DEVICE_CLASS_VOLTAGE, ELECTRIC_POTENTIAL_VOLT, ENERGY_KILO_WATT_HOUR, PERCENTAGE, @@ -17,83 +30,187 @@ DEFAULT_NAME = "solarlog" """Fixed constants.""" SCAN_INTERVAL = timedelta(seconds=60) -"""Supported sensor types.""" -SENSOR_TYPES = { - "time": ["TIME", "last update", None, "mdi:calendar-clock"], - "power_ac": ["powerAC", "power AC", POWER_WATT, "mdi:solar-power"], - "power_dc": ["powerDC", "power DC", POWER_WATT, "mdi:solar-power"], - "voltage_ac": ["voltageAC", "voltage AC", ELECTRIC_POTENTIAL_VOLT, "mdi:flash"], - "voltage_dc": ["voltageDC", "voltage DC", ELECTRIC_POTENTIAL_VOLT, "mdi:flash"], - "yield_day": ["yieldDAY", "yield day", ENERGY_KILO_WATT_HOUR, "mdi:solar-power"], - "yield_yesterday": [ - "yieldYESTERDAY", - "yield yesterday", - ENERGY_KILO_WATT_HOUR, - "mdi:solar-power", - ], - "yield_month": [ - "yieldMONTH", - "yield month", - ENERGY_KILO_WATT_HOUR, - "mdi:solar-power", - ], - "yield_year": ["yieldYEAR", "yield year", ENERGY_KILO_WATT_HOUR, "mdi:solar-power"], - "yield_total": [ - "yieldTOTAL", - "yield total", - ENERGY_KILO_WATT_HOUR, - "mdi:solar-power", - ], - "consumption_ac": ["consumptionAC", "consumption AC", POWER_WATT, "mdi:power-plug"], - "consumption_day": [ - "consumptionDAY", - "consumption day", - ENERGY_KILO_WATT_HOUR, - "mdi:power-plug", - ], - "consumption_yesterday": [ - "consumptionYESTERDAY", - "consumption yesterday", - ENERGY_KILO_WATT_HOUR, - "mdi:power-plug", - ], - "consumption_month": [ - "consumptionMONTH", - "consumption month", - ENERGY_KILO_WATT_HOUR, - "mdi:power-plug", - ], - "consumption_year": [ - "consumptionYEAR", - "consumption year", - ENERGY_KILO_WATT_HOUR, - "mdi:power-plug", - ], - "consumption_total": [ - "consumptionTOTAL", - "consumption total", - ENERGY_KILO_WATT_HOUR, - "mdi:power-plug", - ], - "total_power": ["totalPOWER", "total power", "Wp", "mdi:solar-power"], - "alternator_loss": [ - "alternatorLOSS", - "alternator loss", - POWER_WATT, - "mdi:solar-power", - ], - "capacity": ["CAPACITY", "capacity", PERCENTAGE, "mdi:solar-power"], - "efficiency": [ - "EFFICIENCY", - "efficiency", - f"% {POWER_WATT}/{POWER_WATT}p", - "mdi:solar-power", - ], - "power_available": [ - "powerAVAILABLE", - "power available", - POWER_WATT, - "mdi:solar-power", - ], - "usage": ["USAGE", "usage", None, "mdi:solar-power"], -} + +@dataclass +class SolarlogRequiredKeysMixin: + """Mixin for required keys.""" + + json_key: str + + +@dataclass +class SolarLogSensorEntityDescription( + SensorEntityDescription, SolarlogRequiredKeysMixin +): + """Describes Solarlog sensor entity.""" + + +SENSOR_TYPES: tuple[SolarLogSensorEntityDescription, ...] = ( + SolarLogSensorEntityDescription( + key="time", + json_key="TIME", + name="last update", + device_class=DEVICE_CLASS_TIMESTAMP, + ), + SolarLogSensorEntityDescription( + key="power_ac", + json_key="powerAC", + name="power AC", + icon="mdi:solar-power", + native_unit_of_measurement=POWER_WATT, + state_class=STATE_CLASS_MEASUREMENT, + ), + SolarLogSensorEntityDescription( + key="power_dc", + json_key="powerDC", + name="power DC", + icon="mdi:solar-power", + native_unit_of_measurement=POWER_WATT, + state_class=STATE_CLASS_MEASUREMENT, + ), + SolarLogSensorEntityDescription( + key="voltage_ac", + json_key="voltageAC", + name="voltage AC", + native_unit_of_measurement=ELECTRIC_POTENTIAL_VOLT, + device_class=DEVICE_CLASS_VOLTAGE, + state_class=STATE_CLASS_MEASUREMENT, + ), + SolarLogSensorEntityDescription( + key="voltage_dc", + json_key="voltageDC", + name="voltage DC", + native_unit_of_measurement=ELECTRIC_POTENTIAL_VOLT, + device_class=DEVICE_CLASS_VOLTAGE, + state_class=STATE_CLASS_MEASUREMENT, + ), + SolarLogSensorEntityDescription( + key="yield_day", + json_key="yieldDAY", + name="yield day", + icon="mdi:solar-power", + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + ), + SolarLogSensorEntityDescription( + key="yield_yesterday", + json_key="yieldYESTERDAY", + name="yield yesterday", + icon="mdi:solar-power", + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + ), + SolarLogSensorEntityDescription( + key="yield_month", + json_key="yieldMONTH", + name="yield month", + icon="mdi:solar-power", + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + ), + SolarLogSensorEntityDescription( + key="yield_year", + json_key="yieldYEAR", + name="yield year", + icon="mdi:solar-power", + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + ), + SolarLogSensorEntityDescription( + key="yield_total", + json_key="yieldTOTAL", + name="yield total", + icon="mdi:solar-power", + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + state_class=STATE_CLASS_TOTAL_INCREASING, + ), + SolarLogSensorEntityDescription( + key="consumption_ac", + json_key="consumptionAC", + name="consumption AC", + native_unit_of_measurement=POWER_WATT, + device_class=DEVICE_CLASS_POWER, + state_class=STATE_CLASS_MEASUREMENT, + ), + SolarLogSensorEntityDescription( + key="consumption_day", + json_key="consumptionDAY", + name="consumption day", + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + device_class=DEVICE_CLASS_ENERGY, + ), + SolarLogSensorEntityDescription( + key="consumption_yesterday", + json_key="consumptionYESTERDAY", + name="consumption yesterday", + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + device_class=DEVICE_CLASS_ENERGY, + ), + SolarLogSensorEntityDescription( + key="consumption_month", + json_key="consumptionMONTH", + name="consumption month", + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + device_class=DEVICE_CLASS_ENERGY, + ), + SolarLogSensorEntityDescription( + key="consumption_year", + json_key="consumptionYEAR", + name="consumption year", + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + device_class=DEVICE_CLASS_ENERGY, + ), + SolarLogSensorEntityDescription( + key="consumption_total", + json_key="consumptionTOTAL", + name="consumption total", + native_unit_of_measurement=ENERGY_KILO_WATT_HOUR, + device_class=DEVICE_CLASS_ENERGY, + state_class=STATE_CLASS_TOTAL_INCREASING, + ), + SolarLogSensorEntityDescription( + key="total_power", + json_key="totalPOWER", + name="total power", + icon="mdi:solar-power", + native_unit_of_measurement="Wp", + ), + SolarLogSensorEntityDescription( + key="alternator_loss", + json_key="alternatorLOSS", + name="alternator loss", + icon="mdi:solar-power", + native_unit_of_measurement=POWER_WATT, + device_class=DEVICE_CLASS_POWER, + state_class=STATE_CLASS_MEASUREMENT, + ), + SolarLogSensorEntityDescription( + key="capacity", + json_key="CAPACITY", + name="capacity", + icon="mdi:solar-power", + native_unit_of_measurement="W/Wp", + state_class=STATE_CLASS_MEASUREMENT, + ), + SolarLogSensorEntityDescription( + key="efficiency", + json_key="EFFICIENCY", + name="efficiency", + native_unit_of_measurement=PERCENTAGE, + device_class=DEVICE_CLASS_POWER_FACTOR, + state_class=STATE_CLASS_MEASUREMENT, + ), + SolarLogSensorEntityDescription( + key="power_available", + json_key="powerAVAILABLE", + name="power available", + icon="mdi:solar-power", + native_unit_of_measurement=POWER_WATT, + device_class=DEVICE_CLASS_POWER, + state_class=STATE_CLASS_MEASUREMENT, + ), + SolarLogSensorEntityDescription( + key="usage", + json_key="USAGE", + name="usage", + native_unit_of_measurement=PERCENTAGE, + device_class=DEVICE_CLASS_POWER_FACTOR, + state_class=STATE_CLASS_MEASUREMENT, + ), +) diff --git a/homeassistant/components/solarlog/sensor.py b/homeassistant/components/solarlog/sensor.py index a6a35bad80c..5df86d64997 100644 --- a/homeassistant/components/solarlog/sensor.py +++ b/homeassistant/components/solarlog/sensor.py @@ -9,7 +9,7 @@ from homeassistant.components.sensor import SensorEntity from homeassistant.const import CONF_HOST from homeassistant.util import Throttle -from .const import DOMAIN, SCAN_INTERVAL, SENSOR_TYPES +from .const import DOMAIN, SCAN_INTERVAL, SENSOR_TYPES, SolarLogSensorEntityDescription _LOGGER = logging.getLogger(__name__) @@ -46,71 +46,14 @@ async def async_setup_entry(hass, entry, async_add_entities): data = await hass.async_add_executor_job(SolarlogData, hass, api, host) # Create a new sensor for each sensor type. - entities = [] - for sensor_key in SENSOR_TYPES: - sensor = SolarlogSensor(entry.entry_id, device_name, sensor_key, data) - entities.append(sensor) - + entities = [ + SolarlogSensor(entry.entry_id, device_name, data, description) + for description in SENSOR_TYPES + ] async_add_entities(entities, True) return True -class SolarlogSensor(SensorEntity): - """Representation of a Sensor.""" - - def __init__(self, entry_id, device_name, sensor_key, data): - """Initialize the sensor.""" - self.device_name = device_name - self.sensor_key = sensor_key - self.data = data - self.entry_id = entry_id - self._state = None - - self._json_key = SENSOR_TYPES[self.sensor_key][0] - self._label = SENSOR_TYPES[self.sensor_key][1] - self._unit_of_measurement = SENSOR_TYPES[self.sensor_key][2] - self._icon = SENSOR_TYPES[self.sensor_key][3] - - @property - def unique_id(self): - """Return the unique id.""" - return f"{self.entry_id}_{self.sensor_key}" - - @property - def name(self): - """Return the name of the sensor.""" - return f"{self.device_name} {self._label}" - - @property - def native_unit_of_measurement(self): - """Return the state of the sensor.""" - return self._unit_of_measurement - - @property - def icon(self): - """Return the sensor icon.""" - return self._icon - - @property - def native_value(self): - """Return the state of the sensor.""" - return self._state - - @property - def device_info(self): - """Return the device information.""" - return { - "identifiers": {(DOMAIN, self.entry_id)}, - "name": self.device_name, - "manufacturer": "Solar-Log", - } - - def update(self): - """Get the latest data from the sensor and update the state.""" - self.data.update() - self._state = self.data.data[self._json_key] - - class SolarlogData: """Get and update the latest data.""" @@ -154,10 +97,37 @@ class SolarlogData: self.data["consumptionTOTAL"] = self.api.consumption_total / 1000 self.data["totalPOWER"] = self.api.total_power self.data["alternatorLOSS"] = self.api.alternator_loss - self.data["CAPACITY"] = round(self.api.capacity * 100, 0) + self.data["CAPACITY"] = round(self.api.capacity, 3) self.data["EFFICIENCY"] = round(self.api.efficiency * 100, 0) self.data["powerAVAILABLE"] = self.api.power_available - self.data["USAGE"] = self.api.usage + self.data["USAGE"] = round(self.api.usage * 100, 0) _LOGGER.debug("Updated Solarlog overview data: %s", self.data) except AttributeError: _LOGGER.error("Missing details data in Solarlog response") + + +class SolarlogSensor(SensorEntity): + """Representation of a Sensor.""" + + def __init__( + self, + entry_id: str, + device_name: str, + data: SolarlogData, + description: SolarLogSensorEntityDescription, + ) -> None: + """Initialize the sensor.""" + self.entity_description = description + self.data = data + self._attr_name = f"{device_name} {description.name}" + self._attr_unique_id = f"{entry_id}_{description.key}" + self._attr_device_info = { + "identifiers": {(DOMAIN, entry_id)}, + "name": device_name, + "manufacturer": "Solar-Log", + } + + def update(self): + """Get the latest data from the sensor and update the state.""" + self.data.update() + self._attr_native_value = self.data.data[self.entity_description.json_key]