1. 程式人生 > 實用技巧 >基於物聯網的智慧開關係統設計

基於物聯網的智慧開關係統設計

記錄一下,自己的第一個專案,雖然很簡單,但也瞭解了關於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的訂閱和釋出必須得非常熟悉。

建議購買【技小新】的物聯網開發板學習,但只能作為入門,雖然我也才入門.......

物聯網開發板的購買連結:https://detail.tmall.com/item.htm?spm=a230r.1.14.16.353165e9rELAwD&id=621916769804&ns=1&abbucket=12(類似於這種40多塊的,可以到技小新旗艦店看看)