基於華爲物聯網IOT的應用開發 --- 基於.net 的SDK封裝

最近,物聯網的概念比較熱門,一大批廠商搶着佔領物聯網的高低,包括有華爲物聯網、阿里雲物聯網、騰訊物聯網、AWS物聯網等等,沒法一一列舉,通常物聯網包含設備側開發、平臺側開發、應用側開發,三個部分構成了線上線下的完整鏈接,和咱們常規的微信應用、釘釘應用等不一樣,物聯網的終端是由各類各樣的設備組合而成,這些設備經過各類不一樣的協議(如CoAP,LWM2M、MQTT)鏈接到IOT的平臺,並且這些設備是低能耗的設備,能夠實時的發送數據上來,也能夠接受來自IOT平臺下發的各類操做指令。本篇隨筆主要介紹基於華爲物聯網IOT的應用開發,實現對.net SDK的封裝,方便後期進行應用集成使用。node

一、物聯網的相關介紹

物聯網其實有點相似咱們之前作的一些行業設備的接入,不過它相對比較通用化一些,能夠鏈接各類各樣的類型設備,並且更加安全、低能耗等,咱們之前接入不少設備,可能須要走TCP/UDP協議,而後在後臺服務器有一個對這些設備管理的一個Socket服務器,不過和物聯網對比,這些都被完全改造過了,以便適應更多的 應用場景,更簡化的開發,以及支持更強大的功能吧。json

物聯網目前能夠針對一些傳感器採集一些特定的參數,如光感、溫度、溼度、壓力、電壓、電流等常規的信息,也能夠擴展實現語音、圖像、視頻等方面的採集處理,如經典的智慧路燈應用場景。安全

下面是其中的一個應用的架構設計,主要就是針對這些設備管理,物聯網還提供了不少完善的應用API接口,使得咱們能夠更加簡化對設備的管理(不用架設Socket服務),更加方便的經過API獲取相應的信息,節省更多的維護成本。服務器

 

物聯網平臺支持海量設備鏈接上雲,設備與雲端能夠實現穩定可靠地雙向通訊。微信

  • 提供設備端SDK、驅動、軟件包等幫助不一樣設備、網關輕鬆接入物聯網雲。
  • 提供2G/ 3G /4G、NB-IoT、LoRa、WiFi等不一樣網絡設備接入方案,解決企業異構網絡設備接入管理痛點。
  • 提供MQTT、CoAP、HTTP/S等多種協議的設備端SDK,既知足長鏈接的實時性需求,也知足短鏈接的低功耗需求。
  • 開源多種平臺設備端代碼,提供跨平臺移植指導,賦能企業基於多種平臺作設備接入。

通常的物聯網平臺,都會包括產品管理、設備管理、設備組管理、規則引擎管理、消息推送和消息訂閱、任務管理、設備升級等等,不一樣的物聯網雲平臺有所不一樣。網絡

 

物聯網的幾個相關的協議:架構

MQTT(Message Queue Telemetry Transport)app

MQTT是一個物聯網傳輸協議,被設計用於輕量級的發佈/訂閱式消息傳輸,旨在爲低帶寬和不穩定的網絡環境中的物聯網設備提供可靠的網絡服務。svg

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終端

 

二、應用側開發接口

應用側的開發接口通常雲平臺都會提供不一樣平臺的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封裝處理的思路, 供你們參考交流。