Files
vps/hosts/pgdb.md
T
windyboy 8c73d1f894 docs(hass,pgdb): timescale-plotly-card chart stack — reader+card install, sensor_minute pipeline, Quick dashboard
- reader timescale_database_reader v1.1.0 (bb8776a) + card timescale-plotly-card
  2.2.0 (217961d), manual installs; config entry, Lovelace resource id recorded
- pgdb scribe: sensor_minute_aggregate cagg + sensor_minute hypertable + jobs
  1005/1006/1007; states_raw 3-month retention/compression statements deliberately
  skipped (permanent archive per host doc)
- sensor_minute_refresh local patch ELSE 0 → ELSE NULL (unavailable-minute zeros
  poison diff-mode energy charts) + one-time cleanup (505 head rows, 26 impossible
  zeros); re-apply after re-running upstream 02 SQL
- Quick dashboard: 5 chart cards via WS lovelace/config/save; documented section
  column_span (absent → span 1) vs card grid_options sizing rules
2026-08-29 15:54:40 +08:00

7.6 KiB
Raw Blame History

pgdb — TimescaleDB (PG18, Docker)

Role and access

Item Value
Role TimescaleDB PostgreSQL 18 (Docker) — Home Assistant recorder 后端(hass/scribe 库)
IPv4 192.168.55.15 (LAN55)
DNS (none)
SSH ssh -4 windy@192.168.55.15key auth 已验证可用 2026-08-29agent 沙箱用 ssh -F /dev/null -o BatchMode=yespassword auth 亦可)
Host PVE 管理的 QEMU VMi440FX),Debian 13 (trixie),内核 6.12.105
Resources 2 GB RAM / 30 GB disk26 G 空闲)
Docker 29.7.2;容器 timescaledb = timescale/timescaledb:latest-pg18PG 18.6 + TimescaleDB 2.29.2Apache-2.0 版)
Ports 192.168.55.15:5432PGIPv4 only);192.168.55.15:8081pgweb GUIbasic auth

Databases

DB Owner Size 用途
hass hass ~14 MB HA recorderstates/events/statistics),客户端 HAOS 192.168.55.11
scribe postgres ~11 MB HA scribe 集成(entities/areas/devices 注册表同步 + states_raw hypertable
postgres postgres ~9 MB 默认库

Ops notes

  • Docker compose 管理2026-08-29 改造):/opt/database/docker-compose.yml(源码在仓库 compose/pgdb/+ /opt/database/.env0600,密钥)+ /opt/database/pgweb-bookmarks/0600bookmark 含 DB 密码)。三个服务:
    服务 镜像 端口 说明
    timescaledb timescale/timescaledb:latest-pg18 192.168.55.15:5432IPv4 only PG 18.6 + TS 2.29.2healthcheck pg_isreadyrestart: unless-stopped
    pgweb sosedoff/pgweb:latestv0.17.0 192.168.55.15:8081 Web GUIhttp://192.168.55.15:8081basic auth(用户名/密码见 .env PGWEB_AUTH_USER/PASS);--readonly --sessions --bookmarks-only --bookmarks-dir /bookmarksv0.17.0 不读 PGWEB_BOOKMARKS_DIR env,必须用 flag);bookmarks = hass/scribe
    pg-backup prodrigestivill/postgres-backup-local:latest=PG18 客户端) 每日 02:00TZ=Asia/Shanghai,本地时区)pg_dump -Fc 三库 → /opt/database/backups/{daily,weekly,monthly};保留 7 天/4 周/6 月;BACKUP_ON_START
  • 数据盘/dev/sdb132G ext4label pgdata)挂载 /srv/pgdatafstab 按 UUID=c9e12e79-1f66-404c-ab7f-b8809be81d86defaults,noatime)持久化(2026-08-29 迁移)。容器 bind mount /srv/pgdata:/var/lib/postgresql
  • 容器内 postgres 用户 uid/gid = 70(Debian 系,非 999);迁移数据后需 chown -R 70:70
  • 密码:postgres 超级用户已换强密码(hex,存 /opt/database/.env 06002026-08-29)。HA 用 hass 角色不受影响。
  • 备份:由 pg-backup 容器接管(2026-08-29),宿主机 cron 与 /opt/database/pg-backup.sh 已退役。恢复用 pg_restorecustom format)——2026-08-29 已实测还原 hass 库 dumpstates 10014 行)成功。
  • 认证:外部连接 scram-sha-256(密码必填,改密码有效);容器内 loopback 为 trust(官方镜像默认)。
  • 回滚:旧启动命令保留在 /opt/database/run(容器无状态,数据在 /srv/pgdata);旧匿名卷 9375195843b950f4e04c34872409ca095e1136520dd019a8e86e2794be06c236(根盘 ~82M)保留作兜底,确认稳定后可 docker volume rm
  • 本机无防火墙(ufw/nft/iptables 均未装)——待办:如要彻底隔离可加 ufw 白名单 192.168.55.11。
  • /opt/database/backups/ 根下残留 *-2026-08-29_1359.dump(compose 化之前旧备份机制产物)与 backup.log——健康检查只看 daily/,残留可清理。
  • Runbookspgdb-health(只读健康检查)、pgdb-restorepg_restore 还原)、pgdb-update(镜像/compose 升级)。

Known issues

  • 2026-08-29HA 侧 HACS 集成 custom_components.scribeYAML scribe: db_url:,连 scribe 库)建表被拒(permission denied for schema publichass 无 CREATE 权限),之后持续报 relation "entities" does not exist已解决:① GRANT CREATE ON SCHEMA public TO hass;scribe 库)② 重启 HA Core 触发重跑建表。重启后自动创建 entities1591 行)/users/areas/devices/integrations/states_raw 表并启用 TimescaleDB 时间序列能力。报错已停止(最后一条 06:06 UTC),states_raw 持续写入。2026-08-29 复查:scribe 现有两个 hypertable——states_rawsegmentby metadata_id、orderby time)与 eventssegmentby event_type、orderby time),均 1 维 time;压缩已配置(timescaledb_information.compression_settings 可见对应行;2.29.x 该视图无 compression_enabled 列)。
  • 2026-08-29timescale 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 hypertableminute/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-29sensor_minute_refresh 本地补丁(类比 tianqi 补丁,重跑上游 02 SQL 后需重打):值 CASE 的 ELSE 0ELSE 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

  • 2026-08-29:首次检查(只读)+ 修复 scribe 权限 + 安装夜间备份。见 Linear vps 项目登记。
  • 2026-08-29compose 改造完成W1N-227,用户已验收):裸 docker run/opt/database/docker-compose.yml 三服务(timescaledb + pgweb + pg-backup);superuser 换强密码;端口收紧 IPv4;备份容器化(TZ=Asia/Shanghaicron 02:00 本地);pg_restore 还原实测通过;pgweb UI 用户确认可查 hass/scribe 数据。源码在仓库 compose/pgdb/
  • 2026-08-29运维 runbook 落地W1N-228,已验收):新增 runbooks/pgdb-health.md(只读,8 项诊断全绿)、pgdb-restore.md(流程式,temp-DB 安全还原 + 审批门)、pgdb-update.md(门控命令式,回滚=/opt/database/run + 旧卷);README 索引与 validate-repo.sh 分类同步更新;runbook 命令已对活主机逐条实测(含 pg_restore -l 校验当日 dump)。同日修正:SSH key auth 可用(facts 原记"密钥未安装"已过时);scribe 新增 events hypertable。