Skip to content

Commit

Permalink
Commit WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
bramstroker committed Sep 25, 2022
1 parent 6b5d59b commit fd55b6c
Show file tree
Hide file tree
Showing 8 changed files with 333 additions and 48 deletions.
2 changes: 1 addition & 1 deletion custom_components/powercalc/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
from .power_profile.library import ModelInfo, ProfileLibrary
from .power_profile.model_discovery import get_power_profile
from .power_profile.power_profile import PowerProfile
from .sensors.daily_energy import DEFAULT_DAILY_UPDATE_FREQUENCY
from custom_components.powercalc.sensors.fixed_energy.daily_energy import DEFAULT_DAILY_UPDATE_FREQUENCY
from .strategy.factory import PowerCalculatorStrategyFactory
from .strategy.strategy_interface import PowerCalculationStrategyInterface
from .strategy.wled import CONFIG_SCHEMA as SCHEMA_POWER_WLED
Expand Down
1 change: 1 addition & 0 deletions custom_components/powercalc/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
CONF_ENERGY_SENSOR_PRECISION = "energy_sensor_precision"
CONF_ENERGY_SENSOR_UNIT_PREFIX = "energy_sensor_unit_prefix"
CONF_FIXED = "fixed"
CONF_FIXED_ENERGY = "fixed_energy"
CONF_FORCE_UPDATE_FREQUENCY = "force_update_frequency"
CONF_GROUP = "group"
CONF_GROUP_POWER_ENTITIES = "group_power_entities"
Expand Down
2 changes: 1 addition & 1 deletion custom_components/powercalc/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@
)
from .power_profile.model_discovery import is_autoconfigurable
from .sensors.abstract import BaseEntity
from .sensors.daily_energy import (
from custom_components.powercalc.sensors.fixed_energy.daily_energy import (
DAILY_FIXED_ENERGY_SCHEMA,
create_daily_fixed_energy_power_sensor,
create_daily_fixed_energy_sensor,
Expand Down
Empty file.
124 changes: 124 additions & 0 deletions custom_components/powercalc/sensors/fixed_energy/abstract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
from __future__ import annotations

import decimal
import logging
from datetime import timedelta
from decimal import Decimal
from typing import Callable

import homeassistant.util.dt as dt_util
from homeassistant.backports.enum import StrEnum
from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
SensorStateClass,
)
from homeassistant.const import (
CONF_UNIQUE_ID,
CONF_UNIT_OF_MEASUREMENT,
ENERGY_KILO_WATT_HOUR,
ENERGY_MEGA_WATT_HOUR,
ENERGY_WATT_HOUR,
)
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.restore_state import RestoreEntity
from homeassistant.helpers.template import Template
from homeassistant.helpers.typing import ConfigType
from custom_components.powercalc.const import (
CONF_ENERGY_SENSOR_CATEGORY,
CONF_ENERGY_SENSOR_UNIT_PREFIX,
UnitPrefix,
)
from custom_components.powercalc.sensors.energy import EnergySensor

_LOGGER = logging.getLogger(__name__)

ENERGY_ICON = "mdi:lightning-bolt"


class FixedEnergyMode(StrEnum):
DAILY = "daily"
CYCLIC = "cyclic"


class FixedEnergySensor(RestoreEntity, SensorEntity, EnergySensor):
_attr_device_class = SensorDeviceClass.ENERGY
_attr_state_class = SensorStateClass.TOTAL
_attr_should_poll = False
_attr_icon = ENERGY_ICON

def __init__(
self,
hass: HomeAssistant,
name: str,
entity_id: str,
sensor_config: ConfigType,
mode_config: ConfigType,
rounding_digits: int = 4,
):
self._hass = hass
self._attr_name = name
self._state: Decimal = Decimal(0)
self._attr_entity_category = sensor_config.get(CONF_ENERGY_SENSOR_CATEGORY)
self._value: float | Template | None = None
self._user_unit_of_measurement = mode_config.get(CONF_UNIT_OF_MEASUREMENT)
self._update_frequency: int | None = None
self._sensor_config = sensor_config
self._on_time: timedelta | None = None
self._rounding_digits = rounding_digits
self._attr_unique_id = sensor_config.get(CONF_UNIQUE_ID)
self.entity_id = entity_id
self._last_updated: float = dt_util.utcnow().timestamp()
self._last_delta_calculate: float | None = None
self.set_native_unit_of_measurement()
self._update_timer_removal: Callable[[], None] | None = None
self.set_sensor_properties_from_mode_config(mode_config)

def set_sensor_properties_from_mode_config(self, sensor_config: ConfigType):
pass

def set_native_unit_of_measurement(self):
"""Set the native unit of measurement"""
unit_prefix = (
self._sensor_config.get(CONF_ENERGY_SENSOR_UNIT_PREFIX) or UnitPrefix.KILO
)
if unit_prefix == UnitPrefix.KILO:
self._attr_native_unit_of_measurement = ENERGY_KILO_WATT_HOUR
elif unit_prefix == UnitPrefix.NONE:
self._attr_native_unit_of_measurement = ENERGY_WATT_HOUR
elif unit_prefix == UnitPrefix.MEGA:
self._attr_native_unit_of_measurement = ENERGY_MEGA_WATT_HOUR

async def async_added_to_hass(self):
"""Handle entity which will be added."""

if state := await self.async_get_last_state():
try:
self._state = Decimal(state.state)
except decimal.DecimalException:
_LOGGER.warning(
f"{self.entity_id}: Cannot restore state: {state.state}"
)
self._state = Decimal(0)
self._last_updated = state.last_changed.timestamp()
self._state += self.calculate_delta()
self.async_schedule_update_ha_state()
else:
self._state = Decimal(0)

_LOGGER.debug(f"{self.entity_id}: Restoring state: {self._state}")

def calculate_delta(self, elapsed_seconds: int = 0) -> Decimal:
return Decimal(0)

@property
def native_value(self):
"""Return the state of the sensor."""
return round(self._state, self._rounding_digits)

@callback
def async_reset_energy(self) -> None:
_LOGGER.debug(f"{self.entity_id}: Reset energy sensor")
self._state = 0
self._attr_last_reset = dt_util.utcnow()
self.async_write_ha_state()
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
from homeassistant.helpers.template import Template
from homeassistant.helpers.typing import ConfigType

from ..common import SourceEntity
from ..const import (
from custom_components.powercalc.common import SourceEntity
from custom_components.powercalc.const import (
CONF_DAILY_FIXED_ENERGY,
CONF_ENERGY_SENSOR_CATEGORY,
CONF_ENERGY_SENSOR_PRECISION,
Expand All @@ -45,33 +45,24 @@
CONF_VALUE,
UnitPrefix,
)
from ..migrate import async_migrate_entity_id
from .abstract import generate_energy_sensor_entity_id, generate_energy_sensor_name
from .energy import EnergySensor
from .power import VirtualPowerSensor, create_virtual_power_sensor
from custom_components.powercalc.migrate import async_migrate_entity_id
from custom_components.powercalc.sensors.abstract import generate_energy_sensor_entity_id, generate_energy_sensor_name
from custom_components.powercalc.sensors.energy import EnergySensor
from custom_components.powercalc.sensors.power import VirtualPowerSensor, create_virtual_power_sensor

ENERGY_ICON = "mdi:lightning-bolt"
ENTITY_ID_FORMAT = SENSOR_DOMAIN + ".{}"

DEFAULT_DAILY_UPDATE_FREQUENCY = 1800
DAILY_FIXED_ENERGY_SCHEMA = vol.Schema(
CYCLIC_FIXED_ENERGY_SCHEMA = vol.Schema(
{
vol.Required(CONF_VALUE): vol.Any(vol.Coerce(float), cv.template),
vol.Optional(CONF_UNIT_OF_MEASUREMENT, default=ENERGY_KILO_WATT_HOUR): vol.In(
[ENERGY_KILO_WATT_HOUR, POWER_WATT]
),
vol.Optional(CONF_ON_TIME, default=timedelta(days=1)): cv.time_period,
vol.Optional(CONF_START_TIME): cv.time,
vol.Optional(
CONF_UPDATE_FREQUENCY, default=DEFAULT_DAILY_UPDATE_FREQUENCY
): vol.Coerce(int),
vol.Required("triggers"): vol.Any(vol.Coerce(float), cv.template),
}
)

_LOGGER = logging.getLogger(__name__)


async def create_daily_fixed_energy_sensor(
async def create_cyclic_fixed_energy_sensor(
hass: HomeAssistant,
sensor_config: ConfigType,
source_entity: SourceEntity | None = None,
Expand Down Expand Up @@ -121,33 +112,7 @@ async def create_daily_fixed_energy_sensor(
)


async def create_daily_fixed_energy_power_sensor(
hass: HomeAssistant, sensor_config: dict, source_entity: SourceEntity
) -> VirtualPowerSensor | None:
mode_config: dict = sensor_config.get(CONF_DAILY_FIXED_ENERGY)
if mode_config.get(CONF_UNIT_OF_MEASUREMENT) != POWER_WATT:
return None

if mode_config.get(CONF_ON_TIME) != timedelta(days=1):
return None

power_sensor_config = sensor_config.copy()
power_sensor_config[CONF_FIXED] = {CONF_POWER: mode_config.get(CONF_VALUE)}

unique_id = sensor_config.get(CONF_UNIQUE_ID)
if unique_id:
power_sensor_config[CONF_UNIQUE_ID] = f"{unique_id}_power"

_LOGGER.debug(
"Creating daily_fixed_energy power sensor (base_name=%s unique_id=%s)",
sensor_config.get(CONF_NAME),
unique_id,
)

return await create_virtual_power_sensor(hass, power_sensor_config, source_entity)


class DailyEnergySensor(RestoreEntity, SensorEntity, EnergySensor):
class CyclicEnergySensor(RestoreEntity, SensorEntity, EnergySensor):
_attr_device_class = SensorDeviceClass.ENERGY
_attr_state_class = SensorStateClass.TOTAL
_attr_should_poll = False
Expand Down
Loading

0 comments on commit fd55b6c

Please sign in to comment.