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:

sudo apt-get update
sudo apt-get upgrade
sudo apt-get dist-upgrade
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:

# Config file for mosquitto
#
# See mosquitto.conf(5) for more information.

user mosquitto
max_queued_messages 200
message_size_limit 0
allow_zero_length_clientid true
allow_duplicate_messages false

listener 1883
autosave_interval 900
autosave_on_changes false
persistence true
persistence_file mosquitto.db
allow_anonymous true
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.

 

Step 4 - Configure security.py to Run at Boot

I cheat and use the old school mechanism for starting security.py at boot: I add it to /etc/rcc.local and make sure rc.local runs at boot time. This must be done as root. Here are the commands to use to make this configuration:

sudo chmod 755 /etc/rc.local
sudo nano /etc/rc.local

You can use your favorite text editor to make changes to /etc/rc.local. All you need to do is add one line near the bottom of the file. Here is the bottom of my rc.local file on my Raspberry Pi that controls the alarm system:

ifup eth0

/usr/bin/python /home/pi/security.py &
  
exit 0

The line with python that executes security.py is the line to add.

Step 5 - Start security.py

This is the easiest part. Just run this command:

sudo /etc/rc.local

Next: Configuring io.adafruit.com

Last updated on 2016-06-23 at 07.35.58 AM Published on 2016-06-23 at 10.55.31 PM