Oktatóanyag: IoT-eszközadatok megjelenítése az IoT Hubról az Azure Web PubSub szolgáltatás és az Azure Functions használatával
Ebben az oktatóanyagban megtudhatja, hogyan hozhat létre kiszolgáló nélküli alkalmazást az Azure Web PubSub szolgáltatás és az Azure Functions használatával valós idejű adatvizualizációval az IoT Hubról.
Ebben az oktatóanyagban az alábbiakkal fog megismerkedni:
- Kiszolgáló nélküli adatvizualizációs alkalmazás létrehozása
- Együttműködés a Web PubSub függvény bemeneti és kimeneti kötéseivel és az Azure IoT Hubbal
- A mintafüggvények helyi futtatása
Előfeltételek
Kódszerkesztő, például Visual Studio Code
Node.js, 18.x vagy újabb verzió.
Megjegyzés:
A Node.js támogatott verzióival kapcsolatos további információkért tekintse meg az Azure Functions futtatókörnyezeti verzióinak dokumentációját.
Az Azure Functions Core Tools (v3 vagy magasabb előnyben részesített) az Azure-függvényalkalmazások helyi futtatásához és az Azure-ban való üzembe helyezéséhez.
If you don't have an Azure subscription, create an Azure free account before you begin.
IoT Hub létrehozása
Ebben a szakaszban az Azure CLI használatával hozhat létre egy IoT Hubot és egy erőforráscsoportot. Az Azure-erőforráscsoport olyan logikai tároló, amelybe a rendszer üzembe helyezi és kezeli az Azure-erőforrásokat. Az IoT Hub központi üzenetközpontként szolgál az IoT-alkalmazás és az eszközök közötti kétirányú kommunikációhoz.
Ha már rendelkezik IoT Hubbal az Azure-előfizetésében, kihagyhatja ezt a szakaszt.
IoT Hub és erőforráscsoport létrehozása:
Indítsa el a CLI-alkalmazást. A parancssori felület parancsainak a cikk további részében való futtatásához másolja ki a parancs szintaxisát, illessze be a parancssori felület alkalmazásába, szerkessze a változóértékeket, és nyomja le
Enter
a billentyűt.- Ha Cloud Shellt használ, kattintson a CLI-parancsok Kipróbálás gombjára a Cloud Shell felosztott böngészőablakban való elindításához. Vagy megnyithatja a Cloud Shellt egy külön böngészőlapon.
- Ha helyileg használja az Azure CLI-t, indítsa el a CLI-konzolalkalmazást, és jelentkezzen be az Azure CLI-be.
Futtassa az az extension add parancsot az azure-iot bővítmény telepítéséhez vagy frissítéséhez az aktuális verzióra.
az extension add --upgrade --name azure-iot
A CLI-alkalmazásban futtassa az az group create parancsot egy erőforráscsoport létrehozásához. Az alábbi parancs létrehoz egy MyResourceGroup nevű erőforráscsoportot az eastus helyen.
Megjegyzés:
Igény szerint másik helyet is beállíthat. Az elérhető helyek megtekintéséhez futtassa a következőt
az account list-locations
: . Ez a rövid útmutató az eastus függvényt használja a példaparancsban látható módon.az group create --name MyResourceGroup --location eastus
Futtassa az az iot hub create parancsot egy IoT Hub létrehozásához. Az IoT Hub létrehozása eltarthat néhány percig.
YourIotHubName. Cserélje le ezt a helyőrzőt és a környező zárójeleket a következő parancsban az IoT Hubhoz választott névvel. Az IoT Hub nevének globálisan egyedinek kell lennie az Azure-ban. Használja az IoT Hub nevét a rövid útmutató többi részében, ahol a helyőrzőt látja.
az iot hub create --resource-group MyResourceGroup --name {your_iot_hub_name}
Web PubSub-példány létrehozása
Ha már rendelkezik Web PubSub-példánysal az Azure-előfizetésében, kihagyhatja ezt a szakaszt.
Futtassa az az extension add parancsot a webpubsub bővítmény telepítéséhez vagy frissítéséhez az aktuális verzióra.
az extension add --upgrade --name webpubsub
Az Azure CLI az webpubsub create paranccsal hozzon létre egy Web PubSub-t a létrehozott erőforráscsoportban. Az alábbi parancs létrehoz egy ingyenes Web PubSub-erőforrást a myResourceGroup erőforráscsoportban az EastUS-ban:
Fontos
Minden Web PubSub-erőforrásnak egyedi névvel kell rendelkeznie. Az alábbi példákban cserélje le <az egyedi erőforrás nevét> a Web PubSub nevére.
az webpubsub create --name "<your-unique-resource-name>" --resource-group "myResourceGroup" --location "EastUS" --sku Free_F1
A parancs kimenete az újonnan létrehozott erőforrás tulajdonságait jeleníti meg. Jegyezze fel az alábbi két tulajdonságot:
- Erőforrás neve: A fenti paraméternek
--name
megadott név. - hostName: A példában a gazdagép neve .
<your-unique-resource-name>.webpubsub.azure.com/
Ezen a ponton az Azure-fiók az egyetlen jogosult az új erőforráson végzett műveletek végrehajtására.
A függvények helyi létrehozása és futtatása
Hozzon létre egy üres mappát a projekthez, majd futtassa az alábbi parancsot az új mappában.
func init --worker-runtime javascript --model V4
index
Statikus weblap olvasására és üzemeltetésére szolgáló függvény létrehozása az ügyfelek számára.func new -n index -t HttpTrigger
Frissítsen
src/functions/index.js
a következő kóddal, amely a HTML-tartalmat statikus webhelyként szolgálja ki.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, }; } });
Hozzon létre egy
index.html
fájlt a gyökérmappában.<!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>
Hozzon létre egy függvényt
negotiate
, amelyet az ügyfelek a szolgáltatáskapcsolat URL-címének és hozzáférési jogkivonatának lekéréséhez használnak.func new -n negotiate -t HttpTrigger
Frissítsen
src/functions/negotiate.js
a létrehozott jogkivonatot tartalmazó használatraWebPubSubConnection
.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')) }; }, });
Hozzon létre egy függvényt
messagehandler
, amely értesítéseket hoz létre a"IoT Hub (Event Hub)"
sablon használatával.func new --template "Azure Event Hub trigger" --name messagehandler
Frissítsen
src/functions/messagehandler.js
a Web PubSub kimeneti kötés hozzáadásához a következő json-kóddal. A változót%hubName%
az IoT eventHubName és a Web PubSub hub központi neveként is használjuk.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); } });
Frissítse a függvénybeállításokat.
Adjon hozzá
hubName
beállítást, és cserélje le{YourIoTHubName}
az IoT Hub létrehozásakor használt hubnevet.func settings add hubName "{YourIoTHubName}"
Az IoT Hub szolgáltatás Csatlakozás ion sztringjének lekérése.
az iot hub connection-string show --policy-name service --hub-name {YourIoTHubName} --output table --default-eventhub
Állítsa be
IOTHubConnectionString
, és cserélje le<iot-connection-string>
az értéket.func settings add IOTHubConnectionString "<iot-connection-string>"
- A Web PubSub Csatlakozás ion sztringjének lekérése.
az webpubsub key show --name "<your-unique-resource-name>" --resource-group "<your-resource-group>" --query primaryConnectionString
Állítsa be
WebPubSubConnectionString
, és cserélje le<webpubsub-connection-string>
az értéket.func settings add WebPubSubConnectionString "<webpubsub-connection-string>"
Megjegyzés:
A
Azure Event Hub trigger
mintában használt függvény-eseményindító függ az Azure Storage-tól, de helyi tárolóemulátort is használhat, ha a függvény helyileg fut. Ha példáulThere was an error performing a read operation on the Blob Storage Secret Repository. Please ensure the 'AzureWebJobsStorage' connection string is valid.
hibaüzenetet kap, le kell töltenie és engedélyeznie kell a Storage Emulatort.Futtassa helyileg a függvényt.
Most már futtathatja a helyi függvényt az alábbi paranccsal.
func start
A helyi gazdagép statikus lapját a következő webhelyen tekintheti meg:
https://localhost:7071/api/index
.
Az eszköz futtatása adatok küldéséhez
Eszköz regisztrálása
Az eszköznek regisztrálva kell lennie az IoT Hubbal, hogy csatlakozhasson hozzá. Ha már regisztrált egy eszközt az IoT Hubon, kihagyhatja ezt a szakaszt.
Futtassa az az iot hub device-identity create parancsot az Azure Cloud Shellben az eszközidentitás létrehozásához.
YourIoTHubName: Cserélje le ezt a helyőrzőt az IoT Hubhoz választott névre.
az iot hub device-identity create --hub-name {YourIoTHubName} --device-id simDevice
Futtassa az Az PowerShell-modul iot hub device-identity connection-string show parancsát az Azure Cloud Shellben az imént regisztrált eszköz eszköz kapcsolati sztring lekéréséhez:
YourIoTHubName: Cserélje le az alábbi helyőrzőt az IoT Hubhoz választott névre.
az iot hub device-identity connection-string show --hub-name {YourIoTHubName} --device-id simDevice --output table
Jegyezze fel az eszköz kapcsolati sztring, amely így néz ki:
HostName={YourIoTHubName}.azure-devices.net;DeviceId=simDevice;SharedAccessKey={YourSharedAccessKey}
A leggyorsabb eredmények érdekében szimulálja a hőmérsékleti adatokat a Raspberry Pi Azure IoT Online szimulátor használatával. Illessze be az eszköz kapcsolati sztring, és válassza a Futtatás gombot.
Ha fizikai Raspberry Pi- és BME280-érzékelővel rendelkezik, akkor a Raspberry Pi és az Azure IoT Hub (Node.js) oktatóanyagának követésével mérheti és jelentheti Csatlakozás a valós hőmérséklet- és páratartalom-értékeket.
A vizualizációs webhely futtatása
A függvény gazdagép indexoldalának megnyitása: http://localhost:7071/api/index
a valós idejű irányítópult megtekintéséhez. Regisztráljon több eszközt, és látni fogja, hogy az irányítópult valós időben frissít több eszközt. Nyisson meg több böngészőt, és látni fogja, hogy minden oldal valós időben frissül.
Clean up resources
Ha azt tervezi, hogy az ezt követő rövid útmutatókkal és oktatóanyagokkal dolgozik tovább, ne törölje ezeket az erőforrásokat.
Ha már nincs rá szükség, az Azure CLI az group delete parancsával eltávolíthatja az erőforráscsoportot és az összes kapcsolódó erőforrást:
az group delete --name "myResourceGroup"