feat: 添加 G5 独立写入功能

- 新增 G5 数据库连接配置与可关闭的写入开关
- 在现有 legacy/G4 写入成功路径后,追加独立的 G5 写入流程
- G5 使用与 G4 相同的数据结构映射,但不写入 guid,由数据库自生成 int4 guid
- room_status 新增 G5 独立 upsert 写入路径,并保留旧表与 G5 表的独立开关
- 新增 G5 写入统计与启动摘要输出
- 更新 StatsCounters 和 StatsReporter 以支持 G5 统计
- 增加测试覆盖,确保 G5 写入逻辑与 room_status 的独立执行
- 新增 G5 相关数据库表结构 SQL 文件
This commit is contained in:
2026-03-10 16:29:24 +08:00
parent fe76884b27
commit 2f8857f98e
14 changed files with 924 additions and 130 deletions

View File

@@ -0,0 +1,193 @@
/*
Navicat Premium Dump SQL
Source Server : FnOS 80
Source Server Type : PostgreSQL
Source Server Version : 150017 (150017)
Source Host : 10.8.8.80:5434
Source Catalog : log_platform
Source Schema : heartbeat
Target Server Type : PostgreSQL
Target Server Version : 150017 (150017)
File Encoding : 65001
Date: 10/03/2026 10:18:37
*/
-- ----------------------------
-- Table structure for heartbeat_events_g5
-- ----------------------------
DROP TABLE IF EXISTS "heartbeat"."heartbeat_events_g5";
CREATE TABLE "heartbeat"."heartbeat_events_g5" (
"guid" int4 NOT NULL DEFAULT nextval('"heartbeat".heartbeat_events_g5_guid_seq'::regclass),
"ts_ms" int8 NOT NULL,
"hotel_id" int2 NOT NULL,
"room_id" varchar(50) COLLATE "pg_catalog"."default" NOT NULL,
"device_id" varchar(64) COLLATE "pg_catalog"."default" NOT NULL,
"ip" varchar(21) COLLATE "pg_catalog"."default" NOT NULL,
"power_state" int2 NOT NULL,
"guest_type" int2 NOT NULL,
"cardless_state" int2 NOT NULL,
"service_mask" int8,
"pms_state" int2 NOT NULL,
"carbon_state" int2 NOT NULL,
"device_count" int2 NOT NULL,
"comm_seq" int4 NOT NULL,
"elec_address" _text COLLATE "pg_catalog"."default",
"air_address" _text COLLATE "pg_catalog"."default",
"voltage" _float8,
"ampere" _float8,
"power" _float8,
"phase" _text COLLATE "pg_catalog"."default",
"energy" _float8,
"sum_energy" _float8,
"state" _int2,
"model" _int2,
"speed" _int2,
"set_temp" _int2,
"now_temp" _int2,
"solenoid_valve" _int2,
"extra" jsonb,
"write_ts_ms" int8 NOT NULL DEFAULT ((EXTRACT(epoch FROM clock_timestamp()) * (1000)::numeric))::bigint,
"insert_card" int2,
"bright_g" int2,
"version" int2,
"svc_01" bool,
"svc_02" bool,
"svc_03" bool,
"svc_04" bool,
"svc_05" bool,
"svc_06" bool,
"svc_07" bool,
"svc_08" bool,
"svc_09" bool,
"svc_10" bool,
"svc_11" bool,
"svc_12" bool,
"svc_13" bool,
"svc_14" bool,
"svc_15" bool,
"svc_16" bool,
"svc_17" bool,
"svc_18" bool,
"svc_19" bool,
"svc_20" bool,
"svc_21" bool,
"svc_22" bool,
"svc_23" bool,
"svc_24" bool,
"svc_25" bool,
"svc_26" bool,
"svc_27" bool,
"svc_28" bool,
"svc_29" bool,
"svc_30" bool,
"svc_31" bool,
"svc_32" bool,
"svc_33" bool,
"svc_34" bool,
"svc_35" bool,
"svc_36" bool,
"svc_37" bool,
"svc_38" bool,
"svc_39" bool,
"svc_40" bool,
"svc_41" bool,
"svc_42" bool,
"svc_43" bool,
"svc_44" bool,
"svc_45" bool,
"svc_46" bool,
"svc_47" bool,
"svc_48" bool,
"svc_49" bool,
"svc_50" bool,
"svc_51" bool,
"svc_52" bool,
"svc_53" bool,
"svc_54" bool,
"svc_55" bool,
"svc_56" bool,
"svc_57" bool,
"svc_58" bool,
"svc_59" bool,
"svc_60" bool,
"svc_61" bool,
"svc_62" bool,
"svc_63" bool,
"svc_64" bool,
"air_address_1" text COLLATE "pg_catalog"."default",
"air_address_2" text COLLATE "pg_catalog"."default",
"air_address_residual" _text COLLATE "pg_catalog"."default",
"state_1" int2,
"state_2" int2,
"state_residual" _int2,
"model_1" int2,
"model_2" int2,
"model_residual" _int2,
"speed_1" int2,
"speed_2" int2,
"speed_residual" _int2,
"set_temp_1" int2,
"set_temp_2" int2,
"set_temp_residual" _int2,
"now_temp_1" int2,
"now_temp_2" int2,
"now_temp_residual" _int2,
"solenoid_valve_1" int2,
"solenoid_valve_2" int2,
"solenoid_valve_residual" _int2,
"elec_address_1" text COLLATE "pg_catalog"."default",
"elec_address_2" text COLLATE "pg_catalog"."default",
"elec_address_residual" _text COLLATE "pg_catalog"."default",
"voltage_1" float8,
"voltage_2" float8,
"voltage_residual" _float8,
"ampere_1" float8,
"ampere_2" float8,
"ampere_residual" _float8,
"power_1" float8,
"power_2" float8,
"power_residual" _float8,
"phase_1" text COLLATE "pg_catalog"."default",
"phase_2" text COLLATE "pg_catalog"."default",
"phase_residual" _text COLLATE "pg_catalog"."default",
"energy_1" float8,
"energy_2" float8,
"energy_residual" _float8,
"sum_energy_1" float8,
"sum_energy_2" float8,
"sum_energy_residual" _float8,
"power_carbon_on" float8,
"power_carbon_off" float8,
"power_person_exist" float8,
"power_person_left" float8
)
TABLESPACE "ts_hot"
;
-- ----------------------------
-- Indexes structure for table heartbeat_events_g5
-- ----------------------------
CREATE INDEX "heartbeat_events_g5_ts_ms_idx" ON "heartbeat"."heartbeat_events_g5" USING btree (
"ts_ms" "pg_catalog"."int8_ops" DESC NULLS FIRST
) TABLESPACE "ts_hot";
CREATE INDEX "idx_hb_g5_device_ts" ON "heartbeat"."heartbeat_events_g5" USING btree (
"device_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
"ts_ms" "pg_catalog"."int8_ops" DESC NULLS FIRST
);
CREATE INDEX "idx_hb_g5_room_query" ON "heartbeat"."heartbeat_events_g5" USING btree (
"hotel_id" "pg_catalog"."int2_ops" ASC NULLS LAST,
"room_id" COLLATE "pg_catalog"."default" "pg_catalog"."text_ops" ASC NULLS LAST,
"ts_ms" "pg_catalog"."int8_ops" DESC NULLS FIRST
);
CREATE INDEX "idx_hb_g5_ts_ms" ON "heartbeat"."heartbeat_events_g5" USING btree (
"ts_ms" "pg_catalog"."int8_ops" DESC NULLS FIRST
);
-- ----------------------------
-- Primary Key structure for table heartbeat_events_g5
-- ----------------------------
ALTER TABLE "heartbeat"."heartbeat_events_g5" ADD CONSTRAINT "heartbeat_events_g5_pkey" PRIMARY KEY ("ts_ms", "guid");