×

如何使用MQTT将嵌入式系统连接到AWS IoT Core

消耗积分:0 | 格式:zip | 大小:1.01 MB | 2022-12-12

杨火亭

分享资料个

描述

先决条件和假设

作为先决条件,我们应该提到这个项目是为NetBurner 3.x 构建的,这是我们工具和库的最新版本。这支持 NetBurner 的MOD54415 MOD54417、NANO54415 SB800EX上述MODM7AE70。将这个项目移植回我们工具的早期版本当然是可能的,但它不会像我们在这里布置的那么简单。

我们假设在开始之前,您已经下载并安装了我们工具的最新版本 (NNDK 3.x),并且您的模块已经启动并连接到您的网络。我们还假设您已从此处的存储库下载或克隆源代码。

如果您不熟悉使用 GitHub,您可以下载 .zip 文件中的存储库,或使用此处列出的步骤克隆它。无论您是克隆它还是将 .zip 文件的内容提取到您的计算机,您最终都应该得到一个包含两个名为src和的子文件夹的文件夹html这些文件夹包含应用程序的代码。包含它们的文件夹将是我们应用程序的根文件夹。对于我们来说,这个文件夹将是\AwsIotCoreMqttBase,并且它将在本教程的其余部分中用作参考点。

最后,我们建议有一种方法可以通过开发板查看直接来自您的模块的串行数据。有两种简单的方法可以做到这一点。首先,如果您有开发套件随附的 USB 转 micro-USB 电缆,您可以在开发板上设置跳线配置,以便它既可以向 micro-USB 插孔发送串行输出,也可以从 micro-USB 插孔接收电源。或者,您可以将开发板上的跳线设置为使用 DB9 端口(UART0)进行串行输出。有关如何在开发板上配置跳线的更多信息,请参阅开发板随附的“快速入门指南”。

如果您的计算机上没有串口(现在很多都没有)并且缺少 USB 转 micro-USB 电缆,您可以使用USB 转串口适配器来完成工作。这当然假设你有一个 USB 端口。

计划概览

我们的应用程序非常简单,并实现了四个不同的功能:

  • 最初设定
  • 每 5 秒发布一次 MQTT 消息
  • 订阅 MQTT 主题以接收传入消息
  • 提供web界面查看最近发送和接收的消息

我们希望以JSON 格式发布和接收消息,并在处理 MQTT 负载数据时广泛使用该类。ParsedJsonDataSet

设置 AWS IoT 核心

在设置 AWS IoT“事物”之前,正如他们亲切地称呼的那样,您需要创建一个 AWS 管理控制台帐户。该帐户本身是免费的(尽管服务定价各不相同,请查看此链接以了解有关 IoT Core 的详细信息),并将为大量不同的 AWS 云服务打开网关。如果您还没有这样做,您可以在这里处理。去吧,我们等着。

现在您已经正式加入俱乐部,如果您还没有,请继续并登录您的帐户。作为旁注,我们将使用我们的根帐户来避免在教程过程中遇到权限问题。如果您想按照 AWS 推荐的方式执行此操作,则必须创建一个辅助用户帐户,然后您需要通过 IAM 向该帐户授予所需的 IoT Core 权限。登录后,您应该会看到“AWS 管理控制台”页面,如图 1 所示。

poYBAGOS7FCAZvO9AABHGXBlUSg500.png
图 1:AWS 管理控制台
 

从这里您需要导航到 IoT Core 服务。您可以通过使用页面上的“查找服务”搜索字段来完成此操作,就像我们上面所做的那样,或者单击页面顶部横幅中的“服务”下拉菜单。

pYYBAGOS7FaAWreiAABO2i-7OTo602.png
图 2:物联网登陆屏幕
 

从这里,您将点击 AWS IoT 登陆屏幕,如上图 2 所示。这里有一些很棒的信息,我们鼓励大家在可能的时候四处看看。不过,我们正在执行任务,因此我们将绕过它并直接添加设备。单击“Get Started”按钮,您应该会看到一个欢迎屏幕,如下图 3 所示。

poYBAGOS7FqAHh0HAABMEFdWL7I995.png
图 3:IoT Core 欢迎屏幕
 

在我们可以将我们的设备注册为“事物”之前,我们需要为它设置一个“策略”。该策略将在注册过程中分配给我们的“事物”,并将授予它访问我们将用于发送和接收消息的 MQTT 主题所需的权限。从左侧菜单中,选择“Secure”,然后选择“Policies”的子菜单,如下图 4 所示。这会将您带到显示的控制台,通知我们当前没有任何策略。

pYYBAGOS7F-APp9pAAAusH7G_-Q730.png
图 4:创建策略
 

单击标有“Create a policy”的按钮,这将带您进入图 5 所示的屏幕。

