Computing stuff tied to the physical world

Hooking RasPi RF into MQTT

Being able to send and receive wireless packets is only part of the story, of course. We’re going to want to collect the packet data, aggregate it to generate averages and other statistics, produce nice graphs, and allow buttons and other controls as well as automated rules to send out commands if we also want to control stuff.

A modular design becomes a necessity, so that we can add and extend the setup over time, without having to rebuild and tinker with what is already in place.

This is where MQTT comes in, the “Message Queue Telemetry Transport”. From the Wikipedia page, we learn that:

MQTT […] is a publish-subscribe based “light weight” messaging protocol for use on top of the TCP/IP protocol. It is designed for connections with remote locations where a “small code footprint” is required and/or network bandwidth is limited. The Publish-Subscribe messaging pattern requires a message broker. The broker is responsible for distributing messages to interested clients based on the topic of a message.

Quite a mouthful. You can think of MQTT as a Reuters news agency (broker) for Physical Computing: news stories (messages) are submitted (published) to it from all over the world, and newspapers sign up (subscribe) to it to get the stories as soon as they come in.

MQTT messages consist of a topic string and a payload (string, number, bytes, whatever). Topics are structured as “a/b/c” levels, and subscribers can specify to receive only certain matches, e.g. “a/+/c” or “a/#”, where “+” matches one segment and “#” matches anything.

What this means is that our RasPi RF can pick some meaningful topic(s) and publish every packet it receives there, without ever caring who is interested in its messages. There could be any number of subscribers, or none. Similarly, it can subscribe to a specific channel and transmit whatever comes in as outgoing wireless packet. Total modularity and freedom!

MQTT clients (this includes our RasPi RF, but also the rest of the processing we set up) connect to the server / broker via TCP/IP, which means that the broker does not have to run on the same computer as where the RasPi RF is connected. But for simplicity and as first test, let’s set everything up on a single Raspberry Pi.

We’ll need an MQTT broker. Mosquitto is a popular one and trivial to install:

sudo apt-get install mosquitto

That’s it. From now on, the broker will always be running in the background. By default, it listens on port 1883 and accepts all connections in plaintext and without a password.

Let’s install a few more packages for convenience, though:

sudo apt-get install mosquitto-clients
sudo apt-get install libmosquitto0-dev libmosquittopp0-dev

The clients are simple command-line tools to simplify testing, the dev packages have everything we need to build C and C++ programs to talk to the broker.

We can now take our little test-raspi-linux example, and turn it into an rf69mqtt demo. This example will use the class-based C++ API, so first we need to define a subclass:

class MyMqtt : public mosquittopp::mosquittopp {
public:
  MyMqtt () : mosquittopp::mosquittopp (NAME) {
    MyMqtt::lib_init();
  }

  virtual void on_connect (int err) {
    printf("connected %d\n", err);
  }

  virtual void on_disconnect () {
    printf("disconnected\n");
  }
};

Then we define an instance and insert the proper initialisation and publishing calls:

MyMqtt mqtt;
mqtt.connect("127.0.0.1");

struct {
  int16_t afc;
  uint8_t rssi;
  uint8_t lna;
  uint8_t buf [64];
} rx;

while (true) {
  int len = rf.receive(rx.buf, sizeof rx.buf);
  if (len >= 0) {
    rx.afc = rf.afc;
    rx.rssi = rf.rssi;
    rx.lna = rf.lna;

    char topic [30];
    sprintf(topic, "test/RasPiRF/%d", myTopic, rx.buf[1] & 0x3F);
    mqtt.publish(0, topic, 4 + len, (const uint8_t*) &rx);
  }

  mqtt.loop(1);
}

The “rx” struct has all the details about the received packet, i.e. not just the payload but also some other information provided by the RF69 driver, such as signal strength.

Note also that the topic ends with a number which is the node ID of the sending node. That way, clients can subscribe to be notified only of packets from a specific node if they want.

Since this still uses the WiringPi library and needs access to the physical SPI bus and GPIO pins, we need to run this program as superuser:

$ make
g++ -I../../../lib/arch-raspi -I../../../lib/driver rf69mqtt.cpp \
  -lwiringPi -lwiringPiDev -lpthread -lmosquittopp -o rf69mqtt
$ sudo ./rf69mqtt

[rf69mqtt]
connected 0

That’s it, we’re connected without errors. But there will no longer be any visible output from this program, since all messages are now being sent to Mosquitto instead.

In fact, we should keep this program running forever in the background:

    nohup sudo ./rf69mqtt &

Then we can use a command-line utility client to see if anything is happening:

    mosquitto_sub -v -t '#'

This will subscribe to “#”, i.e. all topics, and print the topics and payloads as they come in. Unfortunately, the payloads are binary data, so this will print gibberish. A slightly better way to see all published data is to convert all the output to text using the “xxd” hex dumper:

    mosquitto_sub -v -t '#' | xxd

This way, the output will at least be plain ASCII text. But it’s not quite as easy to read.

Yet another way is to look at Mosquitto’s built-in statistics, which it publishes as special topics (these are not included when using just “#” as subscription wildcard!):

$ mosquitto_sub -v -t '$SYS/#'
$SYS/broker/bytes/received 2239
$SYS/broker/bytes/sent 281
$SYS/broker/bytes/per second/received 1
$SYS/broker/bytes/per second/sent 0
$SYS/broker/version mosquitto version 0.15
$SYS/broker/timestamp 2013-08-23 19:24:40+0000
$SYS/broker/changeset $Revision: e745e1ab5007 $
$SYS/broker/uptime 1639 seconds
$SYS/broker/messages/stored 20
$SYS/broker/messages/received 67
$SYS/broker/messages/sent 15
$SYS/broker/messages/per second/received 0
$SYS/broker/messages/per second/sent 0
$SYS/broker/clients/total 1
$SYS/broker/clients/inactive 0
$SYS/broker/clients/active 1
$SYS/broker/clients/maximum 2
$SYS/broker/heap/current size 3756 bytes
$SYS/broker/heap/maximum size 6368 bytes

As you can see, data is coming in: Mosquitto has received 67 messages so far.

The actual rf69mqtt code on GitHub is a slightly extended version of this demo, which publishes to a topic that includes the frequency band and network group, so that multiple RFM69 modules can be set up and report to this same central broker. It also listens to a fixed topic and sends out every message published to it as RF packet, turning rf69mqtt into a bi-directional bridge between MQTT and our Wireless Sensor Network.

Note that this first crude design still uses idle polling and consumes 10..30% of CPU.

Anyway. Welcome to the Internet of Things! Go wild! Connect anything to anything!

All we need is a bunch of remote nodes and software to do something meaningful with all this data (might also be a good time to think about security and start using passwords!).

[Back to article index]