天天看點

【AllJoyn專題】基于AllJoyn和Yeelink的傳感器資料上傳與指令下行的研究1 工具和開發環境2 結構架構3 各子系統詳解4 示範驗證5 值得改進

接觸高通物聯網架構alljoyn不太久,但确是被深深地吸引了。在我看來,促進我深入學習的原因有三點:一、alljoyn開源,對開源的軟硬體總會有種莫名的喜愛,盡管也許不會都深入下去;二、順應潮流,物聯網雖遠未普及,但已是大勢所趨,高通公司在領域布局,緻力于打造舒适高效的智能家居場景,推出alljoyn軟體架構,适應了發展趨勢;三、文檔豐富,開源軟體的使用,特别是架構,若沒有文檔相助,相信沒有多少開發者願意嘗試,alljoyn在這方面做得不錯,日後還需做得更好。當然啦,也有些額外原因,包括高通的大力推廣,個人對c++的喜愛等等。

最近,根據之前所學,利用alljoyn和國内受人歡迎的yeelink物聯網平台完成了一個簡單的web of things的小系統。我們知道随着網際網路的蓬勃發展和物聯網在全球的興起,一個新的運作模式也在悄然誕生,即web of things,簡稱為wot。它可被了解為是iot的一部分,集中實作以web方式來控制和管理物聯網中的資源,包括各種網關及網關上的傳感器,其主旨是提倡通過rest web api的形式直接對智能終端與網關上的資源進行開放,使用者可以通過通路網際網路的方式來通路終端的資料資源,這就是典型的網際網路模式。而yeelink平台恰好能提供這樣的功能需求,是以我選擇了它作為應用層;而在網絡層可以細分為兩種,一種是公網傳輸,即借助目前成熟的網際網路,二種是區域網路傳輸,alljoyn與生俱來的局域傳輸能力就在這裡得到了展現;最下面為感覺層,即arduino終端作為網關接各種感覺裝置。結構示意圖如圖0所示:

【AllJoyn專題】基于AllJoyn和Yeelink的傳感器資料上傳與指令下行的研究1 工具和開發環境2 結構架構3 各子系統詳解4 示範驗證5 值得改進

目前系統實作的兩大功能如下:

1、上傳溫度傳感器采集的溫度值至yeelink平台,在平台上以易讀方式顯示;

2、通過點選平台上的虛拟開關向感覺層的arduino終端發出指令,控制led燈的亮滅;

alljoyn

關于alljoyn的介紹,我相信維基百科和官方文檔會比我說得詳細得多,可參考後文的連結。按照我目前的了解就是用它可以實作鄰近裝置間的互聯互通,不管是什麼裝置,隻要支援alljoyn,通過wifi、藍牙都可快速連接配接,實作資訊共享和及時通信。它的好處之一就在于支援多程式設計語言和多平台,非常友善開發者的使用

yeelink

yeelink是一個國内開放的的物聯網平台,每個注冊使用者都可免費添加裝置及傳感器,利用平台提供的restful接口,實作對各個傳感器的代碼通路,進而可以實作傳感器資料上傳和控制終端等多種功能。有這樣一個免費平台,相信對開發者來說是一大福音!

軟體環境

我目前服務端是在windows 7系統下做此實驗,如若在linux環境下運作,需修改部分平台相關代碼。內建開發環境是visual studio 2012,很強大的ide,在x86平台下用scons指令生成的samples檔案夾下同樣都是vs項目檔案。用戶端的實作則是用開源硬體流行的ide——arduino-1.5.6-r2,它支援arduino due開發闆,用它可進行檔案的編輯與燒寫。

硬體環境

除了x86 pc,大點的就隻是arduino due開發闆了。日前智能硬體的盛行也促進了開源硬體領域的發展,用arduino等相關成熟硬體可快速做系統原型,大量節約成本,在适當情況下是個很好的技術解決方案。令開發者欣慰的是,開源硬體社群非常流行,是以有很好的問題解決資源。

