Wednesday 7 June 2017

Basic Bluetooth Network using Raspbian Jessie

Recently I wanted to setup a Bluetooth network to allow several Raspberry Pis to communicate amongst themselves and, as I'd not done this before, tried to search for articles on how to achieve this. I managed to find many, many articles covering this subject, unfortunately they tended to be either out of date (e.g. using Raspbian Wheezy + BlueZ 4.x), incomplete (starting from X do Y, without explaining how to achieve X) or just plain confusing.

After some further research, plus plenty of trial and error, I eventually got a bluetooth network up and running, connecting together one Raspberry Pi 3 with four Raspberry Pi Zero Ws, and decided to document the steps I took for my own reference, as well as for anyone else who would like to achieve the same.

To setup the Bluetooth network we need to allocate one Raspberry Pi to act as the central hub, responsible for allocating IP addresses, IP forwarding (if needed), along with one or more client Raspberry Pis to connect to it.

Setting up the Hub

  • Download the latest Raspbian image (Here I am using 2017-04-10-raspbian-jessie-lite.zip) and write to an SD Card.
  • Boot the Raspberry Pi, login and run the 'raspi-config' application.
pi@raspberrypi:~$ sudo raspi-config
  • Select option 2 to change the hostname, setting it to 'hub'.
  • Select 'Finish', followed by 'Yes' to reboot.
  • Wait for the Raspberry Pi to reboot and log in again.
  • Setup a network connection. Depending on your setup this can be either by plugging in an Ethernet cable or by setting up a Wireless connection.
  • Install the packages required for setting up the bluetooth network.
pi@hub:~$ sudo apt-get install bluez-test-scripts bridge-utils dnsmasq python-dbus
  • Next we need to add the network interface we'll be using for Bluetooth. Edit the /etc/network/interfaces file and add the following to it.
auto pan0
 iface pan0 inet static
         address 172.168.10.1
         netmask 255.255.255.0
         bridge-ports none
         bridge-fd 0
  • And then we need to configure dnsmasq to listen on the pan0 interface and assign IP addresses in the correct range. Edit the /etc/dnsmasq.conf file and add the following
domain-needed
 bogus-priv
 no-resolv
 no-poll
 server=8.8.8.8
 local=/localnet/
 interface=pan0
 no-hosts
 expand-hosts
 domain=local
 # Enable DHCP for the 172.168.200.X range
 dhcp-range=172.168.10.10,172.168.10.50,12h
  • To setup the bluetooth network we'll be using one of the BlueZ test scripts (installed as part of the bluez-test-scripts package earlier), however the test script exits after 16 minutes, so we need to copy and edit the script.
pi@hub:~$ sudo cp /usr/share/doc/bluez-test-scripts/examples/bluezutils.py /usr/local/sbin/
pi@hub:~$ sudo cp /usr/share/doc/bluez-test-scripts/examples/test-nap /usr/local/sbin/
pi@hub:~$ sudo chmod +x  /usr/local/sbin/test-nap
  • To keep the script running edit /usr/local/sbin/test-nap and change the lines :-
try:
        time.sleep(1000)
  • to
try:
        while True:
            time.sleep(1000)
  • We want the script to run at startup and one of the easiest ways is using the crontab file. Edit your crontab by running crontab -e and add the following line to the end.
@reboot sudo nohup /usr/local/sbin/test-nap pan0  &
  • Reboot once more (sudo reboot), log in and check that the pan0 interface exists, and the test-nap script is running.

pi@hub:~$ ifconfig pan0
pan0      Link encap:Ethernet  HWaddr da:87:54:2c:f8:66
          inet addr:172.168.10.1  Bcast:172.168.10.255  Mask:255.255.255.0
          inet6 addr: fe80::d887:54ff:fe2c:f866/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:60 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:9090 (8.8 KiB)

