MQTT上的Arduino数据

300 阅读5分钟

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可视化 ,也在 历史 图表 中 可视化 。