poYBAGOS7GKAVwriAABAJmHvVDo785.png
图 5:初始策略创建屏幕
 

在策略创建页面中,我们将添加声明,这些声明将指示允许连接的设备执行的操作。我们将我们的策略命名为“ NBTutorial”,并添加四个声明,其中包含以下信息。请注意,当您输入操作时,将自动填充标记为“Resource ARN”的字段。选中“效果”字段下的“允许”,并将每个资源 ARN 的最后一部分“ replaceWithA”替换为星号 (*)。完成后,您应该有以下语句:

pYYBAGOS7GSAU-IBAACEy2xSvto884.png
上表提供了一些有关如何配置 AWS IoT Core 策略以供您使用的指南。
 
pYYBAGOS7GmAF4E1AAA0eh6pWOE679.png
图 6:完成的 AWS IoT 核心策略
 

请注意,在生产环境中,您将希望对策略创建更具选择性(例如,不要在资源 ARN 末尾使用星号)。我们在这里保持非常简单的方式来启动球,但我们绝不认可在现场生产环境中使用这些漫不经心的政策设置。

输入后,单击“创建”。现在是时候注册我们的“东西”了。

poYBAGOS7GuAOHm3AAAulnn69tw836.png
图 7:在 AWS IoT Core 上注册一个事物
 

返回左窗格的主菜单,单击“管理”菜单选项,然后单击“事物”子菜单。Amazon 友善地提醒我们,我们实际上还没有任何“东西”,所以现在让我们通过单击标记为“Register a thing”的按钮来处理它,如上图 7 所示。

这会将我们带到一个窗口,允许我们注册一个“事物”或多个“事物”。对于本教程,我们将坚持使用一个,所以请继续并单击标有“创建一个东西”的按钮。这会将我们带到图 8 中所示的屏幕,我们将在其中提供设备的详细信息。

pYYBAGOS7G2Abi14AAA_tmzAYGI187.png
图 8:添加您的物联网设备
 

我们唯一要在这里添加的是“名称”,我们将其设置为“ NBTutorial”。点击“下一步”,您将被带到一个屏幕,您可以在其中选择如何将您的“事物”与证书相关联,这些证书将用于通过 AWS IoT Core 服务对其进行身份验证。我们将让亚马逊在这里为我们做肮脏的工作,所以继续并单击顶部标有“创建证书”的按钮。

在撰写本文时,推荐使用他们的证书创建过程,在完成本教程中的所有步骤后,我们可以了解原因。生成证书后,您将进入类似于下面图 9 所示的屏幕。

旁白:点击“下一步”后,您可能会收到以下消息:“我们正在为您的帐户配置设备网关端点。端点准备就绪可能需要几分钟时间,之后您可以将设备连接到 AWS IoT、发布/订阅主题以及访问设备影子。在这种情况下,导航回仪表板并单击“管理”,然后单击左侧窗格中的子菜单项“事物”。你应该看到你注册的“ NBTutorial”东西在那里等着你。单击它,然后是将在屏幕左侧列出的“安全”菜单项。最后,单击标有“创建证书”的按钮继续。

poYBAGOS7HGAGQRIAAAw9jj3WjQ827.png
图 9:证书已创建!
 

在我们继续之前,我们需要在这里做一些事情。首先,我们要下载证书和私钥。我们实际上建议下载所有三个文件(证书文件以及公钥和私钥文件)并将它们藏在安全的地方,但您只需要证书和私钥就可以使用我们的应用程序连接您的设备。现在,我们将把它们放在项目的根目录中,\AwsIotCoreMqttBase. 适当移动这些后,单击标有“激活”的按钮。

最后但同样重要的是,我们将把我们之前创建的策略附加到我们的设备上。单击标有“附加策略”的按钮。这会将您带到一个屏幕,您可以在该屏幕上将您之前创建的任何策略附加到证书,如下面的图 10 所示。

pYYBAGOS7HWAdaUPAAA11TeT_F4900.png
图 10:附加策略
 

因为我们只创建了一个,所以我们应该看到的就是这个。单击它旁边的复选框以将其选中,然后单击最后一个按钮,“Register Thing”或“Done”(取决于您是否能够一次性完成注册)。

成功!如果一切按计划进行,您应该会回到当前活动“事物”的列表,其中包括我们刚刚创建的事物,如图 11 所示。

pYYBAGOS7HeAEdqzAAAwlImnYPk595.png
图 11:Huzzah!使用 AWS IoT Core 成功添加事物
 

修改、构建和加载应用程序

在这一点上,我们将远离 AWS,并专注于让应用程序在您的设备上启动和运行。

编译证书和私钥

还记得我们之前创建的证书和私钥吗?是时候把那些坏孩子赶出去了,因为我们要将它们直接编译到我们的应用程序中。在我们这样做之前,我们需要将它们变成设备可以真正理解的东西。