pi@hub:~$ ps ax | grep test-nap
   438 ?        S      0:00 sudo nohup /usr/local/sbin/test-nap pan0
   470 ?        S      0:00 /usr/bin/python /usr/local/sbin/test-nap pan0
   851 ttyS0    S+     0:00 grep --color=auto test-nap
  • If everything is running as expected we just need to take a note of the Bluetooth MAC so we can tell the clients who they need to contact. We can find this by running 'hciconfig dev'.

pi@hub:~$ hciconfig dev
hci0:   Type: BR/EDR  Bus: UART
        BD Address: B8:27:EB:25:A0:AE  ACL MTU: 1021:8  SCO MTU: 64:1
        UP RUNNING
        RX bytes:731 acl:0 sco:0 events:44 errors:0
        TX bytes:1784 acl:0 sco:0 commands:44 errors:0

Setting up a client

  • Download the latest Raspbian image (Here I am using 2017-04-10-raspbian-jessie-lite.zip) and write to an SD Card.
  • Boot the Raspberry Pi, login and run the 'raspi-config' application.
pi@raspberrypi:~$ sudo raspi-config
  • Select option 2 to change the hostname, change it to 'client0'.
  • Select 'Finish', followed by 'Yes' to reboot.
  • Wait for the Raspberry to reboot and log in again.
  • Setup a network connection. Depending on your setup this can be either by plugging in an Ethernet cable or by setting up a Wireless connection.
  • Install the packages required for setting up the bluetooth network.
pi@client0: sudo apt-get install python-dbus
  • Download a helper script for establishing the bluetooth network.
pi@client0:~ $ wget https://raw.githubusercontent.com/mk-fg/fgtk/master/bt-pan
pi@client0:~ $ sudo mv bt-pan /usr/local/sbin/
pi@client0:~ $ sudo chmod +x /usr/local/sbin/bt-pan
  • Again we want to run this script at startup, so run crontab -e and add the following, replacing the MAC Address with that of your bluetooth dongle.
@reboot sudo noup /usr/local/sbin/bt-pan client B8:27:EB:25:A0:AE &

Pair client to hub

Before the network can be established a bluetooth connection first needs to be setup between the client device and the hub. This is achieved by making use of the 'bluetoothctl' application.
  • First setup the client so it can be discovered by running the commands in bold below.
pi@client0:~ $ sudo bluetoothctl

[NEW] Controller B8:27:EB:5B:CB:74 client0 [default]
[bluetooth]# power on
Changing power on succeeded
[bluetooth]# discoverable on
Changing discoverable on succeeded
[CHG] Controller B8:27:EB:5B:CB:74 Discoverable: yes
  • Then scan for, and connect to it, from the hub (again using the commands in bold). Once its found we want to pair and trust the client to allow it to auto connect in future,

pi@hub:~$ sudo bluetoothctl
[NEW] Controller B8:27:EB:25:A0:AE hub [default]
[bluetooth]# power on
Changing power on succeeded
[bluetooth]# agent on
Agent registered
[bluetooth]# scan on
Discovery started
[CHG] Controller B8:27:EB:25:A0:AE Discovering: yes
[NEW] Device B8:27:EB:5B:CB:74 client0
[bluetooth]# pair B8:27:EB:5B:CB:74
Attempting to pair with B8:27:EB:5B:CB:74
[CHG] Device B8:27:EB:5B:CB:74 Connected: yes
[CHG] Device B8:27:EB:5B:CB:74 UUIDs:
        0000110c-0000-1000-8000-00805f9b34fb
        0000110e-0000-1000-8000-00805f9b34fb
        00001200-0000-1000-8000-00805f9b34fb
        00001800-0000-1000-8000-00805f9b34fb
        00001801-0000-1000-8000-00805f9b34fb
