190 lines
6.6 KiB
Python
190 lines
6.6 KiB
Python
from homeassistant.components.sensor import SensorDeviceClass
|
|
from homeassistant.components.utility_meter.const import CONF_METER_TYPE, METER_TYPES
|
|
from homeassistant.const import UnitOfPower
|
|
from homeassistant.data_entry_flow import section
|
|
from homeassistant.helpers import selector
|
|
from homeassistant.helpers.selector import NumberSelector, NumberSelectorMode
|
|
import voluptuous as vol
|
|
|
|
from custom_components.powercalc.const import (
|
|
CONF_APPLY_TO_ALL,
|
|
CONF_COST_SENSOR_FRIENDLY_NAMING,
|
|
CONF_COST_SENSOR_NAMING,
|
|
CONF_CREATE_COST_SENSOR,
|
|
CONF_CREATE_ENERGY_SENSOR,
|
|
CONF_CREATE_UTILITY_METERS,
|
|
CONF_ENERGY_FILTER_OUTLIER_ENABLED,
|
|
CONF_ENERGY_FILTER_OUTLIER_MAX,
|
|
CONF_ENERGY_INTEGRATION_METHOD,
|
|
CONF_ENERGY_PRICE,
|
|
CONF_ENERGY_PRICE_MULTIPLIER,
|
|
CONF_ENERGY_PRICE_SENSOR,
|
|
CONF_ENERGY_PRICE_SURCHARGE,
|
|
CONF_ENERGY_SENSOR_UNIT_PREFIX,
|
|
CONF_SUB_PROFILE,
|
|
CONF_UTILITY_METER_NET_CONSUMPTION,
|
|
CONF_UTILITY_METER_OFFSET,
|
|
CONF_UTILITY_METER_TARIFFS,
|
|
CONF_UTILITY_METER_TYPES,
|
|
ENERGY_INTEGRATION_METHOD_LEFT,
|
|
ENERGY_INTEGRATION_METHODS,
|
|
UnitPrefix,
|
|
)
|
|
from custom_components.powercalc.power_profile.power_profile import PowerProfile
|
|
|
|
SCHEMA_UTILITY_METER_TOGGLE = vol.Schema(
|
|
{
|
|
vol.Optional(CONF_CREATE_UTILITY_METERS, default=False): selector.BooleanSelector(),
|
|
},
|
|
)
|
|
|
|
SCHEMA_ENERGY_SENSOR_TOGGLE = vol.Schema(
|
|
{
|
|
vol.Optional(CONF_CREATE_ENERGY_SENSOR, default=True): selector.BooleanSelector(),
|
|
},
|
|
)
|
|
|
|
SCHEMA_COST_SENSOR_TOGGLE = vol.Schema(
|
|
{
|
|
vol.Optional(CONF_CREATE_COST_SENSOR, default=False): selector.BooleanSelector(),
|
|
},
|
|
)
|
|
|
|
SECTION_COST_PRICING = "cost_pricing"
|
|
SECTION_COST_NAMING = "cost_naming"
|
|
COST_DOCS_URI = "https://docs.powercalc.nl/sensor-types/cost-sensor/"
|
|
|
|
# The pricing fields are used both for the global energy price and for the per sensor
|
|
# price override, so they are defined once and reused by both schemas.
|
|
SCHEMA_COST_PRICING = vol.Schema(
|
|
{
|
|
vol.Optional(CONF_ENERGY_PRICE): NumberSelector(
|
|
selector.NumberSelectorConfig(mode=NumberSelectorMode.BOX, step="any"),
|
|
),
|
|
vol.Optional(CONF_ENERGY_PRICE_SENSOR): selector.EntitySelector(
|
|
selector.EntitySelectorConfig(domain="sensor", device_class=SensorDeviceClass.MONETARY),
|
|
),
|
|
vol.Optional(CONF_ENERGY_PRICE_SURCHARGE): NumberSelector(
|
|
selector.NumberSelectorConfig(mode=NumberSelectorMode.BOX, step="any"),
|
|
),
|
|
vol.Optional(CONF_ENERGY_PRICE_MULTIPLIER): NumberSelector(
|
|
selector.NumberSelectorConfig(mode=NumberSelectorMode.BOX, step="any"),
|
|
),
|
|
},
|
|
)
|
|
|
|
SCHEMA_GLOBAL_COST_NAMING = vol.Schema(
|
|
{
|
|
vol.Optional(CONF_COST_SENSOR_NAMING): selector.TextSelector(),
|
|
vol.Optional(CONF_COST_SENSOR_FRIENDLY_NAMING): selector.TextSelector(),
|
|
},
|
|
)
|
|
|
|
# Presented in the GUI as two collapsible sections (pricing and naming).
|
|
SCHEMA_GLOBAL_COST = vol.Schema(
|
|
{
|
|
vol.Required(SECTION_COST_PRICING): section(SCHEMA_COST_PRICING),
|
|
vol.Required(SECTION_COST_NAMING): section(SCHEMA_GLOBAL_COST_NAMING, {"collapsed": True}),
|
|
},
|
|
)
|
|
|
|
# Flat variant with all cost keys, used to merge/clear the (un)nested user input.
|
|
SCHEMA_GLOBAL_COST_FLAT = SCHEMA_COST_PRICING.extend(SCHEMA_GLOBAL_COST_NAMING.schema)
|
|
|
|
# Shown when the global create_cost_sensors toggle is flipped, to optionally propagate the
|
|
# change to all existing GUI sensors.
|
|
SCHEMA_COST_APPLY = vol.Schema(
|
|
{
|
|
vol.Optional(CONF_APPLY_TO_ALL, default=True): selector.BooleanSelector(),
|
|
},
|
|
)
|
|
|
|
SCHEMA_ENERGY_OPTIONS = vol.Schema(
|
|
{
|
|
vol.Optional(
|
|
CONF_ENERGY_INTEGRATION_METHOD,
|
|
default=ENERGY_INTEGRATION_METHOD_LEFT,
|
|
): selector.SelectSelector(
|
|
selector.SelectSelectorConfig(
|
|
options=ENERGY_INTEGRATION_METHODS,
|
|
mode=selector.SelectSelectorMode.DROPDOWN,
|
|
),
|
|
),
|
|
vol.Optional(CONF_ENERGY_SENSOR_UNIT_PREFIX): selector.SelectSelector(
|
|
selector.SelectSelectorConfig(
|
|
options=[
|
|
selector.SelectOptionDict(value=UnitPrefix.KILO, label="k (kilo)"),
|
|
selector.SelectOptionDict(value=UnitPrefix.MEGA, label="M (mega)"),
|
|
selector.SelectOptionDict(value=UnitPrefix.GIGA, label="G (giga)"),
|
|
selector.SelectOptionDict(value=UnitPrefix.TERA, label="T (tera)"),
|
|
],
|
|
mode=selector.SelectSelectorMode.DROPDOWN,
|
|
),
|
|
),
|
|
},
|
|
)
|
|
|
|
SCHEMA_SENSOR_ENERGY_OPTIONS = SCHEMA_ENERGY_OPTIONS.extend(
|
|
vol.Schema(
|
|
{
|
|
vol.Optional(CONF_ENERGY_FILTER_OUTLIER_ENABLED, default=False): selector.BooleanSelector(),
|
|
vol.Optional(CONF_ENERGY_FILTER_OUTLIER_MAX): NumberSelector(
|
|
selector.NumberSelectorConfig(mode=NumberSelectorMode.BOX, unit_of_measurement=UnitOfPower.WATT),
|
|
),
|
|
},
|
|
).schema,
|
|
)
|
|
|
|
|
|
SCHEMA_UTILITY_METER_OPTIONS = vol.Schema(
|
|
{
|
|
vol.Required(CONF_UTILITY_METER_TYPES): selector.SelectSelector(
|
|
selector.SelectSelectorConfig(
|
|
options=METER_TYPES,
|
|
translation_key=CONF_METER_TYPE,
|
|
multiple=True,
|
|
),
|
|
),
|
|
vol.Optional(CONF_UTILITY_METER_TARIFFS, default=[]): selector.SelectSelector(
|
|
selector.SelectSelectorConfig(options=[], custom_value=True, multiple=True),
|
|
),
|
|
vol.Optional(CONF_UTILITY_METER_NET_CONSUMPTION, default=False): selector.BooleanSelector(),
|
|
vol.Required(CONF_UTILITY_METER_OFFSET, default=0): selector.NumberSelector(
|
|
selector.NumberSelectorConfig(
|
|
min=0,
|
|
max=28,
|
|
mode=selector.NumberSelectorMode.BOX,
|
|
unit_of_measurement="days",
|
|
),
|
|
),
|
|
},
|
|
)
|
|
|
|
|
|
async def build_sub_profile_schema(
|
|
profile: PowerProfile,
|
|
selected_sub_profile: str | None,
|
|
) -> vol.Schema:
|
|
"""Create sub profile schema."""
|
|
sub_profiles = [
|
|
selector.SelectOptionDict(
|
|
value=sub_profile[0],
|
|
label=sub_profile[1]["name"] if "name" in sub_profile[1] else sub_profile[0],
|
|
)
|
|
for sub_profile in await profile.get_sub_profiles()
|
|
]
|
|
return vol.Schema(
|
|
{
|
|
vol.Required(
|
|
CONF_SUB_PROFILE,
|
|
description={"suggested_value": selected_sub_profile},
|
|
default=selected_sub_profile,
|
|
): selector.SelectSelector(
|
|
selector.SelectSelectorConfig(
|
|
options=sub_profiles,
|
|
mode=selector.SelectSelectorMode.DROPDOWN,
|
|
),
|
|
),
|
|
},
|
|
)
|