在命令行终端上,导航到您存放这些文件的文件夹(\AwsIotCoreMqttBase对我们来说)并运行命令:

compfile privatekey PRIVATE_KEY_LEN privatekey.cpp

替换为您之前下载的私钥文件的名称。该文件的格式通常为 - private.pem.key. 如果您在运行时遇到问题compfile,请确保所有 NetBurner 工具的安装目录都在您的路径中。这通常是 \nburn\pcbin.

运行上面的命令创建文件privatekey.cpp,其中包含以数组形式存储的私钥的全部内容。该数组的长度也作为常量存储在文件中PRIVATE_KEY_LEN

接下来,使用以下命令对证书执行相同操作:

compfile privatekey PRIVATE_KEY_LEN privatekey.cpp

替换为您在上一节中下载的包含证书的文件。该文件的格式通常为 - certificate.pem.crt. 与上面的命令类似,它生成文件certificate.cpp,该文件定义了一个包含证书数据的数组以及该数组的长度,该数组的长度存储在变量 中CERTIFICATE_LEN

如果一切顺利,您现在将看到两个新的 C++ 源文件,privatekey.cpp并且certificate.cpp在我们的根目录中\AwsIotCoreMqttBase,每个文件的大小都大于0. 如果不是,您可能需要重复上述步骤并进行一些故障排除。

此时,让我们继续将新文件移动到我们的\AwsIotCoreMqttBase\src目录,这将使我们在 NBEclipse 项目的道路上少走一步。说到这,让我们继续前进,现在继续。

在 NBEclipse 中创建一个项目

NBEclipse 是 NetBurner 基于 Eclipse 的 IDE,它提供了开发、构建和部署应用程序到 NetBurner 设备所需的一切。它可以在nburn子文件夹下的 NNDK 安装目录(默认情况下)中找到NBEclipse继续并立即启动该应用程序,并在出现对话框时随时接受工作空间的默认目录。

有关在 NBEclipse 中创建项目和开发应用程序的详细信息,请参见此处的文档。但是,我们将继续进行简要概述,以帮助您尽快入门。

我们将使用 Project Wizard 开始并创建我们的项目,使其实际指向我们的根文件夹\AwsIotCoreMqttBase,这将避免我们必须导入任何代码。为此, File->New->Project从窗口顶部的工具栏导航到 ,如图 12 所示。

poYBAGOS7HqABjubAAAy6dwYtCk052.png
图 12:在 NBEclipse IDE 中创建一个新项目
 

这应该会打开 New Project Wizard,如图 13 所示。

pYYBAGOS7H2ACuJ4AAB4hMNsXn8171.png
图 13:新建项目向导
 

确保在“NetBurner”选项下选择了“NetBurner Project”,然后点击“Next”。这会将您带到下面图 14 中所示的窗口。

pYYBAGOS7IKAZtYLAAB5jfRa44Y501.png
图 14:命名您的项目
 

通常,我们在这里做的唯一一件事就是为项目命名并继续。但是,在这种情况下,我们还将取消选中标记为“使用默认位置”的框,然后单击“浏览”按钮导航到您克隆回购的文件夹。对我们来说,这是\AwsIotCoreMqttBase确保在标有“工具链”的窗口中列出并选择了“NetBurner 工具链”。

从这个窗口点击“下一步”将带我们到我们可以选择我们想要构建的配置的地方。我们希望能够在“Debug”和“Release”模式下运行应用程序,因此选中选项,然后再次点击“Next”。

在下一个窗口中,如图 15 所示,我们可以指定要为哪个平台构建此应用程序。我们将选择 MODM7AE70。如果您使用我们的其他平台之一,请相应地选择它。如果您的设备已经插入并连接到您的网络,您可以通过点击标有“搜索”的按钮继续查找它的 IP 地址,然后从屏幕上弹出的列表中选择它。

pYYBAGOS7IeAPGFwAABhHOdkmPY643.png
图 15:选择您的设备
 

如果您的设备未连接,您可以暂时忽略此字段,然后点击“下一步”按钮。下一个窗口显示了一些可以自动添加到应用程序的基本组件,但由于我们使用的是 repo 文件夹中的代码,我们可以跳过所有这些,只需点击“完成”。

完成此操作后,您应该会看到您的项目已创建并列在 NBEclipse 左侧的“项目资源管理器”选项卡中。您可能会注意到您的项目会自动从右下角的控制台输出开始构建。如果我们在项目设置中正确地完成了所有操作并记得移动certificate.cppprivatekey.cpp\AwsIotCoreMqttBase\src,那么它应该会成功构建。如果您在 NBEclipse 控制台窗口的底部看到以下内容,您就知道您已准备就绪:

poYBAGOS7IqASXgmAABZeYr0WH4925.png
图 16:达到另一个里程碑
 

相反,如果您看到错误,请\AwsIotCoreMqttBase\src通过验证所有源文件是否显示在 src 文件夹下的“项目资源管理器”选项卡中,确保正确映射到项目中列出的 src 文件夹。还要仔细检查是否也列出了前面部分中生成的证书和私钥文件。

做一些改变

为了让我们的设备成功连接到 AWS IoT Core 服务,我们需要对aws_iot_config.h源代码中的文件进行一些更改。在 NBEclipse 中从项目的 src 文件夹中打开此文件。在此文件的顶部,定义了两个需要修改的宏。这些是AWS_IOT_MQTT_HOSTAWS_IOT_MQTT_CLIENT_ID

AWS_IOT_MQTT_HOST :这是我们需要连接和验证的端点。要查找此值,请转到您的 AWS IoT Core 管理控制台,单击“管理”,然后单击左侧窗格中的子菜单项“事物”,然后单击您的“ NBTutorial”注册的“事物”。在主窗口的左侧,您会找到菜单选项列表。其中,单击“Interact”,这会将您带到类似于图 17 中的页面。

poYBAGOS7IyADsWtAABZuTzAEmk134.png
图 17:“事物”详细信息
 

我们正在寻找的值是“HTTPS”标题下列出的令人讨厌的长值。复制该值并将其粘贴到您的 aws_iot_config.h 文件中以代替文本。

AWS_IOT_MQTT_CLIENT_ID :这是您设备的唯一客户端 ID,对于连接到此端点的每个设备都应该是唯一的。我们选择无聊并使用我们的 MAC 地址,但您可以随意想出您喜欢的创意和有趣的东西(只要它是独一无二的)。如果您也想使用 MAC 地址,可以在模块条形码标签的底部找到它,或者访问https://discover.netburner.com。无论您选择什么,将该值复制到aws_iot_config.h文件中的文本上。

当您保存 NBEclipse 项目时,它应该会再次自动构建项目并显示一条“构建完成”消息,如前所述。如果没有,您可以通过从 NBEclipse 菜单中进行选择来手动触发构建。Project->Build Project

加载您的应用程序

此时,我们已准备好在设备上加载我们的应用程序。您应该能够通过选择从 IDE 的顶部菜单自动设置运行配置Run->Run As->As Neturner Application有关运行配置的更多详细信息,请参阅我们的文档

如果由于某种原因您的设备在创建过程中未与项目相关联,您可以将设备的 IP 地址添加到项目中。通过右键单击“Project Explorer”选项卡中的项目,然后选择列表最底部的“Properties”选项来执行此操作。从那里,从显示的窗口左侧的列表中选择“NetBurner 选项”,然后在“设备选项”部分下的相应字段中输入您的设备 IP 地址,如下面的图 18 所示。同样,您可以通过以下网址找到您的设备 IP:https://discover.netburner.com/。

pYYBAGOS7JKAaCYeAAB6TfGYmpE036.png
图 18:为您的项目分配 IP 地址
 

可选(和推荐)步骤:当程序成功加载后,您可以通过MTTTY 终端监视应用程序的串行输出。通过将您的开发板直接连接到您的计算机来执行此操作。根据您的威廉希尔官方网站 板的跳线配置,这将通过 UART0 DB9 端口或微型 USB 插孔完成。如果一切顺利,在一些初始初始化和连接信息之后,您应该看到“Publish Success”消息定期滚动,如下图 19 所示:

poYBAGOS7JaAQ-YzAAEXLXZykow537.png
图 19:发布的成功消息
 

测试

现在到了你一直在等待的时刻。是时候使用带有 NetBurner 模块的 MQTT 协议向 AWS IoT Core 服务发送和接收消息了。对于下一组步骤,我们将需要返回到 AWS IoT Core 管理控制台。然而,这一次,我们将从左侧菜单中选择“测试”,这会将您带到类似于图 20 中所示的控制台。

pYYBAGOS7JmAN4z-AAA-jcg-wZY888.png
图 20:MQTT 测试
 

我们自称为天才,巧妙地将用于从 NetBurner 模块发布到 AWS 的 MQTT 主题命名为“ NBTutorial/ToAws”。继续在“订阅主题”字段中输入这个(不带引号),然后点击标有“订阅主题”的按钮。

如果一切顺利并且您的设备正在运行,您应该会看到 MQTT 消息开始显示在窗口的底部,如图 21 所示。如果没有,请返回并查看“可选(和推荐)步骤” ”,并验证您的设备是否在串行终端中正确初始化 AWS SDK。还要确认端口 8883 未在您的防火墙上被阻止,因为这是 MQTT 的默认端口,限制它会阻止您的 NetBurner 设备与 AWS 通信。最后,验证我们上面创建的策略中的资源 ARN 是否正确以 (*) 结尾。

