MQTT上的Arduino数据
使用MQTT和API功能的组合,我们已经为我们的设备自动创建了数字双胞胎。
MQTT 是一个OASIS标准的物联网(IoT)消息传输协议,也是akenza所支持的协议之一。
它被设计成一个极其轻量级的 发布/订阅消息协议 ,是连接远程设备的理想选择,代码占用小,网络带宽小。 MQTT 被应用于各个行业。
为了运行这个项目,我们使用akenza作为物联网平台,因为它运行了 Eclipse Mosquitto 的开源MQTT 代理 。 通过使用MQTT和API功能的组合,我们已经能够 为我们的设备自动创建 数字双胞胎 。
作为硬件,我们选择了一个 Arduino Uno WiFi Rev2。
1.配置Arduino设备
1.1 设置WiFi连接
为了使Arduino Uno Wifi能够连接到WiFi,我们使用了WiFiNINA库,在Arduino IDE的库管理器中可用。
1.1.1 管理用户名和密码
为了管理用户名和密码,我们创建了一个额外的头文件,名为arudino_secrets.h。
#define SECRET_SSID "<your username>"
#define SECRET_PASS "<your password>"
1.1.2 WiFi连接代码
连接Arduino和WiFi的代码报告如下。
#include <WiFiNINA.h>
#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID; // your network SSID (name)
char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP)
WiFiClient wifiClient;
void setup() {
//Initialize serial and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
// attempt to connect to Wifi network:
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(ssid);
while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
// failed, retry
Serial.print(".");
delay(5000);
}
Serial.println("You're connected to the network");
Serial.println();
}
void loop()
{}
1.2 设置与akenza的MQTT连接
出于安全考虑,akenza只支持 通过MQTT的认证连接。为此,我们选择了 PubSubClient 库来管理我们的MQTT连接。这使我们可以在连接字符串中使用用户名和密码。
#include <PubSubClient.h>
//MQTTClient mqttClient(WiFiClient);
char host[] = "mqtt.akenza.io";
char clientid[] = "Arduino";
char username[] = "<copy from Akenza Device Api configuration>";
char password[] = "<copy from Akenza Device Api configuration>";
char outTopic[] = "<copy from Akenza Device Api configuration>";
PubSubClient client(host, 1883, callback, wifiClient);
void setup() {
if (client.connect(host, username, password)) {
Serial.print("Connected to ");
Serial.println(host);
Serial.println();
boolean r = client.subscribe(outTopic);
Serial.print("Subscribed to ");
Serial.println(outTopic);
Serial.println();
}
else {
// connection failed
// mqttClient.state() will provide more information
// on why it failed.
Serial.print("Connection failed: ");
Serial.println(client.state());
Serial.println();
}
}
Akenza接受 JSON格式的MQTT连接信息 。为了建立一个格式良好的JSON对象,我们 使用了ArduinoJson库。
#include <ArduinoJson.h>
void loop()
{
StaticJsonDocument<256> doc;
doc["Temperature"] = 22;
doc["Humidity"] = 68;
doc["Light"] = 96;
// Add an array
JsonArray data = doc.createNestedArray("data");
data.add(48);
data.add(2.3);
char out[128];
int b =serializeJson(doc, out);
Serial.print("publishing bytes = ");
Serial.println(b,DEC);
boolean rc = client.publish(outTopic, out);
// The above line prints:
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
delay(5000);
client.loop();
}
请注意,这些只是数据的例子;如果你想把来自传感器的数据发送到云端,代码必须做相应的调整。
2.通过AKENZA上的MQTT连接Arduino设备
2.1 创建一个秘密
为了安全地与akenza通信,必须产生一个秘密,这个秘密必须在上行请求的主题结构中提供。
这个步骤必须对所有你想连接的具有相同连接参数的设备进行。每个设备将 相应地 由一个 特定的ID来唯一识别 。 在数据流 上 创建 MQTT设备连接器 后,将产生一个秘密 。
2.1.1 在akenza上设置一个MQTT设备连接器
在菜单中 进入 数据流 ,选择 创建数据流。
选择MQTT作为设备连接器。作为设备类型,选择 Passthrough 来接收与从你的MQTT设备发送的相同格式的数据。
选择一个或多个 你选择的 输出连接器 。有几个选项可以选择。在本教程中,我们选择 Akenza DB。
2.2 创建一个MQTT设备
要创建一个新的MQTT设备, 在 资产清单 的菜单中选择 创建设备。添加一个设备名称和可选的描述,资产标签,和自定义字段。选择 "下一步" 并选择你创建的MQTT数据流。选择 继续。
点击 生成ID ,为该设备 生成一个 随机的 ID。 点击 "创建设备"按钮,完成这一过程 。你的设备现在将显示在 资产库存概览中。
2.3 设置Arduino设备
作为下一步,Arduino设备现在必须被配置为向 akenza的 MQTT代理发送数据 。进入 资产清单 ,使用过滤器来搜索你的设备。通过选择你的设备,打开设备的详细页面。在 API-配置 中 ,所有需要的信息都可以用来将设备设置为MQTT-客户端。
3.最终结果
现在你有了在Arduino上设置你的代码和通过MQTT向akenza传输数据所需的所有元素。
最后的代码报告如下。
#include <SPI.h>
#include <PubSubClient.h>
#include <WiFiNINA.h>
#include <ArduinoJson.h>
#include "arduino_secrets.h"
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID; // your network SSID (name)
char pass[] = SECRET_PASS; // your network password (use for WPA, or use as key for WEP)
char host[] = "mqtt.akenza.io";
char clientid[] = "Arduino";
char username[] = "0783ddd64683f579";
char password[] = "bd604gmgit0x7kilc8puok3g2rxsldl2";
char outTopic[] = "/up/bd604gmgit0x7kilc8puok3g2rxsldl2/id/99E77F4ECC728656";
//set interval for sending messages (milliseconds)
const long interval = 8000;
unsigned long previousMillis = 0;
int count = 0;
//receive data
void callback(char* topic, byte* payload, unsigned int length) {
char str[length+1];
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
int i=0;
for (i=0;i<length;i++) {
Serial.print((char)payload[i]);
str[i]=(char)payload[i];
}
str[i] = 0; // Null termination
Serial.println();
StaticJsonDocument <256> doc;
deserializeJson(doc,payload);
// deserializeJson(doc,str); can use string instead of payload
const char* sensor = doc["sensor"];
long time = doc["time"];
float latitude = doc["data"][0];
float longitude = doc["data"][1];
Serial.println("latitude =");
Serial.println(latitude,2);
Serial.println(sensor);
}
WiFiClient wifiClient;
PubSubClient client(host, 1883, callback, wifiClient);
void setup() {
//Initialize serial and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
// attempt to connect to Wifi network:
Serial.print("Attempting to connect to WPA SSID: ");
Serial.println(ssid);
while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
// failed, retry
Serial.print(".");
delay(5000);
}
Serial.println("You're connected to the network");
Serial.println();
if (client.connect(host, username, password)) {
Serial.print("Connected to ");
Serial.println(host);
Serial.println();
boolean r = client.subscribe(outTopic);
Serial.print("Subscribed to ");
Serial.println(outTopic);
Serial.println();
}
else {
// connection failed
Serial.println("Connection failed ");
Serial.println(client.state());
Serial.println();
}
}
void loop()
{
StaticJsonDocument<256> doc;
doc["Temperature"] = 22;
doc["Humidity"] = 68;
doc["Light"] = 96;
// Add an array
JsonArray data = doc.createNestedArray("data");
data.add(48);
data.add(2.3);
char out[128];
int b =serializeJson(doc, out);
Serial.print("publishing bytes = ");
Serial.println(b,DEC);
boolean rc = client.publish(outTopic, out);
// The above line prints:
// {"sensor":"gps","time":1351824120,"data":[48.756080,2.302038]}
delay(5000);
client.loop();
}
它自动解码收到的JSON,并将从Arduino设备收到的数据可视化。传入的数据可以在 消息日志 中的 设备详情页上查看 。
传入的数据在 数据概览中 作为 设备数据KPI可视化 ,也在 历史 图表 中 可视化 。