08 Feb 2016, 17:43

Three ways to build Go 1.4 binaries for MIPS32 Onion Omega #golang #docker

I previously wrote about using gccgo to build Go binaries for the Onion Omega due to Go’s lack of support for MIPS CPUs. But TBH it’s a pain in the butt. Things were looking up when it was revealed that Go 1.6 would have MIPS support but sadly it’s for MIPS64 only, for datacenter applications I guess.

Onion Omega

However Cathal Garvey discovered a GitHub repo where some lovely person has ported v1.4.2 of Go to MIPS32 and it works perfectly on the Onion Omega (and presumably all other Atheros AR9331 boards).

This is a huge jump forward for the Onion Omega. Language support has been a bit of a problem for me with both Node.js and Go not really being usable there until now.

Due to the lack of storage on the Omega, you won’t be able to install the full Go build system there so a cross-compilation setup is needed.

I’ve been able to build the binaries on Linux, Windows and in a Docker container. All are easy.

Linux (or Linux VM on Windows)

Following Cathal’s simple instructions, I was able to build Go for MIPS32 in a few minutes in a Linux VM on my main Windows machine. I then cross-compiled a Hello World and scp’ed it to the Omega. It worked first time!

My steps:

git clone https://github.com/gomini/go-mips32.git
cd go-mips32/src
export GOOS=linux
export GOARCH=mips32
sudo mkdir /opt/mipsgo
cd ..
sudo cp -R * /opt/mipsgo
export GOROOT=/opt/mipsgo
export PATH=/opt/mipsgo/bin:$PATH
vi helloworld.go
go build helloworld.go

Windows 10

I was very surprised this worked but of course Go is strongly cross-platform. My standard build setup for Node.js native modules did the trick. You’ll probably need Visual Studio Community 2015 and Git for Windows. Then:

Open a CMD prompt (note I have all my code on D: drive)

cd gitwork
git clone https://github.com/gomini/go-mips32.git
cd go-mips32\src
set GOOS=linux
set GOARCH=mips32

I then created a simple CMD file which sets everything up when I need to build for MIPS so it doesn’t interfere with my main Go install.

set GOOS=linux
set GOARCH=mips32
set GOROOT=d:\gitwork\go-mips32
set GOPATH=d:\gitwork\go
set PATH=d:\gitwork\go-mips32\bin;%PATH%

When I launch that, I can do the usual go build filename.go. Note that the MIPS port seems to be able to share the same GOPATH as my x86-64 one. Not sure that will work in every case tho e.g. If C modules are bound?

For Windows I use WinSCP to copy the files to the Omega. For some reason Filezilla SFTP has a problem talking to it.

Docker Container on Windows

Hello World

To get more familiar with Docker I decided to create a Docker image that others can use. That turned out to be pretty easy too. Here is the Dockerfile:

FROM alpine:3.3

ENV GOLANG_SRC_URL https://github.com/gomini/go-mips32.git
ENV GOOS linux
ENV GOROOT /usr/local/go

RUN set -ex \
	&& apk add --no-cache --virtual .build-deps \
        bash \
        git \
        file \
        ca-certificates \
        gcc \
        musl-dev \
        openssl \
        openssh \
  && cd /usr/local/ \
	&& git clone "$GOLANG_SRC_URL" go \
	&& cd /usr/local/go/src \
	&& ./make.bash \
	&& apk del .build-deps

ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH

RUN rm -rf "$GOROOT/src"
RUN rm -rf "$GOROOT/test"
RUN rm -rf "$GOROOT/doc"
RUN mkdir -p "$GOPATH/src" "$GOPATH/pkg" "$GOPATH/bin" && chmod -R 777 "$GOPATH"

And you can grab the image from Docker Hub here.

The full set of steps for Windows are as follows:

  • Install Docker Toolbox for Windows. It’ll also install VirtualBox if you don’t already have it.
  • Run a Docker shell and type:
docker run -t -i conoro/go-mips32:v1 /bin/sh

(Note v2 has some problems I need to fix so you’ll need to manually install openssh and git on v1)

  • You’ll now be at a Linux prompt and you can type: go version
  • Then create a Hello World using: vi helloworld.go
package main

import "fmt"