pYYBAGOS7J6AUm47AAA_jMSBGGY924.png
图 21:测试 NetBurner 设备发布
 

接下来我们想看看我们的设备是否已经成功订阅了一个频道。在同一个 AWS 控制台中,单击位于“订阅”标题下的二级左侧菜单中的链接“发布到主题”。我们看到 NetBurner 设备消息传入的控制台底部应该被一个名为“Publish”的小框替换。它应该包含主题的文本字段,以及要发送的消息的文本字段,最后是一个标记为“发布到主题”的按钮。这可以在下面的图 22 中看到。

poYBAGOS7KKAV665AAA2ag4tmPs010.png
图 22:在 NetBurner 设备上测试订阅
 

对于此主题,输入“ NBTutorial/ToNb”。这很重要,因为它是我们的应用程序希望接收消息的主题。您可以将消息保留为默认值,即“Hello from AWS IoT console”,或者您可以根据自己的喜好进行修改。但请注意,它遵循 JSON 格式。

填写完这些字段后,继续点击旁边的魔法按钮(“发布到主题”)。如果您碰巧通过 UART0 直接连接到您的设备,请查找您的消息以显示在串行终端中,如下面的图 23 所示。

pYYBAGOS7KSALfdoAAA_4IR5LIE620.png
图 23:胜利的甜蜜滋味。使用 NetBurner 的 MTTTY 串行实用程序对其进行测试。
 

如果您不喜欢串行终端或没有串行转 USB 适配器,您还可以通过 Web 浏览器查看设备上发送和接收的最后一条消息。为此,请打开您选择的浏览器并在顶部的 URL 栏中输入您设备的 IP 地址。同样,您可以使用 URL https://discover.netburner.com/ 获取 IP 地址。将此 IP 地址放入您的浏览器将引导您进入一个由 NetBurner 模块托管的简单网页,该网页显示最近发送和接收的消息,如下面的图 24 所示。

pYYBAGOS7KeAQvK2AAAikUvBa1U412.png
图 24:更好看的胜利。使用 discover.netburner.com 测试一切
 

到目前为止,我们已经逐步了解了如何开始使用 Amazon 的 AWS IoT Core 托管云服务。为此,我们使用轻量级MQTT消息传递协议和 NetBurner开发工具包作为物联网设备。虽然我们从头到尾涵盖了所有基本要求,但我们也忽略了很多关于在 NetBurner 模块上运行的实际应用程序的内容。现在,我们将查看整个应用程序的功能,查看源代码并近距离接触执行肮脏工作的各个部分。我们已经包含了该应用程序的重要部分,但如果您想要真正身临其境的体验,您可以在此处找到该项目的 GitHub 存储库

源代码审查

poYBAGOS7KyAdi1xAADRiPqnA8I121.png
图 25:项目文件
 

我们的项目包含几个源文件、AWS SDK 和一个包含index.html我们在 Web 界面中使用的 html 文件夹。我们将主要关注.cpp直接位于src文件夹中的六个文件(如上图 25 所示)、它们关联的头文件和一个配置头文件。以下是对其中每一项的简要说明:

main.cpp– 这是应用程序的起点。它定义了应用程序名称AWS IoT Core Base ,并为我们的程序提供了入口点UserMain()稍后会详细介绍这一点。

post-record-data.cpp– 此文件包含初始化AWS SDK 的函数,并处理传入和传出 MQTT 消息的处理。

network_netburner.cpp– 此文件包含实现AWS SDK API的网络接口所需的函数,并将其绑定到我们的网络堆栈。这些都与 TLS 网络连接有关。

timer_netburner.cpp– 此文件包含AWS IoT Core MQTT 客户端所需的附加功能,并且与用于管理 MQTT 连接的计时器功能相关。

record-data.cpp– 这包含一个小函数,用于序列化MQTT 消息中使用的 JSON 数据。

html-control.cpp– 此文件包含两个函数,用于构建显示最近发送和接收的 MQTT 消息的 HTML 页面,如下所示。

aws_iot_config.h– 该文件包含我们连接到服务和发布/接收消息所需的所有配置常量值。如前所述,您需要将 和 更改AWS_IOT_MQTT_HOSTAWS_IOT_MQTT_CLIENT_ID特定于您的帐户和环境的值。

poYBAGOS7K6AbPHRAACdMesWx78806.png
图 26:Web 界面显示最后接收和发送的消息
 

最初设定

让我们将注意力转移到应用程序的入口点UserMain(),位于 中main.cpp在 内部,您将看到在我们进入主循环UserMain()之前或多或少按给定顺序调用以下函数:while()

init()– 此函数为应用程序设置网络堆栈,启动配置服务器,赋予UserMain()正确的任务优先级,并设置一些调试细节。如果您碰巧在申请中忘记了这一点,您很快就会知道。

