-
-
Notifications
You must be signed in to change notification settings - Fork 34.1k
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
Nest config flow #14921
Conversation
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']) |
There was a problem hiding this comment.
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)
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.
This comment was marked as resolved.
Sorry, something went wrong.
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.
This comment was marked as resolved.
Sorry, something went wrong.
There was a problem hiding this 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", |
There was a problem hiding this comment.
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", |
There was a problem hiding this comment.
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' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we get those URLs from python-nest?
https://github.com/jkoelker/python-nest/blob/a45cda8c4efae0ec0725fe15d2788928cd54f21d/nest/nest.py#L22-L23
There was a problem hiding this comment.
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.
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.""" |
There was a problem hiding this comment.
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.""" |
There was a problem hiding this comment.
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): |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'requests' imported but unused
Yes. Home Assistant Cloud will try to work directly with partners to pass certification. |
26c1225
to
ffd704c
Compare
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 |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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] |
There was a problem hiding this comment.
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')
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
@balloob since you are working on config flow, can you add another workflow?
can you change it to
By this way, I don't need save my client_secret in conf file anymore |
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. |
31d76fb
to
d40e09e
Compare
* 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
* 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
Description:
Add a config flow to configure Nest. Backwards compatible!
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):Checklist:
tox
. Your PR cannot be merged unless tests passIf user exposed functionality or configuration variables are added/changed:
If the code communicates with devices, web services, or third-party tools:
REQUIREMENTS
variable (example).requirements_all.txt
by runningscript/gen_requirements_all.py
..coveragerc
.If the code does not interact with devices: