This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Server Room Temperature Monitor - A lightweight environmental monitoring system running on a Raspberry Pi 4 with Sense HAT that provides:
- Real-time temperature and humidity monitoring with hardware compensation for CPU heat
- Web dashboard (auto-refreshes every 60 seconds)
- REST API with Bearer token authentication
- Slack webhook notifications for temperature/humidity alerts
- Periodic status updates
- LED matrix display showing current temperature
Flask Application (temp_monitor.py)
- Main entry point that initializes Flask app with Flask-RESTX for API documentation
- Manages sensor reading loop in a background thread (
update_sensor_data()) - Implements routes for web dashboard (
/) and API endpoints (/api/temp,/api/raw,/api/verify-token) - Bearer token authentication via
@require_tokendecorator on protected endpoints
Webhook Service (webhook_service.py)
WebhookServiceclass: Handles outbound Slack webhook communicationWebhookConfigdataclass: Configuration for webhook endpoint (URL, retry logic, timeout)AlertThresholdsdataclass: Temperature/humidity thresholds that trigger alerts- Features: Alert cooldown (900s / 15-min between same alert type), exponential backoff retry logic, thread-safe operations with locks
- Methods:
check_and_alert()(threshold checking),send_status_update()(periodic reports),send_slack_message()(generic Slack formatting)
API Models (api_models.py)
- Flask-RESTX namespace (
webhooks_ns) defining OpenAPI/Swagger models - Input models with validation constraints (e.g., retry_count 1-10, timeout 5-120 seconds)
- Output models for responses
- Validation functions:
validate_webhook_config()andvalidate_thresholds()(cross-field validation)
Sensor Data Processing
get_compensated_temperature(): Takes 10 readings (5 from humidity + 5 from pressure sensors), filters outliers, applies CPU heat compensation (factor: 0.7) and a -13.5°F correctionget_humidity(): Takes 3 readings, filters outliers, applies +4% correctionget_cpu_temperature(): Reads from/sys/class/thermal/thermal_zone0/temp
Public Routes:
GET /- Web dashboard (HTML)GET /docs- Swagger UIGET /health- Health check endpoint for monitoring/load balancers
Protected Routes (require Bearer token):
GET /api/temp- Current temperature/humidity dataGET /api/raw- Raw sensor readings for debuggingGET /api/verify-token- Token validation checkGET /metrics- System and application metrics (requires psutil for system stats); exposes process internals (RSS, thread count, open FDs), so it requires a token since the service is reachable over a public tunnelGET /api/webhook/config- Get webhook configurationPUT /api/webhook/config- Update webhook config and thresholds (with validation)POST /api/webhook/test- Send test webhookPOST /api/webhook/enable- Enable webhooksPOST /api/webhook/disable- Disable webhooks
Environment variables (from .env):
LOG_FILE- Path to log file (default:temp_monitor.log)BEARER_TOKEN- Required for API access (generated withpython3 -c "import secrets; print(secrets.token_hex(32))")SLACK_WEBHOOK_URL- Slack webhook URL (enables webhook service)WEBHOOK_ENABLED- Enable/disable webhook notifications (default: true)WEBHOOK_RETRY_COUNT- Retry attempts (default: 3)WEBHOOK_RETRY_DELAY- Initial retry delay in seconds (default: 5)WEBHOOK_TIMEOUT- Request timeout (default: 10)ALERT_TEMP_MIN_C,ALERT_TEMP_MAX_C,ALERT_HUMIDITY_MIN,ALERT_HUMIDITY_MAX- ThresholdsSTATUS_UPDATE_ENABLED- Enable periodic status updates (default: false)STATUS_UPDATE_INTERVAL- Status update frequency in seconds (default: 3600)STATUS_UPDATE_ON_STARTUP- Send status update on startup (default: false)
Thread Safety
- Global state (
current_temp,current_humidity) is read-only from thread perspective WebhookServiceusesthreading.Lock()for concurrent access to alert tracking and config- Background thread runs sensor loop with 60-second sampling interval
Sensor Data Quality
- Multiple readings with outlier filtering (removes min/max)
- CPU heat compensation formula to correct for SoC temperature affecting sensor
- Sensor readings are cached and accessed by multiple endpoints
API Security
- Bearer token required for all non-public endpoints
- Token format validation:
Authorization: Bearer <token> - 401 (missing header) vs 403 (invalid token) distinction
- Swagger UI accessible without auth for API documentation
Webhook Reliability
- Alert cooldown prevents spam (900 seconds / 15 minutes between same alert type, via
ALERT_COOLDOWN_SECONDS) - Exponential backoff: delay = initial_delay × 2^(attempt_number)
- Configurable retry count (1-10) and timeout (5-120 seconds)
- Thread-safe alert tracking via locks
# Install dependencies
pip install -r requirements.txt
# Set up environment (copy example)
cp .env.example .env
# Edit .env to add BEARER_TOKEN and other settings
# Run directly (requires Sense HAT hardware or mock)
python temp_monitor.py
# Run with Docker Compose (includes ARM build support)
docker compose build
docker compose up -d# Run the whole suite the way CI does -- both invocations, because each
# catches what the other hides. Script style misses tests a file's custom
# main() forgets to register; discover misses a file whose __main__ block
# is broken.
for f in test_*.py; do
[ "$f" = "test_support.py" ] && continue # shared helper, no test cases
python "$f" || break
done
python -m unittest discover -v -p 'test_*.py'
# Or a single file while iterating
python test_webhook.py# Build image
docker build -t temp-monitor .
# Run container with hardware access
docker run -d \
--name temp-monitor \
--privileged \
-p 8080:8080 \
-v $(pwd)/logs:/app/logs \
-v $(pwd)/.env:/app/.env \
-v /sys:/sys:ro \
--device /dev/i2c-1:/dev/i2c-1 \
temp-monitorCreate /etc/systemd/system/temp_monitor.service:
[Unit]
Description=Temperature Monitor Service
After=network.target
[Service]
User=yourusername
WorkingDirectory=/path/to/temp_monitor
ExecStart=/path/to/venv/bin/python3 temp_monitor.py
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.targetThen enable: sudo systemctl enable temp_monitor.service && sudo systemctl start temp_monitor.service
Tests use unittest.mock to mock the sense_hat module (unavailable on non-RPi systems). Key test patterns:
# Mock sense_hat before importing temp_monitor
sys.modules['sense_hat'] = MagicMock()
from temp_monitor import app, webhook_service
# Use test client with Bearer token
self.client.get('/api/temp', headers={'Authorization': f'Bearer {token}'})Critical areas to test:
- Webhook config creation when
webhook_serviceisNone(AttributeError bug fix) - Threshold validation (cross-field min/max relationships)
- Alert cooldown preventing duplicate alerts
- Exponential backoff retry logic
Sense HAT Detection
- Ensure I2C is enabled:
sudo raspi-config→ Interface Options → I2C - Verify with:
i2cdetect -y 1
Temperature Calibration
- Adjust
TEMP_CPU_FACTOR(default0.7) andTEMP_OFFSET_F(default-13.5) via environment variables — no code change or rebuild needed. See CLAUDE.md's "Temperature Calibration" section for the full two-point calibration procedure. - CPU heat affects accuracy; hardware compensation attempts to correct this
Webhook Failures
- Check Slack webhook URL format:
https://hooks.slack.com/services/... - Verify network connectivity:
curl -X POST <webhook_url> - Monitor logs for retry attempts and final failures
API Authentication
- Generate token:
python3 -c "import secrets; print(secrets.token_hex(32))" - Always include
Authorization: Bearer <token>header - Bearer token is case-sensitive
- Flask 2.3.3 - Web framework
- Flask-RESTX 1.3.0+ - REST API with OpenAPI/Swagger documentation
- sense-hat 2.6.0 - Sense HAT hardware library
- python-dotenv 1.0.0 - Environment variable management
- requests 2.31.0 - HTTP client for webhooks
- waitress 2.1.2+ - Production WSGI server
- psutil 5.9.0+ - System metrics (optional, enhances /metrics endpoint)
temp_monitor.py- Main application (~800 lines)webhook_service.py- Webhook/alert logic (~410 lines)api_models.py- Flask-RESTX models and validation (~170 lines)wsgi.py- Production WSGI entry point (waitress)mock_sense_hat.py- Mock/compatibility layer for Sense HAT (loaded only whenUSE_MOCK_SENSORis set)test_webhook_api.py- Integration tests for API endpointstest_webhook.py- Unit tests for webhook servicetest_webhook_retry.py- Unit tests for webhook retry/backoff logictest_periodic_updates.py- Tests for periodic status updatestest_api_models.py- Unit tests for API model validationtest_auth.py- Tests for Bearer token authenticationtest_config_endpoint.py- Tests for the webhook config endpointtest_dashboard.py- Tests for the web dashboard routetest_env_parsing.py- Tests for environment variable parsing helperstest_health.py- Tests for the/healthendpointtest_ops.py- Tests for operational/metrics endpointstest_sensor_integrity.py- Tests for sensor failure/edge-case handlingtest_sensor_math.py- Tests for sensor reading and compensation mathtest_support.py- Shared test helpers/fixturesDockerfile- ARM-compatible build (Python 3.9)docker-compose.yml- Production-ready compose configurationrequirements.txt- Python dependencies.env.example- Environment templatestatic/- Web assets (favicon, logo)