网络知识 娱乐 微信小程序获取Onenet温湿度数据并控制灯亮灭

微信小程序获取Onenet温湿度数据并控制灯亮灭

​ 其实之前就写过类似的文章,但是看过我博客的朋友就知道,我是先写微信小程序获取onenet,然后再写esp32上云到onenet。一篇是ESP32-C3通过MQTT协议把温湿度上传到OneNet平台(实际是mqtts协议,之前没细看以为没区别),一篇是微信小程序获取onenet数据显示温湿度(硬件连接上云是朋友搞的),之所以写这一篇是因为协议不同,权限不同,之前设备协议用的是mqtts协议,由于之前是作业需要,只搞了获取数据,并没有搞下发命令。这两天重新去翻阅相关文档才发现,onenet现在暂不支持mqtts协议下发命令,支持mqtt协议。部分重要代码需要修改,顺便优化了小程序界面。

需要注意的是这里用的是onenet老版的mqtt协议,多协议接入。新版和旧版数据不互通

硬件设备:	 安信可的ESP32-C3
传感器:	  dht11
代码编译环境: Arduino ide
设备传输协议: mqtt
onenet云平台: 老版多协议接入
微信小程序:	 微信开发者工具

文章目录

        • 一、Onenet云平台
          • 1、创建产品
          • 2、创建设备
          • 3、创建数据流
        • 二、Arduino ide编译环境
        • 三、嵌入代码撰写
          • 1、设备怎么连上网
          • 2、温湿度
          • 3 、接入地址
          • 4、数据如何发送给onenet
          • 5、下发命令
          • 6、led灯
          • 7、嵌入源代码
        • 四、微信开发者工具
          • 1、微信界面
          • 2、获取Onenet的API接口
          • 3、查询OneNet平台多协议接入文档,这里直接查看MQTT的API使用
          • 4、我用ApiPost来进行测试是否能获取数据
          • 5、微信小程序获取OneNet数据
          • 6、微信小程序下发命令
          • 7、数据刷新
          • 8、效果展示
        • 结语

一、Onenet云平台

1、创建产品

控制台 —>多接入–>添加产品

关于产品名称、行业、类别那些自行选择即可,这里选用mqtt旧版协议

在这里插入图片描述
在这里插入图片描述

点击我们刚刚创建的dht11,然后点击产品概况,记住我们的产品id,后面用得上

2、创建设备

点击设备列表->点击右边的添加设备,设备名称和鉴权信息需要填写,鉴权信息设备连接onenet用的上,还有设备的id号
在这里插入图片描述

3、创建数据流

首先点击数据流,然后点击数据流模板管理,最后添加数据流模板

这里设置的数据流名称后面要用到,这里我创建了温度、湿度、灯的数据流。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二、Arduino ide编译环境

这里我使用的是Arduino IDE,它的库很多,大部分可以直接调用,只有少部分需要自己下载,网上资源有很多,可以自己查找下载,这里我直接跳过安装。
在这里插入图片描述

因为我之前使用过esp32开发板,一开始我以为环境是跟ESP32一样的,事实证明我还是太年轻了。后面我通过安信可官方给的包替换。下面的链接是官方的,里面也有Arduino IDE 的安装包

链接:https://pan.baidu.com/s/1kLPvsDpwQf1lz_e3goxpJg
提取码:1234
在这里插入图片描述
在这里插入图片描述
配置好开发板相应环境
在这里插入图片描述

三、嵌入代码撰写

之前用的是mqtts协议,这里是mqtt协议,只需要修改之前代码的一部分就能解决

1、设备怎么连上网

这里可以调用wifi库

#include 
const char* ssid     = "3671"; //wifi名称
const char* password = "05210835";//wifi密码
2、温湿度

我传感器用的是DHT11,这里也可以调用库

#include "DHT.h"

定义DHT11,数据引脚我接在IO7口

#define DHTPIN 7     // io7
#define DHTTYPE DHT11   // DHT 11
DHT dht(DHTPIN, DHTTYPE);
3 、接入地址

mqtts协议的接口端号是1883,这里是6002

const char *mqtt_server = "183.230.40.96"; //onenet 的 IP地址
const int port = 6002;                     //端口号

在这里插入图片描述

4、数据如何发送给onenet

这里我们需要查阅onenet的相关文档

https://open.iot.10086.cn/doc/v5/develop/detail/463

在这里插入图片描述

#define mqtt_devid "884337606" //设备ID
#define mqtt_pubid "487632"        //产品ID
//鉴权信息
#define mqtt_password "20222222" //鉴权信息
char msg_buf[200];               //发送信息缓冲区
char msgJson[75]; //要发送的json格式的数据
unsigned short json_len = 0;                      //json长度
//信息模板
char dataTemplate[] = "{"temp":%.2f,"humi":%.2f,"led":%d}";  //  temp humi led要与onenet相对应
void sendTempAndHumi()
{
  if (client.connected())
  {
    //dht.readHumidity()
    snprintf(msgJson,75,dataTemplate,dht.readTemperature(),dht.readHumidity(),god); 
    json_len = strlen(msgJson);                   //msgJson的长度
    msg_buf[0] = char(0x03);                       //要发送的数据必须按照ONENET的要求发送, 根据要求,数据第一位是3
    msg_buf[1] = char(json_len >> 8);              //数据第二位是要发送的数据长度的高八位
    msg_buf[2] = char(json_len & 0xff);            //数据第三位是要发送数据的长度的低八位
    memcpy(msg_buf + 3, msgJson, strlen(msgJson)); //从msg_buf的第四位开始,放入要传的数据msgJson
    msg_buf[3 + strlen(msgJson)] = 0;              //添加一个0作为最后一位, 这样要发送的msg_buf准备好了

    Serial.print("public the data:");
    Serial.print(msgJson);
    client.publish("$dp", (uint8_t *)msg_buf, 3+strlen(msgJson));
    //发送数据到主题
    delay(500);
    
  }
}

在 setup()函数定义了每5秒发送一次数据到onenet

 tim1.attach(5, sendTempAndHumi);                            //定时每5秒调用一次发送数据函数sendTempAndHumi

5、下发命令

在 setup()函数订阅命令下发主题

  client.setCallback(callback); //订阅命令下发主题
//收到主题下发的回调, 注意这个回调要实现三个形参 1:topic 主题, 2: payload: 传递过来的信息 3: length: 长度
void callback(char *topic, byte *payload, unsigned int length)
{
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
 
  if ((char)payload[0] == '0') {
    digitalWrite(led, LOW);   // 
    god=0;
  } if ((char)payload[0] == '1') {
    digitalWrite(led, HIGH);  // 
    god=1;
  }
  else{}

}
6、led灯

关于灯,本来想外接的,但是我在查看原理图后就想偷懒了,毕竟开发板有自带了两个灯和RGB灯。这里我选择的是18接口的灯,因为19的灯是常亮的,所以不选它。
在这里插入图片描述

const int led =18; //灯的接口

在setup()定义灯是输出的

pinMode(led,OUTPUT);//输出

我这里设置一个god变量,初始化是0,即灯没有开,等接收到指令再进行变化,1为灯开。

7、嵌入源代码
#include 
#include "DHT.h"
#include "PubSubClient.h"
#include "Ticker.h"
#define DHTPIN 7     
#define DHTTYPE DHT11   // DHT 11
DHT dht(DHTPIN, DHTTYPE);
int god=0;
const int led =18; //灯的接口
const char *ssid     = "3671"; //wifi名称
const char *password = "05210835";//wifi密码
const char *mqtt_server = "183.230.40.96"; //onenet 的 IP地址
const int port = 6002;                     //端口号
#define mqtt_devid "884337606" //设备ID
#define mqtt_pubid "487632"        //产品ID
//鉴权信息
#define mqtt_password "20222222" //鉴权信息
WiFiClient espClient;           //创建一个WIFI连接客户端
PubSubClient client(espClient); // 创建一个PubSub客户端, 传入创建的WIFI客户端
char msg_buf[200];               //发送信息缓冲区
char msgJson[75]; //要发送的json格式的数据
unsigned short json_len = 0;                      //json长度
//信息模板
char dataTemplate[] = "{"temp":%.2f,"humi":%.2f,"led":%d}";  //  temp humi要与onenet相对应
Ticker tim1; //定时器,用来循环上传数据

void setupWifi(){
  WiFi.begin(ssid, password);
   while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print("正在连接中----n");
        
    }

    Serial.print("WIFI已连接n");
    Serial.print(WiFi.localIP());
}
void setup() {


  Serial.begin(115200);
  pinMode(led,OUTPUT);//输出
  setupWifi();   //调用函数连接WIFI
  Serial.print(F("DHT11 test!"));
  dht.begin();                                            
  client.setServer(mqtt_server, port);                   //设置客户端连接的服务器,连接Onenet服务器, 使用6002端口
  client.connect(mqtt_devid, mqtt_pubid, mqtt_password); //客户端连接到指定的产品的指定设备.同时输入鉴权信息
  if (client.connected())
  {
    Serial.print("OneNet is connected!");//判断以下是不是连好了.
  }
  //client.setCallback(callback);                                //设置好客户端收到信息是的回调
  client.setCallback(callback); //订阅命令下发主题
  tim1.attach(5, sendTempAndHumi);                            //定时每5秒调用一次发送数据函数sendTempAndHumi

}
  
void loop() {
delay(5000);
float h = dht.readHumidity(); 
float t = dht.readTemperature(); 
float f = dht.readTemperature(true);
  if (isnan(h) || isnan(t) || isnan(f)) {
    Serial.println(F("Failed to read from DHT sensor!n"));
    return;
  }
  //可以让我们通过串口查看数据
  Serial.print(F("Humidity: "));        
  Serial.print(h);
  Serial.print(F("%  Temperature: "));
  Serial.print(t);
  Serial.print(F("℃  n "));
  
  if (!WiFi.isConnected()) //先看WIFI是否还在连接
  {
    setupWifi();
  }
  if (!client.connected()) //如果客户端没连接ONENET, 重新连接
  {
    clientReconnect();
    delay(100);
  }
  client.loop(); //客户端循环检测


}

void sendTempAndHumi()
{
  if (client.connected())
  {
    //dht.readHumidity()
    snprintf(msgJson,75,dataTemplate,dht.readTemperature(),dht.readHumidity(),god); 
    json_len = strlen(msgJson);                   //msgJson的长度
    msg_buf[0] = char(0x03);                       //要发送的数据必须按照ONENET的要求发送, 根据要求,数据第一位是3
    msg_buf[1] = char(json_len >> 8);              //数据第二位是要发送的数据长度的高八位
    msg_buf[2] = char(json_len & 0xff);            //数据第三位是要发送数据的长度的低八位
    memcpy(msg_buf + 3, msgJson, strlen(msgJson)); //从msg_buf的第四位开始,放入要传的数据msgJson
    msg_buf[3 + strlen(msgJson)] = 0;              //添加一个0作为最后一位, 这样要发送的msg_buf准备好了

    Serial.print("public the data:");
    Serial.print(msgJson);
    client.publish("$dp", (uint8_t *)msg_buf, 3+strlen(msgJson));
    //发送数据到主题
    delay(500);
    
  }
}

//收到主题下发的回调, 注意这个回调要实现三个形参 1:topic 主题, 2: payload: 传递过来的信息 3: length: 长度
void callback(char *topic, byte *payload, unsigned int length)
{
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
 
  if ((char)payload[0] == '0') {
    digitalWrite(led, LOW);   // 
    god=0;
  } if ((char)payload[0] == '1') {
    digitalWrite(led, HIGH);  // 
    god=1;
  }
  else{}

}

void clientReconnect()
{
  while (!client.connected()) //再重连客户端
  {
    Serial.print("reconnect MQTT...");
   if (client.connect(mqtt_devid, mqtt_pubid, mqtt_password))
    {
      Serial.print("connected");
    }
    else
    {
      Serial.print("failed");
      Serial.print(client.state());
      Serial.print("try again in 5 sec");
     delay(5000);
    }
  }
}

四、微信开发者工具

​ 这个是微信提供的一个开发工具,有框架,也方便我们把项目部署到线上。这里我着重讲述怎么获取onene数据和发送指令

1、微信界面

在这里插入图片描述
在这里插入图片描述

2、获取Onenet的API接口

回到onenet的设备列表,然后在点击右边的详情就可以看到设备的详细信息,复制API地址和API-key,一个设备可以多个apikey,自行添加。

在这里插入图片描述

3、查询OneNet平台多协议接入文档,这里直接查看MQTT的API使用

在这里插入图片描述

4、我用ApiPost来进行测试是否能获取数据

在这里插入图片描述

5、微信小程序获取OneNet数据

这里我定义了points()函数,是用来获取Onenet平台数据的,主要放在index.js,为后面数据定时刷新做好铺垫。

 points:function(e) {
 
 
 }

​ 2、参考小程序文档,我这里采用wx.request 获取数据

points:function(e) {
    var that = this
    wx.request({
      url: 'http://api.heclouds.com/devices/xxxxxxxxxx/datapoints?', //xxz这里填写你的设备id
      //设备ID
      //api-key
      header:{
        "api-key":"xxxxxxx"  //这里写你的api-key
      },
      data:{
        limit:1    //数据流最新的一个数据 如果是5,即五个数据
      },
      method :"GET",
       //获取成功
      success:function(res){
       that.setData({
          wendu:res.data.data.datastreams[0].datapoints[0].value,
         time:res.data.data.datastreams[0].datapoints[0].at,
         shidu:res.data.data.datastreams[1].datapoints[0].value,
         led:res.data.data.datastreams[2].datapoints[0].value, //这里的shidu要跟wxml{{shidu}} 名字相同
        
       })    
      }
    })
  },

​ 3、关于如何显示到具体数字,因人而异,下面我这两行代码是根据json数据来定位的

shidu:res.data.data.datastreams[0].datapoints[0].value, 
wendu:res.data.data.datastreams[1].datapoints[0].value,

在这里插入图片描述

6、微信小程序下发命令

这里我也封装了两个函数,一个是发1值,一个发0值,因为我们的嵌入代码写是1代表打开灯,0代表关灯。这里以打开灯函数介绍

 openled:function(e){
    wx.request({
      url: 'http://api.heclouds.com/cmds?device_id=*****',//*号这里写你设备id
      //设备ID
      //api-key
      header:{
        'content-type':'application/json',
        "api-key":"xxxxxxx"  //这里写你的api-key
      },

      method :"POST",
      data:1,//数据1是为灯开
      success(res){
        console.log("控制成功,已开灯")
        console.log(res)
        console.log(res.data);

      }

    })
  },
7、数据刷新

其实这些网上都有的函数例子,我试过页面刷新、定时刷新,如果页面没有点击事件的话都可以用我下面这两个方法。但是有点击事件的话还是用定时刷新

页面刷新

//生命周期函数--监听页面加载
onLoad:function(options){
	this.points();  //这个是我获取onenet