Skip to content

vsenkiv/using-azure-iot-eventgrid-function-dashboard

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

IoT Monitoring System - Architecture and Implementation Guide

Overview

This project implements a complete real-time IoT monitoring system on Azure that collects system metrics (CPU temperature, RAM usage, disk space) from a laptop, processes them through Azure services, and displays them on a live dashboard.

Table of Contents

High-Level Architecture

┌─────────────────┐
│  Windows Laptop │
│  IoT Emulator   │
│  (Java 21)      │
└────────┬────────┘
         │ MQTT
         │ Telemetry Data
         ↓
┌─────────────────┐
│  Azure IoT Hub  │
│  (S1 Tier)      │
└────────┬────────┘
         │ Event Grid
         │ Integration
         ↓
┌─────────────────┐
│  Event Grid     │
│  System Topic   │
└────────┬────────┘
         │ Triggers
         ↓
┌─────────────────┐
│  Azure Function │
│  (Java 21)      │
│  Consumption    │
└────────┬────────┘
         │ Stores Data
         ↓
┌─────────────────┐
│  Azure Redis    │
│  Cache (Basic)  │
└────────┬────────┘
         │ Reads Data
         ↓
┌─────────────────┐
│  Spring Boot    │
│  WebFlux API    │
│  (Docker/ACR)   │
└────────┬────────┘
         │ Server-Sent
         │ Events (SSE)
         ↓
┌─────────────────┐
│  HTML Dashboard │
│  (Real-time UI) │
└─────────────────┘

System Components

1. IoT Device Emulator (Windows Laptop)

Technology: Java 21, Maven

Purpose: Simulates IoT device collecting system metrics

Functionality:

  • Collects CPU temperature using OSHI library
  • Monitors CPU usage percentage
  • Tracks RAM usage (used/total MB)
  • Monitors disk space (used/total GB)
  • Sends telemetry every 5 seconds via MQTT protocol

Azure SDK: azure-iot-device-client for IoT Hub communication

Key Dependencies:

  • com.microsoft.azure.sdk.iot:iot-device-client:2.4.3
  • com.github.oshi:oshi-core:6.4.10
  • com.google.code.gson:gson:2.10.1

2. Azure IoT Hub

SKU: S1 (Standard tier)

Purpose: Central message hub for IoT device communication

Configuration:

  • Device identity: laptop-monitor
  • Protocol: MQTT
  • Retention: 1 day
  • Partition count: 2

Features:

  • Device-to-cloud messaging
  • Device authentication via connection strings
  • Integration with Event Grid for event routing

3. Azure Event Grid System Topic

Type: System Topic for IoT Hub

Purpose: Routes IoT Hub telemetry events to Azure Function

Event Types: Microsoft.Devices.DeviceTelemetry

Configuration:

  • Event subscription with Azure Function as endpoint
  • Retry policy: 30 attempts, 1440 minutes TTL
  • Batch size: 1 event per batch

4. Azure Function (Event Processor)

Runtime: Java 21 on Linux

Plan: Consumption (Y1 SKU)

Trigger: Event Grid trigger

Purpose: Process incoming telemetry and store in Redis

Functionality:

  • Receives telemetry events from Event Grid
  • Parses JSON payload (handles base64 encoding)
  • Stores data in Redis with TTL (1 hour expiration)
  • Maintains sorted set for time-based retrieval
  • Limits storage to last 1000 entries

Dependencies:

  • azure-functions-java-library:3.1.0
  • jedis:5.1.0 for Redis connection
  • gson:2.10.1 for JSON parsing

Function Code Structure:

@FunctionName("ProcessIoTEvent")
public void processEvent(
    @EventGridTrigger(name = "event") String eventData,
    final ExecutionContext context) {
    // Parse event, decode payload, store in Redis
}

5. Azure Redis Cache

SKU: Basic C0

Purpose: Temporary storage for telemetry data

Configuration:

  • SSL enabled (port 6380)
  • TLS 1.2 minimum
  • Public network access enabled
  • Eviction policy: allkeys-lru

