This adventure covers transferring temperature data from Beaglebone Black over Meshblu using MQTT, Bluetooth and/or WiFi. The part about displaying the data on a dashboard using Freeboard will eventually be written at some point.


  1. Remote Linux server or machine to install Meshblu and Freeboard. (could be a local machine too)
  2. Beaglebone Black
  3. AM2302 temperature sensor

Network on the Bone

The first step is to get the BBB connected to the Internet/cloud. If you have access to wired ethernet, this is trivial. But if not, it is important to be able to use Bluetooth or WiFi. BT is interesting because we could potentially pair the Bone with a phone, while using the phone's WiFi connection. This avoids creating a WiFi hotspot and using the Data on the phone.

The latest Debian images for the BBB, come with all packages preinstalled to support BT and WiFi out of the box (i.e. packages are installed, it still needs configuration).

This note assumes that you've downloaded and installed the latest Debian image, that the Bone is connected to the host using ssh on the USB interface.

$ uname -a
Linux beaglebone 3.8.13-bone70 #1 SMP Fri Jan 23 02:15:42 UTC 2015 armv7l GNU/Linux




Connect the dongle to the Bone and verify if it is detected. lsusb is part of the usbutils package and may need to be installed.

$ lsusb
Bus 001 Device 003: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

$ service bluetooth status
bluetooth.service - Bluetooth service
      Loaded: loaded (/lib/systemd/system/bluetooth.service; enabled)
      Active: active (running) since Sun, 02 Aug 2015 22:09:36 -0400; 56min ago
    Main PID: 6610 (bluetoothd)
      CGroup: name=systemd:/system/bluetooth.service
          └ 6610 /usr/sbin/bluetoothd -n

$ hcitool scan
Scanning ...
    80:E6:50:16:9D:5B   MacBook Pro

Pairing the dongle and Internet host

This did not work for me, but theoretically it should work:

$ sudo hcitool cc 80:E6:50:16:9D:5B
$ sudo hcitool auth 80:E6:50:16:9D:5B

If this works then the following steps are unnecessary to a pair with host (gateway). Don't know if pairing is necessary for PAN to work. But probably yes. TTD: Try PAN without pairing

Use sdptool to look for records of services offered by host (gateway). Make the host / phone discoverable in the BT menu.

$ sdptool records 80:E6:50:16:9D:5B

Look for RFCOMM channel information. On my MBP this is shown as:

Service Name: Bluetooth-Incoming-Port
Service RecHandle: 0x10004
Service Class ID List:
  "Serial Port" (0x1101)
Protocol Descriptor List:
  "L2CAP" (0x0100)
  "RFCOMM" (0x0003)
    Channel: 3

Edit /etc/bluetooth/rfcomm.conf as follows:

