Tutorial: Memvisualisasikan data perangkat IoT dari IoT Hub menggunakan layanan Azure Web PubSub dan Azure Functions
Dalam tutorial ini, Anda akan mempelajari cara menggunakan layanan Azure Web PubSub dan Azure Functions untuk membangun aplikasi tanpa server dengan visualisasi data real time dari IoT Hub.
Dalam tutorial ini, Anda akan mempelajari cara:
- Membangun aplikasi visualisasi data tanpa server
- Bekerja sama dengan pengikatan input dan output fungsi Web PubSub dan hub Azure IoT
- Menjalankan fungsi sampel secara lokal
Penting
String koneksi mentah muncul dalam artikel ini hanya untuk tujuan demonstrasi.
String koneksi menyertakan informasi otorisasi yang diperlukan agar aplikasi Anda mengakses layanan Azure Web PubSub. Kunci akses di dalam string koneksi mirip dengan kata sandi root untuk layanan Anda. Di lingkungan produksi, selalu lindungi kunci akses Anda. Gunakan Azure Key Vault untuk mengelola dan memutar kunci Anda dengan aman dan mengamankan koneksi Anda dengan WebPubSubServiceClient
.
Hindari mendistribusikan kunci akses ke pengguna lain, melakukan hard-coding, atau menyimpannya di mana saja dalam teks biasa yang dapat diakses orang lain. Putar kunci Anda jika Anda yakin bahwa kunci tersebut mungkin telah disusupi.
Prasyarat
Editor kode seperti Visual Studio Code
Node.js, versi 18.x atau lebih tinggi.
Catatan
Untuk informasi selengkapnya tentang versi aplikasi yang Node.js, lihat Dokumentasi versi runtime Azure Functions.
Azure Functions Core Tools (v3 atau yang lebih tinggi) untuk menjalankan aplikasi Azure Function secara lokal dan menyebarkan ke Azure.
Azure CLI untuk mengelola sumber daya Azure.
Jika Anda tidak memiliki Langganan Azure, buat Akun gratis Azure sebelum memulai.
Membuat IoT Hub
Di bagian ini, Anda menggunakan Azure CLI untuk membuat hub IoT dan grup sumber daya. Grup sumber daya Azure adalah kontainer logis tempat sumber daya Azure disebarkan dan dikelola. Hub IoT bertindak sebagai hub pesan pusat untuk komunikasi dua arah antara aplikasi IoT Anda dan perangkat.
Jika sudah memiliki IoT hub di langganan Azure, Anda dapat melewati bagian ini.
Untuk membuat hub IoT dan grup sumber daya:
Luncurkan aplikasi CLI Anda. Untuk menjalankan perintah CLI di sisa artikel ini, salin sintaks perintah, tempelkan ke aplikasi CLI Anda, edit nilai variabel, dan tekan
Enter
.- Jika Anda menggunakan Cloud Shell, pilih tombol Cobalah pada perintah CLI untuk meluncurkan Cloud Shell di jendela browser terpisah. Atau Anda dapat membuka Cloud Shell di tab browser terpisah.
- Jika Anda menggunakan Azure CLI secara lokal, buka aplikasi konsol CLI Anda dan masuk ke Azure CLI.
Jalankan az extension add untuk memasang atau meningkatkan ekstensi azure-iot ke versi saat ini.
az extension add --upgrade --name azure-iot
Di aplikasi CLI Anda, jalankan perintah az group create untuk membuat grup sumber daya. Perintah berikut membuat grup sumber daya bernama MyResourceGroup di lokasi eastus.
Catatan
Secara opsional, Anda dapat mengatur lokasi yang berbeda. Untuk melihat lokasi yang tersedia, jalankan
az account list-locations
. Mulai cepat ini menggunakan eastus seperti yang ditunjukkan dalam perintah contoh.az group create --name MyResourceGroup --location eastus
Jalankan perintah az iot hub create untuk membuat hub IoT. Mungkin perlu waktu beberapa menit untuk membuat hub IoT.
YourIotHubName. Ganti tempat penampung ini dan kurung kurawal di sekitarnya dalam perintah berikut, menggunakan nama yang Anda pilih untuk hub IoT Anda. Nama hub IoT harus unik secara global di Azure. Gunakan nama hub IoT Anda di sisa mulai cepat ini di mana pun Anda melihat tempat penampung.
az iot hub create --resource-group MyResourceGroup --name {your_iot_hub_name}
Membuat instans Web PubSub
Jika Anda sudah memiliki instans Web PubSub di langganan Azure, Anda dapat melewati bagian ini.
Jalankan az extension add untuk menginstal atau meningkatkan ekstensi webpubsub ke versi saat ini.
az extension add --upgrade --name webpubsub
Gunakan perintah az webpubsub create Azure CLI untuk membuat Web PubSub di grup sumber daya yang telah Anda buat. Perintah berikut membuat sumber daya Web PubSub Gratis di bawah grup sumber daya myResourceGroup di EastUS:
Penting
Setiap sumber daya Web PubSub harus memiliki nama yang unik. Ganti <your-unique-resource-name> dengan nama Web PubSub Anda dalam contoh berikut.
az webpubsub create --name "<your-unique-resource-name>" --resource-group "myResourceGroup" --location "EastUS" --sku Free_F1
Keluaran dari perintah ini menunjukkan properti sumber daya yang baru dibuat. Perhatikan dua properti yang tercantum di bawah:
-
Nama Sumber Daya: Nama yang Anda berikan untuk parameter
--name
di atas. -
hostName: Dalam contoh, nama host adalah
<your-unique-resource-name>.webpubsub.azure.com/
.
Pada titik ini, akun Azure Anda adalah satu-satunya yang berwenang untuk melakukan operasi apa pun di sumber daya baru ini.
Membuat dan menjalankan fungsi secara lokal
Buat folder kosong untuk proyek, lalu jalankan perintah berikut di folder baru.
func init --worker-runtime javascript --model V4
Buat fungsi
index
untuk membaca dan menghosting halaman web statis untuk klien.func new -n index -t HttpTrigger
Perbarui
src/functions/index.js
dengan kode berikut, yang melayani konten HTML sebagai situs statis.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, }; } });
Buat
index.html
file di bawah folder akar.<!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>
Buat
negotiate
fungsi yang digunakan klien untuk mendapatkan URL koneksi layanan dan token akses.func new -n negotiate -t HttpTrigger
Perbarui
src/functions/negotiate.js
untuk menggunakanWebPubSubConnection
yang berisi token yang dihasilkan.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')) }; }, });
Buat
messagehandler
fungsi untuk menghasilkan pemberitahuan dengan menggunakan"IoT Hub (Event Hub)"
templat.String koneksi mentah muncul dalam artikel ini hanya untuk tujuan demonstrasi. Di lingkungan produksi, selalu lindungi kunci akses Anda. Gunakan Azure Key Vault untuk mengelola dan memutar kunci Anda dengan aman dan mengamankan koneksi Anda dengan
WebPubSubServiceClient
.func new --template "Azure Event Hub trigger" --name messagehandler
Perbarui
src/functions/messagehandler.js
untuk menambahkan pengikatan output Web PubSub dengan kode json berikut. Kami menggunakan variabel%hubName%
sebagai nama hub untuk hub IoT eventHubName dan 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); } });
Perbarui pengaturan Fungsi.
Tambahkan
hubName
pengaturan dan ganti{YourIoTHubName}
dengan nama hub yang Anda gunakan saat membuat IoT Hub Anda.func settings add hubName "{YourIoTHubName}"
Dapatkan String Koneksi Layanan untuk IoT Hub.
az iot hub connection-string show --policy-name service --hub-name {YourIoTHubName} --output table --default-eventhub
Atur
IOTHubConnectionString
, ganti<iot-connection-string>
dengan nilai .func settings add IOTHubConnectionString "<iot-connection-string>"
- Dapatkan String Koneksi untuk Web PubSub.
az webpubsub key show --name "<your-unique-resource-name>" --resource-group "<your-resource-group>" --query primaryConnectionString
Atur
WebPubSubConnectionString
, ganti<webpubsub-connection-string>
dengan nilai .func settings add WebPubSubConnectionString "<webpubsub-connection-string>"
Catatan
Pemicu
Azure Event Hub trigger
fungsi yang digunakan dalam sampel memiliki dependensi pada Azure Storage, tetapi Anda dapat menggunakan emulator penyimpanan lokal saat fungsi berjalan secara lokal. Jika Anda mendapatkan kesalahan sepertiThere was an error performing a read operation on the Blob Storage Secret Repository. Please ensure the 'AzureWebJobsStorage' connection string is valid.
, Anda harus mengunduh dan mengaktifkan Storage Emulator.Jalankan fungsi secara lokal.
Sekarang Anda dapat menjalankan fungsi lokal Anda dengan perintah di bawah ini.
func start
Anda dapat mengunjungi halaman statis host lokal Anda dengan mengunjungi:
https://localhost:7071/api/index
.
Jalankan perangkat untuk mengirim data
Mendaftarkan perangkat
Perangkat harus terdaftar dengan hub IoT Anda sebelum dapat terhubung. Jika sudah memiliki perangkat yang terdaftar di IoT hub, Anda dapat melewati bagian ini.
Jalankan perintah az iot hub device-identity create di Azure Cloud Shell untuk membuat identitas perangkat.
YourIoTHubName: Ganti tempat penampung ini dengan nama yang Anda pilih untuk hub IoT Anda.
az iot hub device-identity create --hub-name {YourIoTHubName} --device-id simDevice
Jalankan perintah Az PowerShell modul iot hub device-identity connection-string show di Azure Cloud Shell untuk mendapatkan perangkat string koneksi untuk perangkat yang baru saja Anda daftarkan:
YourIoTHubName: Ganti placeholder di bawah dengan nama yang Anda pilih untuk Azure IoT Hub Anda.
az iot hub device-identity connection-string show --hub-name {YourIoTHubName} --device-id simDevice --output table
Catat perangkat string koneksi, yang terlihat seperti ini:
HostName={YourIoTHubName}.azure-devices.net;DeviceId=simDevice;SharedAccessKey={YourSharedAccessKey}
Untuk hasil tercepat, simulasikan data suhu menggunakan Raspberry Pi Azure IoT Online Simulator. Tempelkan perangkat string koneksi, dan pilih tombol Jalankan.
Jika Anda memiliki sensor Raspberry Pi dan BME280 fisik, Anda dapat mengukur dan melaporkan nilai suhu dan kelembaban nyata dengan mengikuti tutorial Sambungkan Raspberry Pi ke Azure IoT Hub (Node.js).
Menjalankan situs web visualisasi
Buka halaman indeks host fungsi: http://localhost:7071/api/index
untuk melihat dasbor real-time. Daftarkan beberapa perangkat dan Anda akan melihat dasbor memperbarui beberapa perangkat secara real time. Buka beberapa browser dan Anda akan melihat setiap halaman diperbarui secara real-time.
Membersihkan sumber daya
Jika berencana untuk melanjutkan bekerja dengan mulai cepat dan tutorial berikutnya, Anda mungkin ingin membiarkan sumber daya ini tetap di tempatnya.
Jika tidak lagi dibutuhkan, gunakan perintah az group delete Azure CLI untuk menghapus grup sumber daya, dan semua sumber daya terkait:
az group delete --name "myResourceGroup"