Data Structure:

  • Keys: telemetry:<timestamp>
  • Sorted set: telemetry:timeline (for time-ordered retrieval)
  • TTL: 1 hour per entry

6. Azure Container Registry

SKU: Standard

Purpose: Store Docker images for Spring Boot application

Configuration:

  • Admin user enabled
  • Repository: iot-dashboard:latest
  • Public network access enabled

7. Spring Boot Microservice (API Backend)

Framework: Spring Boot 3.4.1, Java 21

Architecture: Reactive WebFlux

Hosting: Azure App Service (B1 Linux)

Container: Docker image from ACR

Purpose: REST API for telemetry data with real-time streaming

REST Endpoints:

  • GET /api/telemetry/stream - Server-Sent Events (SSE) stream
  • GET /api/telemetry/recent?count=N - Last N telemetry records
  • GET /actuator/health - Health check endpoint

Key Components:

  • RedisConfig: Reactive Redis connection with Lettuce client
  • TelemetryService: Flux-based reactive data streaming
  • TelemetryController: WebFlux REST endpoints with CORS enabled
  • TelemetryModel: Data model for telemetry records

Configuration:

server:
  port: 8080

redis:
  host: ${REDIS_HOST}
  port: ${REDIS_PORT}
  password: ${REDIS_PASSWORD}

Docker Configuration:

FROM eclipse-temurin:21-jdk-alpine AS build
WORKDIR /app
COPY pom.xml .
COPY src ./src
RUN mvn clean package -DskipTests

FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY --from=build /app/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]

8. HTML Dashboard (Frontend)

Technology: Pure HTML5, CSS3, JavaScript (ES6)

Hosting: Served as static content from Spring Boot app

Location: src/main/resources/static/index.html

Features:

  • Real-time updates via Server-Sent Events
  • Responsive grid layout with glassmorphism design
  • Visual progress bars with color coding (green/yellow/red)
  • Alert system for threshold violations (>75°C, >90% usage)
  • Auto-reconnection on connection loss
  • No page reload required

UI Components:

  • CPU Temperature card (threshold: >75°C warning)
  • CPU Usage card (threshold: >90% warning)
  • RAM Usage card with total/used display
  • Disk Usage card with total/used display
  • Connection status indicator
  • Last update timestamp

Data Flow

1. Telemetry Collection

IoT Emulator → Collects metrics every 5 seconds
              ↓
              Creates JSON payload:
              {
                "deviceId": "laptop-monitor",
                "timestamp": "2026-01-26T10:30:00Z",
                "cpuTemperature": 55.3,
                "cpuUsage": 23.5,
                "ramUsedMB": 8192,
                "ramTotalMB": 16384,
                "ramUsagePercent": 50.0,
                "diskUsedGB": 120,
                "diskTotalGB": 256,
                "diskUsagePercent": 46.9
              }

2. Message Transmission

MQTT Client → Sends to IoT Hub
            ↓
            IoT Hub validates device identity
            ↓
            Publishes to Event Grid topic

3. Event Processing

Event Grid → Triggers Azure Function
           ↓
           Function parses event data
           ↓
           Decodes base64 payload if needed
           ↓
           Stores in Redis:
           - Key: telemetry:<timestamp>
           - Value: JSON string
           - TTL: 3600 seconds
           - Sorted set: telemetry:timeline

4. Data Retrieval

Dashboard → HTTP GET to /api/telemetry/stream
          ↓
          Spring Boot WebFlux establishes SSE connection
          ↓
          Flux.interval(1 second) polls Redis
          ↓
          Queries sorted set for latest entry
          ↓
          Returns Flux<TelemetryModel>
          ↓
          Streams to client as Server-Sent Events

5. Dashboard Update

JavaScript EventSource → Receives SSE messages
                       ↓
                       Parses JSON
                       ↓
                       Updates DOM elements
                       ↓
                       Updates progress bars
                       ↓
                       Checks thresholds
                       ↓
                       Displays alerts if needed

