版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、 Azure IoT 物联网解决方案套件介绍微软中国MSDN 微信号 cnmsdn功能介绍 微软中国MSDN开发社区官方微信。物联网 (IoT) 解决方案包括远程遥测设备、Web 门户、云存储和实时处理功能。结构如此复杂,你就更不愿意开始进行 IoT 开发了。为了简化工作,Microsoft Azure IoT 套件提供了以下两个预配置解决方案:远程监视和预测性维护。本文将介绍如何创建远程监视解决方案,从而收集和分析 Windows 10 IoT 核心版控制的远程 IoT 设备中的数据。此 Raspberry Pi 设备将通过 USB 摄像头采集图像。随后,图像亮度会在 IoT 设备上进行计算
2、,然后流式传输到云中,并在云中进行存储、处理和显示(见图 1)。此外,最终用户不仅可以查看通过远程设备采集的信息,还能远程控制相应设备。有关辅助此论述的完整源代码,请访问/magazine/0617magcode图 1:Azure IoT 套件预配置解决方案门户,以及用于采集并处理视频流的远程通用 Windows 平台应用远程设备Frank LaVigne (/magazine/mt694090) 和 Bruno Sonnino (/magazine/mt808503) 已在本杂志中介绍过在安装了 Windows 10 IoT 核心版的 Raspberry Pi 上进行编程的基础知识。LaVi
3、gne 和 Sonnino 介绍了如何设置开发环境和 IoT 开发板、如何在浏览器中使用设备门户配置 IoT 单元,以及如何使用 Windows 10 IoT 核心版控制 GPIO 端口。此外,LaVigne 还在他的文章中提到,可以使用 IoT 对远程摄像头进行编程和控制。在本文中,我扩展了这一想法,并明确介绍了如何将 Raspberry Pi 变成这样的设备。为此,我使用空白应用(通用 Windows)Visual C# 项目模板创建了 RemoteCamera 通用 Windows 平台 (UWP) 应用,然后将目标和最低 API 版本设置为 Windows 10 周年版本(10.0;生
4、成号 14393)。我使用此 API 版本是为了能够绑定到方法,从而直接将视图模型的方法与可视控件触发的事件相关联:接下来,我声明了 UI,如图 1所示。有两个选项卡: “摄像头捕捉”和“云”。第一个选项卡中的控件可用于启动或停止摄像头预览、显示视频流并呈现图像亮度(标签和进度栏)。第二个选项卡中有两个按钮,分别用于将设备连入云中,以及在 IoT 门户中注册设备。“云”选项卡还包含一个复选框,用于启用流式传输遥测数据。与 UI 相关联的大部分逻辑是在 RemoteCameraViewModel 类(见 RemoteCamera 项目的 ViewModels 子文件夹)中实现。除了实现一些与 U
5、I 绑定的属性之外,此类还负责处理视频采集、图像处理和云交互。这些子功能分别是在以下各个类中实现: CameraCapture、ImageProcessor 和 CloudHelper。我很快将会介绍 CameraCapture 和 ImageProcessor,而 CloudHelper 及相关帮助程序类则稍后将在 Azure IoT 预配置解决方案上下文中进行介绍。相机捕捉摄像头捕捉(见 Helpers 文件夹下的 CameraCapture.cs)是在以下两个元素的基础之上生成: Windows.Media.Capture.MediaCapture class 和 Windows.UI.
6、Xaml.Controls.CaptureElement。前者用于采集视频,而后者则用于显示采集的视频流。由于使用摄像头采集视频,因此必须在 Package.appxmanifest 中声明相应的设备功能。若要初始化 MediaCapture 类,请调用 InitializeAsync 方法。最终,可以向此方法传递 MediaCaptureInitializationSettings 类的实例,从而指定捕捉选项。可以选择是流式传输视频还是音频,并选择捕捉硬件。在本文中,我仅通过默认摄像头采集视频(见图 2)。图 2:摄像头捕捉初始化public MediaCapture get; privat
7、e set; = new MediaCapture();public bool IsInitialized get; private set; = false;public async Task Initialize(CaptureElement captureElement) if (!IsInitialized) var settings = new MediaCaptureInitializationSettings() StreamingCaptureMode = StreamingCaptureMode.Video ; try await MediaCapture.Initializ
8、eAsync(settings); GetVideoProperties(); captureElement.Source = MediaCapture; IsInitialized = true; catch (Exception ex) Debug.WriteLine(ex.Message); IsInitialized = false; 接下来,使用 CaptureElement 类实例的 Source 属性,将此对象与 MediaCapture 控件相关联,以显示视频流。我还调用了帮助程序方法 GetVideoProperties,用于读取并存储视频帧的大小。稍后会使用此信息来获取预览
9、帧以供处理。最后,为了能够真正启动和停止视频采集,我调用了 MediaCapture 类的 StartPreviewAsync 和 StopPreviewAsync。在 CameraCapture 中,我使用其他逻辑包装了这些方法,同时验证了初始化和预览状态:public async Task Start() if (IsInitialized) if (!IsPreviewActive) await MediaCapture.StartPreviewAsync(); IsPreviewActive = true; 运行应用时,可以按“开始预览”按钮来配置摄像头采集,之后不久就可以看到摄像头图
10、像。请注意,由于 RemoteCamera 应用是通用应用,因此无需进行任何更改,即可部署到开发 PC、智能手机、平板电脑或 Raspberry Pi。如果使用 Windows 10 PC 测试 RemoteCamera 应用,需要确保应用可使用摄像头。可以使用“设置”应用(“隐私”/“摄像头”)来配置此设置。为了使用 Raspberry Pi 测试此应用,我使用了预算较低的 Microsoft Life Cam HD-3000。由于这是一个 USB 摄像头,因此,当我将它连到四个 Raspberry Pi USB 端口之一后,Windows 10 IoT 核心版可以自动检测到摄像头。有关与
11、Windows 10 IoT 核心版兼容的摄像头的完整列表,请访问bit.ly/2p1ZHGD。将摄像头与 Rasbperry Pi 相连后,它显示在“设备门户”的“设备”选项卡下。图像处理器ImageProcessor 类在后台计算当前帧的亮度。为了执行后台操作,我使用基于任务的异步模式创建了线程,如图 3所示。图 3:在后台计算亮度public event EventHandler ProcessingDone;private void InitializeProcessingTask() processingCancellationTokenSource = new Cancellati
12、onTokenSource(); processingTask = new Task(async () = while (!processingCancellationTokenSource.IsCancellationRequested) if (IsActive) var brightness = await GetBrightness(); ProcessingDone(this, new ImageProcessorEventArgs(brightness); Task.Delay(delay).Wait(); , processingCancellationTokenSource.T
13、oken);在 while 循环中,我确定了图像亮度,然后将此值传递给 ProcessingDone 事件的侦听器。系统向此事件馈送 ImageProcessorEventArgs 类的实例,其中只有一个公共属性 Brightness。在收到取消信号前,处理任务会一直运行。图像处理的关键元素是 GetBrightness 方法,如图 4所示。图 4:GetBrightness 方法private async Task GetBrightness() var brightness = new byte(); if (cameraCapture.IsPreviewActive) / Get cur
14、rent preview bitmap var previewBitmap = await cameraCapture.GetPreviewBitmap(); / Get underlying pixel data var pixelBuffer = GetPixelBuffer(previewBitmap); / Process buffer to determine mean gray value (brightness) brightness = CalculateMeanGrayValue(pixelBuffer); return brightness;我使用 CameraCaptur
15、e 类实例的 GetPreviewBitmap 来获取预览帧。在内部,GetPreviewBitmap 使用 MediaCapture 类的 GetPreviewFrameAsync。GetPreviewFrameAsync 有两个版本。第一个版本是无参数方法,返回的是 VideoFrame 类的实例。在这种情况下,可以通过读取 Direct3DSurface 属性来获取实际的像素数据。第二个版本接受 VideoFrame 类的实例,并将像素数据复制到其 SoftwareBitmap 属性中。在本文中,我使用第二个选项(见 CameraCapture 类的 GetPreviewBitmap 方
16、法),然后通过 SoftwareBitmap 类实例的 CopyToBuffer 方法访问像素数据(如图 5所示)。图 5:访问像素数据private byte GetPixelBuffer(SoftwareBitmap softwareBitmap) / Ensure bitmap pixel format is Bgra8 if (softwareBitmap.BitmapPixelFormat != CameraCapture.BitmapPixelFormat) SoftwareBitmap.Convert(softwareBitmap, CameraCapture.BitmapPix
17、elFormat); / Lock underlying bitmap buffer var bitmapBuffer = softwareBitmap.LockBuffer(BitmapBufferAccessMode.Read); / Use plane description to determine bitmap height / and stride (the actual buffer width) var planeDescription = bitmapBuffer.GetPlaneDescription(0); var pixelBuffer = new byteplaneD
18、escription.Height * planeDescription.Stride; / Copy pixel data to a buffer softwareBitmap.CopyToBuffer(pixelBuffer.AsBuffer(); return pixelBuffer;首先,我将确认像素格式是否为 BGRA8。此像素格式表示图像使用四个 8 位通道:三个通道分别用于表示蓝色、绿色和红色,另外一个通道用于表示 alpha 或透明度。如果输入位图采用其他像素格式,我会执行相应的转换。接下来,我将把像素数据复制到字节数组中,其大小由图像高度与图像步幅的乘积决定 (bit.ly/
19、2om8Ny9)。我从 BitmapPlaneDescription 实例中读取这两个值,此实例是通过 SoftwareBitmap.LockBuffer 方法返回的 BitmapBuffer 对象获取而来。鉴于字节数组包含像素数据,只需计算所有像素的平均值即可。因此,我循环访问了像素缓存(见图 6)。图 6:计算像素的平均值private byte CalculateMeanGrayValue(byte pixelBuffer) / Loop index increases by four since / there are four channels (blue, green, red a
20、nd alpha). / Alpha is ignored for brightness calculation const int step = 4; double mean = 0.0; for (uint i = 0; i DisplayBrightness(brightness); ); 预配远程监视解决方案若要预配解决方案,可以使用专用门户 ()。登录并选择 Azure 订阅后,便会重定向到一个页面,可以在其中按“创建新的解决方案”矩形框。这会打开一个网站,可以在其中选择两个预配置解决方案之一:预测性维护或远程监视(见图 8)。选择解决方案后,将会看到另一个窗体,可以在其中设置 Az
21、ure 资源的解决方案名称和区域。在本文中,我将解决方案名称和区域分别设置为“RemoteCameraMonitoring”和“美国西部”。图 8:Azure IoT 套件预配置解决方案(上)和远程监视解决方案配置(下)预配远程监视解决方案时,Azure IoT 套件门户会创建以下多个 Azure 资源: IoT 中心、流分析作业、存储和 App Service。IoT 中心可实现云和远程设备之间的双向通信。流分析作业会转换远程设备流式传输的数据,通常是筛选掉不必要的数据。筛选后的数据会进行存储或定向,以供将来分析时使用。最后,App Service 用于托管 Web 门户。也可以通过命令行完
22、成解决方案预配。为此,可以从bit.ly/2osI4RW克隆或下载解决方案源代码,然后按照bit.ly/2p7MPPc中的说明操作。也可以视需要在本地部署解决方案,如bit.ly/2nEePNi所述。在这种情况下,不会创建 Azure App Service,因为解决方案门户是在本地计算机上运行。若要进行开发和调试或修改预配置解决方案,就会发现此类方法特别有用。完成预配后,可以启动解决方案,它的门户显示在默认浏览器中(再次见图 1)。此门户包含多个选项卡。在本文中,我将仅关注其中两个选项卡,即“仪表板”和“设备”。“仪表板”显示远程设备及其流式传输的遥测数据的映射。“设备”选项卡显示远程设备列
23、表,包括设备的状态、功能和说明。默认情况下,有多个仿真设备。我将介绍如何注册新的非仿真硬件。注册设备若要注册设备,请按解决方案门户中左下角的“添加设备”超链接。然后,选择添加仿真设备还是自定义设备。选取第二个选项,然后按“添加新设备”按钮。现在,可以定义“设备 ID”了。我将此值设置为“RemoteCamera”。此后,“添加自定义设备”窗体中显示设备凭据(见图 9),稍后用它将 IoT 设备连入 IoT 中心。图 9:设备注册摘要设备元数据和云通信添加的设备显示在设备列表中,然后便可以发送设备元数据或设备信息。设备信息包括描述远程设备的 JSON 对象。此对象可告知云终结点设备功能,并包含硬
24、件描述以及设备接受的远程命令列表。最终用户可通过 IoT 解决方案门户向设备发送这些命令。在 RemoteCamera 应用中,设备信息表示为 DeviceInfo 类(位于 AzureHelpers 子文件夹中):public class DeviceInfo public bool IsSimulatedDevice get; set; public string Version get; set; public string ObjectType get; set; public DeviceProperties DeviceProperties get; set; public Com
25、mand Commands get; set; DeviceInfo 的前两个属性指定了是否为仿真设备,并定义了 DeviceInfo 对象的版本。稍后可以看到,第三个属性 ObjectType 被设置为字符串常数 DeviceInfo。云(特别是 Azure 流分析作业)使用此字符串从遥测数据中筛选出设备信息。接下来,DeviceProperties(见 AzureHelpers 子文件夹)包含一系列描述设备的属性(如序列号、内存、平台、RAM)。最后,Commands 属性包含设备识别的一系列远程命令。通过指定名称和参数列表(分别由 Command 和 CommandParameter 类
26、表示,见 AzureHelpersCommand.cs),可定义每个命令。若要在 IoT 设备和 IoT 中心之间建立通信,请使用 Microsoft.Azure.Devices.Client NuGet 包。此包提供 DeviceClient 类,可用于向云发送消息和接收云消息。可以使用 Create 或 CreateFromConnectionString 静态方法,创建 DeviceClient 实例。在本文中,我使用第一个选项(见 AzureHelpers 文件夹中的 CloudHelper.cs):public async Task Initialize() if (!IsIniti
27、alized) deviceClient = DeviceClient.Create( Configuration.Hostname, Configuration.AuthenticationKey(); await deviceClient.OpenAsync(); IsInitialized = true; BeginRemoteCommandHandling(); 可以看到,若要使用 DeviceClient.Create 方法,需要提供 IoT 中心的主机名和设备凭据(标识符和密钥)。这些值是在设备预配期间从解决方案门户获取(再次见图 9)。在 RemoteCamera 应用中,我在
28、Configuration 静态类中存储了主机名、设备 ID 和密钥:public static class Configuration public static string Hostname get; = .; public static string DeviceId get; = RemoteCamera; public static string DeviceKey get; = ; public static DeviceAuthenticationWithRegistrySymmetricKey AuthenticationKey() return new DeviceAuth
29、enticationWithRegistrySymmetricKey(DeviceId, DeviceKey); 此外,Configuration 类还会实现静态方法 AuthenticationKey,从而将设备凭据包装到 DeviceAuthenticationWithRegistrySymmetricKey 类的实例中。我借此来简化 DeviceClient 类实例的创建工作。连接建立后,只需发送 DeviceInfo 即可,如图 10所示。图 10:发送设备信息public async Task SendDeviceInfo() var deviceInfo = new DeviceI
30、nfo() IsSimulatedDevice = false, ObjectType = DeviceInfo, Version = 1.0, DeviceProperties = new DeviceProperties(Configuration.DeviceId), / Commands collection Commands = new Command CommandHelper.CreateCameraPreviewStatusCommand() ; await SendMessage(deviceInfo);RemoteCamera 应用可发送描述实际硬件的设备信息,因此 IsS
31、imulatedDevice 属性设置为 false。如上所述,ObjectType 设置为 DeviceInfo。此外,我还将 Version 属性设置为 1.0。对于 DeviceProperties,我使用的是任意值,主要包括静态字符串(见 DeviceProperties 类的 SetDefaultValues 方法)。我还定义了远程命令“更新摄像头预览”,以便能够远程控制摄像头预览。此命令包含一个布尔参数 IsPreviewActive,用于指定应启动还是停止摄像头预览(见 AzureHelpers 文件夹下的 CommandHelper.cs 文件)。为了能够真正将数据发送到云中,
32、我实现了 SendMessage 方法:private async Task SendMessage(Object message) var serializedMessage = MessageHelper.Serialize(message); await deviceClient.SendEventAsync(serializedMessage);一般来说,需要将 C# 对象序列化成包含 JSON 格式对象的字节数组(见 AzureHelpers 子文件夹中的 MessageHelper 静态类):public static Message Serialize(object obj) A
33、rgumentCheck.IsNull(obj, obj); var jsonData = JsonConvert.SerializeObject(obj); return new Message(Encoding.UTF8.GetBytes(jsonData);然后,将生成的数组包装到 Message 类中,以使用 DeviceClient 类实例的 SendEventAsync 方法将其发送到云中。Message 类是对象,为原始数据(传输的 JSON 对象)补充了其他属性。这些属性用于跟踪设备与 IoT 中心之间发送的消息。在 RemoteCamera 应用中,与云建立连接和发送设备信息
34、是通过“云”选项卡上的两个按钮触发的: “连接和初始化”和“发送设备信息”。第一个按钮的 click 事件处理程序绑定到 RemoteCameraViewModel 的 Connect 方法:public async Task Connect() await CloudHelper.Initialize(); IsConnected = true;第二个按钮的 click 事件处理程序与 CloudHelper 类实例的 SendDeviceInfo 方法相关联。此方法前面介绍过。连入云后,还可以开始发送遥测数据,与发送设备信息相似。也就是说,可以使用 SendMessage 方法,向其传递遥
35、测对象。在本文中,此对象是 TelemetryData 类的实例,只有一个属性 Brightness。下面的完整示例展示了如何将遥测数据发送到云中,具体是在 CloudHelper 类的 SendBrightness 方法内实现:public async void SendBrightness(byte brightness) if (IsInitialized) / Construct TelemetryData var telemetryData = new TelemetryData() Brightness = brightness ; / Serialize TelemetryDat
36、a and send it to the cloud await SendMessage(telemetryData); 在获取 ImageProcessor 计算的亮度后,便会立即调用 SendBrightness。ProcessingDone 事件处理程序负责执行此操作:private void ImageProcessor_ProcessingDone(object sender, ImageProcessorEventArgs e) / Update display through dispatcher DisplayBrightness(e.Brightness); / Send t
37、elemetry if (remoteCameraViewModel.IsTelemetryActive) remoteCameraViewModel.CloudHelper.SendBrightness(e.Brightness); 因此,如果现在运行 RemoteCamera 应用,然后开始预览并连接云,将会看到亮度值显示在相应图表中,如图 1所示。请注意,尽管预配置解决方案的仿真设备旨在以遥测数据形式发送温度和湿度,但也可以发送其他值。在本文中,我将发送亮度,它会自动显示在相应图表中。处理远程命令CloudHelper 类还实现方法来处理从云中收到的远程命令。同样,与 ImageProc
38、essor 一样,我是在后台处理命令(见 CloudHelper 类的 BeginRemoteCommandHandling)。我将再次使用基于任务的异步模式:private void BeginRemoteCommandHandling() Task.Run(async () = while (true) var message = await deviceClient.ReceiveAsync(); if (message != null) await HandleIncomingMessage(message); );此方法负责创建任务来持续分析从云终结点收到的消息。若要接收远程消息,请
39、调用 DeviceClient 类的 ReceiveAsync 方法。ReceiveAsync 返回 Message 类的实例,可用于获取包含 JSON 格式远程命令数据的原始字节数组。然后,将此数组反序列化成 RemoteCommand 对象(见 AzureHelpers 文件夹中的 RemoteCommand.cs),具体是在 MessageHelper 类(见 AzureHelpers 子文件夹)中进行实现:public static RemoteCommand Deserialize(Message message) ArgumentCheck.IsNull(message, mess
40、age); var jsonData = Encoding.UTF8.GetString(message.GetBytes(); return JsonConvert.DeserializeObject( jsonData);虽然 RemoteCommand 包含多个属性,但通常只使用以下两个:名称和参数(其中包含命令名称和命令参数)。在 RemoteCamera 应用中,我使用这些值来确定是否按预期接收到了命令(见图 11)。如果收到,我会触发 UpdateCameraPreviewCommandReceived 事件,将相应信息传递给侦听器,然后我会使用 DeviceClient 类的 C
41、ompleteAsync 方法,通知云已收到命令。如果命令无法识别,我会使用 RejectAsync 方法拒绝接收。图 11:远程消息反序列化和分析private async Task HandleIncomingMessage(Message message) try / Deserialize message to remote command var remoteCommand = MessageHelper.Deserialize(message); / Parse command ParseCommand(remoteCommand); / Send confirmation to the cloud await deviceClient.CompleteAsync(message); catch (Exception ex) Debug.WriteLine(ex.Message); / Reject message, if it was not parsed correctly await deviceClient.RejectAsync(message); private
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 施工现场安全预防措施
- 公司员工年会迟到检讨书
- 食品加工厂环氧地坪施工方案
- 吉安职业技术学院《adobephotoshop图像处理》2023-2024学年第一学期期末试卷
- 吉林大学《地球物理学》2023-2024学年第一学期期末试卷
- 惠州学院《聚合物表征》2023-2024学年第一学期期末试卷
- 惠州工程职业学院《视觉传达与编拍设计》2023-2024学年第一学期期末试卷
- 婚姻财产协商协议书
- 铁路沿线场地硬化施工方案
- 污水处理厂电气接地施工方案
- 银行消保知识培训总结
- 首尾件检查作业指导书
- 第七章-卡方检验
- 思想道德与法治考试题库及答案2021
- 乙状结肠癌学习课件
- DB11T 381-2023 既有居住建筑节能改造技术规程
- 锂电池回收项目投资计划书
- 热网系统培训资料
- 新闻摄影培训
- 蔬菜、副食品配送服务投标方案(技术方案)
- 重庆市2022-2023学年六年级上学期语文期末试卷(含答案)
评论
0/150
提交评论