有arduino闆,但無傳感器可不行。為友善起見,我目前所展示的就隻是溫度傳感器ds18b20一種。由于具體的傳感器資料擷取與alljoyn并無關聯,是以就以溫感為例闡述基于alljoyn的資料傳輸,其它傳感器資料就與之類似了。另外,為了配合控制指令下傳,配備了一個發光二極管,當然這是arduino due闆上已有的,在13号引腳上。

---------------------------------------------------------------------------------------------------- --------------

友情建議:建議初學者學習x86平台下的alljoyn時,先可直接在vs下進行編輯生成,畢竟有比較好的代碼提示功能,熟練後再可用notepad等工具。如若剛學就在notepad上寫代碼,會很讓人無奈,因為一大堆函數和參數你都不知道,不容易發現錯誤。

本系統共有兩個arduino due開發闆作用戶端,由于是瘦用戶端,是以需要标準用戶端提供daemon才可連接配接,這一點在官方文檔中講得很明白,不再贅述;windows 7 pc端作為服務端,釋出服務供瘦用戶端連接配接,也許有朋友注意到了這與官方例子ledctrl和aj_ledservice不太一樣,客戶與服務的角色颠倒了,瘦用戶端不再作為服務而是客戶了;另外一方面,pc服務端通過網際網路與yeelink平台進行互動,實作資料上傳與接收指令,接收到的指令又通過alljoyn總線控制瘦用戶端,進而實作了yeelink平台下基于alljoyn的資料傳輸與控制功能。其結構框圖如圖1所示:

【AllJoyn專題】基于AllJoyn和Yeelink的傳感器資料上傳與指令下行的研究1 工具和開發環境2 結構架構3 各子系統詳解4 示範驗證5 值得改進

要想利用yeelink資源,就須在官網注冊一個唯一帳号,在使用者中心進行裝置和傳感器添加。如下圖所示,我添加了arduino裝置

【AllJoyn專題】基于AllJoyn和Yeelink的傳感器資料上傳與指令下行的研究1 工具和開發環境2 結構架構3 各子系統詳解4 示範驗證5 值得改進

在講到接下來的服務和客戶實作時,我會就核心代碼作詳細解析,而不會寫上完整代碼,望讀者了解

服務端主流程如下圖所示:

【AllJoyn專題】基于AllJoyn和Yeelink的傳感器資料上傳與指令下行的研究1 工具和開發環境2 結構架構3 各子系統詳解4 示範驗證5 值得改進

上圖是主線程的流程,由于在pc上是多線程運作,所在在監聽對象、總線對象上都有額外的線程運作,它們是異步的,也就意味着當事件發生時,可以迅速得到響應,比如當服務端收到溫感瘦用戶端傳來看溫度時,總線對象就調用其方法處理函數向yeelink平台上傳。下面就重點細節來談談如何設計服務端

首先建立總線對象,然後給總線對象添加接口。接口中有一個sendtemp方法,帶一個字元串輸入參數,有一個ledswitch信号,帶一個uint8_t型參數。最後激活接口和啟動總線

接下來建立監聽和總線對象,分别給總線注冊監聽和總線對象執行個體,最後總線執行個體開始連接配接本地router

在監聽類中,我們重新實作了幾個虛函數,包括

bool acceptsessionjoiner(sessionportsessionport, const char* joiner, const sessionopts& opts)

void sessionjoined(sessionport sessionport,sessionid id, const char* joiner)

void nameownerchanged(const char* name,const char* previousowner, const char* newowner)

前兩個是服務端特有的,當有客戶接入時,會自動被調用;最後一個服務和客戶都可調用,當有服務或客戶進入或退出時,總線上會發生名稱改變,進而它被調用,有時不止一次。這三個虛函數的實作基本是正常寫法,就不在此講解了

在總線對象執行個體的構造中,我是這樣做的:

首先給總線添加已經設定的接口,為sendtemp方法添加方法處理函數,同時給私有成員ledswitchmember設定值

在方法處理函數中,擷取傳過來的溫度值,字元串形式,就往yeelink平台上傳:

我需要強調的是,在makestring方法中,若要正确拼裝成http post請求,有幾條屬性不能少,于是定義了四個全局數組:

char yeelink_server[] = "api.yeelink.net";

char temp_path[] = "/v1.0/device/9966/sensor/19877/datapoints";

char switch_path[] = "/v1.0/device/9966/sensor/22595/datapoints";

char apikey[] = "d3d565a5923afdd82105e0e5a";

對應着post請求中的以下項:

post /v1.0/device/9966/sensor/19877/datapoints http/1.1

host: api.yeelink.net

u-apikey: d3d565a5923afdd82105e0e5a

host和path共同組成了傳感器的url,詳細說明可參見yeelink文檔

至于在初使化windows socket函數中,也需用到yeelink_server,填入相關結構的域,如下所示:

這部分是與平台相關的,若移植到linux平台,需要修改

在總線對象類中,還有一個成員函數emitledswitchsignal用于主線程發射信号給led瘦用戶端

将發來的參數封裝成message參數,和信号一起發送出去,注意sessionid為led用戶端id

我們回到主線程main中,connect之後就開始釋出服務了,三步曲:request,createsession,advertise

最後進入循環,輪詢我在yeelink中添加的控制開關狀态:

在這裡我采取的是被動輪詢開關狀态的方式,其實不是最佳的,最好是開關狀态一改變,就像硬體中斷似的,立刻通知cpu,而在此之前cpu完全可以去做其它事。但這需要yeelink平台的主動發送,貌似不太好辦,是以就隔斷時間輪詢狀态了。時間間隔也要選好,大了,led燈變化有延遲;小了,請求太頻繁又被yeelink拒絕。那麼如何輪詢呢?其實與上傳溫度差不多,還是組裝(不過現在是get請求)、初使化socket,不過在接收中我是這麼做的:

相關注意點已在注釋中說明。之是以待狀态改變後才發射信号,也是為了性能着想,沒有必要在狀态未改變時也發射。最後傳回的值是一個uint8_t型,取值為0或1,0表示熄滅led燈,1表示點亮led燈。隻要開關狀态改變,就把此資訊發送給led瘦用戶端

dallastemperature.cpp,dallastemperature.h,onewire.cpp,onewire.h,這屬于擷取溫度的庫,全部和ino檔案放在一起

另外建立另外一個cpp檔案,為alljoyn相關的核心檔案,傳輸溫度值。下面着重講述這個檔案

首先要重視以下幾個資料結構的書寫:

服務名、路徑、端口、接口名務必和服務端保持一緻,接口中必須要有sendtemp方法,攜帶一個字元串參數,其它的和dummy作用一樣,作填充;send_temp表示為aj_prx_message_id型

在aj_main中,首先做如下工作:

成功連上服務後,startclient才會傳回

接下來才是核心動作,擷取溫度、方法調用、睡眠,再循環:

由于我不關心後面的解消息過程,是以重點就是前幾句,方法調用如下:

首先marshal方法,然後marshal參數,即溫度值,最後deliver。這樣,就會導緻服務端的方法回調函數被調用

這一端與溫感有些地方類似,不過檔案就隻有2個,一個ino,一個以alljoyn為主的cpp

主要修改在于在sampleinterface中,添加ledswitch信号"!ledswitch instr>y",再預定義#define led_switch  aj_prx_message_id(0, 0, 2)

開始階段當然就與溫感類似了,startclient成功後,就開始解消息,因為服務端的信号要過來了:

當信号過來後,檢驗消息id,發現是led_switch,就解參數,擷取開關狀态。如果為1,則點亮led;為0則熄滅之。另外在這個用戶端就不用睡眠了,因為是被動接收服務端的信号

待服務、兩個用戶端代碼實作後,服務端生成exe檔案,連接配接好硬體,用戶端分别燒入兩個arduino due開發闆。粗略圖如下圖:

【AllJoyn專題】基于AllJoyn和Yeelink的傳感器資料上傳與指令下行的研究1 工具和開發環境2 結構架構3 各子系統詳解4 示範驗證5 值得改進

