Using resin-wifi-connect on Raspberry Pi without Docker
Published on 28 October 2015
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.