基於華為物聯網IOT的應用開發 --- 基於.net 的SDK封裝
最近,物聯網的概念比較熱門,一大批廠商搶著佔領物聯網的高低,包括有華為物聯網、阿里雲物聯網、騰訊物聯網、AWS物聯網等等,無法一一列舉,一般物聯網包含裝置側開發、平臺側開發、應用側開發,三個部分構成了線上線下的完整連線,和我們常規的微信應用、釘釘應用等不同,物聯網的終端是由各種各樣的裝置組合而成,這些裝置通過各種不同的協議(如CoAP,LWM2M、MQTT)連線到IOT的平臺,而且這些裝置是低能耗的裝置,可以實時的傳送資料上來,也可以接受來自IOT平臺下發的各種操作指令。本篇隨筆主要介紹基於華為物聯網IOT的應用開發,實現對.net SDK的封裝,方便後期進行應用整合使用。
1、物聯網的相關介紹
物聯網其實有點類似我們以前做的一些行業裝置的接入,不過它相對比較通用化一些,可以連線各種各樣的型別裝置,而且更加安全、低能耗等,我們以前接入很多裝置,可能需要走TCP/UDP協議,然後在後臺伺服器有一個對這些裝置管理的一個Socket伺服器,不過和物聯網對比,這些都被徹底改造過了,以便適應更多的 應用場景,更簡化的開發,以及支援更強大的功能吧。
物聯網目前可以針對一些感測器採集一些特定的引數,如光感、溫度、溼度、壓力、電壓、電流等常規的資訊,也可以擴充套件實現語音、影象、視訊等方面的採集處理,如經典的智慧路燈應用場景。
下面是其中的一個應用的架構設計,主要就是針對這些裝置管理,物聯網還提供了很多完善的應用API介面,使得我們可以更加簡化對裝置的管理(不用架設Socket服務),更加方便的通過API獲取相應的資訊,節省更多的維護成本。
物聯網平臺支援海量裝置連線上雲,裝置與雲端可以實現穩定可靠地雙向通訊。
- 提供裝置端SDK、驅動、軟體包等幫助不同裝置、閘道器輕鬆接入物聯網雲。
- 提供2G/ 3G /4G、NB-IoT、LoRa、WiFi等不同網路裝置接入方案,解決企業異構網路裝置接入管理痛點。
- 提供MQTT、CoAP、HTTP/S等多種協議的裝置端SDK,既滿足長連線的實時性需求,也滿足短連線的低功耗需求。
- 開源多種平臺裝置端程式碼,提供跨平臺移植指導,賦能企業基於多種平臺做裝置接入。
一般的物聯網平臺,都會包括產品管理、裝置管理、裝置組管理、規則引擎管理、訊息推送和訊息訂閱、任務管理、裝置升級等等,不同的物聯網雲平臺有所不同。
物聯網的幾個相關的協議:
MQTT(Message Queue Telemetry Transport)
MQTT是一個物聯網傳輸協議,被設計用於輕量級的釋出/訂閱式訊息傳輸,旨在為低頻寬和不穩定的網路環境中的物聯網裝置提供可靠的網路服務。
MQTTS指MQTT+SSL/TLS,在MQTTS中使用SSL/TLS協議進行加密傳輸。
CoAP(Constrained Application Protocol)
受約束的應用協議(CoAP)是一種軟體協議,旨在使非常簡單的電子裝置能夠在網際網路上進行互動式通訊。
CoAPS指CoAP over DTLS,在CoAPS中使用DTLS協議進行加密傳輸。
LWM2M(lightweight Machine to Machine)
LWM2M是由OMA(Open Mobile Alliance)定義的物聯網協議,主要使用在資源受限(包括儲存、功耗等)的NB-IoT終端
2、應用側開發介面
應用側的開發介面一般雲平臺都會提供不同平臺的SDK,如阿里雲開源提供Java SDK/C# SDK等;而華為則提供了Java、PHP等SDK,沒有包含.net 的SDK。
阿里物聯網雲的應用側API介面包括:
華為物聯網雲的應用側API介面包括:
本篇主要介紹最基礎的物聯網SDK的包裝,以方便後續的應用開發整合。本篇隨筆也主要是基於華為應用側API的封裝,使用C#語言實現對.net SDK的全部封裝處理。
針對上面的介面分類,我們定義不同的介面類來處理它們。
基本上所有API訪問都先需要通過鑑權介面獲取訪問的token,鑑權介面定義如下所示。
而且華為的API介面,需要使用X509證書處理的,我們可以通過在官網下載對應的X509證書進行整合測試API。
為了實現對API進行的.net SDK封裝,我們定義一些系統常見變數,方便在介面中使用。
根據鑑權返回的結果,我們定義一個對應的實體類來儲存這些屬性資訊,如下所示。
/// <summary> /// 鑑權結果 /// </summary> public class AuthenticationResult : BaseJsonResult { /// <summary> /// 申請許可權範圍,即accessToken所能訪問物聯網平臺資源的範圍,引數值固定為default。 /// </summary> public string scope { get; set; } /// <summary> /// accessToken的型別,引數值固定為Bearer 。 /// </summary> public string tokenType { get; set; } /// <summary> /// accessToken的有效時間,引數值固定為3600秒 /// </summary> public int expiresIn { get; set; } /// <summary> /// 鑑權引數,訪問物聯網平臺API介面的憑證。 /// </summary> public string accessToken { get; set; } /// <summary> /// 鑑權引數,有效時間為1個月,用於“重新整理Token”介面。 /// 當accessToken即將過期時,可通過“重新整理Token”介面來獲取新的accessToken。 /// </summary> public string refreshToken { get; set; } }
然後根據鑑權定義,我們實現對這個介面的封裝處理。
/// <summary> /// IOT鑑權介面實現 /// </summary> public class AuthenticationApi : IAuthenticationApi { /// <summary> /// 使用者鑑權 /// 應用伺服器首次訪問物聯網平臺的開放API時,需呼叫此介面完成接入認證; /// 應用伺服器在物聯網平臺的認證過期後,需呼叫此介面重新進行認證,才能繼續訪問物聯網平臺的開放API。 /// </summary> public AuthenticationResult Authentication() { string postData = string.Format("appId={0}&secret={1}", Constants.AppId, Constants.Secret); var url = Constants.AppBaseUrl + "/iocm/app/sec/v1.1.0/login";//名稱大小寫不能錯 HttpHelper helper = new HttpHelper(); helper.ContentType = "application/x-www-form-urlencoded"; helper.ClientCertificates = new X509CertificateCollection() { new X509Certificate2(Constants.CertFilePath, Constants.CertPassword) }; string content = helper.GetHtml(url, postData, true); var result = JsonConvert.DeserializeObject<AuthenticationResult>(content); return result; }
對於Token的重新整理操作,封裝也是類似操作
/// <summary> /// 重新整理token。 /// 應用伺服器通過鑑權介面獲取到的accessToken是有有效時間的,在accessToken快過期時, /// 應用伺服器通過呼叫此介面,獲取新的accessToken。 /// </summary> /// <param name="refreshToken"> /// 重新整理token,用來獲取一個新的accessToken。refreshToken在呼叫鑑權介面或重新整理token介面時獲得。 /// </param> /// <returns></returns> public AuthenticationResult RefreshToken(string refreshToken) { string postData = new { appId = Constants.AppId, secret = Constants.Secret, refreshToken = refreshToken }.ToJson(); var url = Constants.AppBaseUrl + "/iocm/app/sec/v1.1.0/refreshToken";//名稱大小寫不能錯 var result = WeJsonHelper<AuthenticationResult>.ConvertJson(url, postData); return result; }
上面有些是為了方便操作,定義了一些公用類庫,以減少程式碼的重複。
一般除了鑑權外的所有的API,它們處理方式都類似的,都是以 application/json 格式進行互動,使用POST、PUT、GET、Delete操作方式實現對資料的處理。
而且它們都需要有固定的請求頭資訊,我們以設備註冊為例進行介紹。
一般我們可以通過一個函式封裝,對介面的頭部請求資訊進行設定,如下所示。
/// <summary> /// 通用獲取頭部資訊 /// </summary> /// <param name="accessToken">介面訪問口令</param> /// <returns></returns> protected NameValueCollection GetHeader(string accessToken) { var header = new NameValueCollection(); header.Add(Constants.HEADER_APP_KEY, Constants.AppId); header.Add(Constants.HEADER_APP_AUTH, string.Format("Bearer {0}", accessToken)); return header; }
然後在定義請求的JSON和返回的JSON對應的實體類物件,封裝對應的API介面即可。
例如,我們註冊裝置的介面封裝如下所示。
/// <summary> /// 裝置管理介面實現 /// </summary> public class DeviceApi : BaseCommon, IDeviceApi { /// <summary> /// 註冊裝置(驗證碼方式)。 /// 在裝置接入物聯網平臺前,應用伺服器需要呼叫此介面在物聯網平臺註冊裝置,並設定裝置的唯一標識(如IMEI)。 /// 在裝置接入物聯網平臺時攜帶裝置唯一標識,完成裝置的接入認證。 /// </summary> /// <param name="accessToken"></param> /// <param name="info"></param> /// <returns></returns> public RegDeviceResult RegisterDevice(string accessToken, RegDeviceJson info) { var header = GetHeader(accessToken); string postData = info.ToJson(); var url = Constants.AppBaseUrl + "/iocm/app/reg/v1.1.0/deviceCredentials";//名稱大小寫不能錯 url += string.Format("?appId={0}", Constants.AppId); var result = WeJsonHelper<RegDeviceResult>.ConvertJson(url, postData, header); return result; } ......
這裡請求的資訊是 RegDeviceJson , 返回資訊的類是RegDeviceResult 。我們依照API定義,實現對應的處理即可。
為了方便處理,我們可以把這些對應裝置的實體類定義在一個檔案裡面,如DeviceJson.cs裡面,如下所示,這樣非常方便我們管理。
其他業務範疇的Api也是如此封裝,不在一一贅述。
我們測試的時候,可以建立一個單獨的Winform專案進行介面功能的測試,也可以自己編寫單元測試程式碼進行測試,根據自己熟練程度選擇吧。
例如鑑權介面測試程式碼如下所示,我們可以看看輸出進行判斷是否正常工作。
private void btnLogin_Click(object sender, EventArgs e) { var result = basicApi.Authentication(); Console.WriteLine(result != null ? "accessToken:" + result.ToJson() : "獲取結果出錯"); if (result != null) { var refreshResult = basicApi.RefreshToken(result.refreshToken); Console.WriteLine(refreshResult != null ? "accessToken:" + refreshResult.ToJson() : "獲取結果出錯"); this.accessToken = refreshResult.accessToken;//記錄待用 } }
設備註冊的功能測試如下所示。
private void btnRegDevice_Click(object sender, EventArgs e) { if (string.IsNullOrEmpty(accessToken)) { MessageUtil.ShowTips("請先鑑權獲取AccessToken"); return; } var deviceApi = new DeviceApi(); var regDeviceInfo = new RegDeviceJson() { endUserId = "64bf5869-b271-4007-8db8-fab185e19c10", nodeId = "64bf5869-b271-4007-8db8-fab185e19c10", psk = "12345678", timeout = 0, verifyCode = "", deviceInfo = new DeviceJson() { deviceType = "Smoke", manufacturerId = "49ac78c99f3e453598c155870efe8bfc", manufacturerName = "iqidi", //與manufacturerId、manufacturerName、deviceType、model和protocolType系列引數二選一 //productId = "5d9bf49b6a018f02d04cae28", model = "1001", name = "NBSimulator", imsi = "fafafasfasf", mac = "testetst", isSecurity = true.ToString().ToUpper(), protocolType = "LWM2M", } }; var regResult = deviceApi.RegisterDevice(accessToken, regDeviceInfo); Console.WriteLine(regResult != null ? regResult.ToJson() : "no regResult"); }
另外對於事件的通知,我們一般是在應用端被動的進行相應的處理,因此需要對它們的訊息進行轉換和處理。
針對以上的訊息通知,我們需要定義對應的訊息型別,然後進行判斷處理。
我們另起一個專案,然後定義對應給的事件接收處理,如下所示是一個統一的入口處理。
有了一個總入口,我們把對應通知的資訊轉換為對應的實體後,就可以進行記錄或者響應的處理了。
在後面我們接著開發應用功能的時候,這些對應的介面API就可以整合整合在我們的系統中了。
以上就是對於華為物聯網IOT平臺應用側的API封裝處理的思路, 供大家參考交流。