My Raspberry Pi Zero W Portable Development Server

I love my iPad, it’s a great, very portable device that I can use for almost everything. Unfortunately the almost for most people is a deal breaker – but I’m stubborn and see these things as a problem to be solved rather than a reason to use another device!

One of my most frequently used “tools” are servers – if you can call a server a tool. This blog runs on one, as does Automation Orchard, as well as a lot of little scripts which make my life easier. Unfortunately having an entire server running locally on an iPad isn’t quite possible yet – apps like DraftCode Offline PHP IDE are fabulous and can even run WordPress – but sometimes needs must, and you need something that is less restricted. This is where my Raspberry Pi Zero W comes into play.

The Raspberry Pi Zero W, for those of you not familiar with it, is an extremely small headless computer – it doesn’t have a screen – indeed when you buy it you just get the board, that’s it! The hard drive is a micro SD card, and it sports a few ports – 2 micro USB (one for power), and a mini HDMI. How on earth can you connect to that with an iPad?

The answer is not the shortest or easiest, but it does sound simple: wifi. I have set my Raspberry Pi up so that when it boots up it creates a wifi network, of course this doesn’t create an internet connection, but that’s not what we’re after here. I won’t go into the steps of setting this up here, instead I recommend you follow this guide: Setting Up a Raspberry Pi as an Access Point in a Standalone Network (NAT)

The other part I needed to do was to make sure the Pi would always have the same IP address. This allows me to use use Workflow to control it via SSH, and connect to it with Coda which lets me hook right into the device and has great syntax highlighting. As I mostly program for the web with PHP I use Coda in split screen with Safari which I can refresh to see the results of what I’m doing.

I use a CMS called Grav, and they have a nice little guide to help you set up the Raspberry Pi to run it – there are guides to set up most CMS on a Pi if you look.

Why would I do all of this over using something like Linode or Digital Ocean, you might ask. It’s a very simple answer: internet isn’t always a given. I travel a lot, and most of my flights do not have wifi (and those that do charge a fortune for it). Even trains go through tunnels where you lose your connection. If you always have wifi or cellular data then you can avoid carrying a tiny computer, cable and battery pack along with your iPad, but if you don’t then this is a very small combination that gives you a lot of power.

Hardware in use:

Creating My Own Raspberry Pi HomeKit Controlled Light

I recently bought a Raspberry Pi Zero W mood light kit on Pimoroni. I’ve been looking for a project to practice my python and thought playing with lights would be fun. After assembling said light (I recommend the solderless set by the way, unless you really like soldering) and playing with it, I wanted to control it along with the Philips Hue lights which are around my desk – via HomeKit.

Pimoroni has a guide to set up Mote lights via HomeKit, so with some tweaking I got it running.

Make sure you install the software first. Then I had to modify their code – I don’t have Mote lights, but I have the Unicorn pHAT. So instead of importing mote I had to import unicornhat, and very importantly I had to change the dimension of the lights – if you try to set lights that don’t exist on the unicorn pHAT then it won’t work. Despite doing this I had some problems with floats being returned instead of integers, so I changed all the division to use // instead of / which resolved that issue nicely. Here’s the code for the API:

#!/usr/bin/env python
from colorsys import hsv_to_rgb, rgb_to_hsv
import unicornhat as unicorn
from flask import Flask, jsonify, make_response

app = Flask(__name__)
width, height = unicorn.get_shape()

colour = 'FFFFFF'
status = 0

def hex_to_rgb(value):
    value = value.lstrip('#')
    length = len(value)
    return tuple(int(value[i:i + length // 3], 16) for i in range(0, length, length // 3))

def unicorn_on(c):
    r, g, b = hex_to_rgb(c)
    for channel in range(width):
        for pixel in range(height):
            unicorn.set_pixel(channel, pixel, int(r), int(g), int(b))
    return True

def unicorn_off():
    return True

def get_status():
    global status
    for channel in range(width):
        for pixel in range(height):
            if unicorn.get_pixel(channel, pixel) != (0, 0, 0):
                status = 1
    return status

@app.route('/unicorn/api/v1.0/<string:st>', methods=['GET'])
def set_status(st):
    global status, colour
    if st == 'on':
        status = 1
    elif st == 'off':
        status = 0
    elif st == 'status':
        status = get_status()
    return jsonify({'status': status, 'colour': colour})

@app.route('/unicorn/api/v1.0/set', methods=['GET'])
def get_colour():
    global colour
    return jsonify({'status': status, 'colour': colour})

@app.route('/unicorn/api/v1.0/set/<string:c>', methods=['GET'])
def set_colour(c):
    global status, colour
    colour = c
    if status != 0:
        status = 1
    return jsonify({'status': status, 'colour': colour})

def not_found(error):
    return make_response(jsonify({'error': 'Not found'}), 404)

if __name__ == '__main__':
    unicorn_off()'', debug=True)

(I can’t claim any credit here, I just modified their example to work for the unicorn pHAT instead of Mote.)

Next I had to add the light to my HomeBridge installation. I ran sudo npm install -g homebridge-better-http-rgb, added the following configuration and restarted HomeBridge. Make sure to replace the IP address with your light, or with localhost if you’re running HomeBridge on the same machine as your light.

          "accessory": "HTTP-RGB",
          "name": "MoodLight",

          "switch": {
              "status": "",
              "powerOn": "",
              "powerOff": ""

          "brightness": {
              "status": "",
              "url": ""

          "color": {
              "status": "",
              "url": "",
              "brightness": true

Here’s a video of the light in action.