forked from home-assistant/core
260 lines
13 KiB
Python
260 lines
13 KiB
Python
"""Platform for sensor integration."""
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Final
|
|
|
|
from homeassistant.core import HomeAssistant
|
|
from homeassistant.config_entries import ConfigEntry
|
|
from homeassistant.const import (ELECTRIC_POTENTIAL_VOLT, ELECTRIC_CURRENT_AMPERE, POWER_WATT, POWER_KILO_WATT,
|
|
FREQUENCY_HERTZ, ENERGY_WATT_HOUR, ENERGY_KILO_WATT_HOUR, TEMP_CELSIUS,
|
|
SIGNAL_STRENGTH_DECIBELS, DEVICE_CLASS_CURRENT, DEVICE_CLASS_ENERGY,
|
|
DEVICE_CLASS_POWER_FACTOR, DEVICE_CLASS_POWER, DEVICE_CLASS_SIGNAL_STRENGTH,
|
|
DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_VOLTAGE)
|
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity, DataUpdateCoordinator
|
|
from homeassistant.components.sensor import STATE_CLASS_MEASUREMENT, STATE_CLASS_TOTAL_INCREASING
|
|
from homeassistant.components.sensor import SensorEntity
|
|
|
|
from .const import DOMAIN
|
|
|
|
POWER_FACTOR: Final = "%"
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities) -> None:
|
|
coordinator = hass.data[DOMAIN][config_entry.entry_id]
|
|
serial = config_entry.data["serial"]
|
|
|
|
def car_state_data(data):
|
|
car_state_texts = {
|
|
0: "Unknown",
|
|
1: "Idle",
|
|
2: "Charging",
|
|
3: "WaitCar",
|
|
4: "Complete",
|
|
5: "Error"
|
|
}
|
|
|
|
if data["car"] in car_state_texts:
|
|
return car_state_texts[data["car"]]
|
|
|
|
return "Unknown (" + str(data["car"]) + ")"
|
|
|
|
def error_data(data):
|
|
error_texts = {
|
|
0: "None",
|
|
1: "FiAc",
|
|
2: "FiDc",
|
|
3: "Phase",
|
|
4: "Overvolt",
|
|
5: "Overamp",
|
|
6: "Diode",
|
|
7: "PpInvalid",
|
|
8: "GndInvalid",
|
|
9: "ContactorStuck",
|
|
10: "ContactorMiss",
|
|
11: "FiUnknown",
|
|
12: "Unknown",
|
|
13: "Overtemp",
|
|
14: "NoComm",
|
|
15: "StatusLockStuckOpen",
|
|
16: "StatusLockStuckLocked",
|
|
17: "Reserved20",
|
|
18: "Reserved21",
|
|
19: "Reserved22",
|
|
20: "Reserved23",
|
|
21: "Reserved24"
|
|
}
|
|
|
|
if data["err"] in error_texts:
|
|
return error_texts[data["err"]]
|
|
|
|
return "Unknown (" + str(data["err"]) + ")"
|
|
|
|
def model_status_data(data):
|
|
model_status_texts = {
|
|
0: "NotChargingBecauseNoChargeCtrlData",
|
|
1: "NotChargingBecauseOvertemperature",
|
|
2: "NotChargingBecauseAccessControlWait",
|
|
3: "ChargingBecauseForceStateOn",
|
|
4: "NotChargingBecauseForceStateOff",
|
|
5: "NotChargingBecauseScheduler",
|
|
6: "NotChargingBecauseEnergyLimit",
|
|
7: "ChargingBecauseAwattarPriceLow",
|
|
8: "ChargingBecauseAutomaticStopTestLadung",
|
|
9: "ChargingBecauseAutomaticStopNotEnoughTime",
|
|
10: "ChargingBecauseAutomaticStop",
|
|
11: "ChargingBecauseAutomaticStopNoClock",
|
|
12: "ChargingBecausePvSurplus",
|
|
13: "ChargingBecauseFallbackGoEDefault",
|
|
14: "ChargingBecauseFallbackGoEScheduler",
|
|
15: "ChargingBecauseFallbackDefault",
|
|
16: "NotChargingBecauseFallbackGoEAwattar",
|
|
17: "NotChargingBecauseFallbackAwattar",
|
|
18: "NotChargingBecauseFallbackAutomaticStop",
|
|
19: "ChargingBecauseCarCompatibilityKeepAlive",
|
|
20: "ChargingBecauseChargePauseNotAllowed",
|
|
22: "NotChargingBecauseSimulateUnplugging",
|
|
23: "NotChargingBecausePhaseSwitch",
|
|
24: "NotChargingBecauseMinPauseDuration"
|
|
}
|
|
|
|
if data["modelStatus"] in model_status_texts:
|
|
return model_status_texts[data["modelStatus"]]
|
|
|
|
return "Unknown (" + str(data["modelStatus"]) + ")"
|
|
|
|
async_add_entities([
|
|
GoeChargerSensor(coordinator, "Voltage L1", serial, "voltage_l1", ELECTRIC_POTENTIAL_VOLT, DEVICE_CLASS_VOLTAGE,
|
|
STATE_CLASS_MEASUREMENT, "nrg", lambda data: data["nrg"][0]),
|
|
GoeChargerSensor(coordinator, "Voltage L2", serial, "voltage_l2", ELECTRIC_POTENTIAL_VOLT, DEVICE_CLASS_VOLTAGE,
|
|
STATE_CLASS_MEASUREMENT, "nrg", lambda data: data["nrg"][1]),
|
|
GoeChargerSensor(coordinator, "Voltage L3", serial, "voltage_l3", ELECTRIC_POTENTIAL_VOLT, DEVICE_CLASS_VOLTAGE,
|
|
STATE_CLASS_MEASUREMENT, "nrg", lambda data: data["nrg"][2]),
|
|
GoeChargerSensor(coordinator, "Voltage N", serial, "voltage_n", ELECTRIC_POTENTIAL_VOLT, DEVICE_CLASS_VOLTAGE,
|
|
STATE_CLASS_MEASUREMENT, "nrg", lambda data: data["nrg"][3]),
|
|
GoeChargerSensor(coordinator, "Current L1", serial, "current_l1", ELECTRIC_CURRENT_AMPERE, DEVICE_CLASS_CURRENT,
|
|
STATE_CLASS_MEASUREMENT, "nrg", lambda data: data["nrg"][4]),
|
|
GoeChargerSensor(coordinator, "Current L2", serial, "current_l2", ELECTRIC_CURRENT_AMPERE, DEVICE_CLASS_CURRENT,
|
|
STATE_CLASS_MEASUREMENT, "nrg", lambda data: data["nrg"][5]),
|
|
GoeChargerSensor(coordinator, "Current L3", serial, "current_l3", ELECTRIC_CURRENT_AMPERE, DEVICE_CLASS_CURRENT,
|
|
STATE_CLASS_MEASUREMENT, "nrg", lambda data: data["nrg"][6]),
|
|
GoeChargerSensorNative(coordinator, "Power L1", serial, "power_l1", POWER_KILO_WATT, DEVICE_CLASS_POWER,
|
|
STATE_CLASS_MEASUREMENT, "nrg", (lambda data: data["nrg"][7] / 1000), POWER_KILO_WATT,
|
|
lambda data: data["nrg"][7]),
|
|
GoeChargerSensorNative(coordinator, "Power L2", serial, "power_l2", POWER_KILO_WATT, DEVICE_CLASS_POWER,
|
|
STATE_CLASS_MEASUREMENT, "nrg", (lambda data: data["nrg"][8] / 1000), POWER_KILO_WATT,
|
|
lambda data: data["nrg"][8]),
|
|
GoeChargerSensorNative(coordinator, "Power L3", serial, "power_l3", POWER_KILO_WATT, DEVICE_CLASS_POWER,
|
|
STATE_CLASS_MEASUREMENT, "nrg", (lambda data: data["nrg"][9] / 1000), POWER_KILO_WATT,
|
|
lambda data: data["nrg"][9]),
|
|
GoeChargerSensorNative(coordinator, "Power N", serial, "power_n", POWER_KILO_WATT, DEVICE_CLASS_POWER,
|
|
STATE_CLASS_MEASUREMENT, "nrg", (lambda data: data["nrg"][10] / 1000), POWER_KILO_WATT,
|
|
lambda data: data["nrg"][10]),
|
|
GoeChargerSensorNative(coordinator, "Power Total", serial, "power_total", POWER_KILO_WATT, DEVICE_CLASS_POWER,
|
|
STATE_CLASS_MEASUREMENT, "nrg", (lambda data: data["nrg"][11] / 1000), POWER_KILO_WATT,
|
|
lambda data: data["nrg"][11]),
|
|
GoeChargerSensor(coordinator, "Powerfactor L1", serial, "powerfactor_l1", POWER_FACTOR,
|
|
DEVICE_CLASS_POWER_FACTOR, STATE_CLASS_MEASUREMENT, "nrg", lambda data: data["nrg"][12]),
|
|
GoeChargerSensor(coordinator, "Powerfactor L2", serial, "powerfactor_l2", POWER_FACTOR,
|
|
DEVICE_CLASS_POWER_FACTOR, STATE_CLASS_MEASUREMENT, "nrg", lambda data: data["nrg"][13]),
|
|
GoeChargerSensor(coordinator, "Powerfactor L3", serial, "powerfactor_l3", POWER_FACTOR,
|
|
DEVICE_CLASS_POWER_FACTOR, STATE_CLASS_MEASUREMENT, "nrg", lambda data: data["nrg"][14]),
|
|
GoeChargerSensor(coordinator, "Powerfactor N", serial, "powerfactor_n", POWER_FACTOR, DEVICE_CLASS_POWER_FACTOR,
|
|
STATE_CLASS_MEASUREMENT, "nrg", lambda data: data["nrg"][15]),
|
|
GoeChargerSensor(coordinator, "Frequency", serial, "frequency", FREQUENCY_HERTZ, None, STATE_CLASS_MEASUREMENT,
|
|
"fhz", lambda data: data["fhz"]),
|
|
GoeChargerSensorNative(coordinator, "Charged", serial, "charged", ENERGY_KILO_WATT_HOUR, DEVICE_CLASS_ENERGY,
|
|
STATE_CLASS_TOTAL_INCREASING, "wh", (lambda data: data["wh"] / 1000), POWER_KILO_WATT,
|
|
lambda data: data["wh"]),
|
|
GoeChargerSensorNative(coordinator, "Charged total", serial, "charged_total", ENERGY_KILO_WATT_HOUR,
|
|
DEVICE_CLASS_ENERGY, STATE_CLASS_TOTAL_INCREASING, "eto",
|
|
(lambda data: data["eto"] / 1000), POWER_KILO_WATT, lambda data: data["eto"]),
|
|
GoeChargerSensor(coordinator, "Temperature 1", serial, "temperature_1", TEMP_CELSIUS, DEVICE_CLASS_TEMPERATURE,
|
|
STATE_CLASS_MEASUREMENT, "tma", lambda data: data["tma"][0]),
|
|
GoeChargerSensor(coordinator, "Temperature 2", serial, "temperature_2", TEMP_CELSIUS, DEVICE_CLASS_TEMPERATURE,
|
|
STATE_CLASS_MEASUREMENT, "tma", lambda data: data["tma"][1]),
|
|
GoeChargerSensor(coordinator, "WiFi RSSI", serial, "wifi_rssi", SIGNAL_STRENGTH_DECIBELS,
|
|
DEVICE_CLASS_SIGNAL_STRENGTH, STATE_CLASS_MEASUREMENT, "rssi", lambda data: data["rssi"]),
|
|
GoeChargerSensor(coordinator, "Cable current limit", serial, "cable_current_limit", ELECTRIC_CURRENT_AMPERE,
|
|
DEVICE_CLASS_CURRENT, None, "cbl", lambda data: data["cbl"]),
|
|
GoeChargerSensor(coordinator, "Allowed current", serial, "allowed_current", ELECTRIC_CURRENT_AMPERE,
|
|
DEVICE_CLASS_CURRENT, None, "acu", lambda data: "" if data["acu"] is None else data["acu"]),
|
|
GoeChargerSensor(coordinator, "Car state", serial, "car_state", None, None, None, "car", car_state_data),
|
|
GoeChargerSensor(coordinator, "Error", serial, "error", None, None, None, "err", error_data),
|
|
GoeChargerSensor(coordinator, "Model status", serial, "model_status", None, None, None, "modelStatus",
|
|
model_status_data),
|
|
])
|
|
|
|
|
|
class GoeChargerSensor(CoordinatorEntity, SensorEntity):
|
|
"""Representation of a Sensor."""
|
|
|
|
def __init__(self, coordinator: DataUpdateCoordinator, name: str, serial: str, unique_id: str,
|
|
unit_of_measurement: str | None, device_class: str | None, state_class: str | None, key: str,
|
|
state_cb):
|
|
"""Pass coordinator to CoordinatorEntity."""
|
|
super().__init__(coordinator)
|
|
self._name = name
|
|
self._serial = serial
|
|
self._unique_id = unique_id
|
|
self._unit_of_measurement = unit_of_measurement
|
|
self._device_class = device_class
|
|
self._state_class = state_class
|
|
self._key = key
|
|
self._state_cb = state_cb
|
|
|
|
@property
|
|
def name(self):
|
|
"""Return the name of the device."""
|
|
return self._name
|
|
|
|
@property
|
|
def unique_id(self):
|
|
"""Return the unique id of the device."""
|
|
return "goe_charger_" + self._serial + "_" + self._unique_id
|
|
|
|
@property
|
|
def available(self) -> bool:
|
|
"""Return True if entity is available."""
|
|
return (self.coordinator.data is not None and
|
|
self._key in self.coordinator.data and
|
|
self.coordinator.data[self._key] is not None)
|
|
|
|
@property
|
|
def state(self):
|
|
"""Return the state of the sensor."""
|
|
return None if not self.available else self._state_cb(self.coordinator.data)
|
|
|
|
@property
|
|
def unit_of_measurement(self):
|
|
"""Return the unit of measurement."""
|
|
return self._unit_of_measurement
|
|
|
|
@property
|
|
def device_class(self):
|
|
"""Return the device class."""
|
|
return self._device_class
|
|
|
|
@property
|
|
def state_class(self):
|
|
"""Return the state class."""
|
|
return self._state_class
|
|
|
|
async def async_update(self):
|
|
"""Fetch new state data for the sensor.
|
|
This is the only method that should fetch new data for Home Assistant.
|
|
"""
|
|
await self.coordinator.async_request_refresh()
|
|
|
|
@property
|
|
def device_info(self):
|
|
"""Get attributes about the device."""
|
|
return {
|
|
"identifiers": {(DOMAIN, self._serial)}
|
|
}
|
|
|
|
|
|
class GoeChargerSensorNative(GoeChargerSensor):
|
|
"""Representation of a Sensor with separated native unit/value."""
|
|
|
|
def __init__(self, coordinator: DataUpdateCoordinator, name: str, serial: str, unique_id: str,
|
|
unit_of_measurement: str | None, device_class: str | None, state_class: str | None, key: str, state_cb,
|
|
native_unit_of_measurement: str | None, native_state_cb):
|
|
"""Pass coordinator to GoeChargerSensor."""
|
|
super().__init__(coordinator, name, serial, unique_id, unit_of_measurement, device_class, state_class, key,
|
|
state_cb)
|
|
self._native_unit_of_measurement = native_unit_of_measurement
|
|
self._native_state_cb = native_state_cb
|
|
|
|
@property
|
|
def native_value(self):
|
|
"""Return the value reported by the sensor."""
|
|
return None if not self.available else self._native_state_cb(self.coordinator.data)
|
|
|
|
@property
|
|
def native_unit_of_measurement(self) -> str | None:
|
|
"""Return the native unit of measurement."""
|
|
return self._native_unit_of_measurement
|