Infrastructure Deployment

All infrastructure is deployed using pure Azure CLI commands.

Prerequisites

# Azure CLI
az login
az account set --subscription "YOUR_SUBSCRIPTION_ID"

# Java 21
java -version

# Maven
mvn -version

# Docker
docker --version

Deployment Steps

1. Set Variables

export SUBSCRIPTION_ID="your-subscription-id"
export RESOURCE_GROUP="rg-iot-monitoring"
export LOCATION="westeurope"
export UNIQUE_SUFFIX=$(date +%s | sha256sum | base64 | head -c 8 | tr '[:upper:]' '[:lower:]')

az account set --subscription $SUBSCRIPTION_ID

2. Create Resource Group

az group create \
  --name $RESOURCE_GROUP \
  --location $LOCATION

3. Create Storage Account

export STORAGE_ACCOUNT="stfunc${UNIQUE_SUFFIX}"

az storage account create \
  --name $STORAGE_ACCOUNT \
  --resource-group $RESOURCE_GROUP \
  --location $LOCATION \
  --sku Standard_LRS \
  --kind StorageV2 \
  --https-only true \
  --min-tls-version TLS1_2

4. Create IoT Hub

export IOT_HUB_NAME="iothub-mon-${UNIQUE_SUFFIX}"

az iot hub create \
  --name $IOT_HUB_NAME \
  --resource-group $RESOURCE_GROUP \
  --location $LOCATION \
  --sku S1 \
  --partition-count 2 \
  --retention-day 1

az iot hub device-identity create \
  --hub-name $IOT_HUB_NAME \
  --device-id laptop-monitor

5. Create Redis Cache

export REDIS_NAME="redis-mon-${UNIQUE_SUFFIX}"

az redis create \
  --name $REDIS_NAME \
  --resource-group $RESOURCE_GROUP \
  --location $LOCATION \
  --sku Basic \
  --vm-size C0 \
  --enable-non-ssl-port false \
  --minimum-tls-version 1.2

6. Create Container Registry

export ACR_NAME="acrmon${UNIQUE_SUFFIX}"

az acr create \
  --name $ACR_NAME \
  --resource-group $RESOURCE_GROUP \
  --location $LOCATION \
  --sku Standard \
  --admin-enabled true

7. Create Function App

export FUNCTION_APP_NAME="func-proc-${UNIQUE_SUFFIX}"

az functionapp create \
  --name $FUNCTION_APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --storage-account $STORAGE_ACCOUNT \
  --consumption-plan-location $LOCATION \
  --runtime java \
  --runtime-version 21 \
  --functions-version 4 \
  --os-type Linux

8. Create Web App

export APP_SERVICE_PLAN="plan-webapp-${UNIQUE_SUFFIX}"
export WEB_APP_NAME="webapp-dash-${UNIQUE_SUFFIX}"

az appservice plan create \
  --name $APP_SERVICE_PLAN \
  --resource-group $RESOURCE_GROUP \
  --location $LOCATION \
  --is-linux \
  --sku B1

az webapp create \
  --name $WEB_APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --plan $APP_SERVICE_PLAN \
  --deployment-container-image-name nginx

9. Create Event Grid System Topic

export EVENT_GRID_TOPIC="evt-mon-${UNIQUE_SUFFIX}"

az eventgrid system-topic create \
  --name $EVENT_GRID_TOPIC \
  --resource-group $RESOURCE_GROUP \
  --location $LOCATION \
  --topic-type Microsoft.Devices.IoTHubs \
  --source $(az iot hub show --name $IOT_HUB_NAME -g $RESOURCE_GROUP --query id -o tsv)

Application Deployment

1. Build and Deploy Azure Function

cd iot-function
mvn clean package

cd target/azure-functions/iot-function-local
zip -r ../../../../function-app.zip .
cd ../../../..

az functionapp deployment source config-zip \
  --resource-group $RESOURCE_GROUP \
  --name $FUNCTION_APP_NAME \
  --src function-app.zip

2. Build and Deploy Spring Boot Application

