# Raspberry Pi代理MQTT协议一对ESP8266节点

{% tabs %}
{% tab title="关键词" %}
Raspberry Pi | ESP8266 | MQTT&#x20;
{% endtab %}

{% tab title="梗概" %}
#### 硬件 | 软件 | 介绍

任何物联网项目中，我们都有许多独特的要求和限制。连接设备并在设备之间发送数据的通信策略至关重要。

#### 什么是MQTT协议？

在嵌入式世界中，我们默认情况下假定终端设备将在各种处理能力，能源或通信约束下工作。 特别是在本文中涉及到我们的主题上，我们如何实现系统的通信将直接影响设备的资源和能源消耗。

在本指南中，我们将探讨MQTT，这是一种基于TCP的轻量级通信协议，该协议是IBM的Andy Stanford-Clark和Arcom的Arlen Nipper于1999年发明的，最初设计用于电池供电的设备来监测石油管道。 2010年晚些时候，IBM发布了它作为免版税协议。 2014年，OASIS宣布MQTT v.3.1.1已成为OASIS标准，并且为所有编程语言开发了许多MQTT客户端。

最常用的代理是Eclipse的Mosquitto库：MQTT v3.1和v.3.1.1标准的开源实现，提供了一种轻量级的方法来传输消息，从而为低功耗传感器，移动设备，嵌入式计算机和微控制器提供了发布/订阅模式。 您可以在PC以及任何具有Linux支持的嵌入式系统（例如Raspberry Pi）上安装Mosquitto代理。

**主要特征**

* 数据不可知：您可以使用它来发送传感器数据，图像甚至OTA（广播）更新
* 轻量级和带宽高效：最小的帧只有2个字节长
* 每队列QoS级别
* 在TCP / IP堆栈上运行，因此您可以使用它来使用TLS / SSL加密数据并在客户端之间建立安全连接
* 易于开发：存在所有操作系统和编程语言的客户端
* 中央代理：不同的设备可以彼此通信，而不必担心兼容性
* 会话意识：为订阅提供基于身份的方法
* 使用单级和多级通配符的灵活订阅主题

**基本术语**

* 代理：从发布客户端接收消息并将消息路由到适当的已订阅客户端的软件应用程序
* 客户端：可以将消息发布到主题或订阅主题消息的设备
* 主题：代理程序用来为每个连接的客户端过滤消息的标识符（字符串）。 它由客户端在订阅请求中发送给代理，以表达接收其他客户端发布的消息的愿望。 由客户端在将消息发布到订阅了同一主题的任何其他客户端时发送
* 发布：从客户端向代理发送消息的操作
* 订阅：通知代理有兴趣接收其他客户在该主题上发布的将来消息的操作。客户可以订阅多个主题
* 取消订阅：通知代理不希望接收指定主题的消息的操作

现在，在进入真实世界之前，让我们首先确保我们与开发工具在同一页面上。

### 设置

#### 使用**Raspberry Pi和BalenaOS的MQTT代理**

如前所述，Mosquitto可以安装在任何PC（Windows，MacOS和Linux）上，因此，如果手头没有任何RPi，则可以在本地安装Mosquitto并使用计算机的静态IP。

就我而言，我正在一个小型家庭自动化项目中工作，我需要集成多个设备，在webapp中显示数据并分析该数据以执行某些操作。 如您所见，这里涉及到完整的开发堆栈（数据库，后端，前端），对于这种设置，没有什么比使用容器更好的了。

我们如何在自动部署的Raspberry Pi上使用Docker，而不必浪费时间配置Raspbian？ 这是Balena可以实现的目标之一。 在您问之前：是的，它是免费的，但仅对于前10个设备 …

以下是创建新Balena应用程序过程的简短视频（从开始到结束，我花了大约15分钟的时间）：

