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:
- Install mosquitto (MQTT) components.
- Configure mosquitto and restart the service.
- Copy in the security.py program and edit it for your installation.
- Configure security.py to run at boot.
- 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.
This is the easiest part. Just run this command:
sudo /etc/rc.local
Next: Configuring io.adafruit.com
Text editor powered by tinymce.