IoT Development with Python: Practical Communication between MQTT Protocol and ESP8266 for Smart Home Solutions!

Last summer. That hot afternoon.

I was busy debugging my smart socket at home when I found it inexplicably disconnected again. This was the third time this week. Each time I had to reconfigure the WiFi, which was driving me crazy. At that moment, I thought, why can’t I make a more stable smart device myself?

At that time, I was still a novice in the Internet of Things (IoT), only knowing that the ESP8266 was a cheap and useful WiFi module, but I didn’t know how to make a Python program communicate with it.

01

Communication between IoT devices is actually like chatting between people; it requires a common “language”. This language is the MQTT protocol.

To put it simply, MQTT is a lightweight messaging protocol specifically designed for the IoT. Its working principle is very similar to a WeChat group chat, where there is a “server” acting as the group owner, and all devices connect to this group to send messages and subscribe to others’ messages.

I was completely amazed by the simplicity of MQTT when I first encountered it. It is much lighter than the HTTP protocol, making it particularly suitable for IoT devices with small memory and unstable networks.

The ESP8266 is such a device. Cheap. Stable. Powerful WiFi functionality.

02

First, let’s set up the MQTT client on the Python side. I used the paho-mqtt library, which is super easy to install:

import paho.mqtt.client as mqtt
import json
import time

class IoTController:
    def __init__(self, broker_host="localhost", broker_port=1883):
        self.client = mqtt.Client()
        self.broker_host = broker_host
        self.broker_port = broker_port
        
        # Set callback functions
        self.client.on_connect = self.on_connect
        self.client.on_message = self.on_message
        
    def on_connect(self, client, userdata, flags, rc):
        print(f"Connection result code: {rc}")
        if rc == 0:
            print("Successfully connected to MQTT broker")
            # Subscribe to sensor data sent by ESP8266
            client.subscribe("sensor/temperature")
            client.subscribe("sensor/humidity")
        
    def on_message(self, client, userdata, msg):
        topic = msg.topic
        payload = msg.payload.decode()
        print(f"Received message - Topic: {topic} Content: {payload}")
        
        # Parse JSON data
        try:
            data = json.loads(payload)
            self.process_sensor_data(topic, data)
        except json.JSONDecodeError:
            print("JSON parsing failed")
            
    def process_sensor_data(self, topic, data):
        """Process sensor data"""
        if topic == "sensor/temperature":
            temp = data.get("value")
            print(f"Current temperature: {temp}°C")
            
            # Control fan if temperature is too high
            if temp > 28:
                self.control_device("fan", "on")
                
        elif topic == "sensor/humidity":
            humidity = data.get("value")
            print(f"Current humidity: {humidity}%")
            
    def control_device(self, device, action):
        """Control smart device"""
        command = {"device": device, "action": action}
        self.client.publish("control/commands", json.dumps(command))
        print(f"Sent control command: {command}")
        
    def start(self):
        self.client.connect(self.broker_host, self.broker_port, 60)
        self.client.loop_forever()

# Example usage
if __name__ == "__main__":
    controller = IoTController()
    controller.start()

This code may look a bit long, but the logic is very clear. It mainly connects to the MQTT broker, subscribes to sensor data, and then controls accordingly based on the data.

The key is the on_message callback function, which is called every time the ESP8266 sends data.

03

The code on the ESP8266 side was written using the Arduino IDE, mainly to read sensor data and send it to the MQTT topics:

#include <WiFi.h>
#include <PubSubClient.h>
#include <DHT.h>
#include <ArduinoJson.h>

// WiFi configuration
const char* ssid = "Your WiFi Name";
const char* password = "WiFi Password";

// MQTT configuration
const char* mqtt_server = "Your MQTT Server IP";
const int mqtt_port = 1883;

// Sensor configuration
#define DHT_PIN 2
#define DHT_TYPE DHT22
DHT dht(DHT_PIN, DHT_TYPE);

WiFiClient espClient;
PubSubClient client(espClient);

void setup() {
    Serial.begin(115200);
    dht.begin();
    
    // Connect to WiFi
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println("WiFi connected successfully");
    
    // Configure MQTT
    client.setServer(mqtt_server, mqtt_port);
    client.setCallback(callback);
}

void callback(char* topic, byte* payload, unsigned int length) {
    // Handle control commands from Python
    String message = "";
    for (int i = 0; i < length; i++) {
        message += (char)payload[i];
    }
    
    DynamicJsonDocument doc(1024);
    deserializeJson(doc, message);
    
    String device = doc["device"];
    String action = doc["action"];
    
    if (device == "fan" && action == "on") {
        digitalWrite(LED_BUILTIN, HIGH);  // Simulate fan with LED
        Serial.println("Fan has been turned on");
    }
}

void loop() {
    if (!client.connected()) {
        reconnect();
    }
    client.loop();
    
    // Read sensor data every 10 seconds
    static unsigned long lastMsg = 0;
    unsigned long now = millis();
    if (now - lastMsg > 10000) {
        lastMsg = now;
        
        float temp = dht.readTemperature();
        float humidity = dht.readHumidity();
        
        if (!isnan(temp)) {
            DynamicJsonDocument doc(1024);
            doc["value"] = temp;
            doc["timestamp"] = now;
            
            String output;
            serializeJson(doc, output);
            client.publish("sensor/temperature", output.c_str());
        }
        
        if (!isnan(humidity)) {
            DynamicJsonDocument doc(1024);
            doc["value"] = humidity;
            doc["timestamp"] = now;
            
            String output;
            serializeJson(doc, output);
            client.publish("sensor/humidity", output.c_str());
        }
    }
}

The core of the entire system is the MQTT broker. I recommend using Mosquitto, which is free and stable.

04

In actual projects, I encountered many pitfalls.

Network disconnections and reconnections are the most troublesome. The ESP8266’s WiFi sometimes disconnects inexplicably, so an automatic reconnection mechanism must be added. My experience is to set a watchdog timer; if a heartbeat packet is not successfully sent for a long time, the device should automatically restart.

Also, the choice of message QoS level is important. Generally, QoS 0 is sufficient for sensor data; losing a message occasionally is acceptable, but control commands must use QoS 1 to ensure delivery.

Although JSON format is convenient, parsing it on the ESP8266 consumes a lot of memory. If the data volume is large, consider using a simpler format, such as directly concatenating strings.

Power management is also crucial. The ESP8266 can enter deep sleep mode, significantly reducing power consumption, which is especially suitable for battery-powered scenarios.

05

I have been using this solution at home for almost a year, controlling the living room lights, bedroom air conditioning, and the automatic watering system on the balcony. Its stability is much better than those purchased smart devices.

The biggest gain is understanding the essence of IoT development, which is essentially about data collection, transmission, and processing. The MQTT protocol makes this process very simple and elegant.

Next, I plan to incorporate machine learning to predict household electricity usage based on historical data, achieving smarter energy management.

Friends interested can start with this simple temperature and humidity monitoring system and gradually build their own smart home system. Trust me, it’s much more interesting than buying ready-made products!

Leave a Comment