23、使用 Mosquitto 和 Eclipse Paho 实现 MQTT 通信

使用 Mosquitto 和 Eclipse Paho 实现 MQTT 通信

1. 相关工具介绍
  • Mosquitto :它是一个开源的消息代理,实现了 MQTT 协议的 3.1 和 3.1.1 版本,支持使用发布/订阅模型处理消息。它是 iot.eclipse.org 项目的一部分,采用 Eclipse Public Project (EPL)/EDL 许可。其官网为: http://mosquitto.org
  • Eclipse Paho :该项目提供了 MQTT 的开源客户端实现,其中包含 Python 客户端,也被称为 Paho Python 客户端或 Eclipse Paho MQTT Python 客户端库。这个 Python 客户端最初来自 Mosquitto 项目。Eclipse Paho 项目官网: http://www.eclipse.org/paho ;Eclipse Paho MQTT Python 客户端库(paho - mqtt 模块)官网: https://pypi.python.org/pypi/paho - mqtt/1.1
2. 安装 paho - mqtt 模块

在之前的操作中,我们已经在运行于开发板的 Yocto Linux 中安装了 pip 安装器,用于轻松安装额外的 Python 2.7.3 包。现在,我们使用 pip 安装器来安装 paho - mqtt 1.1,在 SSH 终端中运行以下命令:

pip install paho - mqtt

安装成功后,输出的最后几行将显示 paho - mqtt 包已成功安装,无需担心与构建 wheel 相关的错误消息和不安全平台警告。示例输出如下:

Collecting paho - mqtt
  Downloading paho - mqtt - 1.1.tar.gz (41kB)
    100% |################################| 45kB 147kB/s
Installing collected packages: paho - mqtt
  Running setup.py install for paho - mqtt
Successfully installed paho - mqtt - 1.1
3. 利用公共沙箱服务器

Eclipse 提供了一个公共的沙箱服务器,用于 Eclipse IoT 项目,地址为 iot.eclipse.org,端口为 1883。在后续示例中,我们将使用这个沙箱服务器作为 Mosquitto 消息代理,这样就无需自行设置 Mosquitto 消息代理来测试示例和学习如何使用 Paho Python 客户端。不过,在实际应用中,建议自行设置 Mosquitto 消息代理。

4. 代码示例及实现

我们以之前编写的读取传感器温度和湿度值、在 OLED 矩阵中显示这些值并旋转舵机轴以显示华氏温度的代码(文件名为 iot_python_chapter_08_03.py)为基础,添加与使用 PubNub 云时相同的功能。但这次我们使用 Paho Python 客户端和公共沙箱服务器提供的 Mosquitto 消息代理。

4.1 创建 MessageTopic 类

我们创建一个 MessageTopic 类来表示通信主题,配置 MQTT 客户端、订阅客户端并声明在特定事件触发时执行的回调代码。代码文件为 iot_python_chapter_09_05.py。以下是具体代码:

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

class MessageTopic:
    command_key = "command"
    successfully_processed_command_key = "successfully_processed_command"
    # 请替换为你自己的主题名称
    topic = "iot - python - gaston - hillar/temperature"
    active_instance = None

    def __init__(self, temperature_servo, oled):
        self.temperature_servo = temperature_servo
        self.oled = oled
        self.client = mqtt.Client()
        self.client.on_connect = MessageTopic.on_connect
        self.client.on_message = MessageTopic.on_message
        self.client.connect(host="iot.eclipse.org",
                            port=1883,
                            keepalive=60)
        MessageTopic.active_instance = self

    def loop(self):
        self.client.loop()

    @staticmethod
    def on_connect(client, userdata, flags, rc):
        print("Connected to the {0} topic".format(MessageTopic.topic))
        subscribe_result = client.subscribe(MessageTopic.topic)
        publish_result_1 = client.publish(
            topic=MessageTopic.topic,
            payload="Listening to messages in the Intel Galileo Gen 2 board")

    @staticmethod
    def on_message(client, userdata, msg):
        if msg.topic == MessageTopic.topic:
            print("I've received the following message: {0}".format(str(msg.payload)))
            try:
                message_dictionary = json.loads(msg.payload)
                if MessageTopic.command_key in message_dictionary:
                    if message_dictionary[MessageTopic.command_key] == "print_temperature_fahrenheit":
                        MessageTopic.active_instance.temperature_servo.print_temperature(
                            message_dictionary["temperature_fahrenheit"])
                        MessageTopic.active_instance.publish_response_message(
                            message_dictionary)
                    elif message_dictionary[MessageTopic.command_key] == "print_information_message":
                        MessageTopic.active_instance.oled.print_line(
                            11, message_dictionary["text"])
                        MessageTopic.active_instance.publish_response_message(message_dictionary)
            except ValueError:
                # msg 不是字典
                # 无法解码 JSON 对象
                pass

    def publish_response_message(self, message):
        response_message = json.dumps({
            self.__class__.successfully_processed_command_key:
                message[self.__class__.command_key]})
        result = self.client.publish(topic=self.__class__.topic,
                                     payload=response_message)
        return result