StartHttp()– 这将启动设备上的网络服务器。再简单不过了。

InitializeAWSSDK()– 这几乎完全符合您的预期。它设置 AWS SDK 并负责初始 MQTT 设置。我们将在下面更深入地探讨这一点。

一切都初始化后,我们将进入我们的主要 while 循环,您将在其中看到以下代码:

while (1)
{
    // Post our record data
    PostRecordData();
    // Wait 5 seconds before doing it again
    OSTimeDly(TICKS_PER_SECOND * 5);
}

在真正的嵌入式系统中,我们将无限期地继续运行我们的 while() 循环。每五秒钟我们将调用PostRecordData(),这将向我们订阅的 MQTT 主题发布一条消息,定义如下gTopicNameSendpost-record-data.cpp

初始化适用于 MQTT 的 AWS IoT Core 开发工具包

如上所述,初始化 AWS SDK for IoT Core 服务发生在InitializeAWSSDK(),位于post-record-data.cpp.

InitializeAWSSDK()
{
    IoT_Error_t rc = FAILURE;
    IoT_Client_Init_Params mqttInitParams = iotClientInitParamsDefault;
    IoT_Client_Connect_Params connectParams = iotClientConnectParamsDefault;

    iprintf("\nAWS IoT SDK Version %d.%d.%d-%s\n", VERSION_MAJOR, VERSION_MINOR,
    VERSION_PATCH, VERSION_TAG);

    // Set required MQTT parameters
    mqttInitParams.enableAutoReconnect = false;
    mqttInitParams.pHostURL = AWS_IOT_MQTT_HOST;
    mqttInitParams.port = AWS_IOT_MQTT_PORT;
    mqttInitParams.pRootCALocation = "";
    mqttInitParams.pDeviceCertLocation = (char *) certificate;
    mqttInitParams.pDevicePrivateKeyLocation = (char *) privatekey;
    mqttInitParams.mqttCommandTimeout_ms = 30000;
    mqttInitParams.tlsHandshakeTimeout_ms = 10000;
    mqttInitParams.isSSLHostnameVerify = true;
    mqttInitParams.disconnectHandler = nullptr;
    mqttInitParams.disconnectHandlerData = nullptr;

    rc = aws_iot_mqtt_init(&client, &mqttInitParams);
    if (SUCCESS != rc)
    {
        iprintf("aws_iot_mqtt_init returned error : %d ", rc);
        return false;
    }

    connectParams.keepAliveIntervalInSec = 600;
    connectParams.isCleanSession = true;
    connectParams.MQTTVersion = MQTT_3_1_1;
    connectParams.pClientID = AWS_IOT_MQTT_CLIENT_ID;
    connectParams.clientIDLen = (uint16_t) strlen(AWS_IOT_MQTT_CLIENT_ID);
    connectParams.isWillMsgPresent = false;

    iprintf("Connecting...\n");
    rc = aws_iot_mqtt_connect(&client, &connectParams);
    if (SUCCESS != rc)
    {
        iprintf("Error(%d) connecting to %s:%d\n", rc, mqttInitParams.pHostURL, mqttInitParams.port);
        return false;
    }

    rc = aws_iot_mqtt_autoreconnect_set_status(&client, true);
    if (SUCCESS != rc)
    {
        iprintf("Unable to set Auto Reconnect to true - %d\n", rc);
        return false;
    }

    iprintf("Subscribing to topic: %s, %d\n", gTopicNameRec, strlen(gTopicNameRec));
    rc = aws_iot_mqtt_subscribe(&client, (char *) gTopicNameRec, strlen(gTopicNameRec), QOS1, IoTSubscribeCallbackHandler, nullptr);

    if (SUCCESS != rc)
    {
        iprintf("Error subscribing : %d\n", rc);
        return false;
    }

    return true;
}

在函数顶部附近,您将看到为调用 设置的参数aws_iot_mqtt_init()坚持我们提供的价值观应该没问题。但是,对于特别好奇的人,您可以从官方 AWS API 文档here.

假设 MQTT 初始化函数成功,然后我们将设置我们的连接参数并将它们传递给函数,aws_iot_mqtt_connet()您可能猜到了,建立与 AWS IoT Core 服务的连接。同样,您应该接受我们设置的值,但您可以在此处找到有关这些值代表什么的更多信息如果我们能够成功建立一个连接,我们将通过一个aws_iot_mqtt_autoreconnect_set_status()包含 true 参数的调用来跟进它。如果由于某种原因连接失败,这将确保我们自动重新连接。

最后,我们通过调用订阅我们的主题aws_iot_mqtt_subscribe()我们将订阅的主题是gTopicNameRec,它定义在 的顶部post-record-data.cpp我们还传递了一个指向接收消息时调用的函数的指针IoTSubscribeCallbackHandler()

