async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
    """Set up Nest from a config entry with dispatch between old/new flows."""

    if DATA_SDM not in entry.data:
        return await async_setup_legacy_entry(hass, entry)

    implementation = (
        await config_entry_oauth2_flow.async_get_config_entry_implementation(
            hass, entry))

    config = hass.data[DOMAIN][DATA_NEST_CONFIG]

    session = config_entry_oauth2_flow.OAuth2Session(hass, entry,
                                                     implementation)
    auth = api.AsyncConfigEntryAuth(
        aiohttp_client.async_get_clientsession(hass),
        session,
        API_URL,
    )
    subscriber = GoogleNestSubscriber(auth, config[CONF_PROJECT_ID],
                                      config[CONF_SUBSCRIBER_ID])
    subscriber.set_update_callback(SignalUpdateCallback(hass))
    asyncio.create_task(subscriber.start_async())
    hass.data[DOMAIN][entry.entry_id] = subscriber

    for component in PLATFORMS:
        hass.async_create_task(
            hass.config_entries.async_forward_entry_setup(entry, component))

    return True
Beispiel #2
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
    """Set up Nest from a config entry with dispatch between old/new flows."""

    if DATA_SDM not in entry.data:
        return await async_setup_legacy_entry(hass, entry)

    implementation = (
        await config_entry_oauth2_flow.async_get_config_entry_implementation(
            hass, entry
        )
    )

    config = hass.data[DOMAIN][DATA_NEST_CONFIG]

    session = config_entry_oauth2_flow.OAuth2Session(hass, entry, implementation)
    auth = api.AsyncConfigEntryAuth(
        aiohttp_client.async_get_clientsession(hass),
        session,
        config[CONF_CLIENT_ID],
        config[CONF_CLIENT_SECRET],
    )
    subscriber = GoogleNestSubscriber(
        auth, config[CONF_PROJECT_ID], config[CONF_SUBSCRIBER_ID]
    )
    callback = SignalUpdateCallback(hass)
    subscriber.set_update_callback(callback.async_handle_event)

    try:
        await subscriber.start_async()
    except AuthException as err:
        _LOGGER.debug("Subscriber authentication error: %s", err)
        raise ConfigEntryAuthFailed from err
    except ConfigurationException as err:
        _LOGGER.error("Configuration error: %s", err)
        subscriber.stop_async()
        return False
    except GoogleNestException as err:
        if DATA_NEST_UNAVAILABLE not in hass.data[DOMAIN]:
            _LOGGER.error("Subscriber error: %s", err)
            hass.data[DOMAIN][DATA_NEST_UNAVAILABLE] = True
        subscriber.stop_async()
        raise ConfigEntryNotReady from err

    try:
        await subscriber.async_get_device_manager()
    except GoogleNestException as err:
        if DATA_NEST_UNAVAILABLE not in hass.data[DOMAIN]:
            _LOGGER.error("Device manager error: %s", err)
            hass.data[DOMAIN][DATA_NEST_UNAVAILABLE] = True
        subscriber.stop_async()
        raise ConfigEntryNotReady from err

    hass.data[DOMAIN].pop(DATA_NEST_UNAVAILABLE, None)
    hass.data[DOMAIN][DATA_SUBSCRIBER] = subscriber

    hass.config_entries.async_setup_platforms(entry, PLATFORMS)

    return True
Beispiel #3
0
async def test_subscribe_device_manager_init(aiohttp_server) -> None:
    subscriber_factory = FakeSubscriberFactory()
    r = Recorder()
    handler = NewDeviceHandler(
        r,
        [
            {
                "name": "enterprises/project-id1/devices/device-id1",
                "type": "sdm.devices.types.device-type1",
                "traits": {},
                "parentRelations": [],
            },
            {
                "name": "enterprises/project-id1/devices/device-id2",
                "type": "sdm.devices.types.device-type2",
                "traits": {},
                "parentRelations": [],
            },
        ],
    )

    app = aiohttp.web.Application()
    app.router.add_get("/enterprises/project-id1/devices", handler)
    app.router.add_get(
        "/enterprises/project-id1/structures",
        NewStructureHandler(
            r,
            [
                {
                    "name": "enterprises/project-id1/structures/structure-id1",
                }
            ],
        ),
    )
    server = await aiohttp_server(app)

    async with aiohttp.test_utils.TestClient(server) as client:
        subscriber = GoogleNestSubscriber(
            FakeAuth(client), PROJECT_ID, SUBSCRIBER_ID, subscriber_factory
        )
        start_async = subscriber.start_async()
        device_manager = await subscriber.async_get_device_manager()
        await start_async
        devices = device_manager.devices
        assert "enterprises/project-id1/devices/device-id1" in devices
        assert (
            "sdm.devices.types.device-type1"
            == devices["enterprises/project-id1/devices/device-id1"].type
        )
        assert "enterprises/project-id1/devices/device-id2" in devices
        assert (
            "sdm.devices.types.device-type2"
            == devices["enterprises/project-id1/devices/device-id2"].type
        )
