Not
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
I den här självstudien får du lära dig hur du använder Tjänsten Azure Web PubSub och Azure Functions för att skapa ett serverlöst program med datavisualisering i realtid från IoT Hub.
I den här tutorialen lär du dig följande:
- Bygg en serverlös datavisualiseringsapp
- Arbeta tillsammans med Web PubSub-funktionens in- och utdata-bindningar och Azure IoT-hubb
- Kör exempelfunktionerna lokalt
Viktigt
Råa anslutningssträng visas endast i den här artikeln i demonstrationssyfte.
En anslutningssträng innehåller den auktoriseringsinformation som krävs för att din applikation ska kunna få tillgång till Azure Web PubSub-tjänsten. Åtkomstnyckeln i anslutningssträng liknar ett rotlösenord för din tjänst. I produktionsmiljöer, skydda alltid dina åtkomstnycklar. Använd Azure Key Vault för att hantera och rotera dina nycklar säkert och säkra din anslutning med WebPubSubServiceClient.
Undvik att distribuera åtkomstnycklar till andra användare, hårdkoda dem eller spara dem någonstans i klartext som är åtkomlig för andra. Rotera dina nycklar om du tror att de har komprometterats.
Förutsättningar
En kodredigerare, till exempel Visual Studio Code
Node.js version 18.x eller senare.
Anmärkning
För mer information om de versioner av Node.js som stöds, se dokumentationen om Azure Functions runtime-versioner.
Azure Functions Core Tools (v3 eller högre rekommenderas) för att köra Azure Function-appar lokalt och distribuera till Azure.
Med Azure CLI för att hantera Azure-resurser.
Om du inte har något Azure-konto skapar du ett kostnadsfritt konto innan du börjar.
Skapa en IoT-hubb
I det här avsnittet använder du Azure CLI för att skapa en IoT-hubb och en resursgrupp. En Azure-resursgrupp är en logisk behållare i vilken Azure-resurser distribueras och hanteras. En IoT-hubb fungerar som en central meddelandehubb för dubbelriktad kommunikation mellan din IoT-applikation och enheterna.
Om du redan har en IoT-hubb i din Azure-prenumeration kan du hoppa över det här avsnittet.
Så här skapar du en IoT-hubb och en resursgrupp:
Starta DIN CLI-app. För att köra CLI-kommandona i resten av den här artikeln, kopiera kommandosyntaxen, klistra in den i din CLI-app, redigera variabelvärdena och tryck på Enter.
- Om du använder Cloud Shell, välj knappen Testa på CLI-kommandona för att starta Cloud Shell i ett delat webbläsarfönster. Eller så kan du öppna Cloud Shell på en separat webbläsarflik.
- Om du använder Azure CLI lokalt, starta din CLI-konsolapp och logga in på Azure CLI.
Kör az extension add för att installera eller uppgradera azure-iot-tillägget till den aktuella versionen.
az extension add --upgrade --name azure-iotI din CLI-app, kör kommandot az group create för att skapa en resursgrupp. Följande kommando skapar en resursgrupp med namnet MyResourceGroup på platsen eastus .
Anmärkning
Du kan också ange en annan plats. För att se tillgängliga platser, kör
az account list-locations. Denna snabbstart använder eastus som visas i exempelkörningen.az group create --name MyResourceGroup --location eastusKör kommandot az iot hub create för att skapa en IoT-hubb. Det kan ta några minuter att skapa en IoT-hubb.
YourIoTHubName. Ersätt denna platshållare och de omgivande måsvingarna i följande kommando med det namn du valde för din IoT-hubb. Ett IoT-hubbenamn måste vara unikt globalt i Azure. Använd ditt IoT-navns namn i resten av detta snabbstartsguide där du ser platshållaren.
az iot hub create --resource-group MyResourceGroup --name {YourIoTHubName}
Skapa en Web PubSub-instans
Om du redan har en Web PubSub-instans i ditt Azure-abonnemang kan du hoppa över det här avsnittet.
Kör az extension add för att installera eller uppgradera webpubsub-tillägget till den senaste versionen.
az extension add --upgrade --name webpubsub
Använd Azure CLI-kommandot az webpubsub create för att skapa en Web PubSub i resursgruppen du har skapat. Följande kommando skapar en Free Web PubSub-resurs under resursgruppen myResourceGroup i EastUS:
Viktigt
Varje Web PubSub-resurs måste ha ett unikt namn. Byt ut <your-unique-resource-name> mot namnet på din Web PubSub i följande exempel.
az webpubsub create --name "<your-unique-resource-name>" --resource-group "myResourceGroup" --location "EastUS" --sku Free_F1
Output från det här kommandot visar egenskaperna för den nyss skapade resursen. Notera de två egenskaperna som listas nedan:
-
Resursnamn: Namnet du angav för
--name-parametern ovan. -
hostName: I exemplet är
<your-unique-resource-name>.webpubsub.azure.com/värdnamnet .
För närvarande är ditt Azure-konto det enda som är auktoriserat att utföra några åtgärder på denna nya resurs.
Skapa och kör funktionerna lokalt
Skapa en tom mapp för projektet och kör sedan följande kommando i den nya mappen.
func init --worker-runtime javascript --model V4Skapa en
indexfunktion för att läsa och vara värd för en statisk webbsida för klienter.func new -n index -t HttpTriggerUppdatera
src/functions/index.jsmed följande kod, som levererar HTML-innehållet som en statisk webbplats.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, }; } });Skapa en
index.html-fil i rotmappen.<!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>Skapa en
negotiatefunktion som klienter använder för att få en tjänsteanslutnings-URL och åtkomsttoken.func new -n negotiate -t HttpTriggerUppdatera
src/functions/negotiate.jsför att användaWebPubSubConnectionsom innehåller den genererade token.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')) }; }, });Skapa en
messagehandlerfunktion för att generera meddelanden med hjälp av mallen"IoT Hub (Event Hub)".Råa anslutningssträng visas endast i den här artikeln i demonstrationssyfte. I produktionsmiljöer, skydda alltid dina åtkomstnycklar. Använd Azure Key Vault för att hantera och rotera dina nycklar säkert och säkra din anslutning med
WebPubSubServiceClient.func new --template "Azure Event Hub trigger" --name messagehandlerUppdatera
src/functions/messagehandler.jsför att lägga till Web PubSub output binding med följande JSON-kod. Vi använder variabeln%hubName%som hubbnamn för både IoT eventHubName och Web PubSub Hub.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); } });
Uppdatera funktionsinställningarna.
Lägg till
hubNameinställning och ersätt{YourIoTHubName}med det hub-namn du använde när du skapade din IoT Hub.func settings add hubName "{YourIoTHubName}"Hämta Service Connection String för IoT Hub.
az iot hub connection-string show --policy-name service --hub-name {YourIoTHubName} --output table --default-eventhubStäll in
IOTHubConnectionStringoch ersätt<iot-connection-string>med värdet.func settings add IOTHubConnectionString "<iot-connection-string>"- Hämta Anslutningssträngen för Web PubSub.
az webpubsub key show --name "<your-unique-resource-name>" --resource-group "<your-resource-group>" --query primaryConnectionStringStäll in
WebPubSubConnectionStringoch ersätt<webpubsub-connection-string>med värdet.func settings add WebPubSubConnectionString "<webpubsub-connection-string>"Anmärkning
En
Azure Event Hub triggerfunktionstrigger som används i exemplet har beroende på Azure Storage, men du kan använda en lokal lagringsemlulator när funktionen körs lokalt. Om du får ett fel, till exempelThere was an error performing a read operation on the Blob Storage Secret Repository. Please ensure the 'AzureWebJobsStorage' connection string is valid., måste du ladda ned och aktivera Lagringsemulatorn.Kör funktionen lokalt.
Nu kan du köra din lokala funktion med kommandot nedan.
func startDu kan besöka din lokala värds statiska sida genom att gå till:
https://localhost:7071/api/index.
Kör enheten för att skicka data
Registrera en enhet
Enheten måste registreras hos din IoT-hubb innan den kan ansluta. Om du redan har en enhet registrerad i din IoT-hubb kan du hoppa över det här avsnittet.
Kör kommandot az iot hub device-identity create i Azure Cloud Shell för att skapa enhetsidentiteten.
YourIoTHubName: Ersätt den här platshållaren med det namn du valde för din IoT-hubb.
az iot hub device-identity create --hub-name {YourIoTHubName} --device-id simDeviceKör kommandot Az PowerShell-modulen iot hub device-identity connection-string show i Azure Cloud Shell för att hämta enhetsanslutningssträngen för den enhet som du nyss registrerade:
YourIoTHubName: Ersätt platshållaren nedan med det namn du valde för din IoT-hubb.
az iot hub device-identity connection-string show --hub-name {YourIoTHubName} --device-id simDevice --output tableObservera anslutningssträngen för enheten, som ser ut så här:
HostName={YourIoTHubName}.azure-devices.net;DeviceId=simDevice;SharedAccessKey={YourSharedAccessKey}
För snabbast resultat, simulera temperaturdata med hjälp av Raspberry Pi Azure IoT Online Simulator. Klistra in enhetsanslutningssträngen och välj knappen Kör.
Om du har en fysisk Raspberry Pi och en BME280-sensor kan du mäta och rapportera verkliga temperatur- och luftfuktighetsvärden genom att följa handledningen Connect Raspberry Pi to Azure IoT Hub (Node.js).
Kör visualiseringswebbplatsen
Öppna funktionsvärdens indexsida: http://localhost:7071/api/index för att visa realtidsdatanpanelen. Registrera flera enheter och du kommer att se att instrumentpanelen uppdaterar flera enheter i realtid. Öppna flera webbläsare så ser du att varje sida uppdateras i realtid.
Rensa resurser
Om du planerar att fortsätta med efterföljande snabbstartsguider och handledningar, kan det vara bra att låta dessa resurser vara kvar.
När det inte längre behövs, kan du använda kommandot az group delete i Azure CLI för att ta bort resursgruppen och alla relaterade resurser.
az group delete --name "myResourceGroup"