I've been meaning to add the possibility to control the AC in my car from Google Home for a while but never got around to it. A few nights ago a finally set to action.
Google Home is basically Google's take on the smart home. It is an ecosystem of things. The google home smart speaker is integrated with the google home app which is integrated with the google voice assistant, etc. etc.. In the Google Home app, you can setup devices you have around the house that are compatible, such as lights, power outlets, thermostats, etc. Once they are setup in the app, you can control them using google assistant or google home smart speakers. So, if I want to turn to be able to turn on the AC in my car by saying "Ok Google, turn on car AC", I must make sure I can have a device in google home with the name "car AC" and when I issue the command "turn on", it will send a signal to my car to turn the AC on. To do that I started looking at Actions on Google.
(Do I really need to build something for this? No, there are a couple of actions on google integrations already that you can simply add. However, when you do, you basically give away all control of your car to a third party. With this control and physical access to the car, you can essentially walk up to the car, unlock it, and drive away. Now, I'm not too paranoid about this, even though I probably should be. But, in this case, instead of giving someone the chance to drive away with my car, I much rather learn how to build this myself. After all, it's really quite easy.)
Actions on Google allow you to "integrate with google assistant". This currently means that you can extend your mobile apps to work with the voice assistant, to create conversational apps (basically apps that you use through voice/text... yes, chat bots), or connect to smart devices (i.e. google home). For my purposes, I do not want to create a conversational app. If I did, I would have to say things like "Ok google, talk to my car. -Ok, talking to your car. -Hi I'm your car what can i do for you? -Turn on AC. -Ok, AC turning on". Zzz. I much rather just open the app on my phone and press the climate button. So, instead I went for smart device integration.
Actions on Google for smart home devices is really quite simple. You need an Oauth server that can issue a token, and an https endpoint that respond to commands issued by the google assistant. We are simply building a service that acts as a server for a particular device type. There are only four commands possible: Sync, Query, Execute, and Disconnect. WIth an access token received from your Oauth server, the Sync command should respond with a list of devices that this user possesses. Query should respond with the state of the queried devices. Execute should abide to whatever the particular command is (e.g. TurnOn should turn on the device), and Disconnect should do what ever needs to be done whenever the user unlinks their google home with your service.
So I first implemented the Oauth server. There are essentially two routes required: auth and token. The auth route should let a user authorize themselves and tell Google that it is ok for your service to share access to their devices. The server responds to google through a redirect route including an authorization code. The token route should take an authorization code and return an access token (as well as a refresh token that can be used to refresh the access token). For more information go here.
In my case I let a user authenticate with their tesla account, and use their access token as the access token (together with some other stuff). This means I never have to bother storing any information on my server, but let Google store that in the token instead.
Next, the action route. Google issues POST requests to the route with access token in an Authorization header. The post data is JSON and includes a requestId and a list of intents. The intent specifies if it is Sync, Query, Execute or Disconnect.
Sync does not send any additional data, but simply expects to have the devices associated with the user returned. For this, I lookup the devices associated with the tesla account (as given by the access token) and return the device data mapped to data expected by Google, including an id that can be used to identify the device when issuing commands to the Tesla API in the future. For each device Google also expects the type of device, and its traits. The device type is not really important as far as i can tell although it will dictate what it looks like in the Google Home app. But the traits specify what commands can be sent by google assistant. In my case I want to be able to the the heat on or off, so I picked the device type action.devices.types.HEATER (CAR doesn't exist as a type), and the trait is actions.devices.traits.OnOff.
For Query, Google sends a list of devices it wants the status of. Here I simply iterate through the list, and fetch the status of the climate of each device. (The Tesla API has four distinct states fetched through four different routes: climate, drive, vehicle, and charge.) With a device trait of OnOff, Google expects a state named on to be true or false. I set it to true of the climate is on.
Finally, (I don't bother with Disconnect as there is nothing to do), I implement Execute. Execute is a bit of a handful as it will send a list of commands as a set of devices and executions. Here I cheat majorly and assume there will be only one command, with one device, and one execution. The execution of action.devices.commands.OnOff carries a parameter of on that is set to on when the command is to turn the device on. Depending on this value I either turn the climate on or off through the Tesla API. Finally, Google expects you to respond with the final status of the commands for each device.
Finally, when setting up the Action on the Actions on Google Console, you simply add the auth and token routes for your Oauth server, and the action route for your Action. When complete, hitting test will set the action up for you to use through your own google assistant only.
All in all, there are a few concepts required to learn around Actions on Google, but once you understand those, enabling you to control something through google assistant is really as simple as writing a small rest API. Next I might add more capabilities, such as adding both the car heater, and the car charger, so that I can start or stop charging at home. I might also add the capability to set the temperature I want in my car, although I very rarely change this so it's very far down my todo list.