Professional air quality monitoring system for Raspberry Pi using the BME680 environmental sensor with OLED display, automated calibration, and persistent data logging.
- Real-time Environmental Monitoring - Temperature, humidity, pressure, and air quality
- Intelligent Calibration - Automatic burn-in and baseline establishment with persistence
- Hybrid Air Quality Algorithm - Combines absolute and relative thresholds for accurate readings
- Comfort Interpretations - Human-readable assessments with actionable recommendations
- OLED Display Support - Alternating views with sensor data and comfort emoji
- SQLite Data Storage - Efficient database storage with statistics and auto-cleanup
- Telegram Notifications - Alerts for air quality, temperature, humidity + daily summaries
- Optimized Logging - Reduced log frequency (15 min) while maintaining full data
- Configuration Management - YAML-based configuration without code changes
- Professional Logging - Structured logs with automatic rotation
- Service Management - Systemd integration for auto-start
- Unit Tests - Comprehensive test coverage
- Modular Architecture - Clean, maintainable codebase
BME680/
├── src/ # Source code
│ └── bme680_monitor/ # Main package
│ ├── config.py # Configuration management
│ ├── sensor_manager.py # BME680 interface
│ ├── air_quality.py # Hybrid AQI algorithm
│ ├── comfort_index.py # Comfort interpretations
│ ├── display.py # OLED display with alternating views
│ ├── database.py # SQLite data storage
│ ├── telegram_notifier.py # Telegram notifications
│ └── data_logger.py # CSV logging (legacy)
├── data/ # SQLite database (auto-created)
├── tests/ # Unit tests
├── docs/ # Documentation
│ ├── AIR_QUALITY_ALGORITHM.md
│ ├── COMFORT_INTERPRETATIONS.md
│ └── CHANGELOG.md
├── scripts/ # Utility scripts
│ ├── sensor_control.sh # Service control
│ └── bme680-sensor.service # Systemd service
├── config/ # Configuration files
│ └── config.yaml # Main configuration
├── sensor.py # Main entry point
├── setup.py # Package installation
├── pyproject.toml # Build configuration
├── Makefile # Development tasks
└── requirements.txt # Dependencies
- Raspberry Pi (any model with I2C)
- BME680 sensor module
- Optional: 0.96" OLED display (SSD1306)
# Clone the repository
git clone <your-repo-url>
cd BME680
# Create virtual environment
make setup-venv
source venv/bin/activate
# Install dependencies
make install
# Or install with development tools
make install-devEdit config/config.yaml to match your hardware:
sensor:
i2c_address: 0x77 # Change to 0x76 if needed
oled:
enabled: true # Set to false if no display
i2c_address: 0x3C# Direct execution
make run
# Or using control script
make start # Start as background service
make status # Check status
make logs # View live logs
make stop # Stop serviceComprehensive documentation is available in the docs/ directory:
- Full Documentation - Complete usage guide
- Migration Guide - Upgrading from v1.0
- Changelog - Version history
- Air Quality Algorithm - Hybrid algorithm explanation
- Comfort Interpretations - Assessment guide
By default, the sensor logs to sensor.log every 15 minutes, while measures.csv captures every reading. To adjust the log frequency, edit sensor.py:
# Line 23 in sensor.py
LOG_INTERVAL_MINUTES = 15 # Change to your preferred intervalThe OLED display alternates between two views. To adjust timing, edit src/bme680_monitor/display.py:
# Lines 61-62
self._normal_view_duration = 5.0 # Normal view duration (seconds)
self._comfort_view_duration = 3.0 # Comfort view duration (seconds)-
Create a bot with @BotFather:
- Send
/newbotand follow instructions - Copy the bot token
- Send
-
Get your Chat ID with @userinfobot:
- Start a chat and it will show your ID
-
Configure in
config/config.yaml:
telegram:
enabled: true
bot_token: "YOUR_BOT_TOKEN"
chat_id: "YOUR_CHAT_ID"Choose between SQLite (recommended) or CSV:
data_logging:
storage_mode: "sqlite" # or "csv" for legacy# Run all tests
make test
# Run with coverage
make test-cov
# Lint code
make lint
# Format code
make format
# Type checking
make typecheckmake help # Show all available commands
make install # Install package
make test # Run tests
make clean # Clean build artifacts
make build # Build distributionSensor data is stored in data/sensor_data.db with the following schema:
| Column | Description |
|---|---|
| id | Auto-increment ID |
| timestamp | Reading time (ISO format) |
| temperature_c | Temperature (°C) |
| humidity_rh | Humidity (%) |
| pressure_hpa | Pressure (hPa) |
| gas_resistance_ohms | Gas sensor (Ω) |
| air_quality_index | 0=Cal, 1=Poor, 2=Mod, 3=Good |
| air_quality_label | Human-readable quality |
| comfort_level | 0-4 (Very Uncomfortable to Very Comfortable) |
| comfort_label | Human-readable comfort |
Query examples:
# View recent readings
sqlite3 data/sensor_data.db "SELECT * FROM measurements ORDER BY timestamp DESC LIMIT 10"
# Get 24h statistics
sqlite3 data/sensor_data.db "SELECT AVG(temperature_c), MIN(humidity_rh), MAX(humidity_rh) FROM measurements WHERE timestamp > datetime('now', '-24 hours')"If using storage_mode: "csv", data is logged to measures.csv:
| Column | Description |
|---|---|
| timestamp | Reading time |
| temperature_c | Temperature (°C) |
| humidity_rh | Humidity (%) |
| pressure_hpa | Pressure (hPa) |
| gas_resistance_ohms | Gas sensor (Ω) |
| air_quality_index | 0=Cal, 1=Poor, 2=Mod, 3=Good |
| air_quality_label | Human-readable quality |
The system uses a hybrid algorithm combining:
-
Relative Assessment (baseline comparison):
ratio = current_gas_resistance / baseline Good: ratio > 1.35 Moderate: 0.70 ≤ ratio ≤ 1.35 Poor: ratio < 0.70 -
Absolute Assessment (scientific thresholds):
Excellent: > 150 kΩ Good: > 100 kΩ Moderate: > 50 kΩ Poor: < 50 kΩ
The final quality is the minimum of both assessments for safety. See AIR_QUALITY_ALGORITHM.md for details.
BME680 → Raspberry Pi
VCC → 3.3V (Pin 1)
GND → GND (Pin 6)
SDA → SDA (Pin 3)
SCL → SCL (Pin 5)
OLED → Raspberry Pi (shared I2C)
VCC → 3.3V
GND → GND
SDA → SDA
SCL → SCL
sudo raspi-config
# Navigate to: Interface Options → I2C → Enable
# Or use make command
make enable-i2c# Check I2C devices
make check-hardware
# Should show:
# 0x3C (OLED)
# 0x77 (BME680)Install as a system service for auto-start:
# Install service
make install-service
# Enable and start
sudo systemctl enable bme680-sensor
sudo systemctl start bme680-sensor
# Check status
sudo systemctl status bme680-sensor
# View logs
sudo journalctl -u bme680-sensor -fFor accurate air quality readings:
- Position sensor in clean, outdoor air during calibration
- Wait 5 minutes for burn-in
- Sample baseline for 5 minutes
- Avoid smoke, cooking, or chemical fumes
The baseline is automatically saved and reloaded on restart.
Use the CSV output with:
- Grafana - Time-series dashboards
- Jupyter - Data analysis notebooks
- Excel/LibreOffice - Charts and graphs
- Python/pandas - Custom analysis
Example:
import pandas as pd
df = pd.read_csv('measures.csv')
df['timestamp'] = pd.to_datetime(df['timestamp'])
df.set_index('timestamp').plot()Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Write tests for new features
- Ensure all tests pass:
make test - Format code:
make format - Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
- Pimoroni BME680 Library
- Luma.OLED
- BME680 community for calibration insights
- Issues: GitHub Issues
- Documentation: docs/README.md
- Hardware Issues: Check
make check-hardware
- Web dashboard
- REST API
- InfluxDB integration
- Multi-sensor support
- Mobile app
- Email/SMS alerts
Version: 2.0.0 | Python: 3.7+ | Platform: Linux (Raspberry Pi)