蜂窝网络模组的MQTT功能

MQTT协议全面解析

MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是一种轻量级、基于发布/订阅模式的物联网通信协议

一、MQTT核心概念

1. 设计目的

复制代码
为物联网而生:
- 低带宽环境优化
- 低功耗设计  
- 高延迟/不可靠网络容错
- 简单易实现

2. 与HTTP对比

特性 MQTT HTTP
协议模型 发布/订阅 请求/响应
消息方向 双向 单向
连接开销 小(2字节心跳) 大(每次TCP握手)
消息大小 小(头部最小2字节) 大(头部几百字节)
实时性 高(推送机制) 低(轮询或长连接)

二、MQTT架构模型

发布/订阅模式:

三、MQTT协议详解

1. MQTT控制报文结构

复制代码
固定头部(2-5字节)
+------------+------------+------------+
| 控制报文类型 | 标志位      | 剩余长度    |
| (4 bits)   | (4 bits)   | (1-4 bytes)|
+------------+------------+------------+

可变头部(可选)
+---------------------+
| 协议名/版本         |
| 连接标志           |
| 保持连接时间       |
| 客户端ID等         |
+---------------------+

有效载荷(可选)
+---------------------+
| 实际消息数据        |
+---------------------+

2. 14种控制报文类型

报文类型 方向 说明
1 CONNECT C→S 客户端连接请求
2 CONNACK S→C 连接确认
3 PUBLISH 双向 发布消息
4 PUBACK 双向 QoS 1消息确认
5 PUBREC 双向 QoS 2消息收到
6 PUBREL 双向 QoS 2消息释放
7 PUBCOMP 双向 QoS 2消息完成
8 SUBSCRIBE C→S 订阅请求
9 SUBACK S→C 订阅确认
10 UNSUBSCRIBE C→S 取消订阅
11 UNSUBACK S→C 取消订阅确认
12 PINGREQ C→S 心跳请求
13 PINGRESP S→C 心跳响应
14 DISCONNECT C→S 断开连接

四、QoS(服务质量等级)

QoS 0:最多交付一次

QoS 1:至少交付一次

QoS 2:恰好交付一次

五、蜂窝网络模组的MQTT功能详解

蜂窝网络模组(4G/5G Cat.1/NB-IoT)的MQTT功能是物联网通信的核心。

1. 整体架构图

2. 工作模式对比

模式 实现方式 优点 缺点
AT命令模式 模组内置MQTT客户端,通过AT命令控制 省电,代码简单 功能受限,依赖模组固件
Socket模式 模组提供TCP Socket,上位机实现MQTT 灵活,功能完整 功耗高,实现复杂
内置SDK模式 模厂商提供MQTT SDK 优化好,功能丰富 平台依赖,更新慢

六、AT命令模式详解(最常用)

1. 主流模组AT命令对比

移远模组(Quectel):
复制代码
# MQTT AT命令集
AT+QMTCFG="version",3,4        # 设置MQTT版本(3:3.1.1, 4:5.0)
AT+QMTCFG="aliauth",1,"client1","username","password"
AT+QMTCFG="ssl",1,1            # 启用SSL
AT+QMTOPEN=0,"broker.example.com",1883  # 打开连接
AT+QMTCONN=0,"client123"       # 连接Broker
AT+QMTSUB=0,1,"sensor/temp",1  # 订阅主题
AT+QMTPUBEX=0,1,1,0,"control/light","{"state":"on"}"  # 发布消息
广和通模组(Fibocom):
复制代码
AT+MCONFIG="client123","username","password"  # 配置客户端
AT+MIPSTART="TCP","broker.example.com",1883   # 建立TCP连接
AT+MCONNECT=1,60                              # MQTT连接
AT+MSUB="sensor/#",1                          # 订阅
AT+MPUB="device/status",1,0,"online"          # 发布
华为模组(HiSilicon):
复制代码
AT+MQTTCFG="url","mqtt://broker.example.com:1883"
AT+MQTTCFG="clientid","device_001"
AT+MQTTCFG="username","user"
AT+MQTTCFG="password","pass"
AT+MQTTCONNECT=1,30,1                         # 连接,保持30秒心跳
AT+MQTTSUB="topic/data",1                     # QoS 1订阅
AT+MQTTPUB="topic/cmd",1,0,"reboot"           # 发布命令

2. 完整MQTT会话流程

复制代码
# Python控制蜂窝模组MQTT的示例
import serial
import time
import json

