A lightweight environmental monitoring system for server rooms built on Raspberry Pi 4 with Sense HAT. Features real-time monitoring, REST API, Slack webhook alerts, and production-ready deployment options.
- Features
- Hardware Requirements
- Quick Start
- Configuration
- API Reference
- Webhook Notifications
- Deployment
- Troubleshooting
- Contributing
- Real-time Monitoring: Temperature with CPU heat compensation, humidity tracking
- Web Dashboard: Auto-refreshing interface at port 8080
- REST API: JSON endpoints with Bearer token authentication
- Swagger Documentation: Interactive API docs at
/docs - Slack Webhooks: Threshold-based alerts with configurable cooldowns
- Periodic Status Updates: Scheduled status reports via webhook
- LED Display: Current temperature on Sense HAT matrix
- Production Ready: Waitress WSGI server, health checks, metrics endpoint
- Docker Support: Pre-configured docker-compose for easy deployment
- Raspberry Pi 4 (2GB+ RAM recommended)
- Sense HAT add-on board
- 5V/3A USB-C power supply
- (Optional) Case for the Raspberry Pi
git clone https://github.com/freightcognition/temp_monitor.git
cd temp_monitor
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txtcp .env.example .env
# Generate a bearer token (required)
python3 -c "import secrets; print(secrets.token_hex(32))"
# Add the output to .env as BEARER_TOKEN=<token># Development
python temp_monitor.py
# Production (with Waitress)
./start_production.sh
# Docker
docker compose up -dAccess the dashboard at http://[raspberry-pi-ip]:8080
All configuration is done via environment variables in .env. Copy .env.example to get started.
| Variable | Default | Description |
|---|---|---|
BEARER_TOKEN |
(required) | API authentication token |
LOG_FILE |
temp_monitor.log |
Log file path |
CLOUDFLARED_TOKEN |
(required for CI) | Cloudflare Tunnel token for docker-compose cloudflared service (optional for local dev) |
USE_MOCK_SENSOR |
false |
Load the fabricated-data stub (mock_sense_hat.py) instead of real hardware. Never set in production — see note below. |
TEMP_CPU_FACTOR |
0.7 |
CPU-heat coupling coefficient used in temperature compensation |
TEMP_OFFSET_F |
-13.5 |
Empirical temperature offset (°F) used in temperature compensation |
HUMIDITY_OFFSET |
4.0 |
Empirical humidity offset (percentage points) |
Mock sensor note: USE_MOCK_SENSOR=true loads mock_sense_hat.py instead of the real sense-hat package, for development on non-Raspberry Pi hardware. This file was previously named sense_hat.py, which shadowed the real package on sys.path and made the app silently report a constant fabricated 25.0°C/40.0% in production. It was renamed specifically so it can no longer collide with the real package name — never set USE_MOCK_SENSOR in production.
| Variable | Default | Description |
|---|---|---|
SLACK_WEBHOOK_URL |
(optional) | Slack incoming webhook URL for alerts |
WEBHOOK_ENABLED |
true |
Enable/disable notifications |
WEBHOOK_RETRY_COUNT |
3 |
Retry attempts (1-10) |
WEBHOOK_RETRY_DELAY |
5 |
Initial retry delay in seconds |
WEBHOOK_TIMEOUT |
10 |
Request timeout in seconds |
| Variable | Default | Description |
|---|---|---|
ALERT_TEMP_MIN_C |
15.0 |
Low temperature alert (Celsius) |
ALERT_TEMP_MAX_C |
32.0 |
High temperature alert (Celsius) |
ALERT_HUMIDITY_MIN |
20.0 |
Low humidity alert (%) |
ALERT_HUMIDITY_MAX |
70.0 |
High humidity alert (%) |
ALERT_COOLDOWN_SECONDS |
900 |
Minimum time between repeating the same alert type |
| Variable | Default | Description |
|---|---|---|
STATUS_UPDATE_ENABLED |
false |
Enable periodic status reports |
STATUS_UPDATE_INTERVAL |
3600 |
Interval in seconds (min: 60) |
STATUS_UPDATE_ON_STARTUP |
false |
Send status on startup |
| Endpoint | Method | Description |
|---|---|---|
/ |
GET | Web dashboard |
/docs |
GET | Swagger UI documentation |
/health |
GET | Health check for load balancers |
Include header: Authorization: Bearer YOUR_TOKEN
| Endpoint | Method | Description |
|---|---|---|
/api/temp |
GET | Current temperature and humidity |
/api/raw |
GET | Raw sensor data for debugging |
/api/verify-token |
GET | Validate authentication token |
/metrics |
GET | Application and system metrics (exposes process internals, so it requires a token since the service is reachable over a public tunnel) |
| Endpoint | Method | Description |
|---|---|---|
/api/webhook/config |
GET | Get current webhook configuration |
/api/webhook/config |
PUT | Update webhook config and thresholds |
/api/webhook/test |
POST | Send a test webhook message |
/api/webhook/enable |
POST | Enable webhook notifications |
/api/webhook/disable |
POST | Disable webhook notifications |
# Get temperature data
curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:8080/api/temp
# Response:
{
"temperature_c": 23.5,
"temperature_f": 74.3,
"humidity": 45.2,
"timestamp": "2024-01-15 14:23:45"
}
# Health check (no auth needed)
curl http://localhost:8080/health
# Response:
{
"status": "healthy",
"uptime_seconds": 12345,
"sensor_thread_alive": true,
"timestamp": 1705329825.123
}
# Update webhook thresholds
curl -X PUT http://localhost:8080/api/webhook/config \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"thresholds": {
"temp_min_c": 18.0,
"temp_max_c": 25.0
}
}'When configured with a Slack webhook URL, the system sends alerts when readings exceed thresholds.
- Temperature High: Triggered when temp >
ALERT_TEMP_MAX_C - Temperature Low: Triggered when temp <
ALERT_TEMP_MIN_C - Humidity High: Triggered when humidity >
ALERT_HUMIDITY_MAX - Humidity Low: Triggered when humidity <
ALERT_HUMIDITY_MIN
- Alert Cooldown: 900-second (15-minute) cooldown between same alert type (prevents spam), configurable via
ALERT_COOLDOWN_SECONDS - Exponential Backoff: Retries with increasing delays on failure
- URL Masking: Webhook URLs are masked in API responses and logs for security
- Go to Slack API
- Create a new app or use an existing one
- Enable Incoming Webhooks
- Create a webhook for your channel
- Copy the URL to
SLACK_WEBHOOK_URLin.env
# Create logs directory and configure
mkdir -p logs
cp .env.example .env
# Edit .env with your settings
# Build and run
docker compose up -d
# View logs
docker compose logs -f
# Stop
docker compose downNote: Requires privileged mode for I2C/hardware access.
Cloudflare Tunnel: The bundled Cloudflare Tunnel service starts automatically:
- Add
CLOUDFLARED_TOKENto.env - Start with:
docker compose up -d - In Cloudflare Zero Trust UI, point the tunnel service at
http://temp-monitor:8080
Note: CLOUDFLARED_TOKEN is required for CI/production - the CI workflow's CLOUDFLARED_TOKEN validation step (in .github/workflows/ci.yml) enforces this and will fail deployment if missing. For local development, the token is optional: if not set, the cloudflared service will fail to start but the main temp-monitor service continues working. To run locally without Cloudflare Tunnel, use docker compose up -d temp-monitor.
sudo cp deployment/systemd/temp-monitor.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable temp-monitor.service
sudo systemctl start temp-monitor.serviceIf you are using Docker Compose, use deployment/systemd/temp-monitor-compose.service instead (update the WorkingDirectory and User).
- Memory Limit: 512MB (configurable)
- Server: Waitress WSGI, single worker/thread
- Health Checks: Every 30 seconds via
/health - Auto-restart: On failure with 10-second delay
For detailed production deployment, see docs/PI4_DEPLOYMENT.md.
The Sense HAT sits directly above the CPU, so raw readings run hot. The system compensates using:
comp_c = raw_c - (cpu_c - raw_c) * TEMP_CPU_FACTOR + (TEMP_OFFSET_F * 5/9)
TEMP_CPU_FACTOR (default 0.7) tracks the CPU-heat coupling; TEMP_OFFSET_F (default -13.5) is an empirical single-point offset. Both are set via environment variables — no code change or rebuild needed to recalibrate. See CLAUDE.md for the full calibration procedure.
| Issue | Solution |
|---|---|
| Sense HAT not detected | Enable I2C via sudo raspi-config, check connection |
| Port 8080 blocked | Check firewall: sudo ufw allow 8080 |
| Inaccurate temperature | Adjust TEMP_CPU_FACTOR / TEMP_OFFSET_F in .env (no rebuild needed) |
| Webhook failures | Check URL, network connectivity, view logs |
| API returns 401/403 | Verify Bearer token in request header |
| Service won't start | Check logs: journalctl -u temp-monitor -f |
| Package | Version | Description |
|---|---|---|
| Flask | 2.3.3 | Web framework |
| Flask-RESTX | 1.3.0+ | REST API with Swagger |
| sense-hat | 2.6.0 | Sense HAT library |
| python-dotenv | 1.0.0 | Environment management |
| requests | 2.31.0 | HTTP client for webhooks |
| waitress | 2.1.2+ | Production WSGI server |
| psutil | 5.9.0+ | System metrics (optional) |
Contributions are welcome! Please feel free to submit a Pull Request.
