Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement include area in config flow for group #1747

Merged
merged 8 commits into from
Jul 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions custom_components/powercalc/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

from .common import SourceEntity, create_source_entity
from .const import (
CONF_AREA,
CONF_CALCULATION_ENABLED_CONDITION,
CONF_CALIBRATE,
CONF_CREATE_ENERGY_SENSOR,
Expand Down Expand Up @@ -873,6 +874,7 @@ def _create_group_options_schema(hass: HomeAssistant) -> vol.Schema:
),
),
vol.Optional(CONF_SUB_GROUPS): _create_group_selector(hass, multiple=True),
vol.Optional(CONF_AREA): selector.AreaSelector(),
vol.Optional(
CONF_CREATE_UTILITY_METERS,
default=False,
Expand Down Expand Up @@ -915,6 +917,7 @@ def _validate_group_input(user_input: dict[str, Any] | None = None) -> dict:
and CONF_GROUP_POWER_ENTITIES not in user_input
and CONF_GROUP_ENERGY_ENTITIES not in user_input
and CONF_GROUP_MEMBER_SENSORS not in user_input
and CONF_AREA not in user_input
):
errors["base"] = "group_mandatory"

Expand Down
18 changes: 17 additions & 1 deletion custom_components/powercalc/group_include/include.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
CONF_FILTER,
CONF_GROUP,
CONF_TEMPLATE,
DATA_CONFIGURED_ENTITIES,
DOMAIN,
)
from custom_components.powercalc.errors import SensorConfigurationError

Expand All @@ -23,8 +25,22 @@
_LOGGER = logging.getLogger(__name__)


def resolve_include_entities(hass: HomeAssistant, include_config: dict) -> list:
powercalc_entities = []
source_entities = resolve_include_source_entities(hass, include_config)
_LOGGER.debug("Found include entities: %s", source_entities)
for source_entity in source_entities:
if source_entity.entity_id in hass.data[DOMAIN][DATA_CONFIGURED_ENTITIES]:
powercalc_entities.extend(
hass.data[DOMAIN][DATA_CONFIGURED_ENTITIES][
source_entity.entity_id
],
)
return powercalc_entities


