Skip to content

Commit

Permalink
handling new grid object (supporting PR evcc-io/evcc#18063)
Browse files Browse the repository at this point in the history
  • Loading branch information
marq24 committed Jan 11, 2025
1 parent 7139db5 commit 510c54e
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 54 deletions.
16 changes: 12 additions & 4 deletions custom_components/evcc_intg/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ def __init__(self, hass: HomeAssistant, config_entry):
self._loadpoint = {}
self._vehicle = {}
self._version = None
self._grid_data_as_object = False

super().__init__(hass, _LOGGER, name=DOMAIN, update_interval=SCAN_INTERVAL)

Expand Down Expand Up @@ -220,8 +221,12 @@ async def read_evcc_config_on_startup(self):
if self._currency == "EUR":
self._currency = "€"

if "grid" in initdata:
if "power" in initdata["grid"] and "currents" in initdata["grid"]:
self._grid_data_as_object = True

_LOGGER.debug(
f"read_evcc_config: LPs: {len(self._loadpoint)} VEHs: {len(self._vehicle)} CT: '{self._cost_type}' CUR: {self._currency}")
f"read_evcc_config: LPs: {len(self._loadpoint)} VEHs: {len(self._vehicle)} CT: '{self._cost_type}' CUR: {self._currency} GAO: {self._grid_data_as_object}")

async def _async_update_data(self) -> dict:
"""Update data via library."""
Expand Down Expand Up @@ -397,17 +402,20 @@ def _convert_time(value: str):
return None

@property
def system_id(self):
def system_id(self) -> str:
return self._system_id

@property
def currency(self):
def currency(self) -> str:
return self._currency

@property
def device_info_dict(self):
def device_info_dict(self) -> dict:
return self._device_info_dict

@property
def grid_data_as_object(self) -> bool:
return self._grid_data_as_object

class EvccBaseEntity(Entity):
_attr_should_poll = False
Expand Down
134 changes: 90 additions & 44 deletions custom_components/evcc_intg/const.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from dataclasses import dataclass
from typing import Final

from custom_components.evcc_intg.pyevcc_ha.keys import Tag
from custom_components.evcc_intg.pyevcc_ha.keys import Tag, GRID_CONTENT, PV_CONTENT
from homeassistant.components.binary_sensor import BinarySensorEntityDescription, BinarySensorDeviceClass
from homeassistant.components.button import ButtonEntityDescription
from homeassistant.components.number import NumberEntityDescription, NumberMode, NumberDeviceClass
Expand Down Expand Up @@ -396,84 +396,130 @@ class ExtSwitchEntityDescription(SwitchEntityDescription):
)
]

SENSOR_SENSORS = [
SENSOR_SENSORS_GRID_AS_PREFIX = [
ExtSensorEntityDescription(
tag=Tag.AUXPOWER,
key=Tag.AUXPOWER.key,
icon="mdi:home-circle-outline",
tag=Tag.GRIDPOWER,
key=Tag.GRIDPOWER.key,
icon="mdi:transmission-tower",
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
entity_registry_enabled_default=False
suggested_display_precision=2,
device_class=SensorDeviceClass.POWER
),
ExtSensorEntityDescription(
tag=Tag.BATTERYMODE,
key=f"{Tag.BATTERYMODE.key}_value",
icon="mdi:state-machine",
lookup=True
tag=Tag.GRIDCURRENTS,
key=f"{Tag.GRIDCURRENTS.key}_0",
array_idx=0,
icon="mdi:current-ac",
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
device_class=SensorDeviceClass.CURRENT,
entity_registry_enabled_default=False
),
ExtSensorEntityDescription(
tag=Tag.BATTERYMODE,
key=f"{Tag.BATTERYMODE.key}",
icon="mdi:state-machine",
tag=Tag.GRIDCURRENTS,
key=f"{Tag.GRIDCURRENTS.key}_1",
array_idx=1,
icon="mdi:current-ac",
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
device_class=SensorDeviceClass.CURRENT,
entity_registry_enabled_default=False
),
ExtSensorEntityDescription(
tag=Tag.BATTERYPOWER,
key=Tag.BATTERYPOWER.key,
icon="mdi:battery-charging",
tag=Tag.GRIDCURRENTS,
key=f"{Tag.GRIDCURRENTS.key}_2",
array_idx=2,
icon="mdi:current-ac",
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER
),
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
device_class=SensorDeviceClass.CURRENT,
entity_registry_enabled_default=False
)
]

SENSOR_SENSORS_GRID_AS_OBJECT = [
ExtSensorEntityDescription(
tag=Tag.BATTERYSOC,
key=Tag.BATTERYSOC.key,
icon="mdi:home-battery-outline",
tag=Tag.GRID,
key=Tag.GRIDPOWER.key,
idx = GRID_CONTENT.POWER,
icon="mdi:transmission-tower",
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=PERCENTAGE,
device_class=None,
suggested_display_precision=0
native_unit_of_measurement=UnitOfPower.WATT,
suggested_display_precision=2,
device_class=SensorDeviceClass.POWER
),
ExtSensorEntityDescription(
tag=Tag.GRIDCURRENTS,
tag=Tag.GRID,
key=f"{Tag.GRIDCURRENTS.key}_0",
array_idx=0,
tuple_idx = [GRID_CONTENT.CURRENTS, 0],
icon="mdi:current-ac",
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
device_class=SensorDeviceClass.CURRENT,
entity_registry_enabled_default=False
),
ExtSensorEntityDescription(
tag=Tag.GRIDCURRENTS,
tag=Tag.GRID,
key=f"{Tag.GRIDCURRENTS.key}_1",
array_idx=1,
tuple_idx = [GRID_CONTENT.CURRENTS, 1],
icon="mdi:current-ac",
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
device_class=SensorDeviceClass.CURRENT,
entity_registry_enabled_default=False
),
ExtSensorEntityDescription(
tag=Tag.GRIDCURRENTS,
tag=Tag.GRID,
key=f"{Tag.GRIDCURRENTS.key}_2",
array_idx=2,
tuple_idx = [GRID_CONTENT.CURRENTS, 2],
icon="mdi:current-ac",
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
device_class=SensorDeviceClass.CURRENT,
entity_registry_enabled_default=False
),
]

