你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
向设备更新注册组件
本文介绍 Device Update for IoT Hub 组件枚举器的示例实现。 可以参考此示例来实现 IoT 设备的自定义组件枚举器。 组件是设备级别下的标识,与主机设备具有构成关系。
本文演示了使用名为 Contoso Virtual Vacuum 的虚拟 IoT 设备的组件枚举器。 组件枚举器用于实现代理更新功能。
通过代理更新,可使用单个无线部署在连接到 IoT 设备的同一 IoT 设备或多个传感器上更新多个组件。 代理更新支持用于更新组件的安装顺序。 它还支持具有预安装、安装和安装后功能的多步更新。
代理更新适用的用例包括:
- 将特定更新文件的目标指定为设备上的分区。
- 将特定更新文件定位到设备上的应用或组件。
- 将特定的更新文件定位到通过网络协议(例如 USB 或 CAN 总线)连接到 IoT 设备的传感器。
有关详细信息,请参阅代理更新和多组件更新。
设备更新代理在主机设备上运行。 它可以将每个更新发送到一个特定组件或同一硬件类型的一组组件(即需要相同的软件或固件更新)。
什么是组件枚举器?
组件枚举器是一种设备更新代理扩展,它提供有关通过主机设备的 Azure IoT 中心连接实现无线更新所需的每个组件的信息。
设备更新代理与设备和组件无关。 代理本身在更新时并不知道主机设备上或连接到主机设备的组件的信息。
若要启用代理更新,设备生成器必须识别设备上的所有可更新组件,并为每个组件指定唯一名称。 此外,可以将组名称分配给同一硬件类型的组件,以便可以将同一更新安装到同一个组中的所有组件上。 然后,更新内容处理程序可以安装更新并将其应用到正确的组件。
代理更新流的每个部分的职责如下:
设备制造商
设计和生成设备。
集成设备更新代理及其依赖项。
实现设备特定的组件枚举器扩展,并向设备更新代理注册。
组件枚举器使用组件清单或配置文件中的信息,通过动态数据(例如固件版本、连接状态和硬件标识)来补充静态组件数据(需要设备更新)。
创建一个代理更新,其中包含一个或多个针对设备上或连接到设备的一个或多个组件的子更新。
将更新发送到解决方案操作员。
解决方案操作员
将更新和清单导入到设备更新服务。
将更新部署到一组设备。
设备更新代理
通过设备孪生或模块孪生从 IoT 中心获取更新信息。
调用步骤处理程序来处理适用于设备上的一个或多个组件的代理更新。
本文中的示例有两个更新:
host-fw-1.1
和motors-fw-1.1
。 对于每个子更新,父步骤处理程序将调用子步骤处理程序,以枚举与子更新的清单文件中指定的Compatibilities
属性匹配的所有组件。 接下来,处理程序将下载、安装子更新并将其应用于所有目标组件。为了获取匹配组件,子更新会调用组件枚举器提供的
SelectComponents
API。 如果没有匹配的组件,则会跳过子更新。收集来自父更新和子更新的所有更新结果,并将这些结果报告给 IoT 中心。
子步骤处理程序
- 循环访问与子更新内容兼容的组件实例的列表。 有关详细信息,请参阅步骤处理程序。
在生产环境中,设备构建者可以使用现有的处理程序或实现一个自定义处理程序,用于调用无线更新所需的安装程序。 有关详细信息,请参阅实现自定义更新内容处理程序。
Virtual Vacuum 组件
在本文中,我们使用虚拟 IoT 设备来演示关键概念和功能。 Contoso Virtual Vacuum 设备包含五个逻辑组件:
- 主机固件
- 主机启动文件系统
- 主机根文件系统
- 三个电机(左轮、右轮和真空)
- 两个相机(正面和背面)
以下目录结构模拟组件:
/usr/local/contoso-devices/vacuum-1/hostfw
/usr/local/contoso-devices/vacuum-1/bootfs
/usr/local/contoso-devices/vacuum-1/rootfs
/usr/local/contoso-devices/vacuum-1/motors/0 /* left motor */
/usr/local/contoso-devices/vacuum-1/motors/1 /* right motor */
/usr/local/contoso-devices/vacuum-1/motors/2 /* vacuum motor */
/usr/local/contoso-devices/vacuum-1/cameras/0 /* front camera */
/usr/local/contoso-devices/vacuum-1/cameras/1 /* rear camera */
每个组件的目录都包含一个 JSON 文件,该文件存储每个组件的模拟软件版本号。 示例 JSON 文件是 firmware.json 和 diskimage.json。
在此演示中,为了更新组件固件,我们会将 firmware.json 或 diskimage.json(更新有效负载)复制到目标组件目录。
以下是一个 firmware.json 示例文件:
{
"version": "0.5",
"description": "This component is generated for testing purposes."
}
注意
Contoso Virtual Vacuum 包含用于演示代理更新的软件或固件版本。 它不提供任何其他功能。
实现组件枚举器(C 语言)
要求
实现 component_enumerator_extension.hpp 中声明的所有 API:
函数 | 自变量 | 返回 |
---|---|---|
char* GetAllComponents() |
无 | 一个 JSON 字符串,其中包含一系列 所有ComponentInfo 值。 有关详细信息,请参阅示例返回值。 |
char* SelectComponents(char* selector) |
一个 JSON 字符串,其中包含用于选择更新目标组件的一个或多个名称/值对 | 一个 JSON 字符串,其中包含一系列 ComponentInfo 值。 有关详细信息,请参阅示例返回值。 |
void FreeComponentsDataString(char* string) |
指向之前由 GetAllComponents 或 SelectComponents 函数返回的字符串缓冲区的指针 |
无 |
ComponentInfo
ComponentInfo
JSON 字符串必须包含以下属性:
名称 | Type | 说明 |
---|---|---|
id |
string | 组件的唯一标识(设备范围)。 示例包括硬件序列号、磁盘分区 ID 以及组件的唯一文件路径。 |
name |
string | 组件的逻辑名称。 此属性是设备生成器分配给同一 device 类型的每个设备中可用的组件的名称。例如,每个 Contoso Virtual Vacuum 设备都包含一个用于驱动左轮的电动机。 Contoso 将“左电机”指定为该电机的通用(逻辑)名称,以便指代该组件,而不是使用硬件 ID(这可能具有全局唯一性)。 |
group |
string | 此组件所属的组。 例如,所有电机都可能属于“电机”组。 |
manufacturer |
string | 对于物理硬件组件,此属性是制造商或供应商名称。 对于逻辑组件(如磁盘分区或目录),它可以是任何设备生成器的定义值。 |
model |
string | 对于物理硬件组件,此属性是一个型号名称。 对于逻辑组件(如磁盘分区或目录),此属性可以是任何设备生成器的定义值。 |
properties |
object | 包含任何可选设备特定属性的 JSON 对象。 |
下面是基于 Contoso Virtual Vacuum 组件的 ComponentInfo
代码示例:
{
"id": "contoso-motor-serial-00000",
"name": "left-motor",
"group": "motors",
"manufacturer": "contoso",
"model": "virtual-motor",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/0",
"firmwareDataFile": "firmware.json",
"status": "connected",
"version" : "motor-fw-1.0"
}
}
示例返回值
下面是从 GetAllComponents
函数返回的 JSON 文档。 它基于 Contoso Virtual Vacuum 组件枚举器的示例实现。
{
"components": [
{
"id": "hostfw",
"name": "hostfw",
"group": "firmware",
"manufacturer": "contoso",
"model": "virtual-firmware",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/hostfw",
"firmwareDataFile": "firmware.json",
"status": "ok",
"version" : "host-fw-1.0"
}
},
{
"id": "bootfs",
"name": "bootfs",
"group": "boot-image",
"manufacturer": "contoso",
"model": "virtual-disk",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/bootfs",
"firmwareDataFile": "diskimage.json",
"status": "ok",
"version" : "boot-fs-1.0"
}
},
{
"id": "rootfs",
"name": "rootfs",
"group": "os-image",
"manufacturer": "contoso",
"model": "virtual-os",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/rootfs",
"firmwareDataFile": "diskimage.json",
"status": "ok",
"version" : "root-fs-1.0"
}
},
{
"id": "contoso-motor-serial-00000",
"name": "left-motor",
"group": "motors",
"manufacturer": "contoso",
"model": "virtual-motor",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/0",
"firmwareDataFile": "firmware.json",
"status": "ok",
"version" : "motor-fw-1.0"
}
},
{
"id": "contoso-motor-serial-00001",
"name": "right-motor",
"group": "motors",
"manufacturer": "contoso",
"model": "virtual-motor",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/1",
"firmwareDataFile": "firmware.json",
"status": "ok",
"version" : "motor-fw-1.0"
}
},
{
"id": "contoso-motor-serial-00002",
"name": "vacuum-motor",
"group": "motors",
"manufacturer": "contoso",
"model": "virtual-motor",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/2",
"firmwareDataFile": "firmware.json",
"status": "ok",
"version" : "motor-fw-1.0"
}
},
{
"id": "contoso-camera-serial-00000",
"name": "front-camera",
"group": "cameras",
"manufacturer": "contoso",
"model": "virtual-camera",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/camera\/0",
"firmwareDataFile": "firmware.json",
"status": "ok",
"version" : "camera-fw-1.0"
}
},
{
"id": "contoso-camera-serial-00001",
"name": "rear-camera",
"group": "cameras",
"manufacturer": "contoso",
"model": "virtual-camera",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/camera\/1",
"firmwareDataFile": "firmware.json",
"status": "ok",
"version" : "camera-fw-1.0"
}
}
]
}
以下 JSON 文档是从 SelectComponents
函数返回的。 它基于 Contoso 组件枚举器的示例实现。
下面是用于选择“电机”组件组的输入参数:
{
"group" : "motors"
}
下面是参数的输出。 所有组件都属于“电机”组。
{
"components": [
{
"id": "contoso-motor-serial-00000",
"name": "left-motor",
"group": "motors",
"manufacturer": "contoso",
"model": "virtual-motor",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/0",
"firmwareDataFile": "firmware.json",
"status": "ok",
"version" : "motor-fw-1.0"
}
},
{
"id": "contoso-motor-serial-00001",
"name": "right-motor",
"group": "motors",
"manufacturer": "contoso",
"model": "virtual-motor",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/1",
"firmwareDataFile": "firmware.json",
"status": "ok",
"version" : "motor-fw-1.0"
}
},
{
"id": "contoso-motor-serial-00002",
"name": "vacuum-motor",
"group": "motors",
"manufacturer": "contoso",
"model": "virtual-motor",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/2",
"firmwareDataFile": "firmware.json",
"status": "ok",
"version" : "motor-fw-1.0"
}
}
]
}
下面是用于选择名为“hostfw”的单个组件的输入参数:
{
"name" : "hostfw"
}
下面是 hostfw 组件的参数输出:
{
"components": [
{
"id": "hostfw",
"name": "hostfw",
"group": "firmware",
"manufacturer": "contoso",
"model": "virtual-firmware",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/hostfw",
"firmwareDataFile": "firmware.json",
"status": "ok",
"version" : "host-fw-1.0"
}
}
]
}
注意
前面的示例演示,如果需要可以向按 name
属性选择的组件的任何实例发送较新的更新。 例如,将 motor-fw-2.0
更新部署到 vacuum-motor,同时继续在 left-motor 和 right-motor 上使用 motor-fw-1.0
。
清单文件
前面针对 Contoso Virtual Vacuum 组件枚举器显示的示例实现将读取 component-inventory.json 文件中特定于设备的组件的信息。 此示例实现仅用于演示目的。
在生产场景中,应直接从实际组件检索某些属性。 这些属性包括 id
、manufacturer
和 model
。
设备生成器定义 name
和 group
属性。 这些值在定义后不应更改。 name
属性在设备中必须是唯一的。
component-inventory.json 示例文件
注意
此文件中的内容看起来与 GetAllComponents
函数返回的值几乎相同。 但是此文件中的 ComponentInfo
不包含 version
和 status
属性。 组件枚举器将在运行时填充这些属性。
例如,对于 hostfw,属性 properties.version
的值将从指定(模拟)firmwareDataFile
值 (/usr/local/contoso-devices/vacuum-1/hostfw/firmware.json) 填充。
{
"components": [
{
"id": "hostfw",
"name": "hostfw",
"group": "firmware",
"manufacturer": "contoso",
"model": "virtual-firmware",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/hostfw",
"firmwareDataFile": "firmware.json",
}
},
{
"id": "bootfs",
"name": "bootfs",
"group": "boot-image",
"manufacturer": "contoso",
"model": "virtual-disk",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/bootfs",
"firmwareDataFile": "diskimage.json",
}
},
{
"id": "rootfs",
"name": "rootfs",
"group": "os-image",
"manufacturer": "contoso",
"model": "virtual-os",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/rootfs",
"firmwareDataFile": "diskimage.json",
}
},
{
"id": "contoso-motor-serial-00000",
"name": "left-motor",
"group": "motors",
"manufacturer": "contoso",
"model": "virtual-motor",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/0",
"firmwareDataFile": "firmware.json",
}
},
{
"id": "contoso-motor-serial-00001",
"name": "right-motor",
"group": "motors",
"manufacturer": "contoso",
"model": "virtual-motor",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/1",
"firmwareDataFile": "firmware.json",
}
},
{
"id": "contoso-motor-serial-00002",
"name": "vacuum-motor",
"group": "motors",
"manufacturer": "contoso",
"model": "virtual-motor",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/motors\/2",
"firmwareDataFile": "firmware.json",
}
},
{
"id": "contoso-camera-serial-00000",
"name": "front-camera",
"group": "cameras",
"manufacturer": "contoso",
"model": "virtual-camera",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/camera\/0",
"firmwareDataFile": "firmware.json",
}
},
{
"id": "contoso-camera-serial-00001",
"name": "rear-camera",
"group": "cameras",
"manufacturer": "contoso",
"model": "virtual-camera",
"properties": {
"path": "\/usr\/local\/contoso-devices\/vacuum-1\/camera\/1",
"firmwareDataFile": "firmware.json",
}
}
]
}
后续步骤
本文中的示例使用了 C。若要浏览 C++ 示例源代码,请参阅:
有关连接到 Contoso Virtual Vacuum 设备的各种组件示例更新,请参阅代理更新演示。