视频(略）

现在，该设置MQTT代理了：

* 创建一个新的github项目并添加此docker-compose.yml文件
* 添加您在仪表板前面看到的balena远程端点
* 首先将更改推送到github，然后推送到balena
* 做完了！几分钟后，您将在balena仪表板中看到如何创建和启动mosquitto容器

#### ESP8266开发环境

我建议您使用Linux，因为与Mac或Windows相比，Linux具有许多优点，可以帮助您避免某些麻烦。 例如，在标准的Ubuntu安装中，我能够使用Arduino板，ESP甚至STM，而不必担心安装单个驱动程序。

在任何情况下，请记住，有时不可避免地要通过Windows，因为有一些特定的供应商开发软件仅适用于该操作系统。 因此，请始终检查您的要求，并确保您事先知道与设备配合使用所需的软件。

对于本指南中进行的实验，我们不需要花哨的所有内容，因此，幸运的是，我们可以使用Linux。

**PlatformIO + VS Code (or Atom)**

不用使用Arduino IDE。除了功能性和实用性之外，什么都没有。它缺少构成良好IDE的所有功能。

幸运的是，我们拥有PlatformIO，它是VS Code和Atom的扩展，可以将这些出色的编辑器转变为用于我们的嵌入式实验的真实IDE。

从文档中可以得出：“它负责在最流行的平台（例如Windows，Mac和Linux）上工作的工具链，调试器和框架。它支持500多个开发板以及30多个开发平台和15个框架。”

#### ESP8266文件系统：将WiFi凭证存储到闪存中

由于我将在不同的项目上使用多个ESP8266一段时间，所以我认为花一些时间来预配置模块，而不必在脚本中对wifi网络凭据进行硬编码，然后在输入之前输入虚拟文本是个好主意。 将项目上传到github。 我确定我最终会输入密码。

在SPIFFS和ArduinoJson库的帮助下，使用ESP8266来实现此操作非常简单。为了封装与我们设备相关的基本功能（网络连接和闪存管理），我创建了一个名为NodeMcu的小类。

如您所见，构造函数之一接受一个参数，我们将使用该参数传递要保留在内存中的字符串化JSON。 在setup（）方法中，它将尝试从内存中恢复数据，或者如果找不到正确的数据以连接到本地网络，则它将失败。

现在我们已经正确配置了电路板，接下来可以进行第一个实验。

#### 使用MQTT连接两个设备

在第一个实验中，我们将专注于MQTT协议的核心功能：发布/收听到主题的消息，或使用它来切换LED。 作为触发消息的触发器，我使用了2向开关，这不十分适合原型，如下面的GIF所示，但比大多数教程中通常使用的四个引脚的典型扁平按钮要酷得多。

工作流程很简单：当我们按下左侧设备的按钮时，它将从右侧切换LED； 反之亦然。 唯一的陷阱是每个设备都侦听所有已发布的消息，因此我们需要过滤掉自发布的消息，以避免对其自身采取行动。

#### 使用最后的消息检测断开连接的设备

MQTT协议最有趣的功能之一是，代理跟踪其自身与所有连接的客户端之间的连接。 代理始终知道其客户之一何时断开连接。 怎么做？ 非常简单：它会持续ping通其客户端，并且其中一个客户端在特定时间段内停止响应（超时）时，它会假定客户端已断开连接。

超时是由客户端在将初始连接请求发送给代理时定义的，因此客户端可以完全配置超时。 在此连接请求中，我们还可以包含“最后遗嘱”（LWT）消息的参数，其中包括：有效负载，要发布的主题，QoS以及是否应保留该消息。

这里出现了MQTT的新功能：保留一条消息。 这使我们可以告诉代理，每当我们向主题发送“保留”标记的消息时，都应存储该消息并保持其安全。 现在，当新客户订阅该主题时，它将收到该保留的消息。 认为它是新来者的欢迎信。

我们可以结合使用这两种MQTT功能来跟踪设备的状态，这就是我们在本实验中要做的。 当然，PubSubClient库为我们提供了API，可轻松在类似Arduino的板上使用LWT消息。

#### 总结

在本指南中，我们使用了最广泛使用的ESP8266变体之一（NodeMcu）来实现MQTT通信协议的一些基本概念。

我们还看到了如何使用模块的内部存储来存储配置文件并加快原型开发。

现在，您可以在可能想到的一些实际项目中应用我们在此处学到的技术，实现高效而直接的通信系统，例如将数据从传感器发送到本地服务器，以供以后分析。

MQTT远远超过了我们今天在这里看到的内容，但是我希望至少这些实验能帮助您了解该协议的核心概念以及如何使用它们。继续尝试和学习！

#### 原理图

#### 完整代码
{% endtab %}
{% endtabs %}

{% content-ref url="../zhi-dian-mi-jin-brief" %}
[zhi-dian-mi-jin-brief](../zhi-dian-mi-jin-brief)
{% endcontent-ref %}
