Note: These are rough notes and there may be some variance as versions of raspbian get updated but should be pretty reliable as a guide.
This gist provides some instructions and config in order to have your Raspberry PI automatically connect to a roamed network, however if it fails to discover an available network it will set itself up as a wireless access point for you to connect to.
- Raspberry Pi running Raspbian (latest is test on Jessie)
- you're able to get onto a normal wireless network without any issues at all with your default set up.
- drivers for your wireless device if you need it or a RPi3 with WiFi working.
Ensure the following packages are installed:
apt-get install hostapd wpasupplicant dnsmasq
Now make sure dnsmasq and hostapd don't start as a service every time you boot as we only want this to happen selectively.
update-rc.d -f hostapd remove
update-rc.d -f dnsmasq remove
If you haven't got your network interfaces configured to use wpa_supplicant then do this now and test it is all correct and you can connect reliably to at least one network.
To do this you want a config file in /etc/wpa_supplicant/wpa_supplicant.conf (see the file in this gist for example) that has your roaming network definitions. To get a network definition do this:
wpa-passphrase SSID KEY
And it will output something that looks like this:
network={
ssid="SSID"
#psk="KEYKEYLEYKEY"
psk=fef26ff30be96e6149511e66d2530d21b65b24dbf2908f9b44f7834574e1d048
}
At this point you want to add an "id_str" element so you can determine which network is which when you have multiple, so your config now looks like:
network={
id_str="test_network"
ssid="SSID"
#psk="KEYKEYLEYKEY"
psk=fef26ff30be96e6149511e66d2530d21b65b24dbf2908f9b44f7834574e1d048
}
Add this network config to the wpa_supplicant.conf file. You can add as many of these as individual blocks as you have networks to attach to. Just remember to add your id_str to each one so you can reference it from your network interfaces in a moment.
Okay so now wpa_supplicant is configured, you want to set up your network interfaces in /etc/network/interfaces
See the attached interfaces file and note the wlan stanza - you may need to change this to the device you use.
iface wlan0 inet manual
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
Here we're saying to use wpa-roam which will check the config file we just made for rules and try to find an appropriate network.
You'll also need to add a line that looks like this to the interfaces file after your wlan interface definition:
iface test_network inet dhcp
Notice we're making reference to the name of the network we defined in the wpa_supplicant config. This gives us a hook to define different configs for each network. Mostly you'll use DHCP, but you can use static definitions in here as well if you want your device to come up on a specific IP. Standard iface stanza config applies within each of these sections.
Restart your device and make sure this is all working properly before progressing forward as you want this to work flawlessly every time during boot up.
With more modern versions of raspbian the startup runs in parallel. As such you need to drop the network part of this into wait mode or you'll get conflicts during the start up.
raspi-config
Select "Wait for network at boot" and select "Yes".
This will add a few seconds to each boot stage but makes it fair more robust.
Change the /etc/default/hostapd file to include this line:
DAEMON_CONF="/etc/hostapd/hostapd.conf"
Now create the /etc/hostapd/hostapd.conf file and look at the example attached to this gist. Note you'll probably need to change the interface, the ssid and the wpa_passphrase to something of use for you. Also note the segments that are related to the nl chip being used on an RPi 3 as this has some extra configuration requirements.
Once you have this done run hostapd to just check any config errors. Before
you do this you'll probably want to kill your wireless device with ifdown wlanX
as hostapd will try to configure it and you may run into issues.
hostapd -d /etc/hostapd/hostapd.conf
If you get no errors, background the task and then tail -f /var/log/syslog
and then attempt
to associate to the wifi network with another device, you should see all of the
handshake messages occurring from hostapd and your device. At this point you
won't get an IP but you should see the association (and disassociation if you
drop your connection).
If you get no errors, then background the task and then look at ifconfig. You should now have the wlanX interface up as well as a wlanX.mon interface. If this is all good then you know your config is working for hostapd.
The last piece is to get dnsmasq running. This is fairly straight forward
Use the example in this gist and note that you want to change the interface you listen on and you might want to set your own DHCP-range. Write down what IP address range you want to operate on as you'll need this in a bit. In this example we're using the 192.168.40.0 network.
That's pretty much all you really need to make it work.
Do this:
ifdown wlanX
service hostapd start
ifconfig wlanX 192.168.40.1
service dnsmasq start
Note that we're configuring the IP after we set up hostapd. This is a quirk that we have to deal with as hostapd can't be bound to an aliased network interface which is annoying as it means we can't use ifup and a network stanza.
Now tail -f /var/log/syslog
If there's no errors, connect to the wireless AP from another machine and you should see all the hand shaking etc happen and you should then be able to ping each machine that has joined the network.
Success!!
To make this work at boot you need to use an rc.local script. /etc/rc.local is the very last thing that runs during init just prior to the shell being made available.
See the example provided in rc.local. The idea here is that you check to see if the network is up - if it is it means you've associated using wpa_supplicant roaming settings or are plugged into the network. If this hasn't ocurred then it goes through the process that we did manually above to create the hotspot.
As I have this on a robot, I actually use the RPi GPIO pins to light up LEDs during rc.local's execution to tell me what is going on. This is pretty easy and is readily googleable but very useful if you don't have a monitor and can't use a serial terminal.
Minor correction: On Raspbian stretch, the command
wpa-passphrase
is invalid andwpa_passphrase
should be used instead. (Can't confirm for Jessie)