Using resin-wifi-connect on Raspberry Pi without Docker

Published on 28 October 2015

This is a post about .

UPDATE 2016-02-20: The previous version of these instructions didn't work properly. I've updated them with missing files and required config.

UPDATE 2016-06-09: Clarified newer nodejs installation instructions and installing from Raspbian Jessie Lite. Added automatic install instructions using radiodan/provision.

Resin provides a great platform for enabling Heroku-style deployment for Internet of Things devices. They recently released wifi-connect, a great application that enables limited-input devices to be configured to connect to wifi networks.

This is a very similar interaction approach to the Radiodan wifi-configuration tool that I worked on previously. Resin have taken a different technical approach, using connman, a configuration tool from the Yocto project whereas we used wpa_supplicant directly. They're also using bind9 and iptables to provide the captive portal functionality compared to our use of dnsmasq, hostapd and nginx.

Their in-process approach feels like is should be more stable and controllable than our scripted one which always felt a bit hacky.

So, I thought I'd try to get the resin-wifi-connect code running on a standard Raspbian Raspberry Pi without Docker or the resin base image.

Automatic way

You can use the Radiodan provisioner to automatically install what you need.

After installing Raspbian Jessie (step 1 below), follow the instructions in the Readme.

In the final step (7), instead of sudo ./provision all, just run:

sudo ./provision iptables node wifi-connect

When done, reboot and you'll have a version of wifi-connect that broadcasts the SSID radiodan-configuration.

You can change this, and require a password when connecting to the wifi network by editing /etc/systemd/system/wifi-connect.service.

Manual install steps

1. Install Raspbian Jessie

I started with the Raspian Jessie image.

Expand the filesystem using sudo raspi-config otherwise you'll run out of space.

If you use Raspbian Jessie Lite then you need to follow step 1a too.

1.a Rasbpian Jessie Lite

Jessie Lite doesn't come with some essential stuff installed so you'll need to install it.

$ sudo apt-get update && sudo apt-get install -y \
git

2. Install dependencies listed in the Docker file

  $ sudo apt-get update && sudo apt-get install -y \
    bind9 \
    bridge-utils \
    connman \
    iptables \
    libdbus-1-dev \
    libexpat-dev \
    net-tools \
    usbutils \
    wireless-tools

3. Disable bind9

You don't want bind9 to start on boot since wifi-connect will start it when appropriate.

$ sudo systemctl stop bind9.service
$ sudo systemctl disable bind9.service

4. Change ownership of bind9 key file

$ sudo chown root /etc/bind/rndc.key

5. Config for connman

sudo mkdir /etc/connman

sudo pico /etc/connman/main.conf
[General]
PreferredTechnologies=ethernet,wifi
SingleConnectedTechnology=false
NetworkInterfaceBlacklist=rce,veth,tun
FallbackTimeservers=pool.ntp.org
FallbackNameservers=8.8.8.8,8.8.4.4

6. Install nodejs

I installed nodejs using the radiodan provisioner like this sudo ./provision node.

You can just run the following script directly but you'll need to run them as sudo:

Become super:

sudo su

Install node:

mkdir -pv /opt/node && \
  $(curl -L https://nodejs.org/dist/v5.10.0/node-v5.10.0-linux-armv6l.tar.gz | tar xz --strip-components 1 -C /opt/node) && \
  ln -sf /opt/node/bin/node /usr/local/bin/node && \
  ln -sf /opt/node/bin/npm /usr/local/bin/npm && \
  /opt/node/bin/npm config set prefix /usr/local

Exit super mode:

exit

7. Get the radiodan/resin-wifi-connect fork that works with newer versions of nodejs:

$ git clone https://github.com/radiodan/resin-wifi-connect

8. Install module dependencies

Install node modules:

pi@raspberrypi ~ $ cd resin-wifi-connect/
pi@raspberrypi ~/resin-wifi-connect $ JOBS=MAX npm install --production

9. Install assets for the web interface

pi@raspberrypi ~/resin-wifi-connect $ ./node_modules/.bin/bower install

10. Compile the coffeescript script code to javascript

pi@raspberrypi ~/resin-wifi-connect $ ./node_modules/.bin/coffee -c ./src

11. Copy bind assets into place

pi@raspberrypi ~/resin-wifi-connect $ sudo cp ./assets/bind/* /etc/bind/

12. Create a data directory in the root of the system

This is where wifi network credentials are saved.

$ sudo mkdir /data

13. Configure a password (required)

Connman requires the network hotspot that it will create to have a password of 8 characters or more. Resin have patched connman to work aroudn this. But using that would mean recompiling connmand using their patches.

To change the password, just edit src/wifi.json. And fix the typo of the "passhprase": null property, it should be passphrase.

{
    "ssid": "ResinAP",
    "passphrase": "password",
    "port": 8080
}

14. Make sure nothing else starts wpa_supplicant

Comment out most of /etc/network/interfaces since connman will be managing our network connections.

# interfaces(5) file used by ifup(8) and ifdown(8)

# Please note that this file is written to be used with dhcpcd
# For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf'

# Include files from /etc/network/interfaces.d:
source-directory /etc/network/interfaces.d

auto lo
iface lo inet loopback

# iface eth0 inet manual

# allow-hotplug wlan0
# iface wlan0 inet manual
#     wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

# allow-hotplug wlan1
# iface wlan1 inet manual
#     wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

15. Override default connman service to start with --no-proxy flag

Without this, connman interferes with bind and things don't work.

Connman installs its own service file in /lib/systemd/system/connman.service. Make a copy in /etc/systemd/system/ to override it:

$ sudo cp /lib/systemd/system/connman.service /etc/systemd/system/

Then edit the copied file to add the --nodnsproxy flag to the line that starts with ExecStart=/usr/sbin/connmand -n.

I'd also change the line to output logging to the system log:

StandardOutput=syslog
SyslogIdentifier=connman

The edited file should look like this:

[Unit]
Description=Connection service

[Service]
Type=dbus
BusName=net.connman
Restart=on-failure
ExecStart=/usr/sbin/connmand -n --nodnsproxy
StandardOutput=syslog
SyslogIdentifier=connman

[Install]
WantedBy=multi-user.target

16. Start resin-wifi-connect service on boot

Jessie comes with systemd as the way of starting and stopping applications.

Create a file named resin-wifi-connect.service in /etc/systemd/system/. You can use nano to do this:

sudo pico /etc/systemd/system/resin-wifi-connect.service

Paste the following contents into the file:

[Unit]
Description=Configure wifi
Requires=connman.service dhcpcd.service
After=connman.service dhcpcd.service

[Service]
WorkingDirectory=/home/pi/resin-wifi-connect
ExecStart=/home/pi/resin-wifi-connect/start
Restart=on-failure
StandardOutput=syslog
SyslogIdentifier=resin-wifi-connect
Type=idle

[Install]
WantedBy=multi-user.target

17. Make the startup script editable

chmod +x /home/pi/resin-wifi-connect/start

Finally, enable the new service so that it runs every time the Pi starts up.

sudo systemctl enable resin-wifi-connect

That's it!

Phew! When you restart your Pi and it can't connect to wifi then it will create a network called ResinAP with whatever password you specified in ~/resin-wifi-connect/src/wifi.json. Connecting the network will open a page where you can configure the wifi credentials the Pi should join.

The resin-wifi-connect service will exit when it successfully connects to a wifi network. So, to go through the process again, you just need to reboot your Pi.

I'd be keen to hear how others get on with this so ping me on Twitter.