Exemplo n.º 1
0
async def test_registry_cleanup(hass: HomeAssistant, config_entry: ConfigEntry,
                                owproxy: MagicMock):
    """Test for 1-Wire device.

    As they would be on a clean setup: all binary-sensors and switches disabled.
    """
    entity_registry = mock_registry(hass)
    device_registry = mock_device_registry(hass)

    # Initialise with two components
    setup_owproxy_mock_devices(owproxy, SENSOR_DOMAIN,
                               ["10.111111111111", "28.111111111111"])
    await hass.config_entries.async_setup(config_entry.entry_id)
    await hass.async_block_till_done()

    assert len(dr.async_entries_for_config_entry(device_registry, "2")) == 2
    assert len(er.async_entries_for_config_entry(entity_registry, "2")) == 2

    # Second item has disappeared from bus, and was removed manually from the front-end
    setup_owproxy_mock_devices(owproxy, SENSOR_DOMAIN, ["10.111111111111"])
    entity_registry.async_remove("sensor.28_111111111111_temperature")
    await hass.async_block_till_done()

    assert len(er.async_entries_for_config_entry(entity_registry, "2")) == 1
    assert len(dr.async_entries_for_config_entry(device_registry, "2")) == 2

    # Second item has disappeared from bus, and was removed manually from the front-end
    await hass.config_entries.async_reload("2")
    await hass.async_block_till_done()

    assert len(er.async_entries_for_config_entry(entity_registry, "2")) == 1
    assert len(dr.async_entries_for_config_entry(device_registry, "2")) == 1
Exemplo n.º 2
0
async def test_registry_cleanup(owproxy, hass):
    """Test for 1-Wire device.

    As they would be on a clean setup: all binary-sensors and switches disabled.
    """
    await async_setup_component(hass, "persistent_notification", {})
    entity_registry = mock_registry(hass)
    device_registry = mock_device_registry(hass)

    # Initialise with two components
    setup_owproxy_mock_devices(owproxy, SENSOR_DOMAIN,
                               ["10.111111111111", "28.111111111111"])
    with patch("homeassistant.components.onewire.PLATFORMS", [SENSOR_DOMAIN]):
        await setup_onewire_patched_owserver_integration(hass)
        await hass.async_block_till_done()

    assert len(dr.async_entries_for_config_entry(device_registry, "2")) == 2
    assert len(er.async_entries_for_config_entry(entity_registry, "2")) == 2

    # Second item has disappeared from bus, and was removed manually from the front-end
    setup_owproxy_mock_devices(owproxy, SENSOR_DOMAIN, ["10.111111111111"])
    entity_registry.async_remove("sensor.28_111111111111_temperature")
    await hass.async_block_till_done()

    assert len(er.async_entries_for_config_entry(entity_registry, "2")) == 1
    assert len(dr.async_entries_for_config_entry(device_registry, "2")) == 2

    # Second item has disappeared from bus, and was removed manually from the front-end
    with patch("homeassistant.components.onewire.PLATFORMS", [SENSOR_DOMAIN]):
        await hass.config_entries.async_reload("2")
        await hass.async_block_till_done()

    assert len(er.async_entries_for_config_entry(entity_registry, "2")) == 1
    assert len(dr.async_entries_for_config_entry(device_registry, "2")) == 1
Exemplo n.º 3
0
async def test_device_registry_cleanup(
    hass: HomeAssistant,
    mock_config_entry: MockConfigEntry,
    aioclient_mock: AiohttpClientMocker,
    caplog: LogCaptureFixture,
) -> None:
    """Test that we remove untracked repositories from the decvice registry."""
    mock_config_entry.options = {CONF_REPOSITORIES: ["home-assistant/core"]}
    await setup_github_integration(hass, mock_config_entry, aioclient_mock)

    device_registry = dr.async_get(hass)
    devices = dr.async_entries_for_config_entry(
        registry=device_registry,
        config_entry_id=mock_config_entry.entry_id,
    )

    assert len(devices) == 1

    mock_config_entry.options = {CONF_REPOSITORIES: []}
    assert await hass.config_entries.async_reload(mock_config_entry.entry_id)
    await hass.async_block_till_done()

    assert (
        f"Unlinking device {devices[0].id} for untracked repository home-assistant/core from config entry {mock_config_entry.entry_id}"
        in caplog.text)

    devices = dr.async_entries_for_config_entry(
        registry=device_registry,
        config_entry_id=mock_config_entry.entry_id,
    )

    assert len(devices) == 0
Exemplo n.º 4
0
async def test_removed_device(hass, client,
                              climate_radio_thermostat_ct100_plus,
                              lock_schlage_be469, integration):
    """Test that the device registry gets updated when a device gets removed."""
    driver = client.driver
    assert driver
    # Verify how many nodes are available
    assert len(driver.controller.nodes) == 2

    # Make sure there are the same number of devices
    dev_reg = dr.async_get(hass)
    device_entries = dr.async_entries_for_config_entry(dev_reg,
                                                       integration.entry_id)
    assert len(device_entries) == 2

    # Check how many entities there are
    ent_reg = er.async_get(hass)
    entity_entries = er.async_entries_for_config_entry(ent_reg,
                                                       integration.entry_id)
    assert len(entity_entries) == 29

    # Remove a node and reload the entry
    old_node = driver.controller.nodes.pop(13)
    await hass.config_entries.async_reload(integration.entry_id)
    await hass.async_block_till_done()

    # Assert that the node and all of it's entities were removed from the device and
    # entity registry
    device_entries = dr.async_entries_for_config_entry(dev_reg,
                                                       integration.entry_id)
    assert len(device_entries) == 1
    entity_entries = er.async_entries_for_config_entry(ent_reg,
                                                       integration.entry_id)
    assert len(entity_entries) == 17
    assert dev_reg.async_get_device({get_device_id(driver, old_node)}) is None
Exemplo n.º 5
0
async def test_removed_device(hass, client, multiple_devices, integration):
    """Test that the device registry gets updated when a device gets removed."""
    nodes = multiple_devices

    # Verify how many nodes are available
    assert len(client.driver.controller.nodes) == 2

    # Make sure there are the same number of devices
    dev_reg = dr.async_get(hass)
    device_entries = dr.async_entries_for_config_entry(dev_reg, integration.entry_id)
    assert len(device_entries) == 2

    # Check how many entities there are
    ent_reg = er.async_get(hass)
    entity_entries = er.async_entries_for_config_entry(ent_reg, integration.entry_id)
    assert len(entity_entries) == 24

    # Remove a node and reload the entry
    old_node = nodes.pop(13)
    await hass.config_entries.async_reload(integration.entry_id)
    await hass.async_block_till_done()

    # Assert that the node and all of it's entities were removed from the device and
    # entity registry
    device_entries = dr.async_entries_for_config_entry(dev_reg, integration.entry_id)
    assert len(device_entries) == 1
    entity_entries = er.async_entries_for_config_entry(ent_reg, integration.entry_id)
    assert len(entity_entries) == 15
    assert dev_reg.async_get_device({get_device_id(client, old_node)}) is None
Exemplo n.º 6
0
async def test_device_management(hass: HomeAssistant):
    """Test that we are adding and removing devices for monitors returned from the API."""
    mock_entry = await setup_uptimerobot_integration(hass)
    dev_reg = dr.async_get(hass)

    devices = dr.async_entries_for_config_entry(dev_reg, mock_entry.entry_id)
    assert len(devices) == 1

    assert devices[0].identifiers == {(DOMAIN, "1234")}
    assert devices[0].name == "Test monitor"

    assert hass.states.get(
        UPTIMEROBOT_BINARY_SENSOR_TEST_ENTITY).state == STATE_ON
    assert hass.states.get(
        f"{UPTIMEROBOT_BINARY_SENSOR_TEST_ENTITY}_2") is None

    with patch(
            "pyuptimerobot.UptimeRobot.async_get_monitors",
            return_value=mock_uptimerobot_api_response(data=[
                MOCK_UPTIMEROBOT_MONITOR, {
                    **MOCK_UPTIMEROBOT_MONITOR, "id": 12345
                }
            ]),
    ):
        async_fire_time_changed(hass,
                                dt.utcnow() + COORDINATOR_UPDATE_INTERVAL)
        await hass.async_block_till_done()

    devices = dr.async_entries_for_config_entry(dev_reg, mock_entry.entry_id)
    assert len(devices) == 2
    assert devices[0].identifiers == {(DOMAIN, "1234")}
    assert devices[1].identifiers == {(DOMAIN, "12345")}

    assert hass.states.get(
        UPTIMEROBOT_BINARY_SENSOR_TEST_ENTITY).state == STATE_ON
    assert (hass.states.get(f"{UPTIMEROBOT_BINARY_SENSOR_TEST_ENTITY}_2").state
            == STATE_ON)

    with patch(
            "pyuptimerobot.UptimeRobot.async_get_monitors",
            return_value=mock_uptimerobot_api_response(),
    ):
        async_fire_time_changed(hass,
                                dt.utcnow() + COORDINATOR_UPDATE_INTERVAL)
        await hass.async_block_till_done()

    devices = dr.async_entries_for_config_entry(dev_reg, mock_entry.entry_id)
    assert len(devices) == 1
    assert devices[0].identifiers == {(DOMAIN, "1234")}

    assert hass.states.get(
        UPTIMEROBOT_BINARY_SENSOR_TEST_ENTITY).state == STATE_ON
    assert hass.states.get(
        f"{UPTIMEROBOT_BINARY_SENSOR_TEST_ENTITY}_2") is None
Exemplo n.º 7
0
    async def _async_update_data(self) -> list[UptimeRobotMonitor] | None:
        """Update data."""
        try:
            response = await self.api.async_get_monitors()
        except UptimeRobotAuthenticationException as exception:
            raise ConfigEntryAuthFailed(exception) from exception
        except UptimeRobotException as exception:
            raise UpdateFailed(exception) from exception
        else:
            if response.status != API_ATTR_OK:
                raise UpdateFailed(response.error.message)

        monitors: list[UptimeRobotMonitor] = response.data

        current_monitors = {
            list(device.identifiers)[0][1]
            for device in dr.async_entries_for_config_entry(
                self._device_registry, self._config_entry_id)
        }
        new_monitors = {str(monitor.id) for monitor in monitors}
        if stale_monitors := current_monitors - new_monitors:
            for monitor_id in stale_monitors:
                if device := self._device_registry.async_get_device({
                    (DOMAIN, monitor_id)
                }):
                    self._device_registry.async_remove_device(device.id)
Exemplo n.º 8
0
async def test_get_trigger_capabilities_central_scene_value_notification(
    hass, client, wallmote_central_scene, integration
):
    """Test we get the expected capabilities from a value_notification.central_scene trigger."""
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
    capabilities = await device_trigger.async_get_trigger_capabilities(
        hass,
        {
            "platform": "device",
            "domain": DOMAIN,
            "type": "event.value_notification.central_scene",
            "device_id": device.id,
            "command_class": CommandClass.CENTRAL_SCENE.value,
            "property": "scene",
            "property_key": "001",
            "endpoint": 0,
            "subtype": "Endpoint 0 Scene 001",
        },
    )
    assert capabilities and "extra_fields" in capabilities

    assert voluptuous_serialize.convert(
        capabilities["extra_fields"], custom_serializer=cv.custom_serializer
    ) == [
        {
            "name": "value",
            "optional": True,
            "type": "select",
            "options": [(0, "KeyPressed"), (1, "KeyReleased"), (2, "KeyHeldDown")],
        },
    ]
Exemplo n.º 9
0
async def test_get_trigger_capabilities_scene_activation_value_notification(
    hass, client, hank_binary_switch, integration
):
    """Test we get the expected capabilities from a value_notification.scene_activation trigger."""
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
    capabilities = await device_trigger.async_get_trigger_capabilities(
        hass,
        {
            "platform": "device",
            "domain": DOMAIN,
            "type": "event.value_notification.scene_activation",
            "device_id": device.id,
            "command_class": CommandClass.SCENE_ACTIVATION.value,
            "property": "sceneId",
            "property_key": None,
            "endpoint": 0,
            "subtype": "Endpoint 0",
        },
    )
    assert capabilities and "extra_fields" in capabilities

    assert voluptuous_serialize.convert(
        capabilities["extra_fields"], custom_serializer=cv.custom_serializer
    ) == [
        {
            "name": "value",
            "optional": True,
            "type": "integer",
            "valueMin": 1,
            "valueMax": 255,
        }
    ]
Exemplo n.º 10
0
    def async_update_sensors(hass: HomeAssistant, config_entry: ConfigEntry) -> None:
        dev_reg = device_registry.async_get(hass)

        existing_devices = {
            device.name: device.id
            for device in device_registry.async_entries_for_config_entry(
                dev_reg, config_entry.entry_id
            )
        }

        sensors = []
        for tracked_asset_pair in config_entry.options[CONF_TRACKED_ASSET_PAIRS]:
            # Only create new devices
            if (
                device_name := create_device_name(tracked_asset_pair)
            ) in existing_devices:
                existing_devices.pop(device_name)
            else:
                for sensor_type in SENSOR_TYPES:
                    sensors.append(
                        KrakenSensor(
                            hass.data[DOMAIN],
                            tracked_asset_pair,
                            sensor_type,
                        )
                    )
Exemplo n.º 11
0
async def test_get_trigger_capabilities_entry_control_notification(
    hass, client, lock_schlage_be469, integration
):
    """Test we get the expected capabilities from a notification.entry_control trigger."""
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
    capabilities = await device_trigger.async_get_trigger_capabilities(
        hass,
        {
            "platform": "device",
            "domain": DOMAIN,
            "device_id": device.id,
            "type": "event.notification.entry_control",
            "command_class": CommandClass.ENTRY_CONTROL.value,
        },
    )
    assert capabilities and "extra_fields" in capabilities

    assert_lists_same(
        voluptuous_serialize.convert(
            capabilities["extra_fields"], custom_serializer=cv.custom_serializer
        ),
        [
            {"name": "event_type", "optional": True, "type": "string"},
            {"name": "data_type", "optional": True, "type": "string"},
        ],
    )
Exemplo n.º 12
0
async def test_text_overlay_good_left(hass: HomeAssistant) -> None:
    """Test a working text overlay with device_id."""
    client = create_mock_motioneye_client()
    await setup_mock_motioneye_config_entry(hass, client=client)
    device = dr.async_entries_for_config_entry(
        await dr.async_get_registry(hass), TEST_CONFIG_ENTRY_ID)[0]

    custom_right_text = "one\ntwo\nthree"
    data = {
        ATTR_DEVICE_ID: device.id,
        KEY_TEXT_OVERLAY_LEFT: KEY_TEXT_OVERLAY_TIMESTAMP,
        KEY_TEXT_OVERLAY_RIGHT: KEY_TEXT_OVERLAY_CUSTOM_TEXT,
        KEY_TEXT_OVERLAY_CUSTOM_TEXT_RIGHT: custom_right_text,
    }
    client.async_get_camera = AsyncMock(
        return_value=copy.deepcopy(TEST_CAMERA))
    await hass.services.async_call(DOMAIN, SERVICE_SET_TEXT_OVERLAY, data)
    await hass.async_block_till_done()
    assert client.async_get_camera.called

    expected_camera = copy.deepcopy(TEST_CAMERA)
    expected_camera[KEY_TEXT_OVERLAY_LEFT] = KEY_TEXT_OVERLAY_TIMESTAMP
    expected_camera[KEY_TEXT_OVERLAY_RIGHT] = KEY_TEXT_OVERLAY_CUSTOM_TEXT
    expected_camera[KEY_TEXT_OVERLAY_CUSTOM_TEXT_RIGHT] = "one\\ntwo\\nthree"
    assert client.async_set_camera.call_args == call(TEST_CAMERA_ID,
                                                     expected_camera)
Exemplo n.º 13
0
async def async_unload_entry(hass, entry):
    """Unload a config entry."""

    # cleanup platforms
    unload_ok = all(await asyncio.gather(*[
        hass.config_entries.async_forward_entry_unload(entry, platform)
        for platform in PLATFORMS
    ]))
    if not unload_ok:
        return False

    # disable discovery
    await discovery.async_stop(hass)

    # cleanup subscriptions
    for unsub in hass.data[DATA_UNSUB]:
        unsub()
    hass.data.pop(DATA_REMOVE_DISCOVER_COMPONENT.format("device_automation"))()
    for platform in PLATFORMS:
        hass.data.pop(DATA_REMOVE_DISCOVER_COMPONENT.format(platform))()

    # deattach device triggers
    device_registry = await hass.helpers.device_registry.async_get_registry()
    devices = async_entries_for_config_entry(device_registry, entry.entry_id)
    for device in devices:
        await device_automation.async_remove_automations(hass, device.id)

    return True
Exemplo n.º 14
0
    async def async_step_init(self,
                              user_input: dict[str, Any] | None = None
                              ) -> FlowResult:
        """Manage Hue options."""
        if user_input is not None:
            return self.async_create_entry(title="", data=user_input)

        # create a list of Hue device ID's that the user can select
        # to ignore availability status
        dev_reg = device_registry.async_get(self.hass)
        entries = device_registry.async_entries_for_config_entry(
            dev_reg, self.config_entry.entry_id)
        dev_ids = {
            identifier[1]: entry.name
            for entry in entries for identifier in entry.identifiers
            if identifier[0] == DOMAIN
        }
        # filter any non existing device id's from the list
        cur_ids = [
            item for item in self.config_entry.options.get(
                CONF_IGNORE_AVAILABILITY, []) if item in dev_ids
        ]

        return self.async_show_form(
            step_id="init",
            data_schema=vol.Schema({
                vol.Optional(
                    CONF_IGNORE_AVAILABILITY,
                    default=cur_ids,
                ):
                cv.multi_select(dev_ids),
            }),
        )
Exemplo n.º 15
0
    async def async_setup(self) -> bool:
        """Set up a Netgear router."""
        async with self._api_lock:
            if not await self.hass.async_add_executor_job(self._setup):
                return False

        # set already known devices to away instead of unavailable
        device_registry = dr.async_get(self.hass)
        devices = dr.async_entries_for_config_entry(device_registry, self.entry_id)
        for device_entry in devices:
            if device_entry.via_device_id is None:
                continue  # do not add the router itself

            device_mac = dict(device_entry.connections)[dr.CONNECTION_NETWORK_MAC]
            self.devices[device_mac] = {
                "mac": device_mac,
                "name": device_entry.name,
                "active": False,
                "last_seen": dt_util.utcnow() - timedelta(days=365),
                "device_model": None,
                "device_type": None,
                "type": None,
                "link_rate": None,
                "signal": None,
                "ip": None,
                "ssid": None,
                "conn_ap_mac": None,
                "allow_or_block": None,
            }

        return True
Exemplo n.º 16
0
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Unload a config entry."""
    unload_ok = await hass.config_entries.async_unload_platforms(
        entry, PLATFORMS)

    router = hass.data[DOMAIN][entry.entry_id][KEY_ROUTER]

    if unload_ok:
        hass.data[DOMAIN].pop(entry.entry_id)
        if not hass.data[DOMAIN]:
            hass.data.pop(DOMAIN)

    if router.mode != MODE_ROUTER:
        router_id = None
        # Remove devices that are no longer tracked
        device_registry = dr.async_get(hass)
        devices = dr.async_entries_for_config_entry(device_registry,
                                                    entry.entry_id)
        for device_entry in devices:
            if device_entry.via_device_id is None:
                router_id = device_entry.id
                continue  # do not remove the router itself
            device_registry.async_update_device(
                device_entry.id, remove_config_entry_id=entry.entry_id)
        # Remove entities that are no longer tracked
        entity_registry = er.async_get(hass)
        entries = er.async_entries_for_config_entry(entity_registry,
                                                    entry.entry_id)
        for entity_entry in entries:
            if entity_entry.device_id is not router_id:
                entity_registry.async_remove(entity_entry.entity_id)

    return unload_ok
Exemplo n.º 17
0
    async def try_connect(tries: int = 0, is_disconnect: bool = True) -> None:
        """Try connecting to the API client. Will retry if not successful."""
        if entry.entry_id not in hass.data[DOMAIN]:
            # When removing/disconnecting manually
            return

        device_registry = await hass.helpers.device_registry.async_get_registry()
        devices = dr.async_entries_for_config_entry(device_registry, entry.entry_id)
        for device in devices:
            # There is only one device in ESPHome
            if device.disabled:
                # Don't attempt to connect if it's disabled
                return

        data: RuntimeEntryData = hass.data[DOMAIN][entry.entry_id]
        for disconnect_cb in data.disconnect_callbacks:
            disconnect_cb()
        data.disconnect_callbacks = []
        data.available = False
        data.async_update_device_state(hass)

        if is_disconnect:
            # This can happen often depending on WiFi signal strength.
            # So therefore all these connection warnings are logged
            # as infos. The "unavailable" logic will still trigger so the
            # user knows if the device is not connected.
            _LOGGER.info("Disconnected from ESPHome API for %s", host)

        if tries != 0:
            # If not first re-try, wait and print message
            # Cap wait time at 1 minute. This is because while working on the
            # device (e.g. soldering stuff), users don't want to have to wait
            # a long time for their device to show up in HA again (this was
            # mentioned a lot in early feedback)
            #
            # In the future another API will be set up so that the ESP can
            # notify HA of connectivity directly, but for new we'll use a
            # really short reconnect interval.
            tries = min(tries, 10)  # prevent OverflowError
            wait_time = int(round(min(1.8 ** tries, 60.0)))
            _LOGGER.info("Trying to reconnect to %s in %s seconds", host, wait_time)
            await asyncio.sleep(wait_time)

        try:
            await cli.connect(on_stop=try_connect, login=True)
        except APIConnectionError as error:
            _LOGGER.info(
                "Can't connect to ESPHome API for %s (%s): %s",
                entry.unique_id,
                host,
                error,
            )
            # Schedule re-connect in event loop in order not to delay HA
            # startup. First connect is scheduled in tracked tasks.
            data.reconnect_task = hass.loop.create_task(
                try_connect(tries + 1, is_disconnect=False)
            )
        else:
            _LOGGER.info("Successfully connected to %s", host)
            hass.async_create_task(on_login())
Exemplo n.º 18
0
def async_migrate_entities_devices(
    hass: HomeAssistant, legacy_entry_id: str, new_entry: ConfigEntry
) -> None:
    """Move entities and devices to the new config entry."""
    migrated_devices = []
    device_registry = dr.async_get(hass)
    for dev_entry in dr.async_entries_for_config_entry(
        device_registry, legacy_entry_id
    ):
        for domain, value in dev_entry.identifiers:
            if domain == DOMAIN and value == new_entry.unique_id:
                _LOGGER.debug(
                    "Migrating device with %s to %s",
                    dev_entry.identifiers,
                    new_entry.unique_id,
                )
                migrated_devices.append(dev_entry.id)
                device_registry.async_update_device(
                    dev_entry.id,
                    add_config_entry_id=new_entry.entry_id,
                    remove_config_entry_id=legacy_entry_id,
                )

    entity_registry = er.async_get(hass)
    for reg_entity in er.async_entries_for_config_entry(
        entity_registry, legacy_entry_id
    ):
        if reg_entity.device_id in migrated_devices:
            entity_registry.async_update_entity(
                reg_entity.entity_id, config_entry_id=new_entry.entry_id
            )
Exemplo n.º 19
0
def async_migrate_legacy_entries(
    hass: HomeAssistant,
    hosts_by_mac: dict[str, str],
    config_entries_by_mac: dict[str, ConfigEntry],
    legacy_entry: ConfigEntry,
) -> None:
    """Migrate the legacy config entries to have an entry per device."""
    device_registry = dr.async_get(hass)
    for dev_entry in dr.async_entries_for_config_entry(device_registry,
                                                       legacy_entry.entry_id):
        for connection_type, mac in dev_entry.connections:
            if (connection_type != dr.CONNECTION_NETWORK_MAC
                    or mac in config_entries_by_mac):
                continue
            hass.async_create_task(
                hass.config_entries.flow.async_init(
                    DOMAIN,
                    context={"source": "migration"},
                    data={
                        CONF_HOST: hosts_by_mac.get(mac),
                        CONF_MAC: mac,
                        CONF_NAME: dev_entry.name or f"TP-Link device {mac}",
                    },
                ))

    async def _async_cleanup_legacy_entry(_now: datetime) -> None:
        await async_cleanup_legacy_entry(hass, legacy_entry.entry_id)

    hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STARTED,
                               _async_cleanup_legacy_entry)
Exemplo n.º 20
0
async def test_get_condition_capabilities_node_status(hass, client,
                                                      lock_schlage_be469,
                                                      integration):
    """Test we don't get capabilities from a node_status condition."""
    dev_reg = device_registry.async_get(hass)
    device = device_registry.async_entries_for_config_entry(
        dev_reg, integration.entry_id)[0]

    capabilities = await device_condition.async_get_condition_capabilities(
        hass,
        {
            "platform": "device",
            "domain": DOMAIN,
            "device_id": device.id,
            "type": "node_status",
        },
    )
    assert capabilities and "extra_fields" in capabilities
    assert voluptuous_serialize.convert(
        capabilities["extra_fields"],
        custom_serializer=cv.custom_serializer) == [{
            "name":
            "status",
            "required":
            True,
            "type":
            "select",
            "options": [
                ("asleep", "asleep"),
                ("awake", "awake"),
                ("dead", "dead"),
                ("alive", "alive"),
            ],
        }]
Exemplo n.º 21
0
async def test_deconz_events_bad_unique_id(hass, aioclient_mock,
                                           mock_deconz_websocket):
    """Verify no devices are created if unique id is bad or missing."""
    data = {
        "sensors": {
            "1": {
                "name": "Switch 1 no unique id",
                "type": "ZHASwitch",
                "state": {
                    "buttonevent": 1000
                },
                "config": {},
            },
            "2": {
                "name": "Switch 2 bad unique id",
                "type": "ZHASwitch",
                "state": {
                    "buttonevent": 1000
                },
                "config": {
                    "battery": 100
                },
                "uniqueid": "00:00-00",
            },
        }
    }
    with patch.dict(DECONZ_WEB_REQUEST, data):
        config_entry = await setup_deconz_integration(hass, aioclient_mock)

    device_registry = dr.async_get(hass)

    assert len(hass.states.async_all()) == 1
    assert (len(
        dr.async_entries_for_config_entry(device_registry,
                                          config_entry.entry_id)) == 2)
Exemplo n.º 22
0
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Unload a config entry."""

    # cleanup platforms
    unload_ok = await hass.config_entries.async_unload_platforms(
        entry, PLATFORMS)
    if not unload_ok:
        return False

    # disable discovery
    await discovery.async_stop(hass)

    # cleanup subscriptions
    for unsub in hass.data[DATA_UNSUB]:
        unsub()
    hass.data.pop(DATA_REMOVE_DISCOVER_COMPONENT.format("device_automation"))()
    for platform in PLATFORMS:
        hass.data.pop(DATA_REMOVE_DISCOVER_COMPONENT.format(platform))()

    # deattach device triggers
    device_registry = dr.async_get(hass)
    devices = async_entries_for_config_entry(device_registry, entry.entry_id)
    for device in devices:
        await device_automation.async_remove_automations(hass, device.id)

    return True
Exemplo n.º 23
0
async def test_text_overlay_bad_device_identifier(hass: HomeAssistant) -> None:
    """Test text overlay with bad device identifier."""
    client = create_mock_motioneye_client()
    await setup_mock_motioneye_config_entry(hass, client=client)
    device = dr.async_entries_for_config_entry(
        await dr.async_get_registry(hass), TEST_CONFIG_ENTRY_ID)[0]
    device_registry = await dr.async_get_registry(hass)

    data = {
        ATTR_DEVICE_ID: device.id,
        KEY_TEXT_OVERLAY_LEFT: KEY_TEXT_OVERLAY_TIMESTAMP,
    }

    # Set the device identifier to have a non-int camera_id.
    device_registry.async_update_device(device_id=device.id,
                                        new_identifiers={(DOMAIN,
                                                          "host:port_str")})

    await hass.services.async_call(DOMAIN, SERVICE_SET_TEXT_OVERLAY, data)
    await hass.async_block_till_done()
    assert not client.async_set_camera.called

    # Set the device_unique_id to have the wrong number of values.
    device_registry.async_update_device(device_id=device.id,
                                        new_identifiers={(DOMAIN, "host:port",
                                                          "another")})
    await hass.services.async_call(DOMAIN, SERVICE_SET_TEXT_OVERLAY, data)
    await hass.async_block_till_done()
    assert not client.async_set_camera.called
Exemplo n.º 24
0
    async def _reconnect_once(self) -> None:
        # Wait and clear reconnection event
        await self._reconnect_event.wait()
        self._reconnect_event.clear()

        # If in connected state, do not try to connect again.
        async with self._connected_lock:
            if self._connected:
                return

        # Check if the entry got removed or disabled, in which case we shouldn't reconnect
        if not DomainData.get(self._hass).is_entry_loaded(self._entry):
            # When removing/disconnecting manually
            return

        device_registry = self._hass.helpers.device_registry.async_get(self._hass)
        devices = dr.async_entries_for_config_entry(
            device_registry, self._entry.entry_id
        )
        for device in devices:
            # There is only one device in ESPHome
            if device.disabled:
                # Don't attempt to connect if it's disabled
                return

        await self._try_connect()
Exemplo n.º 25
0
async def async_setup_entry(hass, config_entry: ConfigEntry,
                            async_add_entities):
    """Set up the component sensors from a config entry."""
    # Register service to change the update interval on specific bridges
    platform = entity_platform.current_platform.get()
    platform.async_register_entity_service(
        SERVICE_SET_UPDATE_INTERVAL,
        SET_UPDATE_INTERVAL_SERVICE_SCHEMA,
        "async_set_update_interval",
    )

    # Add one sensor entity for each hue bridge and link it to the hub device
    base_name = config_entry.data.get(CONF_NAME, DEFAULT_SENSOR_NAME)
    initial_scan_interval = max(1, config_entry.data.get(CONF_SCAN_INTERVAL))
    device_registry: dr.DeviceRegistry = await dr.async_get_registry(hass)
    new_entities = []
    for i, (b_entry_id, bridge) in enumerate(hass.data[HUE_DOMAIN].items()):
        # Extract hue hub device to link the sensor with it
        device = next(
            filter(
                lambda dev: dev.via_device_id is None,
                dr.async_entries_for_config_entry(device_registry, b_entry_id),
            ))
        new_entities.append(
            HuePollingInterval(
                f"{base_name}_{i + 1}" if i else base_name,
                device,
                bridge.sensor_manager,
                initial_scan_interval,
            ))
    async_add_entities(new_entities, False)
Exemplo n.º 26
0
    async def handle_event(ev):
        # Find ESPHome Device ID
        esphome_id = ev.data["device_id"]

        device_id = device_ids.get(esphome_id)

        if device_id is not None:
            await scan_tag(ev.data["tag_id"], device_id)
            return

        esphome_entry = None

        # Find ESPHome entry based on esphome_id
        for entry in hass.config_entries.async_entries("esphome"):
            if entry.unique_id:
                esphome_entry = entry
                break

        if esphome_entry is None:
            await scan_tag(ev.data["tag_id"], device_id)
            return

        # Find ESPHome device in registry
        dev_reg = await device_registry.async_get_registry(hass)
        devices = device_registry.async_entries_for_config_entry(
            dev_reg, esphome_entry.entry_id)

        if devices:
            device_id = devices[0].id
            device_ids[esphome_id] = device_id

        await scan_tag(ev.data["tag_id"], device_id)
Exemplo n.º 27
0
async def async_get_config_entry_diagnostics(
    hass: HomeAssistant,
    config_entry: ConfigEntry,
) -> dict[str, Any]:
    """Return diagnostics for a config entry."""
    coordinator = hass.data[DOMAIN][config_entry.entry_id]
    device_registry = dr.async_get(hass)
    entity_registry = er.async_get(hass)

    devices = []

    registry_devices = dr.async_entries_for_config_entry(
        device_registry, config_entry.entry_id)

    for device in registry_devices:
        entities = []

        registry_entities = er.async_entries_for_device(
            entity_registry,
            device_id=device.id,
            include_disabled_entities=True,
        )

        for entity in registry_entities:
            state_dict = None
            if state := hass.states.get(entity.entity_id):
                state_dict = dict(state.as_dict())
                state_dict.pop("context", None)

            entities.append({"entry": asdict(entity), "state": state_dict})

        devices.append({"device": asdict(device), "entities": entities})
Exemplo n.º 28
0
def _async_get_diagnostics(
    hass: HomeAssistant,
    entry: ConfigEntry,
    device: DeviceEntry | None = None,
) -> dict[str, Any]:
    """Return diagnostics for a config entry."""
    mqtt_instance: MQTT = hass.data[DATA_MQTT]

    redacted_config = async_redact_data(mqtt_instance.conf, REDACT_CONFIG)

    data = {
        "connected": is_connected(hass),
        "mqtt_config": redacted_config,
    }

    if device:
        data["device"] = _async_device_as_dict(hass, device)
        data["mqtt_debug_info"] = debug_info.info_for_device(hass, device.id)
    else:
        device_registry = dr.async_get(hass)
        data.update(
            devices=[
                _async_device_as_dict(hass, device)
                for device in dr.async_entries_for_config_entry(
                    device_registry, entry.entry_id)
            ],
            mqtt_debug_info=debug_info.info_for_config_entry(hass),
        )

    return data
Exemplo n.º 29
0
    async def async_setup(self) -> None:
        """Set up a Netgear router."""
        await self.hass.async_add_executor_job(self._setup)

        # set already known devices to away instead of unavailable
        device_registry = dr.async_get(self.hass)
        devices = dr.async_entries_for_config_entry(device_registry, self.entry_id)
        for device_entry in devices:
            if device_entry.via_device_id is None:
                continue  # do not add the router itself

            device_mac = dict(device_entry.connections).get(dr.CONNECTION_NETWORK_MAC)
            self.devices[device_mac] = {
                "mac": device_mac,
                "name": device_entry.name,
                "active": False,
                "last_seen": dt_util.utcnow() - timedelta(days=365),
                "device_model": None,
                "device_type": None,
                "type": None,
                "link_rate": None,
                "signal": None,
                "ip": None,
            }

        await self.async_update_device_trackers()
        self.entry.async_on_unload(
            async_track_time_interval(
                self.hass, self.async_update_device_trackers, SCAN_INTERVAL
            )
        )

        async_dispatcher_send(self.hass, self.signal_device_new)
Exemplo n.º 30
0
    def add_public_entities():
        """Retrieve Netatmo public weather entities."""
        entities = []
        for area in entry.options.get(CONF_WEATHER_AREAS, {}).values():
            data = NetatmoPublicData(
                auth,
                lat_ne=area[CONF_LAT_NE],
                lon_ne=area[CONF_LON_NE],
                lat_sw=area[CONF_LAT_SW],
                lon_sw=area[CONF_LON_SW],
            )
            for sensor_type in SUPPORTED_PUBLIC_SENSOR_TYPES:
                entities.append(NetatmoPublicSensor(
                    area,
                    data,
                    sensor_type,
                ))

        for device in async_entries_for_config_entry(device_registry,
                                                     entry.entry_id):
            if device.model == "Public Weather stations":
                device_registry.async_remove_device(device.id)

        if entities:
            async_add_entities(entities)