A couple of weeks before DockerCon 2017, Victor Coisne asked me whether I would like to create a demo for the DockerCon museum. Having built a hardware gauge with two dials already, it wasn’t going to be very hard to build another! This time, instead of showing load on a swarm, I hooked the dials up to the Twitter Search API to monitor the usage of #DockerCon on Twitter in real time. This was a really fun and quick project to build as I already knew how to make all the hardware. The code is very simple, in essence what it does is:
- Connect to the Twitter API & configure the servos
- Every 5s, query the API for the latest #DockerCon tweets
- Count unique tweeters & tweets in order to drive the servos
- Do some funky maths to create a sensible range for the servos
- Move the servos!
I wrote most of the code in about an hour, the rest (which probably took about 3!) was spent stabilising and ironing out some bugs.
docker run -ti \ --privileged \ --device /dev/gpiomem:/dev/gpiomem \ --env-file=./.env \ --restart=always \ developius/dockercon-tweet-monitor:latest
Let’s step through the arguments:
-ti: attach a keyboard & TTY to the container so we can watch it (I didn't do this in production, instead
--privileged: allows the container to control the GPIO on the Pi (not sure if this is needed when we use
--device: allows the Pi access to the GPIO memory device so that it can control them (see above)
--env-file: specifies a file (
./.env) where the Twitter API credentials are stored (see the README)
--restart=always: means that the container restarts when it exists (regardless of exit code) and will also restart when the host boots up
developius/dockercon-tweet-monitor:latest: I expect you know this one but it’s just the image to use
Pretty simple stuff!
What did I learn?
I learnt how to use the
latest tag on the Docker Hub to essentially symlink
latest to the latest version of your image - mine is 0.0.8 at the time of writing. This is really useful when you want to distribute documentation but not have to constantly update it to reflect the latest changes in an image which bumped the version up.
DockerCon is awesome!
Python support for timezones is horrendous, I mean what does this do?!
parser.parse(tweet.created_at) > pytz.utc.localize(datetime.now()) - timedelta(hours=1)
Well, it checks whether a Tweet’s date (including a timezone) is less than an hour ago, but can you infer that?
Quoting the Zen of Python, I’m pretty sure the line above fails every single rule:
- Beautiful is better than ugly
- Explicit is better than implicit
- Simple is better than complex
- Complex is better than complicated
- Readability counts
What would I have done differently?
Alex Ellis pointed out to me that it might be an idea to utilise the Twitter streaming API to deliver events to the dials instead of polling. As it is, the code works perfectly well but this would have been a neater and cleaner solution compared to performing a DoS on the Twitter API. Given time constraints, I went for a quick hack solution but if I was building it again, I would use the streaming API for efficiency and lower overheads.