diff --git a/custom_components/powercalc/config_flow.py b/custom_components/powercalc/config_flow.py index b3c12d491..2368b7647 100644 --- a/custom_components/powercalc/config_flow.py +++ b/custom_components/powercalc/config_flow.py @@ -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, @@ -262,6 +263,7 @@ { vol.Required(CONF_NAME): str, vol.Optional(CONF_UNIQUE_ID): selector.TextSelector(), + vol.Optional(CONF_DEVICE): selector.DeviceSelector(), }, ) diff --git a/custom_components/powercalc/group_include/filter.py b/custom_components/powercalc/group_include/filter.py index 517821cc3..84f7aecfe 100644 --- a/custom_components/powercalc/group_include/filter.py +++ b/custom_components/powercalc/group_include/filter.py @@ -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 @@ -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, ) @@ -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)) @@ -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) diff --git a/custom_components/powercalc/sensor.py b/custom_components/powercalc/sensor.py index 2bf3d6bdb..9cd996732 100644 --- a/custom_components/powercalc/sensor.py +++ b/custom_components/powercalc/sensor.py @@ -159,7 +159,7 @@ vol.Optional(CONF_TEMPLATE): cv.template, vol.Optional(CONF_DOMAIN): cv.string, vol.Optional(CONF_WILDCARD): cv.string, - } + }, ) SENSOR_CONFIG = { diff --git a/custom_components/powercalc/sensors/group.py b/custom_components/powercalc/sensors/group.py index efee531c5..6e9fa8fa9 100644 --- a/custom_components/powercalc/sensors/group.py +++ b/custom_components/powercalc/sensors/group.py @@ -18,6 +18,7 @@ from homeassistant.const import ( ATTR_ENTITY_ID, ATTR_UNIT_OF_MEASUREMENT, + CONF_DEVICE, CONF_DOMAIN, CONF_ENTITIES, CONF_NAME, @@ -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), ) @@ -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), ) @@ -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 @@ -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: @@ -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, @@ -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: diff --git a/tests/group_include/test_filter.py b/tests/group_include/test_filter.py index 9333fdcf0..c44ebdec6 100644 --- a/tests/group_include/test_filter.py +++ b/tests/group_include/test_filter.py @@ -84,7 +84,7 @@ async def test_complex_nested_filters(hass: HomeAssistant) -> None: CONF_AND: [ {CONF_WILDCARD: "switch.some?"}, {CONF_WILDCARD: "switch.other?"}, - ] + ], }, ], }, diff --git a/tests/group_include/test_include.py b/tests/group_include/test_include.py index 6178fd7db..13debf543 100644 --- a/tests/group_include/test_include.py +++ b/tests/group_include/test_include.py @@ -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( diff --git a/tests/sensors/test_group.py b/tests/sensors/test_group.py index b2194e388..c3fc78911 100644 --- a/tests/sensors/test_group.py +++ b/tests/sensors/test_group.py @@ -12,6 +12,7 @@ ATTR_DEVICE_CLASS, ATTR_ENTITY_ID, ATTR_UNIT_OF_MEASUREMENT, + CONF_DEVICE, CONF_ENTITIES, CONF_ENTITY_ID, CONF_NAME, @@ -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 ( @@ -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,