Drop .env handling, fix default dataset, update README
Build image / build (push) Successful in 37s

- Remove .env.example and its .gitignore entry; compose sets the
  dev credentials directly. Basic auth in the image is unchanged.
- Preselect the last dataset by name instead of by mtime, which is
  meaningless after a git checkout in CI
- README: Esc zoom reset, data update flow, data visibility note,
  runner image requirements, dev login for compose
- Remove duplicate data/history2.csv

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-09-26 11:32:03 +02:00
co-authored by Claude Opus 5.5
parent e70d15f861
commit 93b2f6144d
5 changed files with 18 additions and 84 deletions
-3
View File
@@ -1,3 +0,0 @@
BASIC_AUTH_USER=admin
BASIC_AUTH_PASSWORD=change-me
# HEATPUMP_PORT=8080
-1
View File
@@ -1 +0,0 @@
.env
+15 -6
View File
@@ -3,7 +3,8 @@
A small static web app that visualises when a heat pump compressor is running, A small static web app that visualises when a heat pump compressor is running,
based on Home Assistant history exports (`binary_sensor.*` on/off states). based on Home Assistant history exports (`binary_sensor.*` on/off states).
- Interactive timeline (pan, zoom, mouse-wheel, quick ranges 6 h / 24 h / 3 d / 7 d) - Interactive timeline (pan, zoom, mouse-wheel, quick ranges 6 h / 24 h / 3 d / 7 d;
double-click or Esc resets the zoom)
- Hover an on-phase to see its start, end and duration - Hover an on-phase to see its start, end and duration
- Statistics for the visible range: number of phases, min / max / mean / median - Statistics for the visible range: number of phases, min / max / mean / median
duration, total on-time, duty cycle, mean pause between phases duration, total on-time, duty cycle, mean pause between phases
@@ -20,13 +21,18 @@ Put CSV exports into `data/`. Every `*.csv` in there is baked into the image.
- **One file:** it is loaded directly. - **One file:** it is loaded directly.
- **Several files:** a dropdown in the header lists them alphabetically. The - **Several files:** a dropdown in the header lists them alphabetically. The
most recently modified file (or the viewer's last choice) is preselected. viewer's last choice is preselected, otherwise the **last file by name**.
Name files by date (`2026-09.csv`, `2026-10.csv`, …) so the newest comes last.
A different CSV can also be opened ad hoc with **Load CSV…**. It is parsed in A different CSV can also be opened ad hoc with **Load CSV…**. It is parsed in
the browser and not uploaded. the browser and not uploaded.
The file list comes from nginx's JSON directory listing of `/data/`, so nothing The file list comes from nginx's JSON directory listing of `/data/`, so nothing
has to be registered anywhere. Add or remove files and rebuild the image. has to be registered anywhere. To add or remove files, commit and push; CI
builds a new image. Locally, use `docker compose up -d --build`.
> The data is part of the image. Anyone who can pull the image (or read this
> repository) can read the CSVs; basic auth only protects the running web app.
### CSV format ### CSV format
@@ -76,11 +82,12 @@ the app without a password.
### Local run with Compose ### Local run with Compose
```sh ```sh
cp .env.example .env # set BASIC_AUTH_USER / BASIC_AUTH_PASSWORD
docker compose up -d --build docker compose up -d --build
``` ```
Open <http://localhost:8080> (port configurable with `HEATPUMP_PORT`). Open <http://localhost:8080> and log in as `dev` / `dev`. These development
credentials are set in `docker-compose.yml`. The host port can be changed with
`HEATPUMP_PORT=9000 docker compose up -d`.
## CI: build and push ## CI: build and push
@@ -102,7 +109,9 @@ Setup:
- `REGISTRY_TOKEN`: that robot account's secret - `REGISTRY_TOKEN`: that robot account's secret
2. A runner with Docker access must be registered for the repo, user or 2. A runner with Docker access must be registered for the repo, user or
instance (`act_runner` with the Docker socket mounted), and it must provide instance (`act_runner` with the Docker socket mounted), and it must provide
the `ubuntu-latest` label. the `ubuntu-latest` label. The job image needs Node 20 and the Docker CLI,
e.g. `docker.gitea.com/runner-images:ubuntu-latest`. The old default
`node:16-bullseye` fails on `actions/checkout@v4`.
## Project layout ## Project layout
-71
View File
@@ -1,71 +0,0 @@
entity_id,state,last_changed
binary_sensor.heatpump_compressor,on,2026-09-17T03:00:19.068Z
binary_sensor.heatpump_compressor,off,2026-09-17T03:08:01.062Z
binary_sensor.heatpump_compressor,on,2026-09-17T11:26:17.041Z
binary_sensor.heatpump_compressor,off,2026-09-17T11:41:03.220Z
binary_sensor.heatpump_compressor,on,2026-09-18T03:00:22.102Z
binary_sensor.heatpump_compressor,off,2026-09-18T03:19:35.943Z
binary_sensor.heatpump_compressor,on,2026-09-18T10:19:43.304Z
binary_sensor.heatpump_compressor,off,2026-09-18T10:36:39.042Z
binary_sensor.heatpump_compressor,on,2026-09-19T01:20:46.148Z
binary_sensor.heatpump_compressor,off,2026-09-19T01:22:54.097Z
binary_sensor.heatpump_compressor,on,2026-09-19T02:22:51.267Z
binary_sensor.heatpump_compressor,off,2026-09-19T02:28:06.281Z
binary_sensor.heatpump_compressor,on,2026-09-19T03:28:40.219Z
binary_sensor.heatpump_compressor,off,2026-09-19T03:35:46.221Z
binary_sensor.heatpump_compressor,on,2026-09-19T04:41:58.300Z
binary_sensor.heatpump_compressor,off,2026-09-19T04:49:50.417Z
binary_sensor.heatpump_compressor,on,2026-09-19T05:57:54.487Z
binary_sensor.heatpump_compressor,off,2026-09-19T06:43:11.390Z
binary_sensor.heatpump_compressor,on,2026-09-19T09:12:49.606Z
binary_sensor.heatpump_compressor,off,2026-09-19T09:29:53.590Z
binary_sensor.heatpump_compressor,on,2026-09-20T03:39:39.610Z
binary_sensor.heatpump_compressor,off,2026-09-20T03:42:03.650Z
binary_sensor.heatpump_compressor,on,2026-09-20T04:41:55.897Z
binary_sensor.heatpump_compressor,off,2026-09-20T04:47:38.833Z
binary_sensor.heatpump_compressor,on,2026-09-20T05:48:38.700Z
binary_sensor.heatpump_compressor,off,2026-09-20T05:55:45.486Z
binary_sensor.heatpump_compressor,on,2026-09-20T06:00:23.429Z
binary_sensor.heatpump_compressor,off,2026-09-20T06:36:28.105Z
binary_sensor.heatpump_compressor,on,2026-09-20T09:50:15.244Z
binary_sensor.heatpump_compressor,off,2026-09-20T10:01:52.926Z
binary_sensor.heatpump_compressor,on,2026-09-21T03:00:04.587Z
binary_sensor.heatpump_compressor,off,2026-09-21T03:05:11.361Z
binary_sensor.heatpump_compressor,unknown,2026-09-21T08:18:28.438Z
binary_sensor.heatpump_compressor,off,2026-09-21T08:18:30.643Z
binary_sensor.heatpump_compressor,on,2026-09-22T03:00:05.235Z
binary_sensor.heatpump_compressor,off,2026-09-22T03:20:51.957Z
binary_sensor.heatpump_compressor,on,2026-09-22T09:45:24.980Z
binary_sensor.heatpump_compressor,off,2026-09-22T10:05:30.687Z
binary_sensor.heatpump_compressor,on,2026-09-23T03:00:08.414Z
binary_sensor.heatpump_compressor,off,2026-09-23T03:12:46.457Z
binary_sensor.heatpump_compressor,on,2026-09-23T09:45:29.000Z
binary_sensor.heatpump_compressor,off,2026-09-23T10:04:03.857Z
binary_sensor.heatpump_compressor,on,2026-09-24T03:00:09.997Z
binary_sensor.heatpump_compressor,off,2026-09-24T03:11:26.925Z
binary_sensor.heatpump_compressor,on,2026-09-24T12:34:34.499Z
binary_sensor.heatpump_compressor,off,2026-09-24T13:05:30.499Z
binary_sensor.heatpump_compressor,on,2026-09-25T03:00:07.285Z
binary_sensor.heatpump_compressor,off,2026-09-25T03:39:07.324Z
binary_sensor.heatpump_compressor,unknown,2026-09-25T08:35:58.362Z
binary_sensor.heatpump_compressor,off,2026-09-25T08:36:05.755Z
binary_sensor.heatpump_compressor,unknown,2026-09-25T08:36:57.698Z
binary_sensor.heatpump_compressor,off,2026-09-25T08:36:58.846Z
binary_sensor.heatpump_compressor,unknown,2026-09-25T08:41:12.345Z
binary_sensor.heatpump_compressor,off,2026-09-25T08:41:15.133Z
binary_sensor.heatpump_compressor,on,2026-09-25T09:28:41.719Z
binary_sensor.heatpump_compressor,off,2026-09-25T09:54:51.506Z
binary_sensor.heatpump_compressor,on,2026-09-26T00:42:45.260Z
binary_sensor.heatpump_compressor,off,2026-09-26T00:44:28.166Z
binary_sensor.heatpump_compressor,on,2026-09-26T01:18:30.843Z
binary_sensor.heatpump_compressor,off,2026-09-26T01:23:43.918Z
binary_sensor.heatpump_compressor,on,2026-09-26T02:10:50.330Z
binary_sensor.heatpump_compressor,off,2026-09-26T02:18:56.282Z
binary_sensor.heatpump_compressor,on,2026-09-26T03:08:29.828Z
binary_sensor.heatpump_compressor,off,2026-09-26T03:17:03.786Z
binary_sensor.heatpump_compressor,on,2026-09-26T04:07:50.486Z
binary_sensor.heatpump_compressor,off,2026-09-26T04:17:22.353Z
binary_sensor.heatpump_compressor,on,2026-09-26T05:06:08.060Z
binary_sensor.heatpump_compressor,off,2026-09-26T05:16:05.238Z
binary_sensor.heatpump_compressor,on,2026-09-26T06:00:08.484Z
binary_sensor.heatpump_compressor,off,2026-09-26T06:37:50.037Z
1 entity_id state last_changed
2 binary_sensor.heatpump_compressor on 2026-09-17T03:00:19.068Z
3 binary_sensor.heatpump_compressor off 2026-09-17T03:08:01.062Z
4 binary_sensor.heatpump_compressor on 2026-09-17T11:26:17.041Z
5 binary_sensor.heatpump_compressor off 2026-09-17T11:41:03.220Z
6 binary_sensor.heatpump_compressor on 2026-09-18T03:00:22.102Z
7 binary_sensor.heatpump_compressor off 2026-09-18T03:19:35.943Z
8 binary_sensor.heatpump_compressor on 2026-09-18T10:19:43.304Z
9 binary_sensor.heatpump_compressor off 2026-09-18T10:36:39.042Z
10 binary_sensor.heatpump_compressor on 2026-09-19T01:20:46.148Z
11 binary_sensor.heatpump_compressor off 2026-09-19T01:22:54.097Z
12 binary_sensor.heatpump_compressor on 2026-09-19T02:22:51.267Z
13 binary_sensor.heatpump_compressor off 2026-09-19T02:28:06.281Z
14 binary_sensor.heatpump_compressor on 2026-09-19T03:28:40.219Z
15 binary_sensor.heatpump_compressor off 2026-09-19T03:35:46.221Z
16 binary_sensor.heatpump_compressor on 2026-09-19T04:41:58.300Z
17 binary_sensor.heatpump_compressor off 2026-09-19T04:49:50.417Z
18 binary_sensor.heatpump_compressor on 2026-09-19T05:57:54.487Z
19 binary_sensor.heatpump_compressor off 2026-09-19T06:43:11.390Z
20 binary_sensor.heatpump_compressor on 2026-09-19T09:12:49.606Z
21 binary_sensor.heatpump_compressor off 2026-09-19T09:29:53.590Z
22 binary_sensor.heatpump_compressor on 2026-09-20T03:39:39.610Z
23 binary_sensor.heatpump_compressor off 2026-09-20T03:42:03.650Z
24 binary_sensor.heatpump_compressor on 2026-09-20T04:41:55.897Z
25 binary_sensor.heatpump_compressor off 2026-09-20T04:47:38.833Z
26 binary_sensor.heatpump_compressor on 2026-09-20T05:48:38.700Z
27 binary_sensor.heatpump_compressor off 2026-09-20T05:55:45.486Z
28 binary_sensor.heatpump_compressor on 2026-09-20T06:00:23.429Z
29 binary_sensor.heatpump_compressor off 2026-09-20T06:36:28.105Z
30 binary_sensor.heatpump_compressor on 2026-09-20T09:50:15.244Z
31 binary_sensor.heatpump_compressor off 2026-09-20T10:01:52.926Z
32 binary_sensor.heatpump_compressor on 2026-09-21T03:00:04.587Z
33 binary_sensor.heatpump_compressor off 2026-09-21T03:05:11.361Z
34 binary_sensor.heatpump_compressor unknown 2026-09-21T08:18:28.438Z
35 binary_sensor.heatpump_compressor off 2026-09-21T08:18:30.643Z
36 binary_sensor.heatpump_compressor on 2026-09-22T03:00:05.235Z
37 binary_sensor.heatpump_compressor off 2026-09-22T03:20:51.957Z
38 binary_sensor.heatpump_compressor on 2026-09-22T09:45:24.980Z
39 binary_sensor.heatpump_compressor off 2026-09-22T10:05:30.687Z
40 binary_sensor.heatpump_compressor on 2026-09-23T03:00:08.414Z
41 binary_sensor.heatpump_compressor off 2026-09-23T03:12:46.457Z
42 binary_sensor.heatpump_compressor on 2026-09-23T09:45:29.000Z
43 binary_sensor.heatpump_compressor off 2026-09-23T10:04:03.857Z
44 binary_sensor.heatpump_compressor on 2026-09-24T03:00:09.997Z
45 binary_sensor.heatpump_compressor off 2026-09-24T03:11:26.925Z
46 binary_sensor.heatpump_compressor on 2026-09-24T12:34:34.499Z
47 binary_sensor.heatpump_compressor off 2026-09-24T13:05:30.499Z
48 binary_sensor.heatpump_compressor on 2026-09-25T03:00:07.285Z
49 binary_sensor.heatpump_compressor off 2026-09-25T03:39:07.324Z
50 binary_sensor.heatpump_compressor unknown 2026-09-25T08:35:58.362Z
51 binary_sensor.heatpump_compressor off 2026-09-25T08:36:05.755Z
52 binary_sensor.heatpump_compressor unknown 2026-09-25T08:36:57.698Z
53 binary_sensor.heatpump_compressor off 2026-09-25T08:36:58.846Z
54 binary_sensor.heatpump_compressor unknown 2026-09-25T08:41:12.345Z
55 binary_sensor.heatpump_compressor off 2026-09-25T08:41:15.133Z
56 binary_sensor.heatpump_compressor on 2026-09-25T09:28:41.719Z
57 binary_sensor.heatpump_compressor off 2026-09-25T09:54:51.506Z
58 binary_sensor.heatpump_compressor on 2026-09-26T00:42:45.260Z
59 binary_sensor.heatpump_compressor off 2026-09-26T00:44:28.166Z
60 binary_sensor.heatpump_compressor on 2026-09-26T01:18:30.843Z
61 binary_sensor.heatpump_compressor off 2026-09-26T01:23:43.918Z
62 binary_sensor.heatpump_compressor on 2026-09-26T02:10:50.330Z
63 binary_sensor.heatpump_compressor off 2026-09-26T02:18:56.282Z
64 binary_sensor.heatpump_compressor on 2026-09-26T03:08:29.828Z
65 binary_sensor.heatpump_compressor off 2026-09-26T03:17:03.786Z
66 binary_sensor.heatpump_compressor on 2026-09-26T04:07:50.486Z
67 binary_sensor.heatpump_compressor off 2026-09-26T04:17:22.353Z
68 binary_sensor.heatpump_compressor on 2026-09-26T05:06:08.060Z
69 binary_sensor.heatpump_compressor off 2026-09-26T05:16:05.238Z
70 binary_sensor.heatpump_compressor on 2026-09-26T06:00:08.484Z
71 binary_sensor.heatpump_compressor off 2026-09-26T06:37:50.037Z
+3 -3
View File
@@ -348,11 +348,11 @@ async function init() {
} }
state.datasets = files.map(f => f.name); state.datasets = files.map(f => f.name);
// last selection if still present, otherwise the most recently modified file // last selection if still present, otherwise the last file by name
// (mtimes are useless here: git checkouts in CI give all files the same time)
let saved = null; let saved = null;
try { saved = localStorage.getItem(DATASET_KEY); } catch { /* storage unavailable */ } try { saved = localStorage.getItem(DATASET_KEY); } catch { /* storage unavailable */ }
const newest = files.reduce((a, b) => Date.parse(b.mtime) > Date.parse(a.mtime) ? b : a); loadDataset(state.datasets.includes(saved) ? saved : state.datasets[state.datasets.length - 1]);
loadDataset(state.datasets.includes(saved) ? saved : newest.name);
} }
init(); init();