In this tutorial we will dive into the use of MQTT with the arduino yun (or linkit) to control the LED#13.
One of the common protocols used in the IOT world is MQTT. MQTT is a machine-to-machine (M2M)/”Internet of Things” connectivity protocol. It was designed as an extremely lightweight publish/subscribe messaging transport. It is useful for connections with remote locations where a small code footprint is required and/or network bandwidth is available.
MQTT
The MQTT protocol is based on the principle of publishing messages and subscribing to topics, or “pub/sub”. Multiple clients connect to a broker and subscribe to topics that they are interested in. Clients also connect to the broker and publish messages to topics. Many clients may subscribe to the same topics and do with the information as they please. The broker and MQTT act as a simple, common interface for everything to connect to.
The setup
1.) MQTT broker running on a RPI
2.) Python script on the arduino yun (openwrt)
3.) Sketch for the MCU
MQTT broker
To install the MQTT broker:
apt-get update apt-get install mosquitto
To test it open two SSH connections. One for subscribing and the other for publishing.
mosquitto_sub -h 192.168.2.40 -t "arduino/led"
mosquitto_pub -h 192.168.2.40 -t "arduino/led" -m "1" mosquitto_pub -h 192.168.2.40 -t "arduino/led" -m "0"
Result:
1 0
For debugging purposes you can also run mosquitto in a shell. So open up the third SSH connection. Execute “/etc/init.d/mosquitto stop” and then execute “mosquitto”. Output:
1468435883: mosquitto version 1.3.4 (build date 2014-08-22 06:10:51+0000) starting 1468435883: Using default config. 1468435883: Opening ipv4 listen socket on port 1883. 1468435883: Opening ipv6 listen socket on port 1883. 1468435883: New connection from 192.168.x.x on port 1883.
Python
Install the MQTT python client:
pip install paho-mqtt
And then use the following python code:
#!/usr/bin/python import sys import paho.mqtt.client as mqtt sys.path.insert(0, '/usr/lib/python2.7/bridge/') from bridgeclient import BridgeClient as bridgeclient from tcp import TCPJSONClient json = TCPJSONClient('127.0.0.1', 5700) value = bridgeclient() # The callback for when the client receives a CONNACK response from the server. def on_connect(client, userdata, rc): print("Connected with result code "+str(rc)) # Subscribing in on_connect() means that if we lose the connection and # reconnect then subscriptions will be renewed. client.subscribe("arduino/led") # The callback for when a PUBLISH message is received from the server. def on_message(client, userdata, msg): print(msg.topic+" "+str(msg.payload)) json.send({'command':'put', 'key':'led', 'value':msg.payload}) client = mqtt.Client() client.on_connect = on_connect client.on_message = on_message client.connect("192.168.x.x", 1883, 60) # Blocking call that processes network traffic, dispatches callbacks and # handles reconnecting. # Other loop*() functions are available that give a threaded interface and a # manual interface. client.loop_forever()
Normally I would use value.put() instead of using json.send() only I received a “Bad file descriptor” once in a while. As the arduino yun uses JSON via TCP to the bridge library I used this workaround instead.
Sketch
Upload the sketch. memset will set al the items in the array to zero.
#include <Bridge.h> #include <stdio.h> // Here we will hold the values coming from Python via Bridge. char ledvalue[2]; void setup() { // Zero out the memory we're using for the Bridge. memset(ledvalue, 0, 2); // Initialize digital pins 13 as output. pinMode(13, OUTPUT); // Start using the Bridge. Bridge.begin(); } void loop() { // Write current value of D13 to the pin (basically turning it on or off). Bridge.get("led", ledvalue, 2); int ledD13 = atoi(ledvalue); digitalWrite(13, ledD13); delay(10); }
Please note that the delay for retreiving info from the bridge is rather low, causing heavy load on the linux side.
Update [29-12-2017]:
If you receive the following error: TypeError: on_connect() takes exactly 3 arguments (4 given) the following could help you. Paho-mqtt client has been updated and you need to change the following (1. on_connect and subscribe):
def on_connect(client, userdata, rc):
print(“Connected with result code “+str(rc))
# Subscribing in on_connect() means that if we lose the connection and
# reconnect then subscriptions will be renewed.
client.subscribe(“arduino/led”)
Should be changed to:
def on_connect(self, client, userdata, rc):
print(“Connected with result code “+str(rc))
# Subscribing in on_connect() means that if we lose the connection and
# reconnect then subscriptions will be renewed.
self.subscribe(“arduino/led”)
Hoi Martijn,
Thx for the tutorial, it works great !
However, instead of using the RPi as the mosquitto broker, I tried, since Yun has also Linux (OpenWrt), to use the Yun (linux side) as a broker. But then it doesn’t work anymore.
Think has to do with version of mosquitto broker on the Yun (supports 3.1 and not 3.1.1)
which gives than conflict with paho libs. Do you know how to get this working ?
Tkx
Leo
Hi Leo,
I’m sorry but I do not use the Yun any more. The linkit has a more up to date openwrt version and is much cheaper (around 20 EUR).
Regards,
Martijn
Hi Martijn,
Nice write-up thanks.
ESP-32 based Arduino’s have a number of MQTT libraries, however they are based on the Arduino having direct access to the Wifi hardware. Have you seen any methods where you could talk MQTT directly from the Arduino Yun side ?
I was thinking that a REST interface could be used, which would work for RabbitMQ, but not that many MQTT servers have a REST connector.
Once again thanks for the write-ups
Pete