Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Nest config flow #14921

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Jun 13, 2018
Merged

Nest config flow #14921

merged 15 commits into from
Jun 13, 2018

Conversation

balloob
Copy link
Member

@balloob balloob commented Jun 11, 2018

Description:

Add a config flow to configure Nest. Backwards compatible!

  • Move Nest component to be folder based and split component up
  • When client id/secret is provided via configuration.yaml, the config flow can be used to configure your Nest account. I did not incorporate asking for client id/secret inside the config flow as that requires a developer account, I don't find that suitable for a UI config flow.
  • Config flow is structured in a way that creates foundation for other components to add authentication implementation. This foundation is not done yet, as I didn't want to clutter this PR. In the future, if a user is logged into the cloud component, they will be able to do a full OAuth2 flow without the user having to register their own developer account.

Basic functionality is already working.

To do:

Pull request in home-assistant.github.io with documentation (if applicable): home-assistant/home-assistant.github.io#<home-assistant.github.io PR number goes here>

Example entry for configuration.yaml (if applicable):

nest:
  client_id: bla
  client_secret: bla

Checklist:

  • The code change is tested and works locally.
  • Local tests pass with tox. Your PR cannot be merged unless tests pass

If user exposed functionality or configuration variables are added/changed:

If the code communicates with devices, web services, or third-party tools:

  • New dependencies have been added to the REQUIREMENTS variable (example).
  • New dependencies are only imported inside functions that use them (example).
  • New or updated dependencies have been added to requirements_all.txt by running script/gen_requirements_all.py.
  • New files were added to .coveragerc.

If the code does not interact with devices:

  • Tests have been added to verify that the new code works.

if self.hass.config_entries.async_entries(DOMAIN):
return self.async_abort(reason='already_setup')

tokens = await self.hass.async_add_job(load_json, info['nest_conf_path'])

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long (81 > 79 characters)

@balloob balloob changed the title WIP: Nest config flow Nest config flow Jun 11, 2018
return self.async_abort(reason='already_setup')

