211 lines
7.4 KiB
Python
211 lines
7.4 KiB
Python
"""Utility and Energy Manager classes for Hilo integration."""
|
|
|
|
from collections import OrderedDict
|
|
from datetime import timedelta
|
|
|
|
from homeassistant.components.energy.data import async_get_manager
|
|
from homeassistant.components.utility_meter import async_setup as utility_setup
|
|
from homeassistant.components.utility_meter.const import (
|
|
CONF_TARIFFS,
|
|
DOMAIN as UTILITY_DOMAIN,
|
|
)
|
|
from homeassistant.helpers import entity_registry as er
|
|
|
|
from .const import HILO_ENERGY_TOTAL, LOG
|
|
|
|
|
|
class UtilityManager:
|
|
"""Class that maps to the utility_meters."""
|
|
|
|
def __init__(self, hass, period, tariffs):
|
|
"""Initialize the utility manager."""
|
|
self.tariffs = tariffs
|
|
self.hass = hass
|
|
self.period = period
|
|
self.meter_configs = OrderedDict()
|
|
self.meter_entities = {}
|
|
self.new_entities = 0
|
|
|
|
def add_meter(self, entity, tariff_list, net_consumption=False):
|
|
"""Add meter."""
|
|
self.add_meter_entity(entity, tariff_list)
|
|
self.add_meter_config(entity, tariff_list, net_consumption)
|
|
|
|
def add_meter_entity(self, entity, tariff_list):
|
|
"""Add meter entity."""
|
|
if entity in self.hass.data.get("utility_meter_data", {}):
|
|
LOG.debug("Entity %s is already in the utility meters", entity)
|
|
return
|
|
self.new_entities += 1
|
|
for tarif in tariff_list:
|
|
name = f"{entity}_{self.period}"
|
|
meter_name = f"{name} {tarif}"
|
|
LOG.debug("Creating UtilityMeter entity for %s : %s", entity, meter_name)
|
|
self.meter_entities[meter_name] = {
|
|
"meter": entity,
|
|
"name": meter_name,
|
|
"tariff": tarif,
|
|
}
|
|
|
|
def add_meter_config(self, entity, tariff_list, net_consumption):
|
|
"""Add meter configuration."""
|
|
name = f"{entity}_{self.period}"
|
|
LOG.debug(
|
|
"Creating UtilityMeter config: %s %s (Net Consumption: %s)",
|
|
name,
|
|
tariff_list,
|
|
net_consumption,
|
|
)
|
|
self.meter_configs[entity] = OrderedDict(
|
|
{
|
|
"source": f"sensor.{entity}",
|
|
"name": name,
|
|
"cycle": self.period,
|
|
CONF_TARIFFS: tariff_list,
|
|
"net_consumption": net_consumption,
|
|
"utility_meter_sensors": [],
|
|
"offset": timedelta(0),
|
|
"delta_values": False,
|
|
"periodically_resetting": True,
|
|
"always_available": True,
|
|
}
|
|
)
|
|
|
|
async def update(self, async_add_entities):
|
|
"""Update the entities."""
|
|
LOG.debug("=== UtilityManager.update() called ===")
|
|
LOG.debug("Setting up UtilityMeter entities %s", UTILITY_DOMAIN)
|
|
LOG.debug("new_entities count: %d", self.new_entities)
|
|
|
|
if self.new_entities == 0:
|
|
LOG.debug("No new entities, not setting up again")
|
|
return
|
|
|
|
# Get the entity registry
|
|
registry = er.async_get(self.hass)
|
|
|
|
# Filter out entities that already exist
|
|
filtered_configs = OrderedDict()
|
|
|
|
for source_entity, config in self.meter_configs.items():
|
|
# Check if any of the tariff entities for this source already exist
|
|
name = config["name"]
|
|
should_include = False
|
|
|
|
for tariff in config[CONF_TARIFFS]:
|
|
# Remove period from name to match actual entity ID, this is why the check was failing
|
|
name_without_period = name.replace(f"_{self.period}", "")
|
|
entity_id = f"sensor.{name_without_period.lower().replace(' ', '_')}_{tariff.lower()}"
|
|
|
|
if registry.async_get(entity_id) is None:
|
|
should_include = True
|
|
LOG.debug(
|
|
"Entity %s does not exist, will create config for %s",
|
|
entity_id,
|
|
source_entity,
|
|
)
|
|
break
|
|
else:
|
|
LOG.debug("Entity %s already exists", entity_id)
|
|
|
|
if should_include:
|
|
filtered_configs[source_entity] = config
|
|
|
|
if not filtered_configs:
|
|
LOG.debug("All entities already exist, skipping setup")
|
|
self.new_entities = 0
|
|
return
|
|
|
|
LOG.debug("Creating utility meter config for %d sources", len(filtered_configs))
|
|
config = {
|
|
UTILITY_DOMAIN: OrderedDict(
|
|
{**self.hass.data.get("utility_meter_data", {}), **filtered_configs}
|
|
),
|
|
CONF_TARIFFS: self.tariffs,
|
|
}
|
|
|
|
# Replaced utility_setup_platform call
|
|
await utility_setup(self.hass, config)
|
|
self.new_entities = 0
|
|
LOG.debug("=== UtilityManager.update() completed ===")
|
|
|
|
|
|
class EnergyManager:
|
|
"""Class that manages the energy dashboard configuration."""
|
|
|
|
def __init__(self):
|
|
"""Initialize the energy manager."""
|
|
self.updated = False
|
|
|
|
@property
|
|
def msg(self):
|
|
"""Return the message payload for the energy manager."""
|
|
return {
|
|
"energy_sources": self.src,
|
|
"device_consumption": self.dev,
|
|
}
|
|
|
|
@property
|
|
def default_flows(self):
|
|
"""Return the default grid flow configuration."""
|
|
return {
|
|
"type": "grid",
|
|
"flow_from": [],
|
|
"flow_to": [],
|
|
"cost_adjustment_day": 0.0,
|
|
}
|
|
|
|
async def init(self, hass, period):
|
|
"""Initialize the energy manager."""
|
|
self.period = period
|
|
self._manager = await async_get_manager(hass)
|
|
data = self._manager.data or self._manager.default_preferences()
|
|
self.prefs = data.copy()
|
|
self.src = self.prefs.get("energy_sources", [])
|
|
self.dev = self.prefs.get("device_consumption", [])
|
|
if not self.src:
|
|
self.src.append(self.default_flows)
|
|
return self
|
|
|
|
def add_flow_from(self, sensor, rate):
|
|
"""Add grid source flow_from sensor."""
|
|
sensor = f"sensor.{sensor}"
|
|
if any(d["stat_energy_from"] == sensor for d in self.src[0]["flow_from"]):
|
|
return
|
|
self.updated = True
|
|
flow = {
|
|
"stat_energy_from": sensor,
|
|
"stat_cost": None,
|
|
"entity_energy_from": sensor,
|
|
"entity_energy_price": f"sensor.{rate}",
|
|
"number_energy_price": None,
|
|
}
|
|
LOG.debug("Adding %s / %s to grid source", sensor, rate)
|
|
self.src[0]["flow_from"].append(flow)
|
|
|
|
def add_device(self, sensor):
|
|
"""Add device consumption sensor."""
|
|
sensor = f"sensor.{sensor}"
|
|
if any(d["stat_consumption"] == sensor for d in self.dev):
|
|
return
|
|
LOG.debug("Adding %s to individual device consumption", sensor)
|
|
self.updated = True
|
|
self.dev.append({"stat_consumption": sensor})
|
|
|
|
def add_to_dashboard(self, entity, tariff_list):
|
|
"""Add entity to the energy dashboard."""
|
|
for tarif in tariff_list:
|
|
name = f"{entity}_{self.period}"
|
|
if entity == HILO_ENERGY_TOTAL:
|
|
self.add_flow_from(f"{name}_{tarif}", f"hilo_rate_{tarif}")
|
|
else:
|
|
self.add_device(f"{name}_{tarif}")
|
|
|
|
async def update(self):
|
|
"""Push updates to the energy dashboard."""
|
|
if not self.updated:
|
|
return
|
|
LOG.debug("Pushing config to the energy dashboard")
|
|
await self._manager.async_update(self.msg)
|
|
self.updated = False
|