rfcomm0 {
    # Automatically bind the device at startup
    bind no;

    # Bluetooth address of the device
    device 80:E6:50:16:9D:5B;

    # RFCOMM channel for the connection
    channel 3;

    # Description of the connection
    comment "CSR 4.0 on BBB";

Pair the dongle with host computer:

$ sudo bluetooth-agent 1234 &

This should bring up a pairing dialog on the host, enter the pin 1234 to confirm. Connect the device using RFCOMM to test the BT works.

$ sudo rfcomm connect hci0 80:E6:50:16:9D:5B &

Disconnect RFCOMM as we don't really used it for PAN, but only to setup and test the pairing.

$ sudo rfcomm release hci0


After this worked, I accidently deleted the device from my MBP when I pressed the "x" in the Bluetooth menu. After that, for the longest time I couldn't get this to work with my MBP, as the device would not be detected. Finally got it to work after making the BBB discoverable using dbus commands:

$ export BTADAPTER=`dbus-send --system --dest=org.bluez --print-reply / org.bluez.Manager.DefaultAdapter | tail -1 | sed 's/^.*"\(.*\)".*$/\1/'`
$ dbus-send --system --dest=org.bluez --print-reply $BTADAPTER org.bluez.Adapter.SetProperty string:Discoverable variant:boolean:true

Once the device was discoverable, the agent and rfcomm commands worked without problem.


Now that we know that the host the discoverable and paired, we can use pand to connect to the Internet.

Share your computer's or phone's WiFi using the respective menus. On a Mac, this is done using the Sharing menu and choosing the Bluetooth PAN as the connection interface. On Android, use Bluetooth Tethering menu under Wireless & Networks then More. Then on the BBB, use the pand command along with the MAC address found using the hcitool command.

$ sudo pand -c 80:E6:50:16:9D:5B -n
pand[8892]: Bluetooth PAN daemon version 4.99
pand[8892]: Connecting to 80:E6:50:16:9D:5B
pand[8892]: bnep0 connected

Use dhcp to get an ip address and verify the interface using ifconfi.

$ sudo dhclient bnep0
$ ifconfig bnep0
bnep0     Link encap:Ethernet  HWaddr 00:15:83:6a:64:8d
          inet addr:  Bcast:  Mask:

Verify connectivity with a quick ping

$ ping -c1
PING ( 56(84) bytes of data.
64 bytes from icmp_req=1 ttl=56 time=89.1 ms

--- ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 89.101/89.101/89.101/0.000 ms

Now you can run sudo apt-get update and sudo apt-get upgrade to upgrade to the latest patches, etc.




Connect the WiFi dongle to the Bone and see if it is detected. Usually, this requires a reboot, hot-plugging doesn't seem to work.

$ lsusb
Bus 001 Device 002: ID 0bda:8176 Realtek Semiconductor Corp. RTL8188CUS 802.11n WLAN Adapter
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

Set the SSID and passphrase

Use the wpa_passphrase command to generate the wpa_supplicant.conf file. You may need to install wpasupplicant and wireless-tools packages if wpa_passphrase command is not available.

$ sudo sh -c 'wpa_passphrase SSID PASSWORD >> /etc/wpa_supplicant/wpa_supplicant.conf'
$ cat /etc/wpa_supplicant/wpa_supplicant.conf

Configure the interface

Find the name of the interface used by the dongle. Normally it should be wlan0, but it could be different. Verify using iwconfig. For example, in my case, I got wlan1.

$ iwconfig
lo        no wireless extensions.

eth0      no wireless extensions.

usb0      no wireless extensions.

wlan1     unassociated  Nickname:"<WIFI@REALTEK>"
          Mode:Managed  Frequency=2.437 GHz  Access Point: Not-Associated
          Retry:off   RTS thr:off   Fragment thr:off
          Power Management:off
          Link Quality=0/100  Signal level=0 dBm  Noise level=0 dBm
          Rx invalid nwid:0  Rx invalid crypt:0  Rx invalid frag:0
          Tx excessive retries:0  Invalid misc:0   Missed beacon:0

Modify the /etc/network/interfaces file to include the wlan1 and wpa_supplicant.conf information.

$ cat /etc/network/interfaces
# WiFi Example
allow-hotplug wlan1
auto wlan1
iface wlan1 inet dhcp
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
iface default inet dhcp

Toggle the interface to get an IP address using DHCP.

$ sudo ifdown wlan1
$ sudo ifup wlan1
ioctl[SIOCSIWAP]: Operation not permitted
ioctl[SIOCSIWENCODEEXT]: Invalid argument
ioctl[SIOCSIWENCODEEXT]: Invalid argument
Internet Systems Consortium DHCP Client 4.2.2
Copyright 2004-2011 Internet Systems Consortium.
All rights reserved.
For info, please visit

Listening on LPF/wlan1/00:13:ef:d0:24:fe
Sending on   LPF/wlan1/00:13:ef:d0:24:fe
Sending on   Socket/fallback
DHCPDISCOVER on wlan1 to port 67 interval 8
DHCPDISCOVER on wlan1 to port 67 interval 8
DHCPREQUEST on wlan1 to port 67
bound to -- renewal in 125874 seconds.

Verify connectivity with quick ping.

$ ping -c1
PING ( 56(84) bytes of data.
64 bytes from ( icmp_req=1 ttl=54 time=468 ms

--- ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 468.894/468.894/468.894/0.000 ms

Now that we have Internet connectivity, the next step is to get some temperature measurements.

Monitoring Temperature using AM2302



Using the AM2302 temperature and humidity sensor from Adafruit is incredibly simple. It uses the 1-wire protocol, has only 3 wires, and comes with a 5.1K resistor inside the sensor connecting VCC and DATA so you do not need any additional pullup resistors (in the version sold by Adafruit).

Connect the temperature sensor as below:

  • Data \(\Rightarrow\) P9_22
  • VCC \(\Rightarrow\) P9_3 (VDD 5V)
  • GND \(\Rightarrow\) P9_46 (GND)

Wiring diagram AM2302

Read the temperature

I could not get the temperature measurement to work using the "standard" Device Tree Overlay method. I had expected that the AM2302 would follow the Dallas 1-wire protocol like the DS18B20 that is quite well documented, and spent several days trying all sorts of things like building new kernels, creating new overlays, building GPIO and thermal driver modules, etc. Finally, I did what I should I have done first, and found that the 1-wire protocol used by the DS18B20 (Dallas 1-wire) and the 1-wire protocol used by the DHT sensors (AM2302, DHT11, DHT22) are quite different. The DHT sensors have no module, but fortunately Adafruit has library that can do the time-sensitive bit-banging.

$ git clone
$ cd Adafruit_Python_DHT
$ python install

Test the library.

$ sudo ./examples/ 2302 2
Temp=24.4*C  Humidity=58.8%

The script follows the template:


where SENSOR_TYPE can be 11, 22, or 2302, depending on the sensor used. In this case, we are using GPIO_2, on pin P9_22. The script has an alternative form:


Where PIN_NUM is the pin number on the connector of the GPIO. So we could use the following:

$ sudo ./ 2302 P9_22
Temp=24.4*C  Humidity=55.2%

Now we have Internet connectivity on the Bone and we can read the temperature. Next we will prepare the Meshblu platform, and trasmit data to it using MQTT. We will also display the transmitted data in Freeboard.

Setting up Meshblu



We follow the instructions in the above post almost to the letter except for some minor changes. The author Masato Shimizu has done a great job of using Docker Compose to administer and manage the Meshblu broker.

Meshblu is versatile messaging platform / broker released by Octoblu as an open source project. MQTT, HTTP REST, WebSocket, CoAP, etc. protocols can be used and freely bridged between each other. For example, using MQTT on Raspberry Pi to publish data, and using WebSockets to subscribe to the data on the browser. On a MQTT subscribe channel, the REST API can be used to POST a message to it, thus various devices and services and be easily inter-connected.

We are using a Debian server to install Meshblu and related components.

$ uname -srvmo
Linux 3.16.0-0.bpo.4-amd64 #1 SMP Debian 3.16.7-ckt11-1~bpo70+1 (2015-06-08) x86_64 GNU/Linux
$ mkdir -p ~/iot_apps
$ cd ~/iot_apps
$ git clone --recursive
$ cd meshblu-compose
$ ./

As Debian does not allow normal users to write to /usr/bin or /usr/local/bin, the script fails. We have to modify the script slightly. It is prefereable not to execute the entire script as sudo because we'll end up with some root-owned files in the user directory.

$ cat ./
#!/bin/sh -
set -o nounset

# Docker
wget -qO- | sudo sh

# Docker Compose
sudo sh -c "curl -L`uname -s`-`uname -m` > /usr/local/bin/docker-compose; chmod +x /usr/local/bin/docker-compose"

# SSL Certificate
cd ./nginx/conf/certs

openssl genrsa  -out server.key 4096
openssl req -new -batch -key server.key -out server.csr
openssl x509 -req -days 3650 -in server.csr -signkey server.key -out server.crt

cd -

docker-compose up -d openresty
docker-compose ps

The scripts installs and activates containers for Meshblu, MongoDB, Redis, OpenResty, etc.

Verification of installation

Verify the install using docker-compose ps

$ docker-compose ps
      Name             Command             State              Ports
meshblucompose_f   npm start          Up       >80
reeboard_1                                               80/tcp
meshblucompose_m   npm start          Up       >18
eshblu_1                                                 83/tcp, 80/tcp
meshblucompose_m   /     Up                 27017/tcp
ongo_1             mongod
meshblucompose_o   nginx -c /etc/ng   Up       >443
penresty_1         inx/nginx.conf                        /tcp,
meshblucompose_r   /     Up                 6379/tcp
edis_1             redis-server

docker and docker-compose versions are as below

$ docker version
Client version: 1.7.1
Client API version: 1.19
Go version (client): go1.4.2
Git commit (client): 786b29d
OS/Arch (client): linux/amd64
Server version: 1.7.1
Server API version: 1.19
Go version (server): go1.4.2
Git commit (server): 786b29d
OS/Arch (server): linux/amd64
$ docker-compose --version
docker-compose version: 1.3.3
CPython version: 2.7.9
OpenSSL version: OpenSSL 1.0.1e 11 Feb 2013

It is possible to confirm that the meshblu server is active using curl on the docker host

$ curl --insecure https://localhost/status

If the docker host is on a private network, then ensure that the host is reachable from a public address by opening the requisite firewall ports and/or setting up port forwarding. For this implementation we use ports 443 and 1883 for https and mqtt. curl can be used to test the same from the BBB for example.

$ curl --insecure

Server start and restart

To start the server from stopped state, set the OpenResty service to up.

$ docker-compose up -d openresty
Recreating meshblucompose_redis_1...
Recreating meshblucompose_mongo_1...
Recreating meshblucompose_meshblu_1...
Recreating meshblucompose_openresty_1...

To restart the server, use the restart command.

$ docker-compose restart

Device registration

To start off, use the register command of the iotutil service to initialize some devices. One owner device that is able to send messages to any (every) device, 5 actions, action-*, and 5 commands, trigger-* are created.

$ docker-compose run --rm iotutil register

> iotutil@0.0.1 start /app
> node app.js "register"

|  keyword  | meshblu_auth_token | meshblu_auth_uuid                    |
| owner     | c701f3bb           | 01e14f1a-3106-421a-b72c-bea7a7ee7ab6 |

Once device registration is completed, the authentication information of the owner device can be confirmed using the following command.

$ docker-compose run --rm iotutil owner

> iotutil@0.0.1 start /app
> node app.js "owner"

| keyword | meshblu_auth_token | meshblu_auth_uuid                    |
| owner   | c701f3bb           | 01e14f1a-3106-421a-b72c-bea7a7ee7ab6 |

Authorise device messaging

In case of identical terminating numbers, the serice (broker) is pre-configure to be able to send messages from trigger-* to action-*. For example, from trigger-1 to action-1. To enable messaging between arbitrary devices, the pair is added to a white-list. For example, to authorize messaging from action-1 to trigger-4:

$ docker-compose run --rm iotutil whiten -- -f action-1 -t trigger-4

> iotutil@0.0.1 start /app
> node app.js "whiten" "-f" "action-1" "-t" "trigger-4"

action-1 can send message to trigger-4

We can now verify that the identical trigger to action messaging is pre-configured:

$ docker-compose run --rm iotutil whiten -- -f trigger-2 -t action-2

> iotutil@0.0.1 start /app
> node app.js "whiten" "-f" "trigger-2" "-t" "action-2"

action-2 whitelists already contains trigger-2

Use CLI to obtain service/device UUIDs

The list command of iotutil service displays the UUID information of currently registered devices.

$ docker-compose run --rm iotutil list

> iotutil@0.0.1 start /app
> node app.js "list"

| keyword   | tok      | uuid                                 |
| trigger-1 | c670eef0 | d28f05c1-a73f-4f7b-bac0-f48e67984d55 |
| trigger-2 | b029f95d | a8b2d13b-c6f8-423c-8985-0d1f9233ff4b |
| trigger-3 | e183e0b0 | 258a7753-781e-437c-80b1-ffd1708454ad |
| trigger-4 | 4253f83e | d21118ef-d779-4b21-b13b-03bff991ff88 |
| trigger-5 | 58c3ea7b | f7fc9892-c1a7-40b9-8148-86eee5a990ec |
| action-1  | d5c483d7 | dd438bdf-7b45-40ec-95b9-dab2c3f7194a |
| action-2  | 190da44f | b5d36d77-b104-4e3e-85f4-49b501d5d392 |
| action-3  | 8c3f3fa7 | f6d2f7a3-bf72-40f1-bd93-bd48da58aea4 |
| action-4  | 372958b2 | 449cc489-1d2e-45e3-b12d-b783f6254fc8 |
| action-5  | 05ebfd1a | 0514d739-771b-4eed-b423-5597ec631d53 |

The show command can be used to obtain the individual device information.

$ docker-compose run --rm iotutil show -- --keyword action-1

> iotutil@0.0.1 start /app
> node app.js "show" "--keyword" "action-1"

| keyword  | token    | uuid                                 |
| action-1 | d5c483d7 | dd438bdf-7b45-40ec-95b9-dab2c3f7194a |

Use API to obtain UUIDs

HTTP GET method can be used to obtain the device UUID by passing the keyword and token variables in the query string. In case of owner device, the URL path is /owner/uuid:

$ curl --insecure ""

In case of a device other than the owner, the path is /device/uuid, but I was not able to retrieve the UUID for some reason.

$ curl --insecure ""
$ curl --insecure ""

Device deletion

The del command deletes all all the registered devices. Devices can be created again with the register command.

$ docker-compose run --rm iotutil del

> iotutil@0.0.1 start /app
> node app.js "del"

are you sure?: [Yn]:  Y
trigger-1, trigger-2, trigger-3, trigger-4, trigger-5, action-1, action-2, action-3, action-4, action-5, owner are deleted.
$ docker-compose run --rm iotutil list

> iotutil@0.0.1 start /app
> node app.js "list"

devices not found

Publish/Subscribe Data using MQTT protocol



Install MQTT client from Paho project on the BeagleBone Black.

$ sudo pip install paho-mqtt

Note: Meshblu project has it's own MQTT implementation that uses Javascript/Node.js. It's on the TTD to try that next. Currently we have to use Python because we can read the temperature using Python.

Once devices are registered on Meshblu using the procedure in the section above, some configuration variables are stored We use the token and uuid information from the list or show command.

  • IDCF_CHANNEL_URL: IP address or FQDN of the docker host running the meshblu container
  • TRIGGER_UUID : trigger-1 uuid
  • TRIGGER_TOKEN : trigger-1 token
  • ACTION_UUID : action-1 uuid
  • ACTION_TOKEN : action-1 token
  • FREEBOARD_UUID : action-2 uuid
$ cat
conf = {
"TRIGGER_UUID": "d28f05c1-a73f-4f7b-bac0-f48e67984d55",
"TRIGGER_TOKEN": "c670eef0",
"ACTION_UUID": "dd438bdf-7b45-40ec-95b9-dab2c3f7194a",
"ACTION_TOKEN": "d5c483d7",
"FREEBOARD_UUID": "b5d36d77-b104-4e3e-85f4-49b501d5d392"

The basic idea here is to assign the trigger uuid to the temperature data, and publish it to the two action uuids.

  • trigger-1 : uuid to send the temperature data from Beaglebone Black to Docker host
  • action-1 : uuid on the Docker host for MQTT subscribe
  • action-2 : uuid on Freeboard for WebSocket subscribe

On the Docker host, ensure that messaging from trigger-1 to action-2 is authorized.

$ docker-compose run --rm iotutil whiten -- -f trigger-1 -t action-2

> iotutil@0.0.1 start /app
> node app.js "whiten" "-f" "trigger-1" "-t" "action-2"

trigger-1 can send message to action-2

Read and publish data

Script to read the temperature and publish it using MQTT. A JSON message is contructed with the devices directive set to the ACTION_UUID and FREEBOARD_UUID uuids. The payload is set to the temperature value. The Beaglebone publishes the message with these two uuids set as the destination.

$ cat
# -*- coding: utf-8 -*-
import paho.mqtt.client as mqtt
from time import sleep
import json
import sys
from config import conf
import Adafruit_DHT

def sensing():
    humidity, temp = Adafruit_DHT.read_retry(Adafruit_DHT.AM2302, 2)
    if humidity is not None and temp is not None:
       retval = dict(temperature="{:.2f}".format(temp))
       return retval
       print 'Failed to get reading.'

def on_connect(client, userdata, rc):
    print("Connected with result code {}".format(rc))

def on_publish(client, userdata, mid):
    print("publish: {}".format(mid))

def main():
    client = mqtt.Client(client_id='',
             clean_session=True, protocol=mqtt.MQTTv311)

    client.username_pw_set(conf["TRIGGER_UUID"], conf["TRIGGER_TOKEN"])

    client.on_connect = on_connect
    client.on_publish = on_publish

    client.connect(conf["IDCF_CHANNEL_URL"], 1883, 60)

    while True:
       retval = sensing()
       if retval:
           message = json.dumps({"devices":
                     "payload": retval})

if __name__ == '__main__':

Run the script as root on the BBB. In about 5 seconds, the messages will be published to the two uuids.

$ sudo python ./
{"payload": {"temperature": "22.70"}, "devices": ["dd438bdf-7b45-40ec-95b9-dab2c3f7194a", "b5d36d77-b104-4e3e-85f4-49b501d5d392"]}
publish: 1
{"payload": {"temperature": "22.70"}, "devices": ["dd438bdf-7b45-40ec-95b9-dab2c3f7194a", "b5d36d77-b104-4e3e-85f4-49b501d5d392"]}
publish: 2

Confirm on Docker host that MQTT messages are received by subscribing to the messages on action-2 UUID in a separate shell.

$ mosquitto_sub \
        -h localhost \
        -p 1883 \
        -t b5d36d77-b104-4e3e-85f4-49b501d5d392 \
        -u b5d36d77-b104-4e3e-85f4-49b501d5d392 \
        -P 190da44f \
Client mosqsub/2071-hibana sending CONNECT
Client mosqsub/2071-hibana received CONNACK
Client mosqsub/2071-hibana sending SUBSCRIBE (Mid: 1, Topic: b5d36d77-b104-4e3e-85f4-49b501d5d392, QoS: 0)
Client mosqsub/2071-hibana received SUBACK
Subscribed (mid: 1): 0
Client mosqsub/2071-hibana sending PINGREQ
Client mosqsub/2071-hibana received PINGRESP
Client mosqsub/2071-hibana received PUBLISH (d0, q0, r0, m0, 'b5d36d77-b104-4e3e-85f4-49b501d5d392', ... (32 bytes))
Client mosqsub/2071-hibana received PUBLISH (d0, q0, r0, m0, 'b5d36d77-b104-4e3e-85f4-49b501d5d392', ... (32 bytes))

Thus we can see that the data is being published and subcribed on the channel using MQTT.

Use Freeboard to display dashboard


Blog Comments powered by Disqus.

Next Post