cd iot-dashboard-service
mvn clean package -DskipTests

docker build -t iot-dashboard:latest .
az acr login --name $ACR_NAME
docker tag iot-dashboard:latest $ACR_NAME.azurecr.io/iot-dashboard:latest
docker push $ACR_NAME.azurecr.io/iot-dashboard:latest

az webapp config container set \
  --name $WEB_APP_NAME \
  --resource-group $RESOURCE_GROUP \
  --docker-custom-image-name $ACR_NAME.azurecr.io/iot-dashboard:latest

az webapp restart --name $WEB_APP_NAME --resource-group $RESOURCE_GROUP

3. Configure and Run IoT Emulator

az iot hub device-identity connection-string show \
  --hub-name $IOT_HUB_NAME \
  --device-id laptop-monitor \
  --query connectionString -o tsv

# Update CONNECTION_STRING in IoTEmulator.java
cd iot-emulator
mvn clean package
java -jar target/iot-emulator-1.0.0.jar

Azure DevOps CI/CD Pipelines

Service Connection Setup

az ad sp create-for-rbac \
  --name "sp-azdo-iot-monitoring" \
  --role Contributor \
  --scopes /subscriptions/$SUBSCRIPTION_ID

Configure in Azure DevOps Project Settings → Service connections → New → Azure Resource Manager → Service principal (manual)

Function Pipeline (azure-pipelines-function.yml)