func main() {
	fmt.Println("Hello, Conor")
  • Compile it with: go build helloworld.go
  • Copy it to the Onion Omega with: scp helloworld root@ip-of-your-onion/helloworld
  • Open a shell on your Omega with the webapp or Putty and just type: helloworld

Web App

A more advanced example which also works perfectly is to run a web-app using the Gin framework. For that, all you need to do is:

go get github.com/gin-gonic/gin
vi gintest.go

then in vi:

package main

import "github.com/gin-gonic/gin"

func main() {
    r := gin.Default()
    r.GET("/ping", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "pong",
    r.Run() // listen and server on

Then build that, scp it to the Omega and run it. Then open http://ip-of-your-onion:8080/ping to see everything working nicely.

Gin Ping Onion Omega

Note I also built this using the Windows setup for comparison and it worked too.


Not so much luck with embedded databases I’m afraid. I suspect Bolt and LevelDB are using some more advanced filesystem features which are causing issues on OpenWRT. I lack the expertise to debug.

  • Bolt has some CPU specific code which prevented building. I added an entry for MIPS32 (based on i386) and it then cross-compiled but throws error EINVAL when opening DB. Possibly OpenWRT FS related or down to bug in the Go MIPS port. But I’m using Bolt with Stow successfully on another non-MIPS32 project.
  • go-sqlite3 has a C library dependency so it also won’t cross-compile.
  • I gave up trying to get ql to do anything, even on Windows and Linux. It doesn’t like standard SQL syntax and I ran out of patience with the lack of example code.
  • kv has no sample code and my frustration levels with nothing working meant I gave up instantly
  • tiedot generates a large number of massive files which the Onion wouldn’t be able to handle. If I can get it down to LevelDB sizes, I might retry. Actually it doesn’t like 32-bit systems so forget that.
  • goleveldb looked like it would be perfect but it crashes trying to open a DB it created on the Onion. I have a feeling this is a bug in the MIPS32 port of Go. The crash happens in the Snappy library from what I can see. It can create an empty DB and it can read an empty DB but it crashes on a DB that has entries whether the DB was created on the Onion or on Windows.
  • gkvlite - It works! Hurrah! Well the sample code works. Now to try it on some simple stuff I’ve done elsewhere
  • diskv - Double hurrah, it seems to work too.


I’m looking forward to running a lot more code on the Omega now.

02 Jan 2016, 13:00

When will Car Insurance Monitoring Apps become mandatory? 5yrs?

My Car Insurance Broker, 123.ie just offered me up to 10% off my 2016 premium if I installed a driving monitoring app on my phone.

No thanks

But when does it go from “get a discount” to “we won’t insure you unless you install this app”?

The email:

123 Discount

01 Jan 2016, 10:59

How cheaply can you build a full Raspberry #PiZero computer?

When the incredible $5 Pi Zero was launched, the usual suspects were so busy snarking how it wasn’t really $5, that they completely missed what an important moment in computer history this is. You know the type. The ones who would have ridiculed Tim Berners-Lee’s design for the web. Or would have told Linus in no uncertain terms that he was misguided and that microkernels were the future.

Whilst you can’t turn on a #PiZero for $5, you also can’t connect to the LAN with your $1500 Macbook Pro without buying an adapter.

So assuming we don’t factor in electricity costs, carbon credits and depreciation on your chair, how cheaply can you build a fully functioning Raspberry Pi Zero, living in the UK?

Here’s what you need:

Total: £29.01

Or with obvious re-use/borrowing of stuff: £16.70

In Ireland? Add £1 extra for shipping the Pi Zero. Possibly a bit for the SD card from Amazon. Everything else free P&P from China.

Do you need a screen? Yup. Now walk into the sitting room and see if you can spot one. Well done.

A £29 fully fitted-out computer, that you could build the next global webapp on, remains completely revolutionary. All for around the same price as an Apple Thunderbolt-to-Ethernet adapter :-)

You've Quacked the case

31 Dec 2015, 21:20

What excited Conor in tech in 2015?

A completely random braindump of stuff that got my juices flowing this year.

ESP8266 $1 Wifi modules

I’ve talked about the ESP8266 constantly all year. A price-point of ~$1 in volume means that you can wifi-enable anything. Where previously you might have used one of the many low bandwidth “IoT” protocols internally and connected them to hub-device, now you can do Wifi and IP end-to-end. The only downside is high power consumption. I’d actually prefer if they did a low-power V2 instead of the bells-and-whistles ESP32.

The number of projects and initiatives that have grown up around ESP8266 is impossible to keep track of. Ones to check out are:

  • NodeMCU - A really nice dev board and Lua-based stack. This is what I used for most of this year but will be switching to Espruino
  • Espruino on ESP8266 - Still in heavy development but feels like a complete winner. JavaScript + Wifi for $4 is a killer solution.
  • Cesanta Smart.js - A Dublin-based company. Ex-Googlers I think. Similar to Espruino but without the community. Wish they’d join forces instead.
  • Arduino - Yup, you can run a huge amount of Arduino code straight on the ESP8266. Really exciting to have this. Only drawback is that native AVR code and (I think) interrupt-driven code will not compile. Also far fewer IOs than normal Arduinos.

Raspberry Pi Zero and The Mag Pi Issue 40

A $5 computer that came free on the front of a magazine. Very little else needs to be said here. $5 for 1GHz, 512MB RAM, 1080p HDMI, Linux, Mathematica, Node-Red, Kodi and anything else you want to try. I still get the shivers thinking about it. Meanwhile the never-satisfieds will whine about $1 adapters or the fact that it needs electricity. I’m framing my first one.


Let’s Encrypt

Anyone who has had to go through the rigmarole of setting up a https server knows what a pain it is. The certs are generally completely overpriced too. Let’s Encrypt Certs are free and full automation is already available for Apache, NGINX, Caddy and more. Now you basically have no reason not to use https.

This is a massive industry segment disruption. I’m thrilled to see it happen.

Security First and Privacy First

I use uBlock Origin, Pop-up Blocker, Do Not Track and Ghostery on all my browsers. A lot of the time I use BlackVPN too. Yet somehow, with my anti-business setup, many many companies received online orders and money from me this Christmas. I’m done with the online advertising industry. All the stuff Doc Searls has been talking about for years is still valid. As for governments thinking our online activities are their business, you need to start fighting back now.

Google Cardboard and YouTube 360

Somehow I completely missed the launch of Cardboard support in YouTube and the creation of 360 videos by an ever growing set of people. The first one I saw was Colin Furze and it’s just incredible. The second was one based on Star Wars The Force Awakens, and is 100x better than the movie. I went and got a much more high quality plastic “Cardboard” as a result. It’s excellent. The recently launched Google Cardboard Camera is also superb but images are sadly locked to the device the panoramic photo was taken on.

This is one overall technology-set that myself and the kids are 100% in agreement on. It rocks. The next Star Wars movie should be launched on Cardboard (or Oculus or whatevs).

Node.js 4.x

Phew. The schism has been healed and 4.x is a really great release. Initially I had lots of problems with native modules on Windows which I hope are finally starting to settle down now. Node is still the best choice for a huge range of workloads and cannot be beaten for mobile back-ends.

Embedded JavaScript

I think JavaScript will completely take over the Embedded world where hard realtime is not required. The Espruino project has shown what is possible here and should be much more widely used. I’m looking forward to seeing it running on the BBC’s micro:bit. Other projects like Cylon.js are also worth a look.


I’ll be honest, C has been the only language I really loved working in. I like Python and I really enjoy the productivity of Node.js but C was what I spent most of my real programming years using. C++ is an abomination and Java always feels like a crazy amount of work to eventually run some bloated barely-portable thing.

And then I found Go and immediately felt comfortable. It’s C with the sharp edges removed and some really useful stuff added. Static compilation is the killer feature for me. Just drop the very-quickly-compiled binary in anywhere and run it. I’m using it more and more for small projects that aren’t backing a webapp or mobile app. It could work in both those cases too but it just doesn’t have the community in that area the way Node.js has.

I think Node.js and Go will dominate software development over the next few years.

Left-field: Go is slowly getting some Android capabilities. Google should go all-in on it and replace Java. If Apple can manage it so well with the move to Swift on iOS (and they used 3 CPU architectures on Mac!), why not? It would kill all the Oracle problems completely and move them away from a legacy language.

Scriptcraft & Minecraft

Minecraft continues to dominate my younger kids’ lives. From Stampy to Servers, they are never bored playing it or watching videos about it. My buddy Walter built the amazing Scriptcraft which enables you to build mods and control Minecraft in, yes you guessed it, JavaScript. His book is a must-read for anyone looking for an interesting way to teach kids how to program. I really want to try out some stuff where it interfaces with the real world. I think Microsoft are missing a trick by not rowing in behind Walter and this wonderful project.

It’s also a huge pity to watch Lego completely miss the boat here and continue to sell the crazily overpriced and overspecced Mindstorms. There is a sweetspot to be found in an online-world + real-world + electronics + JavaScript and it ain’t Lego bleedin Dimensions.

Particle Photon

I was given a Particle Photon recently and was blown away by how easy the setup was and how slickly the Cloud IDE works even through firewalls and NAT. Despite the Open Source nature of it, I still worry about lock-in to some degree. Having said that, my DigiStump Oak just shipped (ESP8266 again!) and it it now Particle API compatible. I’d love to see some sort of multi-vendor federated distributed Particle clouds where you aren’t betting your IoT strategy on the financial stability of one startup.

React Native

Use JavaScript to build Native Apps on iOS and Android. What’s not to like? Weird how I hate Facebook the site/app but love so much of their Engineering.

RGB LEDs / Neopixels

Ridiculous amount of fun with simple individually controllable RGB LEDs. These are going to be everywhere in 2016. Everywhere.

3D Printing

I still adore my Printrbot Simple Maker’s Edition. I continue to be surprised by the quality of prints from such a cheap printer. I’ve had some fun with Ninjaflex and unusual colours this year. Also a multitude of #PiZero cases! If funds permit, I’ll probably start looking at one of the Prusa i3 variants to get a bigger print area but otherwise it does everything I need.

eFibre by Eir

We get 92Mbs down, 19Mbs up. It’s completely changed how we use the internet. Bravo Eir(com). Genuinely surpassed all expectations. Getting speeds like that on a poxy twisted pair is staggering.

But let’s be absolutely clear about broadband in this country, the Government’s latest target of 30Mbs for everyone is a joke. By the time it’s done, it’ll be completely out of date. Why can these people not understand that ultra-fast broadband everywhere will do more for employment in this country than anything else. They’d be heroes in history for doing this right, not remembered as a bunch of clowns who couldn’t properly roll out a water quango and postcode quango.

Statically hosted Blogs

It feels like every day there is another WordPress security scare. And that’s without mentioning the plugin ecosystem horror. I got sick of the upgrade cycle treadmill and constant exploits last year and moved everything to statically hosted blogs. First with Harp.js, then with Hexo and now with Hugo. All fine tools, all work well with GitHub Pages and OpenShift. The incredible speed of Hugo is what makes it my current favourite. Edit, build, deploy, fuggedaboudit. I will never go back to a traditional DB-backed CMS.

Dirt-cheap Android phones and tablets

I got a Doogee X5 Android phone for €55 a few weeks ago as a backup device. Apart from the case being a bit plasticky, it could pass for €200 worth. It has a great screen and surprising speed. 2 SIM slots and an SD card slot. Samsung could learn a lot from Doogee.

One of my daughters got the lowest-level Kindle Fire as a Christmas present. The specs are garbage. She loves it. It does absolutely everything she needs and she hasn’t asked to use the iPad Mini once since she got it.

I seriously doubt I’ll ever buy a premium phone on contract again. Once One Plus return to removable backs, replaceable batteries and SD card slots, I’ll jump to either them or the Wileyfox. Apart from the camera, there is practically nothing on my Galaxy S6 that I couldn’t do with an S4 or HTC Sensation. And they are both more robust and have replaceable batteries and SD card slots.

Linux everywhere

Everywhere. This makes me happy. I was very surprised my other daughter was more than happy to get an old hand-me-down laptop running Fedora 23. As long as it had Chrome, YouTube, Kodi and Minecraft she didn’t give a damn what the OS was. The OS is irrelevant to all my kids. In our house we segue seamlessly from Android to iOS to Windows to OSX to Fedora to Raspbian. The only things that matter are the apps and the content.

Messaging Apps

Our entire extended family is on WhatsApp including grandparents. SMS is dead to us. MMS was never a thing. I’d prefer if we were all using an Open Source secure P2P system but we’ll get there. The family breakdown is as follows:

  • Adults: WhatsApp. Tiny amount of FB Messenger
  • Teens: FB Messenger, some Viber and some WhatsApp to the (grand)parents
  • Tweens/Smallies: Viber, Snapchat and some WhatsApp to the (grand)parents
  • Youngest: Uses Hangouts to her cousin. Including live video!
  • No one: Telegram.
  • Curveball - Tweens using Instagram comments as a weird chat channel

Top tip - WhatsApp needs a phone number, Viber doesn’t. Many many smaller kids have tablets, not phones. WhatsApp really missing out here. Our solution is to put free Tesco Mobile SIMs in old phones and never put credit on them. Gets over the WhatsApp problem.

9yo yesterday: “What’s ‘Messaging’ on my iPhone”. Me: “It’s SMS”. Her: “What’s that”. Me: “Texts”. Her: “Ah ok. Why are there so many apps for messaging? Why not just one?”

2FA and Authy

Two Factor Authentication is a complete pain in the neck. It really is.

Turn it on everywhere now. Do it. Do it now.

The fact that PayPal still doesn’t have it is a complete disgrace. I’d strongly recommend using Authy instead of the Google Authenticator App. The main reason is that you can install Authy on multiple phones/tablets which you cannot do with Authenticator. They also have a Chrome extension.

Things that continue to disappoint

  • Twitter - Useless Web App and Mobile App. Still hostile to developers who make better ones. And still no Filters, in 2015!
  • Facebook - Uninstalled the mobile Apps. A hand-crafted List is the only way to put it under your control. Impossible to use FB for realtime events. Ugh.
  • Google - Local Search and Reviews remain a complete embarrassment. Have them AdBlocked and Ghostery-ed. Maps degenerating. Photos great tho!
  • Google Compute Cloud - Awful. Amateur hour. Avoid. Particularly the MySQL service.
  • Mobile device form factors - Nothing new since 2007. Bored to death of glass slabs.
  • Mobile device usability - I’ll still use a desktop for anything other than quick glance. Everything feels slow and awkward. Android and iOS
  • Batteries - Hurry up already. The only excitement here seems to be exploding LiPos
  • AMD CPUs - RIP AMD. After decades of building PCs with AMD CPUs, I got my first i7 in December. It’s over AMD, give up.
  • Emojis - All those emojis but they never have the one I want.
  • Blockchain - Hype machine in overdrive far too soon. Show me something a kid can understand in 30 seconds and delivers immediate benefit. Everything I’ve tried has been a giant pain in the arse including Identity, Money, DNS and Messaging.

31 Dec 2015, 18:41

My 2015 Christmas turkey oven thermometer and clock

For the third year in a row I decided to build a new oven thermometer for the Christmas turkey, as all of the markings on our temperature knob have been gone for years. We also have one of those mechanical dial thermometers you place inside the oven but they are hard to read and get in the way. My last two attempts worked ok but I was concerned about accuracy. I also used a temperature probe in the meat for belt and braces. The setup was as follows:

The code is a mix of Adafruit, Paul Stoffregen for the improved LCD code with lovely Magenta Comic Sans Font :-) and my own.

I didn’t bother with averaging the values but the jumpiness of the temperature compared to room temp or boiling water tells me our old oven is a disaster and needs replacing.

And just like the previous two years, the turkey was dry despite spatchcocking it, dry-brining it and watching the temperature closely :-( Next year I’m doing a boned and rolled one and I’ve ordered a cheap but protected Chinese oven probe and temperature readout.

I really like the DX voltage booster. It enables you to connect a LiPo battery and a micro-USB power source. It then provides 5V on a standard USB socket. The power source can also charge the battery whilst powering the device. You can then remove the power source and the battery will power the device without interruption. It’s almost perfect except for one stupid feature. You can’t connect a battery to it to power a device without connecting (even momentarily) the power source (e.g. a phone charger). If it could do that then it’d be pretty much at the same level as the Adafruit boost devices. I’ve been unable to find any datasheets for it but ordered two more anyway.



Completed Board

Completed board

Lego Case

Lego Case

Side View

Side View

Code (latest always on Gist here )

// Temperature from AD8495 K-type Thermocoule adapter and Datetime from DS1307 RTC. Displayed on ILI9341 LCD.
// MIT License (MIT)
// Copyright (c) 2015 Conor O'Neill
// Portions copyright Limor Fried/Ladyada for Adafruit Industries and others
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

#include <Wire.h>
#include "RTClib.h"

#include "SPI.h"
#include "Adafruit_GFX.h"
#include "ILI9341_t3.h"
#include "font_ComicSansMSBold.h"

#if defined(__SAM3X8E__)
    #undef __FlashStringHelper::F(string_literal)
    #define F(string_literal) string_literal

// These are the pins used for the UNO and Teensy
#define _sclk 13
#define _miso 12
#define _mosi 11
#define _cs 10
#define _dc 9
#define _rst 8

// Using software SPI is really not suggested, its incredibly slow
//Adafruit_ILI9340 tft = Adafruit_ILI9340(_cs, _dc, _mosi, _sclk, _rst, _miso);
// Use hardware SPI
ILI9341_t3 tft = ILI9341_t3(_cs, _dc, _rst);


String dateOut="";
String timeOut="";
String datePrev="";
String timePrev="";
float temperature=0;
float temperaturePrev=0;

void setup () {



    // following line sets the RTC to the date & time this sketch was compiled
    // Uncomment this once per power down of the RTC and flash it. Then re-comment-out and reflash
    //RTC.adjust(DateTime(__DATE__, __TIME__));

  if (! RTC.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    //RTC.adjust(DateTime(__DATE__, __TIME__));


void loop () {

    // Read temperature as analogue voltage from AD8495
    int raw = analogRead(A7);
    float Vout = raw * (3.3 / 8191.0);
    temperature = (Vout - 1.25)/0.005;

    // Print Temperature to Serial console

    // Get current DateTime from DS1307 RTC
    DateTime now = RTC.now();

    // Print it to Serial Console
    Serial.print(now.year(), DEC);
    Serial.print(now.month(), DEC);
    Serial.print(now.day(), DEC);
    Serial.print(' ');
    Serial.print(now.hour(), DEC);
    Serial.print(now.minute(), DEC);
    Serial.print(now.second(), DEC);

    // Generate nicely formatted datetime string for ILI9341
    if (now.hour() < 10){
        timeOut += "0";
    timeOut += now.hour();
    timeOut += ':';
    if (now.minute() < 10){
        timeOut += "0";
    timeOut += now.minute();
    timeOut += ':';
    if (now.second() < 10){
        timeOut += "0";
    timeOut += now.second();
    if (now.day() < 10){
        dateOut += "0";
    dateOut += now.day();
    dateOut += '/';
    if (now.month() < 10){
        dateOut += "0";
    dateOut += now.month();
    dateOut += '/';
    dateOut += now.year();

    // Print Temperature and Datetime to ILI9341 LCD
    unsigned long start = micros();
    tft.setCursor(0, 0);

    // Wipe out previous text and write new text
    tft.setCursor(0, 45);
    temperaturePrev = temperature;

    // Wipe out previous text and write new text
    tft.setCursor(0, 100);
    datePrev = dateOut;

    // Wipe out previous text and write new text
    tft.setCursor(0, 145);
    timePrev = timeOut;


30 Dec 2015, 17:15

Auto-tweeting the #Bandon floods with Twilio, Tasker, Let's Encrypt, a #PiZero, golang, Caddy and an Asus router


I haven’t blogged properly about the $5 Raspberry Pi Zero computer yet, despite Tweeting non-stop about it. I will soon. In the meantime, I’ll just repeat that

It’s a major moment in computing

The inclusion of a free one on the cover of the MagPi Magazine will be remembered for years to come.

The town in which I live, Bandon, flooded again recently, because Ireland. I’ve had a simple Node.js app running on a Gen 1 Raspberry Pi B, scraping the Bandon Flood Warning site every 15 minutes for the past four years and saving the data in Google Fusion Tables.

Yes that’s how Cork County Council’s/OPW’s Flood Warning site looks in the middle of one of our biggest floods ever:

FEWS Unavailable

With all this flooding, I decided to finally create a related setup which takes the SMS Flood alerts from the County Council and auto-tweets them to the @BandonFEWS Twitter account which I created and have manually updated since 2011.

The Details

So the final $7 hardware (including Wifi adapter) now looks as follows:


  • My phone is registered with the Bandon Flood Warning site (it has been for years)
  • I have a Twilio account with a $1 per month UK SMS number. Irish numbers are $6 per month :-(
  • SMSes are sent to my phone from Cork CoCo announcing a new flood warning level or severe weather alert (two different systems and numbers)
  • The Android Tasker App watches for SMS from these sources with particular contents
  • Tasker auto-forwards these SMSes to my Twilio number


  • I have the Twilio number configured to call a my simple API end-point with the SMS contents
  • The API end-point is running on one of my $5 Raspberry Pi Zeros and is written in Go. Code below.
  • The PiZero is behind my home router which is an Asus RT-AC68 so somehow Twilio had to connect through that to the Zero
  • I initially setup a simple port forward to the Zero and I already use no-IP.com for Dynamic DNS. So Twilio called http://something.no-ip.net:1234 and my router passed the request to the PiZero server app on port blah
  • The PiZero server app parsed the POST request and extracted out the SMS. It split this into multiple Tweets (a la Tweetstorm) if more than 140 chars and used the Anaconda Go client library to post that to @BandonFEWS on Twitter
  • Done

But I wasn’t happy with http, nooooo, I wanted https and I wanted to use Let’s Encrypt. Cue rabbit hole.

Let’s Encrypt and Caddy

Let’s Encrypt offers free https certs.

It’s as revolutionary as the PiZero.

It also provides APIs so this can be done completely automatically. This resulted in lots of people adding easy Let’s Encrypt integration and client libraries very quickly.

  • Caddy is a really nice simple-to-use web-server written in Go. It runs perfectly on the PiZero. It also has completely automatic Let’s Encrypt integration if you want it. So I stuck it in front of my Go server to turn it into a https server. Except life is never that easy.
  • I hit two immediate problems:
    • I’d have to drop no-IP for Dynamic DNS since I’m trying to register for my own https cert
    • To stop baddies registering domains they don’t own, Let’s Encrypt calls back to you and insists on doing that on port 443. So my random high port number on my router wasn’t going to work
  • Then I realised that my DNS provider, DNSMadeEasy has Dynamic DNS built-in. So I grabbed one of my parked domains and set it up with a Dynamic DNS A Record, giving it a dedicated password. But then of course I discovered that my Asus Router doesn’t have support for Custom Dynamic DNS out of the box.
  • I quickly found the Merlin Firmware which is interesting. The standard Asus firmware is just a simplified fork of Tomato so Merlin forks again and adds back in the stuff that Asus removed. So you keep the same UI and general functionality, just with more customisation.
  • Installation was a doddle and then I just had to whip up a simple script a few lines long to call out to DNSMadeEasy whenever the router’s IP address changed (see below).
  • I then temporarily port forwarded 443 on the router to the Pi Zero and started Caddy with this incredibly complicated config file :-)


proxy / localhost:9998
  • Caddy saw that I wanted https, so it connected to Let’s Encrypt and a minute later I had everything necessary for my secure web-server.

Jaw-drop time

  • Once the registration was done I could remove the 443 port forward and switch to a non-standard port
  • I went over to Twilio and provided the new https://conorsdomain.com:9999 as the end-point to call. No joy. But a quick support ticket later and they made a change over the weekend(!) to fix it. Boom, everything working fine.
  • With the terrible weather, I didn’t have to wait long for the first non-test SMS to appear. A couple of seconds later it was on Twitter:

Bandon Flood Warning


  • Of course I could exclude Twilio from this entire flow and call the end-point directly from Tasker but SMS will often work when no data connection is available.
  • Having said that, the connection to the phone is a big worry as we are in a poor signal area. But registering my UK Twilio number on the Flood Warning site didn’t work (local warnings for local people) and I’m not paying $6 a month for an Irish number.
  • In theory I could take the scraped data from the site and generate my own alerts but the Council rightly overrides the default trigger levels on occasion to warn people of impending flooding.

Go Code (See for https://gist.github.com/conoro/f1a3f7c5b96e2b033119 for latest)

package main

import (


type Configuration struct {
	ConsumerKey       string
	ConsumerSecret    string
	AccessToken       string
	AccessTokenSecret string

func main() {
	file, _ := os.Open("conf.json")
	//file, _ := os.Open("conf-test.json")
	decoder := json.NewDecoder(file)
	configuration := Configuration{}
	err := decoder.Decode(&configuration)
	if err != nil {
		fmt.Println("config error:", err)
	api := anaconda.NewTwitterApi(configuration.AccessToken, configuration.AccessTokenSecret)

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		body := r.PostFormValue("Body")
		if strings.Contains(body, "Bandon FEWS") || strings.Contains(body, "Met Eireann") {
			fmt.Fprintf(w, "Thanks for the update")

			a := []rune(body)
			if len(a) <= 140 {
				// Just post normal Tweet
				result, err := api.PostTweet(body, nil)
				if err != nil {
				} else {
					fmt.Println("Tweet ID: ", result.Id)
			} else {
				// have to split into a Tweetstorm
				var originalTweetID int64
				var subTweet string = ""
				var tweetCount int64 = 0
				tweetParams := url.Values{}
				for i, r := range a {
					subTweet = subTweet + string(r)
					if i > 0 && (i+1)%137 == 0 {
						// Need to do normal first tweet but in_reply_to successive tweets
						if tweetCount == 1 {
							// Just Tweet and extract the ID from the response
							result, err := api.PostTweet("1/ "+subTweet, nil)
							if err != nil {
							} else {
								originalTweetID = result.Id
						} else {
							// adding one second delay in Tweetstorm to prevent any throttling by Twitter
							// Tweet in reply to the first tweet by setting in_reply_to_status_id
							// originalTweetID
							tweetParams.Set("in_reply_to_status_id", strconv.FormatInt(originalTweetID, 10))
							result, err := api.PostTweet(strconv.FormatInt(tweetCount, 10)+"/ "+subTweet, tweetParams)
							if err != nil {
							} else {
						subTweet = ""
					if i == len(a)-1 && subTweet != "" {
						// just Tweet whatever text is left at the end
						// Tweet in reply to the first tweet by setting in_reply_to_status_id
						// originalTweetID
						tweetParams.Set("in_reply_to_status_id", strconv.FormatInt(originalTweetID, 10))
						result, err := api.PostTweet(strconv.FormatInt(tweetCount, 10)+"/ "+subTweet, tweetParams)
						if err != nil {
						} else {

	log.Fatal(http.ListenAndServe(":8333", nil))


Asus DNSMadeEasy Update

This is smidge fiddly. More details here. Once you have Merlin installed and you are happily connected to the internet again (you did remember to write down all the settings for your ISP didn’t you?). You need to:

  • Go to Administration -> System
  • Enable SSH, which also obviously gives you SFTP
  • Toggle “Format JFFS partition at next boot” to Yes
  • Toggle “Enable JFFS custom scripts and configs” to Yes
  • Click Apply
  • SSH on to the box with your router’s Admin username and password
  • Create a file called /jffs/scripts/ddns-start
  • Make it executable (chmod 755 ddns-start)
  • Copy these contents into ddns-start

curl -k "https://cp.dnsmadeeasy.com/servlet/updateip?username=${USERNAME}&password=${PASSWORD}&id=${ID}&ip=${IP}" >/dev/null

if [ $? -eq 0 ]; then
    /sbin/ddns_custom_updated 1
    /sbin/ddns_custom_updated 0

  • Do a reboot for good measure and you should see DDNS displaying success on the main dashboard

27 Dec 2015, 16:38

Blogging from my phone with DroidEdit, Hugo, GitHub Pages and Travis

I switched this blog to the superb Go-based tool Hugo earlier in the year. Its staggering speed compared to HarpJS and Hexo plus a single executable you can drop in anywhere, make it a no-brainer for static blogs.

I continued to host for free on GitHub Pages which means I never ever ever have to worry about WordPress security exploits or badly written plugins again. However using GH Pages means you are quite limited in how things work.

For several months I used Hugo in the recommended way of having one Git repo for the blog’s “source files” and then the original conoro.github.io repo as a Git sub-module for the deployed HTML. I’ve never heard a good word said about Git sub-modules and now I understand why. Nasty awkward things that mess everything up if you blink wrong. But it worked ok-ish until I decided to try Travis CI.

Travis is a continuous integration tool that can watch for changes in your GitHub repos and then run “jobs” on them. It’s mainly used for building software but there is no reason you can’t use it for building a blog. So the initial idea was that I would git add/commit a new blog post in my source repo and then Travis would run Hugo on it and commit the generated HTML to the blog, thereby publishing it.

The real intent was so I could blog from devices that don’t run Hugo like phones and tablets. Of course they’d somehow need to support a text editor and Git but not Hugo itself.

For Android I quickly found the superb DroidEdit which has Git support built-in. It was dead easy to use it to generate a new post and add that to my repo. So I would have almost WordPress-level of easiness in blogging on the fly. Its only real drawback is the lack of Markdown syntax highlighting.


Except then I tried to get it working with Travis. Several weekends of effort trying to wrangle the Git sub-module setup into submission ended in total frustration. Finally today I said “sod sub-modules” and went old-school “copy the files from one repo to the other and commit them there”. And ye know what? It worked!

There’s a few bits in there to do with using https:// instead of git://. But the critical one-off steps on your PC are:

  1. get a Github token for Travis
  2. Then install Travis locally
  3. and encrypt your token via: bash travis encrypt GH_TOKEN=<secret token here>
  4. Finally add that output to the “secure” string in .travis.yml.

So here you go with the files you need to do the same:


language: go
  - 1.5.1
sudo: required
  - USER: Conor O'Neill
  - EMAIL: cwjoneill@gmail.com
  - GH_REF: github.com/conoro/conoro.github.io.git
  - REPO: conoro.github.io
  - GH_REPO: github.com/conoro/${REPO}.git
  - secure: "hHQScM7MWsK/74fvtoBn7lKuTKx1XlU08Ee4UD6ce0wfKNdE/W8z2dn8qzEsSw3YaoU6AULQgXthX+LVAXVZr1wIC6H9Kvjilaj+9ffRXFKrUv79q8s4EiOKqIvYGla5XlhIzP1Qu1qyLCA4dzgaQF6Cn2jB9AkkObnd8YArf3aW3LUbAnRy0ySo0A/QRupN/ckb81LXYnfbzQZB9zniBIhvGPipR0KdQL7GePShPWDeXJPpblo5kEXiIvHo7b1XYx+xACmaQR9PdoDgoTCAFqz2tJzCU92PnbIGw4Jv/ZdnWmt8Z6/4dO73UhcE3PokPvmg7tdsHbFWxhEzg0NaC7cvYsH3xWy9uTipwYLRd3eGbBt+htCZOj+slNHzREkPJBtEBw+b4iLDAr0T5V0kyflgsGOcgSXPyLIKsI0rHFRVAsZxowowK1UjZ05tnSIlFcIK8DX9c0JoXpM2ktOUt8/2EPCbaoKv17HW4BVDb7vXR8VzBf5MY4qku9NrmmYTMJXrzcdQU8JrbASPlHyF79n5xiiyg74Vq2OYCgHPg1nzmSrC1YgQu0W5WXNjWo9jt8h9C3ztuNYvDJkKkXl7KZDTq/s2XEzpzuLIA4rdTX+7lUB93ggN2YFeh6LV+kq58L8BpMPyiT8kxZLMF0HFTzaRNNwymelkPsV/+QZydro="
  submodules: false
# Use sed to replace the SSH URL with the public URL, then initialize submodules
  - sed -i 's/git@github.com:/https:\/\/github.com\//' .gitmodules
  - sudo pip install Pygments
  - go get github.com/spf13/hugo
script: bash ./deploy.sh



echo -e "\033[0;32mDeploying updates to GitHub...\033[0m"

git config --global user.email "cwjoneill@gmail.com"
git config --global user.name "Conor O'Neill"

# Build the project.
hugo # if using a theme, replace by `hugo -t <yourtheme>`

git clone https://github.com/conoro/conoro.github.io.git
cp -R public/* ${REPO}
cd ${REPO}
git remote
git add -A :/
git commit -a -m "latest via travis"
git push "https://${GH_TOKEN}@${GH_REPO}" master > /dev/null 2>&1

27 Dec 2015, 11:34

Simple Christmas Control of each LED in a 150 RGB LED WS2812 strip

One mistake I made with our Halloween setup was buying an analogue RGB LED strip where all the LEDs had to be set to the same colour. Then a few weeks ago, Joe Desbonnet Facebooked about getting a waterproof WS2812 strip with individual LED control. And it wasn’t that much more expensive than the analogue one. Off to eBay I went and ordered one, far too late for Christmas.

So I was chuffed that it arrived on Christmas Eve. Unfortunately the 8 amp PSU I ordered on Aliexpress didn’t arrive. A quick rustle in my psu drawer found a 4 amp one. Another quick rustle in another box found an old Arduino Nano and it took barely 5 mins to load it up with the Adafruit strand test code and wire everything together (one digital pin, gnd, 5v) to give this:

The psu was running warm but not crazily so. However the Arduino kept crashing which hinted that the psu was dropping below 5V to power all those LEDs. So I ran separate power to the Arduino from a phone charger.

This was followed by 4km of duct tape as the connections and Arduino would have to live outside. A gale was blowing as I tried to attach it to the window frame so I switched to the more sheltered door frame. This Mammoth tape worked really well:

And that was it. Almost zero effort for the best house light decoration we’ve ever done. Since these strips can be cut to any length you want and also spliced together, I’ll be fashioning a full house-length monstrosity for next Christmas. However I doubt I’ll ever reach this level:

16 Nov 2015, 22:35

First impressions of @OnionIoT Omega. Also running #golang 1.1.2 and #nodejs 0.10.5 on MIPS

I did a splurge of backing IoT KickStarters a few months ago and the Onion Omega is the first one to land in my postbox. It’s a tiny (barely bigger than an SD card) board running the same basic guts as many OpenWRT routers i.e. 400 MHz Atheros MIPS CPU with 64MB of DRAM and 16MB of Flash.

Onion Omega

If you’re not familiar with OpenWRT, it’s an Open Source community replacement firmware for many routers (similar to DD-WRT that I’ve used many times) and is Linux under the hood. You generally do your own custom Firmware builds which bundle exactly what you want but you can also install packages via the opkg tool.

Obviously 400MHz with tiny RAM cannot compete with an RPi but it is far more powerful than most MCUs and runs Linux. The question is whether this middle ground addresses a big enough market, particularly when the price point is almost the same as an RPi Model A and you need to buy add-on cards to work easily with it. I’m not sure yet.

The Onion team are currently building a Web UI and an IoT “Cloud” as value-adds and of course everything is OpenSource.

The fact that it just launched means that the software story isn’t great right now. The KickStarter mentions things like Node but that isn’t available in a supported way. Also the effort around accessing GPIOs etc is focused on Python. And add-on boards like the OLED screen I bought have no support yet.

Onion Omega Kit

Summary Opinion

Overall it’s a nice board but the lack of “buzz” around it has me a little worried. The number one thing that projects like this need is community. I think the CHiP might steal a lot of its thunder with more welly at a much lower pricepoint. But perhaps a focus on realtime embedded applications will help here.

I’d like to see a library like WiringPi built for it that can easily have wrappers for others languages implemented.

I think it’ll be ideal as a home API server that I can put anywhere and forget about.

Another area it could shine, due to its tiny size and low power consumption is robotics. See my comment below about Gobot.

Node.js partial success

After an initial play around with it, I decided to try out Node and Go. Node was built by a community member but is back on version 0.10.5.

I copied the Node executable and libv8 to a USB stick and plugged that into the Onion standard “dock”. I mounted it and ran hello world successfully. Hurrah!

But then I realised it doesn’t have NPM. So I put together a simple Tweeting App, did the NPM install on my Fedora VM and then copied everything to the USB stick.

The code which ran fine on Fedora crapped out with “not authenticated” on the Onion. I tried two other Twitter modules with the same result. I wasn’t able to see any other error apart from Twitter complaining about authentication.

So I gave up on Node for the moment.

Golang 1.1.2 first failed attempt

On to Go and a giant big rabbit hole.

So you can’t get a recent version of Go for MIPS. However, one smart person forked OpenWRT and added Go support via gccgo. Yay it’s Go, boo it’s Go 1.1.2.

But I thought it’d be a good experience to try building OpenWRT from scratch anyway. The instructions here and here are pretty straightforward and I managed to build the Gnu cross-compile toolchain inside a Fedora 22 VM on Windows 10.


git clone git@github.com:GeertJohan/openwrt-go.git openwrt
cd openwrt
./scripts/feeds update -a
./scripts/feeds install -a
cp ~/Desktop/scons-2.3.5.tar.gz dl (needed to download this manually as it was missing)
cp ~/Desktop/openssl-1.0.2c.tar.gz dl (needed to download this manually as it was missing)
make menuconfig

In menuconfig you have to enable a few things:

  • -> Advanced configuration options
  • –> Toolchain options
  • —> C library implementation
  • —-> Use eglibc
  • -> Advanced configuration options
  • –> Toolchain options
  • —> Select Build/Install gccgo

Then save and exit, followed by:


Several hours later on my old i7 laptop, I had everything I needed.

Then a simple helloworld Web Server helloweb.go that only uses standard library features:

package main

import (

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:])

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)

Create ~/openwrt.config which consists of

export STAGING_DIR=/home/conor/openwrt/staging_dir 
export TOOLCHAIN_DIR=$STAGING_DIR/toolchain-mips_34kc_gcc-4.8-linaro_glibc-2.19 

Then build it:

. ~/openwrt.config
mips_gccgo -Wall -o helloweb_static_libgo helloweb.go -static-libgo

I copied it over to the Onion but no joy. It just kept saying “not found”. Distant memories told me this was related to libraries and versions but nothing I tried worked. So I took a break.

Golang 1.1.2 second successful attempt

A while later I decided that what I needed to do was build OpenWRT for the Onion but then I hit a blocker. Onion support was added to OpenWRT in July but the latest version of the toolchain that included Go was from May. So I bit the bullet and manually “cherry-picked” all of the author’s changes from the older toolchain into the latest version of OpenWRT.

You can get the patchfile I generated here and apply it.


Now to build from scratch again:

sudo dnf install -y subversion binutils bzip2 gcc gcc-c++ gawk gettext flex ncurses-devel zlib-devel zlib-static make patch unzip perl-ExtUtils-MakeMaker glibc glibc-devel glibc-static quilt sed sdcc intltool sharutils bison wget

. ~/openwrt.config   (see the contents of that file in the first failed attempt)

rm -rf ~/openwrt
git clone git://git.openwrt.org/openwrt.git openwrt
cd openwrt
nano feeds.conf.default

and append the following:

src-git onion https://github.com/OnionIoT/OpenWRT-Packages.git


scripts/feeds update -a

make menuconfig

Note you have to include the same menuconfig settings as before i.e.

  • -> Advanced configuration options
  • –> Toolchain options
  • —> C library implementation
  • —-> Use eglibc
  • -> Advanced configuration options
  • –> Toolchain options
  • —> Select Build/Install gccgo

Plus the following for both the Onion and USB stick. This uses some instructions from the Onion site:

  1. Target System is Atheros AR7xxx/AR9xxx
  2. Subtarget is Generic
  3. Target Profile is Onion Omega
  4. Target Images is squashfs
  5. Add kmod-fs-vfat
  6. Add kmod-nls-cp437

Several hours later again, I finally had a version of the firmware that included Go support and ran on the Onion by doing the following on the Onion:

cd /tmp
scp conor@ .
sysupgrade openwrt-ar71xx-generic-onion-omega-squashfs-factory.bin 

Hello World Web Server in Go on the Onion Omega

Back to helloworld on the Fedora 22 VM:

alias mips_gccgo='mips-openwrt-linux-gccgo -Wl,-R,/home/conor/openwrt/staging_dir/toolchain-mips_34kc_gcc-4.8-linaro_glibc-2.19/lib/gcc/mips-openwrt-linux-gnu/4.8.3 -L /home/conor/openwrt/staging_dir/toolchain-mips_34kc_gcc-4.8.0-linaro_glibc-2.19/lib'

mips_gccgo -Wall -o helloweb_static_libgo helloweb.go -static-libgo

Copy to the Onion and run it with a simple ./helloweb_static_libgo

Hurrah, Hello World in Go on the Onion!

I love mac and cheese

Tweeting from the Onion Omega in Go

I should have left it at that but no, I wanted to Tweet from the Onion. My problems multiplied. Basically, gccgo doesn’t have all the bells and whistles of recent Go and can’t handle included packages easily. After some reading and playing, I managed to build a Tweeting App that used the Twittergo package. Note you need a local Fedora version of Go installed and configured for “go get” to work (or just git clone). My $GOPATH is /home/conor/gitwork/go

I used the example from Twittergo to send the tweet, with the same mods to remove paths from the imports as the other files.

. ~/openwrt.config

cd ~/gitwork/go/src/github.com
go get github.com/kurrik/twittergo
go get github.com/kurrik/oauth1a
go get github.com/kurrik/json
cd kurrik/json
mips-openwrt-linux-gccgo -c json.go
cd ../oauth1a
mips-openwrt-linux-gccgo -c oauth1a.go userconfig.go
cd ../twittergo
cp ../json/json.o .
cp ../oauth1a/oauth1a.o .
emacs twittergo.go  (change github.com/kurrik/oauth1a to oauth1a)
emacs models.go  (change github.com/kurrik/json to json)
mips-openwrt-linux-gccgo -c twittergo.go models.go
emacs tweetomega.go
mips_gccgo -Wall -o tweetomega main.go -static-libgo json.o  oauth1a.o twittergo.o

I was nearly there. The code ran but threw an error almost immediately about x509 root certs being missing. I ran all of the following, which seemed to fix it (but I’m not sure if all needed):

opkg update
opkg install ca-certificates
opkg install openssl-util
opkg install curl
wget http://curl.haxx.se/ca/cacert.pem
mv cacert.pem /etc/ssl/certs/ca-certificates.crt
scp conor@ .
scp conor@ .

And finally ta-daaaa, a Tweet from the Omega:

Tweetin Omega

I now suspect that the Node.js error may have been exactly the same thing but just hidden so I’ll go back and try the same for it.

Final notes

  1. That custom firmware I built is missing all of the Onion’s own stuff and I’m not sure how to add that. However you can easily re-install the latest factory Onion image by wgetting it using the URL you find in this file into /tmp using sysupgrade name_of_image.
  2. We really need Go 1.6 to support MIPS. I think the Onion is a great device for running Go. We might even get Gobots running.

03 Nov 2015, 08:22

All the gory tech behind our Halloween Hallway of Horror

Despite starting weeks earlier than usual, Halloween still involved a day of last minute panic to bring everything together. The end result was this:

The basic setup was an update of ideas from previous years and consisted of the following.

3D-printed Mummy in Coffin Doorbell

This was my favourite aspect of the whole thing. I spotted a cool 3D design on Thingiverse and realised I could turn it into a doorbell by dremeling a hole in the back and hot-glueing the mummy to a simple push button.

Mummy Doorbell 1

In fact the button was one I originally bought in 2012 when I got back into electronics. There was a small bug in my debounce code which I discovered too late and meant that kids had to press the button twice. But overall only a few failed to figure it out.

Mummy Doorbell 2

Adafruit Audio breakout board and amp with speakers

I had intended everything to be Arduino and ESP8266 (running Arduino code) only so I needed some way of playing the scream. In previous years I used a Raspberry Pi (successfully) and a really crappy device (less successfully).

In a bizarre twist to the BE Maker Kit Indiegogo scam, one of the people involved somehow got a Florida company to provide free electronics to the right amount. I used this to buy the Adafruit VS1053 Audio board and Adafruit MAX98306 Audio Amp. The wiring on this looks complicated but it’s straight out of their tutorial.

Scary Sounds

Audio was courtesy of youtube-dl and WinFF on this clip from YouTube.

The Arduino Nano for this was the “Master” device. It detected the doorbell press and then started playing the file on the SD card and sent a high signal both to the Banana Pi for the LED strip and the Arduino Uno for the relays controlling the skull. It’s basically the Adafruit demo VS1053 code with a few extra lines added by me. The code for that is here on Gist.

Wifi Controlled RGB LED Strip using a Banana Pi

I finally ordered a bog-standard 5 metre 5050 RGB LED strip from dx.com over the summer. The value on these things is just staggering at less than €20.


They come with a dedicated remote control and just need a decent PSU to provide the power. Myself and the kids had great fun illuminating my entire home office in a range of colours.

But the challenge for Halloween was how to control it. I could have run irrecord on an ODROID C1 or Banana Pi to reverse engineer the remote control protocol and then use the RC transmitter I bought on DX. But luckily someone told Hackaday about the first ESP8266-powered commercial product they had found. It was a €9 Wifi H801 control module for RGB LED strips! I just had to get one.


It’s a brilliant little box that is easy to wire up and has a simple Android App for control. You connect to the internal Wifi Access Point it provides to do this. Here is the brilliant piece: You then use the app to tell the module to connect to your own Wifi router and then you do the same with the phone. Now your RGB LED strip is on your network!

But it gets better. A very smart person reverse-engineered the basic over-the-air protocol that the app uses to control the Wifi module. Unfortunately he was using a slightly different module to me and it didn’t work. I then spent a week of evenings learning all about Wireshark and Netcat. I was able to do the same as him and find the basic UDP control protocol (only minor difference in the packets)

In summary:

  • OFF: \xfb\xeb\x00\x00\x00\x00\x00\x9f\x97\x9d\x00
  • RED: \xfb\xeb\xff\x00\x00\x00\x00\x9f\x97\x9d\x00
  • GREEN: \xfb\xeb\x00\xff\x00\x00\x00\x9f\x97\x9d\x00
  • BLUE: \xfb\xeb\x00\x00\xff\x00\x00\x9f\x97\x9d\x00

My plan was to use a NodeMCU ESP8266 module to send the relevant commands, using either NodeMCU LUA or the Arduino port to ESP8266 but I ran out of time to experiment.

So I had Netcat working happily on the Banana Pi running Fedora but I also needed to be able to use the GPIO pins to tell the BPi when to turn on/off the LED strip. I then made the classic mistake of panicking on Halloween morning and switching to the RaspberryPi so I could use WiringPi for GPIO. Except the Netcat commands hung on the RPi (still no idea why).

Some Googling revealed that WiringPi had been ported to Raspbian on the BPi so I tried that. Same Netcat problem! So I took a chance and re-inserted the Fedora SD card and downloaded the BPi version of WiringPi. Result! It compiled and ran perfectly.

The I moved on to several hours of trying to write a Bash script to monitor a GPIO pin using WiringPi and control the RGB LED strip with echo/netcat. All I will say about that is I am never ever writing a Bash script again (space-sensitive around brackets/equals for the love of god). This is the final result and, to be fair, it worked seamlessly:

sets=`/usr/local/bin/gpio mode 7 down`
echo -e '\xfb\xeb\x00\x00\x00\x00\x00\x9f\x97\x9d\x00' | nc -v -u 30977
sleep 1
while :
    pins=`/usr/local/bin/gpio read 7`
    if [ $pins = "1" ]; then
        if [ $state = "low" ]; then
            echo -e '\xfb\xeb\xff\x00\x00\x00\x00\x9f\x97\x9d\x00' | nc -v -u 30977
            echo high 
        if [ $state = "high" ]; then
           echo -e '\xfb\xeb\x00\x00\x00\x00\x00\x9f\x97\x9d\x00' | nc -v -u 30977
           echo low

But I was so horrified by Bash, I did a quick and dirty re-write to Go this morning. It uses the Golang bindings to WiringPi and seems to work very well.

So the strip was now sorted. On to the rotating skull.

An anatomically correct skull with scary eyes

The skull idea came from a wonderful tested.com video where special effects artist Frank Ippolito bought a cheap skull on Amazon and then used latex, cotton wool and paint to turn it into a horrific burn-victim thing.

I thought we could do the same and found a skull on Amazon UK. It arrived and looked great apart from the lack of a movable jaw. But it then sat there for months with no progress due to me being artistically challenged.

As an alternative I thought about doing something with eyes so I got some half-eyes from Amazon too They were a smidge small but fit for purpose. I grabbed some of my old tiny micro-servos which I have never found a use for and hot-glued the eyes to them. A bit of messing with the range of movement and I had a vaguely spooky setup.

But the fact that you could see the servos and they move pretty slowly meant I was a bit disappointed. I tried to vamp them up a bit more by adding neopixel ring but it was too big so I switched to a single funky Adafruit RGB neopixel on each one. So now I had 6 wires coming out of each eye.

Finally on Saturday morning I went to finish this bit and decided it was too much work to get the Arduino code tweaked to do 2x Neopixels and 2x servos and somehow trigger them on/off on a potentially rotating head. At this point I found the silly fake-eye pingpong balls from last year. A quick cut in the back and I hot-glued a Neopixel to each one. I then hot-glued the eyes into the skull and wired the Neopixels to an Arduino Nano.

Skull Arduino

I stuck the Nano and a Lipo battery to the top of the skull and covered it with a cool Buff. Having the eyes on permanently removed a little bit of the element of surprise but I still thought it worked well. The code for the Neopixels was just the standard Adafruit strand test.

Buff Skull

Making the skull rotate

I had always known I would rotate the skull in some fashion but for a while I wasn’t sure how. Quite a few weeks ago I came up with the idea to cement a hex driver into the bottom of the skull and sit it on top of a cheap crap €20 electric screwdriver I got ages ago from Woodies.


As a screwdriver it was rubbish due to slowness and lack of torque. As a skull-rotator it was awesome, spinning the skull around at high speed.


Of course I left the difficult bits until a week before Halloween when I sat down and tried to figure out how to control it all. The first attempt was with a dirt cheap double relay board I got 3 years ago and never used. But I couldn’t figure out how to make it go forwards and reverse. I then tried an old knock-off Adafruit Motor Shield but it couldn’t deliver enough juice (even with a 7.2V LiPo) to overcome the motor’s inertia. Finally I found a relay circuit that did forward/reverse and it worked like a charm.



But how was I going to handle starting/stopping the skull so it was facing away (and potentially covered) initially and then rotating at the right time and stopping in the right position? Of course I left that to Halloween itself.

I used polystyrene and duct tape to brace the screwdriver. Then I setup two limit switches. I then applied power. The head spun around and ripped the switches off their mounts. Damn. So another quick executive decision was made. The head would start rotating when the doorbell was pressed and then stop after 10-15 seconds. Which meant some kids would get the full scary effect whilst others would see the flashing eyes before they got to the door.

Tying it all together

This turned out to be pretty easy. I have a ton of decent wire from a dead Christmas tree light string and used that to connect everything up. The doorbell connected to one Arudino which then toggled a pin which the other Arduinos were connected to. After N seconds, it toggled the pin the other way to shut it all down.


It worked very very well.

Next year?

Hmm not sure. I wanted to do something with ghosts flying down zip wires a few years ago but I just didn’t have the knowhow. I’m feeling a lot more confident about that now.