Files
HomeAssistantVS/custom_components/powercalc/flow_helper/schema.py
T

190 lines
6.6 KiB
Python

from homeassistant.components.sensor import SensorDeviceClass
from homeassistant.components.utility_meter 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,
),
),
},
)