发布 MQTT 数据

现在我们已经建立了与 AWS IoT Core 服务的连接,我们已准备好开始使用 MQTT 协议发布消息。正如我们之前提到的,我们将每五秒从我们的UserMain()函数中发布一条新消息,并调用PostRecordData()中定义的post-record-data.cpp

void PostRecordData()
{
    char buffer[200] = { 0 };
    CreateOutMessage(gJsonOut);
    gJsonOut.PrintObjectToBuffer(buffer, 199, false);

    IoT_Publish_Message_Params paramsQOS1;
    paramsQOS1.qos = QOS1;
    paramsQOS1.payload = (void *) buffer;
    paramsQOS1.payloadLen = strlen(buffer);
    paramsQOS1.isRetained = 0;

    IoT_Error_t rc = aws_iot_mqtt_publish(&client, gTopicNameSend, strlen(gTopicNameSend), ¶msQOS1);
    if (SUCCESS != rc)
    {
        iprintf("Error publishing : %d\n", rc);
    }
    else
    {
        iprintf("Publish success:\r\n");
        gJsonOut.PrintObject(true);
        iprintf("\r\n");
    }
}

您会注意到我们做的第一件事就是打电话CreateOutMessage()这将构建我们的 MQTT 有效负载并将其存储在 中gJsonOut,这是一个ParsedJsonDataSet对象。我们将其保存在全局,以便可以通过我们的模块提供的网页来引用和显示它。记录的内容是消息创建时间的时间戳和每当调用函数时递增的静态 ID。记录由类定义,并与设备 ID 一起PostRecord序列化gJsonOutAWS_IOT_MQTT_CLIENT_ID

在我们的有效载荷结构正确的情况下,我们将其转储到缓冲区中,然后再设置我们的 IoT 发布参数。

接收 MQTT 消息

如前所述,我们aws_iot_mqtt_subscribe()在初始设置期间致电给我们订阅了主题gTopicNameRec. 该函数的参数之一 为IoTSubscribeCallbackHandler将用于处理传入消息的函数提供了处理程序。

void IoTSubscribeCallbackHandler(AWS_IoT_Client *pClient, char *topicName, uint16_t topicNameLen, IoT_Publish_Message_Params *params, void *pData)
{
    iprintf("Received Message:\r\n");
    ParsedJsonDataSet jsonIn = ParsedJsonDataSet((char *) params->payload, (int) params->payloadLen);
    jsonIn.PrintObject(true);
    iprintf("\r\n");

    jsonIn.PrintObjectToBuffer( recJson, 256, true);
}

我们知道函数的签名应该是什么,因为 Amazon 非常友好地在他们的API 文档中为我们提供了很好的细分。该函数本身非常短,因为我们只是从 MQTT 消息中获取有效负载数据,并使用它来构造一个ParsedJsonDataSet对象。然后我们将该对象的内容存储到缓冲区中,以便我们可以在网页上提供它并显示最后收到的消息是什么。

网页界面

我们利用 NetBurner 生成动态 Web 内容的能力来显示最近接收和发布的 MQTT 消息。为此,我们定义了两个函数,html-control.cpp它们会在数据从设备提供给请求浏览器之前将数据打印到网页。这些是PrintOutData()PrintInData()

index.html 中特殊格式的注释会触发这些函数,并且它们具有结构,。这使得通过 Web 界面显示任何类型的应用程序级数据变得非常容易。我们有关于该系统的大量文档,并包括几个功能齐全的示例以及我们的 NNDK。

实施 AWS 开发工具包依赖项

当然,AWS SDK 必须有一种方法可以绑定到 NetBurner 平台和网络堆栈中。我们这里使用的SDK提供了两个接口:网络接口定时器接口。如上所述,这些接口的功能分别定义在network_netburner.cpptimer_netburner.cpp中。

网络接口提供所有 TLS 功能,用于启动和关闭安全连接,以及通过这些连接读取和写入数据。计时器接口提供保持 MQTT 连接活动和启动所需的超时功能。

在我们连接到 AWS IoT Core 服务并开始发送和接收 MQTT 消息之前,需要这两个接口的功能。如果您从一开始就按照说明生成和编译证书和私钥,那么应该不需要修改这里实现的功能。

包起来

我们希望您觉得这个项目既有趣又有教育意义。我们在制作过程中玩得很开心,也很想听听您的体验!我们在这里提供了坚实的基础,但这真的只是这个特定项目的开始。天空是极限,所以出去开始试验吧!

如果您对深入解释感兴趣,两篇Netburner 文章提供了更多信息。


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

评论(0)
发评论

下载排行榜

全部0条评论

快来发表一下你的评论吧 !

'+ '

'+ '

