async def test_get_actions( hass: HomeAssistant, device_reg: device_registry.DeviceRegistry, entity_reg: entity_registry.EntityRegistry, ) -> None: """Test we get the expected actions from a button.""" config_entry = MockConfigEntry(domain="test", data={}) config_entry.add_to_hass(hass) device_entry = device_reg.async_get_or_create( config_entry_id=config_entry.entry_id, connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) entity_reg.async_get_or_create(DOMAIN, "test", "5678", device_id=device_entry.id) expected_actions = [{ "domain": DOMAIN, "type": "press", "device_id": device_entry.id, "entity_id": "button.test_5678", }] actions = await async_get_device_automations(hass, DeviceAutomationType.ACTION, device_entry.id) assert_lists_same(actions, expected_actions)
async def test_dimmer_switch_unique_id_fix_original_entity_was_deleted( hass: HomeAssistant, entity_reg: EntityRegistry): """Test that roll out unique id entity id changed to the original unique id.""" config_entry = MockConfigEntry(domain=DOMAIN, data={}, unique_id=MAC_ADDRESS) config_entry.add_to_hass(hass) dimmer = _mocked_dimmer() rollout_unique_id = MAC_ADDRESS.replace(":", "").upper() original_unique_id = tplink.legacy_device_id(dimmer) rollout_dimmer_entity_reg = entity_reg.async_get_or_create( config_entry=config_entry, platform=DOMAIN, domain="light", unique_id=rollout_unique_id, original_name="Rollout dimmer", ) with _patch_discovery(device=dimmer), _patch_single_discovery( device=dimmer): await setup.async_setup_component(hass, DOMAIN, {}) await hass.async_block_till_done() migrated_dimmer_entity_reg = entity_reg.async_get_or_create( config_entry=config_entry, platform=DOMAIN, domain="light", unique_id=original_unique_id, original_name="Migrated dimmer", ) assert migrated_dimmer_entity_reg.entity_id == rollout_dimmer_entity_reg.entity_id
async def test_get_conditions( hass: HomeAssistant, device_reg: device_registry.DeviceRegistry, entity_reg: entity_registry.EntityRegistry, ) -> None: """Test we get the expected conditions from a NEW_DOMAIN.""" config_entry = MockConfigEntry(domain="test", data={}) config_entry.add_to_hass(hass) device_entry = device_reg.async_get_or_create( config_entry_id=config_entry.entry_id, connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) entity_reg.async_get_or_create(DOMAIN, "test", "5678", device_id=device_entry.id) expected_conditions = [ { "condition": "device", "domain": DOMAIN, "type": "is_off", "device_id": device_entry.id, "entity_id": f"{DOMAIN}.test_5678", }, { "condition": "device", "domain": DOMAIN, "type": "is_on", "device_id": device_entry.id, "entity_id": f"{DOMAIN}.test_5678", }, ] conditions = await async_get_device_automations(hass, "condition", device_entry.id) assert_lists_same(conditions, expected_conditions)
async def test_get_triggers( hass: HomeAssistant, device_reg: device_registry.DeviceRegistry, entity_reg: EntityRegistry, ) -> None: """Test we get the expected triggers from a button.""" config_entry = MockConfigEntry(domain="test", data={}) config_entry.add_to_hass(hass) device_entry = device_reg.async_get_or_create( config_entry_id=config_entry.entry_id, connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) entity_reg.async_get_or_create(DOMAIN, "test", "5678", device_id=device_entry.id) expected_triggers = [{ "platform": "device", "domain": DOMAIN, "type": "pressed", "device_id": device_entry.id, "entity_id": f"{DOMAIN}.test_5678", "metadata": { "secondary": False }, }] triggers = await async_get_device_automations(hass, DeviceAutomationType.TRIGGER, device_entry.id) assert_lists_same(triggers, expected_triggers)
async def test_get_trigger_capabilities(hass: HomeAssistant, device_reg: DeviceRegistry, entity_reg: EntityRegistry) -> None: """Test we get the expected capabilities from a update trigger.""" config_entry = MockConfigEntry(domain="test", data={}) config_entry.add_to_hass(hass) device_entry = device_reg.async_get_or_create( config_entry_id=config_entry.entry_id, connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) entity_reg.async_get_or_create(DOMAIN, "test", "5678", device_id=device_entry.id) expected_capabilities = { "extra_fields": [{ "name": "for", "optional": True, "type": "positive_time_period_dict" }] } triggers = await async_get_device_automations(hass, DeviceAutomationType.TRIGGER, device_entry.id) for trigger in triggers: capabilities = await async_get_device_automation_capabilities( hass, DeviceAutomationType.TRIGGER, trigger) assert capabilities == expected_capabilities
async def test_migration_device_online_end_to_end_after_downgrade( hass: HomeAssistant, device_reg: DeviceRegistry, entity_reg: EntityRegistry): """Test migration from single config entry can happen again after a downgrade.""" config_entry = MockConfigEntry(domain=DOMAIN, data={}, unique_id=DOMAIN) config_entry.add_to_hass(hass) already_migrated_config_entry = MockConfigEntry( domain=DOMAIN, data={CONF_HOST: IP_ADDRESS}, unique_id=MAC_ADDRESS) already_migrated_config_entry.add_to_hass(hass) device = device_reg.async_get_or_create( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, MAC_ADDRESS)}, name=ALIAS, ) light_entity_reg = entity_reg.async_get_or_create( config_entry=config_entry, platform=DOMAIN, domain="light", unique_id=MAC_ADDRESS, original_name=ALIAS, device_id=device.id, ) power_sensor_entity_reg = entity_reg.async_get_or_create( config_entry=config_entry, platform=DOMAIN, domain="sensor", unique_id=f"{MAC_ADDRESS}_sensor", original_name=ALIAS, device_id=device.id, ) with _patch_discovery(), _patch_single_discovery(): await setup.async_setup_component(hass, DOMAIN, {}) await hass.async_block_till_done() assert device.config_entries == {config_entry.entry_id} assert light_entity_reg.config_entry_id == config_entry.entry_id assert power_sensor_entity_reg.config_entry_id == config_entry.entry_id assert er.async_entries_for_config_entry(entity_reg, config_entry) == [] hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) await hass.async_block_till_done() legacy_entry = None for entry in hass.config_entries.async_entries(DOMAIN): if entry.unique_id == DOMAIN: legacy_entry = entry break assert legacy_entry is None
async def test_get_triggers(hass: HomeAssistant, device_reg: DeviceRegistry, entity_reg: EntityRegistry) -> None: """Test we get the expected triggers from a update entity.""" config_entry = MockConfigEntry(domain="test", data={}) config_entry.add_to_hass(hass) device_entry = device_reg.async_get_or_create( config_entry_id=config_entry.entry_id, connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) entity_reg.async_get_or_create(DOMAIN, "test", "5678", device_id=device_entry.id) expected_triggers = [ { "platform": "device", "domain": DOMAIN, "type": "changed_states", "device_id": device_entry.id, "entity_id": f"{DOMAIN}.test_5678", }, { "platform": "device", "domain": DOMAIN, "type": "turned_off", "device_id": device_entry.id, "entity_id": f"{DOMAIN}.test_5678", }, { "platform": "device", "domain": DOMAIN, "type": "turned_on", "device_id": device_entry.id, "entity_id": f"{DOMAIN}.test_5678", }, ] triggers = await async_get_device_automations(hass, DeviceAutomationType.TRIGGER, device_entry.id) assert triggers == expected_triggers
async def test_migration_device_online_end_to_end(hass: HomeAssistant, device_reg: DeviceRegistry, entity_reg: EntityRegistry): """Test migration from single config entry.""" config_entry = MockConfigEntry(domain=DOMAIN, title="LEGACY", data={}, unique_id=DOMAIN) config_entry.add_to_hass(hass) device = device_reg.async_get_or_create( config_entry_id=config_entry.entry_id, identifiers={(DOMAIN, SERIAL)}, connections={(dr.CONNECTION_NETWORK_MAC, MAC_ADDRESS)}, name=LABEL, ) light_entity_reg = entity_reg.async_get_or_create( config_entry=config_entry, platform=DOMAIN, domain="light", unique_id=dr.format_mac(SERIAL), original_name=LABEL, device_id=device.id, ) with _patch_discovery(), _patch_config_flow_try_connect(), _patch_device(): await setup.async_setup_component(hass, DOMAIN, {}) await hass.async_block_till_done() migrated_entry = None for entry in hass.config_entries.async_entries(DOMAIN): if entry.unique_id == DOMAIN: migrated_entry = entry break assert migrated_entry is not None assert device.config_entries == {migrated_entry.entry_id} assert light_entity_reg.config_entry_id == migrated_entry.entry_id assert er.async_entries_for_config_entry(entity_reg, config_entry) == [] hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) await hass.async_block_till_done() async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=20)) await hass.async_block_till_done() legacy_entry = None for entry in hass.config_entries.async_entries(DOMAIN): if entry.unique_id == DOMAIN: legacy_entry = entry break assert legacy_entry is None
async def test_migration_device_online_end_to_end_ignores_other_devices( hass: HomeAssistant, device_reg: DeviceRegistry, entity_reg: EntityRegistry): """Test migration from single config entry.""" config_entry = MockConfigEntry(domain=DOMAIN, data={}, unique_id=DOMAIN) config_entry.add_to_hass(hass) other_domain_config_entry = MockConfigEntry(domain="other_domain", data={}, unique_id="other_domain") other_domain_config_entry.add_to_hass(hass) device = device_reg.async_get_or_create( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, MAC_ADDRESS)}, name=ALIAS, ) other_device = device_reg.async_get_or_create( config_entry_id=other_domain_config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "556655665566")}, name=ALIAS, ) light_entity_reg = entity_reg.async_get_or_create( config_entry=config_entry, platform=DOMAIN, domain="light", unique_id=MAC_ADDRESS, original_name=ALIAS, device_id=device.id, ) power_sensor_entity_reg = entity_reg.async_get_or_create( config_entry=config_entry, platform=DOMAIN, domain="sensor", unique_id=f"{MAC_ADDRESS}_sensor", original_name=ALIAS, device_id=device.id, ) ignored_entity_reg = entity_reg.async_get_or_create( config_entry=other_domain_config_entry, platform=DOMAIN, domain="sensor", unique_id="00:00:00:00:00:00_sensor", original_name=ALIAS, device_id=device.id, ) garbage_entity_reg = entity_reg.async_get_or_create( config_entry=config_entry, platform=DOMAIN, domain="sensor", unique_id="garbage", original_name=ALIAS, device_id=other_device.id, ) with _patch_discovery(), _patch_single_discovery(): await setup.async_setup_component(hass, DOMAIN, {}) await hass.async_block_till_done() migrated_entry = None for entry in hass.config_entries.async_entries(DOMAIN): if entry.unique_id == DOMAIN: migrated_entry = entry break assert migrated_entry is not None assert device.config_entries == {migrated_entry.entry_id} assert light_entity_reg.config_entry_id == migrated_entry.entry_id assert power_sensor_entity_reg.config_entry_id == migrated_entry.entry_id assert ignored_entity_reg.config_entry_id == other_domain_config_entry.entry_id assert garbage_entity_reg.config_entry_id == config_entry.entry_id assert er.async_entries_for_config_entry(entity_reg, config_entry) == [] hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) await hass.async_block_till_done() legacy_entry = None for entry in hass.config_entries.async_entries(DOMAIN): if entry.unique_id == DOMAIN: legacy_entry = entry break assert legacy_entry is not None
async def test_discovery_is_more_frequent_during_migration( hass: HomeAssistant, device_reg: DeviceRegistry, entity_reg: EntityRegistry): """Test that discovery is more frequent during migration.""" config_entry = MockConfigEntry(domain=DOMAIN, title="LEGACY", data={}, unique_id=DOMAIN) config_entry.add_to_hass(hass) device = device_reg.async_get_or_create( config_entry_id=config_entry.entry_id, identifiers={(DOMAIN, SERIAL)}, connections={(dr.CONNECTION_NETWORK_MAC, MAC_ADDRESS)}, name=LABEL, ) entity_reg.async_get_or_create( config_entry=config_entry, platform=DOMAIN, domain="light", unique_id=dr.format_mac(SERIAL), original_name=LABEL, device_id=device.id, ) bulb = _mocked_bulb() start_calls = 0 class MockLifxDiscovery: """Mock lifx discovery.""" def __init__(self, *args, **kwargs): """Init discovery.""" self.bulb = bulb self.lights = {} def start(self): """Mock start.""" nonlocal start_calls start_calls += 1 # Discover the bulb so we can complete migration # and verify we switch back to normal discovery # interval if start_calls == 4: self.lights = {self.bulb.mac_addr: self.bulb} def cleanup(self): """Mock cleanup.""" with _patch_device(device=bulb), _patch_config_flow_try_connect( device=bulb), patch.object(discovery, "DEFAULT_TIMEOUT", 0), patch( "homeassistant.components.lifx.discovery.LifxDiscovery", MockLifxDiscovery): await async_setup_component(hass, lifx.DOMAIN, {lifx.DOMAIN: {}}) await hass.async_block_till_done() assert start_calls == 0 hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) await hass.async_block_till_done() assert start_calls == 1 async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=5)) await hass.async_block_till_done() assert start_calls == 3 async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=10)) await hass.async_block_till_done() assert start_calls == 4 async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=15)) await hass.async_block_till_done() assert start_calls == 5
async def test_migration_device_online_end_to_end_ignores_other_devices( hass: HomeAssistant, device_reg: DeviceRegistry, entity_reg: EntityRegistry): """Test migration from single config entry.""" legacy_config_entry = MockConfigEntry(domain=DOMAIN, title="LEGACY", data={}, unique_id=DOMAIN) legacy_config_entry.add_to_hass(hass) other_domain_config_entry = MockConfigEntry(domain="other_domain", data={}, unique_id="other_domain") other_domain_config_entry.add_to_hass(hass) device = device_reg.async_get_or_create( config_entry_id=legacy_config_entry.entry_id, identifiers={(DOMAIN, SERIAL)}, connections={(dr.CONNECTION_NETWORK_MAC, MAC_ADDRESS)}, name=LABEL, ) other_device = device_reg.async_get_or_create( config_entry_id=other_domain_config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "556655665566")}, name=LABEL, ) light_entity_reg = entity_reg.async_get_or_create( config_entry=legacy_config_entry, platform=DOMAIN, domain="light", unique_id=SERIAL, original_name=LABEL, device_id=device.id, ) ignored_entity_reg = entity_reg.async_get_or_create( config_entry=other_domain_config_entry, platform=DOMAIN, domain="sensor", unique_id="00:00:00:00:00:00_sensor", original_name=LABEL, device_id=device.id, ) garbage_entity_reg = entity_reg.async_get_or_create( config_entry=legacy_config_entry, platform=DOMAIN, domain="sensor", unique_id="garbage", original_name=LABEL, device_id=other_device.id, ) with _patch_discovery(), _patch_config_flow_try_connect(), _patch_device(): await setup.async_setup_component(hass, DOMAIN, {}) await hass.async_block_till_done() hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) await hass.async_block_till_done() async_fire_time_changed(hass, dt_util.utcnow() + timedelta(minutes=20)) await hass.async_block_till_done() new_entry = None legacy_entry = None for entry in hass.config_entries.async_entries(DOMAIN): if entry.unique_id == DOMAIN: legacy_entry = entry else: new_entry = entry assert new_entry is not None assert legacy_entry is None assert device.config_entries == {legacy_config_entry.entry_id} assert light_entity_reg.config_entry_id == legacy_config_entry.entry_id assert ignored_entity_reg.config_entry_id == other_domain_config_entry.entry_id assert garbage_entity_reg.config_entry_id == legacy_config_entry.entry_id assert er.async_entries_for_config_entry(entity_reg, legacy_config_entry) == [] assert dr.async_entries_for_config_entry(device_reg, legacy_config_entry) == []