练习 - 向 IoT Edge 部署 Azure 函数

已完成

筛选设备发送的遥测数据。

回想一下,你希望最大程度地减少每个存储发送的数据量。 若要减少发送到 IoT Central 应用程序的遥测数据量,需要筛选 IoT Edge 设备上的数据。

这里将使用 IoT Edge 设备上运行的 Azure Functions 来实现筛选器。 此筛选器可确保设备仅发送环境温度高于 21°C 时的遥测数据。

注意

本练习为选做练习。 若要完成本练习,需要在开始之前创建 Azure 订阅。 如果没有 Azure 帐户,或者现在不想创建帐户,则可以通读说明,以便了解所提供的信息。

配置容器注册表

你的 IoT Edge 设备需要下载并安装实现筛选器的自定义 Azure Functions 模块。 IoT Edge 模块打包为 Docker 兼容的映像,可将其存储在容器存储库中。 你决定使用 Azure 容器注册表 (ACR) 来存储新模块。 还将使用 ACR 从源项目生成容器。

运行以下命令,将容器注册表添加到 Azure 中的资源组:

REGISTRY_NAME="edgecentral$RANDOM"
az acr create -n $REGISTRY_NAME -g <rgn>[sandbox resource group name]</rgn> --sku Standard --admin-enabled true
az acr credential show -n $REGISTRY_NAME
echo "Your registry name is: $REGISTRY_NAME"

记下注册表名称和 password 值,稍后将在本单元中用到。

创建 Azure Functions 项目

你将使用 C# 实现函数。 运行以下命令来安装项目模板,然后生成主干项目:

dotnet new -i Microsoft.Azure.IoT.Edge.Function
dotnet new aziotedgefunction -n FilterFunction -r $REGISTRY_NAME.azurecr.io/filterfunction
cd FilterFunction
ls

运行以下命令,将现有的 FilterFunction.cs 替换为筛选机器温度遥测的实现:

curl -O https://raw.githubusercontent.com/Azure-Samples/iot-central-docs-samples/main/iotedge/FilterFunction.cs

立即生成映像并将其上传到容器注册表。 预计此命令需要几分钟才能运行:

az acr build --registry $REGISTRY_NAME --image filterfunction:v1 -f Dockerfile.amd64 .

可以使用以下命令列出注册表中的映像:

az acr repository list --name $REGISTRY_NAME

更新部署清单

若要在 IoT Edge 设备上使用新的筛选器模块,请更新为新版部署清单。

右键单击以下链接并选择“另存为”,将新的部署清单和接口定义下载到本地计算机:

在文本编辑器中打开 EnvironmentalSensorManifestFilter-1-4.json,并将其更新为使用容器注册表中的筛选器模块:

  1. <YOUR CONTAINER REGISTRY NAME> 的三个实例替换为你的容器注册表名称。 名称类似于 edgecentral27912
  2. <YOUR CONTAINER REGISTRY PASSWORD> 替换为你之前在本单元中记下的密码。
  3. 保存更改。

此版本的部署清单:

  • 添加包含你创建的 Azure 函数的模块:

    "filterfunction": {
      "version": "1.0",
      "type": "docker",
      "status": "running",
      "restartPolicy": "always",
      "settings": {
        "image": "<YOUR CONTAINER REGISTRY NAME>.azurecr.io/filterfunction:v1",
        "createOptions": ""
      }
    
  • 在将筛选后的遥测数据发送到 IoT Central 应用程序之前,需要将 SimulatedTemperatureSensor 模块的输出路由到 filterfunction 模块:

    "routes": {
        "FilterFunctionToIoTCentral": "FROM /messages/modules/filterfunction/outputs/* INTO $upstream",
        "sensorToFilterFunction": "FROM /messages/modules/SimulatedTemperatureSensor/outputs/temperatureOutput INTO BrokeredEndpoint(\"/modules/filterfunction/inputs/input1\")"
      },
    

若要上传新的部署清单,请执行以下操作:

  1. 在 IoT Central 应用程序中,导航到“Edge 清单”并选择“环境传感器”清单。

  2. 在“自定义”页面上,上传新的 EnvironmentalSensorManifestFilter-1-4.json 文件。 选择“下一步”。

  3. “查看并完成”页面显示新的 filterfunction 模块。 选择“保存”。

  4. 从“设备”页面导航到“环境传感器 Edge 设备-store-001”设备并选择“模块”。

  5. 在“模块”页面上,选择“管理清单”>“分配 Edge 清单”。 选择“环境传感器”清单。

  6. 模块列表现在包括正在运行的 filterfunction 模块:

Screenshot that shows the FilterFunction module running on the IoT Edge device.

更新设备模板以使用新模块

IoT Edge 设备现在正通过 filterfunction 接口而不是“遥测数据”接口发送遥测数据。 因此,需要更新设备模板和视图:

  1. 在“设备模板“页面上导航到“环境传感器 Edge 设备”。

  2. 选择“模块”,然后选择“从清单导入模块”。

  3. 在“导入模块”对话框中,选择“环境传感器”,然后选择“导入”。

Screenshot that shows the FilterFunction module added to the device template.

新模块现在会将遥测数据发送到 IoT Central。 接下来向指定遥测的新筛选器模块添加一个接口,并更新图表:

  1. 依次选择“模块 FilterFunction”和“+ 添加继承接口”。 可能需要选择“...”来查看此选项。
  2. 选择“导入接口”磁贴。 选择你先前下载的 TelemetryInterfaceFilter.json 文件。

可以删除原始的“遥测”接口,因为 SimulatedTemperatureModule 不再将遥测数据直接发送到 IoT Central。 IoT Edge 运行时会将此模块的输出路由到 FilterFunction 模块:

  1. 选择 SimulatedTemperatureSensor 模块中的“遥测”接口。
  2. 选择“删除”,然后确认操作。

修改“查看 IoT Edge 设备遥测”视图,以显示 FilterFunction 模块发送的遥测数据:

  1. 在设备模板中,选择“查看 IoT Edge 设备遥测”视图,然后选择图表磁贴上的“编辑”选项。
  2. 添加“环境/温度”、“湿度”、“机器/温度”和“压力”遥测值。
  3. 选择“更新”,然后单击“保存”以保存所做的更改。
  4. 选择“发布”以发布新版本的设备模板。

检查你的工作

若要从 IoT Edge 设备查看筛选的遥测数据,请执行以下操作:

  1. 在“设备”页面上导航到 store-001 设备。

  2. 选择“查看 IoT Edge 设备遥测”视图。

  3. 可以在图表上看到筛选后的遥测数据。 没有显示平均环境温度低于 21.0 度的值。

    Screenshot that shows telemetry plot with no average ambient temperature values less than 21.

如果设备似乎停止发送遥测数据,很可能是因为 SimulatedTemperatureSensor 模块在发送 500 条消息后停止。 如果重启 VM,计数将重置,你会看到遥测数据重新开始流动:

az vm restart --resource-group <rgn>[sandbox resource group name]</rgn> \
  --name $(az vm list --resource-group <rgn>[sandbox resource group name]</rgn> --query [0].name -o tsv)