Package: python-google-nest
Python API and command line tool for the Nest™ ThermostatNOTE: This library support the new (post 2020) API provided by Google which replaced the original Nest Developers API.For a write up on developing this library see:https://www.robopenguins.com/nest/InstallationThis library does not support Python2[sudo]pipinstallpython-google-nestIn addition to the Python library it also adds a CLI toolnestthat is documentedbelowGoogle Device Access RegistrationThis is a fairly onerous process, so make sure to read the details before you begin.The biggest roadblock is that access to this API requires registering with Google for Device Accesshttps://developers.google.com/nest/device-access/registration. This has a one time $5 fee.The documentationhttps://developers.google.com/nest/device-access/get-startedwalks you through the rest of the process.At a high level it involves:Making sure your Nest devices are linked to your Google accountSet up GCP (Google Cloud Platform) accounthttps://console.cloud.google.com/Set up a new GCP projectCreate a Oauth landing page and add your email as a test userEnable the Smart device management APICreate an Oauth credential with the settings called from web server andhttps://www.google.comas the authorized redirect URI. Note the client ID and secret from this step.Inhttps://console.nest.google.com/device-accesscreate a new project and add oauth client ID from step 3.3Follow the series of queries inhttps://developers.google.com/nest/device-access/authorizeto authorize devices.NoteThis step handled by this library.Be careful as you follow along the guide inhttps://developers.google.com/nest/device-access/get-started, since you're dealing with so many similar accounts and keys it can be easy to mix something up and you won't get particularly useful errors.You should end up with the following pieces of information:project_id - ID of the project you created inhttps://console.nest.google.com/device-accessclient_id - value from setting up OAuth inhttps://console.cloud.google.com/projectclient_secret - value from setting up OAuth inhttps://console.cloud.google.com/projectyou will need those values to use this library.AuthenticationThis library uses those values to authenticate itself using refresh token grants. Seehttps://docs.wso2.com/display/IS530/Refresh+Token+GrantThe first time you use this library you'll need to follow a URL the library generates tohttps://nestservices.google.com/partnerconnectionsand authenticate your devices with your Google account. When you finish this process your browser will have a URL that looks likehttps://www.google.com/?state=SOME_STATE_VALUE&code=SOME_AUTHENTICATION_CODE&scope=https://www.googleapis.com/auth/sdm.servicethat you need to copy and paste into the callback.This will be cached and for however long the token is valid the library will keep refreshing the token cache. Eventually you'll be prompted to reauthenticate.UsageAt a high level this library is used to get references to the devices included in the account. These references can be sent commands, and have a list of "traits". Seehttps://developers.google.com/nest/device-access/traitsfor details on these traits and commands.See docstring comments inhttps://github.com/axlan/python-nest/blob/master/nest/nest.pyfor details on the usage of this library.Example:# reautherize_callback should be set to a function with the signature# Callable[[str], str]] it will be called if the user needs to reautherize# the OAuth tokens. It will be passed the URL to go to, and need to have# the resulting URL after authentication returned.withnest.Nest(client_id,client_secret,project_id,access_token_cache_file=access_token_cache_file,reautherize_callback=reautherize_callback,cache_period=cache_period)asnapi:# Will trigger initial auth and fetch of datadevices=napi.get_devices(args.name,args.structure)# For a list of traits and commands see:# https://developers.google.com/nest/device-access/traitsifcmd=='show_trait':# will reuse the cached result unless cache_period has elapseddevices=nest.Device.filter_for_trait(devices,args.trait_name)# will reuse the cached result unless cache_period has elapsedprint(devices[args.index].traits[args.trait_name])elifcmd=='cmd':# will reuse the cached result unless cache_period has elapseddevices=nest.Device.filter_for_cmd(devices,args.cmd_name)# will trigger a request to POST the cmdprint(devices[args.index].send_cmd(args.cmd_name,json.loads(args.cmd_params)))elifcmd=='show':try:whileTrue:fordeviceindevices:# will reuse the cached result and trigger a new request# each time the cache_period elapsesprint(device)print('=========================================')ifnotargs.keep_alive:breaktime.sleep(2)exceptKeyboardInterrupt:returnCommand Lineusage:nest[-h][--confFILE][--token-cacheTOKEN_CACHE_FILE][-tTOKEN][--client-idID][--client-secretSECRET][--project-idPROJECT][-k][-nNAME][-SSTRUCTURE][-iINDEX][-v]{show_trait,cmd,show}...

CommandlineinterfacetoNest™Thermostats

positionalarguments:{show_trait,cmd,show}commandhelpshow_traitshowatraitcmdsendacmdshowshoweverything