那個紅色闆上面就有ds18b20溫度傳感器,三個引腳号接入到了其中一個arduino闆的引腳上。兩個闆子都與主機pc通過路由器同處一個區域網路内部。還得強調一點,若要使pc服務端能與闆子通信,必須啟動瘦用戶端sdk bin下的sampledaemon.exe程式,因為服務端并沒有綁定的daemon,它就是來提供daemon給瘦用戶端使用的,其源碼可以\alljoyn-14.02.00-src\alljoyn_core\samples\sampledaemon找到

下面首先看溫度傳感器的驗證

連接配接好硬體上電,打開yeelink平台的溫度傳感器的顯示頁面,友善随時重新整理;點選arduino ide,按shift+ctrl+m打開序列槽終端,有如下顯示:

【AllJoyn專題】基于AllJoyn和Yeelink的傳感器資料上傳與指令下行的研究1 工具和開發環境2 結構架構3 各子系統詳解4 示範驗證5 值得改進

如若沒有sampledaemon,是不會有最後一句輸出的;接下來在指令行執行服務端程式:

【AllJoyn專題】基于AllJoyn和Yeelink的傳感器資料上傳與指令下行的研究1 工具和開發環境2 結構架構3 各子系統詳解4 示範驗證5 值得改進

正如上圖所示,服務端一啟動,就發現了客戶接入,接入成功之後開始會話。由于我的開關初使狀态是開着的,程式預設為關,是以狀态改變就發射了一次信号;同時收到了溫感一端發來的溫度值;序列槽終端的列印也表明傳送溫度成功,字元'f'的輸出是我的輸出函數的小問題,暫不管它。幾秒鐘之後,成了這樣:

【AllJoyn專題】基于AllJoyn和Yeelink的傳感器資料上傳與指令下行的研究1 工具和開發環境2 結構架構3 各子系統詳解4 示範驗證5 值得改進

咦?為什麼溫度上升了呢?呵呵,那是因為我把手指放在ds18b20上了!它當然溫度升高啦。此時我們再來看yeelink上溫感的反應:

【AllJoyn專題】基于AllJoyn和Yeelink的傳感器資料上傳與指令下行的研究1 工具和開發環境2 結構架構3 各子系統詳解4 示範驗證5 值得改進

不負所望,在14年9月13日 12:26:34分顯示了最初的溫度值26.6,前面的為之前的資料了。這也就實作了線上監控溫度的功能了

在另外一用戶端,打開序列槽視窗:

【AllJoyn專題】基于AllJoyn和Yeelink的傳感器資料上傳與指令下行的研究1 工具和開發環境2 結構架構3 各子系統詳解4 示範驗證5 值得改進

服務端收到了另外一客戶的接入,nameownerchanged被調用了好幾次,倘若我接下來在用滑鼠點選yeelink的控制開關,即下圖所示:

【AllJoyn專題】基于AllJoyn和Yeelink的傳感器資料上傳與指令下行的研究1 工具和開發環境2 結構架構3 各子系統詳解4 示範驗證5 值得改進

服務和瘦用戶端的反應是:

【AllJoyn專題】基于AllJoyn和Yeelink的傳感器資料上傳與指令下行的研究1 工具和開發環境2 結構架構3 各子系統詳解4 示範驗證5 值得改進

由結果可知,我是開了一次開關,又關了一次開關,導緻用戶端先後接到1,0,過程中觀察led燈的反應就是一亮一滅,同時溫度值也可在下圖中收到:

【AllJoyn專題】基于AllJoyn和Yeelink的傳感器資料上傳與指令下行的研究1 工具和開發環境2 結構架構3 各子系統詳解4 示範驗證5 值得改進

上面應該是傳輸錯誤才出現了a字元

到此為止,整個預先設想功能基本實作了

1、可以添入更多傳感器,進而讓功能更加豐富

2、可以讓第三個瘦用戶端充當服務,比如用arduino闆,移動手機等等,如果處理能力滿足條件的話。因為作為多個客戶的服務端,資料處理能力應該要強些,如果隻是單線程,像arduino闆,能否處理值得驗證

3、可以給溫度傳感器設定門檻值,一旦溫度超過給定值就采取報警,鳴響蜂鳴器之類的裝置

繼續閱讀