快速建置物聯網系統: Azure IoT Suite - Remote Monitoring 簡介及客製化

<2/15 更新:補充 IoT Hub GA 後支援MQTT, 新增 Azure-PowerShell v0.9.8.1 下載連結>

Azure IoT Suite 是微軟針對物聯網應用所規畫出來的雲端服務套件。 它具有快速建置, 高度擴展(High Scalable )性及高安全性, 加上支援多種裝置端作業系統(包含Linux、Windows、mbed、TI-RTOS) 並將裝置端SDK及系統客製化程式在GitHub上開源(Open Source)等特性;可以大幅減少一般物聯網專案的建置時程,加速IoT產品解決方案推出市場。 透過微軟IoT Suite 的Portal 網站, 甚至可以20 分鐘內就建置完一個 IoT Suite 的展示網站。

有關更多IoT Suite的介紹, 可以參考 :

由於各類物聯網情境的應用特性及作業流程不一, 因此Azure IoT Suite 在Device 端 SDK 及呈現介面上採取在GitHub 上OpenSource 的方式, 開發者可以在GitHub 上取得相關原始碼, 以修改成符合各自領域應用所需的網站系統。

跟Azure IoT Suite Remote Monitoring 有關的GitHub 專案有 :

 • azure-iot-remote-monitoring : 這是遠端監控應用情境的IoT Suite 範本專案 , 也是本文主要應用的專案。
  

 • azure-iot-predictive-maintenance : 這是應用在預測行維護情境的IoT Suite 範本專案。
  

 • azure-iot-sdks : 這是在裝置端使用的IoT Hub SDK, 提供C、Csharp、Jave、Node.js 等不同程式語言的版本。
 

 • azure-iot-protocol-gateway : 由於Azure IoT Suite 主要提供AMQP 1.0 , MQTT v3.1.1 及 HTTPS 兩種通訊協定, 如果想要使用其他通訊協定, 可以透過雲端閘道(Cloud Gatway) 的架構來達成。 這個專案實作 MQTT的通訊協定,由於IoT Hub 在GA 後已經內建支援MQTT v3.1.1 協定,此專案只是展示如何擴充IoT Suite 所支援的通訊協定。
  

 • PowerBI-visuals :   由於要呈現各式裝置回傳值最好的方式是透過圖形化介面, 因此在Remote Monitoring 專案中藉由PowerBI 的許多資料視覺化圖表功能,將物聯網裝置的回傳值呈現在專案管理介面上。 PowerBI-visuals 上提供了超過20種圖表呈現方式, 全部都開源在GitHub上, 讓資料呈現更直覺與豐富。
 

本文主要介紹 Azure IoT Suite 中的遠端監控( remote morning )範本客製化, 基本上它已經包含了微軟在Azure 物聯網上提供的主要技術與雲端服務元件。

下圖大致是遠端監控範本的架構圖 :  

來自 <https://azure.microsoft.com/en-us/documentation/articles/iot-suite-remote-monitoring-sample-walkthrough/>

遠端監控主要用到 :

    •  IoT Hub :  IoT Hub 是今年九月推出, 在Preview 階段的雲端服務。 它以Unit 為單位, 分別有三個等級, 每個等級每天可以接受的訊息量不一, 最基本的免費等級每天可以接收8000 個訊息量。 透過同時使用多個Unit, IoT Hub 可以承載每秒數百萬的訊息量。

 
    • Azure Stream Analytics (ASA) : 在Azure上的即時訊息處理服務,它可以將訊息的Stream 及時分類,根據時間加總運算(例如計算過去五分鐘收到的溫度平均值)。  透過ASA 即時運算,彙總,可以節省許多後製處理(Post Process)資料的時間。  
    • Event Hub (事件中樞) : Event 可以每秒接收數百萬訊息的服務,同時可讓多個應用程式去處理及使用這些訊息.特別是針對訊息量不固定或是偶有暴增裝況,Event Hub 可以避免批次處理及後製處理程式被未預期的訊息量壓垮。
    • Document DB : 屬於NoSQL 的一種,它是一種類似MangoDB 的JSON 資料庫.具有可以處理大量非固定結構的JSON 資料,並可以透過常見的SQL語法查詢這些文件.提供Restful API 以及JavaScript、Java、Node.js、Python及.Net SDK。
    • App Service - Web App :  支援.Net、Java、PHP、Node.js及Python 的網站環境, 提供自動調整(Auto Scale)與負載平衡,並且可以透過Git、TFS、GitHub 及VS Team Services 做連續部署.前述提到的azure-iot-remote-monitoring 就是執行在上面. 
    • App Service -Web Job : 是在Web App 上執行的背景工作及服務, 可以執行PHP、Python、Node.js、Java、Bash、Powershell、cmd、bat、exe 等背景或批次處理程式.透過Azure 入口網站中的 WebJob 儀表板能夠掌控 WebJob 的執行。
    • Azure AD : 提供雲端身分識別和存取管理功能,由於Remote Monitoring 的網站需要有權限管理的功能,因此會用到Azure AD 的服務
    • PowerBI :  在Remote Monitoring 的網站會透過圖表呈現各個Device 目前傳入遙測數值, 因此會借重Microsoft Power BI visuals project 來做資料圖表的呈現。

