A Python client for logging environmental sensor data to MQTT brokers. Supports both server deployments (Linux/Unix with systemd) and embedded CircuitPython microcontrollers (ESP32, RP2040, etc.).
- Automatic sensor detection via I2C bus scanning
- Multiple deployment targets: Server (systemd) and CircuitPython microcontrollers
- MQTT-based data transport with configurable QoS
- Flexible configuration: File-based (server) or environment variable-based (CircuitPython)
- Periodic measurements with configurable intervals
- Built-in calculations: Sea-level pressure adjustment, temperature compensation
All sensors use I2C communication and are automatically detected:
| Sensor Type | Measurement | I2C Address (Hex) |
|---|---|---|
| BME680 | Temperature, Humidity, Pressure, Air Quality (VOC) | 0x77 |
| BMP3xx | Temperature, Pressure | Various |
| DPS310 | Temperature, Pressure | Various |
| SHT4x | Temperature, Relative Humidity | 0x44 |
| SGP30 | Air Quality (eCO2, TVOC) | Various |
| SGP40 | Air Quality (VOC raw) | 0x59 |
| SCD4x | CO2 Concentration | 0x62 |
| PM25 | Particulate Matter (PM1.0, PM2.5, PM10) | 0x12 |
| BH1750 | Light Intensity | 0x23 |
| VEML7700 | Ambient Light | 0x10 |
| TSL2591 | Light (Visible + IR) | 0x29 |
| MMC56x3 | Magnetic Field (3-axis) | 0x30 |
It is recommended to use a virtual environment:
# Create virtual environment
virtualenv /opt/klimalogger
# Activate virtual environment
. /opt/klimalogger/bin/activate
# Install klimalogger
pip install klimaloggerCreate a configuration file at /etc/klimalogger.conf:
[queue]
host=mqtt.example.com
port=1883
queue_prefix=sensors
queue_qos=1
# Optional authentication
username=mqtt_user
password=mqtt_password
[client]
# Optional: Explicitly specify sensor I2C addresses (hex, comma-separated)
# If not specified, sensors are auto-detected
# sensors=0x44,0x62,0x77
# Optional: Override default device mapping
# device_map=0x44=SHT4x,0x62=SCD4x
# Optional: Elevation in meters for pressure calculations
elevation=100Alternate config locations (checked in order):
./klimalogger.conf/etc/klimalogger/klimalogger.conf/etc/klimalogger.conf
Validate sensor detection and readout:
/opt/klimalogger/bin/klimalogger --checkThis outputs JSON-formatted measurement data.
For debugging with verbose output:
/opt/klimalogger/bin/klimalogger --service --debugCreate /etc/systemd/system/klimalogger.service:
[Unit]
Description=Klimalogger Service
After=multi-user.target
[Service]
Type=simple
Restart=always
ExecStart=/opt/klimalogger/bin/klimalogger --service
[Install]
WantedBy=multi-user.targetEnable and start the service:
sudo systemctl daemon-reload
sudo systemctl enable klimalogger
sudo systemctl start klimalogger
# Check status
sudo systemctl status klimalogger
# View logs
sudo journalctl -u klimalogger -fConnect your CircuitPython device via USB. The device should mount as /Volumes/CIRCUITPY (macOS) or similar on Linux/Windows.
Verified boards include:
- Adafruit QT Py ESP32-S2
- Adafruit QT Py ESP32-S3
Any CircuitPython-compatible board with I2C support should be supported with some minor modifications.
To update to the latest CircuitPython firmware:
- Enter bootloader mode (press BOOT + RESET, then release RESET)
- Flash firmware using esptool:
esptool write-flash -e 0 ~/Downloads/adafruit-circuitpython-*.binDownload firmware from circuitpython.org/downloads
Wait for the hardware to reboot. You should have the mount /Volumes/CIRCUITPY visible.
Install required CircuitPython libraries using circup:
# Install circup if needed
pip install circup
# Install dependencies
circup install -U -r requirements_cpy.txtCreate a settings.toml file in the root of your CircuitPython device:
# WiFi Configuration
WIFI_SSID = "your-wifi-ssid"
WIFI_PASSWORD = "your-wifi-password"
# MQTT Configuration
MQTT_HOST = "mqtt.example.com"
MQTT_PORT = "1883"
MQTT_PREFIX = "sensors"
MQTT_USERNAME = "mqtt_user" # Optional
MQTT_PASSWORD = "mqtt_password" # Optional
# Optional: Elevation in meters
ELEVATION = "100"
# Optional: Device mapping (address=SensorName)
DEVICE_MAP = "119=BMP3xx"
# Local NTP server
NTP_SERVER = "192.168.2.119"Run the installation script to copy source files to your device:
./install.pyThis copies the klimalogger package and main_cpy.py to your CircuitPython device.
The device will automatically run main_cpy.py on boot. To restart:
- Press CTRL+D in the REPL, or
- Reset the device
Monitor output via the serial console:
# macOS/Linux
screen /dev/tty.usbmodem* 115200
# Or use Mu Editor's serial console- Python 3.10 or later
- Poetry for dependency management
# Clone the repository
git clone https://github.com/wuan/klimalogger.git
cd klimalogger
# Install dependencies with Poetry
poetry install
# Activate virtual environment
poetry shell# Run all tests
pytest
# Run with coverage report
pytest --cov=klimalogger
# Run specific test file
pytest tests/sensor/test_bme680.pyThis project uses pre-commit hooks for code quality:
# Install pre-commit hooks
pip install pre-commit
pre-commit install
# Run all hooks manually
pre-commit run --all-filesConfigured tools:
- black and isort: Code formatting
- ruff: Linting with auto-fixes
- mypy: Static type checking
poetry publish --buildklimalogger/
├── klimalogger/ # Main package
│ ├── sensor/ # Individual sensor drivers
│ ├── calc/ # Calculation utilities (pressure, temperature)
│ ├── cpy/ # CircuitPython-specific code
│ ├── script/ # CLI entry points
│ ├── config.py # Configuration management
│ ├── transport.py # MQTT transport layer
│ ├── measurement.py # Data structures
│ └── sensors.py # Sensor management and auto-detection
├── tests/ # Test suite
├── main_cpy.py # CircuitPython entry point
├── install.py # CircuitPython deployment script
└── pyproject.toml # Poetry configuration
klimalogger --checkOutput:
{
"sensor": "SHT4x",
"measurement": "temperature",
"value": 23.5,
"unit": "°C"
}# With default log level (warnings only)
klimalogger --service
# With verbose output
klimalogger --service --verbose
# With debug output
klimalogger --service --debugklimalogger --versionContributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes with tests
- Run pre-commit hooks
- Submit a pull request
Apache License 2.0 - See LICENSE file for details.