Beispiel #4
0
async def test_subscriber_watchdog(aiohttp_server) -> None:
    # Waits for the test to wake up the background thread
    event1 = asyncio.Event()

    async def task1():
        print("Task1")
        await event1.wait()
        return

    event2 = asyncio.Event()

    async def task2():
        print("Task2")
        event2.set()

    subscriber_factory = FakeSubscriberFactory(tasks=[task1, task2])
    r = Recorder()
    handler = NewDeviceHandler(
        r,
        [],
    )

    app = aiohttp.web.Application()
    app.router.add_get("/enterprises/project-id1/devices",
                       NewDeviceHandler(r, []))
    app.router.add_get(
        "/enterprises/project-id1/structures",
        NewStructureHandler(r, []),
    )
    server = await aiohttp_server(app)

    async with aiohttp.test_utils.TestClient(server) as client:
        subscriber = GoogleNestSubscriber(
            FakeAuth(client),
            PROJECT_ID,
            SUBSCRIBER_ID,
            subscriber_factory=subscriber_factory,
            watchdog_delay=0.1,
        )
        assert len(subscriber_factory.tasks) == 2
        await subscriber.start_async()
        assert len(subscriber_factory.tasks) == 1
        # Wait for the subscriber to start, then shut it down
        event1.set()
        # Block until the new subscriber starts, and notifies this to wake up
        await event2.wait()
        assert len(subscriber_factory.tasks) == 0
        subscriber.stop_async()
Beispiel #5
0
def new_subscriber_with_token(
    hass: HomeAssistant,
    access_token: str,
    project_id: str,
    subscriber_id: str,
) -> GoogleNestSubscriber:
    """Create a GoogleNestSubscriber with an access token."""
    return GoogleNestSubscriber(
        AccessTokenAuthImpl(
            aiohttp_client.async_get_clientsession(hass),
            access_token,
        ),
        project_id,
        subscriber_id,
    )
Beispiel #6
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
    """Set up Nest from a config entry with dispatch between old/new flows."""

    if DATA_SDM not in entry.data:
        return await async_setup_legacy_entry(hass, entry)

    implementation = (
        await config_entry_oauth2_flow.async_get_config_entry_implementation(
            hass, entry))

    config = hass.data[DOMAIN][DATA_NEST_CONFIG]

    session = config_entry_oauth2_flow.OAuth2Session(hass, entry,
                                                     implementation)
    auth = api.AsyncConfigEntryAuth(
        aiohttp_client.async_get_clientsession(hass),
        session,
        API_URL,
    )
    subscriber = GoogleNestSubscriber(auth, config[CONF_PROJECT_ID],
                                      config[CONF_SUBSCRIBER_ID])
    subscriber.set_update_callback(SignalUpdateCallback(hass))

    try:
        await subscriber.start_async()
    except GoogleNestException as err:
        _LOGGER.error("Subscriber error: %s", err)
        subscriber.stop_async()
        raise ConfigEntryNotReady from err

    try:
        await subscriber.async_get_device_manager()
    except GoogleNestException as err:
        _LOGGER.error("Device Manager error: %s", err)
        subscriber.stop_async()
        raise ConfigEntryNotReady from err

    hass.data[DOMAIN][DATA_SUBSCRIBER] = subscriber

    for component in PLATFORMS:
        hass.async_create_task(
            hass.config_entries.async_forward_entry_setup(entry, component))

    return True
Beispiel #7
0
async def new_subscriber_with_impl(
    hass: HomeAssistant,
    entry: ConfigEntry,
    subscriber_id: str,
    implementation: config_entry_oauth2_flow.AbstractOAuth2Implementation,
) -> GoogleNestSubscriber:
    """Create a GoogleNestSubscriber, used during ConfigFlow."""
    config = hass.data[DOMAIN][DATA_NEST_CONFIG]
    session = config_entry_oauth2_flow.OAuth2Session(hass, entry,
                                                     implementation)
    auth = AsyncConfigEntryAuth(
        aiohttp_client.async_get_clientsession(hass),
        session,
        config[CONF_CLIENT_ID],
        config[CONF_CLIENT_SECRET],
    )
    return GoogleNestSubscriber(auth, config[CONF_PROJECT_ID], subscriber_id)