[CHG] Device B8:27:EB:5B:CB:74 Paired: yes
Pairing successful
[bluetooth]# trust B8:27:EB:5B:CB:74
[CHG] Device B8:27:EB:5B:CB:74 Trusted: yes
Changing B8:27:EB:5B:CB:74 trust succeeded
[CHG] Device B8:27:EB:5B:CB:74 Connected: no
[bluetooth]#
  • With the client paired and trusted we can exit out of the bluetoothctl app on both the hub and client by using the quit command.
  • To check that the Bluetooth network is working reboot the client device (sudo reboot), log in and check if the bnep0 interface now exists and has been assigned an IP address.

pi@client0:~ $ ifconfig bnep0
bnep0     Link encap:Ethernet  HWaddr b8:27:eb:5b:cb:74
          inet addr:172.168.10.45  Bcast:172.168.10.255  Mask:255.255.255.0
          inet6 addr: fe80::ba27:ebff:fe5b:cb74/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:60 errors:0 dropped:0 overruns:0 frame:0
          TX packets:53 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
  • To confirm the connection has been established attempt to connect to the hub from the client.

pi@client0:~ $ ping 172.168.10.1
PING 172.168.10.1 (172.168.10.1) 56(84) bytes of data.
64 bytes from 172.168.10.1: icmp_seq=1 ttl=64 time=190 ms
64 bytes from 172.168.10.1: icmp_seq=2 ttl=64 time=33.7 ms

--- 172.168.10.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 33.782/112.324/190.867/78.543 ms

If all has gone well you now have a working Bluetooth network, which you can now extend with multiple clients.

Optional extras

Setup static IP for a client

Sometimes its useful for a client to always be assigned the same IP address when it establishes the network connection and, luckily, this is easy to achieve.
  • First look up the client's bluetooth address using the 'hciconfig dev' command used earlier.
  • Then, on the hub, edit the /etc/dnsmasq.conf file and add the following entry, replacing the MAC with that of your client device.
dhcp-host=B8:27:EB:5B:CB:74,172.168.10.101,client0
    • Once the file has been updated we need to restart the dnsmasq service so the changes take effect.
    pi@hub:~$ sudo service dnsmasq restart
    • Now the next time the client requests an IP address it will receive the one listed in the file, and additional entries can be added for every client in the Bluetooth network.

    Enable IP port forwarding

    If your 'hub' Raspberry Pi has a Wireless or Ethernet network connection you can choose to share it with the client Raspberry Pis, in theory allowing them to access the internet via bluetooth.
    • To configure the 'hub' to forward its network connection first edit the /etc/sysctl.conf file and uncomment line 28 to read :-
    net.ipv4.ip_forward=1
    • Next edit the /etc/rc.local file and add, the following. Updating 'eth0' to match your upstream network interface (e.g. wlan0).
    
    # Enable port forwarding. Change eth0 to match the primary network connection name
    /sbin/iptables -P FORWARD ACCEPT
    /sbin/iptables --table nat -A POSTROUTING -o eth0 -j MASQUERADE
    • Finally reboot (sudo reboot), and you should now be able to access this shared network connection from any of the client Raspberry Pis.

    Wrap up

    Hopefully this set of instructions are relatively clear and cover all the steps needed to get a basic Bluetooth network up and running (Either using a Raspberry Pi with built in Bluetooth, or an older model with a USB bluetooth adaptor). More work would be needed to make this a robust solution (i.e. the client only tries to establish a connection when it first starts up) but its a solid base to build upon. In theory it should also work on none Raspberry Pi based hardware that is also running Debian Jessie or equivalent, but I've not tried myself.

    Whilst a bluetooth network is not as fast as a Wifi one (in my tests 200KB/s vs 1500KB/s) it uses slightly less power to run. On a PiZero W transferring files over WiFi seemed to pull about 0.1A more than when using Bluetooth, of course WiFi was also about 8 times faster. Not a huge difference, but if you are running the Raspberry Pi off battery, e.g. running a remote sensor, and are only transferring smaller amounts of data then this could add up to make a difference to the run time of the Pi.

    Leo