diff --git a/REPORT-plugmeter.md b/REPORT-plugmeter.md new file mode 100644 index 00000000..e87df819 --- /dev/null +++ b/REPORT-plugmeter.md @@ -0,0 +1,34 @@ +# REPORT — reading the N100's power plug from DooPlex (2026-10-13) + +## In plain words + +- **Both ways work.** The plug read 6.6–7.0 W at rest; Home Assistant showed 7 W at the same time. +- **Use the direct (tinytuya) way for measurements.** It gives a new value every 2 seconds. +- **Home Assistant is the backup.** Alone, it did not change for 3 minutes. It looked fast only while the direct + reader ran, because the direct reader makes the plug report to the cloud too. +- Home Assistant from our catalog installed with no problems. It stays on the HP demo box. +- **One mistake:** the plug's local key was shown once in the operator chat (a filter missed it). It is not in any + file or commit. Pairing the plug again in Smart Life replaces the key; the operator decides. + +## How to use it + +``` +~/.venvs/plugmeter/bin/python scripts/bench/plugmeter.py --duration 600 > run.csv +~/.venvs/plugmeter/bin/python scripts/bench/plugmeter.py --once +~/.venvs/plugmeter/bin/python scripts/bench/plugmeter.py --source ha --once +``` + +## Details + +Evidence, data-point map, side-by-side table and control: `documentation/audits/plugmeter-2026-10-13/README.md`. +Data points: 19 power W×10, 18 current mA, 20 voltage V×10, 17 `add_ele` kWh×1000 (not a lifetime total). +10 min side by side: tuya mean 8.36 W / median 7.20 / sd 2.67, 215 rows, 56 slow reads (≤ 8 s), 0 failed; +ha mean 8.40 / 7.20 / 2.74, 301 rows, 0 failed. + +Secrets scan: 10 values (device id, local key, uuid, MAC, HA token, Tuya Access ID/Secret, device id from +credentials) against the diff and every new file — 0 hits; positive control (the key planted in a scratch file) — hit. + +Gates: `python3 scripts/repo_gates.py` rc 0 with the three sibling clones beside it. +Register: 125 rows before, 125 after; 0 opened, 0 closed. +Teardown: N100 untouched; Home Assistant on demo-hp stays (on purpose); hub untouched; DooPlex keeps the user venv +and `~/.config/felhom-bench/`. System poster: no fact changed. diff --git a/documentation/audits/plugmeter-2026-10-13/README.md b/documentation/audits/plugmeter-2026-10-13/README.md new file mode 100644 index 00000000..f7028a47 --- /dev/null +++ b/documentation/audits/plugmeter-2026-10-13/README.md @@ -0,0 +1,68 @@ +# Reading the N100's metered plug from DooPlex — 2026-10-13 + +Two readers for the Tuya Wi-Fi plug that powers the N100 (`demo-felhom`): tinytuya on the LAN, and Home Assistant +installed from the Felhom catalog on demo-hp's guest 9201. Tool: `scripts/bench/plugmeter.py` +(`scripts/bench/README.md`). No key, device id or token is in this folder; they live only in DooPlex +`~/.config/felhom-bench/` (700/600). + +## Setup facts + +- tinytuya **1.20.0** in `~/.venvs/plugmeter` (user venv; no sudo, no system package, no service). +- Wizard: region `eu`, run in `~/.config/felhom-bench/` with its output sent to a 600 file. It found **1 device**, + „Smart Wi-Fi Power Meter Socket", category `cz`. +- `tinytuya scan`: LAN `192.168.0.115`, **protocol 3.4**. No fixed router address yet. +- Home Assistant: deployed through the dashboard endpoint (`POST /api/stacks/home-assistant/deploy`, + `{"DOMAIN":"enkisfelhom.hu","SUBDOMAIN":"ha"}`) at 14:33:34Z → **202**, container healthy at 14:35:46Z + (image pull included). Before the first setup the public address answered **401** (the setup gate closed, as + designed). The operator passed the gate with the dashboard sign-in, made the owner, added the Tuya + integration by QR, and made a non-admin, local-access-only user `felhom-bench` with a long-lived token. + +## Data points (read from the device, checked against Home Assistant's Tuya reading) + +| DP | code | unit | scale | CSV column | +|---|---|---|---|---| +| 19 | `cur_power` | W | ×10 | `watts` | +| 18 | `cur_current` | mA | ×1 | `milliamps` | +| 20 | `cur_voltage` | V | ×10 | `volts` | +| 17 | `add_ele` | kWh | ×1000 | `kwh_total` — energy since the plug last reported to the cloud, NOT lifetime | + +Check: at 14:44–14:45Z tinytuya read 6.6–7.0 W, 59–60 mA, 229.9 V; Home Assistant (Tuya cloud — the same +source the Smart Life app shows) read „7 W, 0.06 A, 230 V" on the operator's screen and 6.6 W through the API. +Match within 0.5 W. Home Assistant's entities: `sensor.smart_wi_fi_power_meter_socket_{power,current,voltage,total_energy}`. + +A refresh is required: plain `status()` repeated one cached reading (3 identical rows at 2 s); `updatedps([18,19,20])` +then `status()` gives a new value each time — the plug's previous measurement, so a row lags about one interval. + +## Side by side — 10 minutes, N100 at rest, `--interval 2` (14:45:17–14:55:17Z) + +| | rows | mean W | median W | spread (sd) | min–max W | read gap median / max | gaps > 3 s | failed reads | +|---|---|---|---|---|---|---|---|---| +| tuya (LAN) | 215 | 8.36 | 7.20 | 2.67 | 6.1–19.1 | 2.0 s / 8.0 s | 56 | 0 | +| ha (cloud) | 301 | 8.40 | 7.20 | 2.74 | 6.1–19.1 | 2.0 s / 2.1 s | 0 | 0 | + +`side-by-side-tuya.csv`, `side-by-side-ha.csv`. The two agree almost exactly — **but not independently**: + +**Control (`ha-alone-3min.csv`, 14:55:44–14:58:44Z):** with the tuya reader stopped, Home Assistant's power value +**did not change once in 3 minutes** (6.5 W throughout). When the tuya reader ran again for 20 s, Home Assistant +moved to the last value it pushed (7.9 W) and stayed there. So the plug reports to the cloud only when asked; Home +Assistant's 2-second freshness in the side-by-side was the tuya reader's doing. Earlier, at 14:44:48Z, Home +Assistant still showed 18.7 W from 14:44:21Z while the plug read 6.7 W. + +**Recommendation: `--source tuya` for every measurement; `--source ha` as the backup and for history.** +Each tuya gap > 3 s is a slow read (up to 8 s), not a lost one. + +## Home Assistant from our catalog — product notes + +- Install, gate and first setup worked with no defect found. Deploy-to-healthy ~2 min 12 s. +- A non-admin Home Assistant user **can still switch the plug** (`switch.smart_wi_fi_power_meter_socket_socket_1` + is visible to it). Home Assistant has no read-only role. So the `felhom-bench` token can power off the N100; + plugmeter only reads states. Home Assistant's design, not ours — no register row. +- A household reading a Tuya meter plug only through Home Assistant's cloud integration gets a value that can sit + still for minutes. Tuya's behaviour, not ours — no register row. +- The `felhom-bench` user is local-access-only, so the public (Cloudflare) path is refused for it; plugmeter + connects to the guest's LAN address `192.168.0.155` and checks the certificate by name. + +## Teardown + +Machine: nothing provisioned on the N100. Host: none. Guest 9201: **Home Assistant stays installed on purpose** +(the plug's second reader, `operations/nodes.md`). Hub: nothing. DooPlex: the user venv and `~/.config/felhom-bench/` stay. diff --git a/documentation/audits/plugmeter-2026-10-13/ha-alone-3min.csv b/documentation/audits/plugmeter-2026-10-13/ha-alone-3min.csv new file mode 100644 index 00000000..0dfc40c7 --- /dev/null +++ b/documentation/audits/plugmeter-2026-10-13/ha-alone-3min.csv @@ -0,0 +1,92 @@ +utc_time,watts,milliamps,volts,kwh_total +2026-10-13T14:55:44.072Z,6.5,58,232.6,0.004 +2026-10-13T14:55:46.072Z,6.5,58,232.6,0.004 +2026-10-13T14:55:48.068Z,6.5,58,232.6,0.004 +2026-10-13T14:55:50.081Z,6.5,58,232.6,0.004 +2026-10-13T14:55:52.070Z,6.5,58,232.6,0.004 +2026-10-13T14:55:54.070Z,6.5,58,232.6,0.004 +2026-10-13T14:55:56.077Z,6.5,58,232.6,0.004 +2026-10-13T14:55:58.069Z,6.5,58,232.6,0.004 +2026-10-13T14:56:00.067Z,6.5,58,232.6,0.004 +2026-10-13T14:56:02.076Z,6.5,58,232.6,0.004 +2026-10-13T14:56:04.080Z,6.5,58,232.6,0.004 +2026-10-13T14:56:06.079Z,6.5,58,232.6,0.004 +2026-10-13T14:56:08.077Z,6.5,58,232.6,0.004 +2026-10-13T14:56:10.073Z,6.5,58,232.6,0.004 +2026-10-13T14:56:12.074Z,6.5,58,232.6,0.004 +2026-10-13T14:56:14.071Z,6.5,58,232.6,0.004 +2026-10-13T14:56:16.077Z,6.5,58,232.6,0.004 +2026-10-13T14:56:18.070Z,6.5,58,232.6,0.004 +2026-10-13T14:56:20.076Z,6.5,58,232.6,0.004 +2026-10-13T14:56:22.068Z,6.5,58,232.6,0.004 +2026-10-13T14:56:24.074Z,6.5,58,232.6,0.004 +2026-10-13T14:56:26.074Z,6.5,58,232.6,0.004 +2026-10-13T14:56:28.073Z,6.5,58,232.6,0.004 +2026-10-13T14:56:30.074Z,6.5,58,232.6,0.004 +2026-10-13T14:56:32.083Z,6.5,58,232.6,0.004 +2026-10-13T14:56:34.075Z,6.5,58,232.6,0.004 +2026-10-13T14:56:36.080Z,6.5,58,232.6,0.004 +2026-10-13T14:56:38.084Z,6.5,58,232.6,0.004 +2026-10-13T14:56:40.074Z,6.5,58,232.6,0.004 +2026-10-13T14:56:42.076Z,6.5,58,232.6,0.004 +2026-10-13T14:56:44.076Z,6.5,58,232.6,0.004 +2026-10-13T14:56:46.085Z,6.5,58,232.6,0.004 +2026-10-13T14:56:48.077Z,6.5,58,232.6,0.004 +2026-10-13T14:56:50.080Z,6.5,58,232.6,0.004 +2026-10-13T14:56:52.076Z,6.5,58,232.6,0.004 +2026-10-13T14:56:54.073Z,6.5,58,232.6,0.004 +2026-10-13T14:56:56.078Z,6.5,58,232.6,0.004 +2026-10-13T14:56:58.072Z,6.5,58,232.6,0.004 +2026-10-13T14:57:00.075Z,6.5,58,232.6,0.004 +2026-10-13T14:57:02.082Z,6.5,58,232.6,0.004 +2026-10-13T14:57:04.084Z,6.5,58,232.6,0.004 +2026-10-13T14:57:06.082Z,6.5,58,232.6,0.004 +2026-10-13T14:57:08.079Z,6.5,58,232.6,0.004 +2026-10-13T14:57:10.078Z,6.5,58,232.6,0.004 +2026-10-13T14:57:12.074Z,6.5,58,232.6,0.004 +2026-10-13T14:57:14.076Z,6.5,58,232.6,0.004 +2026-10-13T14:57:16.077Z,6.5,58,232.6,0.004 +2026-10-13T14:57:18.071Z,6.5,58,232.6,0.004 +2026-10-13T14:57:20.085Z,6.5,58,232.6,0.004 +2026-10-13T14:57:22.082Z,6.5,58,232.6,0.004 +2026-10-13T14:57:24.078Z,6.5,58,232.6,0.004 +2026-10-13T14:57:26.078Z,6.5,58,232.6,0.004 +2026-10-13T14:57:28.074Z,6.5,58,232.6,0.004 +2026-10-13T14:57:30.074Z,6.5,58,232.6,0.004 +2026-10-13T14:57:32.081Z,6.5,58,232.6,0.004 +2026-10-13T14:57:34.076Z,6.5,58,232.6,0.004 +2026-10-13T14:57:36.086Z,6.5,58,232.6,0.004 +2026-10-13T14:57:38.085Z,6.5,58,232.6,0.004 +2026-10-13T14:57:40.078Z,6.5,58,232.6,0.004 +2026-10-13T14:57:42.080Z,6.5,58,232.6,0.004 +2026-10-13T14:57:44.079Z,6.5,58,232.6,0.004 +2026-10-13T14:57:46.075Z,6.5,58,232.6,0.004 +2026-10-13T14:57:48.080Z,6.5,58,232.6,0.004 +2026-10-13T14:57:50.088Z,6.5,58,232.6,0.004 +2026-10-13T14:57:52.074Z,6.5,58,232.6,0.004 +2026-10-13T14:57:54.077Z,6.5,58,232.6,0.004 +2026-10-13T14:57:56.079Z,6.5,58,232.6,0.004 +2026-10-13T14:57:58.078Z,6.5,58,232.6,0.004 +2026-10-13T14:58:00.086Z,6.5,58,232.6,0.004 +2026-10-13T14:58:02.082Z,6.5,58,232.6,0.004 +2026-10-13T14:58:04.091Z,6.5,58,232.6,0.004 +2026-10-13T14:58:06.086Z,6.5,58,232.6,0.004 +2026-10-13T14:58:08.077Z,6.5,58,232.6,0.004 +2026-10-13T14:58:10.077Z,6.5,58,232.6,0.004 +2026-10-13T14:58:12.078Z,6.5,58,232.6,0.004 +2026-10-13T14:58:14.077Z,6.5,58,232.6,0.004 +2026-10-13T14:58:16.078Z,6.5,58,232.6,0.004 +2026-10-13T14:58:18.087Z,6.5,58,232.6,0.004 +2026-10-13T14:58:20.084Z,6.5,58,232.6,0.004 +2026-10-13T14:58:22.082Z,6.5,58,232.6,0.004 +2026-10-13T14:58:24.079Z,6.5,58,232.6,0.004 +2026-10-13T14:58:26.079Z,6.5,58,232.6,0.004 +2026-10-13T14:58:28.076Z,6.5,58,232.6,0.004 +2026-10-13T14:58:30.079Z,6.5,58,232.6,0.004 +2026-10-13T14:58:32.089Z,6.5,58,232.6,0.004 +2026-10-13T14:58:34.078Z,6.5,58,232.6,0.004 +2026-10-13T14:58:36.088Z,6.5,58,232.6,0.004 +2026-10-13T14:58:38.084Z,6.5,58,232.6,0.004 +2026-10-13T14:58:40.080Z,6.5,58,232.6,0.004 +2026-10-13T14:58:42.083Z,6.5,58,232.6,0.004 +2026-10-13T14:58:44.079Z,6.5,58,232.6,0.004 diff --git a/documentation/audits/plugmeter-2026-10-13/side-by-side-ha.csv b/documentation/audits/plugmeter-2026-10-13/side-by-side-ha.csv new file mode 100644 index 00000000..f312aaff --- /dev/null +++ b/documentation/audits/plugmeter-2026-10-13/side-by-side-ha.csv @@ -0,0 +1,302 @@ +utc_time,watts,milliamps,volts,kwh_total +2026-10-13T14:45:16.798Z,6.7,59,229.9,0.004 +2026-10-13T14:45:18.799Z,6.3,56,229.9,0.004 +2026-10-13T14:45:20.803Z,6.9,60,230.4,0.004 +2026-10-13T14:45:22.802Z,8.7,84,230.4,0.004 +2026-10-13T14:45:24.819Z,9.9,99,230.4,0.004 +2026-10-13T14:45:26.800Z,13.2,104,230.4,0.004 +2026-10-13T14:45:28.798Z,13.2,104,230.4,0.004 +2026-10-13T14:45:30.820Z,13.2,104,230.4,0.004 +2026-10-13T14:45:32.808Z,6.6,60,230.4,0.004 +2026-10-13T14:45:34.801Z,6.6,60,230.4,0.004 +2026-10-13T14:45:36.805Z,6.6,60,230.4,0.004 +2026-10-13T14:45:38.811Z,6.5,58,230.4,0.004 +2026-10-13T14:45:40.811Z,6.5,58,230.4,0.004 +2026-10-13T14:45:42.801Z,6.5,58,230.4,0.004 +2026-10-13T14:45:44.801Z,6.9,58,229.5,0.004 +2026-10-13T14:45:46.804Z,12.7,153,229.5,0.004 +2026-10-13T14:45:48.806Z,19,125,229.5,0.004 +2026-10-13T14:45:50.811Z,19,125,229.5,0.004 +2026-10-13T14:45:52.802Z,19,125,229.5,0.004 +2026-10-13T14:45:54.802Z,19,125,229.5,0.004 +2026-10-13T14:45:56.804Z,8.7,78,229.9,0.004 +2026-10-13T14:45:58.803Z,7.1,60,229.9,0.004 +2026-10-13T14:46:00.801Z,7.9,69,229.9,0.004 +2026-10-13T14:46:02.803Z,7.9,69,229.9,0.004 +2026-10-13T14:46:04.816Z,7.9,69,229.9,0.004 +2026-10-13T14:46:06.804Z,7.3,62,229.5,0.004 +2026-10-13T14:46:08.827Z,6.5,58,229.5,0.004 +2026-10-13T14:46:10.806Z,6.7,60,229.5,0.004 +2026-10-13T14:46:12.804Z,6.7,60,229.5,0.004 +2026-10-13T14:46:14.803Z,6.7,60,229.5,0.004 +2026-10-13T14:46:16.808Z,6.7,60,229.5,0.004 +2026-10-13T14:46:18.798Z,6.5,57,229.5,0.004 +2026-10-13T14:46:20.815Z,6.6,57,229.5,0.004 +2026-10-13T14:46:22.803Z,8.8,83,229.5,0.004 +2026-10-13T14:46:24.800Z,8.8,83,229.5,0.004 +2026-10-13T14:46:26.806Z,8.8,83,229.5,0.004 +2026-10-13T14:46:28.806Z,6.8,60,229.9,0.004 +2026-10-13T14:46:30.802Z,7.3,69,229.9,0.004 +2026-10-13T14:46:32.813Z,6.6,59,229.9,0.004 +2026-10-13T14:46:34.806Z,6.6,59,229.9,0.004 +2026-10-13T14:46:36.818Z,6.6,59,229.9,0.004 +2026-10-13T14:46:38.822Z,6.6,59,229.9,0.004 +2026-10-13T14:46:40.809Z,6.4,57,229.5,0.004 +2026-10-13T14:46:42.814Z,8.3,70,229.5,0.004 +2026-10-13T14:46:44.817Z,6.1,56,229.5,0.004 +2026-10-13T14:46:46.805Z,6.1,56,229.5,0.004 +2026-10-13T14:46:48.805Z,6.1,56,229.5,0.004 +2026-10-13T14:46:50.807Z,10.2,62,229.5,0.004 +2026-10-13T14:46:52.805Z,7.5,63,229.5,0.004 +2026-10-13T14:46:54.804Z,9.8,92,229.5,0.004 +2026-10-13T14:46:56.807Z,9.8,92,229.5,0.004 +2026-10-13T14:46:58.805Z,9.8,92,229.5,0.004 +2026-10-13T14:47:00.807Z,9.8,92,229.5,0.004 +2026-10-13T14:47:02.815Z,6.8,60,229.9,0.004 +2026-10-13T14:47:04.813Z,6.8,60,229.9,0.004 +2026-10-13T14:47:06.818Z,6.8,60,229.9,0.004 +2026-10-13T14:47:08.807Z,6.8,60,229.9,0.004 +2026-10-13T14:47:10.819Z,6.4,57,230.4,0.004 +2026-10-13T14:47:12.803Z,7.2,63,230.4,0.004 +2026-10-13T14:47:14.807Z,6.7,59,230.4,0.004 +2026-10-13T14:47:16.803Z,6.9,59,230.4,0.004 +2026-10-13T14:47:18.804Z,7.2,83,230.4,0.004 +2026-10-13T14:47:20.815Z,7.2,83,230.4,0.004 +2026-10-13T14:47:22.807Z,7.2,83,230.4,0.004 +2026-10-13T14:47:24.805Z,10.9,86,229.9,0.004 +2026-10-13T14:47:26.811Z,10.4,102,229.9,0.004 +2026-10-13T14:47:28.803Z,6.9,61,229.9,0.004 +2026-10-13T14:47:30.812Z,6.9,61,229.9,0.004 +2026-10-13T14:47:32.814Z,6.9,61,229.9,0.004 +2026-10-13T14:47:34.809Z,6.9,61,229.9,0.004 +2026-10-13T14:47:36.809Z,6.7,59,229.5,0.004 +2026-10-13T14:47:38.813Z,6.8,60,229.5,0.004 +2026-10-13T14:47:40.806Z,6.8,60,229.5,0.004 +2026-10-13T14:47:42.807Z,6.8,60,229.5,0.004 +2026-10-13T14:47:44.807Z,6.4,58,229.9,0.004 +2026-10-13T14:47:46.814Z,8,155,229.9,0.004 +2026-10-13T14:47:48.841Z,19,63,229.9,0.004 +2026-10-13T14:47:50.808Z,19,63,229.9,0.004 +2026-10-13T14:47:52.809Z,19,63,229.9,0.004 +2026-10-13T14:47:54.811Z,19,63,229.9,0.004 +2026-10-13T14:47:56.811Z,9.2,80,229.9,0.004 +2026-10-13T14:47:58.811Z,7.3,64,229.9,0.004 +2026-10-13T14:48:00.812Z,6.8,70,229.9,0.004 +2026-10-13T14:48:02.809Z,6.8,70,229.9,0.004 +2026-10-13T14:48:04.815Z,6.8,70,229.9,0.004 +2026-10-13T14:48:06.818Z,13.7,60,229.5,0.004 +2026-10-13T14:48:08.807Z,6.7,60,229.5,0.004 +2026-10-13T14:48:10.816Z,8.5,100,229.5,0.004 +2026-10-13T14:48:12.810Z,8.5,100,229.5,0.004 +2026-10-13T14:48:14.810Z,8.5,100,229.5,0.004 +2026-10-13T14:48:16.806Z,8.5,100,229.5,0.004 +2026-10-13T14:48:18.808Z,7.7,64,229.5,0.004 +2026-10-13T14:48:20.822Z,7.1,64,229.5,0.004 +2026-10-13T14:48:22.811Z,9.8,80,229.5,0.004 +2026-10-13T14:48:24.812Z,9.8,80,229.5,0.004 +2026-10-13T14:48:26.809Z,9.8,80,229.5,0.004 +2026-10-13T14:48:28.812Z,9.8,80,229.5,0.004 +2026-10-13T14:48:30.810Z,6.7,92,229.5,0.004 +2026-10-13T14:48:32.823Z,12.2,97,229.5,0.004 +2026-10-13T14:48:34.812Z,12.2,97,229.5,0.004 +2026-10-13T14:48:36.821Z,12.2,97,229.5,0.004 +2026-10-13T14:48:38.828Z,12.2,97,229.5,0.004 +2026-10-13T14:48:40.831Z,6.5,61,229.5,0.004 +2026-10-13T14:48:42.810Z,6.5,60,229.5,0.004 +2026-10-13T14:48:44.813Z,6.2,57,229.5,0.004 +2026-10-13T14:48:46.810Z,6.2,57,229.5,0.004 +2026-10-13T14:48:48.815Z,6.2,57,229.5,0.004 +2026-10-13T14:48:50.813Z,6.2,57,229.5,0.004 +2026-10-13T14:48:52.814Z,9.7,93,229.9,0.004 +2026-10-13T14:48:54.815Z,7.5,69,229.9,0.004 +2026-10-13T14:48:56.820Z,13.3,107,229.9,0.004 +2026-10-13T14:48:58.811Z,13.3,107,229.9,0.004 +2026-10-13T14:49:00.817Z,13.3,107,229.9,0.004 +2026-10-13T14:49:02.817Z,7,60,229.5,0.004 +2026-10-13T14:49:04.818Z,7.1,63,229.5,0.004 +2026-10-13T14:49:06.816Z,8.8,85,229.5,0.004 +2026-10-13T14:49:08.815Z,8.8,85,229.5,0.004 +2026-10-13T14:49:10.811Z,8.8,85,229.5,0.004 +2026-10-13T14:49:12.814Z,6.8,60,229.5,0.004 +2026-10-13T14:49:14.812Z,6.8,60,229.5,0.004 +2026-10-13T14:49:16.814Z,6.8,60,229.5,0.004 +2026-10-13T14:49:18.813Z,7.1,59,229.5,0.004 +2026-10-13T14:49:20.814Z,7.1,59,229.5,0.004 +2026-10-13T14:49:22.813Z,7.1,59,229.5,0.004 +2026-10-13T14:49:24.827Z,13,96,229.5,0.004 +2026-10-13T14:49:26.815Z,9.7,64,229.5,0.004 +2026-10-13T14:49:28.815Z,9.7,62,229.5,0.004 +2026-10-13T14:49:30.815Z,9.7,62,229.5,0.004 +2026-10-13T14:49:32.820Z,9.7,62,229.5,0.004 +2026-10-13T14:49:34.815Z,9.7,62,229.5,0.004 +2026-10-13T14:49:36.837Z,10.6,68,229.5,0.004 +2026-10-13T14:49:38.821Z,6.4,58,229.5,0.004 +2026-10-13T14:49:40.815Z,7.2,66,229.5,0.004 +2026-10-13T14:49:42.815Z,7.2,66,229.5,0.004 +2026-10-13T14:49:44.813Z,7.2,66,229.5,0.004 +2026-10-13T14:49:46.815Z,7.2,66,229.5,0.004 +2026-10-13T14:49:48.819Z,18.6,119,229.5,0.004 +2026-10-13T14:49:50.813Z,11.6,65,229.5,0.004 +2026-10-13T14:49:52.816Z,6.6,60,229.5,0.004 +2026-10-13T14:49:54.815Z,6.6,60,229.5,0.004 +2026-10-13T14:49:56.827Z,6.6,60,229.5,0.004 +2026-10-13T14:49:58.810Z,7,61,229.5,0.004 +2026-10-13T14:50:00.822Z,9.9,88,229.5,0.004 +2026-10-13T14:50:02.819Z,8.2,73,229.5,0.004 +2026-10-13T14:50:04.819Z,8.2,73,229.5,0.004 +2026-10-13T14:50:06.821Z,8.2,73,229.5,0.004 +2026-10-13T14:50:08.815Z,8.2,73,229.5,0.004 +2026-10-13T14:50:10.818Z,6.5,57,229.5,0.004 +2026-10-13T14:50:12.822Z,7.8,67,229.5,0.004 +2026-10-13T14:50:14.817Z,7,64,229.5,0.004 +2026-10-13T14:50:16.824Z,7,64,229.5,0.004 +2026-10-13T14:50:18.814Z,7,64,229.5,0.004 +2026-10-13T14:50:20.826Z,6.6,61,230.4,0.004 +2026-10-13T14:50:22.817Z,8.9,61,230.4,0.004 +2026-10-13T14:50:24.816Z,8.9,63,230.4,0.004 +2026-10-13T14:50:26.818Z,8.9,63,230.4,0.004 +2026-10-13T14:50:28.817Z,8.9,63,230.4,0.004 +2026-10-13T14:50:30.817Z,8.9,63,230.4,0.004 +2026-10-13T14:50:32.829Z,7.1,61,229.9,0.004 +2026-10-13T14:50:34.817Z,12,79,229.9,0.004 +2026-10-13T14:50:36.828Z,7.2,64,229.9,0.004 +2026-10-13T14:50:38.821Z,7.2,64,229.9,0.004 +2026-10-13T14:50:40.818Z,7.2,64,229.9,0.004 +2026-10-13T14:50:42.819Z,6.5,59,229.5,0.004 +2026-10-13T14:50:44.814Z,6.5,59,229.5,0.004 +2026-10-13T14:50:46.817Z,6.5,59,229.5,0.004 +2026-10-13T14:50:48.817Z,6.5,59,229.5,0.004 +2026-10-13T14:50:50.822Z,6.7,60,229.5,0.004 +2026-10-13T14:50:52.824Z,6.9,60,229.5,0.004 +2026-10-13T14:50:54.823Z,12.1,86,229.5,0.004 +2026-10-13T14:50:56.816Z,9.1,64,229.5,0.004 +2026-10-13T14:50:58.818Z,9.2,60,229.5,0.004 +2026-10-13T14:51:00.815Z,9.2,60,229.5,0.004 +2026-10-13T14:51:02.832Z,7.2,63,229.5,0.004 +2026-10-13T14:51:04.833Z,7.2,63,229.5,0.004 +2026-10-13T14:51:06.823Z,7.2,63,229.5,0.004 +2026-10-13T14:51:08.821Z,7.2,65,229.5,0.004 +2026-10-13T14:51:10.817Z,7.2,65,229.5,0.004 +2026-10-13T14:51:12.828Z,7.2,65,229.5,0.004 +2026-10-13T14:51:14.820Z,7.2,65,229.5,0.004 +2026-10-13T14:51:16.818Z,8.3,74,229.5,0.004 +2026-10-13T14:51:18.821Z,6.3,58,229.5,0.004 +2026-10-13T14:51:20.829Z,6.7,61,229.5,0.004 +2026-10-13T14:51:22.829Z,10,95,229.5,0.004 +2026-10-13T14:51:24.817Z,13.4,91,229.5,0.004 +2026-10-13T14:51:26.821Z,12,82,229.5,0.004 +2026-10-13T14:51:28.819Z,6.8,57,229.5,0.004 +2026-10-13T14:51:30.820Z,6.3,57,229.5,0.004 +2026-10-13T14:51:32.829Z,6.3,57,229.5,0.004 +2026-10-13T14:51:34.820Z,6.3,57,229.5,0.004 +2026-10-13T14:51:36.830Z,6.7,60,229.5,0.004 +2026-10-13T14:51:38.829Z,6.6,61,229.5,0.004 +2026-10-13T14:51:40.820Z,7.2,63,229.5,0.004 +2026-10-13T14:51:42.819Z,7.2,63,229.5,0.004 +2026-10-13T14:51:44.828Z,7.2,63,229.5,0.004 +2026-10-13T14:51:46.820Z,7.2,63,229.5,0.004 +2026-10-13T14:51:48.826Z,19.1,127,229.1,0.004 +2026-10-13T14:51:50.827Z,6.9,63,229.1,0.004 +2026-10-13T14:51:52.820Z,7.4,60,229.1,0.004 +2026-10-13T14:51:54.821Z,7.4,60,229.1,0.004 +2026-10-13T14:51:56.822Z,7.4,60,229.1,0.004 +2026-10-13T14:51:58.824Z,6.7,60,229.5,0.004 +2026-10-13T14:52:00.823Z,10.1,87,229.5,0.004 +2026-10-13T14:52:02.834Z,6.9,61,229.5,0.004 +2026-10-13T14:52:04.830Z,6.9,61,229.5,0.004 +2026-10-13T14:52:06.823Z,6.9,61,229.5,0.004 +2026-10-13T14:52:08.823Z,6.9,61,229.5,0.004 +2026-10-13T14:52:10.824Z,6.5,60,229.5,0.004 +2026-10-13T14:52:12.822Z,6.8,61,229.5,0.004 +2026-10-13T14:52:14.823Z,7,62,229.5,0.004 +2026-10-13T14:52:16.829Z,7,62,229.5,0.004 +2026-10-13T14:52:18.828Z,7,62,229.5,0.004 +2026-10-13T14:52:20.831Z,6.9,61,229.5,0.004 +2026-10-13T14:52:22.828Z,6.9,58,229.5,0.004 +2026-10-13T14:52:24.827Z,11.3,96,229.5,0.004 +2026-10-13T14:52:26.823Z,11.3,96,229.5,0.004 +2026-10-13T14:52:28.825Z,11.3,96,229.5,0.004 +2026-10-13T14:52:30.822Z,11.3,96,229.5,0.004 +2026-10-13T14:52:32.833Z,6.5,58,229.5,0.004 +2026-10-13T14:52:34.825Z,6.9,59,229.5,0.004 +2026-10-13T14:52:36.834Z,6.5,60,229.5,0.004 +2026-10-13T14:52:38.829Z,6.5,60,229.5,0.004 +2026-10-13T14:52:40.826Z,6.5,60,229.5,0.004 +2026-10-13T14:52:42.824Z,6.5,60,229.5,0.004 +2026-10-13T14:52:44.826Z,6.6,58,229.5,0.004 +2026-10-13T14:52:46.827Z,6.6,59,229.5,0.004 +2026-10-13T14:52:48.886Z,9.4,79,229.5,0.004 +2026-10-13T14:52:50.824Z,9.4,79,229.5,0.004 +2026-10-13T14:52:52.820Z,9.4,79,229.5,0.004 +2026-10-13T14:52:54.824Z,9.4,79,229.5,0.004 +2026-10-13T14:52:56.826Z,9.7,80,229.5,0.004 +2026-10-13T14:52:58.824Z,6.9,62,229.5,0.004 +2026-10-13T14:53:00.825Z,6.9,62,229.5,0.004 +2026-10-13T14:53:02.833Z,6.9,62,229.5,0.004 +2026-10-13T14:53:04.829Z,6.5,58,229.5,0.004 +2026-10-13T14:53:06.823Z,11.8,61,229.5,0.004 +2026-10-13T14:53:08.823Z,7.7,72,229.5,0.004 +2026-10-13T14:53:10.824Z,7.7,72,229.5,0.004 +2026-10-13T14:53:12.826Z,7.7,72,229.5,0.004 +2026-10-13T14:53:14.828Z,7.7,72,229.5,0.004 +2026-10-13T14:53:16.828Z,7,70,232.1,0.004 +2026-10-13T14:53:18.826Z,6.3,63,232.1,0.004 +2026-10-13T14:53:20.823Z,6.6,60,232.1,0.004 +2026-10-13T14:53:22.828Z,6.6,60,232.1,0.004 +2026-10-13T14:53:24.827Z,6.6,60,232.1,0.004 +2026-10-13T14:53:26.827Z,12.2,67,231.7,0.004 +2026-10-13T14:53:28.829Z,8.7,93,231.7,0.004 +2026-10-13T14:53:30.826Z,6.7,58,231.7,0.004 +2026-10-13T14:53:32.839Z,6.7,58,231.7,0.004 +2026-10-13T14:53:34.839Z,6.7,58,231.7,0.004 +2026-10-13T14:53:36.834Z,6.7,58,231.7,0.004 +2026-10-13T14:53:38.836Z,6.7,59,231.7,0.004 +2026-10-13T14:53:40.834Z,7.1,57,231.7,0.004 +2026-10-13T14:53:42.831Z,8.9,75,231.7,0.004 +2026-10-13T14:53:44.829Z,8.9,75,231.7,0.004 +2026-10-13T14:53:46.827Z,8.9,75,231.7,0.004 +2026-10-13T14:53:48.832Z,8.9,75,230.8,0.004 +2026-10-13T14:53:50.833Z,18.9,99,230.8,0.004 +2026-10-13T14:53:52.833Z,8.7,73,230.8,0.004 +2026-10-13T14:53:54.830Z,8.7,73,230.8,0.004 +2026-10-13T14:53:56.827Z,8.7,73,230.8,0.004 +2026-10-13T14:53:58.828Z,8.7,73,230.8,0.004 +2026-10-13T14:54:00.832Z,7,61,232.1,0.004 +2026-10-13T14:54:02.833Z,7.1,63,232.1,0.004 +2026-10-13T14:54:04.839Z,7.3,61,232.1,0.004 +2026-10-13T14:54:06.830Z,7.3,61,232.1,0.004 +2026-10-13T14:54:08.831Z,7.3,61,232.1,0.004 +2026-10-13T14:54:10.832Z,7.3,61,232.1,0.004 +2026-10-13T14:54:12.832Z,10,95,232.6,0.004 +2026-10-13T14:54:14.839Z,7,61,232.6,0.004 +2026-10-13T14:54:16.829Z,6.6,58,232.6,0.004 +2026-10-13T14:54:18.827Z,6.6,58,232.6,0.004 +2026-10-13T14:54:20.838Z,6.6,58,232.6,0.004 +2026-10-13T14:54:22.833Z,12.7,97,232.1,0.004 +2026-10-13T14:54:24.829Z,11.3,100,232.1,0.004 +2026-10-13T14:54:26.831Z,11.3,99,232.1,0.004 +2026-10-13T14:54:28.829Z,11.3,99,232.1,0.004 +2026-10-13T14:54:30.829Z,11.3,99,232.1,0.004 +2026-10-13T14:54:32.834Z,11.3,99,232.1,0.004 +2026-10-13T14:54:34.839Z,7,63,232.6,0.004 +2026-10-13T14:54:36.841Z,6.6,60,232.6,0.004 +2026-10-13T14:54:38.838Z,7.4,64,232.6,0.004 +2026-10-13T14:54:40.847Z,7.4,64,232.6,0.004 +2026-10-13T14:54:42.836Z,7.4,64,232.6,0.004 +2026-10-13T14:54:44.837Z,7,67,232.1,0.004 +2026-10-13T14:54:46.829Z,7,153,232.1,0.004 +2026-10-13T14:54:48.839Z,7,153,232.1,0.004 +2026-10-13T14:54:50.833Z,7,153,232.1,0.004 +2026-10-13T14:54:52.828Z,7,153,232.1,0.004 +2026-10-13T14:54:54.831Z,11.7,106,232.1,0.004 +2026-10-13T14:54:56.830Z,11.3,91,232.1,0.004 +2026-10-13T14:54:58.831Z,7.3,65,232.1,0.004 +2026-10-13T14:55:00.834Z,7.2,61,232.1,0.004 +2026-10-13T14:55:02.834Z,7.2,61,232.1,0.004 +2026-10-13T14:55:04.839Z,7.2,61,232.1,0.004 +2026-10-13T14:55:06.839Z,9.6,58,232.1,0.004 +2026-10-13T14:55:08.835Z,9.6,58,232.1,0.004 +2026-10-13T14:55:10.832Z,6.5,58,232.1,0.004 +2026-10-13T14:55:12.835Z,6.5,58,232.1,0.004 +2026-10-13T14:55:14.835Z,6.5,58,232.1,0.004 +2026-10-13T14:55:16.833Z,6.5,59,232.6,0.004 diff --git a/documentation/audits/plugmeter-2026-10-13/side-by-side-tuya.csv b/documentation/audits/plugmeter-2026-10-13/side-by-side-tuya.csv new file mode 100644 index 00000000..8baac98e --- /dev/null +++ b/documentation/audits/plugmeter-2026-10-13/side-by-side-tuya.csv @@ -0,0 +1,216 @@ +utc_time,watts,milliamps,volts,kwh_total +2026-10-13T14:45:16.782Z,6.3,56,229.9,0.004 +2026-10-13T14:45:18.773Z,6.9,60,230.4,0.004 +2026-10-13T14:45:20.781Z,8.7,84,230.4,0.004 +2026-10-13T14:45:22.775Z,9.9,99,230.4,0.004 +2026-10-13T14:45:24.790Z,11.6,76,230.4,0.004 +2026-10-13T14:45:31.163Z,6.6,60,230.4,0.004 +2026-10-13T14:45:36.290Z,6.6,60,230.4,0.004 +2026-10-13T14:45:36.413Z,6.5,58,230.4,0.004 +2026-10-13T14:45:43.414Z,6.5,58,230.4,0.004 +2026-10-13T14:45:43.539Z,6.9,58,229.5,0.004 +2026-10-13T14:45:45.532Z,12.7,153,229.5,0.004 +2026-10-13T14:45:47.533Z,19,125,229.5,0.004 +2026-10-13T14:45:54.547Z,19,125,229.5,0.004 +2026-10-13T14:45:54.671Z,8.7,78,229.9,0.004 +2026-10-13T14:45:56.660Z,7.1,60,229.9,0.004 +2026-10-13T14:45:58.664Z,7.9,69,229.9,0.004 +2026-10-13T14:46:05.659Z,7.9,69,229.9,0.004 +2026-10-13T14:46:05.783Z,7.3,62,229.5,0.004 +2026-10-13T14:46:07.777Z,6.5,58,229.5,0.004 +2026-10-13T14:46:09.783Z,6.7,60,229.5,0.004 +2026-10-13T14:46:16.777Z,6.7,60,229.5,0.004 +2026-10-13T14:46:16.894Z,6.5,57,229.5,0.004 +2026-10-13T14:46:18.895Z,6.6,57,229.5,0.004 +2026-10-13T14:46:20.901Z,8.8,83,229.5,0.004 +2026-10-13T14:46:27.911Z,8.8,83,229.5,0.004 +2026-10-13T14:46:28.091Z,6.8,60,229.9,0.004 +2026-10-13T14:46:30.023Z,7.3,69,229.9,0.004 +2026-10-13T14:46:32.040Z,6.6,59,229.9,0.004 +2026-10-13T14:46:39.028Z,6.6,59,229.9,0.004 +2026-10-13T14:46:39.145Z,6.4,57,229.5,0.004 +2026-10-13T14:46:41.150Z,8.3,70,229.5,0.004 +2026-10-13T14:46:43.146Z,6.1,56,229.5,0.004 +2026-10-13T14:46:50.157Z,6.1,56,229.5,0.004 +2026-10-13T14:46:50.274Z,10.2,62,229.5,0.004 +2026-10-13T14:46:52.269Z,7.5,63,229.5,0.004 +2026-10-13T14:46:54.272Z,9.8,92,229.5,0.004 +2026-10-13T14:47:01.279Z,9.8,92,229.5,0.004 +2026-10-13T14:47:01.403Z,6.8,60,229.9,0.004 +2026-10-13T14:47:08.402Z,6.8,60,229.9,0.004 +2026-10-13T14:47:08.526Z,6.4,57,230.4,0.004 +2026-10-13T14:47:10.523Z,7.2,63,230.4,0.004 +2026-10-13T14:47:12.524Z,6.7,59,230.4,0.004 +2026-10-13T14:47:14.516Z,6.9,59,230.4,0.004 +2026-10-13T14:47:16.523Z,7.2,83,230.4,0.004 +2026-10-13T14:47:23.515Z,7.2,83,230.4,0.004 +2026-10-13T14:47:23.630Z,10.9,86,229.9,0.004 +2026-10-13T14:47:25.641Z,10.4,102,229.9,0.004 +2026-10-13T14:47:27.629Z,6.9,61,229.9,0.004 +2026-10-13T14:47:34.640Z,6.9,61,229.9,0.004 +2026-10-13T14:47:34.764Z,6.7,59,229.5,0.004 +2026-10-13T14:47:36.753Z,6.8,60,229.5,0.004 +2026-10-13T14:47:43.767Z,6.8,60,229.5,0.004 +2026-10-13T14:47:43.888Z,6.4,58,229.9,0.004 +2026-10-13T14:47:45.895Z,8,155,229.9,0.004 +2026-10-13T14:47:47.883Z,19,63,229.9,0.004 +2026-10-13T14:47:54.882Z,19,63,229.9,0.004 +2026-10-13T14:47:55.003Z,9.2,80,229.9,0.004 +2026-10-13T14:47:57.000Z,7.3,64,229.9,0.004 +2026-10-13T14:47:59.005Z,6.8,70,229.9,0.004 +2026-10-13T14:48:06.009Z,6.8,70,229.9,0.004 +2026-10-13T14:48:06.130Z,13.7,60,229.5,0.004 +2026-10-13T14:48:08.131Z,6.7,60,229.5,0.004 +2026-10-13T14:48:10.139Z,8.5,100,229.5,0.004 +2026-10-13T14:48:17.138Z,8.5,100,229.5,0.004 +2026-10-13T14:48:17.256Z,7.7,64,229.5,0.004 +2026-10-13T14:48:19.262Z,7.1,64,229.5,0.004 +2026-10-13T14:48:21.258Z,9.8,80,229.5,0.004 +2026-10-13T14:48:28.263Z,9.8,80,229.5,0.004 +2026-10-13T14:48:28.397Z,6.7,65,229.5,0.004 +2026-10-13T14:48:30.378Z,9.6,92,229.5,0.004 +2026-10-13T14:48:32.386Z,12.2,97,229.5,0.004 +2026-10-13T14:48:39.379Z,12.2,97,229.5,0.004 +2026-10-13T14:48:39.493Z,6.5,61,229.5,0.004 +2026-10-13T14:48:41.504Z,6.5,60,229.5,0.004 +2026-10-13T14:48:43.497Z,6.2,57,229.5,0.004 +2026-10-13T14:48:50.499Z,6.2,57,229.5,0.004 +2026-10-13T14:48:50.621Z,9.7,93,229.9,0.004 +2026-10-13T14:48:52.634Z,7.5,69,229.9,0.004 +2026-10-13T14:48:54.627Z,13.3,107,229.9,0.004 +2026-10-13T14:49:01.613Z,13.3,107,229.9,0.004 +2026-10-13T14:49:01.739Z,7,60,229.5,0.004 +2026-10-13T14:49:03.728Z,7.1,63,229.5,0.004 +2026-10-13T14:49:05.733Z,8.8,85,229.5,0.004 +2026-10-13T14:49:11.939Z,6.8,60,229.5,0.004 +2026-10-13T14:49:17.062Z,6.8,60,229.5,0.004 +2026-10-13T14:49:17.177Z,7.1,59,229.5,0.004 +2026-10-13T14:49:24.179Z,7.1,59,229.5,0.004 +2026-10-13T14:49:24.297Z,13,96,229.5,0.004 +2026-10-13T14:49:26.306Z,9.7,64,229.5,0.004 +2026-10-13T14:49:28.297Z,9.7,62,229.5,0.004 +2026-10-13T14:49:35.299Z,9.7,62,229.5,0.004 +2026-10-13T14:49:35.432Z,10.6,68,229.5,0.004 +2026-10-13T14:49:37.418Z,6.4,58,229.5,0.004 +2026-10-13T14:49:39.423Z,7.2,66,229.5,0.004 +2026-10-13T14:49:46.422Z,7.2,66,229.5,0.004 +2026-10-13T14:49:46.545Z,18.6,153,229.5,0.004 +2026-10-13T14:49:48.546Z,11.6,65,229.5,0.004 +2026-10-13T14:49:50.535Z,6.6,60,229.5,0.004 +2026-10-13T14:49:57.541Z,6.6,60,229.5,0.004 +2026-10-13T14:49:57.660Z,7,61,229.5,0.004 +2026-10-13T14:49:59.663Z,9.9,88,229.5,0.004 +2026-10-13T14:50:01.661Z,8.2,73,229.5,0.004 +2026-10-13T14:50:08.661Z,8.2,73,229.5,0.004 +2026-10-13T14:50:08.786Z,6.5,57,229.5,0.004 +2026-10-13T14:50:10.780Z,7.8,67,229.5,0.004 +2026-10-13T14:50:12.779Z,7,64,229.5,0.004 +2026-10-13T14:50:19.778Z,7,64,229.5,0.004 +2026-10-13T14:50:19.899Z,6.6,61,230.4,0.004 +2026-10-13T14:50:21.904Z,8.9,61,230.4,0.004 +2026-10-13T14:50:23.901Z,8.9,63,230.4,0.004 +2026-10-13T14:50:30.895Z,8.9,63,230.4,0.004 +2026-10-13T14:50:31.012Z,7.1,61,229.9,0.004 +2026-10-13T14:50:33.043Z,12,79,229.9,0.004 +2026-10-13T14:50:35.009Z,7.2,64,229.9,0.004 +2026-10-13T14:50:42.011Z,7.2,64,229.9,0.004 +2026-10-13T14:50:42.152Z,6.5,59,229.5,0.004 +2026-10-13T14:50:49.146Z,6.5,59,229.5,0.004 +2026-10-13T14:50:49.262Z,6.7,60,229.5,0.004 +2026-10-13T14:50:51.270Z,6.9,60,229.5,0.004 +2026-10-13T14:50:53.266Z,12.1,86,229.5,0.004 +2026-10-13T14:50:55.263Z,9.1,64,229.5,0.004 +2026-10-13T14:50:57.269Z,9.2,60,229.5,0.004 +2026-10-13T14:51:02.337Z,7.2,63,229.5,0.004 +2026-10-13T14:51:07.473Z,7.2,63,229.5,0.004 +2026-10-13T14:51:07.591Z,7.2,65,229.5,0.004 +2026-10-13T14:51:14.626Z,7.2,65,229.5,0.004 +2026-10-13T14:51:14.751Z,8.3,74,229.5,0.004 +2026-10-13T14:51:16.745Z,6.3,58,229.5,0.004 +2026-10-13T14:51:18.802Z,6.7,61,229.5,0.004 +2026-10-13T14:51:20.785Z,10,95,229.5,0.004 +2026-10-13T14:51:22.795Z,13.4,91,229.5,0.004 +2026-10-13T14:51:24.751Z,12,82,229.5,0.004 +2026-10-13T14:51:26.758Z,6.8,57,229.5,0.004 +2026-10-13T14:51:28.740Z,6.3,57,229.5,0.004 +2026-10-13T14:51:35.743Z,6.3,57,229.5,0.004 +2026-10-13T14:51:35.872Z,6.7,60,229.5,0.004 +2026-10-13T14:51:37.881Z,6.6,61,229.5,0.004 +2026-10-13T14:51:39.858Z,7.2,63,229.5,0.004 +2026-10-13T14:51:46.863Z,7.2,63,229.5,0.004 +2026-10-13T14:51:46.979Z,19.1,127,229.1,0.004 +2026-10-13T14:51:49.007Z,6.9,63,229.1,0.004 +2026-10-13T14:51:50.980Z,7.4,60,229.1,0.004 +2026-10-13T14:51:57.986Z,7.4,60,229.1,0.004 +2026-10-13T14:51:58.110Z,6.7,60,229.5,0.004 +2026-10-13T14:52:00.100Z,10.1,87,229.5,0.004 +2026-10-13T14:52:02.101Z,6.9,61,229.5,0.004 +2026-10-13T14:52:09.105Z,6.9,61,229.5,0.004 +2026-10-13T14:52:09.224Z,6.5,60,229.5,0.004 +2026-10-13T14:52:11.221Z,6.8,61,229.5,0.004 +2026-10-13T14:52:13.233Z,7,62,229.5,0.004 +2026-10-13T14:52:20.223Z,7,62,229.5,0.004 +2026-10-13T14:52:20.340Z,6.9,61,229.5,0.004 +2026-10-13T14:52:22.336Z,8.9,58,229.5,0.004 +2026-10-13T14:52:24.348Z,11.3,96,229.5,0.004 +2026-10-13T14:52:31.349Z,11.3,96,229.5,0.004 +2026-10-13T14:52:31.463Z,6.5,58,229.5,0.004 +2026-10-13T14:52:33.464Z,6.9,59,229.5,0.004 +2026-10-13T14:52:35.490Z,6.5,60,229.5,0.004 +2026-10-13T14:52:42.464Z,6.5,60,229.5,0.004 +2026-10-13T14:52:42.583Z,6.6,58,229.5,0.004 +2026-10-13T14:52:44.581Z,6.6,59,229.5,0.004 +2026-10-13T14:52:46.577Z,9.4,79,229.5,0.004 +2026-10-13T14:52:54.607Z,9.4,79,229.5,0.004 +2026-10-13T14:52:54.725Z,9.7,80,229.5,0.004 +2026-10-13T14:52:56.733Z,6.9,62,229.5,0.004 +2026-10-13T14:53:03.746Z,6.9,62,229.5,0.004 +2026-10-13T14:53:04.126Z,6.5,58,229.5,0.004 +2026-10-13T14:53:05.903Z,11.8,61,229.5,0.004 +2026-10-13T14:53:07.915Z,7.7,72,229.5,0.004 +2026-10-13T14:53:14.881Z,7.7,72,229.5,0.004 +2026-10-13T14:53:15.003Z,7,70,232.1,0.004 +2026-10-13T14:53:17.003Z,6.3,63,232.1,0.004 +2026-10-13T14:53:19.030Z,6.6,60,232.1,0.004 +2026-10-13T14:53:26.022Z,6.6,60,232.1,0.004 +2026-10-13T14:53:26.143Z,12.2,67,231.7,0.004 +2026-10-13T14:53:28.136Z,8.7,93,231.7,0.004 +2026-10-13T14:53:30.135Z,6.7,58,231.7,0.004 +2026-10-13T14:53:37.137Z,6.7,58,231.7,0.004 +2026-10-13T14:53:37.256Z,6.7,59,231.7,0.004 +2026-10-13T14:53:39.257Z,7.1,57,231.7,0.004 +2026-10-13T14:53:41.269Z,8.9,75,231.7,0.004 +2026-10-13T14:53:48.289Z,8.9,75,231.7,0.004 +2026-10-13T14:53:48.417Z,18.9,59,230.8,0.004 +2026-10-13T14:53:50.470Z,11.8,99,230.8,0.004 +2026-10-13T14:53:52.404Z,8.7,73,230.8,0.004 +2026-10-13T14:53:59.406Z,8.7,73,230.8,0.004 +2026-10-13T14:53:59.531Z,7,61,232.1,0.004 +2026-10-13T14:54:01.515Z,7.1,63,232.1,0.004 +2026-10-13T14:54:03.523Z,7.3,61,232.1,0.004 +2026-10-13T14:54:10.522Z,7.3,61,232.1,0.004 +2026-10-13T14:54:10.642Z,10,95,232.6,0.004 +2026-10-13T14:54:12.636Z,7,61,232.6,0.004 +2026-10-13T14:54:14.709Z,6.6,58,232.6,0.004 +2026-10-13T14:54:21.836Z,6.6,58,232.6,0.004 +2026-10-13T14:54:21.972Z,12.7,97,232.1,0.004 +2026-10-13T14:54:23.977Z,11.3,100,232.1,0.004 +2026-10-13T14:54:25.951Z,11.3,99,232.1,0.004 +2026-10-13T14:54:32.988Z,11.3,99,232.1,0.004 +2026-10-13T14:54:33.104Z,7,63,232.6,0.004 +2026-10-13T14:54:35.105Z,6.6,60,232.6,0.004 +2026-10-13T14:54:37.104Z,7.4,64,232.6,0.004 +2026-10-13T14:54:44.103Z,7.4,64,232.6,0.004 +2026-10-13T14:54:44.217Z,7,67,232.1,0.004 +2026-10-13T14:54:46.225Z,7,153,232.1,0.004 +2026-10-13T14:54:53.225Z,7,153,232.1,0.004 +2026-10-13T14:54:53.348Z,11.7,106,232.1,0.004 +2026-10-13T14:54:55.349Z,11.3,91,232.1,0.004 +2026-10-13T14:54:57.344Z,7.3,65,232.1,0.004 +2026-10-13T14:54:59.348Z,7.2,61,232.1,0.004 +2026-10-13T14:55:06.342Z,7.2,61,232.1,0.004 +2026-10-13T14:55:06.469Z,9.6,58,232.1,0.004 +2026-10-13T14:55:08.458Z,6.5,58,232.1,0.004 +2026-10-13T14:55:15.483Z,6.5,58,232.1,0.004 +2026-10-13T14:55:15.598Z,6.5,59,232.6,0.004 +2026-10-13T14:55:17.603Z,6.5,58,232.6,0.004 diff --git a/documentation/operations/nodes.md b/documentation/operations/nodes.md index a3c0a647..68a968e6 100644 --- a/documentation/operations/nodes.md +++ b/documentation/operations/nodes.md @@ -185,6 +185,15 @@ the hub `host_recovery` row **`demo-felhom-8363b5`** (same PUT `…/recovery-cre uses; verified retrievable + authenticating over `:22`). Retrieval + shred-the-copy recipe is identical to demo-hp's below (swap the host_id). So a lost N100 key is recoverable the same way as the key-less HP. +## The N100 is on a metered plug (2026-10-13) + +The N100 draws its power through a Tuya Wi-Fi plug with a power meter (LAN `192.168.0.115`, protocol 3.4; re-check +with `tinytuya scan` if it stops answering). Read it from DooPlex with +`~/.venvs/plugmeter/bin/python scripts/bench/plugmeter.py --once` (`scripts/bench/README.md`). A second reader, +**Home Assistant on demo-hp's guest 9201** (`ha.enkisfelhom.hu`, installed from the catalog 2026-10-13), **stays +installed on purpose**: it reads the plug through Tuya's cloud and keeps its history. Keys live only in DooPlex +`~/.config/felhom-bench/`. `audits/plugmeter-2026-10-13/`. + ## Tailscale on demo-hp is an OPERATOR-LAB EXCEPTION > **Read this before any product-shape audit.** `demo-hp` is **customer-shaped** — it is a normal diff --git a/scripts/CHANGELOG.md b/scripts/CHANGELOG.md index 7a79b874..35240364 100644 --- a/scripts/CHANGELOG.md +++ b/scripts/CHANGELOG.md @@ -1,3 +1,14 @@ +## 2026-10-13 (evening) — plugmeter: the N100's power plug, read from DooPlex + +- New `scripts/bench/plugmeter.py` + `scripts/bench/README.md`: reads the Tuya meter plug the N100 runs on and prints + CSV (`utc_time, watts, milliamps, volts, kwh_total`) every `--interval` s (default 2); `--duration`, `--once`. + `--source tuya` (default) talks to the plug on the LAN (tinytuya 1.20.0, protocol 3.4) and forces a re-measure on + each read; `--source ha` reads Home Assistant on demo-hp's guest. Keys and the token stay in DooPlex + `~/.config/felhom-bench/` (700/600), never in a repo. A failed read logs to stderr and the run goes on. +- Measured (`documentation/audits/plugmeter-2026-10-13/`): 10 min side by side, both mean ~8.4 W, median 7.2 W. + Home Assistant alone did not change for 3 minutes — the plug reports to the cloud only when the local reader asks. + Recommended source: tuya. +- `documentation/operations/nodes.md`: the N100 is on a metered plug; Home Assistant on demo-hp stays installed. ## 2026-10-13 (night) — estimator v3.1 tests - `test_build_sizing_web.py` (12 tests): the bar is never below the smallest named box, its parts still sum to it diff --git a/scripts/bench/README.md b/scripts/bench/README.md new file mode 100644 index 00000000..5698044c --- /dev/null +++ b/scripts/bench/README.md @@ -0,0 +1,33 @@ +# scripts/bench — bench tools that run on DooPlex + +## plugmeter.py — the N100's power meter + +The N100 demo box (`demo-felhom`) is on a Tuya Wi-Fi plug with a power meter. `plugmeter.py` reads it and +prints CSV (`utc_time, watts, milliamps, volts, kwh_total`) every `--interval` seconds (default 2). + +``` +~/.venvs/plugmeter/bin/python scripts/bench/plugmeter.py --once # one reading +~/.venvs/plugmeter/bin/python scripts/bench/plugmeter.py --duration 600 > a.csv # 10 minutes +~/.venvs/plugmeter/bin/python scripts/bench/plugmeter.py --source ha --once # through Home Assistant +``` + +- **`--source tuya` (default) — use this for measurements.** It talks to the plug on the home LAN and + makes it re-measure on every read; a new value every 2 s. Each value is the plug's previous measurement + (it answers a refresh with what it holds), so a row lags by about one interval. About one read in four takes + up to 8 s instead of 2 s; the row is late, not lost. +- **`--source ha` — the backup.** Home Assistant on demo-hp's guest (`https://ha.enkisfelhom.hu`, installed + from the Felhom catalog) reads the plug through Tuya's cloud. **On its own it did not change for 3 minutes** + (2026-10-13); it moves only when something makes the plug report — the tuya reader does. It keeps history and graphs. Its `felhom-bench` user is local-access-only, so the tool connects + to the guest's LAN address and still checks the certificate by name. + +Setup (done 2026-10-13, `documentation/audits/plugmeter-2026-10-13/`): a user venv +(`python3 -m venv ~/.venvs/plugmeter && ~/.venvs/plugmeter/bin/pip install tinytuya`), and the files under +`~/.config/felhom-bench/` (700; every file 600): `plug.json` (device id, local key, address, data points), +`ha.json`, `ha.token`, and the tinytuya wizard's output. **None of them ever goes into a repo.** + +`kwh_total` is the plug's `add_ele` counter — energy since the plug last reported to the cloud, not a +lifetime total. Use watts × time for energy. + +When the plug moves address or is paired again: re-run the tinytuya wizard in `~/.config/felhom-bench/` +(credentials `TUYA_ID`, `TUYA_SECRET`, `TUYA_DEVICE_ID` from `~/.config/credentials`, region `eu`) and +update `plug.json`. Its output prints the key — send it to a file, never to a terminal or a log. diff --git a/scripts/bench/plugmeter.py b/scripts/bench/plugmeter.py new file mode 100644 index 00000000..a45cea55 --- /dev/null +++ b/scripts/bench/plugmeter.py @@ -0,0 +1,150 @@ +#!/usr/bin/env python3 +"""plugmeter.py — read the N100 bench's metered Wi-Fi plug and print CSV. + + ~/.venvs/plugmeter/bin/python scripts/bench/plugmeter.py --once + ~/.venvs/plugmeter/bin/python scripts/bench/plugmeter.py --duration 600 > run.csv + ~/.venvs/plugmeter/bin/python scripts/bench/plugmeter.py --source ha --once + +CSV columns: utc_time, watts, milliamps, volts, kwh_total. + +Sources: + tuya (default) the plug directly on the LAN (tinytuya, protocol 3.4). Reads + ~/.config/felhom-bench/plug.json: id, key, ip, version, dps. + ha Home Assistant on demo-hp's guest (Tuya cloud integration). Reads + ~/.config/felhom-bench/ha.json (url, connect_ip, entities) and + ~/.config/felhom-bench/ha.token (a non-admin long-lived token). + connect_ip sends the request to the guest on the LAN while TLS still + checks the certificate of the url's host name: the felhom-bench user is + "local access only", so the public (Cloudflare) path is refused. + +Data points (read from the device 2026-10-13, documentation/audits/plugmeter-2026-10-13/): + 19 cur_power W x10, 18 cur_current mA, 20 cur_voltage V x10, 17 add_ele kWh x1000. +kwh_total is the plug's add_ele counter: energy since the plug last reported to the Tuya +cloud, NOT a lifetime total. It can drop back to 0. Use watts x time for energy. + +A failed read logs one line to stderr and the loop continues. The key and the token are +never printed. Secrets live only in ~/.config/felhom-bench/ (700/600), never in a repo. +""" +import argparse, datetime, http.client, json, os, socket, ssl, sys, time + +CONF = os.path.expanduser('~/.config/felhom-bench') + + +def log(msg): + print(f'{now()} plugmeter: {msg}', file=sys.stderr, flush=True) + + +def now(): + return datetime.datetime.now(datetime.timezone.utc).strftime('%Y-%m-%dT%H:%M:%S.%fZ')[:-4] + 'Z' + + +class TuyaSource: + def __init__(self): + import tinytuya + c = json.load(open(os.path.join(CONF, 'plug.json'))) + self.dps = c['dps'] + self.dev = tinytuya.OutletDevice(c['id'], c['ip'], c['key'], version=float(c['version'])) + self.dev.set_socketTimeout(5) + self.dev.set_socketRetryLimit(1) + # updatedps asks the plug to re-measure; without it status() repeats a cached reading. + self.refresh = [int(self.dps[k][0]) for k in ('milliamps', 'watts', 'volts')] + # The plug answers a refresh with the reading it already holds; the new one arrives later. So the + # first read of a run can be minutes old (measured 2026-10-13: 18.7 W first, 6.8 W two seconds + # later). Ask once now, so the first printed row is already fresh. + self.dev.updatedps(self.refresh) + time.sleep(1) + + def read(self): + self.dev.updatedps(self.refresh) + s = self.dev.status() + if not isinstance(s, dict) or 'dps' not in s: + # tinytuya returns an error dict, not an exception; it never holds the key. + raise RuntimeError(f"tuya error {s.get('Err') if isinstance(s, dict) else ''} {s.get('Error') if isinstance(s, dict) else s}") + d = s['dps'] + + def val(name): + dp, div = self.dps[name] + return d[dp] / div if dp in d else None + return val('watts'), val('milliamps'), val('volts'), val('kwh_added') + + +class HASource: + def __init__(self): + c = json.load(open(os.path.join(CONF, 'ha.json'))) + self.host = c['url'].split('://', 1)[1].rstrip('/') + self.ip = c.get('connect_ip') or self.host + self.entities = c['entities'] # {"watts": "sensor.…", "milliamps": …, "volts": …, "kwh_total": …} + self.token = open(os.path.join(CONF, 'ha.token')).read().strip() + self.ctx = ssl.create_default_context() + + def state(self, entity): + sock = socket.create_connection((self.ip, 443), timeout=5) + conn = http.client.HTTPSConnection(self.host, timeout=5, context=self.ctx) + conn.sock = self.ctx.wrap_socket(sock, server_hostname=self.host) # SNI + cert check on the name + try: + conn.request('GET', f'/api/states/{entity}', headers={'Authorization': 'Bearer ' + self.token}) + r = conn.getresponse() + body = r.read() + if r.status != 200: + raise RuntimeError(f'HA {entity}: HTTP {r.status}') + return json.loads(body) + finally: + conn.close() + + def read(self): + out = [] + for name in ('watts', 'milliamps', 'volts', 'kwh_total'): + ent = self.entities.get(name) + if not ent: + out.append(None) + continue + st = self.state(ent) + try: + v = float(st['state']) + except (TypeError, ValueError): + v = None + if v is not None and name == 'milliamps' and st.get('attributes', {}).get('unit_of_measurement') == 'A': + v *= 1000 + out.append(v) + return tuple(out) + + +def fmt(v): + return '' if v is None else f'{v:g}' + + +def main(): + ap = argparse.ArgumentParser(description=__doc__.split('\n')[0]) + ap.add_argument('--source', choices=('tuya', 'ha'), default='tuya') + ap.add_argument('--interval', type=float, default=2.0, help='seconds between reads (default 2)') + ap.add_argument('--duration', type=float, default=0, help='seconds to run; 0 = until stopped') + ap.add_argument('--once', action='store_true', help='one read, then exit (rc 1 if it failed)') + a = ap.parse_args() + + src = TuyaSource() if a.source == 'tuya' else HASource() + print('utc_time,watts,milliamps,volts,kwh_total', flush=True) + start = time.monotonic() + fails = 0 + while True: + t0 = time.monotonic() + try: + w, ma, v, kwh = src.read() + print(f'{now()},{fmt(w)},{fmt(ma)},{fmt(v)},{fmt(kwh)}', flush=True) + except Exception as e: # one bad read must not end a measurement run + fails += 1 + log(f'read failed ({type(e).__name__}: {e})') + if a.once: + return 1 + if a.once: + return 0 + if a.duration and time.monotonic() - start >= a.duration: + log(f'done, {fails} failed reads') + return 0 + time.sleep(max(0.0, a.interval - (time.monotonic() - t0))) + + +if __name__ == '__main__': + try: + sys.exit(main()) + except KeyboardInterrupt: + sys.exit(0)