diff --git a/hosts/hass.windy.lan.md b/hosts/hass.windy.lan.md index 85c3c6e..0e6b241 100644 --- a/hosts/hass.windy.lan.md +++ b/hosts/hass.windy.lan.md @@ -351,6 +351,55 @@ deployed 2026-08-18 from `216cc99` (backup - Recorder stays external-Postgres with `purge_keep_days: 30` for daily UI history; Scribe is the permanent archive. +### Timescale Plotly card + database reader (verified 2026-08-29) + +Chart stack over the Scribe TimescaleDB archive. Upstream pair (no HACS; +manual copies): reader `remmob/timescale_database_reader` **v1.1.0** (main +`bb8776a`) + card `remmob/timescale-plotly-card` **2.2.0** (main `217961d`). + +- **Reader integration**: `/homeassistant/custom_components/timescale_database_reader/`. + Config entry `01M165P77QT1FQEAVPNZHDT82W` ("Scribe", `source: user`): connects + `hass@192.168.55.15:5432/scribe` (credentials = `secrets.yaml` `scribe_url`), + `table: sensor_minute`. Exposes no entities/services — it serves WS command + `timescale/query` (window ≤ 365 d, ≤ 50 000 rows, `downsample` bucket seconds). + Benign startup warning `Error executing test query: column "time" does not + exist`: the self-test SQL assumes the LTSS column name; the scribe table uses + `minute` — real queries work (verified: 70 rows for a live power sensor). +- **Card**: `/homeassistant/www/community/timescale-plotly-card/timescale-plotly-card.js` + (root-owned, same convention as HACS dirs). Lovelace resource (storage) + id `2e360d17b5aa4ce59c2fd13c43b51215` → + `/hacsfiles/timescale-plotly-card/timescale-plotly-card.js`, type `module`. + Card config matches the entry by `database: scribe` (name from the reader + entry). Updates: replace the file, resource URL unchanged — browsers need a + hard refresh or a bumped `?v=` query on the resource URL. +- **pgdb side** (`sensor_minute_aggregate` cagg + `sensor_minute` hypertable + + every-minute refresh job): see [hosts/pgdb.md](pgdb.md) § Databases. +- **Agent-side HA WebSocket without a long-lived token** (verified 2026-08-29): + connect `ws://supervisor/core/websocket` with header + `Authorization: Bearer $SUPERVISOR_TOKEN`, then send + `{"type":"auth","access_token":"$SUPERVISOR_TOKEN"}` — the Supervisor proxy + swaps it for a core token (works as the internal Supervisor admin user). Note + `lovelace/resources/create` in HA 2026.8 takes `res_type` (NOT + `resource_type`). +- Scribe stores numeric sensor values in `states_raw.value` with `state` NULL, + so `sensor_minute.state` shows `'0'` for numeric sensors; the card plots + `avg_state` (from `value`) — expected, not a bug. +- **Quick 仪表盘(`dashboard-quick`)图表套件**(2026-08-29,经 WS + `lovelace/config/save` 写入):5 张 timescale 卡——大功率电器/常驻负载 + 功率(按量级拆两张图,避免 1100 W 尖峰压扁 <70 W 基线)、按插座用电量 + (`energy_mode` + cumulative/diff,数据质量前提见 pgdb 的 refresh 过程补丁)、 + 室内外温湿度(温度左轴/湿度右轴,4 位置同色配对)、人体感应活动状态 + (3 个 `motion_state`,banded `state_map` none/small/medium/large → 0-11)。 + 布局:全部分区显式 `column_span: 4`(视图 `type: sections` + `max_columns: 4`), + 灯区 4 张控制卡横排一行。**分区/卡片是两套尺寸键,不可混用**: + 分区宽 = `column_span`(`hui-sections-view.ts` 缺省按 1 列渲染,绝不省略); + 卡片宽 = `grid_options: {columns: }`(`hui-card.ts` 只读 + `config.grid_options`,写在卡片上的 `column_span` 被静默忽略;缺省 12 列, + 分区内格 = 12 × 分区 span,故 span-4 分区里缺省卡片只有 1/4 宽)。另外 + 图表卡固定外壳(标题/时间按钮/状态行 ≈125px)使整卡最低 ~300px,与矮 + 控制区并排必然留白,故不做半宽并排。 + 修改前备份:`/homeassistant/.lovelace-backups/dashboard-quick-*.json`。 + ## Known issues **Bluetooth hci0 instability — RTL8821CS (verified 2026-08-13, W1N-74):** diff --git a/hosts/pgdb.md b/hosts/pgdb.md index 9386129..1fbf879 100644 --- a/hosts/pgdb.md +++ b/hosts/pgdb.md @@ -42,6 +42,8 @@ ## Known issues - 2026-08-29:HA 侧 HACS 集成 `custom_components.scribe`(YAML `scribe: db_url:`,连 `scribe` 库)建表被拒(`permission denied for schema public`,hass 无 CREATE 权限),之后持续报 `relation "entities" does not exist`。**已解决**:① `GRANT CREATE ON SCHEMA public TO hass;`(scribe 库)② 重启 HA Core 触发重跑建表。重启后自动创建 `entities`(1591 行)/`users`/`areas`/`devices`/`integrations`/`states_raw` 表并启用 TimescaleDB 时间序列能力。报错已停止(最后一条 06:06 UTC),`states_raw` 持续写入。2026-08-29 复查:scribe 现有**两个** hypertable——`states_raw`(segmentby `metadata_id`、orderby `time`)与 `events`(segmentby `event_type`、orderby `time`),均 1 维 `time`;压缩已配置(`timescaledb_information.compression_settings` 可见对应行;2.29.x 该视图无 `compression_enabled` 列)。 +- 2026-08-29:**timescale reader 图表对象**(配套 hass 的 `timescale_database_reader` 集成 + `timescale-plotly-card`,上游 SQL `remmob/timescale_database_reader` `SQL/scribe/01+02` @ `bb8776a`,以 postgres 执行):`sensor_minute_aggregate` 连续聚合(1 分钟桶,last(state)/last(value),实时聚合开启)+ `sensor_minute_aggregate_entity` 视图(join `entities`)+ `sensor_minute` hypertable(`minute`/`entity_id`/`state`/`value`,LOCF 前向填充)。任务:1005 `sensor_minute` 压缩(7 天)、1006 `sensor_minute` 保留(10 年)、1007 `every_minute_refresh` 每分钟增量刷新(含 5 分钟回溯窗口修正)。授权:`GRANT SELECT ON sensor_minute_aggregate, sensor_minute_aggregate_entity, sensor_minute, entities TO hass`。种子 19529 行(331 实体,自首个数据点起)。**刻意跳过**了上游脚本对 `states_raw` 的 3 个月保留 + 压缩策略语句——与"`states_raw` 永久归档"定位冲突,如需磁盘回收属用户决策(scribe 自己的压缩任务 1000/1001 未动)。 +- 2026-08-29:**`sensor_minute_refresh` 本地补丁(类比 tianqi 补丁,重跑上游 02 SQL 后需重打)**:值 CASE 的 `ELSE 0` → `ELSE NULL`。原因:scribe 对 unavailable 分钟 value 为 NULL,上游刷新过程兜底写 0;对差分模式的用电图,0→计数器回升会把插座的**生命周期累计值**(最高 1588 kWh)算进掉线那一小时。同日一次性清理既有脏 0:头部占位行 DELETE 505 行(各实体首次非零分钟之前的 value=0);`sensor.%_energy` 与温湿度实体的 value=0 → NULL(10+16 行,物理上不可能的真 0,图表渲染为断点)。功率实体的中途 0 是真实待机读数,保留。 - `hass` 库的 recorder 表仍为普通表(无 hypertable);`scribe` 集成负责时间序列历史(`states_raw` + `events` hypertable)。 ## Verification history