'+ ''+ '
'+ ''+ ''+ '
'+ ''+ '' ); $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code ==5){ $(pop_this).attr('href',"/login/index.html"); return false } if(data.code == 2){ //跳转到VIP升级页面 window.location.href="//m.obk20.com/vip/index?aid=" + webid return false } //是会员 if (data.code > 0) { $('body').append(htmlSetNormalDownload); var getWidth=$("#poplayer").width(); $("#poplayer").css("margin-left","-"+getWidth/2+"px"); $('#tips').html(data.msg) $('.download_confirm').click(function(){ $('#dialog').remove(); }) } else { var down_url = $('#vipdownload').attr('data-url'); isBindAnalysisForm(pop_this, down_url, 1) } }); }); //是否开通VIP $.get('/article/vipdownload/aid/'+webid,function(data){ if(data.code == 2 || data.code ==5){ //跳转到VIP升级页面 $('#vipdownload>span').text("开通VIP 免费下载") return false }else{ // 待续费 if(data.code == 3) { vipExpiredInfo.ifVipExpired = true vipExpiredInfo.vipExpiredDate = data.data.endoftime } $('#vipdownload .icon-vip-tips').remove() $('#vipdownload>span').text("VIP免积分下载") } }); }).on("click",".download_cancel",function(){ $('#dialog').remove(); }) var setWeixinShare={};//定义默认的微信分享信息,页面如果要自定义分享,直接更改此变量即可 if(window.navigator.userAgent.toLowerCase().match(/MicroMessenger/i) == 'micromessenger'){ var d={ title:'如何使用MQTT将嵌入式系统连接到AWS IoT Core',//标题 desc:$('[name=description]').attr("content"), //描述 imgUrl:'https://'+location.host+'/static/images/ele-logo.png',// 分享图标,默认是logo link:'',//链接 type:'',// 分享类型,music、video或link,不填默认为link dataUrl:'',//如果type是music或video,则要提供数据链接,默认为空 success:'', // 用户确认分享后执行的回调函数 cancel:''// 用户取消分享后执行的回调函数 } setWeixinShare=$.extend(d,setWeixinShare); $.ajax({ url:"//www.obk20.com/app/wechat/index.php?s=Home/ShareConfig/index", data:"share_url="+encodeURIComponent(location.href)+"&format=jsonp&domain=m", type:'get', dataType:'jsonp', success:function(res){ if(res.status!="successed"){ return false; } $.getScript('https://res.wx.qq.com/open/js/jweixin-1.0.0.js',function(result,status){ if(status!="success"){ return false; } var getWxCfg=res.data; wx.config({ //debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId:getWxCfg.appId, // 必填,公众号的唯一标识 timestamp:getWxCfg.timestamp, // 必填,生成签名的时间戳 nonceStr:getWxCfg.nonceStr, // 必填,生成签名的随机串 signature:getWxCfg.signature,// 必填,签名,见附录1 jsApiList:['onMenuShareTimeline','onMenuShareAppMessage','onMenuShareQQ','onMenuShareWeibo','onMenuShareQZone'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 }); wx.ready(function(){ //获取“分享到朋友圈”按钮点击状态及自定义分享内容接口 wx.onMenuShareTimeline({ title: setWeixinShare.title, // 分享标题 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享给朋友”按钮点击状态及自定义分享内容接口 wx.onMenuShareAppMessage({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 type: setWeixinShare.type, // 分享类型,music、video或link,不填默认为link dataUrl: setWeixinShare.dataUrl, // 如果type是music或video,则要提供数据链接,默认为空 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ”按钮点击状态及自定义分享内容接口 wx.onMenuShareQQ({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到腾讯微博”按钮点击状态及自定义分享内容接口 wx.onMenuShareWeibo({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); //获取“分享到QQ空间”按钮点击状态及自定义分享内容接口 wx.onMenuShareQZone({ title: setWeixinShare.title, // 分享标题 desc: setWeixinShare.desc, // 分享描述 link: setWeixinShare.link, // 分享链接 imgUrl: setWeixinShare.imgUrl, // 分享图标 success: function () { setWeixinShare.success; // 用户确认分享后执行的回调函数 }, cancel: function () { setWeixinShare.cancel; // 用户取消分享后执行的回调函数 } }); }); }); } }); } function openX_ad(posterid, htmlid, width, height) { if ($(htmlid).length > 0) { var randomnumber = Math.random(); var now_url = encodeURIComponent(window.location.href); var ga = document.createElement('iframe'); ga.src = 'https://www1.elecfans.com/www/delivery/myafr.php?target=_blank&cb=' + randomnumber + '&zoneid=' + posterid+'&prefer='+now_url; ga.width = width; ga.height = height; ga.frameBorder = 0; ga.scrolling = 'no'; var s = $(htmlid).append(ga); } } openX_ad(828, '#berry-300', 300, 250);