Configuring MQTT on the Raspberry Pi
MQTT, which originally was an acronym for Message Queue Telemetry Transport, is a
lightweight message queue protocol designed for small data packets sent across high
latency, low bandwidth links. MQTT is a fairly simple protocol and it's perfect for Internet
of Things projects. It's also perfect for this security system project!
The version of MQTT I use in this tutorial is called Mosquitto. It is available via apt, so
installing it is quite easy. There are a number of steps in configuring the Raspberry Pi
component of the security system. As I mentioned, I'm using a Raspberry Pi 3.
The steps you need to follow are, at a high level:
1. Install mosquitto (MQTT) components.
2. Configure mosquitto and restart the service.
3. Copy in the security.py program and edit it for your installation.
4. Configure security.py to run at boot.
5. Start security.py.
As I've mentioned earlier, I'm using the Raspberry Pi 3 running the latest version of
Raspbian Jessie.
Step 1 - Install the Mosquitto (MQTT) Components
Installing mosquitto is as easy as running a few apt commands. First, though, we make sure
we're running the latest version of Jessie and that all the software is up to date. Here are the
commands to run to upgrade the system and install the mosquitto components:
1. sudo apt-get update
2. sudo apt-get upgrade
3. sudo apt-get dist-upgrade
4. sudo apt-get install mosquitto mosquitto-clients python-mosquitto
Step 2 - Configure Mosquitto and Restart the Service
Mosquitto is controlled in two ways. First, the default configuration is in
/etc/mosquitto/mosquitto.conf. I recommend you not edit this file, however, and instead, use
the second mechanism, which is a file with a .conf extension in /etc/mosquitto/conf.d. I
actually named mine mosquitto.conf, too, so the full path to the local configuration file is
/etc/mosquitto/conf.d/mosquitto.conf. This file is populated with example configurations by
default, so you'll want to edit it for your local use. Here is the local configuration file I
recommend:
1. # Config file for mosquitto
2. #
3. # See mosquitto.conf(5) for more information.
4.
5. user mosquitto
6. max_queued_messages 200
7. message_size_limit 0
8. allow_zero_length_clientid true
9. allow_duplicate_messages false
10.
11. listener 1883
12. autosave_interval 900
13. autosave_on_changes false
14. persistence true
15. persistence_file mosquitto.db
16. allow_anonymous true
17. password_file /etc/mosquitto/passwd
Once you have edited the configuration file, restart the service with the command
sudo systemctl restart mosquitto
Step 3 - Copy in the security.py Program and Edit it for
Your Installation
Here is the security.py program:
#######################################################################
# security.py - Monitors a Mosquitto MQTT queue for security events
# from an array of secufity sensors, detects critical changes in those
# sensor values, and injects alarms into an io.adafruit.com queue.
# Note: The hardware to do this is already developed (Feather Huzzah
# ESP8266 with NodeCMU), along with the Lua software to run on
# the ESP8266. The next development steps are:
# - write this python program
# - write the If This Then That interface to do notifications
# Note two: The implementation uses normally-closed reed switches
# from China. If you use normally open switches, you'll have to
# edit this code to invert the tests for the values coming from
# the sensors.
# Philip R. Moyer
# Adafruit
# May 2016
# This code is released under a BSD liense and is in the public domain.
# Any redistribution must include the above header.
#######################################################################
########################
# Libraries
########################
import os
import string
import paho.mqtt.client as mqtt
import Adafruit_IO
import time
########################
# Globals
########################
# -- Change these as needed for your installatin --
localBroker = "YOUR_BROKER_IP" # Local MQTT broker
localPort = 1883 # Local MQTT port
localUser = "YOUR_MQTT_USERID" # Local MQTT user
localPass = "YOUR_MQTT_PASSWORD" # Local MQTT password
localTopic = "/security" # Local MQTT topic to monitor
localTimeOut = 120 # Local MQTT session timeout
adafruitUser = "YOUR_ADAFRUIT_IO_USERID" # Adafruit.IO user ID
adafruitKey = "YOUR_ADAFRUIT_IO_KEY" # Adafruit.IO user key
adafruitTopic = "alarms" # Adafruit.IO alarm topic
# -- You should not need to change anything below this line --
sensorList = {} # List of sensor objects
########################
# Classes and Methods
########################
class sensor():
def __init__(self):
self.name = "" # Name of sensor in MQTT
self.humanName = "" # Human-meaningful name (e.g., "front door")
self.lastSeen = 0 # Number of seconds since the sensor was last seen
self.state = "unknown" # State of the object: unknown, open, or closed
def setState(self, newstate):
self.state = newState
def getState(self):
return self.state
def resetHeartbeat(self):
self.lastSeen = 0
def setname(self, newName, humanName):
self.name = newName
self.humanName = humanName
def getname(self):
return self.humanName
def checkState(self, newState):
if ("unknown" == self.state):
self.state = newState
return 0
else:
if (newState != self.state):
self.state = newState
if ("closed" == self.state):
return -1
else:
return 1
return 0
class sensorList():
def __init__(self):
self.sensorList = {}
def addSensor(self, sensorName, humanName):
self.sensorList[sensorName] = sensor()
self.sensorList[sensorName].setname(sensorName, humanName)
def getSensorName(self, sensorID):
return self.sensorList[sensorID].getname()
def sensorState(self, sensorID, monitorState):
rv = self.sensorList[sensorID].checkState(monitorState)
if (0 != rv):
# State changed!
if (0 > rv):
outBuf = "INFO "+self.getSensorName(sensorID)+"
"+monitorState
print(outBuf)
else:
outBuf = "ALARM "+self.getSensorName(sensorID)+"
"+monitorState
print(outBuf)
print("Initiating connection to Adafruit.IO")
AIOclient = Adafruit_IO.MQTTClient(adafruitUser,
adafruitKey)
print("Setting callbacks for Adafruit.IO")
AIOclient.on_connect = AIOconnected
AIOclient.on_disconnect = AIOdisconnected
AIOclient.on_message = AIOmessage
print("Connecting to Adafruit.IO")
AIOclient.connect()
time.sleep(5)
print("Publishing outBuf")
# AIOclient.publish("alarms", outBuf)
AIOclient.publish("alarms", outBuf)
print("Disconnecting")
AIOclient.disconnect()
########################
# Functions
########################
# Callback functions for Adafruit.IO connections
def AIOconnected(client):
# client.subscribe('alarms')
print("Connected to Adafruit.IO")
def AIOdisconnected(client):
print("adafruit.io client disconnected!")
def AIOmessage(client, feed_id, payload):
print("adafruit.io received ", payload)
# returnState takes a numeric voltage value from the sensor and
# returns the state of the monitored device. With a voltage divider
# that uses a 1M ohm R1 and a 470K ohm R2, the "closed" state returns
# 1024 and the open state returns between 1 and 40.
def returnState(inVal):
if (1000 < inVal):
return "closed"
if (100 > inVal):
return "open"
else:
return "unknown"
########################
# Main
######################
if "__main__" == __name__:
# Set timer
sensList = sensorList()
sensList.addSensor("security_001", "front door")
# The callback for when the client receives a CONNACK response from the server.
def on_connect(client, userdata, flags, 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("/security")
# The callback for when a PUBLISH message is received from the server.
def on_message(client, userdata, msg):
(sensorID, sensorVoltage) = string.split(msg.payload)
sensorVoltage = string.atoi(sensorVoltage)
sensorName = sensList.getSensorName(sensorID)
sensList.sensorState(sensorID, returnState(sensorVoltage))
# print(sensorName+" "+returnState(sensorVoltage))
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect(localBroker, localPort, localTimeOut)
# 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()
quit()
Copy security.py to /home/pi/security.py on the machine that is your MQTT broker. Edit
the program so the parameters are correct for your installation. I recommend keeping the
"/security" topic, though.
You also need to install the Adafruit_IO Python library. You can clone it from the GitHub
repository or click this button to download a Zip file. Put it in the same directory as your
security.py program.
1. #######################################################################
2. # security.py - Monitors a Mosquitto MQTT queue for security events
3. # from an array of secufity sensors, detects critical changes in those
4. # sensor values, and injects alarms into an io.adafruit.com queue.
5. #
6. # Note: The hardware to do this is already developed (Feather Huzzah
7. # ESP8266 with NodeCMU), along with the Lua software to run on
8. # the ESP8266. The next development steps are:
9. # - write this python program
10. # - write the If This Then That interface to do notifications
11. #
12. # Note two: The implementation uses normally-closed reed switches
13. # from China. If you use normally open switches, you'll have to
14. # edit this code to invert the tests for the values coming from
15. # the sensors.
16. #
17. # Philip R. Moyer
18. # Adafruit
19. # May 2016
20. #
21. # This code is released under a BSD liense and is in the public domain.
22. # Any redistribution must include the above header.
23. #######################################################################
24.
25. ########################
26. # Libraries
27. ########################
28.
29. import os
30. import string
31. import paho.mqtt.client as mqtt
32. import Adafruit_IO
33. import time
34.
35.
36. ########################
37. # Globals
38. ########################
39.
40. # -- Change these as needed for your installatin --
41.
42. localBroker = "YOUR_BROKER_IP" # Local MQTT broker
43. localPort = 1883 # Local MQTT port
44. localUser = "YOUR_MQTT_USERID" # Local MQTT user
45. localPass = "YOUR_MQTT_PASSWORD" # Local MQTT password
46. localTopic = "/security" # Local MQTT topic to monitor
47. localTimeOut = 120 # Local MQTT session timeout
48.
49. adafruitUser = "YOUR_ADAFRUIT_IO_USERID" # Adafruit.IO user ID
50. adafruitKey = "YOUR_ADAFRUIT_IO_KEY" # Adafruit.IO user key
51. adafruitTopic = "alarms" # Adafruit.IO alarm topic
52.
53. # -- You should not need to change anything below this line --
54.
55. sensorList = {} # List of sensor objects
56.
57.
58. ########################
59. # Classes and Methods
60. ########################
61.
62. class sensor():
63. def __init__(self):
64. self.name = "" # Name of sensor in MQTT
65. self.humanName = "" # Human-meaningful name (e.g., "front door")
66. self.lastSeen = 0 # Number of seconds since the sensor was last
seen
67. self.state = "unknown" # State of the object: unknown, open, or closed
68.
69. def setState(self, newstate):
70. self.state = newState
71.
72. def getState(self):
73. return self.state
74.
75. def resetHeartbeat(self):
76. self.lastSeen = 0
77.
78. def setname(self, newName, humanName):
79. self.name = newName
80. self.humanName = humanName
81.
82. def getname(self):
83. return self.humanName
84.
85. def checkState(self, newState):
86. if ("unknown" == self.state):
87. self.state = newState
88. return 0
89. else:
90. if (newState != self.state):
91. self.state = newState
92. if ("closed" == self.state):
93. return -1
94. else:
95. return 1
96. return 0
97.
98.
99. class sensorList():
100. def __init__(self):
101. self.sensorList = {}
102.
103. def addSensor(self, sensorName, humanName):
104. self.sensorList[sensorName] = sensor()
105. self.sensorList[sensorName].setname(sensorName, humanName)
106.
107. def getSensorName(self, sensorID):
108. return self.sensorList[sensorID].getname()
109.
110. def sensorState(self, sensorID, monitorState):
111. rv = self.sensorList[sensorID].checkState(monitorState)
112. if (0 != rv):
113. # State changed!
114. if (0 > rv):
115. outBuf = "INFO "+self.getSensorName(sensorID)+"
"+monitorState
116. print(outBuf)
117. else:
118. outBuf = "ALARM
"+self.getSensorName(sensorID)+" "+monitorState
119. print(outBuf)
120. print("Initiating connection to Adafruit.IO")
121. AIOclient = Adafruit_IO.MQTTClient(adafruitUser,
adafruitKey)
122. print("Setting callbacks for Adafruit.IO")
123. AIOclient.on_connect = AIOconnected
124. AIOclient.on_disconnect = AIOdisconnected
125. AIOclient.on_message = AIOmessage
126. print("Connecting to Adafruit.IO")
127. AIOclient.connect()
128. time.sleep(5)
129. print("Publishing outBuf")
130. # AIOclient.publish("alarms", outBuf)
131. AIOclient.publish("alarms", outBuf)
132. print("Disconnecting")
133. AIOclient.disconnect()
134.
135.
136. ########################
137. # Functions
138. ########################
139.
140. # Callback functions for Adafruit.IO connections
141. def AIOconnected(client):
142. # client.subscribe('alarms')
143. print("Connected to Adafruit.IO")
144.
145. def AIOdisconnected(client):
146. print("adafruit.io client disconnected!")
147.
148. def AIOmessage(client, feed_id, payload):
149. print("adafruit.io received ", payload)
150.
151.
152. # returnState takes a numeric voltage value from the sensor and
153. # returns the state of the monitored device. With a voltage divider
154. # that uses a 1M ohm R1 and a 470K ohm R2, the "closed" state returns
155. # 1024 and the open state returns between 1 and 40.
156.
157. def returnState(inVal):
158. if (1000 < inVal):
159. return "closed"
160. if (100 > inVal):
161. return "open"
162. else:
163. return "unknown"
164.
165.
166. ########################
167. # Main
168. ########################
169.
170. if "__main__" == __name__:
171. # Set timer
172.
173. sensList = sensorList()
174. sensList.addSensor("security_001", "front door")
175.
176. # The callback for when the client receives a CONNACK response from the
server.
177. def on_connect(client, userdata, flags, rc):
178. print("Connected with result code "+str(rc))
179.
180. # Subscribing in on_connect() means that if we lose the connection
and
181. # reconnect then subscriptions will be renewed.
182. client.subscribe("/security")
183.
184. # The callback for when a PUBLISH message is received from the server.
185. def on_message(client, userdata, msg):
186. (sensorID, sensorVoltage) = string.split(msg.payload)
187. sensorVoltage = string.atoi(sensorVoltage)
188. sensorName = sensList.getSensorName(sensorID)
189. sensList.sensorState(sensorID, returnState(sensorVoltage))
190. # print(sensorName+" "+returnState(sensorVoltage))
191.
192. client = mqtt.Client()
193. client.on_connect = on_connect
194. client.on_message = on_message
195.
196. client.connect(localBroker, localPort, localTimeOut)
197.
198. # Blocking call that processes network traffic, dispatches callbacks and
199. # handles reconnecting.
200. # Other loop*() functions are available that give a threaded interface and a
201. # manual interface.
202. client.loop_forever()
203.
204. quit()
MQTT Security: Securing a Mosquitto
Server
This post describes how to implement MQTT security. In more detail, we will describe
how to secure a Mosquitto MQTT server. As you may already know, MQTT is one of the
most important protocols widely used in IoT and IIoT. MQTT is a lightweight, messaging-
oriented protocol where an MQTT client exchanges messages through an MQTT server
called an MQTT broker. We have covered all these aspects of MQTT in my MQTT
protocol tutorial.
In this post, we want to face the MQTT security aspects with a special regard to the aspects
related to MQTT Mosquitto security.
Generally speaking, the Internet of Things is the upcoming technological revolution where
objects, called smart objects, are connected to the Internet exchanging data and
information. One of the main concerns about IoT is the security aspect. Considering that
IoT will impact our everyday lives and these smart objects are able to acquire and collect
different kinds of information, security is an important aspect. Some of this information is
sensitive (we can think about health data), and it is important to be sure that no one else can
use it except the permitted persons and systems.
In this context, it is important to know how to secure the MQTT protocol and how to
protect your information. In the next paragraphs, we will analyze the steps we have to
follow to secure MQTT using a Raspberry Pi as the MQTT broker.
What Does MQTT Security Mean?
By its nature, MQTT is a plain protocol. All the information exchanged is in plain-text
format. In other words, anyone could access to this message and read the payload. Of
course, there are several use cases where we want to keep information private and
guarantee that it cannot be read or modified during the transmitting process. In this case,
there are several approaches we can use to face the MQTT security problem:
1. Create a VPN between the clients and the server.
2. Use MQTT over SSL/TSL to encrypt and secure the information between the
MQTT clients and MQTT broker.
We will focus our attention on how to create an MQTT over SSL. To make MQTT a
secure protocol, we have to follow these steps:
Create a private key (CA Key).
Generate a certificate using the private key (CA cert).
Create a certificate for Mosquitto MQTT server with the key.
The final step is configuring Mosquitto MQTT so that it uses these certificates.
Securing Mosquitto MQTT Server
The first step in this process is creating a private key. Connect to the Raspberry Pi using ssh
or a remote desktop as you prefer and open a command terminal. Before starting, it is
important you ensure OpenSSL is installed on your Raspberry Pi. If not, you can download
it from here.
Before creating the private key, you should create a directory where you store all the
certificates you will create. In the terminal, write:
openssl genrsa -out mosq-ca.key 2048
Using this command, we are creating a 2048-bit key called mosq-ca.key. The result is
shown in the picture below:
The next step is creating an X509 certificate that uses the private key generated in the
previous step. Open the terminal again and, in the same directory you used to store the
private key, write:
openssl req -new -x509 -days365 -key mosq-ca.key -out mosq-ca.crt
In this step, you have to provide different information before creating the certificate as
shown in the picture below:
Creating the MQTT Server Certificate
Once the private key and the certificate are ready, we can move on and create the MQTT
server certificate and private key:
openssl genrsa -out mosq-serv.key 2048
Then the server certificate. During this step, we have to create a CSR (Certificate Signing
Request). This certificate should be sent to the Certification authority that, after verifying
the author identity, returns a certificate. In this tutorial, we will use a self-signed certificate:
openssl req -new -key mosq-serv.key -out mosq-serv.csr
As you can see, we have used the private key generated in the step before. Finally, we can
create the certificate to use in our MQTT Mosquitto Server:
openssl x509 -req -in mosq-serv.csr -CA mosq-ca.crt -CAkey mosq-ca.key -
CAcreateserial -out mosq-serv.crt -days 365 -sha256
All done! We have completed the steps necessary to secure our MQTT server. You can
verify your certificate:
openssl x509 -in mosq-serv.crt -noout -textjavascript:void(0)
Now you should see the certificate.
How to Configure MQTT Mosquitto Server to Secure
MQTT
Once the certificates are ready, we have to configure MQTT Mosquitto Server so that it can
use these certificates. The certificates we have to use are:
mosq-ca.crt
mosq-serv.crt
mosq-serv.key
Locate the mosquitto.conf file that holds all the configuration parameters and add the
following lines:
listener 8883
cafile /home/pi/ssl-cert-mosq/mosq-ca.crt
certfile /home/pi/ssl-cert-mosq/mosq-serv.crt
keyfile /home/pi/ssl-cert-mosq/mosq-serv.key
The path /home/pi/ssl-cert-mosq is the path where you stored your certificate. Moreover,
we change the default Mosquitto MQTT port to 8883.
Now you have to stop and restart Mosquitto MQTT so that it can read the new
configuration file:
sudo service mosquitto stop/start
That's all. Now our MQTT protocol is secure and encrypted. The last step is testing the
configuration and the MQTT server.
MQTT Security Testing Mosquitto Over SSL/TSL
In this step, we will verify if the connection is correctly configured. For this purpose, we
use MQTT.fx, a Java-based MQTT client. After you install it, we have to create a new
profile providing all the information as shown in the picture below:
Notice that we have enabled the SSL/TSL configuration, providing the mosq-ca.crt creating
during the previous steps.
Finally, we can connect to the MQTT Mosquitto server:
Click on Connect. You will notice that the MQTT client will establish the connection to the
MQTT broker as you can check in the log tab.
Now it is time to test if our client gets the message. Select the subscribe menu and
subscribe the MQTT client to a topic (choosing a topic name).
On the Raspberry Pi side, let's send a message on the same channel:
mosquitto_pub -p 8883 -t "test" -cafile mosq-ca.crt -m "Hello MQTT" -d -h
192.168.1.8
The result is shown in the picture below:
On the subscriber side, we have:
As you can see, we received the message sent by the publisher.