该类的主要功能如下:
- command_key :定义了代码将其理解为命令的键字符串。
- successfully_processed_command_key :定义了在发布到主题的响应消息中,用于表示命令已成功处理的键字符串。
- __init__ 方法:保存传入的 temperature_servo oled 实例,创建 MQTT 客户端实例,设置连接和消息接收的回调函数,并连接到 MQTT 代理。
- on_connect 方法:在成功连接到 MQTT 代理后执行,订阅指定主题并发布一条消息。
- on_message 方法:当接收到订阅主题的消息时执行,解析消息并根据命令执行相应操作。
- publish_response_message 方法:发布响应消息,表明命令已成功处理。

4.2 修改 main 方法

我们使用之前编写的 MessageTopic 类创建一个新的 __main__ 方法,使用 Mosquitto 代理和 MQTT 客户端接收和处理命令。代码如下:

if __name__ == "__main__":
    temperature_and_humidity_sensor = TemperatureAndHumiditySensor(0)
    oled = TemperatureAndHumidityOled(0)
    temperature_servo = TemperatureServo(3)
    message_topic = MessageTopic(temperature_servo, oled)
    while True:
        temperature_and_humidity_sensor.measure_temperature_and_humidity()
        oled.print_temperature(
            temperature_and_humidity_sensor.temperature_fahrenheit,
            temperature_and_humidity_sensor.temperature_celsius)
        oled.print_humidity(
            temperature_and_humidity_sensor.humidity)
        print("Ambient temperature in degrees Celsius: {0}".format(temperature_and_humidity_sensor.temperature_celsius))
        print("Ambient temperature in degrees Fahrenheit: {0}".format(temperature_and_humidity_sensor.temperature_fahrenheit))
        print("Ambient humidity: {0}".format(temperature_and_humidity_sensor.humidity))
        # 睡眠 10 秒(10000 毫秒),但每秒处理一次消息
        for i in range(0, 10):
            message_topic.loop()
            time.sleep(1)

该代码的主要流程如下:
1. 创建传感器、OLED 显示和舵机控制的实例。
2. 创建 MessageTopic 类的实例。
3. 进入无限循环,不断测量温度和湿度,在 OLED 上显示数据,并在控制台打印信息。
4. 每秒调用一次 message_topic.loop() 方法,确保与 MQTT 代理的通信。

5. 代码执行流程示意图
graph LR
    A[开始] --> B[创建实例]
    B --> C[连接 MQTT 代理]
    C --> D[订阅主题]
    D --> E[发布监听消息]
    E --> F[循环测量数据]
    F --> G[显示数据]
    G --> H[处理 MQTT 消息]
    H --> F
6. 总结

通过以上步骤,我们可以利用 Mosquitto 和 Eclipse Paho 实现 MQTT 通信,接收和处理来自 MQTT 代理的消息。在实际应用中,我们可以根据需求修改代码,实现更复杂的功能。同时,要注意使用唯一的主题名称,确保只接收自己发布的消息。

使用 Mosquitto 和 Eclipse Paho 实现 MQTT 通信

7. 编写 Python 客户端发布消息

我们已经有了运行在 Intel Galileo Gen 2 开发板上处理来自 Mosquitto 消息代理命令消息的代码。现在,我们要编写一个 Python 客户端,向 “iot - python - gaston - hillar/temperature” 主题发布消息,从而设计能够通过 MQTT 消息与物联网设备通信的应用程序。

7.1 定义变量和函数

我们将创建多个函数作为 MQTT 客户端事件的回调函数,并声明变量和辅助函数,以便轻松发布包含命令和所需值的消息。代码文件为 iot_python_chapter_09_06.py。以下是具体代码:

import paho.mqtt.client as mqtt
import json

command_key = "command"
topic = "iot - python - gaston - hillar/temperature"

