Off-The-Shelf Hacker: More MQTT Fun on Your Network

This week, I’m again digging the MQTT messaging protocol, and how can use it with the ESP8266 module, the Raspberry Pi, the CHIP and my Linux notebook. The capability to easily send two-way messages between all these devices opens a lot of possibilities for interesting and possibly useful, remote and automated gadgets.
Installing the Mosquitto MQTT broker on a CHIP computer is an absolute no-brainer, as explained in last week’s last week’s article. By the way, if it doesn’t restart at boot-up, you may have to edit /etc/rc.local, as root and add a reference program at the bottom, along with the “&” (run in the background) symbol. It should then start up on the next boot.
Running Mosquitto on the CHIP is also painless. I had a spare outlet in the kitchen, so I simply plugged it into a 2-Amp wall wart and located the board on an out-of-the-way shelf. It’s been happily humming along, brokering MQTT messages, for the last couple of days. I can ssh and/or MQTT_subscribe into the CHIP from anywhere on my local area network, using a Linux notebook or my Android super-phone.
Dozens of Android MQTT client programs exist in the Google Play Store. Just punch “MQTT client” into the search bar and pick one. Use them for testing or a quick and dirty data monitoring solution. Once you have a client app on your phone, just enter your CHIP’s IP address along with the appropriate topic and you’re usually good to go.
Let’s talk about our data generator, next.
Modding the ESP8266 Firmware for MQTT
ESP8266-based sensors make great data generators. They are inexpensive, easy to program through the Arduino IDE and can handle MQTT messages without a sweat. Pick your sensor, hook it to a GPIO pin and start sending data. Going the other direction, pick an output device, watch for a specific message and activate the pin connected to the device. We’ll cover watching for messages (on an ESP8266) and activating a GPIO pin in a future story.
I used the mqtt_esp8266 example program (in the Arduino IDE) as a baseline MQTT client on the ESP8266. Adding the PIR sensor code, which was covered in “Create an Early Warning Detector with Passive Infrared Sensors” produced a completely usable program for data generating purposes. Whenever a hot-body moves in front of the sensor, it sends an MQTT message to the CHIP broker. Look, Ma, no wires.
Here’s the code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
/* ----------------------------------------- drtorq's Modded - Basic ESP8266 MQTT example filename: mqtt_esp8266_1 ----------------------------------------- */ #include #include // Update these with values suitable for your network. const char* ssid = "your AP name"; const char* password = "your AP password"; const char* mqtt_server = "192.168.1.111"; // IP address of the MQTT Broker WiFiClient espClient; PubSubClient client(espClient); long lastMsg = 0; char msg[50]; int value = 0; int calibrationTime = 20; int pirPin = 2; //the digital pin connected to the PIR sensor's output int ledPin = 13; void setup_wifi() { delay(10); // We start by connecting to a WiFi network Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } randomSeed(micros()); Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } void callback(char* topic, byte* payload, unsigned int length) { Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] "); for (int i = 0; i < length; i++) { Serial.print((char)payload[i]); } Serial.println(); // Switch on the LED if an 1 was received as first character if ((char)payload[0] == '1') { digitalWrite(BUILTIN_LED, LOW); // Turn the LED on (Note that LOW is the voltage level // but actually the LED is on; this is because // it is acive low on the ESP-01) } else { digitalWrite(BUILTIN_LED, HIGH); // Turn the LED off by making the voltage HIGH } } void reconnect() { // Loop until we're reconnected while (!client.connected()) { Serial.print("Attempting MQTT connection..."); // Create a random client ID String clientId = "ESP8266Client-"; clientId += String(random(0xffff), HEX); // Attempt to connect if (client.connect(clientId.c_str())) { Serial.println("connected"); // Once connected, publish an announcement... client.publish("mqtt", "hello world"); // ... and resubscribe client.subscribe("inTopic"); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); // Wait 5 seconds before retrying delay(5000); } } } void setup() { pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output Serial.begin(115200); setup_wifi(); client.setServer(mqtt_server, 1883); client.setCallback(callback); // Calibrate sensor Serial.print("calibrating sensor "); for(int i = 0; i < calibrationTime; i++){ Serial.print("."); delay(1000); } Serial.println(" done"); Serial.println("SENSOR ACTIVE"); delay(50); } void loop() { if (!client.connected()) { reconnect(); } client.loop(); // added PIR sensor code segment here int proximity = digitalRead(pirPin); if (proximity == LOW) // If the sensor's output goes low, motion is detected { digitalWrite(ledPin, HIGH); snprintf (msg, 75, "Motion Detected #%ld", value); ++value; Serial.println("Motion detected!"); client.publish("mqtt", msg); delay(200); } else { digitalWrite(ledPin, LOW); delay(200); } } |
The setup has silently run for a few days, detecting every time I move, at my desk. Here’s a screen-shot of the mosquitto_sub command, on a Linux notebook window, monitoring the sensor from the network. That’s right, over 46,500 “Motion Detected” messages. Works like a charm.

mosquitto_sub Results On The Linux Notebook
The sensor is capable of seeing motion several times a second, so changing the code to ignore detection over a one- to three-second period, after it initially fires, would cut down on the amount of data streamed to the broker. I think it’s unlikely we’ll miss intruders, using this technique, in the real World.
ESP8266-based devices aren’t the only ones that can send MQTT messages.
Run an MQTT Client on the Raspberry Pi, too
The Raspberry Pi can muscle itself into your little MQTT universe as a subscriber AND a publisher, as well.
Imagine having an ESP8266-enabled yard light, that’s toggled on/off with an MQTT message. It might be useful to be able to push a button on a Raspberry Pi and have the light turn on.
I wrote a Python program a while back to detect button pushes on a Raspberry Pi. It’s a bit of a kludge since it used the xdotool and a system call. Off-the-shelf hacking IS sometimes a kludge. Like I always say, get the prototype working, do your demo, then refine the design, as needed. Also, if it works well enough, you might always just use it “as is.”
The good thing is that all I had to do was add the Mosquitto client to the Pi and mod the Python program to call the mosquitto_pub command instead of xdotool.
Fire up the Pi and install the Mosquitto client software using apt-get.
1 |
pi% apt-get install mosquitto-clients |
Next, try out the Mosquitto client by subscribing to the PIR sensor, through the CHIP MQTT broker (IP=192.168.1.111).
1 |
pi% mosquitto_sub -h 192.168.1.111 -t “mqtt” |
A new message will appear, whenever there’s movement in front of the PIR sensor.
It’s easy to test sending messages using the mosquitto_pub command, too. Open another terminal, on the Raspberry Pi and enter the following command line.
1 |
pi% mosquitto_pub -h 192.168.1.111 -t “mqtt” -m “Button Pushed” |
The “Button Pushed” will immediately appear in the other Raspberry Pi window. If you are monitoring the “mqtt” topic on your Linux notebook, the message will appear there, as well.
Here’s the Python code, substituting the mosquitto_pub line for xdotool, on the Pi:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# filename: mqtt-button-push.py import RPi.GPIO as GPIO import time import os GPIO.setmode(GPIO.BCM) GPIO.setup(17, GPIO.IN, pull_up_down=GPIO.PUD_UP) osout = '' while True: input_state = GPIO.input(17) if input_state == False: print 'Long Button Pressed' # os.system("xdotool search --name 'Impress' key Down") # system call line for a button push to advance a LibreOffice Impress slide # building a new line with the mosquitto_pub system call osout = "mosquitto_pub -h '192.168.1.111' -t 'mqtt' -m 'Button Pushed'" print osout os.system(osout) time.sleep(0.2) |
The button is hooked up to GPIO pin 17, on the Pi.
Next, it’s just a matter of running the Python program to make the button send MQTT messages to the broker.
1 |
pi% python mqtt-button-push.py |
Every time the button gets pushed, a new message should appear in all mosquitto_sub windows subscribing to the “mqtt” topic.
Notice that the “Button Pushed” message is seamlessly rolled in among the PIR “motion detected” messages.
You could have the ESP8266-connected yard light watching for a “Button Pushed” message to show up in the “mqtt” topic and then toggle the light, whenever it sees one. We could also toggle the light on when a “Motion Detected” message came through, as well.
Several Python MQTT libraries exist for the Raspberry Pi, so you might consider using those instead of a system call to mosquitto_pub.
How easy is that?
Connecting the Dots
I get the impression that a lot of people think MQTT is something exotic, hard to use and complicated. As we’ve seen, using the Mosquitto server (broker) and clients on the ESP8266, the CHIP, the Raspberry Pi and a Linux notebook is pretty straightforward.
Obviously, security and device management are important areas to consider, for production environments. The great thing is that there are plenty of prototyping ideas, on an encrypted wireless network, behind a firewall that you can try right now. We’ll expand on those other topics as we come up to speed with the technology.