Google Home Message Broadcast System [Node.js]
A simple tutorial on how broadcast any message or text to Google Home mini using NodeJS
Introduction
If you are a tech nerd like me, you just have collected random devices as you go on walking through life. One of my favorites is called a Google Home Mini. I got these bad boys at BestBuy for around $35 during black Friday and have one set up in 3 different rooms.
The best part of this is that I can set timers, reminders, or ask what the weather is when I'm to lazy to check. With my house slowly moving towards home customization, one of the features I wanted was a household notification system. Turns out I have a Google Home Mini that can do just that... broadcast a custom message.
Demo
Prerequisites
- Node.js
- castv2-client
- google-tts-api
- Google Home/Google Home Mini
- Static IP assigned to each given device
Step 1: Installing & setup of project
This one should be a breeze. If you are using straight up command line use NPM to install the packages. I currently use WebStorm IDE from JetBrains however to write all my Node.JS code but all of this tutorial will be done assuming you use good old fashioned notepad.exe (plz don't actually)
Create a new directory in your file system and open up your command line/terminal then run the following commands.
cd /path/to/directory
npm init
npm install castv2-client
npm install google-tts-api
The above commands will a new project with the installed libraries that you will need. Once your project has been initialized create a JS file in that directory and open it, you can name it whatever you'd like but I named mine GoogleHomeBroadcaster.js
Step 2: Writing the code
Full Code (CLICK ME)
var Client = require('castv2-client').Client;
var DefaultMediaReceiver = require('castv2-client').DefaultMediaReceiver;
const googleTTS = require('google-tts-api');
var App = {
playin: false,
DeviceIp: "",
Player: null,
GoogleHome: function (host, url) {
var client = new Client();
client.connect(host, function () {
client.launch(DefaultMediaReceiver, function (err, player) {
client.setVolume({ level: 1 }, function(err, volume) {
if (err) {
console.log('Error on setVolume:', err);
} else {
console.log('Volume set to ' + volume)
}
});
var media = {
contentId: url,
contentType: 'audio/mp3',
streamType: 'BUFFERED'
};
App.Player = player;
App.Player.load(media, { autoplay: true }, function (err, status) {
App.Player.on('status', function (status) {
if (status.playerState === "IDLE" && App.playin === false) {
client.close();
}
});
});
});
});
client.on('error', function (err) {
console.log('Error: %s', err.message);
client.close();
});
},
run: function (ip, text) {
App.DeviceIp = ip;
const url = googleTTS.getAudioUrl(text, {
lang: 'en-US',
slow: false,
host: 'https://translate.google.com',
});
App.GoogleHome(App.DeviceIp, url, function (res) {
console.log(res);
})
},
broadcast: function(text){
//From config, 192.168.68.105,192.168.68.107,192.168.68.124
const ips = process.env.GOOGLEHOME_IPS.split(",");
for (var s of ips){
App.run(s, text);
}
}
};
App.run("192.168.68.124", "Test message sent to one device");
//Only works if you did step 4.5
//App.broadcast("Broadcasted to all of the devices");
client.setVolume({ level: 1 }, function(err, volume) {
if (err) {
// Handle error as appropriate
console.log('Error on setVolume:', err);
} else {
console.log('Volume:', volume)
}
});
Explanation of Full Code (CLICK ME)
var Client = require('castv2-client').Client;
var DefaultMediaReceiver = require('castv2-client').DefaultMediaReceiver;
const googleTTS = require('google-tts-api');
- castv2-client
- A Chromecast client based on the new (CASTV2) protocol. This is how we communicate to our Google Home/Google Home Mini.
- google-tts-api
- An API from google that converts our plaintext string into a mp3 file that gets played on our Google Home/Google Home Mini
- Client
- This is our object that allows us to control our Google Home, it references the speaker itself and allows us to alter it like change the volume on it.
- DefaultMediaReceiver
- This is the default client provided by the Google API. Handles basic audio streaming. You can read more about the DefaultMediaReciever and how to create your own at the above link
var App = {
playin: false,
DeviceIp: "",
Player: null,
GoogleHome: function (host, url) {
var client = new Client();
client.connect(host, function () {
client.launch(DefaultMediaReceiver, function (err, player) {
client.setVolume({ level: 1 });
var media = {
contentId: url,
contentType: 'audio/mp3',
streamType: 'BUFFERED'
};
App.Player = player;
App.Player.load(media, { autoplay: true }, function (err, status) {
App.Player.on('status', function (status) {
if (status.playerState === "IDLE" && App.playin === false) {
client.close();
}
});
});
});
});
client.on('error', function (err) {
console.log('Error: %s', err.message);
client.close();
});
},
This is our initial skeleton for our App object. The main section to look at is the GoogleHome function, which takes a "host" parameter (our google home static IP) and a "url" parameter which is our Google TTS service.
We then connect to the client and launch the "DefaultMediaReciever" which will notify the GoogleHome that we are going to be sending some media to be played.
We set the volume to the highest level, goes from 0F - 1F (think percentages so .6 would be 60% volume).
After that we construct our media object, this lets the google home know that it is going to be an audio/mp3 file that is coming from an URL (the google tts url)
We then load it nto the player (set auto play to true so it broadcasts as soon as it loads) and when the status of the player goes to "IDLE" it means the media is done playing so we can then close it.
I just dumped any errors that occured to console, but if you have any other error handling logic add it there.
run: function (ip, text) {
App.DeviceIp = ip;
const url = googleTTS.getAudioUrl(text, {
lang: 'en-US',
slow: false,
host: 'https://translate.google.com',
});
App.GoogleHome(App.DeviceIp, url, function (res) {
console.log(res);
})
},
This next section is our entry point to each individual google home mini. The "ip" parameter is the numerical IP for our GoogleHome and the "text" parameter is the text you want to get broadcasted.
The googleTTS.getAudioUrl() is a wrapper around Google's TTS service, you can always construct the link yourself but I find it easier to just use a library which abstracts a lot of it out. The value of "url" after the library will be something like
https://translate.google.com/translate_tts?ie=UTF-8&q=Hello+this+is+a+test+message+to+see+if+TTS+works&tl=en&total=1&idx=0&textlen=48&client=tw-ob&prev=input&ttspeed=1
We then call our GoogleHome function defined in the above section with our parameters and it should call it and run.
broadcast: function(text){
//From config, 192.168.68.105,192.168.68.107,192.168.68.124
const ips = process.env.GOOGLEHOME_IPS.split(",");
for (var s of ips){
App.run(s, text);
}
}
};
This last section is how we broadcast it to multiple devices at once. A simple for loop that iterates over each IP of each of the Google Home Mini and then broadcasts it to them
App.run("192.168.68.124", "Test message sent to one device");
This is the entry point to the application, you can abstract the two parameters to console or some other variable that you have defined to change the target and parameters.
Step 3: Conclusion
Overall this is a simple solution to having information broadcasted to your home.
The reason I went down this route to implement, was I upgraded the doorbell in my house to a Ring doorbell, and unfortunately the indoor doorbell system wouldn't interface with it correct (it is really old and finnicky) so I needed a way to let the house know someone was outsite.
Henceforth the broadcast system using my Google Home Minis, the best part is that since it can take any text, I change it up for each month, during February I'll have it saying Cupid is here to drop off some love, go say hi or during the Christmas season I'll have it saying Santa is at the door, go check it out before he flies away.
This is a nice way for me to add some variety in the everyday dull life of doorbells.
P.S. It's really easy to get this working with music as well (think any .mp3 file with an URL) so changing doorbell rings to be music is really easy!