flow = self.hass.data[DATA_FLOW_IMPL][DOMAIN]
tokens = await self.hass.async_add_job(

This comment was marked as resolved.

if self.hass.config_entries.async_entries(DOMAIN):
return self.async_abort(reason='already_setup')

flow = self.hass.data[DATA_FLOW_IMPL][DOMAIN]

This comment was marked as resolved.

Copy link
Member

@MartinHjelmare MartinHjelmare left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Two small comments.

{
"config": {
"abort": {
"already_setup": "You can only configure a single Nest account",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no period at the end here.

"internal_error": "Internal error validating code"
},
"abort": {
"already_setup": "You can only configure a single Nest account",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

from . import config_flow
from .const import DOMAIN

ACCESS_TOKEN_URL = 'https://api.home.nest.com/oauth2/access_token'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I've rewritten to use this whole file to use the authentication mechanism from python-nest. I've added a test so that if the package changes, it will blow up our test.

@awarecan
Copy link
Contributor

awarecan commented Jun 11, 2018

without the user having to register their own developer account.

Does that mean HA Cloud will have to pass Work with Nest certification? I have little doubt about that, some guy in SmartThings community want to do similar things and rejected by Nest several times. Nest said, such "usage" should ask each user register their own developer account.

See Nest's response here

@@ -0,0 +1,154 @@
"""Config flow to configure Philips Hue."""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy paste issue

VERSION = 1

def __init__(self):
"""Initialize the Hue flow."""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy paste issue

filename = config.get(CONF_FILENAME, NEST_CONFIG_FILE)
access_token_cache_file = hass.config.path(filename)

if await hass.async_add_job(os.path.isfile, access_token_cache_file):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is await unnecessary? I think async_add_job is not a coroutine

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It returns a task that is awaitable for the result of the function. This is used to run non asyncio functions inside a worker thread pool and get the response.


_LOGGER.debug("proceeding with setup")
conf = config[DOMAIN]
conf = hass.data.get(DATA_NEST_CONFIG, {})
hass.data[DATA_NEST] = NestDevice(hass, conf, nest)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There may have a potential issue, inside NestDevice constructor, it will first call nest.Nest._status, which will trigger the establish of the persistence HTTP connection. This function may block event loop for few seconds, depends on network condition. It wouldn't be necessary address in this PR. I will figure out some solution, or take this chane to change python-nest better support asyncio.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! We should never do I/O inside the event loop. I've pushed the I/O pieces into a standalone initialize function.


import pytest

import requests

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'requests' imported but unused

@balloob
Copy link
Member Author

balloob commented Jun 12, 2018

Does that mean HA Cloud will have to pass Work with Nest certification?

Yes. Home Assistant Cloud will try to work directly with partners to pass certification.

from homeassistant.helpers.dispatcher import async_dispatcher_send, \
async_dispatcher_connect
from homeassistant.helpers.entity import Entity

REQUIREMENTS = ['python-nest==4.0.2']
from .const import DOMAIN
from . import local_auth

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

module level import not at top of file

from homeassistant.helpers.dispatcher import async_dispatcher_send, \
async_dispatcher_connect
from homeassistant.helpers.entity import Entity

REQUIREMENTS = ['python-nest==4.0.2']
from .const import DOMAIN

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

module level import not at top of file

def initialize(self):
"""Initialize Nest."""
if self.local_structure is None:
self.local_structure = [s.name for s in self.nest.structures]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to trigger a Nest API call even self.local_structure is None.

structure_names = [s.name for s in self.nest.structures]
if self.local_structure is None:
    self.local_structure = structure_names
else:
    for structure in self.local_structure:
        if  structure not in structure_names:
            # raise ValueError('cannot find structure')

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure? That's not how the current logic works:

image

Copy link
Contributor

@awarecan awarecan Jun 12, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am sure. Because in current implement, in next few lines, it will access nest.structures anyway.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see that in the current code

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If goes else, then next line talked to Nest API will be here, it is called by climate.nest setup code.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, in that case, it would not block nest component setup, but will block climate.nest setup. I think better resolve that in initialize() method.

@awarecan
Copy link
Contributor

@balloob since you are working on config flow, can you add another workflow?
Current implement if I understanding is right, likes

load_config() ---> client_id/client_secret --> if access_token_cached --> import(access_token)
                                                |--> else redirect user to input pin -> cache access_token

can you change it to

load_config() ---> if access_token_cached --> import(access_token)
                   |--> else if no client_id/secret --> ask user input client_id/secret -->
                   |--> else if has client_id/secret --> redirect user to input pin -> cache access_token

By this way, I don't need save my client_secret in conf file anymore

@balloob
Copy link
Member Author

balloob commented Jun 12, 2018

I will not change that work flow. As said in the PR description, client ID / secret will have to be defined in configuration.yaml. As also mentioned in the PR description, existing access tokens are already imported.

Sorry I misunderstood. You're not talking about config flow but about how to deal with configuration.yaml.

I only added the initial importing now for backwards compatibility. In the future, people don't have an access token cache anymore.

Also, making any further changes is out of scope for this PR. It's already big enough.

@balloob balloob force-pushed the nest-config-flow branch from 31d76fb to d40e09e Compare June 13, 2018 14:59
@balloob balloob merged commit e014a84 into dev Jun 13, 2018
@ghost ghost removed the in progress label Jun 13, 2018
@balloob balloob deleted the nest-config-flow branch June 13, 2018 15:14
awarecan pushed a commit to awarecan/home-assistant that referenced this pull request Jun 13, 2018
* Move nest to dir based component

* Add config flow for Nest

* Load Nest platforms via config entry

* Add tests for Nest config flow

* Import existing access tokens as config entries

* Lint

* Update coverage

* Update translation

* Fix tests

* Address strings

* Use python-nest token resolution

* Lint

* Do not do I/O inside constructor

* Lint

* Update test requirements
@balloob balloob mentioned this pull request Jun 22, 2018
girlpunk pushed a commit to girlpunk/home-assistant that referenced this pull request Sep 4, 2018
* Move nest to dir based component

* Add config flow for Nest

* Load Nest platforms via config entry

* Add tests for Nest config flow

* Import existing access tokens as config entries

* Lint

* Update coverage

* Update translation

* Fix tests

* Address strings

* Use python-nest token resolution

* Lint

* Do not do I/O inside constructor

* Lint

* Update test requirements
@home-assistant home-assistant locked and limited conversation to collaborators Dec 10, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants