Using voice to control a website with Google Home, part 2/3
Setting up the database and connecting our Google Action
Update 01.01.2020
This tutorial was written in 2017, and it is now outdated. Thank you for all the kind feedback and suggestions. If you finished the tutorial, congratulations! :)
In the previous chapter we created a simple Google Action that allows us to speak a number to the Google Home and have the device repeat the number back to us. In this chapter we will set up the database we will use to store and later retrieve the command we spoke to Google Home. We will also expand our Action so that the number is stored in the database. To do that we will add some Node.js code to the Action.
This is part 2 out of 3 articles in this tutorial:
Part 1: Introduction, prerequisites, and building the Google Action
Part 2: Setting up the database and connecting our Google Action
Part 3: Creating the website and extending our Action to display all images
We’re currently on stage 2 in the flow diagram:
Setting up the database on Firebase
Before we can connect our Action to the database, we need to create the database. For this prototype we will use Google’s Firebase Realtime Database. There are plenty of other databases and storage services available both on Google Firebase and Google Cloud, and you’re free to use whichever one you’re comfortable with, but here we will focus on the Firebase Realtime Database because it is easy to set up and access for the purpose of this specific solution.
To set up the database, open a new browser tab and navigate to console.firebase.google.com. In chapter 1 you were instructed to sign up for Firebase. If you haven’t already done so, please sign up for Firebase before continuing.
Once signed in, you will see the landing page for Firebase. From this page, locate your Dog Pictures project, it is probably located under ‘Other projects using Firebase’.
Click on the card that says Dog Pictures, and you will be taken to the project homepage on Firebase.
Firebase is a mobile and web application development platform with a lot of powerful tools and features. Here we will only take advantage of the Realtime Database. This is the database we will use to store the number that you spoke to Google Home.
Click on the Database option in the menu to the left, this will take you to the database screen.
On the next screen, click on the ‘Get Started’ button on the card for Realtime Database. If you feel adventurous you can try Cloud Firestore instead, but this tutorial will not cover Cloud Firestore.
After selecting Realtime Database, you’re presented with the UI that lets you set up the database for our project.
In this example, the database is called dog-pictures-2d717, the name of your database will be slightly different. We now need to create the fields that we want our Google Action to update. To do that we click the ‘+’ sign to the right of dog-pictures-2d717:[null].
This gives you the ability to add a property with a corresponding value to the database, like this:
In the ‘name’ field type ‘picture’, don’t type anything in the ‘value’ field, but hit the ‘+’ to the right of the value field.
This adds a child node to the picture node in our database, like this:
In this child node, type number for Name, and put 0 (the number zero) as value, and then hit the ‘Add’ button. It should look like this:
After hitting ‘Add’, your database structure should look like this:
Every time we ask for a new number, we want the value of ‘number’ in our database to change accordingly. When we say ‘Show number 5’, the database should update to the number 5.
You may have noticed the following message in the database window:
We’re now going to do something that would be bad in a production environment, but ok for this prototype. In order to get this to work with minimal configuration, we’re going to disable security so that anyone has read and write privileges to the database without authentication. When we do that, we will be able to update the database from Google Home, and read the database contents from our webpage, without having to worry about authentication. This greatly simplifies setting up the prototype.
I do not recommend this approach for a live production environment. By doing this you run the risk that anyone can put stuff in your database if they have the URL for it. So after you’re happy with your prototype you should take every measure possible to secure it. This approach is only ok for a prototype.
To disable authentication, go to the RULES tab of your database:
To change security to require no authentication, all you have to is edit the read and write rules so that it looks like this:
{
"rules": {
".read": "auth == null",
".write": "auth == null"
}
}
Notice how the rules now say ==, instead of !=, this opens up the database to anybody with the URL.
Your rules screen should now look like this:
Hit the ‘Publish’ button to publish the changes to the rules.
An easy way to check that you can now read from the database, is to open a new tab, and go to the URL of your database, and append /picture.json to the url.
You can find the URL at the top of your database screen, here:
The URL displayed here is to my project, yours will look different.
Take that URL, and append picture.json, so that it looks like this:
https://dog-pictures-2d717.firebaseio.com/picture.json
Open this URL in an anonymous tab, and you should get the contents of the database as a JSON response, like this:
{"number":0}
We will later use this feature, a built-in API that gives you the contents of the database, when we create our webpage that will show the dog pictures. We will also use this URL when we write the function that updates the database.
This concludes setting up your database, our next task is to connect our Google Action to the database so that we can update it from the Google Home.
Connecting the Google Action to the database
In order for this to work, we have to write a function in Node.js that takes the input the user gave, and stores it in the database.
Navigate back to your Dog Pictures project in Dialogflow, but keep the Realtime Database tab open, you will later check this tab to see the results of your commands.
In Dialogflow, in your Dog Pictures project, click on the Fulfillment option in the left menu, this takes you to the Fulfillment screen:
We will use the inline editor to write our function. You have to set the slider to ‘enabled’ for the inline editor, currently it is disabled. Enable it so it looks like this:
The inline editor has a lot of template code to enhance the functionality of your app and send rich responses to multiple platforms such as the Google Assistant app, Facebook, or Slack. We will leave all of the code here intact, and just add the functionality we need to connect to the database and write our number.
To start, go to the top of the index.js file, and locate this line:
and add the following code:
const requestNode = require('request');
const NUMBER_ARGUMENT = 'number';
So that it looks like this:
const requestNode uses the Node.js request http client to update our database. We will add more code for that later.
We also define a constant NUMBER_ARGUMENT that we will later use to get the number from the user’s command.
Next, locate the line that defines the processV1Request function, it looks like this:
Above this line, we will add a new function that writes to the database, we will call that function saveToDb. This is what the function looks like:
function saveToDb(numberToSave) {
const options = {
url: 'https://dog-pictures-2d717.firebaseio.com/picture.json',
method: 'PUT',
headers: {
'Content-Type': 'application/json'
},
body : JSON.stringify({
"number" : numberToSave
})
};
requestNode(options, function(error, requestInternal, body){
console.log(body);
});
}
This function takes the number from the user’s input and uses the previously declared requestNode constant to update the database using PUT.
This function needs the URL of your database. In the above example I’ve put in the URL to my test project. You need to put the URL that you tested earlier in this chapter where it says:
This part of your file should now look like this:
You may remember that we wrote an Intent called Show pictures. We now need to write code so that when this intent is being triggered, there is code in this file to support extracting the number and sending it to the saveToDb function. The intent Show pictures gets triggered every time the user says “number 34”, and similar commands.
When we defined the intent, we specified an Action for it in the Action field, it looks like this:
That’s the action we’re looking for: showPicture.
Go back to your index.js file in the inline editor, and locate the following lines:
Inside the processV1Request function, there is a constant called actionHandlers. These are the handlers that gets executed when the user triggers an Intent with an accompanying Action. You need to add code for ‘showPicture’ to the actionHandlers. You do this by adding the following code after the ‘input.welcome’ handler:
'showPicture': () => {
let number = app.getArgument(NUMBER_ARGUMENT);
if (requestSource === googleAssistantRequest) {
saveToDb(number);
sendGoogleResponse('picture ' + number); // Send simple response to user
} else {
sendResponse('picture ' + number); // Send simple response to user
}
},
The code should now look like this, don’t forget the final comma before the next declaration:
The code we just added takes the number the user said, that happens here:
let number = app.getArgument(NUMBER_ARGUMENT);
It then passes that number to the saveToDb function, and the number gets written to the database.
The function also repeats the number back to you by saying “picture {number}”. This is useful for testing, but you may have noticed in the example video that Google Home isn’t saying anything to confirm which picture I asked for. In order to achieve that you have to put an empty reply in the sendGoogleResponse() function call. I found that I need to put a space, not just two quotation marks, so the function call will look like this:
You’re now done editing the index.js file, but you need to quickly check the package.json file to see that it has all the required dependencies listed. Click on the package.json tab, and you should see something like this:
You need to make sure that “request”:”^ 2.81.0" is listed among the dependencies, this is the Node.js request http client which our project needs in order to write to the database. (the actual version number may be different). If it isn’t, you need to put it in as listed in this screenshot.
You’re now done with your function, and you can hit ‘Deploy’.
Deploying the function takes a few seconds, but eventually you will get a message saying that the function has been successfully saved and deployed.
Occasionally I’ve experienced errors deploying the function the first time I hit deploy. If that happens, hit deploy again, and if there are no errors in your code, it usually deploys on the second attempt.
If you need to view the logs for the function, you can go to the Firebase Console and choose Functions from the left menu. From there you can access the logs for your project.
You have now written a webhook that can take your intents and perform actions depending on what the user says. However, you’re not done yet, you have to go back to the intent and specify that it should use the code in the webhook when the intent is triggered. To do that, navigate back to the Show picture intent and locate the Fulfillment section:
You have to check the checkbox that says ‘use webhook’. Without this checkbox the code in your index.js file will not be executed.
After you checked the box, make sure to save your intent.
You’re now ready to test speaking to Google Home and see if the database updates. This is exciting as it marks an important step in creating this prototype. If it works you have more than 75% of the solution done.
Testing writing to the database
To test writing to the database, open a browser window that shows the contents of your database, like this:
With this window open, talk to your Google Home and start your test app. You can also use the simulator for this.
As you ask for different images, the number in the database should be updated immediately.
You should also try to access the database through the API, and see if you get the same result:
Summary and next steps
We’ve successfully set up a Google Action that lets us speak a number to the Google Home device. The number gets stored in a database, and can be retrieved by any client that can access the API of the database.
We’ve completed step 2 in our prototype:
The next step is to write the webapp that will show the pictures. We also need to extend our Google Action to handle showing all pictures, right now we can only ask for individual pictures.
Part 3: Creating the website and extending our Action to display all images