精品国产一级在线观看,国产成人综合久久精品亚洲,免费一级欧美大片在线观看

使用 Azure IoT 套件推動 IoT 開發(fā)

責任編輯:editor004

2017-07-18 10:58:31

摘自:微軟中國

(IoT) 解決方案包括遠程遙測設(shè)備、Web 門戶、云存儲和實時處理功能。圖 1:Azure IoT 套件預配置解決方案門戶,以及用于采集并處理視頻流的遠程通用 Windows 平臺應(yīng)用 

物聯(lián)網(wǎng) (IoT) 解決方案包括遠程遙測設(shè)備、Web 門戶、云存儲和實時處理功能。結(jié)構(gòu)如此復雜,你就更不愿意開始進行 IoT 開發(fā)了。為了簡化工作,Microsoft Azure IoT 套件提供了以下兩個預配置解決方案:遠程監(jiān)視和預測性維護。

本文將介紹如何創(chuàng)建遠程監(jiān)視解決方案,從而收集和分析 Windows 10 IoT 核心版控制的遠程 IoT 設(shè)備中的數(shù)據(jù)。此 Raspberry Pi 設(shè)備將通過 USB 攝像頭采集圖像。隨后,圖像亮度會在 IoT 設(shè)備上進行計算,然后流式傳輸?shù)皆浦校⒃谠浦羞M行存儲、處理和顯示(見圖 1)。

此外,最終用戶不僅可以查看通過遠程設(shè)備采集的信息,還能遠程控制相應(yīng)設(shè)備。有關(guān)輔助此論述的完整源代碼,請訪問 msdn.com/magazine/0617magcode

圖 1:Azure IoT 套件預配置解決方案門戶,以及用于采集并處理視頻流的遠程通用 Windows 平臺應(yīng)用

遠程設(shè)備

Frank LaVigne (msdn.com/magazine/mt694090) 和 Bruno Sonnino (msdn.com/magazine/mt808503) 已在本雜志中介紹過在安裝了 Windows 10 IoT 核心版的 Raspberry Pi 上進行編程的基礎(chǔ)知識。

LaVigne 和 Sonnino 介紹了如何設(shè)置開發(fā)環(huán)境和 IoT 開發(fā)板、如何在瀏覽器中使用設(shè)備門戶配置 IoT 單元,以及如何使用 Windows 10 IoT 核心版控制 GPIO 端口。此外,LaVigne 還在他的文章中提到,可以使用 IoT 對遠程攝像頭進行編程和控制。

在本文中,我擴展了這一想法,并明確介紹了如何將 Raspberry Pi 變成這樣的設(shè)備。

為此,我使用空白應(yīng)用(通用 Windows)Visual C# 項目模板創(chuàng)建了 RemoteCamera 通用 Windows 平臺 (UWP) 應(yīng)用,然后將目標和最低 API 版本設(shè)置為 Windows 10 周年版本(10.0;生成號 14393)。我使用此 API 版本是為了能夠綁定到方法,從而直接將視圖模型的方法與可視控件觸發(fā)的事件相關(guān)聯(lián):

 

接下來,我聲明了 UI,如圖 1 所示。有兩個選項卡: “攝像頭捕捉”和“云”。第一個選項卡中的控件可用于啟動或停止攝像頭預覽、顯示視頻流并呈現(xiàn)圖像亮度(標簽和進度欄)。第二個選項卡中有兩個按鈕,分別用于將設(shè)備連入云中,以及在 IoT 門戶中注冊設(shè)備。“云”選項卡還包含一個復選框,用于啟用流式傳輸遙測數(shù)據(jù)。

與 UI 相關(guān)聯(lián)的大部分邏輯是在 RemoteCameraViewModel 類(見 RemoteCamera 項目的 ViewModels 子文件夾)中實現(xiàn)。除了實現(xiàn)一些與 UI 綁定的屬性之外,此類還負責處理視頻采集、圖像處理和云交互。

