commit ccbff5662745608ef9e6cfac3d6e37015b867f4a Author: james.liu Date: Tue Aug 25 16:19:31 2020 +0800 first commit diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..217df35 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright (c) 2008-2015 Nicholas O'Leary + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/REDME.md b/REDME.md new file mode 100644 index 0000000..10cbd9f --- /dev/null +++ b/REDME.md @@ -0,0 +1,137 @@ +#arduino esp32接入物联网通信云平台 +------------ +###本实践使用arduino平台esp32 wrover-b开发板连接上物联网通信云平台(UIoT Core),实现mqtt消息的发布与订阅 +##一、环境准备 +###1.下载并安装arduino IDE,[点击选择下载方式](https://www.arduino.cn/thread-5838-1-1.html) + +###2.完成安装之后,打开IDE,安装ESP32包,步骤如下: + +点击文件->首选项,弹出对话框 + +![1](./photo/1.png) + +按如图所示,点击1处方框,将 https://dl.espressif.com/dl/package_esp32_index.json 填入,点击好,保存 + +![2](./photo/2.png) + +点击工具->开发板->开发板管理器,弹出对话框 + +![3](./photo/3.png) + +等待下载完成之后,安装 + +![4](./photo/4.png) + +下载完成之后点击搜索框搜索esp32,点击安装,安装完成之后显示INSTALLED + +![5](./photo/5.png) + +esp32开发板安装完成! + +###3.安装依赖库 +点击 工具->管理库,弹出对话框 + +![6](./photo/6.png) + +安装PubSubClient库,在搜索框中粘贴```PubSubClient```,找到该名称**对应的库**,并安装 + +![7](./photo/7.png) + +安装ArduinoJson库,在搜索框中粘贴```Arduino_JSON```,找到该名称**对应的库**,并安装 + +![8](./photo/8.png) + + + +安装UCloudIoTSDK库,在搜索框中粘贴```UCloudIoTSDK```,找到该名称**对应的库**,并安装 + +![9](./photo/9.png) + +###4.开发板设置 + +用USB--连接上开发板,将开发板信息设置为如图所示(该设置仅仅针对该款ESP32,其它请自行查阅资料确认如何设置) + +![10](./photo/10.png) + +##二、程序编写 + +###1.首先包含sdk头文件以及连接wifi所需头文件。 +###2.设置wifi ssid以及password。 +###3.设置连接物联网通信平台需要的信息,该部分信息必须在物联网通信平台[创建产品以及设备](https://docs.ucloud.cn/uiot-core/console_guide/product_device/create_products)之后获得。```product_sn``` 和```device_sn```必填。[静态连接](https://docs.ucloud.cn/uiot-core/device_develop_guide/authenticate_devices/unique-certificate-per-device_authentication)时,将```product_secret```置为NULL并填写```device_secret```。[动态注册](https://docs.ucloud.cn/uiot-core/device_develop_guide/authenticate_devices/unique-certificate-per-product_authentication)时将```device_secret```置为NULL并填写```product_secret```。 +###4.定义mqtt测试topic。 +###5.设置用户消息回调函数,该回调函数在mqtt收到消息之后调用。 +###6.wifi连接过程 +###7.根据四元组信息以及回调函数构造UCloudMQTT对象 +###8.setup里面进行wifi连接以及mqtt连接,订阅测试topic +###9.loop里面进行消息接收以及每两秒发布一条测试topic的消息 +![11](./photo/11.png) +![12](./photo/12.png) + +##三、烧录以及现象 +###1.烧录 +点击图中→方向,点击之后开始编译,编译通过后自动下载到开发板 +![13](./photo/13.png) + +###2.现象 +使用串口工具连接esp32串口,看到如图所示有wifi连接成功,mqtt连接成功。以及订阅发布成功的log。 +![14](./photo/14.png) + +##四、注意事项 +###1.编译出现有些文件找不到,请确认是否将必要的库安装成功 +###2.烧录不了,确认arduino IDE能够读取到端口信息,如果开发板端口连接到其他串口工具,将会造成烧录失败 + +##五、拓展 +###该例程只演示了使用静态连接连上物联网通信云平台,此外SDK还有动态注册,以及TLS加密连接功能。想要使用动态注册只需要将四元组信息的```device_sn```置为NULL,并且正确填写四元组的其他三个信息。如果想要使用TLS加密连接,找到库文件,将库文件中的```ucloud_iot_sdk_esp32.h```打开,将```ENABLE_TLS```宏打开即可 +![15](./photo/15.png) + +##六、API参考 +###1.构造对象接口 +要使用该库进行mqtt连接到物联网通信云平台时,需要首先构建UCloudMQTT对象,使用到以下接口: +UCloudMQTT( +char *product_sn, +char *device_sn, +char *product_secret, +char *device_secret, +MQTTHandlerFun callback +); +参数:```product_sn```,指向存有产品序列号字符串的指针 +参数:```device_sn``` ,指向存有设备序列号字符串的指针 +参数:```product_secret```,指向存有产品秘钥字符串的指针 +参数:```device_secret``` ,指向存有设备秘钥字符串的指针 +参数:```callback```,用户消息回调函数指针 +使用示例: +```UCloudMQTT ucloudMQTT(product_sn,device_sn,product_secret,device_secret,msg_callback);``` + +###2.MQTT连接接口 +int mqtt_connect(void); +返回值: 0-连接成功 1-连接失败 +使用示例:```mqtt_connect();``` + +###3.延时等待接收MQTT消息接口 +void mqttYield(int time_ms); +参数:```time_ms```,延时等待的时间,ms为单位。 +使用示例:```mqttYield(2000);``` + +###4.查询MQTT状态接口 +boolean mqtt_status(void); +返回值: true-处于连接状态 false-断开状态 +使用示例:```mqtt_status();``` + +###5.MQTT发布接口 +boolean publish( +const char* topic, +const char* payload +); +参数:```topic```,消息TOPIC +参数:```payload```,消息内容 +返回值:true-发布成功 false-发布失败 +使用示例:```publish(MSG_TOPIC,"123456");``` + +###6.MQTT订阅接口 +boolean subscribe(const char* topic); +参数:```topic```,订阅的TOPIC +返回值:true-订阅成功 false-订阅失败 +使用示例:```subscribe(MSG_TOPIC);``` + +------------- +#结束 \ No newline at end of file diff --git a/examples/ESP32/esp32.ino b/examples/ESP32/esp32.ino new file mode 100644 index 0000000..111c180 --- /dev/null +++ b/examples/ESP32/esp32.ino @@ -0,0 +1,78 @@ +#include "ucloud_iot_sdk_esp32.h" +#include +/******用户实现************/ +#define wifi_ssid "LJZ" +#define wifi_password "12345678" + +#define product_sn "o2lp4qngf6ytdq1n" +#define device_sn "hhg4fq0iiw23lwp7" +#define product_secret NULL//"i1jybkmxm1ez9l4y" +#define device_secret "da5qd9isg6j8eany" +/*************************/ + +#define MQTT_TEST_TOPIC "/%s/%s/test/mqtt_connect" +#define MQTT_TEST_MESSAGE "This is a test message!" +char mqtt_test_topic[80]; + + +/*******用户消息回调函数************/ +void msg_callback(char* topic, uint8_t* payload, unsigned int length) +{ + Serial.println("calling user callback "); + Serial.print("Message received: "); + Serial.println(topic); + Serial.print("payload: "); + for (int i = 0; i < length; i++) { + Serial.print((char)payload[i]); + } + Serial.println(); +} + + +int wifi_connect(char *ssid,char *password) +{ + + Serial.print("attempting to connect "); + Serial.println(ssid); + WiFi.begin(ssid, password); + while (WiFi.status()!= WL_CONNECTED) + { + Serial.print("."); + // wait 1 second for re-trying + delay(1000); + } + Serial.print("connected with "); + Serial.println(ssid); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + +} + +UCloudMQTT ucloudMQTT(product_sn,device_sn,product_secret,device_secret,msg_callback); + +void setup() { + // put your setup code here, to run once: + Serial.begin(115200); + //连接wifi + wifi_connect(wifi_ssid,wifi_password); + //连接mqtt + while(!ucloudMQTT.mqtt_status()) { + ucloudMQTT.mqtt_connect(); + } + Serial.println("connected to ucloud iot core platform!"); + //订阅topic + sprintf(mqtt_test_topic,MQTT_TEST_TOPIC,product_sn,device_sn); + if(ucloudMQTT.subscribe(mqtt_test_topic)==false) + Serial.println("subscribe topic failed !"); + else + Serial.println("subscribe topic success !"); +} + +void loop() { + // put your main code here, to run repeatedly: + ucloudMQTT.mqttYield(2000); + if(ucloudMQTT.publish(mqtt_test_topic,MQTT_TEST_MESSAGE)==false) + Serial.println("publish topic failed !"); + else + Serial.println("publish topic success !"); +} diff --git a/examples/ESP8266/esp8266.ino b/examples/ESP8266/esp8266.ino new file mode 100644 index 0000000..b6857ce --- /dev/null +++ b/examples/ESP8266/esp8266.ino @@ -0,0 +1,73 @@ +#include "ucloud_iot_sdk_esp8266.h" +#include "ESP8266WiFi.h" +/******用户实现************/ +#define wifi_ssid "LJZ" +#define wifi_password "12345678" + +#define product_sn "o2lp4qngf6ytdq1n" +#define device_sn "4dg7a36jyla1qz1j" +#define product_secret NULL//"i1jybkmxm1ez9l4y" +#define device_secret "s2zrz9eaaj5ibpho" +/*************************/ + +#define MQTT_TEST_TOPIC "/%s/%s/test/mqtt_connect" +char mqtt_test_topic[80]; + +/*******用户消息回调函数************/ +void msg_callback(char* topic, uint8_t* payload, unsigned int length) +{ + Serial.println("calling user callback "); + Serial.print("Message received: "); + Serial.println(topic); + Serial.print("payload: "); + for (int i = 0; i < length; i++) { + Serial.print((char)payload[i]); + } +} + +int wifi_connect(char *ssid,char *password) +{ + Serial.print("attempting to connect "); + Serial.println(ssid); + //WiFi.mode(WIFI_STA); + WiFi.begin(ssid, password); + while (WiFi.status()!= WL_CONNECTED) + { + Serial.print("."); + // wait 1 second for re-trying + delay(1000); + } + Serial.print("connected with "); + Serial.println(ssid); + Serial.println("IP address: "); + Serial.println(WiFi.localIP()); + +} +UCloudMQTT ucloudMQTT(product_sn,device_sn,product_secret,device_secret,msg_callback); +void setup() { + // put your setup code here, to run once: + Serial.begin(76800); + Serial.println(); + //连接wifi + wifi_connect(wifi_ssid,wifi_password); + //连接mqtt + while(!ucloudMQTT.mqtt_status()) { + ucloudMQTT.mqtt_connect(); + } + Serial.println("connected to ucloud iot core platform!"); + //订阅topic + sprintf(mqtt_test_topic,MQTT_TEST_TOPIC,product_sn,device_sn); + if(ucloudMQTT.subscribe(mqtt_test_topic)==false) + Serial.println("subscribe topic failed !"); + else + Serial.println("subscribe topic success !"); +} + +void loop() { + // put your main code here, to run repeatedly: + ucloudMQTT.mqttYield(2000); + if(ucloudMQTT.publish(mqtt_test_topic,"123456789")==false) + Serial.println("publish topic failed !"); + else + Serial.println("publish topic success !"); +} diff --git a/keywords.txt b/keywords.txt new file mode 100644 index 0000000..ae4d434 --- /dev/null +++ b/keywords.txt @@ -0,0 +1,17 @@ +# Syntax Coloring Map For UCloud IoT Platform + +# Datatypes (KEYWORD1) + +UCloudIoTSDK KEYWORD1 + + +# Methods and Functions (KEYWORD2) + +mqtt_connect KEYWORD2 +mqttYield KEYWORD2 +mqtt_status KEYWORD2 +publish KEYWORD2 +subscribe KEYWORD2 + +# Constants (LITERAL1) + diff --git a/library.json b/library.json new file mode 100644 index 0000000..ae015b4 --- /dev/null +++ b/library.json @@ -0,0 +1,21 @@ +{ + "name": "UCloudIoTSDK", + "keywords": "ethernet, ucloud, mqtt, m2m, iot", + "description": "UCloudIoTSDK is designed & developed by UCloud IoT team , this library is used to connect with UCloud iot platform.", + "repository": { + "type": "git", + "url": "https://github.com/ucloud/ucloud-iot-sdk-arduino" + }, + "version": "0.0.1", + "examples": "examples/*/*.ino", + "frameworks": "arduino", + "platforms": ["espressif8266", "espressif32"], + "dependencies": [ + { + "name": "PubSubClient", + }, + { + "name": "Arduino_JSON" + } + ] +} diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..b087b5e --- /dev/null +++ b/library.properties @@ -0,0 +1,9 @@ +name=UCloudIoTSDK +version=0.0.1 +author=James Liu +maintainer=James Liu +sentence=An Arduino library for connecting ucloud iot platform made by UCloud IoT team. +paragraph=UCloudIoTSDK is designed & developed by UCloud IoT team , this library is used to connect with UCloud iot platform. +category=Communication +url=https://github.com/ucloud/ucloud-iot-sdk-arduino +architectures=* \ No newline at end of file diff --git a/photo/1.png b/photo/1.png new file mode 100644 index 0000000..627fc3f Binary files /dev/null and b/photo/1.png differ diff --git a/photo/10.png b/photo/10.png new file mode 100644 index 0000000..e65b8e3 Binary files /dev/null and b/photo/10.png differ diff --git a/photo/11.png b/photo/11.png new file mode 100644 index 0000000..36f17e7 Binary files /dev/null and b/photo/11.png differ diff --git a/photo/12.png b/photo/12.png new file mode 100644 index 0000000..aa15222 Binary files /dev/null and b/photo/12.png differ diff --git a/photo/13.png b/photo/13.png new file mode 100644 index 0000000..491030f Binary files /dev/null and b/photo/13.png differ diff --git a/photo/14.png b/photo/14.png new file mode 100644 index 0000000..837621f Binary files /dev/null and b/photo/14.png differ diff --git a/photo/15.png b/photo/15.png new file mode 100644 index 0000000..8039978 Binary files /dev/null and b/photo/15.png differ diff --git a/photo/2.png b/photo/2.png new file mode 100644 index 0000000..cf0aed8 Binary files /dev/null and b/photo/2.png differ diff --git a/photo/3.png b/photo/3.png new file mode 100644 index 0000000..48c4f43 Binary files /dev/null and b/photo/3.png differ diff --git a/photo/4.png b/photo/4.png new file mode 100644 index 0000000..6b6da87 Binary files /dev/null and b/photo/4.png differ diff --git a/photo/5.png b/photo/5.png new file mode 100644 index 0000000..112d2e1 Binary files /dev/null and b/photo/5.png differ diff --git a/photo/6.png b/photo/6.png new file mode 100644 index 0000000..a46e615 Binary files /dev/null and b/photo/6.png differ diff --git a/photo/7.png b/photo/7.png new file mode 100644 index 0000000..7245eaa Binary files /dev/null and b/photo/7.png differ diff --git a/photo/8.png b/photo/8.png new file mode 100644 index 0000000..b8e9b43 Binary files /dev/null and b/photo/8.png differ diff --git a/photo/9.png b/photo/9.png new file mode 100644 index 0000000..b8e9b43 Binary files /dev/null and b/photo/9.png differ diff --git a/src/ucloud_iot_sdk_esp32.cpp b/src/ucloud_iot_sdk_esp32.cpp new file mode 100644 index 0000000..6278a9d --- /dev/null +++ b/src/ucloud_iot_sdk_esp32.cpp @@ -0,0 +1,265 @@ + +#include "ucloud_iot_sdk_esp32.h" + + +#define PASSWRD_TOPIC "/$system/%s/%s/password" +#define PASSWORD_REPLY_TOPIC "/$system/%s/%s/password_reply" +#define CLIENT_ID "%s.%s" +#define USER_NAME "%s|%s|%d" + +WiFiClientSecure espSecureClient; +WiFiClient espClient; + +static PubSubClient client; +static const char* mqtt_server = "mqtt-cn-sh2.iot.ucloud.cn"; +char password_string[30] = "{\"RequestID\":\"1\"}"; +char passwrd_topic[100]; +char passwrd_reply_topic[100]; +Uiot_Info_st uiot_info_st; + +const char* mqtt_ca_crt= \ +{ + "-----BEGIN CERTIFICATE-----\n" \ + "MIIDsjCCApoCCQCudOie27G3QDANBgkqhkiG9w0BAQsFADCBmjELMAkGA1UEBhMC\n" + "Q04xETAPBgNVBAgMCFNoYW5naGFpMREwDwYDVQQHDAhTaGFuZ2hhaTEPMA0GA1UE\n" + "CgwGVUNsb3VkMRgwFgYDVQQLDA9VQ2xvdWQgSW9ULUNvcmUxFjAUBgNVBAMMDXd3\n" + "dy51Y2xvdWQuY24xIjAgBgkqhkiG9w0BCQEWE3Vpb3QtY29yZUB1Y2xvdWQuY24w\n" + "HhcNMTkwNzI5MTIyMDQxWhcNMzkwNzI0MTIyMDQxWjCBmjELMAkGA1UEBhMCQ04x\n" + "ETAPBgNVBAgMCFNoYW5naGFpMREwDwYDVQQHDAhTaGFuZ2hhaTEPMA0GA1UECgwG\n" + "VUNsb3VkMRgwFgYDVQQLDA9VQ2xvdWQgSW9ULUNvcmUxFjAUBgNVBAMMDXd3dy51\n" + "Y2xvdWQuY24xIjAgBgkqhkiG9w0BCQEWE3Vpb3QtY29yZUB1Y2xvdWQuY24wggEi\n" + "MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0g9bzkQBipln/nRsUKeQcwAkU\n" + "ZUk/VMWrg5AzBislYW9hujCGZHWXUknVHPSQM2Pk30tPeIdmupSkOJllYtFplI6U\n" + "6kqHpVsyPn925H5zz4uP5Ty0hkkNK+rIR/YjbEjGn8loTqWk++/o6qST5QOrZLUR\n" + "vxaWvshpce0QUcYU9xMfUPzLa6/ZfmaNHgn1aWExYMJAWDyBCyw4OxeSMUyH+ydh\n" + "egW7VHNQuVHOYdnXiC+VYImNJ8+QAyCIZ88lP0nqVPSKTt1XXmGW6vXrWSl+/XhO\n" + "GaHNMzlwb1kqlFx/ZagTQoQ0hpmqSUKtqPgKSqGPxY9go1Rda1m2rYc8k3gJAgMB\n" + "AAEwDQYJKoZIhvcNAQELBQADggEBAHU0KKqEbR7uoY1tlE+MDsfx/2zXNk9gYw44\n" + "O+xGVdbvTC298Ko4uUEwc1C+l9FaMmN/2qUPSXWsSrAYDGMS63rzaxqNuADTgmo9\n" + "QY0ITtTf0lZTkUahVSqAxzMFaaPzSfFeP9/EaUu14T5RPQbUZMVOAEPKDNmfK4rD\n" + "06R6dnO12be4Qlha14o67+ojaNtyZ7/ESePXA/RjO9YMkeQAoa4BdnsJCZgCFmXf\n" + "iKvGM+50+L/qSbH5F//byLGTO1t3TWCCdBE5/Mc/QLYEXDmZM6LMHyEAw4VuinIa\n" + "I8m1P/ceVO0RjNNBG0pDH9PH4OA7ikY81c63PBCQaYMKaiksCzs=\n" + "-----END CERTIFICATE-----\n" +}; + +//消息回调函数,收到数据之后对数据进行处理 +void dynamic_msg_callback(char* topic, uint8_t* payload, unsigned int length) +{ + Serial.print("Message received: "); + Serial.println(topic); + + Serial.print("payload: "); + for (int i = 0; i < length; i++) { + Serial.print((char)payload[i]); + } + Serial.println(); + + if((0 == strncmp(topic, passwrd_reply_topic, strlen(topic))) && ( uiot_info_st.auth_mode== DYNAMIC_AUTH)) + { + JSONVar myObject = JSON.parse((const char *)payload); + if (myObject.hasOwnProperty("Password")) + { + strncpy(uiot_info_st.deviceSecret, myObject["Password"], strlen(myObject["Password"])); + } + if (JSON.typeof(myObject) == "Password") + + Serial.print("Password received: "); + Serial.println(uiot_info_st.deviceSecret); + client.disconnect(); + uiot_info_st.auth_mode = STATIC_AUTH; + } +} + + +//构造函数,内部对传入的四元组进行检查以及初始化四元组,传入用户回调函数 +UCloudMQTT::UCloudMQTT(char *product_sn,char *device_sn,char *product_secret,char *device_secret,MQTTHandlerFun callback) +{ + if(product_sn==NULL||device_sn==NULL) + Serial.println("MQTT CONSTRUCT FAILED!"); + if(device_secret!=NULL) + { + uiot_info_st.auth_mode=STATIC_AUTH; + memcpy(uiot_info_st.deviceSecret,device_secret,20); + this->passWord=uiot_info_st.deviceSecret; + } + else if(product_secret!=NULL) + { + uiot_info_st.auth_mode=DYNAMIC_AUTH; + memcpy(uiot_info_st.productSecret,product_secret,20); + this->passWord=uiot_info_st.productSecret; + } + else + { + Serial.println("there is no any secret!"); + //~UCloudMQTT(); + } + if(callback==NULL) + { + uiot_info_st.user_callback=dynamic_msg_callback; + } + else + { + uiot_info_st.user_callback=callback; + } + #ifdef ENABLE_TLS + uiot_info_st.is_tls=IS_TLS; + #else + uiot_info_st.is_tls=NO_TLS; + #endif + memcpy(uiot_info_st.productSn,product_sn,20); + memcpy(uiot_info_st.deviceSn,device_sn,20); +} + +//mqtt连接,分为动态注册时的预认证和静态连接 +int UCloudMQTT::mqtt_connect(void) +{ + int retry_time=10; + while (!client.connected()&&retry_time) + { + if(uiot_info_st.is_tls==IS_TLS) + { + espSecureClient.setCACert(mqtt_ca_crt); + client.setClient(espSecureClient); + client.setServer(mqtt_server, 8883); + Serial.println("support TLS connection!"); + } + else + { + client.setClient(espClient); + client.setServer(mqtt_server, 1883); + } + client.setKeepAlive(500); + Serial.print("MQTT connecting ..."); + /* connect now */ + if(uiot_info_st.auth_mode == DYNAMIC_AUTH) + { + client.setCallback(dynamic_msg_callback); + gen_mqtt_connect_info(DYNAMIC_AUTH); + Serial.print("MQTT dynamic register ..."); + //如果是动态注册,等待预认证完成,auth_mode会在回调函数中改变 + while (uiot_info_st.auth_mode==DYNAMIC_AUTH&&retry_time) + { + client.connect(this->clientId,this->userName,this->passWord); + if(mqtt_status()==true) + { + Serial.println("connected"); + /* subscribe topic to get device secret */ + client.subscribe(passwrd_reply_topic); + client.publish(passwrd_topic, password_string); + long start_tick = millis(); + long timeout_flg=0; + while(uiot_info_st.auth_mode == DYNAMIC_AUTH&&timeout_flg==0) + { + mqttYield(1000); + if(millis()-start_tick>=10000) + timeout_flg=1; + } + if(timeout_flg) + { + Serial.println("mqtt dynamic register failed! get device password timeout!"); + return FAILED_RET; + } + } + else + { + Serial.print("failed, status code ="); + Serial.print(client.state()); + Serial.println(" try again in 3 seconds"); + /* Wait 3 seconds before retrying */ + delay(3000); + retry_time--; + } + + } + if(!retry_time) + { + Serial.println("mqtt dynamic register failed! retry too many times"); + return FAILED_RET; + } + } + else + { + client.setCallback(uiot_info_st.user_callback); + gen_mqtt_connect_info(STATIC_AUTH); + Serial.print("MQTT static connect..."); + if (client.connect(this->clientId,this->userName,this->passWord)) + { + Serial.println("connected"); + return 0; + } + else + { + Serial.print("failed, status code ="); + Serial.print(client.state()); + Serial.println(" try again in 3 seconds"); + /* Wait 3 seconds before retrying */ + delay(3000); + retry_time--; + } + } + } + if(!retry_time) + { + Serial.println("mqtt connect failed! retry too many times"); + return FAILED_RET; + } + return SUCCESS_RET; +} + +//根据四元组生成mqtt连接三要素,clientID,userName以及passward +void UCloudMQTT::gen_mqtt_connect_info(int auth_mode) +{ + sprintf(this->clientId,CLIENT_ID,uiot_info_st.productSn,uiot_info_st.deviceSn); + if(auth_mode==DYNAMIC_AUTH) + { + sprintf(this->userName,USER_NAME,uiot_info_st.productSn,uiot_info_st.deviceSn,2); + sprintf(passwrd_topic,PASSWRD_TOPIC,uiot_info_st.productSn,uiot_info_st.deviceSn); + sprintf(passwrd_reply_topic,PASSWORD_REPLY_TOPIC,uiot_info_st.productSn,uiot_info_st.deviceSn); + } + else + { + sprintf(this->userName,USER_NAME,uiot_info_st.productSn,uiot_info_st.deviceSn,1); + this->passWord = uiot_info_st.deviceSecret; + } +} + +//返回mqtt连接的状态 +boolean UCloudMQTT::mqtt_status() +{ + return client.connected(); +} + +//mqtt延时等待消息 +void UCloudMQTT::mqttYield(int time_ms) +{ + long start_tick = millis(); + while(millis()-start_tick +#include +#include +#include +#include +#include + +//#define ENABLE_TLS + +#define DYNAMIC_AUTH 1 +#define STATIC_AUTH 0 + +#define IS_TLS 1 +#define NO_TLS 0 + +#define FAILED_RET 1 +#define SUCCESS_RET 0 + +typedef void (*MQTTHandlerFun)(char* topic, uint8_t* payload, unsigned int length); + +typedef struct { + char productSn[20]; + char deviceSn[20]; + char productSecret[20]; + char deviceSecret[20]; + int auth_mode; + int is_tls; + MQTTHandlerFun user_callback; +}Uiot_Info_st; + +class UCloudMQTT +{ +public: + UCloudMQTT(char *product_sn,char *device_sn,char *product_secret,char *device_secret,MQTTHandlerFun callback); + ~UCloudMQTT(void); + int mqtt_connect(void); + void mqttYield(int time_ms); + boolean mqtt_status(void); + boolean publish(const char* topic, const char* payload); + boolean subscribe(const char* topic); +private: + char clientId[40]; + char userName[40]; + char *passWord; + void gen_mqtt_connect_info(int auth_mode); +}; + +void dynamic_msg_callback(char* topic, uint8_t* payload, unsigned int length); + +#endif /* ___UCLOUDIOTSDK_H___ */ diff --git a/src/ucloud_iot_sdk_esp8266.cpp b/src/ucloud_iot_sdk_esp8266.cpp new file mode 100644 index 0000000..4522de9 --- /dev/null +++ b/src/ucloud_iot_sdk_esp8266.cpp @@ -0,0 +1,287 @@ + +#include "ucloud_iot_sdk_esp8266.h" + + +#define PASSWRD_TOPIC "/$system/%s/%s/password" +#define PASSWORD_REPLY_TOPIC "/$system/%s/%s/password_reply" +#define CLIENT_ID "%s.%s" +#define USER_NAME "%s|%s|%d" + +const char* mqtt_ca_crt= \ +{ + "-----BEGIN CERTIFICATE-----\n" \ + "MIIDsjCCApoCCQCudOie27G3QDANBgkqhkiG9w0BAQsFADCBmjELMAkGA1UEBhMC\n" + "Q04xETAPBgNVBAgMCFNoYW5naGFpMREwDwYDVQQHDAhTaGFuZ2hhaTEPMA0GA1UE\n" + "CgwGVUNsb3VkMRgwFgYDVQQLDA9VQ2xvdWQgSW9ULUNvcmUxFjAUBgNVBAMMDXd3\n" + "dy51Y2xvdWQuY24xIjAgBgkqhkiG9w0BCQEWE3Vpb3QtY29yZUB1Y2xvdWQuY24w\n" + "HhcNMTkwNzI5MTIyMDQxWhcNMzkwNzI0MTIyMDQxWjCBmjELMAkGA1UEBhMCQ04x\n" + "ETAPBgNVBAgMCFNoYW5naGFpMREwDwYDVQQHDAhTaGFuZ2hhaTEPMA0GA1UECgwG\n" + "VUNsb3VkMRgwFgYDVQQLDA9VQ2xvdWQgSW9ULUNvcmUxFjAUBgNVBAMMDXd3dy51\n" + "Y2xvdWQuY24xIjAgBgkqhkiG9w0BCQEWE3Vpb3QtY29yZUB1Y2xvdWQuY24wggEi\n" + "MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC0g9bzkQBipln/nRsUKeQcwAkU\n" + "ZUk/VMWrg5AzBislYW9hujCGZHWXUknVHPSQM2Pk30tPeIdmupSkOJllYtFplI6U\n" + "6kqHpVsyPn925H5zz4uP5Ty0hkkNK+rIR/YjbEjGn8loTqWk++/o6qST5QOrZLUR\n" + "vxaWvshpce0QUcYU9xMfUPzLa6/ZfmaNHgn1aWExYMJAWDyBCyw4OxeSMUyH+ydh\n" + "egW7VHNQuVHOYdnXiC+VYImNJ8+QAyCIZ88lP0nqVPSKTt1XXmGW6vXrWSl+/XhO\n" + "GaHNMzlwb1kqlFx/ZagTQoQ0hpmqSUKtqPgKSqGPxY9go1Rda1m2rYc8k3gJAgMB\n" + "AAEwDQYJKoZIhvcNAQELBQADggEBAHU0KKqEbR7uoY1tlE+MDsfx/2zXNk9gYw44\n" + "O+xGVdbvTC298Ko4uUEwc1C+l9FaMmN/2qUPSXWsSrAYDGMS63rzaxqNuADTgmo9\n" + "QY0ITtTf0lZTkUahVSqAxzMFaaPzSfFeP9/EaUu14T5RPQbUZMVOAEPKDNmfK4rD\n" + "06R6dnO12be4Qlha14o67+ojaNtyZ7/ESePXA/RjO9YMkeQAoa4BdnsJCZgCFmXf\n" + "iKvGM+50+L/qSbH5F//byLGTO1t3TWCCdBE5/Mc/QLYEXDmZM6LMHyEAw4VuinIa\n" + "I8m1P/ceVO0RjNNBG0pDH9PH4OA7ikY81c63PBCQaYMKaiksCzs=\n" + "-----END CERTIFICATE-----\n" +}; + +WiFiClient espClient; +BearSSL::WiFiClientSecure espSecureClient; +BearSSL::X509List mqttcert(mqtt_ca_crt); + +static PubSubClient client; +static const char* mqtt_server = "mqtt-cn-sh2.iot.ucloud.cn"; +char password_string[30] = "{\"RequestID\":\"1\"}"; +char passwrd_topic[100]; +char passwrd_reply_topic[100]; +Uiot_Info_st uiot_info_st; + + +//消息回调函数,收到数据之后对数据进行处理 +void dynamic_msg_callback(char* topic, uint8_t* payload, unsigned int length) +{ + Serial.print("Message received: "); + Serial.println(topic); + + Serial.print("payload: "); + for (int i = 0; i < length; i++) { + Serial.print((char)payload[i]); + } + Serial.println(); + + if((0 == strncmp(topic, passwrd_reply_topic, strlen(topic))) && ( uiot_info_st.auth_mode== DYNAMIC_AUTH)) + { + JSONVar myObject = JSON.parse((const char *)payload); + if (myObject.hasOwnProperty("Password")) + { + strncpy(uiot_info_st.deviceSecret, myObject["Password"], strlen(myObject["Password"])); + } + if (JSON.typeof(myObject) == "Password") + + Serial.print("Password received: "); + Serial.println(uiot_info_st.deviceSecret); + client.disconnect(); + uiot_info_st.auth_mode = STATIC_AUTH; + } +} + +//构造函数,内部对传入的四元组进行检查以及初始化四元组,传入用户回调函数 +UCloudMQTT::UCloudMQTT(char *product_sn,char *device_sn,char *product_secret,char *device_secret,MQTTHandlerFun callback) +{ + if(product_sn==NULL||device_sn==NULL) + Serial.println("MQTT CONSTRUCT FAILED!"); + if(device_secret!=NULL) + { + uiot_info_st.auth_mode=STATIC_AUTH; + memcpy(uiot_info_st.deviceSecret,device_secret,20); + this->passWord=uiot_info_st.deviceSecret; + } + else if(product_secret!=NULL) + { + uiot_info_st.auth_mode=DYNAMIC_AUTH; + memcpy(uiot_info_st.productSecret,product_secret,20); + this->passWord=uiot_info_st.productSecret; + } + else + { + Serial.println("there is no any secret!"); + } + if(callback==NULL) + { + uiot_info_st.user_callback=dynamic_msg_callback; + } + else + { + uiot_info_st.user_callback=callback; + } + #ifdef ENABLE_TLS + uiot_info_st.is_tls=IS_TLS; + #else + uiot_info_st.is_tls=NO_TLS; + #endif + memcpy(uiot_info_st.productSn,product_sn,20); + memcpy(uiot_info_st.deviceSn,device_sn,20); +} + +//mqtt连接,分为动态注册时的预认证和静态连接 +int UCloudMQTT::mqtt_connect(void) +{ + int retry_time=10; + while (!client.connected()&&retry_time) + { + if(uiot_info_st.is_tls==IS_TLS) + { + + espSecureClient.setTrustAnchors(&mqttcert); + setClock(); + // if no check the CA Certification + espSecureClient.setInsecure(); + client.setClient(espSecureClient); + client.setServer(mqtt_server, 8883); + Serial.println("support TLS connection!"); + } + else + { + client.setClient(espClient); + client.setServer(mqtt_server, 1883); + } + client.setKeepAlive(500); + Serial.print("MQTT connecting ..."); + /* connect now */ + if(uiot_info_st.auth_mode == DYNAMIC_AUTH) + { + client.setCallback(dynamic_msg_callback); + gen_mqtt_connect_info(DYNAMIC_AUTH); + Serial.print("MQTT dynamic register ..."); + //如果是动态注册,等待预认证完成,auth_mode会在回调函数中改变 + while (uiot_info_st.auth_mode==DYNAMIC_AUTH&&retry_time) + { + client.connect(this->clientId,this->userName,this->passWord); + if(mqtt_status()==true) + { + Serial.println("connected"); + /* subscribe topic to get device secret */ + client.subscribe(passwrd_reply_topic); + client.publish(passwrd_topic, password_string); + long start_tick = millis(); + long timeout_flg=0; + while(uiot_info_st.auth_mode == DYNAMIC_AUTH&&timeout_flg==0) + { + mqttYield(1000); + if(millis()-start_tick>=10000) + timeout_flg=1; + } + if(timeout_flg) + { + Serial.println("mqtt dynamic register failed! get device password timeout!"); + return FAILED_RET; + } + } + else + { + Serial.print("failed, status code ="); + Serial.print(client.state()); + Serial.println(" try again in 3 seconds"); + /* Wait 3 seconds before retrying */ + delay(3000); + retry_time--; + } + + } + if(!retry_time) + { + Serial.println("mqtt dynamic register failed! retry too many times"); + return FAILED_RET; + } + } + else + { + client.setCallback(uiot_info_st.user_callback); + gen_mqtt_connect_info(STATIC_AUTH); + Serial.print("MQTT static connect..."); + if (client.connect(this->clientId,this->userName,this->passWord)) + { + Serial.println("connected"); + return 0; + } + else + { + Serial.print("failed, status code ="); + Serial.print(client.state()); + Serial.println(" try again in 3 seconds"); + /* Wait 3 seconds before retrying */ + delay(3000); + retry_time--; + } + } + } + if(!retry_time) + { + Serial.println("mqtt connect failed! retry too many times"); + return FAILED_RET; + } + return SUCCESS_RET; +} + +//根据四元组生成mqtt连接三要素,clientID,userName以及passward +void UCloudMQTT::gen_mqtt_connect_info(int auth_mode) +{ + sprintf(this->clientId,CLIENT_ID,uiot_info_st.productSn,uiot_info_st.deviceSn); + if(auth_mode==DYNAMIC_AUTH) + { + sprintf(this->userName,USER_NAME,uiot_info_st.productSn,uiot_info_st.deviceSn,2); + sprintf(passwrd_topic,PASSWRD_TOPIC,uiot_info_st.productSn,uiot_info_st.deviceSn); + sprintf(passwrd_reply_topic,PASSWORD_REPLY_TOPIC,uiot_info_st.productSn,uiot_info_st.deviceSn); + } + else + { + sprintf(this->userName,USER_NAME,uiot_info_st.productSn,uiot_info_st.deviceSn,1); + this->passWord = uiot_info_st.deviceSecret; + } +} +// Set time via NTP, as required for x.509 validation +void UCloudMQTT::setClock() +{ + configTime(3 * 3600, 0, "pool.ntp.org", "time.nist.gov"); + Serial.print("Waiting for NTP time sync: "); + time_t now = time(nullptr); + while (now < 8 * 3600 * 2) + { + delay(500); + Serial.print("."); + now = time(nullptr); + } + Serial.println(""); + struct tm timeinfo; + gmtime_r(&now, &timeinfo); + Serial.print("Current time: "); + Serial.print(asctime(&timeinfo)); +} + +//返回mqtt连接的状态 +boolean UCloudMQTT::mqtt_status() +{ + return client.connected(); +} + +//mqtt延时等待消息 +void UCloudMQTT::mqttYield(int time_ms) +{ + long start_tick = millis(); + while(millis()-start_tick +#include +#include +#include +#include +#include + +//#define ENABLE_TLS + +#define DYNAMIC_AUTH 1 +#define STATIC_AUTH 0 + +#define IS_TLS 1 +#define NO_TLS 0 +#define FAILED_RET 1 +#define SUCCESS_RET 0 + + +typedef void (*MQTTHandlerFun)(char* topic, uint8_t* payload, unsigned int length); + +typedef struct { + char productSn[20]; + char deviceSn[20]; + char productSecret[20]; + char deviceSecret[20]; + int auth_mode; + int is_tls; + MQTTHandlerFun user_callback; +}Uiot_Info_st; + + + +class UCloudMQTT +{ +public: + UCloudMQTT(char *product_sn,char *device_sn,char *product_secret,char *device_secret,MQTTHandlerFun callback); + ~UCloudMQTT(void); + int mqtt_connect(void); + void mqttYield(int time_ms); + boolean mqtt_status(void); + boolean publish(const char* topic, const char* payload); + boolean subscribe(const char* topic); + +private: + char clientId[40]; + char userName[40]; + char *passWord; + void gen_mqtt_connect_info(int auth_mode); + void setClock(); +}; + +void dynamic_msg_callback(char* topic, uint8_t* payload, unsigned int length); + + +#endif /* ___UCLOUDIOTSDK_H___ */