class CellularMQTTClient:
    def __init__(self, port="/dev/ttyUSB2", baudrate=115200):
        self.ser = serial.Serial(port, baudrate, timeout=1)
        self.client_id = f"device_{int(time.time())}"
        
    def send_at(self, command, expected="OK", timeout=2):
        """发送AT命令并等待响应"""
        self.ser.write(f"{command}\r\n".encode())
        time.sleep(0.1)
        
        start_time = time.time()
        response = ""
        
        while time.time() - start_time < timeout:
            if self.ser.in_waiting:
                line = self.ser.readline().decode().strip()
                response += line + "\n"
                if expected in line:
                    return True, response
                if "ERROR" in line:
                    return False, response
        
        return False, response
    
    def setup_mqtt(self, broker, port=1883):
        """配置MQTT连接"""
        steps = [
            # 1. 检查模组就绪
            ("AT", "OK"),
            # 2. 设置MQTT版本
            ('AT+QMTCFG="version",3,4', "OK"),
            # 3. 配置SSL/TLS(可选)
            ('AT+QMTCFG="ssl",1,1', "OK"),
            # 4. 打开连接
            (f'AT+QMTOPEN=0,"{broker}",{port}', "+QMTOPEN: 0,0"),
            # 5. 等待连接建立
            ("", "+QMTOPEN: 0,0"),
        ]
        
        for cmd, expected in steps:
            if cmd:
                success, resp = self.send_at(cmd, expected)
                if not success:
                    print(f"步骤失败: {cmd}")
                    return False
            time.sleep(1)
        
        return True
    
    def connect_broker(self, username=None, password=None):
        """连接MQTT Broker"""
        # 准备连接参数
        client_id = self.client_id
        keepalive = 60
        cleansession = 1
        
        cmd = f'AT+QMTCONN=0,"{client_id}",{keepalive},{cleansession}'
        
        if username and password:
            cmd = f'AT+QMTCONN=0,"{client_id}",{keepalive},{cleansession},"{username}","{password}"'
        
        success, resp = self.send_at(cmd, "+QMTCONN: 0,0,0")
        
        if success:
            print(f"MQTT连接成功,ClientID: {client_id}")
            return True
        else:
            print("MQTT连接失败")
            return False
    
    def subscribe(self, topic, qos=1):
        """订阅主题"""
        cmd = f'AT+QMTSUB=0,1,"{topic}",{qos}'
        success, resp = self.send_at(cmd, "+QMTSUB: 0,1,0")
        return success
    
    def publish(self, topic, payload, qos=1, retain=0):
        """发布消息"""
        # 如果是字典,转换为JSON
        if isinstance(payload, dict):
            payload = json.dumps(payload)
        
        # 注意:payload需要正确处理特殊字符
        encoded_payload = payload.replace('"', '\\"')
        
        cmd = f'AT+QMTPUBEX=0,{qos},{retain},0,"{topic}","{encoded_payload}"'
        success, resp = self.send_at(cmd, "+QMTPUBEX: 0,0")
        return success
    
    def listen_for_messages(self, callback, timeout=30):
        """监听接收到的消息"""
        start_time = time.time()
        
        while time.time() - start_time < timeout:
            if self.ser.in_waiting:
                line = self.ser.readline().decode().strip()
                
                # 解析MQTT消息
                if "+QMTRECV: 0," in line:
                    # 格式: +QMTRECV: 0,<msgid>,<topic>,<payload>
                    parts = line.split(",")
                    if len(parts) >= 4:
                        msgid = parts[1]
                        topic = parts[2].strip('"')
                        payload = parts[3].strip('"')
                        
                        # 调用回调函数处理消息
                        callback(topic, payload)
            
            time.sleep(0.1)
    
    def disconnect(self):
        """断开连接"""
        self.send_at("AT+QMTDISC=0", "+QMTDISC: 0,0")
        self.send_at("AT+QMTCLOSE=0", "+QMTCLOSE: 0,0")
        self.ser.close()

# 使用示例
def on_message_received(topic, payload):
    print(f"收到消息 - 主题: {topic}, 内容: {payload}")
    
    # 解析JSON数据
    try:
        data = json.loads(payload)
        print(f"温度: {data.get('temperature')}°C")
    except:
        print(f"原始数据: {payload}")

# 主程序
if __name__ == "__main__":
    mqtt_client = CellularMQTTClient("/dev/ttyUSB2", 115200)
    
    # 1. 配置MQTT
    if mqtt_client.setup_mqtt("broker.hivemq.com", 1883):
        # 2. 连接Broker
        if mqtt_client.connect_broker():
            # 3. 订阅主题
            mqtt_client.subscribe("sensor/#")
            mqtt_client.subscribe("control/#")
            
            # 4. 发布设备信息
            device_info = {
                "device_id": "sensor_001",
                "firmware": "1.0.0",
                "status": "online",
                "timestamp": time.time()
            }
            mqtt_client.publish("device/info", device_info)
            
            # 5. 模拟传感器数据上报
            for i in range(10):
                sensor_data = {
                    "temperature": 25 + i * 0.5,
                    "humidity": 60 - i,
                    "battery": 85 - i,
                    "timestamp": time.time()
                }
                mqtt_client.publish("sensor/data", sensor_data, qos=1)
                time.sleep(10)
            
            # 6. 监听消息(非阻塞方式)
            import threading
            listen_thread = threading.Thread(
                target=mqtt_client.listen_for_messages,
                args=(on_message_received, 300)  # 监听5分钟
            )
            listen_thread.start()
            
            # 等待线程结束
            listen_thread.join()
            
            # 7. 断开连接
            mqtt_client.disconnect()
相关推荐
HaiLang_IT2 小时前
【信息安全毕业设计】基于双层滤波与分割点改进孤立森林的网络入侵检测算法研究
网络·算法·课程设计
k_cik_ci2 小时前
什么是负载均衡?
服务器·网络·负载均衡
I love this bad girl2 小时前
华为无线VRRP热备份
网络
zbtlink2 小时前
为什么建议用poe路由器,但不建议用poe供电?
网络·智能路由器
Hill_HUIL2 小时前
学习日志19-不同VLAN间通信(3)-三层交换机
网络·学习
阿钱真强道2 小时前
10 jetlinks-mqtt-直连设备-属性-读取-返回
linux·服务器·网络·鸿蒙
BHXDML2 小时前
计算机网络实验:(三)设置虚拟局域网(VLAN)
网络·网络协议·计算机网络
夏旭泽3 小时前
计算机网络-网络层
服务器·网络·计算机网络
数据安全科普王3 小时前
QUIC协议:HTTP/3为何要抛弃TCP?
网络