盧于輝,秦會斌
(杭州電子科技大學新型電子器件與材料研究所,浙江杭州310018)
結(jié)合物聯(lián)網(wǎng)技術(shù)與嵌入式技術(shù),可以將家庭中的各種設(shè)備通過APP進行無線控制,實現(xiàn)家居智能化[1]。因此設(shè)計一款低成本、高可靠、使用簡便、用戶體驗高的智能家居系統(tǒng)具有很重要的意義。傳統(tǒng)的智能化家居系統(tǒng)一旦手機綁定成功,解綁過程比較復(fù)雜,需要手機端和硬件端同時操作才能解綁,也不能根據(jù)用戶需求動態(tài)地添加、刪除設(shè)備,使得用戶體驗和系統(tǒng)通用性都比較差[2]。
針對傳統(tǒng)智能家居出現(xiàn)的問題,本文提出并設(shè)計了基于MQTT控制的智能家居系統(tǒng),可以動態(tài)添加、刪除設(shè)備及實現(xiàn)對設(shè)備的近遠場控制,同時在設(shè)備端增加一鍵刪除功能,手機端和硬件端都可同時刪除設(shè)備信息。系統(tǒng)通過ESP8266 WIFI模塊直接控制家居,不需要額外的MCU,大大減少了成本和體積[3][4]。由于MQTT協(xié)議精簡、易于實現(xiàn),在控制功耗和節(jié)約帶寬上表現(xiàn)出很好的性能[5-7],系統(tǒng)采用MQTT協(xié)議進行消息推送。在內(nèi)網(wǎng)通過基于UDP的SmartConfig等實現(xiàn)了用戶的個人信息管理、設(shè)備的個人配網(wǎng)綁定,并且無論在內(nèi)網(wǎng)還是外網(wǎng)都可以隨時隨地控制家居設(shè)備。
MQTT協(xié)議最早由IBM公司在1999年提出,是ISO標準(ISO/IEC PRF 20922)下基于發(fā)布/訂閱范式的消息協(xié)議。該協(xié)議工作在TCP/IP協(xié)議族上,屬于為硬件性能低下的遠程設(shè)備以及網(wǎng)絡(luò)狀況糟糕的情況設(shè)計的發(fā)布/訂閱型消息協(xié)議。同CoAP、HTTP等其他協(xié)議相比,具有以下優(yōu)勢:
(1)每消息的標題可以短至2個字節(jié)。同時,對于HTTP,為每個新請求消息重新建立HTTP連接會導(dǎo)致重大的開銷,而MQTT所使用的永久連接顯著減少了這一開銷。
(2)能夠從斷開等故障中恢復(fù),而且沒有進一步的代碼需求。相反,HTTP無法原生地實現(xiàn)此目的,需要客戶端重試編碼,這可能增加冪等性問題。
(3)專門針對低功耗目標而設(shè)計。HTTP的設(shè)計沒有考慮此因素,功耗較高。
(4)HTTP堆棧上,維護數(shù)百萬個并發(fā)連接需要做大量工作來提供支持,而且大多數(shù)商業(yè)產(chǎn)品都需要為處理這一數(shù)量級的永久連接而進行優(yōu)化。IBM提供了IBM MessageSight單機架裝載服務(wù)器,經(jīng)過測試能處理多達100萬個通過MQTT并發(fā)連接的設(shè)備。
MQTT以上的優(yōu)勢再加上其完全開源,國內(nèi)外的許多云供應(yīng)商如騰訊、阿里、百度以及Azure、AWS、Bluemix均有對MQTT的支持,已經(jīng)形成了較好的生態(tài)圈。所以,MQTT應(yīng)用在智能家居中較為方便。
智能家居系統(tǒng)總體可分為4部分:基于Android平臺的客戶端、云服務(wù)器、WIFI模塊、智能家居設(shè)備。系統(tǒng)總體框架如圖1所示。
圖1中WIFI模塊通過發(fā)送心跳包和云服務(wù)器維持長連接,主動上報設(shè)備狀態(tài),用戶通過Android客戶端登錄家居控制APP配置網(wǎng)絡(luò),WIFI模塊通過UDP廣播獲取連接WIFI所需要的用戶名和密碼,連上WIFI,此時設(shè)備和客戶端處于同一網(wǎng)段內(nèi),Android客戶端可以直接對設(shè)備進行添加、刪除、控制等操作。若客戶端和設(shè)備不在同一網(wǎng)段時,客戶端通過HTTP通信連接到云服務(wù)器,云服務(wù)器將指令經(jīng)過MQTT推送機制轉(zhuǎn)發(fā)給WIFI模塊,從而控制設(shè)備。系統(tǒng)通過內(nèi)網(wǎng)和外網(wǎng)相結(jié)合的方式控制設(shè)備,有效解決了內(nèi)網(wǎng)不可用時不能控制設(shè)備的問題,確保用戶隨時隨地控制家居設(shè)備。
圖1 系統(tǒng)總體框架
本系統(tǒng)的WIFI模塊選用ESP8266,該模塊是2015年推出的WIFI芯片,主要由網(wǎng)路模塊、控制模塊和微處理器模塊三部分組成[8]。其電路如圖2所示。
硬件部分采用ESP8266 WIFI模塊,完成相關(guān)功能需要對其固件進行編程,主要的設(shè)計思路如下:
首先讓ESP8266進入混雜模式,進而進入SmartConfig模式,在SmartConfig的模式下,通過UDP廣播獲取連接WIFI所需要的用戶名和密碼,同時還要獲取與之相配對的手機號碼,該號碼用于告訴云端服務(wù)器ESP8266與哪部手機配對。代碼和注釋如下:
case SC_STATUS_FIND_CHANNEL://開始掃描信道
caseSC_STATUS_GETTING_SSID_PSWD://獲取配置模式是微信的AirKiss還是SmartConfig
圖2 ESP8266模塊電路圖
case SC_STATUS_LINK://此狀態(tài)可以得到WIFI的用戶名和密碼
接著根據(jù)MQTT協(xié)議來搭建MQTT客戶端,其過程如下:
(1)與MQTT服務(wù)器建立TCP連接。
(2)根據(jù)MQTT協(xié)議進行連接、訂閱、設(shè)置心跳包等操作,考慮到綁定過程的唯一性,其訂閱內(nèi)容是ESP8266的mac地址。
搭建完MQTT的客戶端后,需要搭建另一個客戶端,可以與云端服務(wù)器進行通信,其過程如下:
(1)與云端服務(wù)器建立TCP連接。
(2)通過HTTP的post請求來上傳設(shè)備信息到云端服務(wù)器中。
代碼和注釋如下:
os_sprintf(databuf,"telphone=%s&type=3&mac="MACSTR"&name=fan&status=0&data1=2&data2=%d&data3=0",telnum,MAC2STR(mac_addr),turnonoff);
//將要傳的數(shù)據(jù)通過字符串的形式給databuf
os_sprintf(buf,"POST/suibian/mqtt/desend.action HTTP/1.1 Host:主機地址 User-Agent:ESP8266 Content-Length:%d Cache-Control:no-cache Content-type:application/x-www-formurlencoded %s",os_strlen(databuf),databuf);
//根據(jù)HTTP中的post請求模式,將字符串傳遞給buf
InterNet_TCP_SendData(buf,0,pCon);
//通過TCP發(fā)送請求
智能家居設(shè)備有多種,這里以控制單燈和風扇為例,其他設(shè)備類似。
2.2.1 對單燈的控制
主要通過PWM實現(xiàn)對單燈亮度的控制,ESP8266的PWM波產(chǎn)生方式有兩種,一種是調(diào)用內(nèi)部的API函數(shù),這種方式產(chǎn)生的PWM波具有較高的調(diào)節(jié)精度,但缺點是這種精度的調(diào)節(jié)主要靠后面的窄波,也就是說每個PWM波周期都具有一小段窄波,所以該模式下PWM波的占空比達不到100%。另一種是通過定時器進行軟件編程來產(chǎn)生PWM波,該模式下PWM波的占空比可以達到100%,但調(diào)節(jié)精度要低很多。由于我們所控制的小燈采用的是上拉模式(必須保證占空比100%),其調(diào)節(jié)精度不需要那么細致,所以采用第二種方法比較合理。
2.2.2 對電機的控制
主要利用PWM波來實現(xiàn)對電機速度的控制。由于ESP8266引腳所產(chǎn)生的PWM波無法驅(qū)動電機的轉(zhuǎn)動,故增加L298N驅(qū)動模塊來驅(qū)動電機,同時還增加兩個控制引腳來控制電機的正轉(zhuǎn)和反轉(zhuǎn)。以下是PWM轉(zhuǎn)速調(diào)整程序:
voidpwm_check_high(void*arg){os_timer_setfn(&PWMTimer_ALL,(os_timer_func_t*)pwm_check_high,NULL);//進行下一次定時
os_timer_arm_us(&PWMTimer_ALL,1000,0);
//周期為1000us
if(HIGH_LOW==1000)
//HIGH_LOW表示高電平的時間,若為1000全高
{gpio_output_set(BIT12,0,BIT12,0);
os_timer_disarm(&PWMTimer_HIGH);}
else if(HIGH_LOW==0)//全為低電平時
{gpio_output_set(0,BIT12,BIT12,0);
os_timer_disarm(&PWMTimer_HIGH);}
else{//0到1000之間
gpio_output_set(BIT12,0,BIT12,0);
os_timer_setfn(&PWMTimer_HIGH,pwm_check_low,NULL);
//從HIGH_LOW時間后開始輸出低電平
os_timer_arm_us(&PWMTimer_HIGH,HIGH_LOW,0);}}
2.2.3 一鍵式解綁的實現(xiàn)
當WiFi模塊采集到一段時間的低電平時,觸發(fā)解綁過程,該過程步驟如下:
馬上斷開HTTP,斷開MQTT,斷開WIFI,清除flash內(nèi)所綁定的電話號碼記錄,清除WIFI的用戶名和密碼,進入SmartConfig模式。
基于Android的控制客戶端主要實現(xiàn)用戶個人信息管理、設(shè)備信息管理、設(shè)備配網(wǎng)連接和設(shè)備的遠場控制,如圖3所示。
圖3 客戶端功能模塊
(1)用戶信息管理。手機客戶端使用用戶手機號碼或者QQ、微信、微博等第三方賬號進行注冊登錄,登錄成功的用戶可以在個人中心管理界面查看和修改個人信息。
(2)設(shè)備信息管理。系統(tǒng)暫時采用一對多原則,即一個用戶可以擁有多臺設(shè)備,但一個設(shè)備只能歸屬一個用戶。成功添加設(shè)備后,用戶可以在設(shè)備列表界面對設(shè)備進行增、刪、改、查、分享等一系列操作,應(yīng)用會自動在云平臺服務(wù)器對設(shè)備的操作進行同步。其中設(shè)備的內(nèi)部信息需要進入控制界面才能進行相應(yīng)的更改。
(3)設(shè)備配網(wǎng)連接。使用ESP官網(wǎng)提供的ESP8266無線WIFI模塊,通過基于UDP的SmartConfig協(xié)議,當設(shè)備和客戶端處于同一個局域網(wǎng)時,通過UDP廣播將自身連接的WIFI屬性傳遞給ESP8266無線WIFI模塊,模塊成功連接上網(wǎng)絡(luò)便自動完成與用戶賬號的綁定,即設(shè)備連接成功。
(4)遠近場設(shè)備控制。設(shè)備的配網(wǎng)必須在同一個局域網(wǎng)之下,但設(shè)備的控制沒有網(wǎng)絡(luò)的限制,設(shè)備成功添加到用戶設(shè)備列表后,點擊設(shè)備,通過相應(yīng)的控制和觸發(fā)按扭即可完成對設(shè)備的控制,應(yīng)用集成了多個控制APP,可以對不同的設(shè)備進行專一性控制。
客戶端采用MVC架構(gòu),將應(yīng)用的界面顯示、邏輯控制和業(yè)務(wù)處理分離,降低應(yīng)用的耦合性,增加程序運行的健壯性[9][10],同時方便后期的運行維護。應(yīng)用中使用的框架有異步網(wǎng)絡(luò)請求框架、基于UDP的SmartConfig框架、LiteOrm輕量級數(shù)據(jù)庫框架、ShareSDK的三方登錄或分享框架以及強大的谷歌MD設(shè)計框架。移動端控制設(shè)備使用Volley請求框架,可以有效預(yù)防用戶頻繁操作,防止網(wǎng)絡(luò)請求頻繁操作而出現(xiàn)網(wǎng)絡(luò)故障。
系統(tǒng)采用基于UDP協(xié)議的SmartConfig通信和基于TCP的HTTP通信。通信模塊設(shè)備配網(wǎng)連接流程如圖4所示。
圖4 通信模塊設(shè)備配網(wǎng)連接流程圖
新用戶注冊并且登錄成功后,設(shè)備列表的設(shè)備數(shù)量為0,需要用戶通過SmartConfig將手機連接的有效WIFI信息配置給設(shè)備連接網(wǎng)絡(luò),最終完成用戶與設(shè)備的綁定。系統(tǒng)中其他的訪問都是基于TCP的HTTP通信的短連接,除控制命令外,訪問外端需要攜帶用戶基本信息,向服務(wù)器發(fā)送驗證,驗證通過才能完成相應(yīng)的操作,否則視為違規(guī)操作,需要用戶重新登陸完成身份的驗證,以確保用戶和設(shè)備信息安全。
3.3.1 UDP通信
客戶端通過UDP通信發(fā)送WIFI的SSID和密碼到ESP8266WIFI模塊,進行SmartConfig配對,成功則讓模塊連接上網(wǎng)。
//獲取輸入文本
String ssid=etName.getText().toString();
String passwrod=App.getInstance().getUser().getUsername()+etPwd.getText().toString();
boolean isSsidHidden=cbSsid.isChecked();
if(ssid==null||TextUtils.isEmpty(etPwd.get-Text())){
Toast.makeText(this,"請先連接路由器",Toast.LENGTH_SHORT).show();return;}
//本地保存數(shù)據(jù)
share.edit().putString(ssid,passwrod).commit();
//啟動異步任務(wù)開啟SmartConfig
new ConfigNetWork(this,ssid,bssid,passwrod,isSsidHidden).execute();
3.3.2 HTTP通信
應(yīng)用中主要采用了兩類HTTP通信,一類是常規(guī)HTTP請求,另一類是基于Volley的HTTP網(wǎng)絡(luò)訪問。不涉及頻繁操作并且需要對身份進行驗證的訪問采用的是常規(guī)HTTP。但對設(shè)備的控制采用的是基于Volley的網(wǎng)絡(luò)訪問。Volley小數(shù)據(jù)量和請求隊列等優(yōu)點保證了用戶的每次操作能得到正確的結(jié)果,同時也可以預(yù)防因用戶頻繁控制而導(dǎo)致的網(wǎng)絡(luò)延遲。
RequestParams params=new RequestParams();
params.put("token",App.getInstance().getToken());
params.put("telphone",tel);
params.put("mac",mac);
httpclient.post(Const.MAIN+Const.QUERY_SINGLE_DEVICE,params,new AsyncHttpResponse-Handler());
//攜帶token查詢單個設(shè)備
云平臺由應(yīng)用服務(wù)器、MQTT消息推送服務(wù)器和數(shù)據(jù)庫服務(wù)器組成,應(yīng)用服務(wù)器主要處理用戶登錄、注冊、設(shè)備查詢等業(yè)務(wù)邏輯問題,MQTT消息推送服務(wù)器主要負責移動客戶端控制設(shè)備的命令推送以及設(shè)備上線后將設(shè)備信息的推送,云平臺的架構(gòu)如圖5所示。
圖5 云平臺的架構(gòu)
由于JAVA開發(fā)效率高、性能穩(wěn)定且跨平臺,應(yīng)用服務(wù)器后臺采用JAVA編寫,使用Spring+SpringMVC+Mybatis框架,用戶和服務(wù)器的交互使用Md5Hash算法進行加密,確保用戶信息的安全。加密代碼如下:
Public static String md5(String password,String salt){return new Md5Hash(password,salt,2).toString();}//高強度加密算法,不可逆。
圖6 MQTT消息推送服務(wù)器發(fā)布訂閱模式
MQTT發(fā)布/訂閱模式如圖6所示。系統(tǒng)中使用MQTT推送協(xié)議完成設(shè)備與用戶的綁定以及用戶控制設(shè)備命令的傳達。在CentOS系統(tǒng)的服務(wù)器上安裝Mosquitto,通過訂閱和發(fā)布來管理所有主題,客戶端和設(shè)備都可以指定主題(topic)發(fā)布消息,服務(wù)器代理接收,并將消息轉(zhuǎn)發(fā),當有訂閱者訂閱操作時,根據(jù)主題獲取發(fā)布的內(nèi)容。客戶端向設(shè)備發(fā)送控制指令流程如圖7所示。
代碼和注解如下:
public void SendControlCmd(final String cmd,final String mac){
//手機客戶端依據(jù)mac向服務(wù)器發(fā)送設(shè)備控制命令
Stringurl="http://106.14.9.111:8080/suibian/mqtt/send.action";//服務(wù)器請求地址
int method=Request.Method.POST;
Map
//傳遞控制參數(shù)
params.put("data",cmd);
params.put("topic",mac);
return params;
//服務(wù)器將其轉(zhuǎn)發(fā)到MQTT代理服務(wù)器
Message
//發(fā)布主題和內(nèi)容
mqtt.handleMessage(message);//提交
圖7 客戶端向設(shè)備發(fā)送控制指令流程
數(shù)據(jù)庫使用MySQL和Redis,使用Redis作為MySQL的緩存數(shù)據(jù)庫,減小了MySQL的壓力。用戶第一次登陸,服務(wù)器驗證成功后,會簽發(fā)一個Token,并將Token攜帶的信息存放在Redis里,同時將Token發(fā)送給客戶端,客戶端收到Token以后將其存放在Cookie里??蛻舳嗣看卧L問服務(wù)器都會帶著Token,服務(wù)器接收到請求后,會去Redis服務(wù)器驗證Token,如果驗證成功,將相關(guān)信息返回給客戶端。
用戶通過客戶端登錄后,能夠根據(jù)用戶需要動態(tài)添加家居設(shè)備、管理用戶信息,管理WIFI模塊下的設(shè)備,以及對家居設(shè)備進行控制。本測試選用燈和空調(diào)作為家居設(shè)備,首先通過手機客戶端配網(wǎng)連接,WIFI模塊通過UDP廣播來獲取連接WIFI所需要的用戶名和密碼,連接上網(wǎng)絡(luò);手機客戶端添加設(shè)備(燈和空調(diào)),對燈進行打開、關(guān)閉、調(diào)節(jié)亮度操作,對空調(diào)進行打開、關(guān)閉、調(diào)溫、調(diào)風速操作,實時控制家居設(shè)備。設(shè)備控制視圖如圖8所示。
圖8 設(shè)備控制視圖
手機客戶端和硬件端都可以解綁,長按硬件端按鈕,手機和硬件端同時刪除設(shè)備信息,快速解綁。
本文設(shè)計并實現(xiàn)了基于MQTT的智能家居系統(tǒng),選用ESP8266WIFI模塊進行通信和控制,成本低、體積小;采用MQTT推送機制,速度快、實時性好,通過內(nèi)外網(wǎng)配合的方式通信,時效性高;一鍵式清除設(shè)備,使綁定和解綁過程更加直觀和方便。本系統(tǒng)能夠動態(tài)添加和控制設(shè)備,實現(xiàn)對家居設(shè)備隨時隨地控制。