SENSOR_SENSORS = [
ExtSensorEntityDescription(
tag=Tag.GRIDPOWER,
key=Tag.GRIDPOWER.key,
icon="mdi:transmission-tower",
tag=Tag.AUXPOWER,
key=Tag.AUXPOWER.key,
icon="mdi:home-circle-outline",
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
entity_registry_enabled_default=False
),
ExtSensorEntityDescription(
tag=Tag.BATTERYMODE,
key=f"{Tag.BATTERYMODE.key}_value",
icon="mdi:state-machine",
lookup=True
),
ExtSensorEntityDescription(
tag=Tag.BATTERYMODE,
key=f"{Tag.BATTERYMODE.key}",
icon="mdi:state-machine",
entity_registry_enabled_default=False
),
ExtSensorEntityDescription(
tag=Tag.BATTERYPOWER,
key=Tag.BATTERYPOWER.key,
icon="mdi:battery-charging",
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfPower.WATT,
suggested_display_precision=2,
device_class=SensorDeviceClass.POWER
),
ExtSensorEntityDescription(
tag=Tag.BATTERYSOC,
key=Tag.BATTERYSOC.key,
icon="mdi:home-battery-outline",
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=PERCENTAGE,
device_class=None,
suggested_display_precision=0
),
ExtSensorEntityDescription(
tag=Tag.HOMEPOWER,
key=Tag.HOMEPOWER.key,
Expand All @@ -495,7 +541,7 @@ class ExtSwitchEntityDescription(SwitchEntityDescription):
ExtSensorEntityDescription(
tag=Tag.PV,
key="pv_0_energy",
tuple_idx = [0, "energy"],
tuple_idx = [0, PV_CONTENT.ENERGY],
icon="mdi:solar-power",
state_class=SensorStateClass.TOTAL,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
Expand All @@ -506,7 +552,7 @@ class ExtSwitchEntityDescription(SwitchEntityDescription):
ExtSensorEntityDescription(
tag=Tag.PV,
key="pv_1_energy",
tuple_idx = [1, "energy"],
tuple_idx = [1, PV_CONTENT.ENERGY],
icon="mdi:solar-power",
state_class=SensorStateClass.TOTAL,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
Expand All @@ -517,7 +563,7 @@ class ExtSwitchEntityDescription(SwitchEntityDescription):
ExtSensorEntityDescription(
tag=Tag.PV,
key="pv_2_energy",
tuple_idx = [2, "energy"],
tuple_idx = [2, PV_CONTENT.ENERGY],
icon="mdi:solar-power",
state_class=SensorStateClass.TOTAL,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
Expand All @@ -528,7 +574,7 @@ class ExtSwitchEntityDescription(SwitchEntityDescription):
ExtSensorEntityDescription(
tag=Tag.PV,
key="pv_3_energy",
tuple_idx = [3, "energy"],
tuple_idx = [3, PV_CONTENT.ENERGY],
icon="mdi:solar-power",
state_class=SensorStateClass.TOTAL,
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
Expand All @@ -548,7 +594,7 @@ class ExtSwitchEntityDescription(SwitchEntityDescription):
ExtSensorEntityDescription(
tag=Tag.PV,
key="pv_0_power",
tuple_idx = [0, "power"],
tuple_idx = [0, PV_CONTENT.POWER],
icon="mdi:solar-power",
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfPower.WATT,
Expand All @@ -559,7 +605,7 @@ class ExtSwitchEntityDescription(SwitchEntityDescription):
ExtSensorEntityDescription(
tag=Tag.PV,
key="pv_1_power",
tuple_idx = [1, "power"],
tuple_idx = [1, PV_CONTENT.POWER],
icon="mdi:solar-power",
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfPower.WATT,
Expand All @@ -570,7 +616,7 @@ class ExtSwitchEntityDescription(SwitchEntityDescription):
ExtSensorEntityDescription(
tag=Tag.PV,
key="pv_2_power",
tuple_idx = [2, "power"],
tuple_idx = [2, PV_CONTENT.POWER],
icon="mdi:solar-power",
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfPower.WATT,
Expand All @@ -581,7 +627,7 @@ class ExtSwitchEntityDescription(SwitchEntityDescription):
ExtSensorEntityDescription(
tag=Tag.PV,
key="pv_3_power",
tuple_idx = [3, "power"],
tuple_idx = [3, PV_CONTENT.POWER],
icon="mdi:solar-power",
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfPower.WATT,
Expand Down
11 changes: 7 additions & 4 deletions custom_components/evcc_intg/pyevcc_ha/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
JSONKEY_BATTERYMODE: Final = "batteryMode"
JSONKEY_BATTERYPOWER: Final = "batteryPower"
JSONKEY_BATTERYSOC: Final = "batterySoc"
JSONKEY_GRIDCURRENTS: Final = "gridCurrents"
JSONKEY_GRIDPOWER: Final = "gridPower"
JSONKEY_HOMEPOWER: Final = "homePower"
JSONKEY_PVENERGY: Final = "pvEnergy"
JSONKEY_PVPOWER: Final = "pvPower"
Expand All @@ -22,13 +20,18 @@
JSONKEY_STATISTICS_365D: Final = "365d"
JSONKEY_STATISTICS_30D: Final = "30d"

JSONKEY_GRIDCURRENTS: Final = "gridCurrents"
JSONKEY_GRIDPOWER: Final = "gridPower"
JSONKEY_GRID: Final = "grid"

STATES: Final = [JSONKEY_LOADPOINTS, JSONKEY_AUXPOWER, JSONKEY_BATTERYMODE, JSONKEY_BATTERYPOWER, JSONKEY_BATTERYSOC,
JSONKEY_GRIDCURRENTS, JSONKEY_GRIDPOWER, JSONKEY_HOMEPOWER, JSONKEY_PVENERGY, JSONKEY_PVPOWER, JSONKEY_PV, JSONKEY_VEHICLES, JSONKEY_STATISTICS]
JSONKEY_GRID, JSONKEY_GRIDCURRENTS, JSONKEY_GRIDPOWER, JSONKEY_HOMEPOWER, JSONKEY_PVENERGY,
JSONKEY_PVPOWER, JSONKEY_PV, JSONKEY_VEHICLES, JSONKEY_STATISTICS]

# FILTER_LOADPOINTS: Final = f"?jq=.{JSONKEY_LOADPOINTS}"

STATE_QUERY = (
f"?jq={{{JSONKEY_LOADPOINTS}:.{JSONKEY_LOADPOINTS},{JSONKEY_AUXPOWER}:.{JSONKEY_AUXPOWER},{JSONKEY_BATTERYMODE}:.{JSONKEY_BATTERYMODE},{JSONKEY_BATTERYPOWER}:.{JSONKEY_BATTERYPOWER},{JSONKEY_BATTERYSOC}:.{JSONKEY_BATTERYSOC},{JSONKEY_GRIDCURRENTS}:.{JSONKEY_GRIDCURRENTS},{JSONKEY_GRIDPOWER}:.{JSONKEY_GRIDPOWER},{JSONKEY_HOMEPOWER}:.{JSONKEY_HOMEPOWER},{JSONKEY_HOMEPOWER}:.{JSONKEY_HOMEPOWER},{JSONKEY_PVENERGY}:.{JSONKEY_PVENERGY},{JSONKEY_PVPOWER}:.{JSONKEY_PVPOWER},{JSONKEY_PV}:.{JSONKEY_PV},{JSONKEY_VEHICLES}:.{JSONKEY_VEHICLES},{JSONKEY_STATISTICS}:.{JSONKEY_STATISTICS}}}"
f"?jq={{{JSONKEY_LOADPOINTS}:.{JSONKEY_LOADPOINTS},{JSONKEY_AUXPOWER}:.{JSONKEY_AUXPOWER},{JSONKEY_BATTERYMODE}:.{JSONKEY_BATTERYMODE},{JSONKEY_BATTERYPOWER}:.{JSONKEY_BATTERYPOWER},{JSONKEY_BATTERYSOC}:.{JSONKEY_BATTERYSOC},{JSONKEY_GRID}:.{JSONKEY_GRID},{JSONKEY_GRIDCURRENTS}:.{JSONKEY_GRIDCURRENTS},{JSONKEY_GRIDPOWER}:.{JSONKEY_GRIDPOWER},{JSONKEY_HOMEPOWER}:.{JSONKEY_HOMEPOWER},{JSONKEY_HOMEPOWER}:.{JSONKEY_HOMEPOWER},{JSONKEY_PVENERGY}:.{JSONKEY_PVENERGY},{JSONKEY_PVPOWER}:.{JSONKEY_PVPOWER},{JSONKEY_PV}:.{JSONKEY_PV},{JSONKEY_VEHICLES}:.{JSONKEY_VEHICLES},{JSONKEY_STATISTICS}:.{JSONKEY_STATISTICS}}}"
)

MIN_CURRENT_LIST: Final = ["0.125", "0.25", "0.5", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13",
Expand Down
15 changes: 14 additions & 1 deletion custom_components/evcc_intg/pyevcc_ha/keys.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ class EP_TYPE(Enum):
STATISTICS = JSONKEY_STATISTICS
SITE = "site"

class GRID_CONTENT(Enum):
CURRENTS = "currents"
POWER = "power"

class PV_CONTENT(Enum):
ENERGY = "energy"
POWER = "power"

class ApiKey(NamedTuple):
key: str
type: str
Expand All @@ -51,7 +59,7 @@ class ApiKey(NamedTuple):

@property
def snake_case(self) -> str:
return _camel_to_snake(self.key)
return camel_to_snake(self.key)

# see https://docs.evcc.io/docs/reference/api for details
class Tag(ApiKey, Enum):
Expand Down Expand Up @@ -84,6 +92,11 @@ def __str__(self):
# "gridPower": -6280.24,
GRIDPOWER = ApiKey(key="gridPower", type=EP_TYPE.SITE)

# "grid": { "currents": [17.95, 7.71, 1.99],
# "power": -6280.24,
# ...}
GRID = ApiKey(key="grid", type=EP_TYPE.SITE)

# "homePower": 2594.19,
HOMEPOWER = ApiKey(key="homePower", type=EP_TYPE.SITE)

Expand Down
16 changes: 15 additions & 1 deletion custom_components/evcc_intg/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.restore_state import RestoreEntity
from . import EvccDataUpdateCoordinator, EvccBaseEntity
from .const import DOMAIN, SENSOR_SENSORS, SENSOR_SENSORS_PER_LOADPOINT, ExtSensorEntityDescription
from .const import DOMAIN, SENSOR_SENSORS, SENSOR_SENSORS_GRID_AS_PREFIX, SENSOR_SENSORS_GRID_AS_OBJECT, \
SENSOR_SENSORS_PER_LOADPOINT, ExtSensorEntityDescription

_LOGGER = logging.getLogger(__name__)

Expand All @@ -20,6 +21,19 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, add_
entity = EvccSensor(coordinator, description)
entities.append(entity)

# we need to check if the grid data (power & currents) is available as separate object...
# or if it's still part of the main/site object (as gridPower, gridCurrents)
if coordinator.grid_data_as_object():
_LOGGER.debug("evcc grid data is available as separate object")
for description in SENSOR_SENSORS_GRID_AS_OBJECT:
entity = EvccSensor(coordinator, description)
entities.append(entity)
else:
_LOGGER.debug("evcc grid as prefix")
for description in SENSOR_SENSORS_GRID_AS_PREFIX:
entity = EvccSensor(coordinator, description)
entities.append(entity)

multi_loadpoint_config = len(coordinator._loadpoint) > 1
for a_lp_key in coordinator._loadpoint:
load_point_config = coordinator._loadpoint[a_lp_key]
Expand Down

0 comments on commit 510c54e

Please sign in to comment.