記錄一下,自己的第一個項目,雖然很簡單,但也了解了關於MQTT的部分知識。
這是APP的界面
這是物聯網的界面,用的是百度雲,之前用阿里雲上傳數據沒成功。
app的教程是根據B站一位大佬學的:https://www.bilibili.com/video/BV1G7411t7zs
講的挺好的,零基礎,我一點java都不會也能聽懂。
至於百度雲的使用方法就是看文檔了,(雖然很煩)
下面是ESP8266的核心代碼
/* main.c -- MQTT client example * * Copyright (c) 2014-2015, Tuan PM <tuanpm at live dot com> * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Redis nor the names of its contributors may be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // // // 工程: MQTT_Data-Visualization // 注:在《MQTT_JX》例程上修改 // // // // // 平台: 物聯網開發板 ESP8266 V1.0 // ①:按照創建【物影子】時獲取到的MQTT連接參數,修改<mqtt_config.h> // // // // // 功能: ①:設置【物影子】MQTT相關參數 // ②:將<dht11.c>添加到<modules>,將<dht11.h>添加到<include/modules> // // // // // ②:ESP8266接入百度雲【物影子】 // ③:需注意,<dht11.c>中,須改為<#include modules/dht11.h> // // // // // ③:每5秒向【物影子】上報【溫濕度數據】 // ④:在<mqtt.c>定時函數中,添加:每5秒向【物影子】上報【溫濕度數據】 // // // // // 版本: V1.0 // ⑤:取消【訂閱"SW_LED"】【向"SW_LED"發布消息】操作 // // // ⑥:led_flag :0代表繼電器關,1代表繼電器開 // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // 頭文件 //============================== #include "ets_sys.h" #include "driver/uart.h" #include "osapi.h" #include "mqtt.h" #include "wifi.h" #include "config.h" #include "debug.h" #include "gpio.h" #include "user_interface.h" #include "user_config.h" #include "mem.h" #include "sntp.h" //添加,iic LED頭文件 #include "driver/oled.h" // OLED #include "c_types.h" // 變量類型 #include "eagle_soc.h" // GPIO函數、宏定義 #include "modules/dht11.h" // DHT11 #include "dht11.h" // DHT11 //============================== // 類型定義 //================================= typedef unsigned long u32_t; //================================= // 全局變量 //============================================================================ MQTT_Client mqttClient; // MQTT客戶端_結構體【此變量非常重要】 static ETSTimer sntp_timer; // SNTP定時器 char *dataBuf="{\"SW_LED\":1}"; //傳入數據所對應的字符串 char *topicBuf=NULL; //topic所對應的字符串 char led_flag = 0;//表示燈的狀態,燈滅 //============================================================================ os_timer_t OS_Timer_1; // 軟件定時器 // 定時的回調函數 //========================================================================================== void ICACHE_FLASH_ATTR OS_Timer_1_cb(void) { if(DHT11_Read_Data_Complete() == 0) // 讀取DHT11溫濕度值,讀取成功才能顯示值 { // OLED顯示溫濕度 //--------------------------------------------------------------------------------- DHT11_NUM_Char(); // DHT11數據值轉成字符串 OLED_ShowString(0,2,DHT11_Data_Char[0]); // DHT11_Data_Char[0] == 【濕度字符串】 OLED_ShowString(0,6,DHT11_Data_Char[1]); // DHT11_Data_Char[1] == 【溫度字符串】 } } // 軟件定時器初始化(ms毫秒) //========================================================================================== void ICACHE_FLASH_ATTR OS_Timer_1_Init_JX(u32 time_ms, u8 time_repetitive) { os_timer_disarm(&OS_Timer_1); // 關閉定時器 os_timer_setfn(&OS_Timer_1,(os_timer_func_t *)OS_Timer_1_cb, NULL); // 設置定時器 os_timer_arm(&OS_Timer_1, time_ms, time_repetitive); // 使能定時器 } //========================================================================================== // 毫秒延時函數 //=========================================== void ICACHE_FLASH_ATTR delay_ms(u32 C_time) { for(;C_time>0;C_time--) os_delay_us(1000); } //=========================================== // SNTP定時函數:獲取當前網絡時間 //============================================================================ void sntpfn() { u32_t ts = 0; ts = sntp_get_current_timestamp(); // 獲取當前的偏移時間 os_printf("current time : %s\n", sntp_get_real_time(ts)); // 獲取真實時間 if (ts == 0) // 網絡時間獲取失敗 { os_printf("did not get a valid time from sntp server\n"); } else //(ts != 0) // 網絡時間獲取成功 { os_timer_disarm(&sntp_timer); // 關閉SNTP定時器 MQTT_Connect(&mqttClient); // 開始MQTT連接 } } //============================================================================ // WIFI連接狀態改變:參數 = wifiStatus //============================================================================ void wifiConnectCb(uint8_t status) { // 成功獲取到IP地址 //--------------------------------------------------------------------- if(status == STATION_GOT_IP) { ip_addr_t * addr = (ip_addr_t *)os_zalloc(sizeof(ip_addr_t)); // 在官方例程的基礎上,增加2個備用服務器 //--------------------------------------------------------------- sntp_setservername(0, "us.pool.ntp.org"); // 服務器_0【域名】 sntp_setservername(1, "ntp.sjtu.edu.cn"); // 服務器_1【域名】 ipaddr_aton("210.72.145.44", addr); // 點分十進制 => 32位二進制 sntp_setserver(2, addr); // 服務器_2【IP地址】 os_free(addr); // 釋放addr sntp_init(); // SNTP初始化 // 設置SNTP定時器[sntp_timer] //----------------------------------------------------------- os_timer_disarm(&sntp_timer); os_timer_setfn(&sntp_timer, (os_timer_func_t *)sntpfn, NULL); os_timer_arm(&sntp_timer, 1000, 1); // 1s定時 } // IP地址獲取失敗 //---------------------------------------------------------------- else { MQTT_Disconnect(&mqttClient); // WIFI連接出錯,TCP斷開連接 } } //============================================================================ // MQTT已成功連接:ESP8266發送【CONNECT】,並接收到【CONNACK】 //============================================================================ void mqttConnectedCb(uint32_t *args) { MQTT_Client* client = (MQTT_Client*)args; // 獲取mqttClient指針 INFO("MQTT: Connected\r\n"); // 【參數2:主題過濾器 / 參數3:訂閱Qos】 //----------------------------------------------------------------- MQTT_Subscribe(client, "$baidu/iot/general/a", 0); // 訂閱主題"SW_LED",QoS=0 // MQTT_Subscribe(client, "SW_LED", 1); // MQTT_Subscribe(client, "SW_LED", 2); // 【參數2:主題名 / 參數3:發布消息的有效載荷 / 參數4:有效載荷長度 / 參數5:發布Qos / 參數6:Retain】 //----------------------------------------------------------------------------------------------------------------------------------------- // MQTT_Publish(client, "SW_LED", "ESP8266_Online", strlen("ESP8266_Online"), 0, 0); // 向主題"SW_LED"發布"ESP8266_Online",Qos=0、retain=0 // MQTT_Publish(client, "SW_LED", "ESP8266_Online", strlen("ESP8266_Online"), 1, 0); // MQTT_Publish(client, "SW_LED", "ESP8266_Online", strlen("ESP8266_Online"), 2, 0); } //============================================================================ // MQTT成功斷開連接 //============================================================================ void mqttDisconnectedCb(uint32_t *args) { MQTT_Client* client = (MQTT_Client*)args; INFO("MQTT: Disconnected\r\n"); } //============================================================================ // MQTT成功發布消息 //============================================================================ void mqttPublishedCb(uint32_t *args) { MQTT_Client* client = (MQTT_Client*)args; INFO("MQTT: Published\r\n"); } //============================================================================ // 【接收MQTT的[PUBLISH]數據】函數 【參數1:主題 / 參數2:主題長度 / 參數3:有效載荷 / 參數4:有效載荷長度】 //=============================================================================================================== void mqttDataCb(uint32_t *args, const char* topic, uint32_t topic_len, const char *data, uint32_t data_len) { topicBuf = (char*)os_zalloc(topic_len+1); // 申請【主題】空間 dataBuf = (char*)os_zalloc(data_len+1); // 申請【有效載荷】空間 //dataBuf是從topic訂閱而來的消息,通過與{\"SW_LED\":1}對比去控制繼電器的狀態 MQTT_Client* client = (MQTT_Client*)args; // 獲取MQTT_Client指針 os_memcpy(topicBuf, topic, topic_len); // 緩存主題 topicBuf[topic_len] = 0; // 最后添'\0' os_memcpy(dataBuf, data, data_len); // 緩存有效載荷 dataBuf[data_len] = 0; // 最后添'\0' INFO("Receive topic: %s, data: %s \r\n", topicBuf, dataBuf); // 串口打印【主題】【有效載荷】 //######################################################################################## //注釋掉的原因:無法在串口打印出來 // 【參數2:主題名 / 參數3:發布消息的有效載荷 / 參數4:有效載荷長度 / 參數5:發布Qos / 參數6:Retain】 //MQTT_Publish(client, "$baidu/iot/shadow/TH_ESP8266/update", dataBuf, strlen(dataBuf), 0, 0);// 向主題"$baidu/iot/general/a"發布"dataBuf",Qos=0、retain=0 //os_printf("\r\n------ Shadow_Report_Data:%s -- ",dataBuf); // 上報到物影子的數據 //os_printf("Report_Data_Length:%d ------\r\n\r\n",strlen(dataBuf)); // 上報數據長度 //######################################################################################## // 根據接收到的主題名/有效載荷,控制LED的亮/滅 //----------------------------------------------------------------------------------- if( os_strcmp(topicBuf,"$baidu/iot/general/a") == 0 ) { if( os_strcmp(dataBuf,"{\"SW_LED\":1}") == 0 ) // 有效載荷 == "SW_LED:1" { GPIO_OUTPUT_SET(GPIO_ID_PIN(4),0); // LED滅 led_flag = 0; } else if( os_strcmp(dataBuf,"{\"SW_LED\":0}") == 0 ) // 有效載荷 == "SW_LED;0" { GPIO_OUTPUT_SET(GPIO_ID_PIN(4),1); // LED亮 led_flag = 1; } } //######################################################################################## //必須釋放后,才能再次賦值 os_free(topicBuf); // 釋放【主題】空間 os_free(dataBuf); // 釋放【有效載荷】空間 } //=============================================================================================================== /****************************************************************************** * FunctionName : user_rf_cal_sector_set * Description : SDK只是反轉了4個扇區,用於rf init數據和參數。 * 我們增加這個功能是為了迫使用戶設置rf cal扇區,因為 * 我們不知道用戶的應用中哪個扇區是免費的。 * 最后幾個扇區的扇區圖 : ABCCC * A : rf cal * B : rf init data * C : sdk parameters * Parameters參數 : none * Returns 返回值 : rf cal sector *******************************************************************************/ uint32 ICACHE_FLASH_ATTR user_rf_cal_sector_set(void) { enum flash_size_map size_map = system_get_flash_size_map(); uint32 rf_cal_sec = 0; switch (size_map) { case FLASH_SIZE_4M_MAP_256_256: rf_cal_sec = 128 - 5; break; case FLASH_SIZE_8M_MAP_512_512: rf_cal_sec = 256 - 5; break; case FLASH_SIZE_16M_MAP_512_512: case FLASH_SIZE_16M_MAP_1024_1024: rf_cal_sec = 512 - 5; break; case FLASH_SIZE_32M_MAP_512_512: case FLASH_SIZE_32M_MAP_1024_1024: rf_cal_sec = 1024 - 5; break; case FLASH_SIZE_64M_MAP_1024_1024: rf_cal_sec = 2048 - 5; break; case FLASH_SIZE_128M_MAP_1024_1024: rf_cal_sec = 4096 - 5; break; default: rf_cal_sec = 0; break; } return rf_cal_sec; } // user_init:進入用戶應用程序,在這里初始化用戶函數 //=================================================================================================================== void user_init(void) { uart_init(BIT_RATE_115200, BIT_RATE_115200); // 串口波特率設為115200 os_delay_us(60000); //########################################################################### PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO4_U, FUNC_GPIO4); // GPIO4輸出高 # GPIO_OUTPUT_SET(GPIO_ID_PIN(4),1); // LED初始化 # //########################################################################### CFG_Load(); // 加載/更新系統參數【WIFI參數、MQTT參數】 // 網絡連接參數賦值:服務端域名【mqtt_test_jx.mqtt.iot.gz.baidubce.com】、網絡連接端口【1883】、安全類型【0:NO_TLS】 //------------------------------------------------------------------------------------------------------------------- MQTT_InitConnection(&mqttClient, sysCfg.mqtt_host, sysCfg.mqtt_port, sysCfg.security); // MQTT連接參數賦值:客戶端標識符【..】、MQTT用戶名【..】、MQTT密鑰【..】、保持連接時長【120s】、清除會話【1:clean_session】 //---------------------------------------------------------------------------------------------------------------------------- MQTT_InitClient(&mqttClient, sysCfg.device_id, sysCfg.mqtt_user, sysCfg.mqtt_pass, sysCfg.mqtt_keepalive, 1); // 設置遺囑參數(如果雲端沒有對應的遺囑主題,則MQTT連接會被拒絕) //-------------------------------------------------------------- // MQTT_InitLWT(&mqttClient, "Will", "ESP8266_offline", 0, 0); // 設置MQTT相關函數 //-------------------------------------------------------------------------------------------------- MQTT_OnConnected(&mqttClient, mqttConnectedCb); // 設置【MQTT成功連接】函數的另一種調用方式 MQTT_OnDisconnected(&mqttClient, mqttDisconnectedCb); // 設置【MQTT成功斷開】函數的另一種調用方式 MQTT_OnPublished(&mqttClient, mqttPublishedCb); // 設置【MQTT成功發布】函數的另一種調用方式 MQTT_OnData(&mqttClient, mqttDataCb); // 設置【接收MQTT數據】函數的另一種調用方式 // 連接WIFI:SSID[..]、PASSWORD[..]、WIFI連接成功函數[wifiConnectCb] //-------------------------------------------------------------------------- WIFI_Connect(sysCfg.sta_ssid, sysCfg.sta_pwd, wifiConnectCb); // OLED顯示初始化 //-------------------------------------------------------- OLED_Init(); // OLED初始化 OLED_ShowString(0,0,"Humidity:"); // 濕度 OLED_ShowString(0,4,"Temperature:"); // 溫度 //-------------------------------------------------------- OS_Timer_1_Init_JX(3000,1); // 3秒定時(重復) INFO("\r\nSystem started ...\r\n"); } //===================================================================================================================
其他代碼我會盡快上傳的,另外這個項目需要對topic的訂閱和發布必須得非常熟悉。
建議購買【技小新】的物聯網開發板學習,但只能作為入門,雖然我也才入門.......
注意:SDK要使用技小新視頻里面的版本,如果找不到視頻中的版本,可以輸入視頻中的網址。
物聯網開發板的購買鏈接:https://item.taobao.com/item.htm?spm=a1z09.2.0.0.15e92e8deWtUFD&id=623696943330&_u=c2d1kccp1c25或者https://detail.tmall.com/item.htm?spm=a230r.1.14.16.2e2b1de7koSLxu&id=603272487818&ns=1&abbucket=12(類似於這種40多塊的,可以到技小新旗艦店看看)