将 Azure 数字孪生数据集成到 Azure Maps 室内地图中

本文展示了如何通过 Azure Maps 使用 Azure 数字孪生数据更新室内地图上显示的信息。 由于 Azure 数字孪生存储 IoT 设备关系图,并将设备数据路由到不同的终结点,因此它是用于更新地图上的信息覆盖的一项非常好的服务。

本指南涵盖以下信息:

  1. 配置你的 Azure 数字孪生实例,以将孪生体更新事件发送到 Azure Functions 中的函数。
  2. 创建一个函数来更新 Azure Maps 室内地图特征状态集。
  3. 在 Azure 数字孪生图中存储地图 ID 和特征状态集 ID。

开始使用

本部分为本文中的信息设置其他上下文。

先决条件

在继续本文之前,请先设置单独的 Azure 数字孪生和 Azure Maps 资源。

  • 对于 Azure 数字孪生:按照连接端到端解决方案中的说明,使用示例孪生图和模拟数据流设置 Azure 数字孪生实例。
    • 在本文中,将使用另一个终结点和路由扩展该解决方案。 你还将向在该教程中创建的函数应用添加另一个函数。
  • 对于 Azure Maps:按照使用 Creator 创建室内地图中的说明,创建具有某个“特征状态集”的 Azure Maps 室内地图
    • 特征状态集是分配给数据集特征(例如房间或设备)的动态属性(状态)的集合。 在上述 Azure Maps 说明中,特征状态集存储会在地图上显示的房间状态。
    • 你需要 Azure Maps 订阅密钥、特征状态集 ID 和 mapConfiguration

拓扑

下图展示了本教程中的室内地图集成元素在更大的端到端 Azure 数字孪生方案中的相应位置。

端到端方案中的 Azure 服务的图示,其中突出显示了 Indoor Maps 集成块。

从 Azure 数字孪生路由孪生更新通知

每当孪生体的状态更新时,Azure 数字孪生实例就可以发出孪生体更新事件。 上面链接的 Azure 数字孪生连接端到端解决方案展示了以下方案:使用温度计来更新附加到房间的孪生体的温度属性。 本教程通过订阅 Azure 函数来更新孪生通知,并使用该函数来更新地图,从而扩展该解决方案。

此模式直接从房间孪生体读取数据,而不是从 IoT 设备读取数据,这样你就能灵活地更改温度的基础数据源,而无需更新映射逻辑。 例如,你可以添加多个温度计或将此房间设置为与另一个房间共用一个温度计,所有这些都不需要更新你的地图逻辑。

首先,你将在 Azure 数字孪生中创建一个路由,以便将所有孪生体更新事件转发到事件网格主题。

  1. 使用以下 CLI 命令创建一个事件网格主题,用于接收来自 Azure 数字孪生实例的事件:

    az eventgrid topic create --resource-group <your-resource-group-name> --name <your-topic-name> --location <region>
    
  2. 使用以下 CLI 命令创建一个终结点,用于将事件网格主题链接到 Azure 数字孪生:

    az dt endpoint create eventgrid --endpoint-name <Event-Grid-endpoint-name> --eventgrid-resource-group <Event-Grid-resource-group-name> --eventgrid-topic <your-Event-Grid-topic-name> --dt-name <your-Azure-Digital-Twins-instance-name>
    
  3. 使用以下 CLI 命令在 Azure 数字孪生中创建路由,将孪生体更新事件发送到终结点。 对于此命令中的 Azure 数字孪生实例名称占位符,可以使用易记名称或主机名来提高性能。

    注意

    目前,Cloud Shell 中存在一个已知问题,该问题会影响以下命令组:az dt routeaz dt modelaz dt twin

    若要解决此问题,请在运行命令之前在 Cloud Shell 中运行 az login,或者使用本地 CLI 而不使用 Cloud Shell。 有关此方面的更多详细信息,请参阅 Azure 数字孪生已知问题

    az dt route create --dt-name <your-Azure-Digital-Twins-instance-hostname-or-name> --endpoint-name <Event-Grid-endpoint-name> --route-name <my-route> --filter "type = 'Microsoft.DigitalTwins.Twin.Update'"
    

创建 Azure 函数以接收事件和更新地图

在本部分中,你将创建一个函数,用于侦听发送到事件网格主题的事件。 该函数会读取这些更新通知并将相应的更新发送到 Azure Maps 特征状态集,以更新一个房间的温度。

在 Azure 数字孪生教程先决条件中,你创建了一个函数应用来存储 Azure 函数 Azure 数字孪生。 现在,在该函数应用中创建一个新的事件网格触发的 Azure 函数

将函数代码替换为以下代码。 它将仅筛选出空间孪生体的更新,读取更新的温度,并将该信息发送到 Azure Maps。

using System;
using System.Threading.Tasks;
using System.Net.Http;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.EventGrid;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Azure.Messaging.EventGrid;

namespace updateMaps
{
    public static class ProcessDTUpdatetoMaps
    {
        // Read maps credentials from application settings on function startup
        private static string statesetID = Environment.GetEnvironmentVariable("statesetID");
        private static string subscriptionKey = Environment.GetEnvironmentVariable("subscription-key");
        private static HttpClient httpClient = new HttpClient();

        [FunctionName("ProcessDTUpdatetoMaps")]
        public static async Task Run([EventGridTrigger]EventGridEvent eventGridEvent, ILogger log)
        {
            JObject message = (JObject)JsonConvert.DeserializeObject(eventGridEvent.Data.ToString());
            log.LogInformation($"Reading event from twinID: {eventGridEvent.Subject}: {eventGridEvent.EventType}: {message["data"]}");

            //Parse updates to "space" twins
            if (message["data"]["modelId"].ToString() == "dtmi:contosocom:DigitalTwins:Space;1")
            {
                // Set the ID of the room to be updated in your map.
                // Replace this line with your logic for retrieving featureID.
                string featureID = "UNIT103";

                // Iterate through the properties that have changed
                foreach (var operation in message["data"]["patch"])
                {
                    if (operation["op"].ToString() == "replace" && operation["path"].ToString() == "/Temperature")
                    {
                        // Update the maps feature stateset
                        var postcontent = new JObject(
                            new JProperty(
                                "States",
                                new JArray(
                                    new JObject(
                                        new JProperty("keyName", "temperature"),
                                        new JProperty("value", operation["value"].ToString()),
                                        new JProperty("eventTimestamp", DateTime.UtcNow.ToString("s"))))));

                        var response = await httpClient.PutAsync(
                            $"https://us.atlas.microsoft.com/featurestatesets/{statesetID}/featureStates/{featureID}?api-version=2.0&subscription-key={subscriptionKey}",
                            new StringContent(postcontent.ToString()));


                        log.LogInformation(await response.Content.ReadAsStringAsync());
                    }
                }
            }
        }
    }
}

你需要在函数应用中设置两个环境变量。 其中一个是你的 Azure Maps 主订阅密钥,另一个是你的 Azure Maps 状态集 ID。

az functionapp config appsettings set --name <your-function-app-name> --resource-group <your-resource-group> --settings "subscription-key=<your-Azure-Maps-primary-subscription-key>"
az functionapp config appsettings set --name <your-function-app-name> --resource-group <your-resource-group> --settings "statesetID=<your-Azure-Maps-stateset-ID>"

在地图中查看实时更新

若要查看实时更新的温度,请执行以下步骤:

  1. 通过运行 Azure 数字孪生连接端到端解决方案中的 DeviceSimulator 项目,开始发送模拟的 IoT 数据。 有关此过程的说明,请参阅配置并运行模拟部分。
  2. 使用 Azure Maps Indoor 模块呈现你在 Azure Maps Creator 中创建的室内地图。
    1. 示例:自定义样式:使用 WebSDK 中的地图配置(预览版)复制示例室内地图 HTML 文件。
    2. 将本地 HTML 文件中的订阅密钥、mapConfiguration、statesetID 和区域替换为你的值。
    3. 在浏览器中打开该文件。

两个样本发送的温度在一个兼容的范围内,所以你应该看到 121 房间的颜色在地图上大约每 30 秒更新一次。

办公室地图的屏幕截图,其中的 121 房间显示为橙色。

将地图信息存储在 Azure 数字孪生中

现在,你已经有了用来更新地图信息的硬编码解决方案,可以使用 Azure 数字孪生图来存储更新室内地图所需的所有信息了。 此信息将包括每个地图和位置的相应状态集 ID、地图订阅 ID 和特征 ID。

此特定示例的解决方案将涉及的内容包括:更新每个顶级空间以使其具有状态集 ID 和地图订阅 ID 属性,以及更新每个房间以使其具有特征 ID。 你需要在初始化孪生图时将这些值设置一次,然后就可以针对每个孪生体更新事件查询这些值。

根据拓扑配置,可以将这三个属性存储在与地图的粒度相关的不同级别。

后续步骤

若要详细了解如何管理、升级和检索孪生图中的信息,请参阅以下参考资料: