Nerves on a Cellular Network with the Hologram Nova

I’ve been experimenting with a Nerves project lately that required a network connection on the go. I wanted to be able to run or connect to a Phoenix channel on a moving device, beyond the range of home WiFi.

Background — Skip if you want just the technical details

Initially I came across devices that provided low-level AT command interfaces for making network calls, but these quickly became limiting as each HTTP call required multiple AT commands to setup and run. Large payload posts or websocket connections were not reliably working.

During the 2018 ElixirConf I spoke to a few people in the Nerves community about the issues I was running into and got some pointers, what I needed was some way to establish a serial PPP session with a usb modem. I began looking around and found the Hologram Nova. This device plugs into a USB port and comes with a handy Python SDK, which had a function called connect that:

Connects to the specified network by establishing a PPP session.

This was exactly what I needed so I ordered one, set it up, and plugged it into the Pi:

Raspberry Pi 3B+ with the Hologram Nova plugged in

Everything powered up correctly, now I needed to figure out how to setup the connection from Elixir code. I didn’t know much about PPP or the details required so I started by first building a modified Nerves system that added Python and all the requirements for the Hologram Python SDK, then used export to call a Python function from Elixir that established the connection to the cellular network. Although this worked, it seemed a bit shaky because:

  • I had to copy the Python SDK locally and modify it in order to make it work with the Nerves setup (it internally used sudo)
  • The Python SDK had several parts I did not need and bloated my project (it has many features beyond just the PPP sessions that I was not using)
  • When installing with buildroot’s utils/scanpypi not all dependencies setup automatically, so I had to make some hacks to get it all to work

These reasons made the custom system hard to work with and maintain, and since I was only trying to connect to a PPP session I spent some time going through the Python SDK and pulling out what I needed. Below the steps indicate how to modify the base RPi3 Nerves system and how to connect to a cellular network through the Nova with just Elixir.

Modifying the Nerves System

To get this working you will need a modified Nerves system, the docs explain how to set this up (If your on a Mac you might run into issues building the system locally, if so Wendy Smoak’s article is a big help). Once you have a setup for modifying a system, the steps end up being fairly simple:

  • Enabling the USB option driver (communicating with the Nova depends on this)
  • Enabling several PPP related modules
  • Enable mknod via BusyBox

These changes come down to the following additions to the Nerves system files:

This file will need to be added to your system at the root level

Build the system with the above changes (I followed Wendy’s article and used nerves_system_br/ and export the output.

A complete modified example system with these changes is available here:

Connecting to the Cellular Network

Now that we have a custom system built we can load up a new Nerves project and go through step by step how to establish the network connection. Let’s start by using the generator to setup a new project:

mix cellular — init-gadget — target rpi3

In the config/config.exs file we want to setup the init-gadget config to use ethernet so we can ssh onto the Pi:

Now you should be able to run ssh nerves.local to open up an iex shell.

Let’s add HTTPoison to make it easy for us to test our connection, update your mix.exs file to include {:httpoison, "~> 1.4"}. Update your firmware and re-ssh onto your Pi, you should be able to run HTTPoison.get "" and get the following output:

** (HTTPoison.Error) :nxdomain
(httpoison) lib/httpoison.ex:128: HTTPoison.request!/5

Use the modified system from above by either linking to it in your mix.exs or by setting NERVES_SYSTEM in your env to point to the outputted system. To finish the setup there are two more files you will need to add to your nerves project rootfs_overlay directory in the following folders:


These two files define some configs and steps needed to establish connection to the Hologram network. To run this all, we can add a connect function to our application:

At this point you should be able to build the firmware and run the above function from iex. You should run this asynchronously, something similar toTask.async(fn -> Cellular.connect() end). This should establish a PPP session and connect to the network, test by running HTTPoison.get! "", this time you should get a response.

An example application for the above is available here:

A big thank you to the Nerves team for being very helpful on Slack and fantastic docs on how to go about modifying systems. If you find the need to do enable additional modules or add libraries the buildroot docs are also very helpful.