Skip to content

Commit

Permalink
Add possibility to bind group sensor to a device
Browse files Browse the repository at this point in the history
  • Loading branch information
bramstroker committed Dec 10, 2023
1 parent c0cfc64 commit 3bde78e
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 9 deletions.
2 changes: 2 additions & 0 deletions custom_components/powercalc/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from homeassistant.config_entries import ConfigEntry, OptionsFlow
from homeassistant.const import (
CONF_ATTRIBUTE,
CONF_DEVICE,
CONF_ENTITY_ID,
CONF_NAME,
CONF_UNIQUE_ID,
Expand Down Expand Up @@ -262,6 +263,7 @@
{
vol.Required(CONF_NAME): str,
vol.Optional(CONF_UNIQUE_ID): selector.TextSelector(),
vol.Optional(CONF_DEVICE): selector.DeviceSelector(),
},
)

Expand Down
9 changes: 3 additions & 6 deletions custom_components/powercalc/group_include/filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def create_composite_filter(


def create_filter(
filter_type: str, filter_config: ConfigType, hass: HomeAssistant
filter_type: str, filter_config: ConfigType, hass: HomeAssistant,
) -> IncludeEntityFilter:
if filter_type == CONF_DOMAIN:
return DomainFilter(filter_config) # type: ignore
Expand Down Expand Up @@ -124,7 +124,7 @@ def __init__(self, hass: HomeAssistant, group_id: str) -> None:
light_component = cast(EntityComponent, hass.data.get(LIGHT_DOMAIN))
light_group = next(
filter(
lambda entity: entity.entity_id == group_id, light_component.entities
lambda entity: entity.entity_id == group_id, light_component.entities,
),
None,
)
Expand All @@ -137,7 +137,7 @@ def is_valid(self, entity: RegistryEntry) -> bool:
return entity.entity_id in self.entity_ids

def find_all_entity_ids_recursively(
self, hass: HomeAssistant, group_entity_id: str, all_entity_ids: list[str]
self, hass: HomeAssistant, group_entity_id: str, all_entity_ids: list[str],
) -> list[str]:
entity_reg = entity_registry.async_get(hass)
light_component = cast(EntityComponent, hass.data.get(LIGHT_DOMAIN))
Expand Down Expand Up @@ -234,6 +234,3 @@ def is_valid(self, entity: RegistryEntry) -> bool:
return any(evaluations)

return all(evaluations)

def append(self, entity_filter: IncludeEntityFilter) -> None:
self.filters.append(entity_filter)
2 changes: 1 addition & 1 deletion custom_components/powercalc/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@
vol.Optional(CONF_TEMPLATE): cv.template,
vol.Optional(CONF_DOMAIN): cv.string,
vol.Optional(CONF_WILDCARD): cv.string,
}
},
)

