Controlling Devices Using MQTT and PythonOnline tutorial and downloadable Project workbook where we use MQTT to control a python script.
The script is a simple sensor but I have used the same technique to control many other python scripts.What it covers:
- Basic topic design
- Basic MQTT API creation
Prerequisites You should be familiar with the Paho MQTT client
MQTT can not only be used for collecting sensor data it can also be used for controlling devices.
In this mini workshop we will be creating a device in Python that can be controlled using MQTT.
Although our sample device is a simple sensor I have used the same idea and similar code to add MQTT control to Python command line control scripts.
We will start the workshop by designing a topic structure and then we will create the Python code.
Before you start it is important to decide on a topic structure.
The structure I normally use for commands looks like this:
topic base + cmnd+ device + device_command +command value
Notice the device_command and command value at the end. This is the actual command you want to issue to the device e.g power to turn the power on/off or timer to set the time.
In a simple case were the device can only accept a single command the device_command can be omitted.
In this workshop the actual command value e.g on or off is part of the topic. For more complex data it would be part of the payload and usually JSON encoded.
Sending a command results in a response from the device. The topic response from the device would be published on
topic base + response + device
In addition the device might also send status data and readings which in turn would use their own topics e.g.
- topic base + telemetry+ device
- topic base + status+ device
You should notice the topic structure is chosen as it allows you to subscribe to the topic base and receive all data and then to easily filter commands from responses.
- house/cmnd/outside-light or house/cmnd/outside-light/power
Friendly Name vs Device ID
Most IOT devices will come with a device ID which can’t be changed and uniquely identifies the device.
When setting up the device then it is common to assign and use a friendly name that is more descriptive e.g main light.
Alternative or Backup Names
A device can also have an alternative name which allows you to control the device in case something happens to the original friendly name. For example if a device rename goes wrong.
It is common to group devices into control groups so that you can, for example, turn all lights off and on with a single command.
So we could put all of our lights in the lights group and turn them on or off with a single command to the lights group.
Command in Payload or Topic
To turn our lights on/off we could issue the command value as part of the topic so we would have the structure:
topic base + cmnd+ device +command_value
topic base + cmnd+ device +command+command_value
In the case of a simple switch the command values would be on and off
Alternatively the command can be sent in the payload.
Simple data can be sent in the topic but more complex data like JSON data is sent in the payload.
In this workshop we will implement the topic method.
The response contains the command in the payload.
The python code needs to:
Subscribe to the topic to receive commands
Analyse the received topic and extract the device, device command, and command value .
Check that the command is valid
Execute the command, and update the status and send a response.
The topic structure Used in the code is shown below and is at the top of the code
In our Python code this is starts in the on_message callback. The on_message callback calls the message handler.
The Message hander extracts the various elements from the topic and checks that the command value sent is valid.
If valid, it calls two functions. These functions update the status and send a response.
The functions are shown below:
You should note that the code currently doesn’t check the device name and so it will work for any device name.
It will also work with a device_command and without one.
The house/connected topic is not mandatory but I use it so that it is easy to identify connected clients by simply subscribing to this topic.
The device publishes a retained message (value=1) on this topic when it connects.
Before it disconnects it should publish a 0 on this topic. For completeness the will message should be set to do this when the connection fails.
The sample code is available below:
I prefer to use the mosquitto_sub and pub tools for testing but you can use MQTTBox or any other tool of your choice.
You will need to subscribe to house/# to see the commands responses and status messages.
You then publish on
To turn the light on and use off to turn it off. These states are checked in the code but the case isn’t important. Example below:
Adding Device Name Support
In the case of a simple sensor there will be only a single name but as mentioned earlier we will have an hard coded name and friendly name and also group names.
In addition we will also need to be able to change the device friendly name, and also add/remove the device from groups.
So we will start with hard coded values.
Device name= 111111
Device friendly name= lounge-light
backup name=sensor/device name
Before updating the status and executing commands the device name needs to be checked. The function is shown below
In the handler we check if the name is valid and ignore the command if it isn’t
Issuing Other Commands
Besides simply turning the switch on and off we might want to add the switch to a group or change its name.
In order to do this we need to use a topic structure like this
topic base + cmnd + device + device_command
For each command we will need to create a function. Below is the code for three functions:
To change the friendly name we need to add another command which we will call change_name and to change it we set the value to the new name so we have a command of the form:
In the message handler we need to extract the command and call it if it is valid.
The message handler function has been re-coded to do this and note that we only need to look for the command if we have the required topic fields.
The do command function checks and calls the command if it is valid.
All of the commands are contained in the commands dictionary which needs to be declared after the functions have been declared
The complete code is in the file device1.py and you should now be able to change the friendly name and change it back again.
Source code Download
Questions That you can answer by trying
Q1- Can you change the sensor name using the device name
Q2- Can you change the sensor name using the group name
Q3 -Can you change the sensor name using the device friendly name
Q4- Should you be able to control the device using the backup friendly name?
Answers are below
This workshop is also available as a pdf with demo scripts on my buy me a coffee page
Continue to part 2
Related tutorials and Resources
- Using MQTT APIs For IOT -Beginners Guide
- Checking Active MQTT Client Connections
- Simple Python MQTT Sensor Simulator
- MQTT Topic and Payload Design Notes