物聯網智慧路燈應用代碼解析(上)

相信不少同學都做過「基於物聯網平台構建智慧路燈應用」這個微認證,在這個微認證中,我們構建並部署了一個智慧路燈應用,這個應用擁有一個web界面,可以註冊路燈設備,可以獲取路燈設備的狀態和上報的環境亮度數據並顯示到界面上,還可以控制路燈的開關。

 

在微認證中,這個應用的源碼是公開的,但不需要修改就可以直接使用,所以很多同學可能並沒有仔細看過這個應用時怎麼實現的。所以本文就帶各位同學一起看下這個應用具體的設計與實現,以及探討下如果想要修改這個應用的功能要怎麼改,想要開發其他設備的應用要怎麼開發。

整體架構

智慧路燈的源碼在華為雲軟件開發平台作為公開示例模板公開,做過微認證的同學已經都已經按照模板創建了自己的代碼倉庫,接下來就是把代碼下到本地用本地的IDE打開,方便查看。

展開代碼的目錄後我們可以看出來這是一個基於Springboot工程模板創建的web應用.

所以,該應用的主要功能代碼都位於main文件夾下,其中java文件夾下是後端代碼,resources文件夾下是前端代碼和資源。

接下來讓我們一邊回憶該應用的使用流程,一邊查看對應的代碼是如何實現的。

Web頁面

使用智慧路燈應用的第一步是通過IP和端口訪問智慧路燈應用。我們通過瀏覽器訪問應用的時候實際上就是訪問了index.html這個文件。

 

打開index.html,可以看到就是個標準的html頁面,定義了頁面上顯示的各個組件。也就是,如果我們想要修改智慧路燈應用界面上顯示的內容,修改這個文件就可以了。

而這個頁面的行為和交互則是通過.js文件定義,和業務相關的主要代碼都在common.js,也就是想要修改該web頁面的交互行為,需要修改common.js。

參數設置

 

首次訪問智慧路燈應用以及點擊「參數設置」按鈕時,會彈出參數設置窗口,這個窗口的行為由openSetParamsDialog()函數控制。

 

這個函數的功能是從後台獲取數據作為默認值顯示在設置窗口,以及在用戶點擊確認後將設置的數據保存到後台。

獲取後台數據的函數是getDeviceParas(),可以看到這裡的後台其實就是瀏覽器的本體緩存,以及若後台沒有存儲數據時則返回空值。

將設置的數據保存到後台的函數是onSetParamsDialogConfirm(),先讀取輸入框的值,再寫入本地存儲,最後調用postDeviceParas()將數據傳到後端供後端使用。

通過文件搜索,我們可以找到/set-paras接口對應的後端函數是SetCustomData類的setPara(@RequestBody ParameterConfiguration value)函數,其作用是將參數值寫入TempDatabase類中的paras實體,並在用戶設置的數據獲取方式為訂閱推送時調用subscribeDataChange()函數。

通過查看TempDatabase類可以看到該類是個單純的數據存儲類,paras這是ParameterConfiguration類的一個實例,再查看ParameterConfiguration類可以看到它也是個單純的數據存儲類,所以該方法就是將用戶設計參數保存到內存中,供本應用運行時調用。

然後讓我們繼續順藤摸瓜,去看下subscribeDataChange類的subscribeDataChange()方法。

這個方法是個調用接口的方法,首先通過調用LoginService類的login()方法獲取accessToken,然後再調用設備接入的的創建訂閱接口。創建訂閱接口用於應用向平台訂閱設備數據,是物聯網應用向物聯網平台獲取數據的一種方法,本文不進行詳述,感興趣的同學可以查看我們之前的博文

(這段代碼相對較多,截圖就只截關鍵部分了,後面相同的情況不再說明)

 

通過對比訂閱函數和接口文檔,我們可以看出來函數中的accessToken對應接口中的X-Auth-Token,所以login()方法對應IAM服務的獲取用戶Token接口。

 

除訂閱推送外這個應用還支持通過DIS獲取數據的方法,不過在當前的代碼流程中我們還沒看到這個數據獲取方式的相關代碼,所以就等後面再進行講解。

註冊設備

參數設置成功後,我們需要輸入設備標識,然後點擊註冊設備。

設備標識是設備的唯一標識碼,一般用設備的MAC或IMEI,如果是虛擬設備可以隨意輸入一串數字。

通過查看index頁面源碼,我們可以看到用戶點擊註冊設備後應用會調用common.js中的regDevice( btn )函數,攜帶的參數就是用戶輸入的設備標識。這個方法會先檢查你是否設置了參數,然後再調用/register-device接口。

/register-device接口對應RegisterDevice類的registerDevice(@RequestBody DeviceRegisterVerifyCode deviceRegisterVerifyCode)函數,然後這個函數又調用了registerDirectConnectedDevice類的registerDirectDevice(DeviceRegisterVerifyCode deviceInfo)函數,調用了物聯網平台的創建設備接口。

然後讓我們看回common.js中的regDevice( btn )函數,可以看到註冊設備成功後它先移除了toggle-block的hide屬性,將頁面上剩下的部分(狀態查看和路燈控制)顯示了出來,然後調用了openDialogRegister(states,title,deviceId,secret)函數,並傳入了接口返回的設備Id和密鑰,實現了彈窗顯示。最後,這個函數調用了initTickTimer()函數,在initTickTimer()函數中,我們終於看到了DIS相關的內容。

這個函數是一個定時任務,循環檢查用戶設置的數據獲取方法,並調用對應函數。

當數據獲取方法是DIS時,該函數調用getDis()函數。getDis()函數調用/get-dis接口,並根據返回值設置界面顯示值。

/get-dis接口對應GetDis類的getDIsData()函數,這個函數通過集成DIS的SDK,實現了從DIS通道或獲取最新數據。這部分的實現可以直接參考DIS的文檔,本文不進行詳述。設備上報的數據從物聯網平台轉發至DIS通道則是基於數據轉發規則,本文也不進行詳述。(眼尖的同學可能會發現這個函數的最後有一行createDeviceCommand.runSetCommand(slMsg);這行代碼涉及到這個應用的命令下發機制,此處暫不講解)

當數據獲取方法是訂閱推送時,被循環調用的是getSub()函數。getSub()函數調用/get-device-data接口,並根據返回值設置界面顯示值。

/get-device-data接口對應GetDevData類的getDeviceData()函數,這個函數直接獲取了TempDatabase中的slMsg(存儲了環境光強和開關狀態)並返回,那這個slMsg的值又是哪來的?

這時候讓我們回想一下訂閱推送的機制:應用訂閱後,物聯網平台作為客戶端推送通知給應用指定的callbackURL。沒錯,這個數據是物聯網平台主動推送上來了,所以在這個應用中應該會有一個對應callbackURL接口的函數。

從subscribeDataChange()函數中我們可以找到callbackURL的後綴「/v1.0.0/messageReceiver」,通過在代碼中搜索我們找到了PushReceiver類中的pushrReceiver(@RequestBody String jsonString)函數。這個函數解析了物聯網平台推送的數據,並存到了slMsg中。

至此,我們的應用已經實現了設備的註冊和設備上報數據的獲取。在下期博客中,我將會為同學們介紹智慧路燈應用三種路燈控制模式的實現。

添加華為IoT小助手(微信號:huawei-iot,回復「博客園」)獲取此物聯網免費學習課程。