For a lesson in creating node.js projects in Docker, read on. If you want a quick and easy way to implement Assistant-Relay, skip to the Docker-Hub section.
I want to setup Assistant Relay in my home automation system so that I can send commands to Google Assistant without having to say something. This opens the door to some automation that Google hasn’t put in public APIs for some reason, like turning off TVs that have a Chromecast hooked up.
Unfortunately Assistant Relay doesn’t have Docker install instructions, only instructions on how to set it up from scratch as a Node.js app. Rather than spin up a VM just for this one app, I’m going to try to create my own docker install instructions, which hopefully will result in having an image posted on Docker-Hub, but I’m not entirely sure what that would involve yet.
To test this out, I’ll be developing the Docker image on my laptop running Linux Mint, but the end goal is to deploy it to my Unraid server.
I have never worked with nodejs, so this is all very new to me, luckily I found some instructions on Dockerizing Node.js apps here which seems like a good place to start.
Demo App
Since I have no idea what I’m doing, I’m going to start by actually just following that demo linked above.
This basically means creating the following structure with the content from the instructions:
- nodejs-test (folder)
- Dockerfile
- package.json
- server.js
The instructions say to run the command:
npm install
This creates a node-modules folder with a bunch of stuff in it and also creates a package-lock.json file. This is apparently to speed up deployment of containers, since if nothing has changed, the command doesn’t need to download anything since it’ll already be there. But if something has changed, then it pulls the differences. I’m not entirely sure I follow it, but I’ll keep it in mind. If you don’t have npm installed on the PC you’re doing this on, it’s totally fair to skip it.
And then building the image:
sudo docker build -t nodejs-test-app .
This basically just walks through the Dockerfile and completes each step. Once it’s done, I can run the app:
docker run -p 49160:8080 -d test-nodejs-app
I can now go to my web browser and type in:
localhost:49160
I am greeted with a Hell World. This is expected since that’s all we told it to run in the server.js file:
// App
const app = express();
app.get('/', (req, res) => {
res.send('Hello world\n');
});
Cool! So that’s all it takes to Dockerize a fake app, how hard could this be? 🙂
Assistant Relay
So looking at the install instructions on the Github page, I need to download the release version, not clone the actual repo. I downloaded the release version for v3.1.3 and unzipped it to the folder called “assistant-relay”.
Before I do anything else, I think I’ll follow the example and run the “npm install” command to get the heavy lifting out of the way so that it doesn’t have to happen in the docker container.
Now I’ll create the Dockerfile within that folder and base it on the example from above with a few changes:
- Added the dependency from the GitHub page (npm – pm2 -g)
- Changed the port from 8080 to 3000
- I know this because I skipped ahead to where we run the start up wizard and it tells you to visit port 3000 to continue
- Added a line for Entrypoint
- This runs the given command when the container first starts. The commend comes from the Github page for how to start the the app.
- Changed the last line reference from server.js to app.js
FROM node:10
# Create app directory
WORKDIR /usr/src/app
# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm@5+)
COPY package*.json ./
RUN npm i pm2 -g
RUN npm install
# If you are building your code for production
# RUN npm ci --only=production
# Bundle app source
COPY . .
EXPOSE 3000
ENTRYPOINT npm run start
CMD [ "node", "app.js" ]
Now I can build the image and run it. I did add a name so that when I need to delete it I know what name to delete rather than letting Docker randomly assigning something. I also matched the internal and external ports for simplicity.
docker build -t assistant-relay .
docker run -p 3000:3000 -d --name assistant-relay assistant-relay
At this point, we should have a running docker container, you can test that by running “docker ps” which should show you the details about the containers that are running. You should now be able to go to port 3000 to see the start up wizard.
There isn’t really a point in going through the rest of the configuration if it isn’t going to stay on this hardware. But I didn’t know that it was going to work at this stage, so I did go through with the rest of the process. If anyone else, or future me is following this, now would be the time to skip to the next section.
This is documented really well, so I won’t get into the specifics here, but once it’s done and assuming you have a Google Home near by, you should be greeted with a notification that it was successfully connected to Assistant Relay. There is also a sandbox tab where you can test that it’s actually working. I can turn off my TV and broadcast messages across the house. Very cool!
Docker-Hub
I signed up for a Docker-Hub account and as I was walking through how to publish a Dockerfile… I for some reason thought to do a search for “assistant-relay”. And would you look at that, there are already several other Docker-Hub images for this. There’s even one that you can install from Hass.io, which is incredibly convenient. I swear I searched up and down for ANYONE that had done this before, and I came up empty. Apparently my search didn’t include Docker-Hub. Eff.
Home Assistant
Once you install Assistant-Relay via Hass.io, you still need to integrate it into HA. Turns out the creator of the Hass.io Assistant-Relay Docker-Hub file also included a really great example. Add the following to your config file and you can issues commands from the Developer Tools/Services tab.
# Example configuration.yaml
rest_command:
assistant_broadcast:
url: http://192.168.10.2:3000/assistant
method: POST
content_type: 'application/json'
payload: '{"command":"{{ command }}", "user":"username", "broadcast":true}'
assistant_converse:
url: http://192.168.10.2:3000/assistant
method: POST
content_type: 'application/json'
payload: '{"command":"{{ command }}", "user":"username", "converse":true}'
assistant_relay:
url: http://192.168.10.2:3000/assistant
method: POST
content_type: 'application/json'
payload: '{"command":"{{ command }}", "user":"username"}'
The only thing you have to do is update “username” to be “<your name>”. The “{{ command }}” section is a template so that you can reuse this for a bunch of things without re-writing a bunch of code.
As a quick test, I added a manual lovelace card based on another example provided.
type: entities
entities:
- action_name: Turn Off
name: Livingroom TV
service: rest_command.assistant_relay
type: call-service
service_data:
command: Turn off livingroom TV
Summary
In the end, I learned some stuff about node.js and Docker that I didn’t know before and I got what I wanted in the first place, so I’m going to call it a win. The Assistant-Relay opens a lot of possibilities that should be available by default, serious props to the create of the tool as well as the creator of the Hass.io Add-on.
Greg