jeelink2mqtt¶
Bridge LaCrosse temperature and humidity sensors to MQTT via a JeeLink USB receiver.
jeelink2mqtt reads frames from LaCrosse TX29DTH-IT wireless sensors through a JeeLink USB stick, maps ephemeral sensor IDs to stable logical names, applies signal conditioning and calibration, and publishes readings to an MQTT broker for consumption by home-automation systems.
Built on the cosalette application framework.
Key Features¶
- Smart Sensor ID Management
- LaCrosse sensors generate a new random ID on every battery swap. jeelink2mqtt's auto-adopt algorithm detects the change and re-maps the ID automatically — no manual intervention needed (ADR-002).
- Per-Sensor Calibration Offsets
- Each sensor can carry individual temperature and humidity offsets, compensating for manufacturing tolerances. Compare against a reference thermometer once, set the offset, forget about it.
- Median Filter Signal Conditioning
- A configurable sliding-window median filter (default window 7) rejects spurious outlier readings before they reach your dashboard.
- MQTT Command Interface
- Manual mapping control (
assign,reset,reset_all,list_unknown) via JSON commands onjeelink2mqtt/mapping/set. Useful when multiple sensors fail simultaneously. - Dry-Run Mode
- Run without hardware — a fake adapter generates synthetic readings so you can validate configuration and MQTT integration before plugging in the receiver.
- Persistent Registry
- Sensor mappings are persisted to
data/jeelink2mqtt.jsonand survive restarts. No lost state after a reboot.
Architecture Overview¶
flowchart TD
A[🔌 JeeLink USB] --> B[Serial Adapter]
B --> C[Decode frame]
C --> D["raw/state (diagnostic)"]
C --> E[Registry — auto-adopt]
E -->|mapped| F[Median filter → Calibrate]
F --> G["{sensor}/state (retained)"]
F --> H["{sensor}/availability"]
E -->|mapping change| I[Mapping reactor]
I --> J["mapping/event + mapping/state"]
I --> K[Persist registry to JsonFileStore]
style A fill:#2d7d9a,color:#fff
style E fill:#1a936f,color:#fff
style G fill:#c44536,color:#fff
style J fill:#c44536,color:#fff
For each decoded LaCrosse frame the receiver executes these steps in order:
- The JeeLink USB receiver captures 868 MHz LaCrosse frames.
- A serial adapter (production:
pylacrosse; dry-run: fake) bridges hardware to Python callbacks. - The frame parser decodes raw strings into typed
SensorReadingobjects. - Every frame is published non-retained to
jeelink2mqtt/raw/stateas a raw diagnostic — before any filtering or mapping. - The registry routes the ephemeral sensor ID to a logical name via auto-adopt or manual assignment.
- For mapped sensors,
filter_and_calibrateapplies per-sensor median filtering (outlier rejection) then calibration offsets. - The calibrated reading is published as retained JSON to
jeelink2mqtt/{sensor}/stateandjeelink2mqtt/{sensor}/availability. - After each frame yields, the mapping reactor drains any queued
MappingEventobjects, publishesjeelink2mqtt/mapping/eventandjeelink2mqtt/mapping/stateto MQTT, and persists the registry snapshot toJsonFileStore.
Quick Start¶
Get your first readings in three steps — see the full Getting Started guide:
# 1. Install
uv add jeelink2mqtt
# 2. Configure (minimal .env)
cat > .env << 'EOF'
JEELINK2MQTT_SERIAL_PORT=/dev/ttyUSB0
JEELINK2MQTT_MQTT__HOST=localhost
JEELINK2MQTT_SENSORS='[{"name": "living_room"}, {"name": "outdoor"}]'
EOF
# 3. Run
jeelink2mqtt
Or try without hardware:
Documentation Map¶
| Page | What you'll find |
|---|---|
| Getting Started | First-success onboarding |
| Setup | Hardware, broker, and detailed configuration |
| User Guide | Mapping flows, commands, calibration |
| Operations | Docker, systemd, monitoring, persistence |
| Troubleshooting | Common issues and fixes |
| Reference | Settings, topics, commands, API |