Beispiel #8
0
async def test_subscribe_update_trait(aiohttp_server) -> None:
    subscriber_factory = FakeSubscriberFactory()
    r = Recorder()
    handler = NewDeviceHandler(
        r,
        [{
            "name": "enterprises/project-id1/devices/device-id1",
            "type": "sdm.devices.types.device-type1",
            "traits": {
                "sdm.devices.traits.Connectivity": {
                    "status": "ONLINE",
                },
            },
            "parentRelations": [],
        }],
    )

    app = aiohttp.web.Application()
    app.router.add_get("/enterprises/project-id1/devices", handler)
    app.router.add_get(
        "/enterprises/project-id1/structures",
        NewStructureHandler(
            r,
            [{
                "name": "enterprises/project-id1/structures/structure-id1",
            }],
        ),
    )
    server = await aiohttp_server(app)

    async with aiohttp.test_utils.TestClient(server) as client:
        subscriber = GoogleNestSubscriber(FakeAuth(client), PROJECT_ID,
                                          SUBSCRIBER_ID, subscriber_factory)
        await subscriber.start_async()
        device_manager = await subscriber.async_get_device_manager()
        devices = device_manager.devices
        assert "enterprises/project-id1/devices/device-id1" in devices
        device = devices["enterprises/project-id1/devices/device-id1"]
        trait = device.traits["sdm.devices.traits.Connectivity"]
        assert "ONLINE" == trait.status

        event = {
            "eventId": "6f29332e-5537-47f6-a3f9-840c307340f5",
            "timestamp": "2020-10-10T07:09:06.851Z",
            "resourceUpdate": {
                "name": "enterprises/project-id1/devices/device-id1",
                "traits": {
                    "sdm.devices.traits.Connectivity": {
                        "status": "OFFLINE",
                    }
                },
            },
            "userId": "AVPHwEv75jw4WFshx6-XhBLhotn3r8IXOzCusfSOn5QU",
        }
        subscriber_factory.push_event(event)

        devices = device_manager.devices
        assert "enterprises/project-id1/devices/device-id1" in devices
        device = devices["enterprises/project-id1/devices/device-id1"]
        trait = device.traits["sdm.devices.traits.Connectivity"]
        assert "OFFLINE" == trait.status
        subscriber.stop_async()
Beispiel #9
0
    """Create a GoogleNestSubscriber."""
    implementation = (
        await config_entry_oauth2_flow.async_get_config_entry_implementation(
            hass, entry))
    if not isinstance(implementation,
                      config_entry_oauth2_flow.LocalOAuth2Implementation):
        raise ValueError(f"Unexpected auth implementation {implementation}")
    if not (subscriber_id := entry.data.get(CONF_SUBSCRIBER_ID)):
        raise ValueError("Configuration option 'subscriber_id' missing")
    auth = AsyncConfigEntryAuth(
        aiohttp_client.async_get_clientsession(hass),
        config_entry_oauth2_flow.OAuth2Session(hass, entry, implementation),
        implementation.client_id,
        implementation.client_secret,
    )
    return GoogleNestSubscriber(auth, entry.data[CONF_PROJECT_ID],
                                subscriber_id)


def new_subscriber_with_token(
    hass: HomeAssistant,
    access_token: str,
    project_id: str,
    subscriber_id: str,
) -> GoogleNestSubscriber:
    """Create a GoogleNestSubscriber with an access token."""
    return GoogleNestSubscriber(
        AccessTokenAuthImpl(
            aiohttp_client.async_get_clientsession(hass),
            access_token,
        ),
        project_id,
Beispiel #10
0
    """Create a GoogleNestSubscriber."""
    implementation = (
        await config_entry_oauth2_flow.async_get_config_entry_implementation(
            hass, entry))
    config = hass.data[DOMAIN][DATA_NEST_CONFIG]
    if not (subscriber_id := entry.data.get(CONF_SUBSCRIBER_ID,
                                            config.get(CONF_SUBSCRIBER_ID))):
        _LOGGER.error("Configuration option 'subscriber_id' required")
        return None
    auth = AsyncConfigEntryAuth(
        aiohttp_client.async_get_clientsession(hass),
        config_entry_oauth2_flow.OAuth2Session(hass, entry, implementation),
        config[CONF_CLIENT_ID],
        config[CONF_CLIENT_SECRET],
    )
    return GoogleNestSubscriber(auth, config[CONF_PROJECT_ID], subscriber_id)


def new_subscriber_with_token(
    hass: HomeAssistant,
    access_token: str,
    project_id: str,
    subscriber_id: str,
) -> GoogleNestSubscriber:
    """Create a GoogleNestSubscriber with an access token."""
    return GoogleNestSubscriber(
        AccessTokenAuthImpl(
            aiohttp_client.async_get_clientsession(hass),
            access_token,
        ),
        project_id,