透過IoT Suite 的Portal 網站在建置IoT Suite 方案時, 也會列出所使用的Azure 服務。

建置Azure IoT Suite時, 除了透過IoT Suite 的Portal 網站做自動建置外, 也可以手動透過PowerShell 建置。

在下載下GitHub 上的azure-iot-remote-monitoring 專案後, 可以看到整個專案結構包含幾部分 :

  • Common 專案:放置一些公用的工具型Class。 例如 輔助存取Document DB 的工具,產生Sample 資料的工具。

  • EventProcessor.WebJob 專案 :  IoT 裝置的設定及狀態資訊處理程式,接收經ASA 分類過送到EventHub的裝置資訊 (藉由EventProcessorHost) ,將之更新到Document DB 以及執行被觸發的Action。
  • Infrastructure 專案:許多基本的資料物件,資料儲存位置,業務邏輯等,都撰寫在這個專案中。

  • Simulator.WebJob專案:包含產生模擬的裝置,在這個模擬的是一個冷卻裝置,它會量測溫濕度數值,送出模擬的遙測值 。 

 

  • Web : 這是IoT Remote Monitoring 的管理及監控網站,可以新增連線裝置,產生模擬裝置,顯示裝置狀態及回傳的遙測值.整個網站是以ASP.Net MVC 5 架構寫成。

   
如果要客製化自己的IoT 管理後台,建議可以先在本機部署RemoteMonitoring 這個專案。 由於有些Azure 服務無法在本機模擬, 因此我們仍要建置以下Azure 服務 :
    • IoT Hub : 規格 S1
    • DocumentDB : 規格 Standard
    • Event Hub
    • Azure Steam Analytic x 3
    • Blob Storage : 規格 Standard GRS

建置的Script 已經在專案中, 在專案的跟目錄下可以找到一個build.cmd 的Script。
首先先進入 Developer Command Promo for VS2015,並按右鍵選擇以 Administrator權限執行。

到專案的目錄後執行 build.cmd local 指令, 就會透過Powershell 部署相關服務並設定參數值。

這邊要注意的是 由於目前(2015/12)最新版的 Azure -PowerShell 已經是1.0.1 版, 在 Azure -PowerShell 在1.0 版後做比較大的改版, 針對Azure Resource Manager (ARM) 的指令有大幅度的更動, 但是 RemoteMonitoring 這個專案的Build Scrip 還未更新支援新的指令, 因此必須要安裝 Azure -PowerShell 0.9 版的才可以順利部署 。   本篇是用 Azure-PowerShell 0.9.8.1 環境建置, 這個版本可以在GitHub 這邊下載 。 (要確認目前環境所使用的 Azure-PowerShell 版本,可以透過這邊的Script 。)

成功部署完後可以在Azure Portal , IotSuiteLocal 的Resourge Group 上看到相關的服務已經建置完成

同時build.cmd local 也會更新 local.config.user 這個設定檔, 這個設定檔包含剛剛在部署過程中所建立的Azure 服務連線資訊。

接下來可以在 RemoteMonitoring的Solution中設定啟動專案, 同時將  EventProcessor、WebJob、Simulator、WebJob、Web 設為啟動。

然後按下執行, 就可以看到專案在本機執行起來並且連線到剛剛建立的Azure 服務。

之後就可以依照需求需修改及測試 Web 專案, 例如我們可以很快的Strings.resx檔來修改網站的Title並做一些中文化。 (這邊僅是為了快速展示的取巧作法, 這個專案已經透過ResourceManager實作多國語系資源, 正確中文化的方式仍是要建立 Message.zh-TW.resx檔案)

重新編譯後網站上的一些文字描述已經轉成剛剛修改的中文。

之後如果要發布到Production環境, 則在部署時可以使用: build.cmd cloud [debug | release] <deploymentname>  

如果要自己的IoT裝置可以連上剛剛建置的網站, 首先要在網站上的裝置管理介面上新增一個Custom Device, 並取得Device Key。


 

接下來就可以透過Device ID, IoT Hub Hostname, 跟Device Key 來進行連線。
以Raspberry Pi 上安裝Windows 10 IoT Core 的專案來說, 可以透過Nuget 加入 Microsoft.Azure.Devices.Client SDK。

在後再加入以下程式碼 :

   1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
 //[設定連線Azure IoT Suite 物件]      private const string DeviceConnectionString = "HostName=hermanIoT15a.azure-devices.net;SharedAccessKeyName=device;SharedAccessKey= [modify to YOUR SHARED ACCESS KEY]";        static string IOTHUB_RUI = "[modify to YOUR IOTHUB RUI]";        DeviceClient _deviceClient = DeviceClient.Create(IOTHUB_RUI, new DeviceAuthenticationWithRegistrySymmetricKey("[DEVICE ID]", "[DEVICE KEY]"), TransportType.Http1); //傳送遙測資訊到Azure IoT Suite 範例        async Task SendEvent(DeviceClient deviceClient, double distance)        {            RemoteMonitorTelemetryData rmtd = new RemoteMonitorTelemetryData();            rmtd.Humidity = distance;            Random random = new Random();            int i = random.Next(15);            rmtd.Temperature = 15 + i; //產生隨機資料            rmtd.ExternalTemperature = 35; //假資料            rmtd.DeviceId = "HermanRP2_001a";            var msgString = JsonConvert.SerializeObject(rmtd);            var msg2 = new Message(Encoding.ASCII.GetBytes(msgString));            await _deviceClient.SendEventAsync(msg2);            Debug.WriteLine("\t{0}> Sending message: {1}, Data: [{2}]", DateTime.Now.ToLocalTime(), 0, msgString);        }        //接收 IoT Suite上傳給裝置的指令        async Task ReceiveCommands(DeviceClient deviceClient)        {            Debug.WriteLine("\nDevice waiting for commands from IoTHub...\n");            Message receivedMessage;            string messageData;            while (true)            {                receivedMessage = await deviceClient.ReceiveAsync();                if (receivedMessage != null)                {                    messageData = Encoding.ASCII.GetString(receivedMessage.GetBytes());                    Debug.WriteLine("\t{0}> Received message: {1}", DateTime.Now.ToLocalTime(), messageData);                    //this.firstText.Text = "Received Command:";                    await deviceClient.CompleteAsync(receivedMessage);                }                await Task.Delay(TimeSpan.FromSeconds(10));            }        }        //設定裝置狀態為啟動        private async void StartDevice()        {            JObject device = new JObject();   // 需修改為實際值            JObject deviceProps = new JObject();            deviceProps.Add("DeviceID", "HermanRP2_001a");            deviceProps.Add("HubEnabledState", 1);            deviceProps.Add("CreatedTime", DateTime.UtcNow);            deviceProps.Add("DeviceState", "normal");            deviceProps.Add("UpdatedTime", null);            deviceProps.Add("Manufacturer", "Raspberry Pi Org");            deviceProps.Add("ModelNumber", "Raspberry Pi 2 B+");            deviceProps.Add("SerialNumber", "A9090");            deviceProps.Add("FirmwareVersion", "10.0586");            deviceProps.Add("Platform", "Windows10 IoT Core");            deviceProps.Add("Processor", "ARM");            deviceProps.Add("Latitude", 35.626897);            deviceProps.Add("Longitude", 139.740729);            device.Add("DeviceProperties", deviceProps);            device.Add("Commands", new JArray());            device.Add("IsSimulatedDevice", 0);            device.Add("ObjectType", "DeviceInfo");            device.Add("Version", "1.0");            JObject command01 = new JObject();            command01.Add("Name", "SetTemperature");            command01.Add("Parameters", null);            JObject command02 = new JObject();            command02.Add("Name", "PingDevice");            command02.Add("Parameters", null);            JObject command03 = new JObject();            command03.Add("Name", "StartTelemetry");            command03.Add("Parameters", null);            JObject command04 = new JObject();            command04.Add("Name", "StopTelemetry");            command04.Add("Parameters", null);            dynamic commands = GetSupportedCommands(device);            commands.Add(command01);            commands.Add(command02);            commands.Add(command03);            commands.Add(command04);            var messageString = JsonConvert.SerializeObject(device);            var message = new Message(Encoding.ASCII.GetBytes(messageString));            await _deviceClient.SendEventAsync(message);            Debug.WriteLine("Send Start Device Info: " + messageString);        }        //設定裝置接受那些指令        public static dynamic GetSupportedCommands(dynamic device)        {            if (device == null)            {                throw new ArgumentNullException("device");            }            dynamic commands = device.Commands;            if (commands == null)            {                commands = new JArray();                device.Commands = commands;            }            return commands;        }  // 遙測資訊格式    public class RemoteMonitorTelemetryData    {        public string DeviceId { get; set; }        public double Temperature { get; set; }        public double Humidity { get; set; }        public double? ExternalTemperature { get; set; }    }

然後再呼叫 StartDevice() method之後, 就可以透過 SendEvent() method 送出遙測資訊到Azure IoT Suite。

有興趣的朋友也可以參考: 打造個人化智慧家庭 - 家庭成員人臉辨識 (Azure IoT + Azure SQL + Project Oxford 中的展示。