A simple, efficient Docker-based monitoring stack with intelligent thermostat control for Shelly BLU H&T sensors via HTTP polling.
This project creates a complete IoT solution featuring:
- Shelly Pro 2 as Bluetooth gateway and switch controller
- Shelly BLU H&T sensors for temperature/humidity measurement
- Intelligent Thermostat with temperature averaging and timing control
- HTTP Polling for simple, reliable data collection (no MQTT complexity!)
- InfluxDB for time-series data storage
- FastAPI for REST API and Prometheus metrics
- Grafana for visualization (user-configured)
Shelly BLU H&T Sensors (Bluetooth)
↓
Shelly Pro 2 (BT Gateway + Switch Controller)
↓
HTTP Polling (every 30s)
↓
Sensor Poller Service
↓
InfluxDB ←──────────┐
↓ │
FastAPI + Thermostat │
↓ │
Temperature Averaging (configurable samples)
↓ │
Control Logic ─────────┘
↓
Switch Control (Shelly Pro 2)
↓
Heating/Cooling Device
Simple and reliable: No message brokers, no complex MQTT configurations, just straightforward HTTP polling with intelligent control.
- Shelly Pro 2 (Model: SPSW-202XE12UL) - Firmware 1.6.2+
- Acts as Bluetooth gateway for sensors
- Controls heating/cooling via built-in relay switches
- Shelly BLU H&T Bluetooth temperature/humidity sensors (1 or more)
- At least one sensor required for thermostat control
- Indoor sensor used for temperature control
- Network connectivity for the Shelly Pro 2
- Pair your Shelly BLU H&T sensors with the Shelly Pro 2 using the Shelly app or web interface
- Verify sensors are detected and named (e.g., "temp_outdoor", "temp_indoor")
Edit sensor-poller/poller.py to match your sensor configuration:
SENSORS = [
{
"device_id": 200, # Your sensor's device ID from Shelly
"name": "temp_outdoor",
"mac": "7c:c6:b6:ab:66:13", # MAC address from Shelly
# ... sensor IDs
}
]Use ./check_sensors.sh to discover your sensor IDs and MAC addresses.
# Set your Shelly IP in docker-compose.yml (default: 192.168.2.12)
docker-compose up -d# Check sensor health
./check_sensors.sh
# View sensor data
curl http://localhost:8001/api/v1/sensors
# Check Prometheus metrics
curl http://localhost:8001/metrics | grep sensor_temperaturePoint Prometheus at http://localhost:8001/metrics and use queries like:
# Query by sensor name (recommended)
sensor_temperature_celsius{sensor_name="temp_outdoor"}
sensor_temperature_celsius{sensor_name="temp_indoor"}
# Or by device_id (Shelly device ID: 200, 201, 202)
sensor_temperature_celsius{device_id="200"}
# Or by gateway_id (Shelly Pro 2 MAC address)
sensor_temperature_celsius{gateway_id="shellypro2-8813bfddbfe8"}
Available labels:
device_id- Shelly device ID (200, 201, 202)gateway_id- Shelly Pro 2 gateway MAC addresssensor_id- BLE sensor MAC addresssensor_name- Human-readable name (temp_outdoor, temp_indoor, temp_buffer)
- Real-time temperature and humidity data from multiple sensors
- Prometheus metrics export for Grafana dashboards
- InfluxDB storage for historical analysis
- REST API for easy integration
-
4 Operating Modes:
AUTO- Normal temperature control with target setpointECO- Energy-saving mode with lower target temperatureON- Manual override (force heating ON)OFF- Manual override (force heating OFF)
-
Smart Temperature Control:
- Configurable temperature averaging (reduces noise from slow-responding systems)
- Symmetric hysteresis prevents oscillation (turn on/off thresholds)
- Minimum ON/OFF time constraints prevent rapid cycling
- Ideal for underfloor heating, radiators, or any slow thermal mass system
-
Safety & Reliability:
- Automatic health monitoring and container restart
- Persistent configuration survives restarts
- Human-readable JSON config file on host
- Real-time logging of all control decisions
-
Monitoring:
- Web-based live monitor at
/monitor- View control loop logs in real-time from any browser - WebSocket streaming with 30-line history buffer
- Live control loop monitoring scripts (
watch_thermostat.sh) - Historical decision review (
show_thermostat_history.sh) - Comprehensive logging with log rotation
- API endpoint for current status
- Web-based live monitor at
| Service | Port | Purpose |
|---|---|---|
| sensor-poller | - | Polls Shelly Pro 2 for sensor data every 30s |
| influxdb | 8086 | Time-series database |
| api | 8001 | REST API + Prometheus metrics + Thermostat control |
Edit docker-compose.yml to configure:
SHELLY_IP: IP address of your Shelly Pro 2 (default: 192.168.2.12)POLL_INTERVAL: Seconds between polls (default: 30)INFLUXDB_*: InfluxDB connection settings
Update sensor-poller/poller.py with your actual sensor details:
- Device IDs from Shelly
- MAC addresses
- Sensor names
- BTHome sensor component IDs
Run ./check_sensors.sh to discover your configuration.
# View current configuration
curl http://localhost:8001/api/v1/thermostat/config
# Set target temperature to 22°C in AUTO mode
curl -X POST http://localhost:8001/api/v1/thermostat/config \
-H "Content-Type: application/json" \
-d '{
"target_temp": 22.0,
"eco_temp": 18.0,
"mode": "AUTO",
"hysteresis": 0.5,
"min_on_time": 30,
"min_off_time": 10,
"temp_sample_count": 3,
"control_interval": 180
}'# Watch real-time control decisions
./watch_thermostat.sh
# View historical decisions
./show_thermostat_history.sh
# Check current status
curl http://localhost:8001/api/v1/thermostat/statusSettings are persisted in ./data/thermostat_config.json and can be edited directly:
{
"config": {
"target_temp": 22.0,
"eco_temp": 18.0,
"mode": "AUTO",
"hysteresis": 0.5,
"min_on_time": 30,
"min_off_time": 10,
"temp_sample_count": 3,
"control_interval": 180
}
}Open in your browser:
http://<raspberry-pi-ip>:8001/monitor
Features:
- Real-time control loop log streaming via WebSocket
- Shows last 30 log entries on connect
- Auto-reconnect on network issues
- Color-coded log types (mode changes, decisions, errors)
- Works on desktop, tablet, and mobile
- No SSH required!
Check sensor health:
./check_sensors.shShows:
- Current temperature and humidity readings
- Battery levels
- Signal strength (RSSI)
- Last update time
- Connection status
Monitor thermostat control:
# Live monitoring (terminal)
./watch_thermostat.sh
# Historical review
./show_thermostat_history.shView logs:
docker logs iot-sensor-poller --tail 20
docker logs iot-api --tail 20
docker logs -f iot-api # Follow liveGET /- API information and endpoint listGET /health- Health check (includes thermostat status)GET /monitor- Web-based live monitor (HTML page with WebSocket streaming)WS /ws/thermostat/logs- WebSocket endpoint for live log streamingGET /api/v1/sensors- List all sensorsGET /api/v1/temperature- Temperature readingsGET /api/v1/humidity- Humidity readingsGET /api/v1/battery- Battery levelsGET /metrics- Prometheus metrics (includes thermostat metrics)
Sensor Prometheus Metrics:
sensor_temperature_celsius{device_id, gateway_id, sensor_id, sensor_name}- Current temperaturesensor_humidity_percent{device_id, gateway_id, sensor_id, sensor_name}- Current humiditysensor_battery_percent{device_id, gateway_id, sensor_id, sensor_name}- Battery levelsensor_last_seen_timestamp{device_id, gateway_id, sensor_id, sensor_name}- Last data timestamp
Thermostat Prometheus Metrics:
thermostat_switch_state- Switch state (1=ON/heating, 0=OFF)thermostat_target_temperature_celsius- Target temperature setpointthermostat_current_temperature_celsius- Current averaged indoor temperature
GET /api/v1/thermostat/config- Get thermostat configurationPOST /api/v1/thermostat/config- Update thermostat settingsGET /api/v1/thermostat/status- Get current status and control decisionPOST /api/v1/thermostat/switch- Manual switch control
Full OpenAPI documentation at http://localhost:8001/docs
Sensors not updating:
- Check Bluetooth range (10-30m typical)
- Run
./check_sensors.shto verify connectivity - Check sensor batteries
- Press sensor button to wake up
No data in InfluxDB:
- Check poller logs:
docker logs iot-sensor-poller - Verify Shelly IP is correct in docker-compose.yml
- Ensure sensors are paired with Shelly Pro 2
Storage (128GB SD Card on Raspberry Pi 5):
- InfluxDB data: ~450 MB max (180-day retention)
- Docker logs: ~60 MB max (30MB per container with rotation)
- Total steady state: ~510 MB (0.4% of capacity)
- Years to fill: 50+ years at current rate
SD Card Longevity:
- Daily writes: ~2.5 MB/day (sensor data + logs)
- All containers have log rotation (10MB × 3 files)
- State writes only on changes (optimized for SD card wear)
- Expected lifespan: Decades on quality SD cards
- No maintenance required for typical home deployment
- ARCHITECTURE.md - Architecture and design decisions
- README_MONITORING.md - Thermostat monitoring guide
- CHANGELOG.md - Version history
- check_sensors.sh - Sensor health check tool
- watch_thermostat.sh - Live control loop monitoring
- show_thermostat_history.sh - Historical review
✅ Production Ready (v3.0)
- HTTP polling implementation
- Real BLU H&T sensor integration
- InfluxDB time-series storage
- FastAPI with Prometheus metrics
- Sensor health monitoring
- Complete Docker deployment
- Intelligent thermostat control
- Temperature averaging for slow systems
- Automatic health monitoring & restart
- Persistent configuration
- Real-time control loop logging
- Grafana dashboards (user-configured)
v2.0 adopts a simple HTTP polling architecture instead of MQTT:
- ✅ Simpler: No message broker configuration
- ✅ More reliable: Direct HTTP requests, no message queuing
- ✅ Easier debugging: Standard HTTP requests and responses
- ✅ Less infrastructure: Fewer services to manage
While MQTT sounds modern and scalable, for a small-scale IoT deployment with a handful of sensors, simple HTTP polling is the pragmatic choice.
MIT License - see LICENSE for details.