Руководство. Визуализация данных устройства Интернета вещей из Центр Интернета вещей с помощью службы Azure Web PubSub и Функции Azure
В этом руководстве вы узнаете, как использовать службу Azure Web PubSub и Функции Azure для создания бессерверного приложения с визуализацией данных в режиме реального времени из Центр Интернета вещей.
В этом руководстве описано следующее:
- Создание приложения визуализации бессерверных данных
- Совместная работа с входными и выходными привязками функции Web PubSub и Центром Интернета вещей Azure
- Локальный запуск примера функций
Необходимые компоненты
Редактор кода, например Visual Studio Code.
Node.js, версия 18.x или более поздней.
Примечание.
Дополнительные сведения о поддерживаемых версиях Node.js см. в документации по версиям среды выполнения Функций Azure.
Azure Functions Core Tools (желательно версии 3 или более поздней версии) для запуска приложений-функций Azure в локальной среде и их развертывания в Azure.
Azure CLI для управления ресурсами Azure.
Если у вас еще нет подписки Azure, создайте бесплатную учетную запись Azure, прежде чем начинать работу.
Создание Центра Интернета вещей
В этом разделе описано, как использовать Azure CLI для создания центра Интернета вещей и группы ресурсов. Группа ресурсов Azure является логическим контейнером, в котором происходит развертывание ресурсов Azure и управление ими. Центр Интернета вещей действует в качестве центра сообщений для двусторонней связи между приложением Интернета вещей и устройствами.
Если у вас уже есть центр Интернета вещей в подписке Azure, этот раздел можно пропустить.
Чтобы создать центр Интернета вещей и группу ресурсов, выполните следующие действия:
Запустите приложение CLI. Чтобы выполнить команды CLI в остальной части этой статьи, скопируйте синтаксис команды, вставьте его в приложение CLI, измените значения переменных и нажмите клавишу
Enter
.- При использовании Cloud Shell нажмите кнопку Попробовать в командах интерфейса командной строки, чтобы запустить Cloud Shell в разделенном окне браузера. Или можно открыть Cloud Shell в отдельной вкладке браузера.
- Если вы используете Azure CLI локально, запустите консольное приложение CLI и войдите в Azure CLI.
Запустите az extension add, чтобы установить или обновить расширение azure-iot до текущей версии.
az extension add --upgrade --name azure-iot
В приложении CLI выполните команду az group create, чтобы создать группу ресурсов. В следующей команде создается группа ресурсов с именем MyResourceGroup в расположении eastus.
Примечание.
При необходимости можно задать другое расположение. Чтобы отобразить доступные расположения, выполните команду
az account list-locations
. В рамках работы с этим кратким руководством используется eastus, как показано в примере команды.az group create --name MyResourceGroup --location eastus
Создайте Центр Интернета вещей с помощью команды az iot hub create. Создание Центра Интернета вещей может занять несколько минут.
YourIotHubName Замените этот заполнитель и окружающие фигурные скобки в указанной ниже команде именем своего центра Интернета вещей. Имя центра Интернета вещей должно быть уникальным по всему Azure. Используйте имя центра Интернета вещей при работе с оставшейся частью этого краткого руководства везде вместо заполнителя.
az iot hub create --resource-group MyResourceGroup --name {your_iot_hub_name}
Создание экземпляра Web PubSub
Если у вас уже есть экземпляр Web PubSub в подписке Azure, можно пропустить этот раздел.
Запустите az extension add to install or upgrade the webpubsub extension to the current version.
az extension add --upgrade --name webpubsub
Используйте команду azure CLI az webpubsub create , чтобы создать web PubSub в созданной группе ресурсов. Следующая команда создает ресурс Free Web PubSub в группе ресурсов myResourceGroup в EastUS:
Важно!
Каждый ресурс Web PubSub должен иметь уникальное имя. В следующих примерах замените <your-unique-resource-name> именем своей службы Web PubSub.
az webpubsub create --name "<your-unique-resource-name>" --resource-group "myResourceGroup" --location "EastUS" --sku Free_F1
В выходных данных команды будут показаны свойства созданного ресурса. Запишите значения двух указанных ниже свойств.
- Имя ресурса: имя, которое вы ввели для указанного выше параметра
--name
. - hostName: в примере имя узла
<your-unique-resource-name>.webpubsub.azure.com/
.
На данном этапе любые операции в этом новом ресурсе могут выполняться только с использованием вашей учетной записи Azure.
Создание и запуск функций в локальной среде
Создайте пустую папку для проекта и выполните следующую команду в новой папке.
func init --worker-runtime javascript --model V4
Создайте функцию
index
для чтения и размещения статической веб-страницы для клиентов.func new -n index -t HttpTrigger
Обновите
src/functions/index.js
следующий код, который служит HTML-содержимому в качестве статического сайта.const { app } = require('@azure/functions'); const { readFile } = require('fs/promises'); app.http('index', { methods: ['GET', 'POST'], authLevel: 'anonymous', handler: async (context) => { const content = await readFile('index.html', 'utf8', (err, data) => { if (err) { context.err(err) return } }); return { status: 200, headers: { 'Content-Type': 'text/html' }, body: content, }; } });
Создайте файл в корневой
index.html
папке.<!doctype html> <html lang="en"> <head> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <script src="https://cdn.jsdelivr.net/npm/chart.js@2.8.0/dist/Chart.min.js" type="text/javascript" charset="utf-8"></script> <script> document.addEventListener("DOMContentLoaded", async function (event) { const res = await fetch(`/api/negotiate?id=${1}`); const data = await res.json(); const webSocket = new WebSocket(data.url); class TrackedDevices { constructor() { // key as the deviceId, value as the temperature array this.devices = new Map(); this.maxLen = 50; this.timeData = new Array(this.maxLen); } // Find a device temperature based on its Id findDevice(deviceId) { return this.devices.get(deviceId); } addData(time, temperature, deviceId, dataSet, options) { let containsDeviceId = false; this.timeData.push(time); for (const [key, value] of this.devices) { if (key === deviceId) { containsDeviceId = true; value.push(temperature); } else { value.push(null); } } if (!containsDeviceId) { const data = getRandomDataSet(deviceId, 0); let temperatures = new Array(this.maxLen); temperatures.push(temperature); this.devices.set(deviceId, temperatures); data.data = temperatures; dataSet.push(data); } if (this.timeData.length > this.maxLen) { this.timeData.shift(); this.devices.forEach((value, key) => { value.shift(); }) } } getDevicesCount() { return this.devices.size; } } const trackedDevices = new TrackedDevices(); function getRandom(max) { return Math.floor((Math.random() * max) + 1) } function getRandomDataSet(id, axisId) { return getDataSet(id, axisId, getRandom(255), getRandom(255), getRandom(255)); } function getDataSet(id, axisId, r, g, b) { return { fill: false, label: id, yAxisID: axisId, borderColor: `rgba(${r}, ${g}, ${b}, 1)`, pointBoarderColor: `rgba(${r}, ${g}, ${b}, 1)`, backgroundColor: `rgba(${r}, ${g}, ${b}, 0.4)`, pointHoverBackgroundColor: `rgba(${r}, ${g}, ${b}, 1)`, pointHoverBorderColor: `rgba(${r}, ${g}, ${b}, 1)`, spanGaps: true, }; } function getYAxy(id, display) { return { id: id, type: "linear", scaleLabel: { labelString: display || id, display: true, }, position: "left", }; } // Define the chart axes const chartData = { datasets: [], }; // Temperature (ºC), id as 0 const chartOptions = { responsive: true, animation: { duration: 250 * 1.5, easing: 'linear' }, scales: { yAxes: [ getYAxy(0, "Temperature (ºC)"), ], }, }; // Get the context of the canvas element we want to select const ctx = document.getElementById("chart").getContext("2d"); chartData.labels = trackedDevices.timeData; const chart = new Chart(ctx, { type: "line", data: chartData, options: chartOptions, }); webSocket.onmessage = function onMessage(message) { try { const messageData = JSON.parse(message.data); console.log(messageData); // time and either temperature or humidity are required if (!messageData.MessageDate || !messageData.IotData.temperature) { return; } trackedDevices.addData(messageData.MessageDate, messageData.IotData.temperature, messageData.DeviceId, chartData.datasets, chartOptions.scales); const numDevices = trackedDevices.getDevicesCount(); document.getElementById("deviceCount").innerText = numDevices === 1 ? `${numDevices} device` : `${numDevices} devices`; chart.update(); } catch (err) { console.error(err); } }; }); </script> <style> body { font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; padding: 50px; margin: 0; text-align: center; } .flexHeader { display: flex; flex-direction: row; flex-wrap: nowrap; justify-content: space-between; } #charts { display: flex; flex-direction: row; flex-wrap: wrap; justify-content: space-around; align-content: stretch; } .chartContainer { flex: 1; flex-basis: 40%; min-width: 30%; max-width: 100%; } a { color: #00B7FF; } </style> <title>Temperature Real-time Data</title> </head> <body> <h1 class="flexHeader"> <span>Temperature Real-time Data</span> <span id="deviceCount">0 devices</span> </h1> <div id="charts"> <canvas id="chart"></canvas> </div> </body> </html>
Создайте функцию, используемую
negotiate
клиентами для получения URL-адреса подключения службы и маркера доступа.func new -n negotiate -t HttpTrigger
Обновите для
src/functions/negotiate.js
использованияWebPubSubConnection
, содержащего созданный маркер.const { app, input } = require('@azure/functions'); const connection = input.generic({ type: 'webPubSubConnection', name: 'connection', hub: '%hubName%' }); app.http('negotiate', { methods: ['GET', 'POST'], authLevel: 'anonymous', extraInputs: [connection], handler: async (request, context) => { return { body: JSON.stringify(context.extraInputs.get('connection')) }; }, });
messagehandler
Создайте функцию для создания уведомлений с помощью"IoT Hub (Event Hub)"
шаблона.func new --template "Azure Event Hub trigger" --name messagehandler
Обновите
src/functions/messagehandler.js
, чтобы добавить выходную привязку Web PubSub со следующим кодом json. Мы используем переменную%hubName%
в качестве имени концентратора для центра IoT eventHubName и Центра Web PubSub.const { app, output } = require('@azure/functions'); const wpsAction = output.generic({ type: 'webPubSub', name: 'action', hub: '%hubName%' }); app.eventHub('messagehandler', { connection: 'IOTHUBConnectionString', eventHubName: '%hubName%', cardinality: 'many', extraOutputs: [wpsAction], handler: (messages, context) => { var actions = []; if (Array.isArray(messages)) { context.log(`Event hub function processed ${messages.length} messages`); for (const message of messages) { context.log('Event hub message:', message); actions.push({ actionName: "sendToAll", data: JSON.stringify({ IotData: message, MessageDate: message.date || new Date().toISOString(), DeviceId: message.deviceId, })}); } } else { context.log('Event hub function processed message:', messages); actions.push({ actionName: "sendToAll", data: JSON.stringify({ IotData: message, MessageDate: message.date || new Date().toISOString(), DeviceId: message.deviceId, })}); } context.extraOutputs.set(wpsAction, actions); } });
Обновите параметры функции.
Добавьте
hubName
параметр и замените{YourIoTHubName}
имя концентратора, которое вы использовали при создании Центр Интернета вещей.func settings add hubName "{YourIoTHubName}"
Получите строку Подключение ion service для Центр Интернета вещей.
az iot hub connection-string show --policy-name service --hub-name {YourIoTHubName} --output table --default-eventhub
Задайте
IOTHubConnectionString
значение, заменив<iot-connection-string>
его значением.func settings add IOTHubConnectionString "<iot-connection-string>"
- Получите строку Подключение ion для Web PubSub.
az webpubsub key show --name "<your-unique-resource-name>" --resource-group "<your-resource-group>" --query primaryConnectionString
Задайте
WebPubSubConnectionString
значение, заменив<webpubsub-connection-string>
его значением.func settings add WebPubSubConnectionString "<webpubsub-connection-string>"
Примечание.
Azure Event Hub trigger
Триггер функции, используемый в примере, зависит от служба хранилища Azure, но при локальном выполнении функции можно использовать эмулятор локального хранилища. Если возникает ошибка, напримерThere was an error performing a read operation on the Blob Storage Secret Repository. Please ensure the 'AzureWebJobsStorage' connection string is valid.
, необходимо скачать и включить эмулятор служба хранилища.выполнение функции в локальной среде;
Теперь вы можете выполнить локальную функцию с помощью приведенной ниже команды.
func start
Чтобы посетить статическую страницу локального узла, посетите:
https://localhost:7071/api/index
Запуск устройства для отправки данных
Регистрация устройства
Устройство должно быть зарегистрировано в центре Интернета вещей, прежде чем оно сможет подключиться. Если устройство уже зарегистрировано в центре Интернета вещей, этот раздел можно пропустить.
Чтобы создать удостоверение устройства, выполните команду az iot hub device-identity create в Azure Cloud Shell.
YourIoTHubName: замените этот заполнитель именем, выбранным для центра Интернета вещей.
az iot hub device-identity create --hub-name {YourIoTHubName} --device-id simDevice
Выполните команду az PowerShell module iot hub device-identity-identity-string show в Azure Cloud Shell, чтобы получить устройство строка подключения для только что зарегистрированного устройства:
YourIoTHubName. Замените этот заполнитель именем вашего центра Интернета вещей.
az iot hub device-identity connection-string show --hub-name {YourIoTHubName} --device-id simDevice --output table
Запишите устройство строка подключения, которое выглядит следующим образом:
HostName={YourIoTHubName}.azure-devices.net;DeviceId=simDevice;SharedAccessKey={YourSharedAccessKey}
Для получения самых быстрых результатов имитируйте данные температуры с помощью симулятора Raspberry Pi Azure IoT Online. Вставьте строка подключения устройства и нажмите кнопку "Выполнить".
Если у вас есть физический датчик Raspberry Pi и BME280, можно измерить и сообщить о реальных значениях температуры и влажности, следуя руководству по Подключение Raspberry Pi в Центр Интернета вещей Azure (Node.js).
Запуск веб-сайта визуализации
Откройте страницу индекса узла функции: http://localhost:7071/api/index
чтобы просмотреть панель мониторинга в режиме реального времени. Зарегистрируйте несколько устройств и вы увидите, что панель мониторинга обновляет несколько устройств в режиме реального времени. Откройте несколько браузеров, и вы увидите, что каждая страница обновляется в режиме реального времени.
Очистка ресурсов
Если вы планируете продолжить работу с последующими краткими руководствами и статьями, эти ресурсы можно не удалять.
Вы можете удалить ставшую ненужной группу ресурсов и все связанные с ней ресурсы с помощью Azure CLI, выполнив команду az group delete:
az group delete --name "myResourceGroup"