mirror of
https://github.com/USA-RedDragon/badnest.git
synced 2025-01-18 22:50:44 +00:00
Added Code for Google Auth Login
This commit is contained in:
parent
c686190a24
commit
5d74119c38
3
.gitignore
vendored
3
.gitignore
vendored
@ -89,4 +89,5 @@ ENV/
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
.vscode/
|
||||
.vscode/
|
||||
.DS_Store
|
||||
|
@ -3,14 +3,19 @@ import voluptuous as vol
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD
|
||||
|
||||
from .const import DOMAIN
|
||||
from .const import DOMAIN, CONF_ISSUE_TOKEN, CONF_COOKIE, CONF_APIKEY
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema(
|
||||
{
|
||||
DOMAIN: vol.Schema(
|
||||
DOMAIN: vol.All(
|
||||
{
|
||||
vol.Required(CONF_EMAIL): cv.string,
|
||||
vol.Required(CONF_PASSWORD): cv.string,
|
||||
vol.Required(CONF_EMAIL, default=""): cv.string,
|
||||
vol.Required(CONF_PASSWORD, default=""): cv.string,
|
||||
},
|
||||
{
|
||||
vol.Required(CONF_ISSUE_TOKEN, default=""): cv.string,
|
||||
vol.Required(CONF_COOKIE, default=""): cv.string,
|
||||
vol.Required(CONF_APIKEY, default=""): cv.string
|
||||
}
|
||||
)
|
||||
},
|
||||
@ -23,10 +28,22 @@ def setup(hass, config):
|
||||
if config.get(DOMAIN) is not None:
|
||||
email = config[DOMAIN].get(CONF_EMAIL)
|
||||
password = config[DOMAIN].get(CONF_PASSWORD)
|
||||
issue_token = config[DOMAIN].get(CONF_ISSUE_TOKEN)
|
||||
cookie = config[DOMAIN].get(CONF_COOKIE)
|
||||
api_key = config[DOMAIN].get(CONF_APIKEY)
|
||||
else:
|
||||
email = None
|
||||
password = None
|
||||
issue_token = None
|
||||
cookie = None
|
||||
api_key = None
|
||||
|
||||
hass.data[DOMAIN] = {CONF_EMAIL: email, CONF_PASSWORD: password}
|
||||
hass.data[DOMAIN] = {
|
||||
CONF_EMAIL: email,
|
||||
CONF_PASSWORD: password,
|
||||
CONF_ISSUE_TOKEN: issue_token,
|
||||
CONF_COOKIE: cookie,
|
||||
CONF_APIKEY: api_key
|
||||
}
|
||||
|
||||
return True
|
||||
|
@ -3,32 +3,71 @@ import requests
|
||||
API_URL = "https://home.nest.com"
|
||||
CAMERA_WEBAPI_BASE = "https://webapi.camera.home.nest.com"
|
||||
CAMERA_URL = "https://nexusapi-us1.camera.home.nest.com"
|
||||
USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) " \
|
||||
"AppleWebKit/537.36 (KHTML, like Gecko) " \
|
||||
"Chrome/75.0.3770.100 Safari/537.36"
|
||||
URL_JWT = "https://nestauthproxyservice-pa.googleapis.com/v1/issue_jwt"
|
||||
|
||||
|
||||
class NestAPI:
|
||||
def __init__(self, email, password):
|
||||
def __init__(self, email, password, issue_token, cookie, api_key):
|
||||
self._user_id = None
|
||||
self._access_token = None
|
||||
self._session = requests.Session()
|
||||
self._session.headers.update({"Referer": "https://home.nest.com/"})
|
||||
self._device_id = None
|
||||
self._login(email, password)
|
||||
if email is not None and password is not None:
|
||||
self._login_nest(email, password)
|
||||
else:
|
||||
self._login_google(issue_token, cookie, api_key)
|
||||
self.update()
|
||||
|
||||
def _login(self, email, password):
|
||||
def _login_nest(self, email, password):
|
||||
r = self._session.post(
|
||||
f"{API_URL}/session", json={"email": email, "password": password}
|
||||
)
|
||||
self._user_id = r.json()["userid"]
|
||||
self._access_token = r.json()["access_token"]
|
||||
|
||||
def _login_google(self, issue_token, cookie, api_key):
|
||||
headers = {
|
||||
'Sec-Fetch-Mode': 'cors',
|
||||
'User-Agent': USER_AGENT,
|
||||
'X-Requested-With': 'XmlHttpRequest',
|
||||
'Referer': 'https://accounts.google.com/o/oauth2/iframe',
|
||||
'cookie': cookie
|
||||
}
|
||||
r = requests.get(url=issue_token, headers=headers)
|
||||
access_token = r.json()['access_token']
|
||||
|
||||
headers = {
|
||||
'Authorization': 'Bearer ' + access_token,
|
||||
'User-Agent': USER_AGENT,
|
||||
'x-goog-api-key': api_key,
|
||||
'Referer': 'https://home.nest.com'
|
||||
}
|
||||
params = {
|
||||
"embed_google_oauth_access_token": True,
|
||||
"expire_after": '3600s',
|
||||
"google_oauth_access_token": access_token,
|
||||
"policy_id": 'authproxy-oauth-policy'
|
||||
}
|
||||
r = requests.post(url=URL_JWT, headers=headers, params=params)
|
||||
self._user_id = r.json()['claims']['subject']['nestId']['id']
|
||||
self._access_token = r.json()['jwt']
|
||||
|
||||
def update(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class NestThermostatAPI(NestAPI):
|
||||
def __init__(self, email, password):
|
||||
super(NestThermostatAPI, self).__init__(email, password)
|
||||
def __init__(self, email, password, issue_token, cookie, api_key):
|
||||
super(NestThermostatAPI, self).__init__(
|
||||
email,
|
||||
password,
|
||||
issue_token,
|
||||
cookie,
|
||||
api_key)
|
||||
self._shared_id = None
|
||||
self._czfe_url = None
|
||||
self._compressor_lockout_enabled = None
|
||||
@ -182,8 +221,13 @@ class NestThermostatAPI(NestAPI):
|
||||
|
||||
|
||||
class NestCameraAPI(NestAPI):
|
||||
def __init__(self, email, password):
|
||||
super(NestCameraAPI, self).__init__(email, password)
|
||||
def __init__(self, email, password, issue_token, cookie, api_key):
|
||||
super(NestCameraAPI, self).__init__(
|
||||
email,
|
||||
password,
|
||||
issue_token,
|
||||
cookie,
|
||||
api_key)
|
||||
# log into dropcam
|
||||
self._session.post(
|
||||
f"{API_URL}/dropcam/api/login",
|
||||
|
@ -7,7 +7,7 @@ from homeassistant.components.camera import Camera, SUPPORT_ON_OFF
|
||||
|
||||
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD
|
||||
from .api import NestCameraAPI
|
||||
from .const import DOMAIN
|
||||
from .const import DOMAIN, CONF_ISSUE_TOKEN, CONF_COOKIE, CONF_APIKEY
|
||||
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
@ -25,7 +25,10 @@ async def async_setup_platform(hass,
|
||||
|
||||
api = NestCameraAPI(
|
||||
hass.data[DOMAIN][CONF_EMAIL],
|
||||
hass.data[DOMAIN][CONF_PASSWORD]
|
||||
hass.data[DOMAIN][CONF_PASSWORD],
|
||||
hass.data[DOMAIN][CONF_ISSUE_TOKEN],
|
||||
hass.data[DOMAIN][CONF_COOKIE],
|
||||
hass.data[DOMAIN][CONF_APIKEY]
|
||||
)
|
||||
|
||||
# cameras = await hass.async_add_executor_job(nest.get_cameras())
|
||||
|
@ -29,7 +29,7 @@ from homeassistant.const import (
|
||||
)
|
||||
|
||||
from .api import NestThermostatAPI
|
||||
from .const import DOMAIN
|
||||
from .const import DOMAIN, CONF_ISSUE_TOKEN, CONF_COOKIE, CONF_APIKEY
|
||||
|
||||
NEST_MODE_HEAT_COOL = "range"
|
||||
NEST_MODE_ECO = "eco"
|
||||
@ -64,7 +64,10 @@ async def async_setup_platform(hass,
|
||||
"""Set up the Nest climate device."""
|
||||
nest = NestThermostatAPI(
|
||||
hass.data[DOMAIN][CONF_EMAIL],
|
||||
hass.data[DOMAIN][CONF_PASSWORD]
|
||||
hass.data[DOMAIN][CONF_PASSWORD],
|
||||
hass.data[DOMAIN][CONF_ISSUE_TOKEN],
|
||||
hass.data[DOMAIN][CONF_COOKIE],
|
||||
hass.data[DOMAIN][CONF_APIKEY]
|
||||
)
|
||||
|
||||
async_add_entities([NestClimate(nest)])
|
||||
|
@ -1 +1,4 @@
|
||||
DOMAIN = 'badnest'
|
||||
CONF_ISSUE_TOKEN = 'issue_token'
|
||||
CONF_COOKIE = 'cookie'
|
||||
CONF_APIKEY = 'api_key'
|
||||
|
37
info.md
37
info.md
@ -13,20 +13,53 @@ This isn't an advertised or public API, it's still better than web scraping, but
|
||||
- Tested with a single thermostat, I have no other devices to test with
|
||||
- Camera integration is untested by me
|
||||
- Nest could change their webapp api at any time, making this defunct
|
||||
- Won't work with Google-linked accounts
|
||||
- Presets don't work (Eco, Away)
|
||||
|
||||
## Example configuration.yaml
|
||||
## Example configuration.yaml - When you're not using the Google Auth Login
|
||||
|
||||
```yaml
|
||||
badnest:
|
||||
email: email@domain.com
|
||||
password: !secret nest_password
|
||||
|
||||
climate:
|
||||
- platform: badnest
|
||||
scan_interval: 10
|
||||
|
||||
camera:
|
||||
- platform: badnest
|
||||
```
|
||||
|
||||
## Example configuration.yaml - When you are using the Google Auth Login
|
||||
|
||||
```yaml
|
||||
badnest:
|
||||
issue_token: "https://accounts.google.com/o/oauth2/iframerpc....."
|
||||
cookie: "OCAK=......"
|
||||
api_key : "#YOURAPIKEYHERE#"
|
||||
|
||||
climate:
|
||||
- platform: badnest
|
||||
scan_interval: 10
|
||||
|
||||
camera:
|
||||
- platform: badnest
|
||||
```
|
||||
|
||||
Google Login support added with many thanks to: chrisjshull from <https://github.com/chrisjshull/homebridge-nest/>
|
||||
|
||||
The values of `"issue_token"`, `"cookie"` and `"api_key"` are specific to your Google Account. To get them, follow these steps (only needs to be done once, as long as you stay logged into your Google Account).
|
||||
|
||||
1. Open a Chrome browser tab in Incognito Mode (or clear your cache).
|
||||
2. Open Developer Tools (View/Developer/Developer Tools).
|
||||
3. Click on 'Network' tab. Make sure 'Preserve Log' is checked.
|
||||
4. In the 'Filter' box, enter `issueToken`
|
||||
5. Go to `home.nest.com`, and click 'Sign in with Google'. Log into your account.
|
||||
6. One network call (beginning with `iframerpc`) will appear in the Dev Tools window. Click on it.
|
||||
7. In the Headers tab, under General, copy the entire `Request URL` (beginning with `https://accounts.google.com`, ending with `nest.com`). This is your `"issue_token"` in `configuration.yaml`.
|
||||
8. In the 'Filter' box, enter `oauth2/iframe`
|
||||
9. Several network calls will appear in the Dev Tools window. Click on the last `iframe` call.
|
||||
10. In the Headers tab, under Request Headers, copy the entire `cookie` (beginning `OCAK=...` - **include the whole string which is several lines long and has many field/value pairs** - do not include the `cookie:` name). This is your `"cookie"` in `configuration.yaml`.
|
||||
11. In the 'Filter' box, enter `issue_jwt`
|
||||
12. Click on the last `issue_jwt` call.
|
||||
13. In the Headers tab, under Request Headers, copy the entire `x-goog-api-key` (do not include the `x-goog-api-key:` name). This is your `"api_key"` in `configuration.yaml`.
|
||||
|
Loading…
x
Reference in New Issue
Block a user