async def test_unique_id_migration(mock_hc, opp, mock_write_config): """Test migration of switch unique ids to stable ones.""" entry = MockConfigEntry(domain=DOMAIN, data={ CONF_HOST: "192.0.2.0", CONF_NAME: HUB_NAME }) entry.add_to_opp(opp) mock_registry( opp, { # old format ENTITY_WATCH_TV: er.RegistryEntry( entity_id=ENTITY_WATCH_TV, unique_id="123443-Watch TV", platform="harmony", config_entry_id=entry.entry_id, ), # old format, activity name with - ENTITY_NILE_TV: er.RegistryEntry( entity_id=ENTITY_NILE_TV, unique_id="123443-Nile-TV", platform="harmony", config_entry_id=entry.entry_id, ), # new format ENTITY_PLAY_MUSIC: er.RegistryEntry( entity_id=ENTITY_PLAY_MUSIC, unique_id=f"activity_{PLAY_MUSIC_ACTIVITY_ID}", platform="harmony", config_entry_id=entry.entry_id, ), # old entity which no longer has a matching activity on the hub. skipped. "switch.some_other_activity": er.RegistryEntry( entity_id="switch.some_other_activity", unique_id="123443-Some Other Activity", platform="harmony", config_entry_id=entry.entry_id, ), }, ) assert await async_setup_component(opp, DOMAIN, {}) await opp.async_block_till_done() ent_reg = er.async_get(opp) switch_tv = ent_reg.async_get(ENTITY_WATCH_TV) assert switch_tv.unique_id == f"activity_{WATCH_TV_ACTIVITY_ID}" switch_nile = ent_reg.async_get(ENTITY_NILE_TV) assert switch_nile.unique_id == f"activity_{NILE_TV_ACTIVITY_ID}" switch_music = ent_reg.async_get(ENTITY_PLAY_MUSIC) assert switch_music.unique_id == f"activity_{PLAY_MUSIC_ACTIVITY_ID}"
async def test_config_entry_migration(opp): """Tests config entry without mode in unique_id can be migrated.""" ipma_entry = MockConfigEntry( domain=DOMAIN, title="Home", data={CONF_LATITUDE: 0, CONF_LONGITUDE: 0, CONF_MODE: "daily"}, ) ipma_entry.add_to_opp(opp) ipma_entry2 = MockConfigEntry( domain=DOMAIN, title="Home", data={CONF_LATITUDE: 0, CONF_LONGITUDE: 0, CONF_MODE: "hourly"}, ) ipma_entry2.add_to_opp(opp) mock_registry( opp, { "weather.hometown": er.RegistryEntry( entity_id="weather.hometown", unique_id="0, 0", platform="ipma", config_entry_id=ipma_entry.entry_id, ), "weather.hometown_2": er.RegistryEntry( entity_id="weather.hometown_2", unique_id="0, 0, hourly", platform="ipma", config_entry_id=ipma_entry.entry_id, ), }, ) with patch( "openpeerpower.components.ipma.weather.async_get_location", return_value=MockLocation(), ): assert await async_setup_component(opp, DOMAIN, {}) await opp.async_block_till_done() ent_reg = er.async_get(opp) weather_home = ent_reg.async_get("weather.hometown") assert weather_home.unique_id == "0, 0, daily" weather_home2 = ent_reg.async_get("weather.hometown_2") assert weather_home2.unique_id == "0, 0, hourly"
async def test_warn_disabled(opp, caplog): """Test we warn once if we write to a disabled entity.""" entry = entity_registry.RegistryEntry( entity_id="hello.world", unique_id="test-unique-id", platform="test-platform", disabled_by=entity_registry.DISABLED_USER, ) mock_registry(opp, {"hello.world": entry}) ent = entity.Entity() ent.opp = opp ent.entity_id = "hello.world" ent.registry_entry = entry ent.platform = MagicMock(platform_name="test-platform") caplog.clear() ent.async_write_op_state() assert opp.states.get("hello.world") is None assert "Entity hello.world is incorrectly being triggered" in caplog.text caplog.clear() ent.async_write_op_state() assert opp.states.get("hello.world") is None assert caplog.text == ""
async def test_disabled_in_entity_registry(opp): """Test entity is removed if we disable entity registry entry.""" entry = entity_registry.RegistryEntry( entity_id="hello.world", unique_id="test-unique-id", platform="test-platform", disabled_by=None, ) registry = mock_registry(opp, {"hello.world": entry}) ent = entity.Entity() ent.opp = opp ent.entity_id = "hello.world" ent.registry_entry = entry assert ent.enabled is True ent.add_to_platform_start(opp, MagicMock(platform_name="test-platform"), None) await ent.add_to_platform_finish() assert opp.states.get("hello.world") is not None entry2 = registry.async_update_entity( "hello.world", disabled_by=entity_registry.DISABLED_USER) await opp.async_block_till_done() assert entry2 != entry assert ent.registry_entry == entry2 assert ent.enabled is False assert opp.states.get("hello.world") is None entry3 = registry.async_update_entity("hello.world", disabled_by=None) await opp.async_block_till_done() assert entry3 != entry2 # Entry is no longer updated, entity is no longer tracking changes assert ent.registry_entry == entry2
async def test_entity_registry_updates_entity_id(opp): """Test that updates on the entity registry update platform entities.""" registry = mock_registry( opp, { "test_domain.world": er.RegistryEntry( entity_id="test_domain.world", unique_id="1234", # Using component.async_add_entities is equal to platform "domain" platform="test_platform", name="Some name", ) }, ) platform = MockEntityPlatform(opp) entity = MockEntity(unique_id="1234") await platform.async_add_entities([entity]) state = opp.states.get("test_domain.world") assert state is not None assert state.name == "Some name" registry.async_update_entity("test_domain.world", new_entity_id="test_domain.planet") await opp.async_block_till_done() await opp.async_block_till_done() assert opp.states.get("test_domain.world") is None assert opp.states.get("test_domain.planet") is not None
async def test_entity_registry_updates_invalid_entity_id(opp): """Test that we can't update to an invalid entity id.""" registry = mock_registry( opp, { "test_domain.world": er.RegistryEntry( entity_id="test_domain.world", unique_id="1234", # Using component.async_add_entities is equal to platform "domain" platform="test_platform", name="Some name", ), "test_domain.existing": er.RegistryEntry( entity_id="test_domain.existing", unique_id="5678", platform="test_platform", ), }, ) platform = MockEntityPlatform(opp) entity = MockEntity(unique_id="1234") await platform.async_add_entities([entity]) state = opp.states.get("test_domain.world") assert state is not None assert state.name == "Some name" with pytest.raises(ValueError): registry.async_update_entity("test_domain.world", new_entity_id="test_domain.existing") with pytest.raises(ValueError): registry.async_update_entity("test_domain.world", new_entity_id="invalid_entity_id") with pytest.raises(ValueError): registry.async_update_entity("test_domain.world", new_entity_id="diff_domain.world") await opp.async_block_till_done() await opp.async_block_till_done() assert opp.states.get("test_domain.world") is not None assert opp.states.get("invalid_entity_id") is None assert opp.states.get("diff_domain.world") is None
async def test_migration(opp: OpenPeerPower) -> None: """Test that we can migrate coronavirus to stable unique ID.""" nl_entry = MockConfigEntry(domain=DOMAIN, title="Netherlands", data={"country": 34}) nl_entry.add_to_opp(opp) worldwide_entry = MockConfigEntry(domain=DOMAIN, title="Worldwide", data={"country": OPTION_WORLDWIDE}) worldwide_entry.add_to_opp(opp) mock_registry( opp, { "sensor.netherlands_confirmed": er.RegistryEntry( entity_id="sensor.netherlands_confirmed", unique_id="34-confirmed", platform="coronavirus", config_entry_id=nl_entry.entry_id, ), "sensor.worldwide_confirmed": er.RegistryEntry( entity_id="sensor.worldwide_confirmed", unique_id="__worldwide-confirmed", platform="coronavirus", config_entry_id=worldwide_entry.entry_id, ), }, ) assert await async_setup_component(opp, DOMAIN, {}) await opp.async_block_till_done() ent_reg = er.async_get(opp) sensor_nl = ent_reg.async_get("sensor.netherlands_confirmed") assert sensor_nl.unique_id == "Netherlands-confirmed" sensor_worldwide = ent_reg.async_get("sensor.worldwide_confirmed") assert sensor_worldwide.unique_id == "__worldwide-confirmed" assert opp.states.get("sensor.netherlands_confirmed").state == "10" assert opp.states.get("sensor.worldwide_confirmed").state == "11" assert nl_entry.unique_id == "Netherlands" assert worldwide_entry.unique_id == OPTION_WORLDWIDE
async def test_registry_respect_entity_disabled(opp): """Test that the registry respects entity disabled.""" mock_registry( opp, { "test_domain.world": er.RegistryEntry( entity_id="test_domain.world", unique_id="1234", # Using component.async_add_entities is equal to platform "domain" platform="test_platform", disabled_by=er.DISABLED_USER, ) }, ) platform = MockEntityPlatform(opp) entity = MockEntity(unique_id="1234") await platform.async_add_entities([entity]) assert entity.entity_id == "test_domain.world" assert opp.states.async_entity_ids() == []
async def test_overriding_name_from_registry(opp): """Test that we can override a name via the Entity Registry.""" component = EntityComponent(_LOGGER, DOMAIN, opp) mock_registry( opp, { "test_domain.world": er.RegistryEntry( entity_id="test_domain.world", unique_id="1234", # Using component.async_add_entities is equal to platform "domain" platform="test_domain", name="Overridden", ) }, ) await component.async_add_entities( [MockEntity(unique_id="1234", name="Device Name")]) state = opp.states.get("test_domain.world") assert state is not None assert state.name == "Overridden"
async def test_domain_control_unauthorized(opp, opp_read_only_user): """Test domain verification in a service call with an unauthorized user.""" mock_registry( opp, { "light.kitchen": ent_reg.RegistryEntry( entity_id="light.kitchen", unique_id="kitchen", platform="test_domain", ) }, ) calls = [] async def mock_service_log(call): """Define a protected service.""" calls.append(call) protected_mock_service = opp.helpers.service.verify_domain_control( "test_domain")(mock_service_log) opp.services.async_register("test_domain", "test_service", protected_mock_service, schema=None) with pytest.raises(exceptions.Unauthorized): await opp.services.async_call( "test_domain", "test_service", {}, blocking=True, context=ha.Context(user_id=opp_read_only_user.id), ) assert len(calls) == 0
async def test_domain_control_no_user(opp): """Test domain verification in a service call with no user.""" mock_registry( opp, { "light.kitchen": ent_reg.RegistryEntry( entity_id="light.kitchen", unique_id="kitchen", platform="test_domain", ) }, ) calls = [] async def mock_service_log(call): """Define a protected service.""" calls.append(call) protected_mock_service = opp.helpers.service.verify_domain_control( "test_domain")(mock_service_log) opp.services.async_register("test_domain", "test_service", protected_mock_service, schema=None) await opp.services.async_call( "test_domain", "test_service", {}, blocking=True, context=ha.Context(user_id=None), ) assert len(calls) == 1
async def test_removing_entity_unavailable(opp): """Test removing an entity that is still registered creates an unavailable state.""" entry = entity_registry.RegistryEntry( entity_id="hello.world", unique_id="test-unique-id", platform="test-platform", disabled_by=None, ) ent = entity.Entity() ent.opp = opp ent.entity_id = "hello.world" ent.registry_entry = entry ent.async_write_op_state() state = opp.states.get("hello.world") assert state is not None assert state.state == STATE_UNKNOWN await ent.async_remove() state = opp.states.get("hello.world") assert state is not None assert state.state == STATE_UNAVAILABLE
def area_mock(opp): """Mock including area info.""" opp.states.async_set("light.Bowl", STATE_ON) opp.states.async_set("light.Ceiling", STATE_OFF) opp.states.async_set("light.Kitchen", STATE_OFF) device_in_area = dev_reg.DeviceEntry(area_id="test-area") device_no_area = dev_reg.DeviceEntry(id="device-no-area-id") device_diff_area = dev_reg.DeviceEntry(area_id="diff-area") device_area_a = dev_reg.DeviceEntry(id="device-area-a-id", area_id="area-a") mock_device_registry( opp, { device_in_area.id: device_in_area, device_no_area.id: device_no_area, device_diff_area.id: device_diff_area, device_area_a.id: device_area_a, }, ) entity_in_own_area = ent_reg.RegistryEntry( entity_id="light.in_own_area", unique_id="in-own-area-id", platform="test", area_id="own-area", ) entity_in_area = ent_reg.RegistryEntry( entity_id="light.in_area", unique_id="in-area-id", platform="test", device_id=device_in_area.id, ) entity_in_other_area = ent_reg.RegistryEntry( entity_id="light.in_other_area", unique_id="in-area-a-id", platform="test", device_id=device_in_area.id, area_id="other-area", ) entity_assigned_to_area = ent_reg.RegistryEntry( entity_id="light.assigned_to_area", unique_id="assigned-area-id", platform="test", device_id=device_in_area.id, area_id="test-area", ) entity_no_area = ent_reg.RegistryEntry( entity_id="light.no_area", unique_id="no-area-id", platform="test", device_id=device_no_area.id, ) entity_diff_area = ent_reg.RegistryEntry( entity_id="light.diff_area", unique_id="diff-area-id", platform="test", device_id=device_diff_area.id, ) entity_in_area_a = ent_reg.RegistryEntry( entity_id="light.in_area_a", unique_id="in-area-a-id", platform="test", device_id=device_area_a.id, area_id="area-a", ) entity_in_area_b = ent_reg.RegistryEntry( entity_id="light.in_area_b", unique_id="in-area-b-id", platform="test", device_id=device_area_a.id, area_id="area-b", ) mock_registry( opp, { entity_in_own_area.entity_id: entity_in_own_area, entity_in_area.entity_id: entity_in_area, entity_in_other_area.entity_id: entity_in_other_area, entity_assigned_to_area.entity_id: entity_assigned_to_area, entity_no_area.entity_id: entity_no_area, entity_diff_area.entity_id: entity_diff_area, entity_in_area_a.entity_id: entity_in_area_a, entity_in_area_b.entity_id: entity_in_area_b, }, )
def zwave_migration_data_fixture(opp): """Return mock zwave migration data.""" zwave_source_node_device = dr.DeviceEntry( id=ZWAVE_SOURCE_NODE_DEVICE_ID, name_by_user=ZWAVE_SOURCE_NODE_DEVICE_NAME, area_id=ZWAVE_SOURCE_NODE_DEVICE_AREA, ) zwave_source_node_entry = er.RegistryEntry( entity_id=ZWAVE_SOURCE_ENTITY, unique_id=ZWAVE_SOURCE_NODE_UNIQUE_ID, platform="zwave", name="Z-Wave Source Node", ) zwave_battery_device = dr.DeviceEntry( id=ZWAVE_BATTERY_DEVICE_ID, name_by_user=ZWAVE_BATTERY_DEVICE_NAME, area_id=ZWAVE_BATTERY_DEVICE_AREA, ) zwave_battery_entry = er.RegistryEntry( entity_id=ZWAVE_BATTERY_ENTITY, unique_id=ZWAVE_BATTERY_UNIQUE_ID, platform="zwave", name=ZWAVE_BATTERY_NAME, icon=ZWAVE_BATTERY_ICON, ) zwave_power_device = dr.DeviceEntry( id=ZWAVE_POWER_DEVICE_ID, name_by_user=ZWAVE_POWER_DEVICE_NAME, area_id=ZWAVE_POWER_DEVICE_AREA, ) zwave_power_entry = er.RegistryEntry( entity_id=ZWAVE_POWER_ENTITY, unique_id=ZWAVE_POWER_UNIQUE_ID, platform="zwave", name=ZWAVE_POWER_NAME, icon=ZWAVE_POWER_ICON, ) zwave_migration_data = { ZWAVE_SOURCE_NODE_UNIQUE_ID: { "node_id": 10, "node_instance": 1, "device_id": zwave_source_node_device.id, "command_class": 113, "command_class_label": "SourceNodeId", "value_index": 2, "unique_id": ZWAVE_SOURCE_NODE_UNIQUE_ID, "entity_entry": zwave_source_node_entry, }, ZWAVE_BATTERY_UNIQUE_ID: { "node_id": 36, "node_instance": 1, "device_id": zwave_battery_device.id, "command_class": 128, "command_class_label": "Battery Level", "value_index": 0, "unique_id": ZWAVE_BATTERY_UNIQUE_ID, "entity_entry": zwave_battery_entry, }, ZWAVE_POWER_UNIQUE_ID: { "node_id": 32, "node_instance": 1, "device_id": zwave_power_device.id, "command_class": 50, "command_class_label": "Power", "value_index": 8, "unique_id": ZWAVE_POWER_UNIQUE_ID, "entity_entry": zwave_power_entry, }, } mock_device_registry( opp, { zwave_source_node_device.id: zwave_source_node_device, zwave_battery_device.id: zwave_battery_device, zwave_power_device.id: zwave_power_device, }, ) mock_registry( opp, { ZWAVE_SOURCE_ENTITY: zwave_source_node_entry, ZWAVE_BATTERY_ENTITY: zwave_battery_entry, ZWAVE_POWER_ENTITY: zwave_power_entry, }, ) return zwave_migration_data