@callback
def resolve_include_entities(
def resolve_include_source_entities(
hass: HomeAssistant,
include_config: dict,
) -> list[entity_registry.RegistryEntry]:
Expand Down
14 changes: 3 additions & 11 deletions custom_components/powercalc/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,7 @@ def convert_config_entry_to_sensor_config(config_entry: ConfigEntry) -> ConfigTy
return sensor_config


async def create_sensors( # noqa: C901
async def create_sensors(
hass: HomeAssistant,
config: ConfigType,
discovery_info: DiscoveryInfoType | None = None,
Expand Down Expand Up @@ -604,7 +604,7 @@ async def create_sensors( # noqa: C901
# Setup power sensors for multiple appliances in one config entry
sensor_configs = {}
entities_to_add = EntitiesBucket()
for entity_config in config.get(CONF_ENTITIES) or []:
for entity_config in config.get(CONF_ENTITIES, []):
# When there are nested entities, combine these with the current entities, recursively
if CONF_ENTITIES in entity_config or CONF_CREATE_GROUP in entity_config:
child_entities = await create_sensors(hass, entity_config, context=context)
Expand All @@ -616,15 +616,7 @@ async def create_sensors( # noqa: C901

# Automatically add a bunch of entities by area or evaluating template
if CONF_INCLUDE in config:
include_entities = resolve_include_entities(hass, config.get(CONF_INCLUDE)) # type: ignore
_LOGGER.debug("Found include entities: %s", include_entities)
for source_entity in include_entities:
if source_entity.entity_id in hass.data[DOMAIN][DATA_CONFIGURED_ENTITIES]:
entities_to_add.existing.extend(
hass.data[DOMAIN][DATA_CONFIGURED_ENTITIES][
source_entity.entity_id
],
)
entities_to_add.existing.extend(resolve_include_entities(hass, config.get(CONF_INCLUDE))) # type: ignore

# Create sensors for each entity
for sensor_config in sensor_configs.values():
Expand Down
13 changes: 11 additions & 2 deletions custom_components/powercalc/sensors/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
from custom_components.powercalc.const import (
ATTR_ENTITIES,
ATTR_IS_GROUP,
CONF_AREA,
CONF_DISABLE_EXTENDED_ATTRIBUTES,
CONF_ENERGY_SENSOR_PRECISION,
CONF_ENERGY_SENSOR_UNIT_PREFIX,
Expand All @@ -71,6 +72,7 @@
SensorType,
UnitPrefix,
)
from custom_components.powercalc.group_include.include import resolve_include_entities

from .abstract import (
BaseEntity,
Expand Down Expand Up @@ -168,8 +170,13 @@ async def create_group_sensors_from_config_entry(
if CONF_UNIQUE_ID not in sensor_config:
sensor_config[CONF_UNIQUE_ID] = entry.entry_id

area_entities: list[Entity] = []
if CONF_AREA in entry.data:
area_entities = resolve_include_entities(hass, {CONF_AREA: entry.data[CONF_AREA]})

power_sensor_ids: set[str] = set(
resolve_entity_ids_recursively(hass, entry, SensorDeviceClass.POWER),
resolve_entity_ids_recursively(hass, entry, SensorDeviceClass.POWER) +
[entity.entity_id for entity in area_entities if isinstance(entity, PowerSensor)],
)
if power_sensor_ids:
power_sensor = create_grouped_power_sensor(
Expand All @@ -181,7 +188,8 @@ async def create_group_sensors_from_config_entry(
group_sensors.append(power_sensor)

energy_sensor_ids: set[str] = set(
resolve_entity_ids_recursively(hass, entry, SensorDeviceClass.ENERGY),
resolve_entity_ids_recursively(hass, entry, SensorDeviceClass.ENERGY) +
[entity.entity_id for entity in area_entities if isinstance(entity, EnergySensor)],
)
if energy_sensor_ids:
energy_sensor = create_grouped_energy_sensor(
Expand Down Expand Up @@ -350,6 +358,7 @@ def resolve_entity_ids_recursively(
_LOGGER.error(f"Subgroup config entry not found: {subgroup_entry_id}")
continue
resolve_entity_ids_recursively(hass, subgroup_entry, device_class, resolved_ids)

return resolved_ids


Expand Down
2 changes: 1 addition & 1 deletion custom_components/powercalc/strategy/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ async def _create_composite(
power_profile: PowerProfile | None,
source_entity: SourceEntity,
) -> CompositeStrategy:
sub_strategies = config.get(CONF_COMPOSITE) # type: ignore
sub_strategies = list(config.get(CONF_COMPOSITE)) # type: ignore

async def _create_sub_strategy(strategy_config: ConfigType) -> SubStrategy:
condition_instance = None
Expand Down
6 changes: 5 additions & 1 deletion custom_components/powercalc/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,16 @@
"group_power_entities": "Additional power entities",
"group_energy_entities": "Additional energy entities",
"sub_groups": "Sub groups",
"area": "Area",
"hide_members": "Hide members",
"create_utility_meters": "[%key:component::powercalc::config::step::virtual_power::data::create_utility_meters%]"
},
"data_description": {
"group_member_sensors": "Powercalc sensors to include in the group",
"group_power_entities": "Additional power sensors (W) from your HA installation to include",
"group_energy_entities": "Additional energy sensors (kWh) from your HA installation to include",
"sub_groups": "All containing sensors from the selected subgroups will be added to this group as well"
"sub_groups": "All containing sensors from the selected subgroups will be added to this group as well",
"area": "Adds all powercalc sensors from the specified area"
}
},
"virtual_power": {
Expand Down Expand Up @@ -191,6 +193,7 @@
"group_member_sensors": "[%key:component::powercalc::config::step::group::data::group_member_sensors%]",
"group_power_entities": "[%key:component::powercalc::config::step::group::data::group_power_entities%]",
"group_energy_entities": "[%key:component::powercalc::config::step::group::data::group_energy_entities%]",
"area": "[%key:component::powercalc::config::step::group::data::area%]",
"sub_groups": "[%key:component::powercalc::config::step::group::data::sub_groups%]",
"hide_members": "[%key:component::powercalc::config::step::group::data::hide_members%]",
"energy_integration_method": "[%key:component::powercalc::config::step::power_advanced::data::energy_integration_method%]",
Expand All @@ -204,6 +207,7 @@
"attribute": "[%key:component::powercalc::config::step::linear::data_description::attribute%]",
"power_template": "[%key:component::powercalc::config::step::fixed::data_description::power_template%]",
"states_power": "[%key:component::powercalc::config::step::fixed::data_description::states_power%]",
"area": "[%key:component::powercalc::config::step::group::data_description::area%]",
"sub_groups": "[%key:component::powercalc::config::step::group::data_description::sub_groups%]",
"group_member_sensors": "[%key:component::powercalc::config::step::group::data_description::group_member_sensors%]",
"group_power_entities": "[%key:component::powercalc::config::step::group::data_description::group_power_entities%]",
Expand Down
6 changes: 5 additions & 1 deletion custom_components/powercalc/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,16 @@
"group_energy_entities": "Additional energy entities",
"name": "Name",
"sub_groups": "Sub groups",
"area": "Area",
"hide_members": "Hide members",
"unique_id": "Unique id"
},
"data_description": {
"group_member_sensors": "Powercalc sensors to include in the group",
"group_power_entities": "Additional power sensors (W) from your HA installation to include",
"group_energy_entities": "Additional energy sensors (kWh) from your HA installation to include",
"sub_groups": "All containing sensors from the selected subgroups will be added to this group as well"
"sub_groups": "All containing sensors from the selected subgroups will be added to this group as well",
"area": "Adds all powercalc sensors from the specified area"
},
"title": "Create a group sensor"
},
Expand Down Expand Up @@ -179,6 +181,7 @@
"step": {
"init": {
"data": {
"area": "Area",
"attribute": "Attribute",
"calculation_enabled_condition": "Calculation enabled condition",
"calibrate": "Calibration values",
Expand Down Expand Up @@ -208,6 +211,7 @@
"value_template": "Value template"
},
"data_description": {
"area": "Adds all powercalc sensors from the specified area",
"attribute": "Specify the attribute. When left empty will be brightness for lights and percentage for fans",
"calculation_enabled_condition": "The configured power calculation strategy will only be executed when this template evaluates to true or 1, otherwise the power sensor will display 0",
"calibrate": "Put a calibration value on each line. Example\n\n1: 20",
Expand Down
6 changes: 5 additions & 1 deletion custom_components/powercalc/translations/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,16 @@
"group_power_entities": "Additionele vermogen entiteiten",
"name": "Naam",
"sub_groups": "Sub groepen",
"area": "Ruimte",
"hide_members": "Verberg onderliggende sensoren",
"unique_id": "Uniek id"
},
"data_description": {
"group_member_sensors": "Powercalc sensoren die je wil toevoegen aan de groep",
"group_power_entities": "Additionele vermogen entiteiten (W)",
"group_energy_entities": "Additionele energie entiteiten (kWh)",
"sub_groups": "Alle onderliggende sensoren van de geselecteerde sub-groepen worden ook automatisch aan deze groep toegevoegd."
"sub_groups": "Alle onderliggende sensoren van de geselecteerde sub-groepen worden ook automatisch aan deze groep toegevoegd.",
"area": "Voeg alle powercalc sensoren van de gespecificeerde ruimte toe"
},
"title": "Creëer een groep sensor"
},
Expand Down Expand Up @@ -179,6 +181,7 @@
"step": {
"init": {
"data": {
"area": "Ruimte",
"attribute": "Attribuut",
"calculation_enabled_condition": "Calculatie ingeschakeld conditie",
"calibrate": "Kalibratie waardes",
Expand Down Expand Up @@ -208,6 +211,7 @@
"value_template": "Waarde template"
},
"data_description": {
"area": "Voeg alle powercalc sensoren van de gespecificeerde ruimte toe",
"attribute": "Specificeer een attribuut. Wanneer je dit leeg laat dan wordt helderheid gebruikt voor verlichting en percentage voor ventilatoren",
"calculation_enabled_condition": "De geconfigureerde vermogen calculatie strategie wordt alleen uitgevoerd indien dit template evalueert naar 1, anders zal de energiesensor 0 tonen",
"calibrate": "Kalibratiewaarde op iedere regel. Voorbeeld\n\n1: 20",
Expand Down
52 changes: 52 additions & 0 deletions tests/test_config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from homeassistant import config_entries, data_entry_flow
from homeassistant.components import sensor
from homeassistant.const import (
CONF_ENTITIES,
CONF_ENTITY_ID,
CONF_NAME,
CONF_PLATFORM,
Expand All @@ -17,6 +18,8 @@
)
from homeassistant.core import HomeAssistant
from homeassistant.data_entry_flow import FlowResult
from homeassistant.helpers.area_registry import AreaRegistry
from homeassistant.helpers.entity_registry import EntityRegistry
from homeassistant.helpers.selector import SelectSelector
from homeassistant.helpers.typing import ConfigType
from homeassistant.setup import async_setup_component
Expand All @@ -29,6 +32,7 @@
MENU_OPTION_LIBRARY,
)
from custom_components.powercalc.const import (
CONF_AREA,
CONF_CALCULATION_ENABLED_CONDITION,
CONF_CREATE_ENERGY_SENSOR,
CONF_CREATE_UTILITY_METERS,
Expand Down Expand Up @@ -708,6 +712,54 @@ async def test_create_group_entry_without_unique_id(hass: HomeAssistant) -> None
assert hass.states.get("sensor.my_group_sensor_power")


async def test_group_include_area(hass: HomeAssistant, entity_reg: EntityRegistry,
area_reg: AreaRegistry) -> None:

# Create light entity and add to group My area
light = MockLight("test")
await create_mock_light_entity(hass, light)
area = area_reg.async_get_or_create("My area")
entity_reg.async_update_entity(light.entity_id, area_id=area.id)

result = await _goto_virtual_power_strategy_step(hass, CalculationStrategy.FIXED, {CONF_ENTITY_ID: "light.test"})
await _set_virtual_power_configuration(
hass,
result,
{CONF_STATES_POWER: {"playing": 1.8}},
)

result = await _select_sensor_type(hass, SensorType.GROUP)
user_input = {
CONF_NAME: "My group sensor",
CONF_AREA: area.id,
CONF_CREATE_UTILITY_METERS: True,
}
result = await hass.config_entries.flow.async_configure(
result["flow_id"],
user_input,
)
assert result["type"] == data_entry_flow.FlowResultType.CREATE_ENTRY
assert result["data"] == {
CONF_SENSOR_TYPE: SensorType.GROUP,
CONF_NAME: "My group sensor",
CONF_HIDE_MEMBERS: False,
CONF_AREA: area.id,
CONF_UNIQUE_ID: "My group sensor",
CONF_CREATE_UTILITY_METERS: True,
}
await hass.async_block_till_done()

power_state = hass.states.get("sensor.my_group_sensor_power")
assert power_state
assert power_state.attributes.get(CONF_ENTITIES) == {"sensor.test_power"}

energy_state = hass.states.get("sensor.my_group_sensor_energy")
assert energy_state
assert energy_state.attributes.get(CONF_ENTITIES) == {"sensor.test_energy"}

assert hass.states.get("sensor.my_group_sensor_energy_daily")


async def test_can_select_existing_powercalc_entry_as_group_member(
hass: HomeAssistant,
) -> None:
Expand Down
Loading