aboutsummaryrefslogtreecommitdiffstats
path: root/README.md
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-08-31 09:49:50 +0200
committerDanilo M. <danix@danix.xyz>2026-08-31 09:49:50 +0200
commit135115b27ad415865458f20965b0e14253eba0ec (patch)
tree1503f933c342f134d6b4db8808dcf0ebcbc09a84 /README.md
downloadtasmota-dash-master.tar.gz
tasmota-dash-master.zip
feat: aggregate five Tasmota plugs with cost and daily historyHEADmaster
Proxy Tasmota energy JSON into Homepage's customapi widget, which can render JSON but cannot do arithmetic. Applies the tariff, sums across plugs, and records the per-day history the plugs do not keep. Plugs are fetched in parallel; sequential polling would stack five timeouts into a 25s hang. An offline plug is reported rather than counted as zero, so a dead sensor cannot read as "consumed nothing". Tasmota exposes only Today/Yesterday/Total, so each poll writes yesterday's finished kWh into SQLite keyed (day, plug), making repeat polls and restarts idempotent. Display strings are preformatted server-side: Homepage's locale formatting renders 1593 W as an ambiguous "1,593", and its widget has no columns, so pairing kWh with its cost in one value is what keeps the cards compact.
Diffstat (limited to 'README.md')
-rw-r--r--README.md85
1 files changed, 85 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..85491d6
--- /dev/null
+++ b/README.md
@@ -0,0 +1,85 @@
+# tasmota-dash
+
+Aggregates five [Tasmota](https://tasmota.github.io/docs/) smart plugs into a
+[Homepage](https://gethomepage.dev) dashboard: live power, per-day and
+lifetime energy, and what it costs in euro.
+
+Homepage's `customapi` widget can render JSON but cannot do arithmetic, so
+this proxy sits between the plugs and the dashboard, applies the tariff, sums
+across plugs and records a daily history that the plugs themselves do not keep.
+
+Stdlib Python, no dependencies, one file.
+
+## Features
+
+- Per-plug and aggregate readings on one endpoint each
+- Cost in euro at two tariffs: marginal (consumption quota) and all-in (total bill / total kWh)
+- Daily kWh history in SQLite, with rolling 7 and 30 day figures
+- A bar-chart page for the last 30 days
+- An offline plug is reported, not silently counted as zero
+
+## Endpoints
+
+| Path | Returns |
+|---|---|
+| `/<name>` | One plug: power, today/yesterday/lifetime kWh, cost |
+| `/total` | Sum across plugs, plus rolling 7/30 day figures |
+| `/history` | Per-day kWh, last 30 days, JSON |
+| `/graph` | HTML bar chart of the last 30 days |
+| `/` | Plug list and available paths |
+
+## Install
+
+Runs on the machine hosting Homepage, listening on `127.0.0.1:8099`.
+
+```bash
+install -Dm755 tasmota_proxy.py /opt/tasmota-proxy/tasmota_proxy.py
+install -Dm644 tasmota-proxy.service /etc/systemd/system/tasmota-proxy.service
+# edit the unit: plug addresses and tariff rates
+systemctl daemon-reload && systemctl enable --now tasmota-proxy
+curl -s localhost:8099/total
+```
+
+Then merge `homepage-services.yaml` into Homepage's `services.yaml` and the
+`layout:` block from `homepage-settings.yaml` into its `settings.yaml`, and
+restart Homepage.
+
+## Configuration
+
+Environment variables, set in the unit file:
+
+| Variable | Default | Meaning |
+|---|---|---|
+| `TASMOTA_PLUGS` | five LAN addresses | `name=host,name=host,...` — also defines the URL paths |
+| `PORT` | `8099` | Listen port, bound to localhost |
+| `RATE_MARGINAL` | `0.17598` | €/kWh, consumption quota only |
+| `RATE_ALLIN` | `0.2754` | €/kWh, total bill divided by total kWh |
+| `HISTORY_DB` | `/var/lib/tasmota-proxy/history.db` | Daily history |
+
+## History
+
+Tasmota keeps only today, yesterday and a lifetime total. Each poll records
+yesterday's finished kWh per plug, keyed by day so repeated polls overwrite
+rather than accumulate. History therefore starts from first run, and only
+covers days the proxy was running for. Today is excluded from rolling sums
+because it is unfinished.
+
+## Tests
+
+```bash
+python3 test_proxy.py
+```
+
+Fakes the plugs, so it needs no LAN access. Prints `ok`.
+
+## License
+
+GPLv2. See [LICENSE](LICENSE).
+
+## Development Approach
+
+This project is developed using AI-assisted tools. Code is generated with the help of AI based on human-provided specifications, design decisions, and iterative feedback.
+
+All contributions are reviewed, tested, and curated by the maintainer before being included in the codebase. AI is used as a productivity and exploration tool, while human oversight remains central to all decisions.
+
+The goal is to combine the flexibility of AI-assisted development with standard open-source practices such as transparency, review, and accountability.