A complete end-to-end solution for IoT predictive maintenance using Azure IoT Hub, Microsoft Fabric, Machine Learning, Power BI, Power Automate, and Power Apps. This project demonstrates how to predict drill bit replacements on industrial screw machines to prevent unexpected downtime.
- 40-60% reduction in unplanned downtime
- Proactive maintenance scheduling based on ML predictions
- Real-time monitoring with Power BI dashboards
- Automated alerting via email and Microsoft Teams
- Mobile work order management for maintenance engineers
- Cost savings from optimized parts inventory and labor scheduling
This repository contains a complete, production-ready solution:
- IoT Device Simulator - Python simulator for 10 screw robot devices
- ML Training Pipeline - Jupyter notebook for predictive maintenance model
- Power BI Dashboard - Real-time monitoring with Gantt chart timeline
- Power Automate Flows - Automated email alerts and work order creation
- Power Apps Solution - Mobile work order management system
- Complete Documentation - Step-by-step setup guides for all components
- 10 Concurrent Devices: Simulates 10 independent screw robot devices running simultaneously
- Event-Based Telemetry: Sends telemetry per screwing operation (configurable 60s intervals with jitter)
- Rich Sensor Data: Temperature, vibration, power consumption, rotation counts, component health scores
- Anomaly Detection: Configurable anomaly injection (duration, speed, temperature, vibration)
- Component Degradation: Optional simulation of gradual machine wear over operational hours
- Hot-Reload Configuration: Modify
.envsettings while simulator runs for real-time testing - Microsoft Fabric Ready: Optimized for ingestion via Fabric Eventstream to Warehouse and Power BI
┌──────────────────────────────────────────────────────────────────────┐
│ IoT Device Layer │
│ 10 Screw Robot Devices (Python Simulator) │
│ • Temperature, Vibration, Torque, Rotation Counters │
│ • Anomaly injection & component degradation simulation │
└────────────┬─────────────────────────────────────────────────────────┘
│ MQTT/AMQP (TLS)
↓
┌──────────────────────────────────────────────────────────────────────┐
│ Azure IoT Hub │
│ • Device authentication & management │
│ • Built-in Event Hub endpoint │
└────────────┬─────────────────────────────────────────────────────────┘
│
↓
┌──────────────────────────────────────────────────────────────────────┐
│ Microsoft Fabric Eventstream │
│ • Real-time ingestion from IoT Hub │
│ • KQL transformations │
└────────────┬─────────────────────────────────────────────────────────┘
│
↓
┌──────────────────────────────────────────────────────────────────────┐
│ Fabric Lakehouse │
│ • Bronze: Raw telemetry (quality_data table) │
│ • Silver: ML predictions (replacement_predictions table) │
└────────────┬─────────────────────────────────────────────────────────┘
│
┌─────┴─────┐
│ │
↓ ↓
┌─────────────┐ ┌──────────────────────────────────────────────────────┐
│ ML Pipeline │ │ Power BI Dashboard │
│ (Notebook) │ │ • Gantt chart timeline │
│ • XGBoost │ │ • Risk level indicators │
│ • MLflow │ │ • Real-time metrics │
│ • Daily │ │ • Machine health scores │
│ Scoring │ └──────────────────────────────────────────────────────┘
└─────┬───────┘
│
↓
┌──────────────────────────────────────────────────────────────────────┐
│ Power Automate │
│ • Trigger: New critical prediction (IsCritical = 1) │
│ • Send email alert to maintenance team │
│ • Create work order in Dataverse/SharePoint │
│ • Post notification to Microsoft Teams │
└────────────┬─────────────────────────────────────────────────────────┘
│
↓
┌──────────────────────────────────────────────────────────────────────┐
│ Power Apps (Canvas App) │
│ • Browse work orders │
│ • Assign to engineers │
│ • Update status (New → In Progress → Completed) │
│ • Mobile access from factory floor │
└──────────────────────────────────────────────────────────────────────┘
Core Services:
- Python 3.8 or higher
- Azure subscription
- Azure IoT Hub (Standard tier S1 recommended)
- Microsoft Fabric workspace (F64 capacity or higher)
Licenses (for complete solution):
- Microsoft Fabric: F64 capacity (~$8,197/month) - includes Power BI Premium
- Microsoft 365: E3, E5, or Business Premium - for Outlook, SharePoint, Teams
- Power Platform (choose one):
- Option A: Power Apps Premium (~$20/user/month) + Dataverse
- Option B: Included with Microsoft 365 (SharePoint backend)
💡 Cost-Effective Path: Use Microsoft 365 E3 + Fabric F64 with SharePoint backend to avoid Power Apps premium costs.
See requirements.txt for complete list:
azure-iot-device- IoT Hub connectivitypandas,numpy- Data manipulationxgboost- ML modelscikit-learn- ML utilitiesmlflow- Experiment tracking
Follow these labs in order to build the complete solution:
- Clone this repository
- Create Azure IoT Hub and register 10 devices
- Configure
.envwith connection strings - Run
python main.pyto start sending telemetry - Verify data in Azure Portal
Guide: See section "Detailed Setup - IoT Simulator" below
- Create Microsoft Fabric workspace
- Set up Eventstream to ingest from IoT Hub
- Create Lakehouse with
quality_datatable - Verify real-time data flowing into Lakehouse
Guide: FABRIC_EVENTSTREAM_SETUP.md
- Upload
sample_quality_data.csvto Lakehouse Files - Open
ML_Replacement_Date_Prediction.ipynbin Fabric - Run all 15 parts sequentially
- Train XGBoost model to predict bit replacement dates
- Deploy daily scoring pipeline
Guide: FABRIC_ML_PREDICTIVE_LAB.md + Notebook Part 1-15
- Create Power BI report connected to Lakehouse
- Build Gantt chart timeline visualization
- Add risk level indicators and KPIs
- Publish dashboard to workspace
Guide: POWERBI_MAINTENANCE_LAB.md
- Create cloud flow triggered by critical predictions
- Send email alerts to maintenance team
- Create work orders in Dataverse or SharePoint
- Post notifications to Microsoft Teams
Guide: Notebook Part 13 or create POWER_AUTOMATE_SETUP.md
- Create Work Orders table in Dataverse/SharePoint
- Build canvas app with 3 screens (Browse/Detail/Edit)
- Add buttons for assign, start, and complete actions
- Share app with maintenance engineers
Guide: Notebook Part 14 or create POWER_APPS_SETUP.md
Using Azure Portal:
- Navigate to Azure Portal
- Create a new IoT Hub:
- Resource: IoT Hub
- Pricing tier: S1 (Standard) or higher
- Name: Choose a unique name (e.g.,
my-iot-hub)
Using Azure CLI:
# Login to Azure
az login
# Create resource group
az group create --name iot-simulator-rg --location eastus
# Create IoT Hub
az iot hub create --name my-iot-hub --resource-group iot-simulator-rg --sku S1Using Azure Portal:
- In your IoT Hub, go to Devices > Add Device
- Create devices with IDs:
screw-robot-001screw-robot-002- ... through
screw-robot-010
- Authentication: Symmetric Key (use the same shared access key)
Using Azure CLI:
# Register 10 devices with the same shared access key
for ($i=1; $i -le 10; $i++) {
$deviceId = "screw-robot-{0:D3}" -f $i
az iot hub device-identity create --hub-name my-iot-hub --device-id $deviceId
}Important: All devices can share the same SharedAccessKey for simplicity in simulation scenarios. The device identity is determined by the DeviceId in the connection string.
-
Clone or download this repository
-
Install Python dependencies:
pip install -r requirements.txt- Create
.envfile from template:
Copy-Item .env.example .env- Update
.envwith your IoT Hub configuration:
Open .env and configure your IoT Hub settings:
# Your IoT Hub hostname (without https://)
IOTHUB_HOSTNAME=my-iot-hub.azure-devices.net
# Shared access key (from device settings or iothubowner policy)
IOTHUB_SHARED_ACCESS_KEY=your-actual-shared-access-key-here
# Device ID prefix (devices will be: screw-robot-001, screw-robot-002, etc.)
DEVICE_ID_PREFIX=screw-robot
# Number of devices to simulate
NUM_DEVICES=10Getting your Shared Access Key:
Option 1 - From a device (recommended for device simulation):
# Get key from first device
az iot hub device-identity connection-string show --hub-name my-iot-hub --device-id screw-robot-001
# Copy the SharedAccessKey value from the connection stringOption 2 - From IoT Hub policy (for testing only):
# Get iothubowner key (has full permissions)
az iot hub policy show --name iothubowner --hub-name my-iot-hub --query primaryKey -o tsv- Adjust simulation parameters (optional):
NUM_DEVICES=10 # Number of devices to simulate (1-10)
SCREWING_INTERVAL_SECONDS=60 # Base interval between operations
INTERVAL_JITTER_SECONDS=10 # Random variance (±seconds)
CONSTANT_SPEED_RPM=1800 # Nominal screwing speed
ANOMALY_RATE=0.05 # 5% anomaly probability
ENABLE_DEGRADATION=false # Component wear simulation
LOG_LEVEL=INFO # DEBUG, INFO, WARNING, ERRORpython main.pyYou should see output similar to:
╔══════════════════════════════════════════════════════════════════╗
║ IoT Screw Robot Simulator for Azure IoT Hub ║
╚══════════════════════════════════════════════════════════════════╝
Configuration:
• Number of devices: 10
• Screwing interval: 60s (±10s jitter)
• Constant speed: 1800 RPM
• Anomaly rate: 5.0%
• Degradation: Disabled
• Log level: INFO
Hot-Reload Enabled:
✓ You can modify .env while the simulator is running
✓ Changes will be applied before each screwing operation
✓ Try changing ANOMALY_RATE to test different scenarios
Press Ctrl+C to stop the simulation
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
2025-11-18 10:30:00 - __main__ - INFO - Initializing 10 device simulators...
2025-11-18 10:30:01 - device_simulator - INFO - screw-robot-001: Connected to IoT Hub
2025-11-18 10:30:02 - device_simulator - INFO - screw-robot-002: Connected to IoT Hub
...
The simulator supports hot-reload of configuration, allowing you to modify settings while it's running:
- Start the simulator with default settings
- Edit
.envwhile simulator is running:ANOMALY_RATE=0.25 # Change from 0.05 to 0.25 (25% anomalies)
- Save the file - changes apply before next screwing operation
- Check logs for confirmation:
2025-11-18 10:35:00 - config_loader - INFO - Configuration changed: anomaly_rate: 0.05 -> 0.25
You can dynamically adjust:
SCREWING_INTERVAL_SECONDS- Change operation frequencyINTERVAL_JITTER_SECONDS- Adjust timing varianceTEMP_ANOMALY_THRESHOLD- Modify temperature alertingVIBRATION_SPIKE_THRESHOLD- Adjust vibration sensitivityENABLE_DEGRADATION- Toggle component wear simulationLOG_LEVEL- Change logging verbosity
Each screwing operation sends a JSON message with the following structure:
{
"deviceId": "screw-robot-001",
"eventId": "f7da01b0-090b-41d2-8416-dacae09fbb4a",
"timestamp": "2025-11-18T10:30:45.123Z",
"rotationCount": 90,
"duration": 2.134,
"speed": 1798.5,
"isAnomaly": false,
"anomalyType": null,
"temperature": 72.45,
"vibration": 0.432,
"powerConsumption": 5.23,
"operationalHours": 15.42,
"totalOperations": 234,
"totalAnomalies": 12,
"componentHealth": {
"motor": 0.987,
"bearing": 0.943,
"sensor": 0.995
},
"overallHealthScore": 0.975
}Custom properties added to each message for routing and filtering:
| Property | Values | Purpose |
|---|---|---|
deviceType |
screw-robot |
Device categorization |
alertLevel |
normal, warning |
Quick anomaly filtering |
maintenanceStatus |
healthy, warning, critical |
Health-based routing |
iothub-creation-time-utc |
ISO 8601 timestamp | Event time tracking |
| Field | Type | Description |
|---|---|---|
deviceId |
string | Unique device identifier |
eventId |
string | UUID for this specific event |
timestamp |
string | ISO 8601 UTC timestamp |
rotationCount |
integer | Number of screw rotations completed |
duration |
float | Operation duration in seconds |
speed |
float | Actual screwing speed in RPM |
isAnomaly |
boolean | Whether this operation is anomalous |
anomalyType |
string | Type(s) of anomaly detected |
temperature |
float | Motor temperature in Celsius |
vibration |
float | Vibration level in g-force |
powerConsumption |
float | Power usage in kilowatts |
operationalHours |
float | Cumulative device runtime hours |
totalOperations |
integer | Total screwing operations performed |
totalAnomalies |
integer | Total anomalies detected |
componentHealth |
object | Health scores (0-1) per component |
overallHealthScore |
float | Average health score (0-1) |
The simulator generates different types of anomalies based on ANOMALY_RATE:
| Anomaly Type | Condition | Normal Range | Anomaly Range |
|---|---|---|---|
duration_too_short |
Duration < 1s | 1.0-3.0s | 0.3-0.9s |
duration_too_long |
Duration > 3s | 1.0-3.0s | 3.5-5.0s |
temperature_spike |
Temp > threshold | 60-75°C | >85°C |
excessive_vibration |
Vibration > threshold | 0.2-0.6g | >2.0g |
speed_drop |
Speed < 85% nominal | ±2% variance | -15% drop |
Multiple anomaly types can occur simultaneously (e.g., duration_too_long,temperature_spike).
When ENABLE_DEGRADATION=true, component health degrades over operational hours:
| Component | Degradation Rate | Impact |
|---|---|---|
| Motor | 15% per 1000 hours | Temperature ↑, Power ↑ |
| Bearing | 12% per 1000 hours | Vibration ↑ |
| Sensor | 5% per 1000 hours | Minimal impact |
Health scores (0.0-1.0) decrease gradually, creating realistic predictive maintenance training data.
-
Create Eventstream Source:
- Open Microsoft Fabric workspace
- Create new Eventstream
- Add source: Azure IoT Hub
- Connection: Select your IoT Hub
- Endpoint:
messages/events(built-in) - Consumer group:
$Defaultor create dedicated group
-
Add Data Transformation (Optional):
Filter anomalies for separate processing:
| where isAnomaly == true
Calculate time-to-failure predictions:
| extend predictedFailureHours = case( overallHealthScore > 0.9, 1000.0, overallHealthScore > 0.7, 500.0, overallHealthScore > 0.5, 200.0, 50.0 )
-
Configure Warehouse Destination:
- Add destination: Fabric Warehouse
- Create table schema matching telemetry JSON
- Map fields accordingly
- Set ingestion mode: Streaming
CREATE TABLE ScrewRobotTelemetry (
DeviceId VARCHAR(50) NOT NULL,
EventId VARCHAR(50) NOT NULL,
Timestamp DATETIME2 NOT NULL,
RotationCount INT,
Duration FLOAT,
Speed FLOAT,
IsAnomaly BIT,
AnomalyType VARCHAR(200),
Temperature FLOAT,
Vibration FLOAT,
PowerConsumption FLOAT,
OperationalHours FLOAT,
TotalOperations INT,
TotalAnomalies INT,
MotorHealth FLOAT,
BearingHealth FLOAT,
SensorHealth FLOAT,
OverallHealthScore FLOAT,
PRIMARY KEY (DeviceId, Timestamp, EventId)
);
-- Index for time-series queries
CREATE INDEX IX_Timestamp ON ScrewRobotTelemetry(Timestamp DESC);
-- Index for anomaly filtering
CREATE INDEX IX_IsAnomaly ON ScrewRobotTelemetry(IsAnomaly, Timestamp DESC);
-- Index for device-specific queries
CREATE INDEX IX_DeviceId ON ScrewRobotTelemetry(DeviceId, Timestamp DESC);1. Real-Time Anomaly Monitor
- Card visual: Count of anomalies in last hour
- Line chart: Anomaly rate over time by device
- Table: Recent anomalies with details
2. Predictive Maintenance Dashboard
- Gauge: Overall health score per device
- Scatter plot: Component health (motor vs bearing)
- Timeline: Health degradation trend
- Alert table: Devices requiring maintenance (health < 0.7)
3. Operational Metrics
- KPI: Total operations per device
- Bar chart: Average duration by device
- Line chart: Temperature/vibration trends
- Histogram: Duration distribution (normal vs anomaly)
4. Efficiency Analysis
- Average screwing speed vs. time
- Power consumption patterns
- Correlation: Health score vs. operational hours
- Device comparison matrix
Error: "Authentication failed"
- Verify connection strings in
.envare correct - Check device exists in IoT Hub
- Ensure SharedAccessKey is complete
Error: "Connection failed"
- Verify IoT Hub is running
- Check network connectivity
- Ensure firewall allows MQTT (8883) or AMQP (5671)
Error: "IOTHUB_HOSTNAME is required"
- Ensure
IOTHUB_HOSTNAMEis set in.env(e.g.,my-iot-hub.azure-devices.net) - Do not include
https://prefix
Error: "IOTHUB_SHARED_ACCESS_KEY is required"
- Get the SharedAccessKey from your device connection string
- Copy only the key value (the long base64-encoded string)
Error: "Authentication failed"
- Verify
IOTHUB_SHARED_ACCESS_KEYis correct - Ensure devices are registered in IoT Hub with matching DeviceIds
- Check that devices use the same SharedAccessKey
Configuration not reloading
- Check
.envfile is in the same directory asmain.py - Ensure file is being saved properly
- Check logs for parsing errors
High CPU usage
- Increase
SCREWING_INTERVAL_SECONDS(reduce message frequency) - Reduce
NUM_DEVICESif testing on limited hardware - Set
LOG_LEVEL=WARNINGto reduce logging overhead
iot-simulator/
├── README.md # This file - project overview
├── LICENSE # MIT License
├── .gitignore # Git ignore patterns
│
├── IoT Simulator/ # Device simulation
│ ├── main.py # Main orchestrator
│ ├── device_simulator.py # Device simulator with IoT Hub SDK
│ ├── telemetry_generator.py # Telemetry data generator
│ ├── config_loader.py # Hot-reload configuration manager
│ ├── requirements.txt # Python dependencies
│ ├── .env.example # Configuration template
│ ├── generate_historical_data.py # Generate 30-day historical dataset
│ └── register_devices.ps1 # PowerShell script to register 10 devices
│
├── ML Pipeline/ # Machine Learning
│ ├── ML_Replacement_Date_Prediction.ipynb # Complete ML training lab (15 parts)
│ └── FABRIC_ML_PREDICTIVE_LAB.md # ML pipeline setup guide
│
├── Power BI/ # Business Intelligence
│ └── POWERBI_MAINTENANCE_LAB.md # Dashboard setup guide
│
├── Power Platform/ # Automation & Apps
│ ├── POWER_AUTOMATE_SETUP.md # Email alerts & work order creation
│ └── POWER_APPS_SETUP.md # Work order management app
│
├── Sample Data/ # Test datasets
│ ├── sample_quality_data.csv # 30-day IoT telemetry sample
│ ├── sample_screw_machine_data.csv # Additional test data
│ └── historical_telemetry_30days.csv # Pre-generated historical data
│
└── Documentation/ # Guides
├── FABRIC_EVENTSTREAM_SETUP.md # Eventstream configuration
├── SCHEMA_MIGRATION_GUIDE.md # Data schema evolution
└── MIGRATION_COMPLETE.md # Migration notes
LOG_LEVEL=DEBUG # Shows all config checks, telemetry generation
LOG_LEVEL=INFO # Shows connections, config changes, messages sent
LOG_LEVEL=WARNING # Shows only warnings and errors# Higher anomaly rate for stress testing
ANOMALY_RATE=0.30 # 30% anomalies
# More sensitive thresholds
TEMP_ANOMALY_THRESHOLD=80
VIBRATION_SPIKE_THRESHOLD=1.5
SPEED_VARIANCE_PERCENT=20# Send messages more frequently (every 10s)
SCREWING_INTERVAL_SECONDS=10
INTERVAL_JITTER_SECONDS=2- Validation MAE: ~150-300 rotations (~0.5-1 day accuracy)
- R² Score: 0.85-0.95 (excellent predictive power)
- Feature Importance: Cumulative rotations (65%), rolling avg (20%), time features (15%)
- 40-60% reduction in unplanned downtime
- 2-3 day advance notice for planned maintenance
- 15-20% savings on parts inventory costs
- ROI: Typically 6-12 months for mid-size manufacturing
- Real-time monitoring of 10 machines
- Critical alerts: <1 day remaining (red indicator)
- High priority: 1-3 days remaining (orange)
- Medium priority: 3-7 days remaining (yellow)
- Low priority: >7 days remaining (green)
Contributions are welcome! Please feel free to submit a Pull Request. For major changes:
- Fork the repository
- Create a feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
- Fabric Eventstream Setup - Configure real-time data ingestion
- ML Predictive Lab - Train and deploy ML model
- Power BI Dashboard - Build monitoring dashboard
- Schema Migration Guide - Data schema evolution
- Migration Notes - Project migration history
Q: Can I use this with on-premises data? A: Yes, use Azure IoT Edge or Azure Data Factory for on-premises connectivity.
Q: What if I don't have 10 machines?
A: Modify NUM_DEVICES in .env to simulate any number (1-100).
Q: Can I use Azure Synapse instead of Fabric? A: Yes, but you'll need to adapt the notebook and use Synapse Spark pools.
Q: Do I need Power Apps premium license? A: No, use SharePoint List backend (Option B in Part 14) with Microsoft 365.
Q: How long does it take to get predictions? A: ML model trains in 5-10 minutes. Daily predictions run in <2 minutes.
Q: Can I add more sensors (e.g., pressure, humidity)?
A: Yes, modify telemetry_generator.py to add custom sensor fields.
MIT License
Copyright (c) 2025
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
For issues or questions:
- GitHub Issues: Create an issue
- Azure IoT Hub: Documentation
- Microsoft Fabric: Documentation
- Power Platform: Documentation
Built with:
- Azure IoT Hub - Device connectivity
- Microsoft Fabric - Data platform
- XGBoost - ML model
- Power BI - Visualization
- Power Platform - Low-code automation
Special thanks to the Microsoft Fabric and Power Platform teams for excellent documentation.
\ud83d\ude80 Ready to build predictive maintenance solutions? Start with Lab 1!
Made with \u2764\ufe0f for the Manufacturing Industry
Quick Start \u2022 Structure \u2022 Docs \u2022 License