- Python 88.4%
- Shell 8.6%
- Dockerfile 1.9%
- Just 1.1%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .forgejo | ||
| examples | ||
| resources/cosign | ||
| src/tasmota_reconciler | ||
| tests | ||
| .gitignore | ||
| .python-version | ||
| Containerfile | ||
| justfile | ||
| pyproject.toml | ||
| README.md | ||
| renovate.json | ||
| requirements-dev.lock | ||
| requirements.lock | ||
| uv.lock | ||
Tasmota reconciler
tasmota-reconciler turns selected, stable Tasmota settings into Git-owned
desired state. It uses the upstream
decode-config utility for
version-aware configuration transport and restore, while this project adds:
- a multi-device manifest;
- MQTT credentials from mounted secret files;
- subset-aware drift detection;
- explicit
plan,apply, and encrypted.dmpbackup operations; - bounded retries for transient or truncated device observations;
- reboot-aware post-apply verification;
- native Tasmota MQTT command fallback when a restore fails to converge; and
- JSON-line output suitable for Kubernetes Jobs and log monitoring.
Runtime values such as relay state, uptime, signal strength, and accumulated energy are intentionally outside the reconciler unless explicitly present in a device's desired JSON. Secret-like fields are rejected from desired-state files; credentials belong in mounted SOPS-managed secret files.
Configuration
See examples/manifest.json and
examples/devices/winterstern.json.
Relative desiredFile paths are resolved from the manifest directory.
The broker URL must not contain credentials. If authentication is required,
use usernameFile and passwordFile. devicePasswordFile is the password
stored in the Tasmota device and is required by decode-config when its MQTT
broker identity uses a different password.
Individual device entries may override the global deviceMqtt identity with
mqttUsername and mqttPasswordFile. Both fields must be supplied together;
this allows each device to have a separately revocable broker credential.
Optional top-level wifi and deviceMqtt blocks inject their passwords only
into a short-lived restore file. This lets Git own the SSID and device MQTT
identity without putting either password in the manifest, desired JSON, drift
output, command arguments, or logs. Password values are intentionally not
verified because decode-config hides them when observing a device.
Commands
tasmota-reconciler --manifest /config/manifest.json plan
tasmota-reconciler --manifest /config/manifest.json apply
tasmota-reconciler --manifest /config/manifest.json backup \
--output-directory /backups
plan returns:
0when all selected devices are converged;2when drift exists; and1for configuration or communication errors.
apply reads current state, restores only devices with drift, and retries
verification while the device reboots. If the restore errors or persistent
drift remains, the reconciler translates the remaining supported fields into
native Tasmota commands, submits them with Backlog, and verifies the device a
second time. It still fails unless every Git-owned field converges.
The fallback covers the Wi-Fi and MQTT transition fields, energy calibration,
resolution, template/module, naming, topic, and telemetry fields used by the
managed fleet. It rejects values that cannot be represented safely in a
Backlog command instead of sending an ambiguous command.
Backups use Tasmota's encrypted .dmp format. They should be written to a
persistent volume and included in the cluster backup policy.
Development
The repository uses the managed Nix Python environment:
direnv exec . uv sync --frozen
direnv exec . uv run ruff check .
direnv exec . uv run pytest
Image publication
Pull requests build the complete image, execute tests and linting inside the build, and inspect the CLI without publishing. Merges and weekly scheduled runs publish signed images with SPDX SBOM and SLSA provenance to:
registry.ancofazi.de/homelab/tasmota-reconciler:<decode-config-version>-<run>
The Andreas/homelab repository owns deployment and pins the resulting image
by tag and digest.