SENSOR_CONFIG = {
Expand Down
7 changes: 7 additions & 0 deletions custom_components/powercalc/sensors/group.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_UNIT_OF_MEASUREMENT,
CONF_DEVICE,
CONF_DOMAIN,
CONF_ENTITIES,
CONF_NAME,
Expand Down Expand Up @@ -405,6 +406,7 @@ def create_grouped_power_sensor(
rounding_digits=sensor_config.get(CONF_POWER_SENSOR_PRECISION)
or DEFAULT_POWER_SENSOR_PRECISION,
entity_id=entity_id,
device_id=sensor_config.get(CONF_DEVICE),
)


Expand Down Expand Up @@ -437,6 +439,7 @@ def create_grouped_energy_sensor(
rounding_digits=sensor_config.get(CONF_ENERGY_SENSOR_PRECISION)
or DEFAULT_ENERGY_SENSOR_PRECISION,
entity_id=entity_id,
device_id=sensor_config.get(CONF_DEVICE),
)


Expand All @@ -453,6 +456,7 @@ def __init__(
sensor_config: dict[str, Any],
rounding_digits: int,
unique_id: str | None = None,
device_id: str | None = None,
) -> None:
self._attr_name = name
# Remove own entity from entities, when it happens to be there. To prevent recursion
Expand All @@ -468,6 +472,7 @@ def __init__(
if unique_id:
self._attr_unique_id = unique_id
self.entity_id = entity_id
self.source_device_id = device_id
self._prev_state_store: PreviousStateStore = PreviousStateStore(self.hass)

async def async_added_to_hass(self) -> None:
Expand Down Expand Up @@ -623,6 +628,7 @@ def __init__(
sensor_config: dict[str, Any],
rounding_digits: int,
unique_id: str | None = None,
device_id: str | None = None,
) -> None:
super().__init__(
name,
Expand All @@ -631,6 +637,7 @@ def __init__(
sensor_config,
rounding_digits,
unique_id,
device_id,
)
unit_prefix = sensor_config.get(CONF_ENERGY_SENSOR_UNIT_PREFIX)
if unit_prefix == UnitPrefix.KILO:
Expand Down
2 changes: 1 addition & 1 deletion tests/group_include/test_filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ async def test_complex_nested_filters(hass: HomeAssistant) -> None:
CONF_AND: [
{CONF_WILDCARD: "switch.some?"},
{CONF_WILDCARD: "switch.other?"},
]
],
},
],
},
Expand Down
2 changes: 1 addition & 1 deletion tests/group_include/test_include.py
Original file line number Diff line number Diff line change
Expand Up @@ -728,7 +728,7 @@ async def test_include_by_wildcard(


async def test_include_complex_nested_filters(
hass: HomeAssistant, area_reg: AreaRegistry
hass: HomeAssistant, area_reg: AreaRegistry,
) -> None:
area = area_reg.async_get_or_create("Living room")
mock_registry(
Expand Down
47 changes: 47 additions & 0 deletions tests/sensors/test_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
ATTR_DEVICE_CLASS,
ATTR_ENTITY_ID,
ATTR_UNIT_OF_MEASUREMENT,
CONF_DEVICE,
CONF_ENTITIES,
CONF_ENTITY_ID,
CONF_NAME,
Expand All @@ -23,6 +24,7 @@
)
from homeassistant.core import HomeAssistant, State
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.device_registry import DeviceRegistry
from homeassistant.helpers.entity_registry import EntityRegistry, RegistryEntry
from homeassistant.util import dt
from pytest_homeassistant_custom_component.common import (
Expand Down Expand Up @@ -1261,6 +1263,51 @@ async def test_create_group_with_real_power_sensors(hass: HomeAssistant) -> None
assert group_state.attributes.get(ATTR_ENTITIES) == {"sensor.existing_power"}


async def test_bind_to_configured_device(
hass: HomeAssistant,
entity_reg: er.EntityRegistry,
device_reg: DeviceRegistry,
) -> None:
"""
Test that all powercalc created sensors are attached to same device as the source entity
"""

# Create a device
config_entry = MockConfigEntry(domain="test")
config_entry.add_to_hass(hass)
device_entry = device_reg.async_get_or_create(
config_entry_id=config_entry.entry_id,
connections={("dummy", "abcdef")},
manufacturer="Google Inc.",
model="Google Home Mini",
)

# Create powercalc sensors
member_entry = await setup_config_entry(
hass,
{
CONF_SENSOR_TYPE: SensorType.VIRTUAL_POWER,
CONF_ENTITY_ID: "light.test",
CONF_MODE: CalculationStrategy.FIXED,
CONF_FIXED: {CONF_POWER: 50},
},
)

await setup_config_entry(
hass,
{
CONF_SENSOR_TYPE: SensorType.GROUP,
CONF_NAME: "MyGroup",
CONF_DEVICE: device_entry.id,
CONF_GROUP_MEMBER_SENSORS: [member_entry.entry_id],
},
)

# Assert that all the entities are bound to correct device
group_entity = entity_reg.async_get("sensor.mygroup_power")
assert group_entity
assert group_entity.device_id == device_entry.id

async def _create_energy_group(
hass: HomeAssistant,
name: str,
Expand Down

0 comments on commit 3bde78e

Please sign in to comment.