optionalarguments:-h,--helpshowthishelpmessageandexit--confFILEconfigfile(default~/.config/nest/config)--token-cacheTOKEN_CACHE_FILEauthaccesstokencachefile-tTOKEN,--tokenTOKENauthaccesstoken--client-idIDproductidondeveloper.nest.com--client-secretSECRETproductsecretfornest.com--project-idPROJECTdeviceaccessprojectid-k,--keep-alivekeepshowingupdatereceivedfromstreamAPIinshowandcamera-showcommands-nNAME,--nameNAMEoptional,specifynameofnestthermostattotalkto-SSTRUCTURE,--structureSTRUCTUREoptional,specifystructurenametoscopedeviceactions-iINDEX,--indexINDEXoptional,specifyindexnumberofnesttotalkto-v,--verboseshowingverboseloggingexamples:# Show all of your devices$nest--confmyconfigshow
name:AVPHwEvCbK85AJxEDHLe91Uf73nesTCg9RyUKBq2r5G2bDnKd_6OoVek1n8JtM4WlGoqsJpCBQkl9ny4oPkTiLith-XSLQwhere:Downstairs-THERMOSTAT(<Info:{'customName':''}>,<Humidity:{'ambientHumidityPercent':45}>,<Connectivity:{'status':'ONLINE'}>,<Fan:{}>,<ThermostatMode:{'mode':'HEAT','availableModes':['HEAT','OFF']}>,<ThermostatEco:{'availableModes':['OFF','MANUAL_ECO'],'mode':'OFF','heatCelsius':4.4444427,'coolCelsius':24.444443}>,<ThermostatHvac:{'status':'OFF'}>,<Settings:{'temperatureScale':'CELSIUS'}>,<ThermostatTemperatureSetpoint:{'heatCelsius':20.44426}>,<Temperature:{'ambientTemperatureCelsius':22.75}>)name:AVPHwEteWa8QXa8PQ7MMzh2CtnzgDPcQCfggZquzPyF__9wUCU7gp0EhO4-_17JiB4WlNupsP3dL28TJmA9-GknM6voZPwwhere:Upstairs-THERMOSTAT(<Info:{'customName':''}>,<Humidity:{'ambientHumidityPercent':44}>,<Connectivity:{'status':'ONLINE'}>,<Fan:{}>,<ThermostatMode:{'mode':'HEAT','availableModes':['HEAT','OFF']}>,<ThermostatEco:{'availableModes':['OFF','MANUAL_ECO'],'mode':'OFF','heatCelsius':4.4444427,'coolCelsius':24.444443}>,<ThermostatHvac:{'status':'OFF'}>,<Settings:{'temperatureScale':'CELSIUS'}>,<ThermostatTemperatureSetpoint:{'heatCelsius':20.44426}>,<Temperature:{'ambientTemperatureCelsius':24.809998}>)name:AVPHwEsz8-DzdIJjNkb7iY5A5HPla6UEy7azMVyXlerdgrcuabbuLMyvlGjMLWdmqtydqtXHWfx7GHmHMaVKSDysceL4XAwhere:Downstairs-DOORBELL(<Info:{'customName':''}>,<CameraLiveStream:{'maxVideoResolution':{'width':640,'height':480},'videoCodecs':['H264'],'audioCodecs':['AAC']}>,<CameraImage:{'maxImageResolution':{'width':1920,'height':1200}}>,<CameraPerson:{}>,<CameraSound:{}>,<CameraMotion:{}>,<CameraEventImage:{}>)=========================================# add the --keep-alive to update the results every 2 seconds until killed with keyboard interrupt# Show all of your devices in the "Upstairs" structure$nest--confmyconfig-SUpstairsshow
name:AVPHwEteWa8QXa8PQ7MMzh2CtnzgDPcQCfggZquzPyF__9wUCU7gp0EhO4-_17JiB4WlNupsP3dL28TJmA9-GknM6voZPwwhere:Upstairs-THERMOSTAT(<Info:{'customName':''}>,<Humidity:{'ambientHumidityPercent':44}>,<Connectivity:{'status':'ONLINE'}>,<Fan:{}>,<ThermostatMode:{'mode':'HEAT','availableModes':['HEAT','OFF']}>,<ThermostatEco:{'availableModes':['OFF','MANUAL_ECO'],'mode':'OFF','heatCelsius':4.4444427,'coolCelsius':24.444443}>,<ThermostatHvac:{'status':'OFF'}>,<Settings:{'temperatureScale':'CELSIUS'}>,<ThermostatTemperatureSetpoint:{'heatCelsius':20.44426}>,<Temperature:{'ambientTemperatureCelsius':24.809998}>)=========================================# Show the device with the matching name$nest--confmyconfig-nAVPHwEsz8-DzdIJjNkb7iY5A5HPla6UEy7azMVyXlerdgrcuabbuLMyvlGjMLWdmqtydqtXHWfx7GHmHMaVKSDysceL4XAshow
name:AVPHwEsz8-DzdIJjNkb7iY5A5HPla6UEy7azMVyXlerdgrcuabbuLMyvlGjMLWdmqtydqtXHWfx7GHmHMaVKSDysceL4XAwhere:Downstairs-DOORBELL(<Info:{'customName':''}>,<CameraLiveStream:{'maxVideoResolution':{'width':640,'height':480},'videoCodecs':['H264'],'audioCodecs':['AAC']}>,<CameraImage:{'maxImageResolution':{'width':1920,'height':1200}}>,<CameraPerson:{}>,<CameraSound:{}>,<CameraMotion:{}>,<CameraEventImage:{}>)=========================================# Show the CameraImage trait of a device$nest--confmyconfigshow_traitCameraImage{'maxImageResolution':{'width':1920,'height':1200}}# Set the ThermostatMode to "HEAT"$nest--confmyconfigcmdThermostatMode.SetMode'{"mode":"HEAT"}'{}A configuration file may be specified and used for the credentials to communicate with the NEST Thermostat.[NEST]client_id=your_client_idclient_secret=your_client_secretproject_id=your_project_idtoken_cache=~/.config/nest/token_cacheThe[NEST]section may also be named[nest]for convenience. Do not use[DEFAULT]as it cannot be readUnimplemented FeaturesThere are two main parts of this API that are not implemented.This library does not handle the Device Access event Pub/Sub systemhttps://developers.google.com/nest/device-access/subscribe-to-events. Using these would avoid needing to poll the API.This library does not currently handle getting video/images from the cameras. This should be possible to implement on top of this library, but would require setting up a RTSP client, or the logic to follow the links in the camera events.Google provides libraries to discover the details of an API and generate codehttps://developers.google.com/nest/device-access/reference/rest. I took a look at this process, and it didn't seem like it wouldn't make a good fit for a simple library like this.HistoryThis module is a fork ofpython-nestwhich was a fork ofnest_thermostatwhich was a fork ofpynest