🌙

后端如何订阅 MQTT 并入库

下面我以 Python 为例,给你一个完整可运行的 后端订阅 MQTT 并存入数据库 的示例代码。 我会把每一步都解释清楚,你可以直接复制修改后使用。


一、整体架构回顾(聚焦后端部分)

LoRa 基站(MQTT 发布者)
   ↓ MQTT(主题:lorawan/devices/+/up)
MQTT Broker(如 Mosquitto,运行在服务器上)
   ↓ 转发消息
后端服务(Python 程序)
   ├─ 订阅 MQTT 主题
   ├─ 解析 JSON 数据
   └─ 存入 MySQL / SQLite 数据库
浏览器通过 HTTP API 查询数据库(这部分在最后简单说明)。

二、准备工作

1. 安装 Python 库

pip install paho-mqtt mysql-connector-python
# 如果只用 SQLite,不需要安装 mysql-connector

2. 准备数据库

选项 A:使用 MySQL(正式环境)

CREATE DATABASE iot_data;
USE iot_data;
​
CREATE TABLE sensor_data (
    id INT AUTO_INCREMENT PRIMARY KEY,
    device_id VARCHAR(50) NOT NULL,
    temperature FLOAT,
    humidity FLOAT,
    rssi INT,
    received_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

选项 B:使用 SQLite(轻量级测试)

# 无需安装,Python 自带
sqlite3 iot_data.db
CREATE TABLE sensor_data (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    device_id TEXT NOT NULL,
    temperature REAL,
    humidity REAL,
    rssi INTEGER,
    received_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

三、完整 Python 后端代码

文件名:mqtt_subscriber.py
import json
import mysql.connector
import sqlite3
import paho.mqtt.client as mqtt
from datetime import datetime
​
# ========== 配置部分 ==========
MQTT_BROKER = "192.168.1.100"  # 改成你的 MQTT Broker IP
MQTT_PORT = 1883
MQTT_TOPIC = "lorawan/devices/+/up"  # + 是通配符,匹配任意设备ID
MQTT_CLIENT_ID = "backend_subscriber"
​
# 数据库选择:True=MySQL, False=SQLite
USE_MYSQL = False  
​
if USE_MYSQL:
    DB_CONFIG = {
        "host": "localhost",
        "user": "root",
        "password": "yourpassword",
        "database": "iot_data"
    }
else:
    SQLITE_DB_PATH = "iot_data.db"
​
# ========== 数据库操作函数 ==========
def save_to_mysql(device_id, temp, hum, rssi):
    """保存数据到 MySQL"""
    conn = mysql.connector.connect(**DB_CONFIG)
    cursor = conn.cursor()
    sql = """
        INSERT INTO sensor_data (device_id, temperature, humidity, rssi)
        VALUES (%s, %s, %s, %s)
    """
    cursor.execute(sql, (device_id, temp, hum, rssi))
    conn.commit()
    cursor.close()
    conn.close()
    print(f"[MySQL] 已保存: {device_id} @ {temp}°C, {hum}%")
​
def save_to_sqlite(device_id, temp, hum, rssi):
    """保存数据到 SQLite"""
    conn = sqlite3.connect(SQLITE_DB_PATH)
    cursor = conn.cursor()
    sql = """
        INSERT INTO sensor_data (device_id, temperature, humidity, rssi)
        VALUES (?, ?, ?, ?)
    """
    cursor.execute(sql, (device_id, temp, hum, rssi))
    conn.commit()
    conn.close()
    print(f"[SQLite] 已保存: {device_id} @ {temp}°C, {hum}%")
​
# ========== MQTT 回调函数 ==========
def on_connect(client, userdata, flags, rc):
    """连接 MQTT Broker 成功时调用"""
    if rc == 0:
        print(f"✅ 成功连接到 MQTT Broker: {MQTT_BROKER}")
        # 订阅主题
        client.subscribe(MQTT_TOPIC)
        print(f"📡 已订阅主题: {MQTT_TOPIC}")
    else:
        print(f"❌ 连接失败,返回码: {rc}")
​
def on_message(client, userdata, msg):
    """收到 MQTT 消息时调用"""
    try:
        # 1. 解析 JSON
        payload = json.loads(msg.payload.decode())
        print(f"📨 收到消息: 主题={msg.topic}, 数据={payload}")
        
        # 2. 提取字段(根据你的实际数据格式调整)
        # 示例数据格式1: {"device":"A001","temp":25.3,"hum":60,"rssi":-75}
        # 示例数据格式2: {"end_device_ids":{"device_id":"A001"},"uplink_message":{"decoded_payload":{"temperature":25.3,"humidity":60},"rx_metadata":[{"rssi":-75}]}}
        
        # 这里按简单格式演示
        device_id = payload.get("device") or payload.get("end_device_ids", {}).get("device_id")
        temperature = payload.get("temp") or payload.get("uplink_message", {}).get("decoded_payload", {}).get("temperature")
        humidity = payload.get("hum") or payload.get("uplink_message", {}).get("decoded_payload", {}).get("humidity")
        rssi = payload.get("rssi") or (payload.get("uplink_message", {}).get("rx_metadata", [{}])[0].get("rssi") if payload.get("uplink_message") else None)
        
        # 3. 检查必要字段
        if device_id is None or temperature is None:
            print("⚠️ 数据格式不完整,跳过")
            return
        
        # 4. 存入数据库
        if USE_MYSQL:
            save_to_mysql(device_id, temperature, humidity, rssi)
        else:
            save_to_sqlite(device_id, temperature, humidity, rssi)
            
    except json.JSONDecodeError:
        print(f"❌ JSON 解析失败: {msg.payload}")
    except Exception as e:
        print(f"❌ 处理消息时出错: {e}")
​
# ========== 主程序 ==========
def main():
    # 创建 MQTT 客户端
    client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=MQTT_CLIENT_ID)
    
    # 绑定回调函数
    client.on_connect = on_connect
    client.on_message = on_message
    
    # 连接到 Broker(如果需要用户名密码,取消下面注释)
    # client.username_pw_set("username", "password")
    client.connect(MQTT_BROKER, MQTT_PORT, 60)
    
    # 开始循环(阻塞式)
    print("🚀 后端服务已启动,等待 MQTT 消息...")
    client.loop_forever()
​
if __name__ == "__main__":
    main()

 

 

四、运行后端服务

python mqtt_subscriber.py

预期输出

🚀 后端服务已启动,等待 MQTT 消息...
✅ 成功连接到 MQTT Broker: 192.168.1.100
📡 已订阅主题: lorawan/devices/+/up
📨 收到消息: 主题=lorawan/devices/A001/up, 数据={'device': 'A001', 'temp': 25.3, 'hum': 60, 'rssi': -75}
[MySQL] 已保存: A001 @ 25.3°C, 60%

五、与你的 AJAX 后端结合(补充 HTTP API)

你还需要一个 HTTP 服务供浏览器 AJAX 调用。可以用 Flask 在同一个 Python 进程中运行(多线程)。

安装 Flask

pip install flask

修改代码,加入 HTTP API

from flask import Flask, jsonify
import sqlite3  # 或 mysql.connector

app = Flask(__name__)

@app.route('/api/latest')
def get_latest():
    """返回最新一条数据"""
    conn = sqlite3.connect(SQLITE_DB_PATH)
    cursor = conn.cursor()
    cursor.execute("SELECT device_id, temperature, humidity, received_at FROM sensor_data ORDER BY received_at DESC LIMIT 1")
    row = cursor.fetchone()
    conn.close()
    
    if row:
        return jsonify({
            "device_id": row[0],
            "temperature": row[1],
            "humidity": row[2],
            "time": row[3]
        })
    else:
        return jsonify({"error": "暂无数据"}), 404

# 在主函数中启动 Flask(需要多线程)
from threading import Thread
def start_flask():
    app.run(host='0.0.0.0', port=8080)

def main():
    # 启动 Flask 线程
    Thread(target=start_flask, daemon=True).start()
    
    # 原来的 MQTT 循环
    client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
    # ... 后面跟之前一样

六、测试整个流程

  1. 启动 MQTT Broker(如果还没有)

    mosquitto -v
  2. 启动后端服务

    python mqtt_subscriber.py
  3. 模拟 LoRa 基站发布消息(测试用)

    mosquitto_pub -h 192.168.1.100 -t "lorawan/devices/A001/up" -m '{"device":"A001","temp":25.3,"hum":60,"rssi":-75}'
  4. 浏览器 AJAX 查询

    • 打开浏览器访问:http://服务器IP:8080/api/latest

    • 返回 JSON 数据


七、关键点总结

步骤说明
MQTT 订阅 client.subscribe("lorawan/devices/+/up") 订阅通配符主题
消息处理 on_message 回调中解析 JSON
数据入库 调用数据库插入函数,支持 MySQL 或 SQLite
并发处理 如果需要同时提供 HTTP API,用多线程(Flask 在另一个线程)
错误处理 捕获 JSON 解析异常、数据库异常,防止程序崩溃

八、实际部署注意事项

  1. QoS 设置:如果担心丢消息,订阅时设置 client.subscribe(topic, qos=1)

  2. 断线重连paho-mqtt 默认会自动重连,但可以加 on_disconnect 回调

  3. 性能优化:高并发时,数据库写入用连接池(如 SQLAlchemy

  4. 安全性

    • MQTT 加用户名密码

    • 用 TLS(端口 8883)

    • 数据库密码用环境变量,不要写死在代码里


posted @ 2026-05-25 21:06  星火撩原  阅读(13)  评论(0)    收藏  举报
本站已运行:0
🌙 夜间模式
🌙
🌙