IoT Dashboard & Visualization — Data Analytics Guide
In this tutorial, you'll learn about IoT Dashboard & Visualization. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
IoT data visualization transforms raw sensor readings into actionable insights through real-time dashboards, time-series charts, and anomaly detection alerts — turning millions of data points into decisions.
What You'll Learn
You'll build a real-time IoT dashboard with Grafana connected to InfluxDB, implement time-series visualizations for temperature, humidity, and vibration data, configure alert thresholds with anomaly detection, and design for mobile and large displays.
Why IoT Visualization Matters
A factory generates 100M data points per day. A raw data dump is useless. A well-designed dashboard shows: are temperatures rising? Which machine is vibrating abnormally? Is energy consumption spiking? At DodaTech, our IoT Security monitoring dashboard processes 50K events/second and displays alerts within 200ms — operators spot intrusions immediately.
Real-World Use Case
A water treatment plant deploys 200 sensors across filtration, chemical dosing, and outflow stages. The Grafana dashboard shows real-time pH, turbidity, and flow rate. When turbidity exceeds 1.0 NTU, a panel turns red and an alert triggers. Operators resolve issues 4x faster than with the previous SCADA system.
Dashboard Visualization Types
| Chart Type | Best For | Example |
|---|---|---|
| Time-Series Line | Continuous sensor values | Temperature over 24h |
| Gauge | Single metric against threshold | Tank level 0-100% |
| Bar Chart | Comparative values | Energy usage by zone |
| Heat Map | Density over time | Network traffic patterns |
| Geographical Map | Location-based data | Asset tracking |
| Status Grid | Binary/state data | Device online/offline |
Setting Up Grafana with InfluxDB
Docker Compose
version: '3.8'
services:
influxdb:
image: influxdb:2.7
ports:
- "8086:8086"
environment:
DOCKER_INFLUXDB_INIT_MODE: setup
DOCKER_INFLUXDB_INIT_USERNAME: admin
DOCKER_INFLUXDB_INIT_PASSWORD: password123
DOCKER_INFLUXDB_INIT_ORG: dodatech
DOCKER_INFLUXDB_INIT_BUCKET: iot_sensors
grafana:
image: grafana/grafana:10.2
ports:
- "3000:3000"
depends_on:
- influxdb
environment:
GF_SECURITY_ADMIN_PASSWORD: admin
Expected output: Run docker-compose up -d. Access Grafana at http://localhost:3000 (admin/admin) and InfluxDB at http://localhost:8086.
Writing Sensor Data to InfluxDB
from influxdb_client import InfluxDBClient, Point
from influxdb_client.client.write_api import SYNCHRONOUS
import time
import random
class IoTDataWriter:
def __init__(self):
self.client = InfluxDBClient(
url="http://localhost:8086",
token="my-token",
org="dodatech"
)
self.write_api = self.client.write_api(write_options=SYNCHRONOUS)
def write_sensor_reading(self, device_id, temperature,
humidity, vibration):
point = Point("sensor_reading") \
.tag("device_id", device_id) \
.tag("location", "factory_floor_a") \
.field("temperature", temperature) \
.field("humidity", humidity) \
.field("vibration", vibration) \
.time(time.time_ns())
self.write_api.write(bucket="iot_sensors", record=point)
def simulate_sensors(self, num_devices=5):
devices = [f"sensor-{i:03d}" for i in range(num_devices)]
while True:
for device in devices:
self.write_sensor_reading(
device_id=device,
temperature=22.0 + random.gauss(0, 3),
humidity=50.0 + random.gauss(0, 10),
vibration=random.uniform(0.1, 2.0)
)
time.sleep(10)
Expected output: Every 10 seconds, simulated sensor data is written to InfluxDB. Grafana queries this data for real-time visualization.
Grafana Dashboard Query
-- InfluxDB Flux query for Grafana
from(bucket: "iot_sensors")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "sensor_reading")
|> filter(fn: (r) => r["_field"] == "temperature")
|> filter(fn: (r) => r["device_id"] == "sensor-001")
|> aggregateWindow(every: 1m, fn: mean)
|> yield(name: "mean_temp")
Expected output: In Grafana, a time-series panel displays the average temperature per minute for sensor-001.
Real-Time Alerting
# Grafana alert webhook handler
from flask import Flask, request, jsonify
import json
app = Flask(__name__)
@app.route('/grafana-alert', methods=['POST'])
def handle_alert():
alert = request.json
alert_name = alert.get('title', 'Unknown')
state = alert.get('state', 'unknown') # alerting, ok, pending
message = alert.get('message', '')
values = alert.get('evalMatches', [])
print(f"[ALERT] {alert_name} -> {state}")
for match in values:
device = match.get('tags', {}).get('device_id', 'unknown')
value = match.get('value', 0)
print(f" Device: {device}, Value: {value}")
if state == 'alerting':
# Send to PagerDuty, Slack, SMS, etc.
send_slack_notification(alert_name, message)
# Log to database
log_alert_to_db(alert_name, state, values)
return jsonify({"status": "received"}), 200
def send_slack_notification(title, message):
webhook_url = "https://hooks.slack.com/services/YOUR/WEBHOOK"
payload = {
"text": f"*IoT Alert: {title}*\n{message}",
"channel": "#iot-alerts"
}
import requests
requests.post(webhook_url, json=payload)
Expected output: When a Grafana alert triggers (e.g., temperature > 35°C for 5 minutes), the webhook receives the alert payload and sends a Slack notification.
Anomaly Detection Dashboard
import numpy as np
from sklearn.ensemble import IsolationForest
import pandas as pd
class IoTAnomalyDetector:
def __init__(self, contamination=0.05):
self.model = IsolationForest(
contamination=contamination,
random_state=42
)
self.is_fitted = False
def fit(self, historical_data):
"""Train on normal sensor data."""
features = historical_data[['temperature', 'humidity',
'vibration', 'pressure']]
self.model.fit(features)
self.is_fitted = True
print(f"Model trained on {len(features)} samples")
def predict(self, sensor_reading):
if not self.is_fitted:
return {'anomaly': False, 'reason': 'Model not trained'}
features = np.array([[
sensor_reading['temperature'],
sensor_reading['humidity'],
sensor_reading['vibration'],
sensor_reading['pressure']
]])
prediction = self.model.predict(features)
score = self.model.score_samples(features)
is_anomaly = prediction[0] == -1
return {
'anomaly': is_anomaly,
'confidence': float(1 - abs(score[0])),
'severity': 'high' if score[0] < -0.5 else 'medium' if is_anomaly else 'none'
}
detector = IoTAnomalyDetector()
# detector.fit(historical_data) # Train on 30+ days of data
reading = {'temperature': 45.0, 'humidity': 80,
'vibration': 5.2, 'pressure': 1020}
result = detector.predict(reading)
print(f"Anomaly: {result['anomaly']}, Severity: {result['severity']}")
Expected output: The Isolation Forest model flags readings with unusual combinations (e.g., high temp + high vibration) as anomalies, even if individual values are within normal range.
Mermaid Diagram: Dashboard Data Pipeline
flowchart LR
A[IoT Devices] -->|MQTT| B[IoT Platform]
B -->|Rules Engine| C[Time-Series DB]
C --> D[Grafana]
D --> E[Dashboard Panels]
D --> F[Alert Rules]
F -->|Webhook| G[Slack / PagerDuty]
C --> H[Anomaly Detection]
H --> F
E -->|0-100ms latency| I[Operator Display]
style C fill:#e6f3ff
style D fill:#ffcc80
style G fill:#d4edda
Common Dashboard Errors
1. Too Many Panels
Problem: 50 panels on one dashboard — information overload. Fix: Create focused dashboards by topic (Temperature, Alerts, Energy) — max 12 panels each.
2. Wrong Time Range
Problem: Default shows 6 hours but trend requires 30 days. Fix: Make time range selectable and pre-set appropriate defaults per dashboard.
3. No Aggregation
Problem: Raw 1-second data in a 30-day view (2.6M points).
Fix: Use $__interval variable in Grafana to auto-aggregate based on zoom level.
4. Alert Fatigue
Problem: 200 alerts/day — operators ignore them. Fix: Use thresholds with hysteresis (alert at 35°C, resolve at 32°C) and minimum duration.
5. Dashboard Drift
Problem: Dashboard shows stale data after sensor re-deployment. Fix: Document and regularly update queries when metric names change.
6. No Anomaly Baseline
Problem: Static thresholds miss gradual degradation. Fix: Use ML-based dynamic thresholds that learn normal patterns per device.
Practice Questions
What is the difference between time-series DB and relational DB for IoT? Time-series DBs (InfluxDB, TimescaleDB) optimize for append-heavy, timestamped data with automatic downsampling and retention policies.
Why use Grafana over building a custom dashboard? Grafana supports multiple data sources, built-in alerting, RBAC, dashboard sharing, and a plugin ecosystem — building equivalent features takes months.
What is hysteresis in alert thresholds? Different values for alert and resolve (alert at 35°C, resolve at 32°C) prevents flapping when value oscillates around the threshold.
How do you handle data gaps in visualization? Use
fill(previous)orfill(linear)in Flux queries, or Grafana's "null value" settings to connect or display gaps.What is downsampling and why is it important? Aggregating raw data to lower resolution (e.g., hourly averages). Reduces storage from TB to GB for long-term retention.
Challenge
Build a complete IoT monitoring stack: simulate 10 sensors (temperature, humidity, vibration) writing to InfluxDB, create a Grafana dashboard with 6 panels (time-series, gauges, heatmap), configure 3 alert rules with webhook to Slack, and implement auto-downsampling to keep storage under 1GB.
Real-World Task
Your manufacturing plant has 50 vibration sensors. Operators currently scan raw values manually every hour. Build a dashboard showing: real-time vibration per machine (time-series), historical trend (7-day), alerts when FFT analysis shows bearing wear frequency, and a status grid showing healthy/warning/critical per machine.
Mini Project: IoT Dashboard Builder
import json
import requests
class GrafanaDashboardBuilder:
def __init__(self, grafana_url, api_key):
self.url = grafana_url
self.headers = {
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json'
}
def create_dashboard(self, title, sensors):
panels = []
for i, sensor in enumerate(sensors):
panel = {
"type": "timeseries",
"title": sensor['name'],
"gridPos": {"x": i % 3 * 8, "y": i // 3 * 8,
"w": 8, "h": 8},
"targets": [{
"query": sensor['query'],
"refId": "A"
}]
}
panels.append(panel)
dashboard = {
"dashboard": {
"title": title,
"panels": panels,
"timezone": "browser",
"schemaVersion": 36
},
"overwrite": True
}
response = requests.post(
f"{self.url}/api/dashboards/db",
headers=self.headers,
json=dashboard
)
return response.json()
# Usage
builder = GrafanaDashboardBuilder(
"http://localhost:3000",
"glsa_api_key_here"
)
builder.create_dashboard("Factory Floor A", [
{"name": "Temperature", "query": "temperature query"},
{"name": "Vibration", "query": "vibration query"},
])
This script automates dashboard creation for new sensor deployments.
Related Tutorials
- IoT Cloud Platforms — Data sources for dashboards
- IoT Edge Computing — Local dashboards for edge nodes
- IoT Industry Applications — Real-world dashboard use cases
- Next: IoT Industry Applications — Smart Home, Healthcare & Manufacturing
- Previous: IoT Cloud Platforms — AWS IoT, Azure IoT & GCP IoT
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro