wuji 发表于 2019-4-19 15:20:39

【阿里云IoT使用教程4】ESP32与阿里云IoT平台通信

本帖最后由 wuji 于 2019-5-11 10:32 编辑

ESP32与阿里云IoT平台通信    
      本篇主要介绍物理设备与阿里云IOT平台之间的交互通信,如:通过阿里云平台点亮一颗LED灯,通过按钮改变阿里云IoT平台上的某个虚拟灯状态。 所需材料阿里云IoT 入门套件x1       在开始之前,先下载阿里云IoT入门套件库文件及样例代码:      下载页面:https://www.dfrobot.com.cn/goods-1896.html
在开始之前,需要了解a. 产品标识符;b.上报(PubTopic)和订阅(SubTopic)TOPIC等信息。
产品标识符         为产品定义某个功能时,会同时为它定义一个标识符,相当于程序中的变量,通过改变它的值,执行相应的功能。         创建并获取方式:进入某个产品的产品详情页,点击功能定义,在自定义功能栏即可创建新功能或获取被创建的产品标识符。上报Topic      通过它,ESP32主控可以上报某个设备的属性(即更新阿里云IoT上某个设备的功能状态)到阿里云平台上。      获取方式:进入某个设备的设备详情页,选择Topic列表,即可找到发布(上报)TOPIC信息,如下图所示:

订阅Topic       通过它,会检测并接收到阿里云IoT向ESP32发送的指令,再通过数据格式解析从而操作ESP32上的某个设备。       获取方式:进入某个设备的设备详情页,选择Topic列表,,即可找到订阅TOPIC信息,如下图所示:
平台数据交互:      ESP32通过上报Topic将设备信息传送给阿里云IoT平台,通过订阅Topic接收来自阿里云IoT平台的指令。      而阿里云IoT可通过真实设备调试,设置并获取ESP32上设备的状态,可通过运行状态实时检测ESP32上报的数据。例:通过阿里云IoT平台点亮或熄灭LED灯,在阿里云IoT平台上实时检测真实设备按钮是否被按下。
准备工作      1.打开浏览器,输入网址iot.aliyun.com;      2.进入物联网平台控制台;      3.在产品栏创建一个名为智能家居(名字自取)的产品,如下图所示:

      4.为ESP32产品,定义一个名为LED开关的属性,标识符为LightSwitch,0代表关灯,1代表开灯,如下图所示:

       5.在智能家居产品下挂载一个设备名为ESP32(名字自取或不填)的设备,如下图所示:

      得到ESP32设备的设备证书信息,如下图所示:

      7.将LED灯连接到插有FireBeetle扩展板的ESP32的D2口,将按钮连接到扩展版的D3口,连接如下图所示:

      8.向ESP32主控烧录程序。      由此准备工作即完成,接下来就是如何用搭建好的平台来实现物理设备同阿里云IOT平台上的通信。

如何通过阿里云IoT平台点亮一颗LED灯?         在产品栏找到上面创建的智能家居产品,单击其后的查看按钮,如下图所示:

         在弹出的产品详情页页面,点击在线调试,如下图所示:

          点击前往查看,进入如下所示页面

      选择ESP32设备,进入在线调试页面,选择调试真实设备,如下图所示

      如果真实设备没有连接上阿里云平台,其功能,方法框都是灰色的,无法使用,如下图所示:

   当真实设备上线后(即连接到阿里云平台上的某个虚拟设备后),即可调试真实设备了,选择LED开关功能,选择设置,如下图所示:
      点亮LED灯,将标识符LightSwitch1的值变为1,再单击发送指令,即可点亮LED灯,如下图所示:

         关LED灯,将标识符LightSwitch1的值变为0,再单击发送指令,即可熄灭LED灯,如下图所示:


如何在阿里云IoT平台上实时检测按钮是否被按下?      在设备列表栏,找到创建的ESP32设备,点击其后的查看按钮,如下图所示:

         进入设备详情页,点击运行状态,开启实时刷新,如下图所示:

       当按钮按下时,会发现LED开关数据变为1,如下图所示:

      当按钮按松开时,会发现LED开关数据变为0,如下图所示:

注:虽然阿里云平台上,设备ESP32中LED开关的状态值发生了改变,但是物理设备上的LED灯,并不会随着按钮的状态而改变。因为阿里云IoT平台上没有创建当检测到设备状态发生改变后,自动下发指令到ESP32设备上的服务。
         以上2个例子(1.调试真实设备;2运行状态实时刷新)简单的实现了真实设备同阿里云IoT平台的交互。下一篇,将会讲述:如何通过阿里云平台,让按钮开关LED灯(需要在阿里云平台上搭建服务)。
扩展:
Arduino程序的逻辑:
      1.将D2(LED)设置为IO输出,并输出低电平(默认关LED);      2.将D3(BUTTON)设置为IO输入,初始状态为低(按钮松开)      3.连接WiFi;      4.通过设备证书信息、域名、端口号连接上阿里云平台;(实现MQTT连接)      5.通过产品表示符、上报和订阅Topic与阿里云平台通信;(实现MQTT通信)      6.上报LED灯初始状态。      7.等待订阅和按钮状态改变时间发生。
MQTT通信程序逻辑功能:
      a.ESP32接收并解析阿里云IoT平台下发的指令,若检测到标识符为0,则执行关灯指令,为1则执行开灯动作,且当LED灯状态发生改变(从亮到灭,或从灭到亮)时才上报LED灯状态;      b.当ESP32检测到按钮状态(松开、按下)发生改变时,发送改变LED灯状态的指令给阿里云平台。                  按下:LED开关状态值变为1                  松开:LED开关状态值变为0   即只有ESP32检测到按钮或灯的状态发生改变后,才上报数据给阿里云平台。
详细代码如下:#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include "DFRobot_Aliyun.h"

#define LEDD2
#define BUTTON D3

/*配置WIFI名和密码*/
const char * WIFI_SSID   = "host";
const char * WIFI_PASSWORD = "123456789";

/*配置设备证书信息*/
String ProductKey = "**********";
String ClientId = "12345";/*自定义ID*/
String DeviceName = "*************";
String DeviceSecret = "******************";

/*配置域名和端口号*/
String ALIYUN_SERVER = "iot-as-mqtt.cn-shanghai.aliyuncs.com";
uint16_t PORT = 1883;

/*需要操作的产品标识符*/
String Identifier = "LightSwitch";

/*需要上报和订阅的两个TOPIC*/
const char * subTopic = "***************************";//****set
const char * pubTopic = "**************************";//******post

DFRobot_Aliyun myAliyun;
WiFiClient espClient;
PubSubClient client(espClient);

/*ButtonState、LEDState用来存储LED灯同BUTTON按钮的当前值*/
uint8_t ButtonState = 0;
uint16_t LEDState = 0;
static void openLight(){
digitalWrite(LED, HIGH);
}

static void closeLight(){
digitalWrite(LED, LOW);
}

void connectWiFi(){
Serial.print("Connecting to ");
Serial.println(WIFI_SSID);
WiFi.begin(WIFI_SSID,WIFI_PASSWORD);
while(WiFi.status() != WL_CONNECTED){
    delay(500);
    Serial.print(".");
}
Serial.println();
Serial.println("WiFi connected");
Serial.print("IP Adderss: ");
Serial.println(WiFi.localIP());
}

void callback(char * topic, byte * payload, unsigned int len){
Serial.print("123");
Serial.print("Recevice [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < len; i++){
    Serial.print((char)payload);
}
Serial.println();
StaticJsonBuffer<300> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject((const char *)payload);
if(!root.success()){
    Serial.println("parseObject() failed");
    return;
}
const uint16_t LightStatus = root["params"];
if(LightStatus == 1){
    openLight();
}else{
    closeLight();
}
/*当LED灯的状态发生改变后,则上报LED灯的当前状态*/
if(LightStatus != LEDState)
{
      LEDState = LightStatus;
      String tempMseg = "{\"id\":"+ClientId+",\"params\":{\""+Identifier+"\":"+(String)LightStatus+"},\"method\":\"thing.event.property.post\"}";
      char sendMseg;
      strcpy(sendMseg,tempMseg.c_str());
      client.publish(pubTopic,sendMseg);
}
}

void ConnectAliyun(){
while(!client.connected()){
    Serial.print("Attempting MQTT connection...");
    /*根据自动计算的用户名和密码连接到Alinyun的设备,不需要更改*/
    if(client.connect(myAliyun.client_id,myAliyun.username,myAliyun.password)){
      Serial.println("connected");
      client.subscribe(subTopic);
    }else{
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
}
}
void setup(){
Serial.begin(115200);
/*将LED(D2)设置为IO输出,BUTTON(D3)设置为IO输入*/
pinMode(LED,OUTPUT);
pinMode(BUTTON,INPUT);

/*连接WIFI*/
connectWiFi();

/*初始化Alinyun的配置,可自动计算用户名和密码*/
myAliyun.init(ALIYUN_SERVER,ProductKey,ClientId,DeviceName,DeviceSecret);

client.setServer(myAliyun.mqtt_server,PORT);

/*设置回调函数,当收到订阅信息时会执行回调函数*/
client.setCallback(callback);

/*连接到Aliyun*/
ConnectAliyun();

/*开机先关灯*/
closeLight();
/*保存BUTTON按钮的初始值状态*/
ButtonState =digitalRead(BUTTON);
//Serial.print("ButtonState:");
//Serial.println(ButtonState);
/*上报关灯信息*/
client.publish(pubTopic,("{\"id\":"+ClientId+",\"params\":{\""+Identifier+"\":0},\"method\":\"thing.event.property.post\"}").c_str());
}

void loop(){
if(!client.connected()){
    ConnectAliyun();
}
uint8_t ButtonValue = digitalRead(BUTTON);
/*如果检测到按钮的状态发生了改变,则发送指令到阿里云平台以更新设备信息*/
if (ButtonValue != ButtonState)
{
    /*保存按钮的当前状态*/
    ButtonState = ButtonValue;
    /*按下:发送开灯指令,阿里云IoT上的相应设备状态变为1;松开:发送关灯指令,阿里云IoT上的相应设备状态值变为0,只需改变Identifier后的值*/
    String tempMseg = "{\"id\":"+ClientId+",\"params\":{\""+Identifier+"\":"+(String)ButtonState+"},\"method\":\"thing.event.property.post\"}";
    char sendMseg;
    strcpy(sendMseg,tempMseg.c_str());
    client.publish(pubTopic,sendMseg);
    delay(1000);
}
client.loop();
}

刁雷 发表于 2019-4-28 15:59:18

阿里云物联网平台花钱么 。。。。

wuji 发表于 2019-4-29 09:08:35

刁雷 发表于 2019-4-28 15:59
阿里云物联网平台花钱么 。。。。

套件用的是免费的

刁雷 发表于 2019-4-29 13:12:39

wuji 发表于 2019-4-29 09:08
套件用的是免费的

好的谢谢

DFlc 发表于 2019-5-23 22:23:48

这咋搞?

RiesenQiao 发表于 2019-10-10 11:05:39

如果不需要写死WiFi SSID和密码,要怎么写呢?

DFHk-0ykaN8 发表于 2020-3-4 16:08:46

请问楼主物联网的开通是否收费,个人能够负担得起吗?

冬歌 发表于 2020-3-9 14:23:08

请问楼主真实设备一直不在线是怎么回事啊

wxyaoo 发表于 2020-4-1 11:00:50

我测试着这个程序灯不能一直亮,在线模拟发一次信号,亮一次就灭了。把这个程序注释掉就没事了,什么原因

沈世安 发表于 2020-12-4 17:05:57

Attempting MQTT connection...failed, rc=2 try again in 5 seconds
页: [1]
查看完整版本: 【阿里云IoT使用教程4】ESP32与阿里云IoT平台通信