采用Zigbee和Raspberry Pi的太阳能/燃气热水器自动控制系统
家在頂樓,想著利用太陽能,就安裝了太陽能熱水器,但畢竟遇上刮風下雨,靠天吃飯不靠譜,太陽能熱水器雖然也有電熱功能,但水用完了加熱等待時間太長,所以也安裝了天然氣熱水器。
大致的管路示意圖如下:
但這樣使用時就稍顯麻煩,因為燃氣熱水器這邊直接承受自來水水壓,壓力較大,如果兩邊的閥門同時打開,水就會從太陽能熱水器的熱水管逆向流動,給太陽能熱水器反向上水,直至熱水器水箱裝滿溢出也不會停止,因此,兩邊的閥門不能同時開啟。曾經(jīng)嘗試在太陽能這邊安裝止逆閥,但效果不佳,止逆閥無法完全密封,只是稍微延緩溢出的時間而已。
我家的燃氣熱水器還有個特點,因為裝在露臺,是室外機型,待機15分鐘就會自動關(guān)閉,此時打開水,熱水器不會自動點火,必須按動控制器上的開關(guān)打開熱水器,才會響應用水請求點火。而且更麻煩的是,每次開機后,之前設定的水溫又會自動回到40°,而洗澡水溫通常要設定到60°,浴室里的水溫水壓感覺才最合適,意味著每次開機都要重新設定水溫。
燃氣熱水器在露臺,而太陽能熱水器的控制器又在洗手間,和露臺隔著一個大客廳。
綜上可見,每次用熱水之前,這個過程之麻煩:
1. 到洗手間查看太陽能熱水器的水溫和水位;
2. a) 如果太陽能的熱水合用,則:
2. a) i) 打開太陽能的熱水出水閥;
2. a) ii) 跑去露臺關(guān)閉燃氣熱水器的進水閥;
2. b) 如果太陽能這邊熱水不可用,則:
2. b) i) 關(guān)閉太陽能出水閥;
2. b) ii) 跑去露臺打開燃氣熱水器的開關(guān);
2. b) iii) 重新設定水溫;
2. b) iv) 擰開燃氣熱水器進水閥。
自己使用習慣了,也就罷了,每次家里來了客人,要洗澡什么的,都得鞍前馬后伺候著,因為實在不覺得客人能在短時間之內(nèi)搞清楚這么復雜的邏輯,直接放棄解釋,親自服務吧。
作為一個Diyer,實在無法忍受這種情況,終于決定要用科技解決這個問題。
方案
決心是下了,大致方向是用單片機采集太陽能的水位水溫,并監(jiān)測太陽能和燃氣的用水狀態(tài),動態(tài)控制兩邊的閥門和燃氣的開關(guān)以及溫度設置,但具體采用什么方案解決這個問題呢?
因為設備分布在幾個不同的地方,肯定需要無線組網(wǎng),之前Wifi、藍牙接觸較多,但感覺太重量級了。聽說過Zigbee,但還從來沒用過,調(diào)查了一下,作為家庭內(nèi)部的智能設備組網(wǎng),確實比藍牙和Wifi都合適,于是初步設計系統(tǒng)架構(gòu)如下:
如上圖所示,系統(tǒng)主要由4個Zigbee設備和一個Raspberry Pi樹莓派組成。
Zigbee Device 1利用自動增壓泵上的自動開關(guān)監(jiān)測太陽能熱水器的用水狀態(tài),并上傳至Coordinator;同時還負責控制太陽能熱水器的出水閥門。
Zigbee Device 2負責監(jiān)測太陽能熱水器的水位和水溫,并上傳至Coordinator。
Coordinator作為Zigbee系統(tǒng)的核心,負責組網(wǎng)的同時,接收Zigbee Device 1、2傳來的太陽能熱水器的各種數(shù)據(jù),自身對燃氣熱水器的開關(guān)狀態(tài)、使用狀態(tài)進行監(jiān)測,并根據(jù)水溫條件,自行對燃氣熱水器和太陽能熱水器的工作狀態(tài)進行控制。同時,Coordinator上還有按鈕,支持手動切換太陽能和燃氣熱水器的工作狀態(tài)。
以上三個組件為系統(tǒng)工作的核心組件,缺一不可,下面則為可選組件。
Zigbee device 3和樹莓派組成了本系統(tǒng)的網(wǎng)關(guān)和遠程控制終端。Device 3和Coordinator通過Zigbee協(xié)議進行通信,并利用串口將各種狀態(tài)和命令與樹莓派進行通訊,樹莓派作為上位機,既可以利用觸摸屏通過QT界面對本系統(tǒng)進行控制,也可以接入家中的Wifi,從而接入Internet,利用手機對本系統(tǒng)進行遠程監(jiān)控操作。
系統(tǒng)架構(gòu)確定了,就開始著手實施,因為這是第一次接觸Zigbee,是一個全新的學習過程,故而通過這篇文章記錄之。
設計與實現(xiàn)
首先在萬能的淘寶上買了四個CC2530的Zigbee模塊和仿真器
也是托大,想碰碰運氣,就沒有買測試板,結(jié)果回來飛線開機啥都沒有,兩眼一抹黑,也不知道是線接的有問題還是程序有問題,畢竟從來沒搞過這個模塊,完全無從下手,只好老老實實再買一塊測試板回來。
然后再對照著教程燒程序,跑馬燈跑起來了,但串口還是沒輸出,只好對著測試版的電路原理圖,一邊看CC2530芯片手冊,一邊測波形,一步步排查,原來商家提供的教程和參考代碼居然和他們賣的測試板都對不上,教程和參考代碼中用的都是串口0,而他們測試板上USB轉(zhuǎn)串口接的是串口1!nnd坑爹!找到原因了,那就對照芯片手冊一步步改吧,終于串口有輸出了,這才意味著開發(fā)過程中可以進行調(diào)試、而不是盲人摸象了。
然后參考教程,從流水燈開始,按鍵、DMA、ADC、透傳……感覺能用得上的實驗都做了一遍,覺得Zigbee模塊基本功能摸得差不多了,可以開始正式進行系統(tǒng)實現(xiàn)了。
當然,當中串口又有個坑:之前調(diào)的是裸機程序,上了透傳后ZStack中的串口配置又不對了,又是一頓好找,跟著整個流程從配置文件、端口到DMA設置改了個遍,好容易HalUARTWrite(1, “ABC”,? 3)看到有輸出了,這才終于松了口氣。
應用框架
要開發(fā),自然得先搭軟件應用層框架。
TI的Zigbee當然是基于ZStack,但即便ZStack中,也分了好多層,從AF、ZDO到ZCL等,其實這個小系統(tǒng),直接基于AF層搞透傳就好了,但畢竟是第一次搞Zigbee,想弄的深入一些,把那些什么profile、device、cluster、endpoint的概念徹底搞清楚,不然看了半天還是云里霧里。因此,這個系統(tǒng)的實現(xiàn)中很多地方應該是有點過度設計了,有點大炮打蚊子的感覺;有的地方甚至是畫蛇添足,完全只是為了驗證知識點。
為了實現(xiàn)設備間的雙向通信,系統(tǒng)中采用了三種辦法:
定時發(fā)送Report,主要用于水位水溫等狀態(tài)數(shù)據(jù)的定時采集;
發(fā)送ZCL Command,主要用于執(zhí)行開關(guān)等動作;
讀寫ZCL Attribute,主要用于一些控制量的設置或讀取;
另外,為了便于后期調(diào)試,Coordinator也利用了AF層進行透傳,把一些調(diào)試信息發(fā)到網(wǎng)關(guān)(Device 3)。
要能通信,首先是設備定義。
Zigbee設備之間進行通信,需要幾個值匹配:ProfileId,ClusterId,AttributeId。
ProfileId范圍最大,是應用所屬范圍,例如0x0104是智能家居,0x0101是工業(yè)自動化;
ClusterId是對設備具體屬性的分類,例如0x0005是場景類,0x0006是開關(guān)類;
AttributeId則是具體可操作的屬性,定義可見zcl_general.h。例如:
#define ATTRID_SCENES_COUNT 0x0000
#define ATTRID_SCENES_CURRENT_SCENE 0x0001
#define ATTRID_SCENES_CURRENT_GROUP 0x0002
就是場景類下的一些屬性定義。
此外,還有一個DeviceId,它定義了設備自身的類型,例如0x0001是可以控制擋位的開關(guān),0x0002只有開/關(guān)動作的開關(guān),0x0100是燈,0x0303是泵等等;但DeviceId只在邏輯上供應用層使用,并不是協(xié)議中達成通信的的必要條件,例如開關(guān)可以控制任何燈、水泵、空調(diào),所以任意兩種DeviceId的設備之間都可以進行通信,不形成任何約束。而服務請求/綁定/通信時的ProfileId,ClusterId,AttributeId必須一致。
還有人會說還有個Endpoint呢,Endpoint就只是一個數(shù)字而已,就好像你去別人家串門,總要知道別人家的門牌號碼,但這個號碼究竟是幾,其實無所謂。也有點類似TCP/IP中的端口號,7777還是8888,無所謂,關(guān)鍵是你知道是幾就好。如果不知道呢?那就用服務請求或綁定去找了。
既然是設備定義,那么要根據(jù)功能整理出一堆需要操作的變量,例如設備的開關(guān)、太陽能的水溫等,定義出相應的的Attributes:
{
ZCL_CLUSTER_ID_GEN_ON_OFF,
{ // Attribute record
ATTRID_ON_OFF,
ZCL_DATATYPE_BOOLEAN,
ACCESS_CONTROL_READ,
(void *)&zclWATERSWITCH_OnOff
}
},
{
ZCL_CLUSTER_ID_MS_TEMPERATURE_MEASUREMENT,
{ // Attribute record
ATTRID_MS_TEMPERATURE_MEASURED_VALUE,
ZCL_DATATYPE_UINT16,
ACCESS_CONTROL_READ,
(void *)&zclWATERSWITCH_Temp
}
},
這里的CLUSTER_ID和ATTRID都是Zigbee規(guī)范中定義的(可以參見Profile Id定義和Cluster Id定義),當然也可以自定義,如果是標準的智能家居,當然要按規(guī)范來。前面提到的三種通信辦法,其實質(zhì)都是根據(jù)CLUSTER_ID和ATTRID對相應的值進行操作。
然后是列出各設備需要輸入輸出的Cluster,兩個設備的輸入/輸出Cluster中至少要有一個是互補匹配的,即A設備的輸出Cluster正好是B設備的輸入Cluster,才能在service discovery的綁定過程中匹配成功:
cId_t zclWATERSWITCH_OutClusterList[ZCLWATERSWITCH_MAX_OUTCLUSTERS] =
{
ZCL_CLUSTER_ID_MS_TEMPERATURE_MEASUREMENT,
ZCL_CLUSTER_ID_MS_OCCUPANCY_SENSING,
ZCL_CLUSTER_ID_MS_FLOW_MEASUREMENT
};
設備的基本信息定義好后,接下來就是響應ZDO_STATE_CHANGE事件,該事件對Coordinator意味著網(wǎng)絡已準備好,對從設備則意味著已加入網(wǎng)絡。
Coordinator在這個事件中通過afSetMatch(WaterSwitch_epDesc.EndPoint, TRUE)允許各device來對其進行綁定。
各從設備則在該事件中通過
dstAddr.addrMode = AddrBroadcast;
dstAddr.addr.shortAddr = NWK_BROADCAST_SHORTADDR;
ZDP_MatchDescReq( &dstAddr, NWK_BROADCAST_SHORTADDR,
WATERSWITCH_PROFID,
ZCLWATERSWITCH_MAX_OUTCLUSTERS, zclWATERSWITCH_OutClusterList, // Server’s input is my output
ZCLWATERSWITCH_MAX_INCLUSTERS, zclWATERSWITCH_InClusterList,
TRUE );
來對Coordinator進行service進行發(fā)現(xiàn)和綁定,需要注意的是如果去看ZDP_MatchDescReq的方法定義,和傳遞的cluser參數(shù)的in/out是反的。正如前面這段代碼的注釋以及前一段說明所解釋的,綁定時的cluster是互補的,server的in正好是本設備的out,反之亦然,所以這里提供的參數(shù)是反的。
如果能匹配上,子設備會收到ZDO_CB_MSG事件下的Match_Desc_rsp消息,可以通過ZDO_ParseEPListRsp解析匹配的端點信息。
比較麻煩的是因為這里需要實現(xiàn)雙向通訊,而現(xiàn)在Coordinator還不知道子設備的信息,無法向子設備發(fā)送指令。
在Coordinator響應子設備發(fā)送的綁定請求時,會產(chǎn)生一個ZDO_MATCH_DESC_RSP_SENT事件,我們在該事件中可以獲得子設備的地址并調(diào)用ZDP_ActiveEPReq(&dstAddr, bindAddr, TRUE)來枚舉子設備的活動端點。
枚舉會返回ZDO_CB_MSG事件下的Active_EP_rsp消息,在該消息中,我們還是通過ZDO_ParseEPListRsp( inMsg )解析出目標設備的所有活動端點;對得到的每個端點號,我們再通過ZDP_SimpleDescReq(&dstAddr, pRsp->nwkAddr, pRsp->epList[i], TRUE)來獲得該端點的簡單描述符。
該請求返回的是ZDO_CB_MSG事件下Simple_Desc_rsp消息,在該消息中,我們終于可以獲得目標設備某個端點的簡單描述符。
如果我們給端點定義了合適的描述符,例如:
#define WATERSWITCH_DEVICEID? ? ? ? ? ? ? ?ZCL_HA_DEVICEID_PUMP
SimpleDescriptionFormat_t WaterSwitch_epDesc =
{
WATERSWITCH_ENDPOINT, // int Endpoint;
WATERSWITCH_PROFID, // uint16 AppProfId[2];
WATERSWITCH_DEVICEID, // uint16 AppDeviceId[2];
WATERSWITCH_DEVICE_VERSION, // int AppDevVer:4;
WATERSWITCH_FLAGS, // int AppFlags:4;
ZCLWATERSWITCH_MAX_INCLUSTERS, // byte AppNumInClusters;
(cId_t *)zclWATERSWITCH_InClusterList, // byte *pAppInClusterList;
ZCLWATERSWITCH_MAX_OUTCLUSTERS, // byte AppNumInClusters;
(cId_t *)zclWATERSWITCH_OutClusterList // byte *pAppInClusterList;
};
那么Coordinator就能通過端點描述符中的deviceId(上例中為ZCL_HA_DEVICEID_PUMP,也是ZCL中的標準設備類型)來判斷出該設備的設備類型,從而決定該如何和該設備進行對話。
這個過程比較繁瑣,當然你也可以通過透傳讓子設備給Coordinator隨便發(fā)個什么消息,告訴Coordinator自己是誰,那樣最簡單。但這里采用的是符合ZCL規(guī)范的形式,如前所述,主要在于知識點的驗證。
上面這個服務請求的過程,簡單畫個流程圖如下:
除了這種服務發(fā)現(xiàn)的方式,還有另一種常見的bind request的方式,但感覺那種更適用于兩兩綁定,而不是這里的一對多,故而沒有采用。
現(xiàn)在雙方都有了對方的電話號碼和身份信息,終于可以開始一場轟轟烈烈的戀愛了。
當然Coordinator處于通訊網(wǎng)絡的核心,它是比較花心的。
下面,子設備就可以通過zcl_SendReportCmd把采集到的各種狀態(tài)數(shù)據(jù)發(fā)給Coordinator了,Coordinator通過ZCL_INCOMING_MSG事件下的ZCL_CMD_REPORT消息進行響應,對收到的Report進行解析。
Coordinator也可以通過發(fā)送zclGeneral_SendOnOff_CmdOn、zclGeneral_SendOnOff_CmdOff命令來控制子設備開關(guān)閥門,子設備則在zclGeneral_AppCallbacks_t中注冊對應的zclGCB_OnOff_t回調(diào)函數(shù)來響應命令,完成具體的操作。
網(wǎng)關(guān)(Device 3)則既可以向Coordinator發(fā)送命令,也可以直接讀寫Coordinator暴露出來的Attributes。因為Attributes的定義中指定了值保存的地址,所以這個過程幾乎是全自動的,只要指定目標cluster和attributeId就好。只是在讀Attribute時,需要對讀回來的值進行處理,不然系統(tǒng)怎么知道你拿這個值來干什么。讀的響應事件是ZCL_INCOMING_MSG下的ZCL_CMD_READ_RSP,在里面對值進行解析就是。
這些命令底層都是利用AF_DataRequest對某端口的特定cluster和特定attribute進行操作,萬變不離其宗,看看代碼就好。
對一些特定的命令和動作,例如前面提到的zclGeneral_SendOnOff_CmdOn、zclGeneral_SendOnOff_CmdOff等,ZStack中定義了對應的回調(diào)函數(shù),注冊后可以直接被調(diào)用;如果沒有,那么就根據(jù)MSGpkt->hdr.event和zclIncomingMsg_t *pInMsg->zclHdr.commandID進行判斷處理吧。
再就是串口通信,因為Device 3和樹莓派通信會用到,可以借用MT層的函數(shù)。MT_UartRegisterTaskID(task_id)注冊以后,收到串口數(shù)據(jù)會產(chǎn)生CMD_SERIAL_MSG事件,就可以對串口數(shù)據(jù)進行處理了。MT層要求的串口數(shù)據(jù)格式為:FE + 數(shù)據(jù)長度(不含命令字節(jié)、校驗位等)+ CMD0 + CMD1 + 數(shù)據(jù) + XOR校驗。這樣很好,我的調(diào)試信息和串口數(shù)據(jù)共用一個串口也不會有什么問題了。
至此,應用層基本框架差不多可以動起來了,可以開始著手對具體的設備和數(shù)據(jù)進行操作了。這也是一個路漫漫其修遠的過程。
數(shù)據(jù)采集及控制
先把這一步要做的任務理一遍,找出輕重緩急。
首先來看看我們家有個性的燃氣熱水器,別人家的燃氣熱水器是24小時開水即熱,我們家的是15分鐘就睡過去了還健忘。。。
控制器那四個角是被我拆開卸螺釘?shù)牡胤?#xff0c;翹起來了,回頭還得粘上。。。
針對燃氣熱水器,需要能夠監(jiān)測其是否開啟,用戶是否正在使用熱水;還要能夠開啟燃氣熱水器,并將水溫設定至最高溫度60°C。
看起來感覺應該不難,控制器右邊兩個LED分別指示開啟狀態(tài)和出熱水狀態(tài),用GPIO去檢測就好了;開關(guān)和溫度設定看是高電平還是低電平觸發(fā),單片機輸出相應電平應該就行了。
再看看增壓泵:
自動增壓泵自己帶了個流量開關(guān),就是標箭頭那個,實現(xiàn)用戶開水就自動開啟,正好利用它來監(jiān)測用戶是否在使用太陽能的熱水。麻煩的是,這個開關(guān)是直接控制220V的,這個電壓對單片機的3.3V來說,好像稍微有點高。。。
旁邊的閥門后面會換成電動閥門,由Device 1根據(jù)Coordinator發(fā)來的命令控制開關(guān)。閥門是四線控制的,這個用兩個繼電器就可以輕松搞定。
最后來看看太陽能。。。控制器,熱水器在樓頂就不拍照片了,想看自己上網(wǎng)搜,都長的差不多。
這里主要是采集太陽能的水位水溫,發(fā)送給Coordinator,作為自動控制的依據(jù)。
看起來好像很easy,但這是這個系統(tǒng)中最最最麻煩的環(huán)節(jié),也是從一開始最沒把握的環(huán)節(jié),所以就選擇從這里開始攻關(guān)吧。這里搞定,其他都是毛毛雨了。
二話不說,先拆為敬,不然沒法分析。
網(wǎng)上大致搜了一下,我這種太陽能熱水器一般是用四線傳感器,其中兩線是測水位的電阻,兩線是熱敏電阻,利用電阻變化來測定水位水溫。
而測定電阻常用的辦法是利用RC電路充放電時間隨R變化,通過記錄充放電時間來間接計算R值。
這個辦法顯然比較麻煩,我怎么知道什么溫度對應什么樣的電阻值,這個阻值又對應什么樣的充放電時間?
看看控制器都已經(jīng)把水位水溫顯示出來了,我能不能直接拿到這個值呢。。。
太陽能熱水器控制器的程序不是我寫的,顯然不可能直接把這個值給我;既然它能驅(qū)動液晶屏顯示出對應的信息,能不能抓液晶屏上的信號來獲得水位水溫呢?這是我想的第一條路。
拆開一看,是那種定制化的液晶屏,左圖上一大排針都是它的引腳,看著就頭大,用示波器看了一下波形,亂的一塌糊涂,而且電平似乎還不穩(wěn)定,除了高低電平,好像還有中間電平?只好上網(wǎng)查查,原來這類液晶驅(qū)動顯示信息較多,為了減少驅(qū)動信號(這還叫少?),采用動態(tài)驅(qū)動,為了防止液晶出現(xiàn)動態(tài)驅(qū)動中對比度降低的“交叉效應”,一般都會采用一種所謂的“平均電壓法”,這就是我在示波器上看到有非高低電平的中間電平的原因,是確有其事,并非我眼花。
這樣的話普通的GPIO就沒法抓這樣的液晶信號了,看來對動態(tài)驅(qū)動的液晶屏,此路不通,只能另辟蹊徑了。
想想,歸根結(jié)底是電阻,控制器在測電阻的時候會有掃描電壓加上去,那么電阻兩端就會產(chǎn)生壓差,如果我用CC2530的ADC去采集這個電壓,假設ADC的精度足夠高,是不是就可以根據(jù)這個電壓算出電阻呢?試試吧。
于是看了下傳感器的接線,在下圖左邊三個畫紅框的地方,引出三組線到CC2530的P0.0-P0.2口,并將P0.0接到P2.0,利用P2.0在有掃描電平的時候觸發(fā)ADC轉(zhuǎn)換序列,并通過DMA采集數(shù)據(jù)。
為了找規(guī)律,在不同的水位和水溫下面抓了不知道幾千條數(shù)據(jù),看起來如下圖
但完全看不出我希望的那種電阻兩端的電壓差。大量數(shù)據(jù)放一起對比,電平上看不出明顯差異,倒是注意到波形的寬窄呈現(xiàn)一定的變化規(guī)律。
同時,這個波形和我從直覺上對電路的理解,覺得應該產(chǎn)生的波形有很大差異,百思不得其解,最后只好拿來紙筆,把相關(guān)電路畫下來,并一個個確認相關(guān)元件的類型和參數(shù)。
左邊那3個藍色圓圓的器件,我一直以為是電容,但根據(jù)上面的字怎么也找不到相關(guān)的資料,最后翻墻出去,終于在萬能的谷歌上找到了這幾個器件的準確型號和照片,原來它們居然是:壓敏電阻!真是大跌眼鏡啊,難怪總覺得電容在電路里產(chǎn)生不了這樣的波形。。。真是做什么事都不能想當然。
最后畫出的傳感器部分電路如下:
根據(jù)采集到的波形,結(jié)合電路圖分析,圖中寫出了我推測的在不同波形下,電路所處的狀態(tài)——看來太陽能控制器確實是在利用RC充放電回路測定電阻。
既然無法采集到希望的電壓信息,看來只能采取這種最基礎、也是最麻煩的方式了:利用RC充放電時間測定電阻。
從圖上看,雖然能看到有的信號電平有逐漸變化的過程,但信號還比較亂,考慮從傳感器端采集信號改為從控制器IC端采集信號,于是把引線改到了第一張拆機圖右邊3個紅圈處,也就是電路圖中標P0、P1、P2的地方。這樣抓到的信號如下:
下面的sheet名代表了不同的水位和水溫,“-”前的4代表滿水位,0是空水位,后面的60、61、62是水溫。
這個圖看起來還是很亂,但如果我們只看P0的數(shù)據(jù),如下:
這個圖看起來就相當規(guī)整了。
通過不同條件下測量數(shù)據(jù)的對比,波形的寬度確實和要采集的信號正相關(guān)。
這樣的話,不用采集3組信號,只用采集P0點的信號就夠了,而且也不用ADC,利用Timer記錄波形寬度就行了。
然后,又是大量的抓數(shù)據(jù),然后看波形寬窄比例的變化,最后,得到水位變化的曲線如下:
水位曲線只有4個等級,比較簡單,這個就可以直接用了。
溫度曲線就比較麻煩,到底是指數(shù)曲線、對數(shù)曲線還是冪指曲線?
采樣了足夠多的數(shù)據(jù)后,在Excel中對時間系數(shù)及其倒數(shù)進行分析,很是驚喜,看來P0/P1和溫度呈線性關(guān)系,采用了Excel的計算出的26.455*x-31.974作為溫度計算公式,上機后與原控制器測溫誤差在1°C以內(nèi),效果相當理想。
最難的一塊骨頭終于啃下來,接下來該輪到別的了。
先來看看太陽能用水檢測吧,這個需要檢測220V通斷的,變壓器肯定犯不著,太大材小用了;阻容分壓?好像隔離不太好。。。上網(wǎng)找了一下,有人建議用光耦隔離,這個不錯,于是草草畫了個圖,橋式整流加光耦:
一開始本來還計劃用Protel來做電路設計,但真臨了一想,就這么幾個器件,隨手畫畫就好,想出錯都難,實在犯不著再開一個工具。。。
于是網(wǎng)上淘了兩個PC817,這邊就算齊活了。
接下來是燃氣控制這邊。
按鍵控制測了一下,是低電平有效,這個好說,搞個9014拉低就好了。
開關(guān)和用水監(jiān)測卻給我找了點小小的麻煩,本來以為LED亮起來,測測正極有沒有電壓就好了,結(jié)果拿示波器一打,根本不是這么一回事:
不論燈亮不亮,正極都是一個5V的方波;負極隨燈開關(guān)有不同波形的變化;如果測LED正負極之間的電壓,則開啟時有1.8V的方波,關(guān)閉時反而有最低-0.4V的方波,如下圖右邊所示。
簡單分析了一下,正極應該是控制器上4個LED共享的PWM驅(qū)動信號,所以不論任何一個LED亮滅,這個方波始終存在;單個LED是低電平驅(qū)動,高電平截至,所以負極正好能觀察到示波器上的波形。
原理分析清楚了,那問題就容易解決了,并個PNP管,跟著LED報告狀態(tài)就行了,翻箱倒柜一番,找到幾個殘留的9012,夠了。電路如下所示,DET點接CC2530中斷腳,有中斷則表示LED開啟,無中斷則表示LED關(guān)閉。
外圍各種信號、狀態(tài)都已采集到,那接下來就簡單了,編程,焊接電路,組裝實施。
實施
大致控制策略無非就是:
1. 檢測太陽能熱水器的水溫和水位;
2. a) 如果太陽能的熱水合用,且用戶此時沒有使用熱水,則:
2. a) i) 打開太陽能的熱水出水閥;
2. a) ii)關(guān)閉燃氣熱水器的進水閥;
2. b) 如果太陽能這邊水溫低于60°,且用戶沒有使用熱水,則:
2. b) i) 打開燃氣熱水器的開關(guān);
2. b) ii) 設定水溫為60°;
2. b) iii)?關(guān)閉太陽能出水閥;
2. b) iv) 打開燃氣熱水器進水閥。
2. c) 如果太陽能這邊水位為最低,那么不管用戶是否正在使用太陽能的熱水,強制切換為燃氣;
2. d) 如果太陽能上水時,用戶嘗試使用熱水,強制切換為燃氣。
3. e) 如果應該使用燃氣熱水器時,燃氣熱水器因為待機15分鐘自動關(guān)閉,則按動電源鍵重新開啟并設置溫度為60°C。
當沒有客人的時候,有時哪怕太陽能20、30°的水溫,也覺得可以用來洗洗手,這時這個自動策略就不適用了,因此在Coordinator又加了兩個按鈕,用于手動切換太陽能/燃氣,以及讓系統(tǒng)在自動和手動工作模式之間切換。
考慮到Coordinator和燃氣熱水器裝在露臺,有淋雨的危險,因此外殼最好減少留孔,普通的按鍵就不適合,不好密封,最好是觸摸按鈕。淘寶上溜了一圈,淘了幾個合適的觸摸模塊回來。
這玩意兒離手的距離要合適,太遠感應不到,離上殼太近又會直接感應到上殼始終保持常開狀態(tài),怎樣可以靈活調(diào)整這個距離呢?想來想去,排針加插座解決這個問題:
既能相對穩(wěn)定,又能靈活調(diào)整觸摸按鈕的高度。
還有就是要解決模塊的燒錄問題。
賣家提供的是測試板上的排座,要在模塊上焊排針插上去燒
測試模塊這樣沒問題,可問題是有的地方安裝空間有限,焊上排針太礙事;飛線燒吧太麻煩,每個模塊都要飛將近10根線。
琢磨著怎么樣自己做個燒錄器呢,結(jié)合手邊有的材料和零件,關(guān)鍵是要能和模塊的引腳緊密接觸。最終利用兩組排針,一個簡易燒錄器出爐了:
燒錄時把模塊的郵票孔夾在兩組排針中間,就可以順利實現(xiàn)燒錄、調(diào)試,雖然偶爾會有點接觸不良,但比一個個飛線好多了。
考慮到模塊總會有bug,而沒有外接Flash,256KB內(nèi)存根本就不夠ZStack實現(xiàn)OTA升級,因此在線調(diào)試時肯定會頻繁拆下來,所以模塊都是用杜邦線引出接到其他電路部分,方便拆卸。
這是從燃氣熱水器控制器引出的線。
下面是Coordinator內(nèi)部的全貌,杜邦線太多,看起來有點亂糟糟,沒辦法,不是工業(yè)化設計出來的成品:
本來計劃從燃氣那邊把5V的電壓引過來,這樣就省了一組電源,奈何繼電器要的電流太大,那邊的功率不夠,一開繼電器就全系統(tǒng)復位,只好外接了一組USB 5V充電電源,通過左上角的電源模塊轉(zhuǎn)為3.3V。
下圖是太陽能熱水閥控制器的內(nèi)部結(jié)構(gòu),看起來比較清爽,外圍主要就一組光耦和一對繼電器:
然后是水管管路改造,要把電動閥門裝上,下面是部分零件:
由于空間有限,電動閥門沒法直接安裝,只能利用波紋管轉(zhuǎn)接,本來一個直直的增壓泵,現(xiàn)在變成了九曲回腸,水泵也趁此機會換了個新的,水壓大了不少:
? ->?
燃氣熱水器這邊:
給Coordinator打印了一個操作面板:
本來還給LED留了孔,后來發(fā)現(xiàn)特別是綠光LED,實在太亮了,就干脆用紙全蒙上,但晚上還是覺得很亮,可以考慮加大電阻或改用PWM控制占空比。
因為中間有墻,Zigbee還是會有通信不良的情況發(fā)生,如果持續(xù)無法收到Device 1或者2的信號,Coordinator右邊兩個LED會分別閃爍,以提示用戶。如果是在自動工作模式,此時也會自動切換到燃氣模式,以保證用水。
至此,本系統(tǒng)核心部分工作已基本完工,可以實現(xiàn)燃氣/太陽能的全時工作和自動切換,也支持手動操控。考慮到用水條件不是一個變換頻率很高、實時性要求很強的場景,系統(tǒng)中大部分地方采取了5秒輪詢的方式,只有少數(shù)控制,例如手動切換燃氣、太陽能等為實時中斷處理。
在電腦上通過串口終端,也已經(jīng)可以通過Device 3向Coordinator發(fā)送指令、獲取工作狀態(tài):
接下來只要用樹莓派替代電腦,開發(fā)一個UI界面,向Device 3收發(fā)串口指令就行了;或者更進一步,就像開頭說的那樣,將樹莓派接入Wifi后,開發(fā)相應的服務器和手機端UI,實現(xiàn)遠程操控,完成智能家居的完整場景。
樹莓派雖然之前沒用過,但其實質(zhì)就是一臺嵌入式Linux電腦而已,這上面的軟件開發(fā)只是時間問題而已,沒有什么新的東西。
不過老實說,之前要么就是在控制臺或Linux內(nèi)核驅(qū)動層折騰,要么就是在Android上做App開發(fā),Linux上的帶UI的App開發(fā)還真沒搞過,用什么來做呢?
調(diào)Zigbee時抓包工具是基于QT的,那干脆我也用QT吧,正好有參考,還可以跨平臺。
QT還算簡單,有Win32 GUI和Android等App開發(fā)的基礎,參考QT Creator中的教程,花兩天時間個大致把功能和界面搭了出來:
然后就是怎么移到樹莓派上去運行。
電腦上交叉編譯是可以,但那個環(huán)境配置估計還是有點麻煩,而且我以后用到的機會應該也不多吧。。。
于是決定直接到樹莓派上去搞。
網(wǎng)上搜羅了一番,先安裝基礎包:
sudo apt-get install qt5-default
sudo apt-get install qtcreator
然后因為需要和Zigbee模塊串口通信,還需要安裝串口模塊:
sudo apt-get install libqt5serialport5
sudo apt-get install libqt5serialport5-dev
在QT Creator中,要手動添加GCC和G++工具:
/usr/bin/gcc, /usr/bin/g++
Debugger可以選擇
/usr/bin/gdb
QT version也要確保選上了,然后確保工程的編譯路徑存在,發(fā)現(xiàn)QT?Creator會在工程目錄后面加一堆后綴,導致路徑不存在然后無法生成。而且不論是在Windows下還是Linux下都有這個問題,QT項目組該看看這個問題,一開始搞得我莫名其妙,不知道工程哪兒出什么錯了。
環(huán)境準備好后,導入工程,編譯順利完成。
本來計劃是飛線直連樹莓派的串口,突然轉(zhuǎn)念一想,直連串口是串口,USB轉(zhuǎn)串口也是串口,既然調(diào)試板有USB口直出,插上就是了,何必飛線呢。沒有飛線的羈絆,以后想將這個Gateway模塊挪作他用,做點別的測試,還更方便。
上機一試,哈哈,要的就是這個DIY的效果。
習慣了做國際化的工程,界面默認都是英文,抽空再用QT的方法翻譯一下吧^_^
前文提到的Zigbee和QT工程,代碼已提交至Github,有興趣的話可以作為參考:https://github.com/shaoyie/WaterSwitch
畢竟是第一次接觸Zigbee,難免有疏漏或理解不正確之處,歡迎指正。
轉(zhuǎn)載請標明出處:?采用Zigbee和Raspberry Pi的太陽能/燃氣熱水器自動控制系統(tǒng)?(https://blog.csdn.net/shaoyie/article/details/103525230)
總結(jié)
以上是生活随笔為你收集整理的采用Zigbee和Raspberry Pi的太阳能/燃气热水器自动控制系统的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: struts2学习笔记之十一:strut
- 下一篇: extern 详解