這些子功能分別是在以下各個類中實現(xiàn): CameraCapture、ImageProcessor 和 CloudHelper。我很快將會介紹 CameraCapture 和 ImageProcessor,而 CloudHelper 及相關(guān)幫助程序類則稍后將在 Azure IoT 預配置解決方案上下文中進行介紹。

相機捕捉

攝像頭捕捉(見 Helpers 文件夾下的 CameraCapture.cs)是在以下兩個元素的基礎(chǔ)之上生成: Windows.Media.Capture.MediaCapture class 和 Windows.UI.Xaml.Controls.CaptureElement。

前者用于采集視頻,而后者則用于顯示采集的視頻流。由于使用攝像頭采集視頻,因此必須在 Package.appxmanifest 中聲明相應(yīng)的設(shè)備功能。

若要初始化 MediaCapture 類,請調(diào)用 InitializeAsync 方法。最終,可以向此方法傳遞 MediaCaptureInitializationSettings 類的實例,從而指定捕捉選項。

可以選擇是流式傳輸視頻還是音頻,并選擇捕捉硬件。在本文中,我僅通過默認攝像頭采集視頻(見圖 2)。

圖 2:攝像頭捕捉初始化

publicMediaCapture { getprivateset} = newMediaCapture(); publicboolIsInitialized { getprivateset} = falsepublicasyncTask Initialize(CaptureElement captureElement){ if(!IsInitialized) { varsettings = newMediaCaptureInitializationSettings() { StreamingCaptureMode = StreamingCaptureMode.Video }; try{ awaitMediaCapture.InitializeAsync(settings); GetVideoProperties(); captureElement.Source = MediaCapture; IsInitialized = true} catch(Exception ex) { Debug.WriteLine(ex.Message); IsInitialized = false} }}

接下來,使用 CaptureElement 類實例的 Source 屬性,將此對象與 MediaCapture 控件相關(guān)聯(lián),以顯示視頻流。

我還調(diào)用了幫助程序方法 GetVideoProperties,用于讀取并存儲視頻幀的大小。稍后會使用此信息來獲取預覽幀以供處理。

最后,為了能夠真正啟動和停止視頻采集,我調(diào)用了 MediaCapture 類的 StartPreviewAsync 和 StopPreviewAsync。在 CameraCapture 中,我使用其他邏輯包裝了這些方法,同時驗證了初始化和預覽狀態(tài):

publicasyncTask Start(){ if(IsInitialized) { if(!IsPreviewActive) { awaitMediaCapture.StartPreviewAsync(); IsPreviewActive = true} }}

運行應(yīng)用時,可以按“開始預覽”按鈕來配置攝像頭采集,之后不久就可以看到攝像頭圖像。請注意,由于 RemoteCamera 應(yīng)用是通用應(yīng)用,因此無需進行任何更改,即可部署到開發(fā) PC、智能手機、平板電腦或 Raspberry Pi。

如果使用 Windows 10 PC 測試 RemoteCamera 應(yīng)用,需要確保應(yīng)用可使用攝像頭。可以使用“設(shè)置”應(yīng)用(“隱私”/“攝像頭”)來配置此設(shè)置。為了使用 Raspberry Pi 測試此應(yīng)用,我使用了預算較低的 Microsoft Life Cam HD-3000。由于這是一個 USB 攝像頭,因此,當我將它連到四個 Raspberry Pi USB 端口之一后,Windows 10 IoT 核心版可以自動檢測到攝像頭。

有關(guān)與 Windows 10 IoT 核心版兼容的攝像頭的完整列表,請訪問 bit.ly/2p1ZHGD。將攝像頭與 Rasbperry Pi 相連后,它顯示在“設(shè)備門戶”的“設(shè)備”選項卡下。

圖像處理器

ImageProcessor 類在后臺計算當前幀的亮度。為了執(zhí)行后臺操作,我使用基于任務(wù)的異步模式創(chuàng)建了線程,如圖 3 所示。

圖 3:在后臺計算亮度

publiceventEventHandler ProcessingDone; privatevoidInitializeProcessingTask(){ processingCancellationTokenSource = newCancellationTokenSource(); processingTask = newTask( async() => { while(!processingCancellationTokenSource.IsCancellationRequested) { if(IsActive) { varbrightness = awaitGetBrightness(); ProcessingDone( this, newImageProcessorEventArgs(brightness)); Task.Delay(delay).Wait(); } } }, processingCancellationTokenSource.Token);}

在 while 循環(huán)中,我確定了圖像亮度,然后將此值傳遞給 ProcessingDone 事件的偵聽器。系統(tǒng)向此事件饋送 ImageProcessorEventArgs 類的實例,其中只有一個公共屬性 Brightness。在收到取消信號前,處理任務(wù)會一直運行。圖像處理的關(guān)鍵元素是 GetBrightness 方法,如圖 4 所示。

圖 4:GetBrightness 方法

privateasyncTask< byte>GetBrightness(){ varbrightness = newbyte(); if(cameraCapture.IsPreviewActive) { // Get current preview bitmapvarpreviewBitmap = awaitcameraCapture.GetPreviewBitmap(); // Get underlying pixel datavarpixelBuffer = GetPixelBuffer(previewBitmap); // Process buffer to determine mean gray value (brightness)brightness = CalculateMeanGrayValue(pixelBuffer); } returnbrightness;}

我使用 CameraCapture 類實例的 GetPreviewBitmap 來獲取預覽幀。在內(nèi)部,GetPreviewBitmap 使用 MediaCapture 類的 GetPreviewFrameAsync。

GetPreviewFrameAsync 有兩個版本。第一個版本是無參數(shù)方法,返回的是 VideoFrame 類的實例。

在這種情況下,可以通過讀取 Direct3DSurface 屬性來獲取實際的像素數(shù)據(jù)。第二個版本接受 VideoFrame 類的實例,并將像素數(shù)據(jù)復制到其 SoftwareBitmap 屬性中。在本文中,我使用第二個選項(見 CameraCapture 類的 GetPreviewBitmap 方法),然后通過 SoftwareBitmap 類實例的 CopyToBuffer 方法訪問像素數(shù)據(jù)(如圖 5 所示)。

圖 5:訪問像素數(shù)據(jù)

privatebyte[] GetPixelBuffer(SoftwareBitmap softwareBitmap){ // Ensure bitmap pixel format is Bgra8if(softwareBitmap.BitmapPixelFormat != CameraCapture.BitmapPixelFormat) { SoftwareBitmap.Convert(softwareBitmap, CameraCapture.BitmapPixelFormat); } // Lock underlying bitmap buffervarbitmapBuffer = softwareBitmap.LockBuffer(BitmapBufferAccessMode.Read); // Use plane deion to determine bitmap height// and stride (the actual buffer width)varplaneDeion = bitmapBuffer.GetPlaneDeion(0); varpixelBuffer = newbyte[planeDeion.Height * planeDeion.Stride]; // Copy pixel data to a buffersoftwareBitmap.CopyToBuffer(pixelBuffer.AsBuffer()); returnpixelBuffer;}

首先,我將確認像素格式是否為 BGRA8。此像素格式表示圖像使用四個 8 位通道:三個通道分別用于表示藍色、綠色和紅色,另外一個通道用于表示 alpha 或透明度。如果輸入位圖采用其他像素格式,我會執(zhí)行相應(yīng)的轉(zhuǎn)換。

接下來,我將把像素數(shù)據(jù)復制到字節(jié)數(shù)組中,其大小由圖像高度與圖像步幅的乘積決定 (bit.ly/2om8Ny9)。我從 BitmapPlaneDeion 實例中讀取這兩個值,此實例是通過 SoftwareBitmap.LockBuffer 方法返回的 BitmapBuffer 對象獲取而來。

鑒于字節(jié)數(shù)組包含像素數(shù)據(jù),只需計算所有像素的平均值即可。因此,我循環(huán)訪問了像素緩存(見圖 6)。

圖 6:計算像素的平均值

privatebyteCalculateMeanGrayValue( byte[] pixelBuffer){ // Loop index increases by four since// there are four channels (blue, green, red and alpha).// Alpha is ignored for brightness calculationconstintstep = 4; doublemean = 0.0; for( uinti = 0; i

然后,每次循環(huán)訪問時,我會計算所有顏色通道的平均值,將給定像素轉(zhuǎn)換成灰度:

privatestaticbyteGetGrayscaleValue( byte[] pixelBuffer, uintstartIndex){ vargrayValue = (pixelBuffer[startIndex] + pixelBuffer[startIndex + 1] + pixelBuffer[startIndex + 2]) / 3.0; returnConvert.ToByte(grayValue);}

Brightness 通過 ProcessingDone 事件傳遞給視圖。

此事件的處理位置為 MainPage 類 (MainPage.xaml.cs),我在其中通過標簽和進度欄顯示亮度。兩個控件均綁定到 RemoteCameraViewModel 的 Brightness 屬性。

請注意,ProcessingDone 是由后臺線程觸發(fā)。因此,我使用 Dispatcher 類通過 UI 線程修改 RemoteCameraViewModel.Brightness,如圖 7 所示。

圖 7:使用 Dispatcher 類通過 UI 線程修改 RemoteCameraViewModel.Brightness

privateasyncvoidDisplayBrightness( bytebrightness){ if(Dispatcher.HasThreadAccess) { remoteCameraViewModel.Brightness = brightness; } else{ awaitDispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { DisplayBrightness(brightness); }); }}

預配遠程監(jiān)視解決方案

若要預配解決方案,可以使用專用門戶 (azureiotsuite.com)。登錄并選擇 Azure 訂閱后,便會重定向到一個頁面,可以在其中按“創(chuàng)建新的解決方案”矩形框。

這會打開一個網(wǎng)站,可以在其中選擇兩個預配置解決方案之一:預測性維護或遠程監(jiān)視(見圖 8)。選擇解決方案后,將會看到另一個窗體,可以在其中設(shè)置 Azure 資源的解決方案名稱和區(qū)域。

在本文中,我將解決方案名稱和區(qū)域分別設(shè)置為“RemoteCameraMonitoring”和“美國西部”。

  圖 8:Azure IoT 套件預配置解決方案(上)和遠程監(jiān)視解決方案配置(下)

預配遠程監(jiān)視解決方案時,Azure IoT 套件門戶會創(chuàng)建以下多個 Azure 資源: IoT 中心、流分析作業(yè)、存儲和 App Service。IoT 中心可實現(xiàn)云和遠程設(shè)備之間的雙向通信。流分析作業(yè)會轉(zhuǎn)換遠程設(shè)備流式傳輸?shù)臄?shù)據(jù),通常是篩選掉不必要的數(shù)據(jù)。篩選后的數(shù)據(jù)會進行存儲或定向,以供將來分析時使用。

最后,App Service 用于托管 Web 門戶。

也可以通過命令行完成解決方案預配。

為此,可以從 bit.ly/2osI4RW克隆或下載解決方案源代碼,然后按照 bit.ly/2p7MPPc中的說明操作。也可以視需要在本地部署解決方案,如 bit.ly/2nEePNi 所述。

在這種情況下,不會創(chuàng)建 Azure App Service,因為解決方案門戶是在本地計算機上運行。若要進行開發(fā)和調(diào)試或修改預配置解決方案,就會發(fā)現(xiàn)此類方法特別有用。

完成預配后,可以啟動解決方案,它的門戶顯示在默認瀏覽器中(再次見圖 1)。此門戶包含多個選項卡。

在本文中,我將僅關(guān)注其中兩個選項卡,即“儀表板”和“設(shè)備”。“儀表板”顯示遠程設(shè)備及其流式傳輸?shù)倪b測數(shù)據(jù)的映射。“設(shè)備”選項卡顯示遠程設(shè)備列表,包括設(shè)備的狀態(tài)、功能和說明。默認情況下,有多個仿真設(shè)備。我將介紹如何注冊新的非仿真硬件。

注冊設(shè)備

若要注冊設(shè)備,請按解決方案門戶中左下角的“添加設(shè)備”超鏈接。然后,選擇添加仿真設(shè)備還是自定義設(shè)備。選取第二個選項,然后按“添加新設(shè)備”按鈕。現(xiàn)在,可以定義“設(shè)備 ID”了。我將此值設(shè)置為“RemoteCamera”。

此后,“添加自定義設(shè)備”窗體中顯示設(shè)備憑據(jù)(見圖 9),稍后用它將 IoT 設(shè)備連入 IoT 中心。

  圖 9:設(shè)備注冊摘要

設(shè)備元數(shù)據(jù)和云通信

添加的設(shè)備顯示在設(shè)備列表中,然后便可以發(fā)送設(shè)備元數(shù)據(jù)或設(shè)備信息。設(shè)備信息包括描述遠程設(shè)備的 JSON 對象。此對象可告知云終結(jié)點設(shè)備功能,并包含硬件描述以及設(shè)備接受的遠程命令列表。最終用戶可通過 IoT 解決方案門戶向設(shè)備發(fā)送這些命令。

在 RemoteCamera 應(yīng)用中,設(shè)備信息表示為 DeviceInfo 類(位于 AzureHelpers 子文件夾中):

publicclassDeviceInfo{ publicboolIsSimulatedDevice { getset} publicstringVersion { getset} publicstringObjectType { getset} publicDeviceProperties DeviceProperties { getset} publicCommand[] Commands { getset}}

DeviceInfo 的前兩個屬性指定了是否為仿真設(shè)備,并定義了 DeviceInfo 對象的版本。稍后可以看到,第三個屬性 ObjectType 被設(shè)置為字符串常數(shù) DeviceInfo。

云(特別是 Azure 流分析作業(yè))使用此字符串從遙測數(shù)據(jù)中篩選出設(shè)備信息。接下來,DeviceProperties(見 AzureHelpers 子文件夾)包含一系列描述設(shè)備的屬性(如序列號、內(nèi)存、平臺、RAM)。最后,Commands 屬性包含設(shè)備識別的一系列遠程命令。

通過指定名稱和參數(shù)列表(分別由 Command 和 CommandParameter 類表示,見 AzureHelpersCommand.cs),可定義每個命令。

若要在 IoT 設(shè)備和 IoT 中心之間建立通信,請使用 Microsoft.Azure.Devices.Client NuGet 包。此包提供 DeviceClient 類,可用于向云發(fā)送消息和接收云消息。可以使用 Create 或 CreateFromConnectionString 靜態(tài)方法,創(chuàng)建 DeviceClient 實例。

在本文中,我使用第一個選項(見 AzureHelpers 文件夾中的 CloudHelper.cs):

publicasyncTask Initialize(){ if(!IsInitialized) { deviceClient = DeviceClient.Create( Configuration.Hostname, Configuration.AuthenticationKey()); awaitdeviceClient.OpenAsync(); IsInitialized = trueBeginRemoteCommandHandling(); }}

可以看到,若要使用 DeviceClient.Create 方法,需要提供 IoT 中心的主機名和設(shè)備憑據(jù)(標識符和密鑰)。這些值是在設(shè)備預配期間從解決方案門戶獲取(再次見圖 9)。在 RemoteCamera 應(yīng)用中,我在 Configuration 靜態(tài)類中存儲了主機名、設(shè)備 ID 和密鑰:

publicstaticclassConfiguration{ publicstaticstringHostname { get} = ".azure-devices.net"publicstaticstringDeviceId { get} = "RemoteCamera"publicstaticstringDeviceKey { get} = ""publicstaticDeviceAuthenticationWithRegistrySymmetricKey AuthenticationKey() { returnnewDeviceAuthenticationWithRegistrySymmetricKey(DeviceId, DeviceKey); }}

此外,Configuration 類還會實現(xiàn)靜態(tài)方法 AuthenticationKey,從而將設(shè)備憑據(jù)包裝到 DeviceAuthenticationWithRegistrySymmetricKey 類的實例中。我借此來簡化 DeviceClient 類實例的創(chuàng)建工作。

連接建立后,只需發(fā)送 DeviceInfo 即可,如圖 10 所示。

圖 10:發(fā)送設(shè)備信息

publicasyncTask SendDeviceInfo(){ vardeviceInfo = newDeviceInfo() { IsSimulatedDevice = false, ObjectType = "DeviceInfo", Version = "1.0", DeviceProperties = newDeviceProperties(Configuration.DeviceId), // Commands collectionCommands = newCommand[] { CommandHelper.CreateCameraPreviewStatusCommand() } }; awaitSendMessage(deviceInfo);}

RemoteCamera 應(yīng)用可發(fā)送描述實際硬件的設(shè)備信息,因此 IsSimulatedDevice 屬性設(shè)置為 false。

如上所述,ObjectType 設(shè)置為 DeviceInfo。此外,我還將 Version 屬性設(shè)置為 1.0。對于 DeviceProperties,我使用的是任意值,主要包括靜態(tài)字符串(見 DeviceProperties 類的 SetDefaultValues 方法)。

我還定義了遠程命令“更新攝像頭預覽”,以便能夠遠程控制攝像頭預覽。此命令包含一個布爾參數(shù) IsPreviewActive,用于指定應(yīng)啟動還是停止攝像頭預覽(見 AzureHelpers 文件夾下的 CommandHelper.cs 文件)。

為了能夠真正將數(shù)據(jù)發(fā)送到云中,我實現(xiàn)了 SendMessage 方法:

privateasyncTask SendMessage(Object message){ varserializedMessage = MessageHelper.Serialize(message); awaitdeviceClient.SendEventAsync(serializedMessage);}

一般來說,需要將 C# 對象序列化成包含 JSON 格式對象的字節(jié)數(shù)組(見 AzureHelpers 子文件夾中的 MessageHelper 靜態(tài)類):

publicstaticMessage Serialize( objectobj){ ArgumentCheck.IsNull(obj, "obj"); varjsonData = JsonConvert.SerializeObject(obj); returnnewMessage(Encoding.UTF8.GetBytes(jsonData));}

然后,將生成的數(shù)組包裝到 Message 類中,以使用 DeviceClient 類實例的 SendEventAsync 方法將其發(fā)送到云中。

Message 類是對象,為原始數(shù)據(jù)(傳輸?shù)?JSON 對象)補充了其他屬性。這些屬性用于跟蹤設(shè)備與 IoT 中心之間發(fā)送的消息。

在 RemoteCamera 應(yīng)用中,與云建立連接和發(fā)送設(shè)備信息是通過“云”選項卡上的兩個按鈕觸發(fā)的: “連接和初始化”和“發(fā)送設(shè)備信息”。第一個按鈕的 click 事件處理程序綁定到 RemoteCameraViewModel 的 Connect 方法:

publicasyncTask Connect(){ awaitCloudHelper.Initialize(); IsConnected = true}

第二個按鈕的 click 事件處理程序與 CloudHelper 類實例的 SendDeviceInfo 方法相關(guān)聯(lián)。此方法前面介紹過。

連入云后,還可以開始發(fā)送遙測數(shù)據(jù),與發(fā)送設(shè)備信息相似。也就是說,可以使用 SendMessage 方法,向其傳遞遙測對象。在本文中,此對象是 TelemetryData 類的實例,只有一個屬性 Brightness。

下面的完整示例展示了如何將遙測數(shù)據(jù)發(fā)送到云中,具體是在 CloudHelper 類的 SendBrightness 方法內(nèi)實現(xiàn):

publicasyncvoidSendBrightness( bytebrightness){ if(IsInitialized) { // Construct TelemetryDatavartelemetryData = newTelemetryData() { Brightness = brightness }; // Serialize TelemetryData and send it to the cloudawaitSendMessage(telemetryData); }}

在獲取 ImageProcessor 計算的亮度后,便會立即調(diào)用 SendBrightness。ProcessingDone 事件處理程序負責執(zhí)行此操作:

privatevoidImageProcessor_ProcessingDone( objectsender, ImageProcessorEventArgs e){ // Update display through dispatcherDisplayBrightness(e.Brightness); // Send telemetryif(remoteCameraViewModel.IsTelemetryActive) { remoteCameraViewModel.CloudHelper.SendBrightness(e.Brightness); }}

因此,如果現(xiàn)在運行 RemoteCamera 應(yīng)用,然后開始預覽并連接云,將會看到亮度值顯示

在相應(yīng)圖表中,如圖 1 所示。請注意,盡管預配置解決方案的仿真設(shè)備旨在以遙測數(shù)據(jù)形式發(fā)送溫度和濕度,但也可以發(fā)送其他值。在本文中,我將發(fā)送亮度,它會自動顯示在相應(yīng)圖表中。

處理遠程命令

CloudHelper 類還實現(xiàn)方法來處理從云中收到的遠程命令。同樣,與 ImageProcessor 一樣,我是在后臺處理命令(見 CloudHelper 類的 BeginRemoteCommandHandling)。

我將再次使用基于任務(wù)的異步模式:

privatevoidBeginRemoteCommandHandling(){ Task.Run( async() => { while( true) { varmessage = awaitdeviceClient.ReceiveAsync(); if(message != null) { awaitHandleIncomingMessage(message); } } });}

此方法負責創(chuàng)建任務(wù)來持續(xù)分析從云終結(jié)點收到的消息。若要接收遠程消息,請調(diào)用 DeviceClient 類的 ReceiveAsync 方法。

ReceiveAsync 返回 Message 類的實例,可用于獲取包含 JSON 格式遠程命令數(shù)據(jù)的原始字節(jié)數(shù)組。

然后,將此數(shù)組反序列化成 RemoteCommand 對象(見 AzureHelpers 文件夾中的 RemoteCommand.cs),具體是在 MessageHelper 類(見 AzureHelpers 子文件夾)中進行實現(xiàn):

publicstaticRemoteCommand Deserialize(Message message){ ArgumentCheck.IsNull(message, "message"); varjsonData = Encoding.UTF8.GetString(message.GetBytes()); returnJsonConvert.DeserializeObject( jsonData);}

雖然 RemoteCommand 包含多個屬性,但通常只使用以下兩個:名稱和參數(shù)(其中包含命令名稱和命令參數(shù))。在 RemoteCamera 應(yīng)用中,我使用這些值來確定是否按預期接收到了命令(見圖 11)。

如果收到,我會觸發(fā) UpdateCameraPreviewCommandReceived 事件,將相應(yīng)信息傳遞給偵聽器,然后我會使用 DeviceClient 類的 CompleteAsync 方法,通知云已收到命令。

如果命令無法識別,我會使用 RejectAsync 方法拒絕接收。

圖 11:遠程消息反序列化和分析

privateasyncTask HandleIncomingMessage(Message message){ try{ // Deserialize message to remote commandvarremoteCommand = MessageHelper.Deserialize(message); // Parse commandParseCommand(remoteCommand); // Send confirmation to the cloudawaitdeviceClient.CompleteAsync(message); } catch(Exception ex) { Debug.WriteLine(ex.Message); // Reject message, if it was not parsed correctlyawaitdeviceClient.RejectAsync(message); }} privatevoidParseCommand(RemoteCommand remoteCommand){ // Verify remote command nameif( string.Compare(remoteCommand.Name, CommandHelper.CameraPreviewCommandName) == 0) { // Raise an event, when the valid command was receivedUpdateCameraPreviewCommandReceived( this, newUpdateCameraPreviewCommandEventArgs( remoteCommand.Parameters.IsPreviewActive)); }}

UpdateCameraPreviewCommandReceived 事件是在 MainPage 類中進行處理。我會停止或啟動本地攝像頭預覽,具體視我通過遠程命令獲取的參數(shù)值而定。此操作會再次分派給 UI 線程,如圖 12 所示。

圖 12:更新攝像頭預覽

privateasyncvoidCloudHelper_UpdateCameraPreviewCommandReceived( objectsender, UpdateCameraPreviewCommandEventArgs e){ if(Dispatcher.HasThreadAccess) { if(e.IsPreviewActive) { awaitremoteCameraViewModel.PreviewStart(); } else{ awaitremoteCameraViewModel.PreviewStop(); } } else{ awaitDispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { CloudHelper_UpdateCameraPreviewCommandReceived(sender, e); }); }}

從云發(fā)送命令

最后,我將介紹可用于遠程控制 IoT 設(shè)備的解決方案門戶。為此,請使用“設(shè)備”選項卡,需要在其中查找并單擊相應(yīng)設(shè)備(見圖 13)。

  圖 13:顯示 RemoteCamera 詳細信息的 IoT 門戶“設(shè)備”選項卡

這會激活設(shè)備詳細信息窗格,可以在其中單擊“命令”超鏈接。然后,將看到另一個窗體,用于選擇并發(fā)送遠程命令。

此窗體的具體布局取決于所選擇的命令。在本文中,我只有一個參數(shù)命令,因此只有一個復選框。如果取消選中此復選框并發(fā)送命令,RemoteCamera 應(yīng)用便會停止預覽。發(fā)送的所有命令及其狀態(tài)顯示在命令歷史記錄中,如圖 14 所示。

  圖 14:用于向 IoT 設(shè)備發(fā)送遠程命令的窗體

總結(jié)

我介紹了如何設(shè)置遠程監(jiān)視 Azure IoT 套件預配置解決方案。此解決方案可收集并顯示與遠程設(shè)備連接的攝像頭采集的圖像相關(guān)信息,并能遠程控制 IoT 設(shè)備。

隨附的源代碼可以在任意 UWP 設(shè)備上運行,因此無需真正將它部署到 Raspberry Pi。本文以及遠程監(jiān)視解決方案的聯(lián)機文檔和源代碼將有助于快速啟動綜合 IoT 開發(fā),以實現(xiàn)實用的遠程監(jiān)視。可以看到,借助 Windows 10 IoT 核心版,可實現(xiàn)的遠不止讓 LED 燈閃爍那么簡單。

Dawid Borycki 是軟件工程師、生物醫(yī)學研究員、作家和會議演講者。他喜歡學習有關(guān)軟件實驗和原型設(shè)計的新技術(shù)。

衷心感謝以下 Microsoft 技術(shù)專家對本文的審閱: Rachel Appel

 

鏈接已復制,快去分享吧

企業(yè)網(wǎng)版權(quán)所有?2010-2024 京ICP備09108050號-6京公網(wǎng)安備 11010502049343號

  • <menuitem id="jw4sk"></menuitem>

    1. <form id="jw4sk"><tbody id="jw4sk"><dfn id="jw4sk"></dfn></tbody></form>
      主站蜘蛛池模板: 桂阳县| 聂拉木县| 永定县| 山东省| 都匀市| 偏关县| 奉新县| 赤壁市| 盈江县| 商都县| 玛沁县| 淮南市| 壶关县| 元谋县| 沂源县| 伽师县| 遂川县| 祥云县| 焉耆| 绥德县| 江门市| 阿克苏市| 定结县| 台中县| 巴林左旗| 牡丹江市| 开封县| 佛冈县| 会同县| 潜江市| 淮安市| 滨海县| 巨鹿县| 阿克苏市| 桃园市| 武穴市| 敦煌市| 介休市| 天峨县| 云龙县| 武邑县|