def on_connect(client, userdata, flags, rc):
    print("Connected to the {0} topic".format(topic))
    subscribe_result = client.subscribe(topic)
    publish_result_1 = client.publish(
        topic=topic,
        payload="Listening to messages in the Paho Python Client")
    publish_result_2 = publish_command(
        client,
        topic,
        "print_temperature_fahrenheit",
        "temperature_fahrenheit",
        45)
    publish_result_3 = publish_command(
        client,
        topic,
        "print_information_message",
        "text",
        "Python IoT")

def on_message(client, userdata, msg):
    if msg.topic == topic:
        print("I've received the following message: {0}".format(str(msg.payload)))

def publish_command(client, topic, command_name, key, value):
    command_message = json.dumps({
        command_key: command_name,
        key: value})
    result = client.publish(topic=topic,
                            payload=command_message)
    return result

这些代码的功能如下:
- command_key :定义了消息中表示命令的键字符串。
- on_connect :连接成功后执行,订阅主题并发布三条消息,其中两条通过 publish_command 函数发布特定命令。
- on_message :当接收到订阅主题的消息时,打印消息内容。
- publish_command :构建并发布包含命令的 JSON 消息。

7.2 编写 main 方法

以下是 __main__ 方法的代码:

if __name__ == "__main__":
    client = mqtt.Client()
    client.on_connect = on_connect
    client.on_message = on_message
    client.connect(host="iot.eclipse.org",
                   port=1883,
                   keepalive=60)
    client.loop_forever()

该代码的执行步骤如下:
1. 创建 MQTT 客户端实例。
2. 设置连接和消息接收的回调函数。
3. 连接到 MQTT 代理。
4. 进入无限循环,处理 MQTT 客户端的消息。

8. 客户端代码执行流程示意图
graph LR
    A[开始] --> B[创建 MQTT 客户端]
    B --> C[设置回调函数]
    C --> D[连接 MQTT 代理]
    D --> E[执行 on_connect 回调]
    E --> F[订阅主题]
    F --> G[发布消息]
    G --> H[进入消息循环]
    H --> I[接收消息并执行 on_message 回调]
    I --> H
9. 运行示例及结果

首先,在开发板上保持之前示例的 Python 代码运行,确保开发板能够处理我们发送的命令。然后,在任何想要作为客户端的计算机或设备上运行 Python 客户端代码,可使用以下命令:

python iot_python_chapter_09_06.py

运行客户端代码后,Python 控制台(运行 iot_python_chapter_09_06.py 脚本)将显示以下输出:

Connected to the iot - python - gaston - hillar/temperature topic
I've received the following message: Listening to messages in the Paho Python Client
I've received the following message: {"command": "print_temperature_fahrenheit", "temperature_fahrenheit": 45}
I've received the following message: {"text": "Python IoT", "command": "print_information_message"}
I've received the following message: {"successfully_processed_command": "print_temperature_fahrenheit"}
I've received the following message: {"successfully_processed_command": "print_information_message"}

同时,运行在开发板上处理命令的代码(iot_python_chapter_09_05.py 脚本)的 SSH 终端将显示类似的输出。在 OLED 矩阵底部将显示文本 “Python IoT”,并且舵机轴将旋转到 45 度。

10. 注意事项和拓展
  • 主题唯一性 :由于我们使用的 Mosquitto 代理是公共的,为确保只接收自己发布的消息,应使用唯一的主题名称。
  • 服务质量 :在更高级的场景中,应添加代码检查 publish 方法的结果,并可能在 on_publish 回调中添加代码,以处理消息成功发布的情况。
  • 线程接口 :MQTT 客户端还有一个线程接口,可通过调用 loop_start 方法运行,这样可以避免多次调用 loop 方法。
11. 总结

通过本文,我们详细介绍了如何使用 Mosquitto 和 Eclipse Paho 实现 MQTT 通信。从安装必要的模块,到利用公共沙箱服务器进行测试,再到编写开发板端和客户端的代码,最后运行示例并观察结果。这些步骤为我们开发基于 MQTT 的物联网应用提供了基础。在实际应用中,我们可以根据具体需求对代码进行修改和扩展,实现更复杂、更安全的物联网通信功能。

12. 相关操作步骤总结
操作内容 操作步骤
安装 paho - mqtt 模块 在 SSH 终端运行 pip install paho - mqtt
运行开发板端代码 运行 python iot_python_chapter_09_05.py
运行客户端代码 运行 python iot_python_chapter_09_06.py
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值