trigger:
  branches:
    include:
      - main
  paths:
    include:
      - iot-function/**

pool:
  vmImage: 'ubuntu-latest'

variables:
  azureSubscription: 'azure-iot-monitoring-sc'
  functionAppName: 'func-proc-<suffix>'
  resourceGroup: 'rg-iot-monitoring'

stages:
  - stage: Build
    jobs:
      - job: BuildFunction
        steps:
          - task: Maven@3
            inputs:
              mavenPomFile: 'iot-function/pom.xml'
              goals: 'clean package'

  - stage: Deploy
    jobs:
      - deployment: DeployFunction
        environment: 'production-function'
        strategy:
          runOnce:
            deploy:
              steps:
                - task: AzureFunctionApp@2
                  inputs:
                    azureSubscription: $(azureSubscription)
                    appName: $(functionAppName)
                    package: '$(System.ArtifactsDirectory)/function-app.zip'

Web App Pipeline (azure-pipelines-webapp.yml)

trigger:
  branches:
    include:
      - main
  paths:
    include:
      - iot-dashboard-service/**

pool:
  vmImage: 'ubuntu-latest'

variables:
  azureSubscription: 'azure-iot-monitoring-sc'
  webAppName: 'webapp-dash-<suffix>'
  containerRegistry: 'acrmon<suffix>'

stages:
  - stage: Build
    jobs:
      - job: BuildApp
        steps:
          - task: Maven@3
            inputs:
              mavenPomFile: 'iot-dashboard-service/pom.xml'
              goals: 'clean package'

          - task: Docker@2
            inputs:
              command: 'buildAndPush'
              repository: 'iot-dashboard'

  - stage: Deploy
    jobs:
      - deployment: DeployWebApp
        environment: 'production-webapp'
        strategy:
          runOnce:
            deploy:
              steps:
                - task: AzureWebAppContainer@1
                  inputs:
                    azureSubscription: $(azureSubscription)
                    appName: $(webAppName)

Monitoring and Operations

Health Checks

# Function App
az functionapp function list --name $FUNCTION_APP_NAME -g $RESOURCE_GROUP

# Web App
curl https://$WEB_APP_URL/actuator/health

# Redis
az redis show --name $REDIS_NAME -g $RESOURCE_GROUP --query provisioningState

Logs

# Function logs
az functionapp logs tail --name $FUNCTION_APP_NAME -g $RESOURCE_GROUP

# Web App logs
az webapp log tail --name $WEB_APP_NAME -g $RESOURCE_GROUP

# IoT Hub events
az iot hub monitor-events --hub-name $IOT_HUB_NAME

Security Considerations

  • Authentication: IoT devices use SAS token connection strings
  • Network: All traffic over HTTPS/TLS 1.2+
  • Secrets: Stored in App Settings (encrypted at rest)
  • Redis: SSL-only mode (port 6380)
  • CORS: Configured for Web App API access

Cost Optimization

Resource SKU Monthly Cost (USD)
IoT Hub S1 ~$25
Redis Cache Basic C0 ~$16
Function App Consumption ~$0.20/million executions
App Service B1 ~$13
Container Registry Standard ~$20
Total ~$75-100/month

Optimization Tips:

  • Use F1 (Free) IoT Hub tier if only one hub needed
  • Reduce Redis TTL to 30 minutes
  • Scale down App Service during off-hours
  • Clean up old Docker images regularly

Testing

End-to-End Test

# Terminal 1: Run emulator
cd iot-emulator
java -jar target/iot-emulator-1.0.0.jar

# Terminal 2: Monitor IoT Hub
az iot hub monitor-events --hub-name $IOT_HUB_NAME

# Terminal 3: Test API
curl https://$WEB_APP_URL/api/telemetry/recent?count=5

# Terminal 4: Open dashboard
open https://$WEB_APP_URL

Troubleshooting

IoT Emulator not connecting

az iot hub device-identity connection-string show \
  --hub-name $IOT_HUB_NAME \
  --device-id laptop-monitor

Function not receiving events

az eventgrid system-topic event-subscription show \
  --name iot-telemetry-subscription \
  -g $RESOURCE_GROUP \
  --system-topic-name $EVENT_GRID_TOPIC

Dashboard not showing data

curl -v https://$WEB_APP_URL/api/telemetry/recent?count=1
az webapp log tail --name $WEB_APP_NAME -g $RESOURCE_GROUP

Technology Stack Summary

Component Technology Version
Language Java 21
Build Tool Maven 3.9+
IoT SDK Azure IoT Device Client 2.4.3
Backend Framework Spring Boot 3.4.1
Reactive Framework Spring WebFlux 6.2.1
Redis Client Jedis / Lettuce 5.1.0
Container Runtime Docker Latest
Cloud Platform Microsoft Azure -

Project Structure

iot-monitoring-system/
├── iot-emulator/
│   ├── pom.xml
│   └── src/main/java/com/iot/emulator/
│       └── IoTEmulator.java
├── iot-function/
│   ├── pom.xml
│   ├── host.json
│   └── src/main/java/com/iot/function/
│       └── IoTEventProcessor.java
├── iot-dashboard-service/
│   ├── pom.xml
│   ├── Dockerfile
│   ├── src/main/java/com/iot/dashboard/
│   │   ├── IoTDashboardApplication.java
│   │   ├── config/RedisConfig.java
│   │   ├── controller/TelemetryController.java
│   │   ├── service/TelemetryService.java
│   │   └── model/TelemetryModel.java
│   └── src/main/resources/
│       ├── application.yml
│       └── static/index.html
├── azure-pipelines-function.yml
├── azure-pipelines-webapp.yml
└── README.md

Cleanup

az group delete --name $RESOURCE_GROUP --yes --no-wait

Conclusion

This IoT monitoring system demonstrates a complete cloud-native architecture using Azure PaaS services with real-time data streaming, serverless computing, and modern CI/CD practices.

Key Achievements

✅ Real-time data streaming with sub-second latency
✅ Serverless architecture for cost optimization
✅ Reactive programming for efficient resource usage
✅ Containerized deployments for portability
✅ Automated CI/CD pipelines for rapid iteration
✅ Infrastructure deployed entirely via Azure CLI
✅ Modern Java 21 features and Spring Boot 3.x


Last Updated: January 2026
Version: 1.0.0
Platform: Microsoft Azure
Runtime: Java 21

About

Example how to use Azure IotHub in conjunction with Azure EventGrid->Azure Function->Azure Redis and UI dashboard on Azure WebApp that's showing the processed events from IoT Hub

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors