Amazon Echo - Integration to Jenkins

Problem:

So if you've ever dealt with an Amazon Echo (Alexa) you'll probably know that it's pretty awesome. There's all sorts of things you can do. As far as I could tell there are two main parts

1) Standard organisation / convenience:
Essentially you get something you can ask questions to, find information from wikipedia, play music, and just be generally entertaining. This is great, but from an engineering point of view is not particularly useful. It's simply a bit gimmicky.

2) Household Automation / IoT:
Now we're getting somewhere, the idea that you can do stuff like turn on your heating or lighting in different places of the house using Alexa! While this is great it also requires additional hardware. You need to purchase all the bits and pieces that Alexa can talk to, this is all well and good - if you can afford it.

Now as an IT engineer I wanted to go a little further. Wouldn't it be cool if you could make Alexa talk to other things, like make generic REST API calls? Or run some script that you can use to do something in your infrastructure?

Well, if you like the sound of that, continue reading!

Solution:

I already covered the deployment and configuration of Jenkins in a previous post. Now we'll integrate Alexa into Jenkins so we can create jobs which are then executed by a voice command to Alexa.

We'll need to run another piece of software in our infrastructure, called HA-Bridge. This project can be found here: https://github.com/bwssytems/ha-bridge

Naturally I run everything in a docker container, and there are a few available. I've built my own using the following:

Dockerfile:

FROM openjdk:jre-alpine

MAINTAINER Dchidell

VOLUME ["/bridge"]
COPY run.sh /tmp/run.sh

RUN apk add --no-cache curl wget

RUN chmod +x /tmp/run.sh

WORKDIR /bridge
CMD ["/tmp/run.sh"]

Run.sh script:

#!/bin/sh

#Get docker env timezone and set system timezone
echo "setting the correct local time"
echo $TZ > /etc/timezone
cd /bridge
if [ ! -z $VERSION ]; then
  echo "Manual version override:" $VERSION
else
  #Check the latest version on github
  VERSION="$(curl -sX GET https://api.github.com/repos/bwssytems/ha-bridge/releases/latest | grep 'tag_name' | cut -d\" -f4)"
  VERSION=${VERSION:1}
  echo "Latest version on bwssystems github repo is" $VERSION
fi

if [ ! -f /bridge/ha-bridge-"$VERSION".jar ]; then
  echo "Installing version '$VERSION'"
  wget https://github.com/bwssytems/ha-bridge/releases/download/v"$VERSION"/ha-bridge-"$VERSION".jar
else
  echo "Using existing version '$VERSION'"
fi
echo "Setting correct permissions"
chown -R nobody:users /bridge

#ADDPARAM="-Dupnp.config.address=$SERVERIP -Dserver.port=$SERVERPORT"
#echo -e "Parameters used:\nServer IP : $SERVERIP\nServer Port : $SERVERPORT"

echo "Starting Home Automation Bridge"
java -jar ha-bridge-"$VERSION".jar 2>&1 | tee /bridge/ha-bridge.log

Credit to the following github repo for the basics + the shell script: https://github.com/aptalca/docker-ha-bridge

I decided to make my own due to storage requirements on that particular container. Mine uses alpine as a base and doesn't install the java environment at runtime but rather pulls it from an existing container. As a result the image is drastically smaller.

Here is the docker-compose configuration I use to deploy this container:

iotbridge:
  image: iot-bridge
  build: ./iot-bridge
  restart: always
  volumes:
   - /mnt/nas/iotbridge_config:/bridge
  network_mode: host

Now one thing you may notice is that I am running it on the host network and not exposing each port. I had issues with this, mainly with the discovery process (i.e. Alexa couldn't find anything) as soon as I switched it over to the host network all problems disappeared. I did notice UPNP was running on port 50000 and 1900 UDP and tried forwarding those with no luck, it was likely due to multicast forwarding of UPNP packets, but I didn't want to go into that much detail.

I do however runs a webserver as well which listens on port 80 (which this does too), so I had to change the port number in the configuration afterwards.

After you get this running you should be able to get into the GUI and start poking with things.

The FAQ and guides on the github page explain most of what you need to know, so I won't bother going into too much detail about the every-day stuff but I'll simply highlight the challenges I faced.


Now we have a container up and running and we can access the GUI, we need to actually make this do something, so create a test job in jenkins and use the build actions section to allow HTTP GET calls to the job:

You will also want the following jenkins plugin: https://wiki.jenkins.io/display/JENKINS/Build+Token+Root+Plugin

This will allow you to call jobs without having a cookie or session authentication, and just use the Authentication Token in the above field to call the job. If you don't use this, you'll have all sorts of 403 responses coming out of the HA Bridge.

Now you can call your project in Jenkins using the following URL: http://[jenkins url]/buildByToken/build?job=[testjobname]&token=[authtoken]

You probably want to test the above in your browser first - that will confirm if it works. You'll see an instance of the Jenkins job run as a result of the test.

This URL can now be entered into a bridge device within the HA-Bridge. Fill in all the appropriate fields. The most important of these is name this is what you will refer to when talking to Alexa. You'll want to then add items into the ON / DIM or OFF fields to correspond to what you want to do.

Now best to go back and hit the test button, this should then fire off the build within jenkins. If you don't see a small pop-up in the right hand side of the HA-Bridge, there's something wrong with the configuration. Check the logs (visible from the GUI) to diagnose the problem.

If all is successful it's time to get Alexa to discover the devices! You can do this inside the Alexa app, or simply say "Alexa, discover devices". Alexa should then find the number of different devices which you have configured. You'll also notice that she asks you to push the discovery button when she's searching for devices. You don't have to do anything :) (I spent ages looking around the GUI for some button after it didn't work).

That's it! You can now give Alexa voice commands to activate your jenkins jobs! The only downside is you have to assign it to a ON / OFF command.

A HA-Bridge docker container (albeit slightly large:
https://github.com/aptalca/docker-ha-bridge/blob/master/firstrun.sh

HA-Bridge GitHub:
https://github.com/bwssytems/ha-bridge

Jenkins Root Plugin:
https://wiki.jenkins.io/display/JENKINS/Build+Token+Root+Plugin