Sometimes, when a cloud-centric hack is useful or cool enough, you may want to make copies either to give your friends or sell to test out a market response.     This converts the hack from a one-off useful item that you know how to make, tweak and fix into a mini-product that must be maintained, and monitored as you update software, adjust cloud server plans, or add features to the product.   Keeping a small fleet of devices updated can quickly become a full-time job.    My need to monitor a mini-fleet of devices came about when I was making ETA Nixie Tube Clocks for my brother and Dad.    While my initial software was working, I knew I would be adding new features, fixing software bugs, and improving performance.  In addition, I wanted to allow easy wi-fi setup of the devices when they were installed at my relative’s homes.   This Blog post shows how this can be done with your Raspberry Pi project using the open source cloud environment.   Since this is an open source project, all the code is readily available at Github.  While the blog focuses on using the ETA Nixie Tube Clock as the example,  the steps can be similarly applied to other projects.

For IoT devices using the Raspberry Pi or other similar mini-computer platforms, is a cloud-based container control engine that makes the updating of multiple IoT devices super simple, and easy to implement.  You may not recognize, but they just changed their name from  They are also the author of Etcher, the great open source compact flash image burning tool.   With this environment, when I upgrade the ETA Nixie Tube Clock at my house, the Docker compatible container methodology of allows these updates to be applied to all the ETA Nixie Tube Clocks deployed around the globe.   

Step 1: Code a IoT Raspberry Pi Project   

     For this project, I started with the ETA Nixie Tube Clock.   This code worked well for a one-off project but was not ready to allow multiple upgrades and improvements when the same projects are deployed throughout the internet.   When using your own code, the key thing to determine is if you want data to be persistent when the code is being upgraded.   The ETA Nixie Tube Clock does require custom ETA travel locations and time zone data to be persistent between upgrades of the code. This data persistence will be addressed in a later step.  Ensure the code for this project is in a git repository and stored in the cloud at your own location or GitHub, as the Raspberry Pi flash memory card will be erased in the next step.    In addition, when upgrading your code using, you will use git.  

Step 2: Installing BalenaCloud 

Fortunately, has a very good step by step process of registering and installing your first device on the Raspberry Pi.    As you go through the steps, when you are at the Deploy code step, instead of using the example given, you can download to your local computer the code for the ETA Nixie Tube Clock as shown:  

git clone

Then continue with the step by step process. If you want to install your own code, you will need to also create a custom Dockerfile file,  you can use the ETA Nixie Tube Clock code as a guide.   This code uses Dockerfile.template to install all the correct environment software.  With the code installed, complete the step by step process by running the code to see that it works.  For the ETA Nixie Tube Clock, you also need to set up the device variables described in Step 4.   Once you get things working you will be able to monitor and maintain the fleet anywhere you have access to the internet.   

Updating ETA Nixie Tube Clock Code from 30,000 Feet while on an airplane wi-fi network

Step 3: Working with Multiple containers

Multiple containers are a powerful addition to the balenaCloud network because they allow a persistent storage volume on each device that will not be reinitialized after each code upgrade.    For the ETA Nixie Tube Clock, each clock will have unique destinations where traffic is collected and shown on the clock.  By adding this storage volume to the container, these destinations are not erased,  provided that the IoT code places this data in the correct location.   The docker-compose.yml file will set up this storage volume and name the correct location.      As shown below the data needs to be stored in /data.

version: '2'
        build: ./main
            - 'resin-data:/data'
        privileged: true
        restart: always
        network_mode: host
           io.resin.features.dbus: '1'

In the python code the locations.txt file is stored as follows so that code upgrades will not reset this information:

locatefile = "/data/locations.txt"

Step 4: Setting up the balenaCloud dashboard

When deploying the code, the balenaCloud dashboard is used to set up device variables,   monitor the operation of the code,  and even login to an individual device with a terminal interface for additional device setup and debug.     

The balenaCloud dashboard shows all the devices in the current fleet of devices.

BalenaCloud dashboard
BalenaCloud dashboard showing the status of the Fleet of devices

Before the ETANixieClock fleet can operate correctly, GOOGLEKEY (i.e. Google Maps API key) and TIMEZONE (i.e. Time zone from the tz database) information needs to be set.  These parameters will be passed to the container when it is started.    

Device Variables
Device Variables for the ETANixieclock fleet

After setting the device variables, you may need to restart the application for each device.   You can click on the ETANixieClock fleet to bring up a detailed dashboard showing the status of each device:

Detailed status of Dashboard
The detailed status of each device in the fleet.

Choosing an individual device will bring you to the log screen.   this shows the output from the program as it is running.  You can monitory this to see if any errors occur.   

To set up the ETA locations in the ETA Nixie Tube Clock, a terminal session will need to be started allowing you to run the  You can also use a terminal for debugging.   For example, the startup script Linux process that the ETA Nixie Tube clock is running within can be killed so that the program could be run.    

ps aux | grep
sudo kill < process number>

The following terminal window is located at the main ETA program location, ready to run the or programs. 

Terminal located in the main application directory

The balenaCloud dashboard is a powerful way to monitor and test your IoT devices as they are deployed into the field.   The next step describes how the wi-fi network can be set up with remote devices

Step 5: Remote IoT Device wi-fi Setup  

Easy setup of the wi-fi at a remote location is important for any deployed IoT device.    BalenaCloud created an open source Linux solution, wi-fi-connect, available on GitHub that makes it this straightforward.  If the wi-fi is not detectable when the device powers up, it will turn into an access point and run as a web server that scans the local networks.   This access point can be logged into using a smartphone so that the correct access point and password are chosen.   You need to do this within 5 minutes (300 minutes) or it will start without a wi-fi connection.    You will need to perform a power cycle to get out of this condition and the clock will not show the correct time.

Here is the code in the Dockerfile.template that shows the wi-fi-connect being installed inside the container       

# install wireless tool
# Use apt-get to install dependencies
RUN apt-get update && apt-get install -yq --no-install-recommends \
    dnsmasq wireless-tools && \
    apt-get clean && rm -rf /var/lib/apt/lists/*

WORKDIR /usr/src/app

#install the access point program
RUN curl -s \
    | grep -hoP 'browser_download_url": "\K.*%%RESIN_ARCH%%\.tar\.gz' \
    | xargs -n1 curl -Ls \
    | tar -xvz -C /usr/src/app/   

In the script below, it first looks for wi-fi connection and then will run the wifi-connect program if none is located.   


#start wifi-connect.  This will start an access point if none is found
export DBUS_SYSTEM_BUS_ADDRESS=unix:path=/host/run/dbus/system_bus_socket

#Is there an active WiFi connection?
iwgetid -r

if [ $? -eq 0 ]; then
    printf 'Skipping WiFi Connect\n'
    printf 'Starting WiFi Connect\n'
    # wifi connect will timeout after 5 minutes.   Giving lots of time 
    ./wifi-connect --portal-ssid="ETANixieClock Connect" --activity-timeout=300

# Default to UTC if no TIMEZONE env variable is set
echo "Setting time zone to ${TIMEZONE=America/Los_Angeles}"
# This only works on Debian-based images
echo "${TIMEZONE}" > /etc/timezone
dpkg-reconfigure tzdata

# GoogleKey will be passed from Resin
python /app/ ${GOOGLEKEY}

Also notice the TIMEZONE and GOOGLEKEY device variables that are set in the dashboard and how they are passed to the system timezone info and python script. 


After working with the balenaCloud for deploying a mini-fleet of ETA Nixie Tube Clocks, I see the power of this platform.   Now, when I  update the ETA clock at my house, , all the other ETA clocks get updated automatically.  This is a super simple device upgrade flow, and many IoT device can benefit from this capability. is also working to make their code open source, widening its acceptance and helping ensure that support will be available in the future.   Right now my devices use the free version of the service.   As I develop other platforms, I may need to purchase a larger fleet deployment.  The pricing for more nodes seems reasonable, ultimately saving money and development costs associated with developing my own IoT upgrade and monitoring capability.  BalenaCloul has done all the hard work and was easy to implement.      

I hope you enjoyed this blog entry.    Please leave your comments below.   Have a great time deploying your next IoT inventions.   🙂