# BLS RCU Action Server 开发文档

## 1. 项目概述
本项目旨在构建一个后端服务，负责从 Kafka 接收 RCU（客房控制单元）的通讯日志，解析数据结构，并将其持久化存储到 PostgreSQL 数据库中。

核心目标是将不同类型的通讯协议数据（0x36 上报、0x0F 下发、ACK）统一存储，并针对不定长数据结构采用 JSON 格式进行灵活保存。

## 2. 系统架构
**数据流向**: `MCU/Server` (产生数据) -> `Kafka` (消息队列) -> `Action Server` (消费 & 解析) -> `PostgreSQL` (存储)

- **Kafka Topic**: `blwlog4Nodejs-rcu-action-topic` (分区数: 6)
- **数据库**: PostgreSQL

## 3. 数据库设计

数据库名：`bls_rcu_action`
模式名: `rcu_action`

### 3.1 表结构设计
表名: `rcu_action_events`

| 字段名 | 类型 | 说明 | 备注 |
| :--- | :--- | :--- | :--- |
| **guid** | VARCHAR(32) | 主键 (Key2) | 32位无符号UUID |
| **ts_ms** | BIGINT | 日志产生时间 (Key1) | **必填** (L49) |
| **write_ts_ms** | BIGINT | 入库时间 | **必填** (L50) |
| **hotel_id** | INTEGER | 酒店ID | **必填** (L51) Index |
| **room_id** | VARCHAR(32) | 房间ID | **必填** (L52) Index |
| **device_id** | VARCHAR(32) | 设备ID | **必填** (新增) Index |
| **direction** | VARCHAR(10) | 数据方向 | **必填** (L53) "上报"/"下发" Index |
| **cmd_word** | VARCHAR(10) | 命令字 | **必填** (L54) 如 "0x36", "0x0F" Index |
| **frame_id** | INTEGER | 通讯帧号 | **必填** (L55) 用于串联命令与状态 |
| **udp_raw** | TEXT | UDP消息原文 | **必填** (L56) base64字符串；当前若上游仍发送十六进制字符串，则后端会在入库前临时转换为base64，后续会取消该自动转换机制 |
| **action_type** | VARCHAR(20) | 记录行为类型 | **必填** (L57) Index |
| **sys_lock_status** | SMALLINT | 系统锁状态 | (L59) 可空 |
| **report_count** | SMALLINT | 本次上报数量 | (L60) 可空 |
| **dev_type** | SMALLINT | 设备类型 | (L61) 可空 (统一字段) |
| **dev_addr** | SMALLINT | 设备地址 | (L62) 可空 (统一字段) |
| **dev_loop** | INTEGER | 设备回路 | (L63) 可空 (统一字段) |
| **dev_data** | INTEGER | 设备状态 | (L64) 可空 (0x36状态) |
| **fault_count** | SMALLINT | 本次故障数量 | (L65) 可空 |
| **error_type** | SMALLINT | 故障类型 | (L69) 可空 (0x36故障) |
| **error_data** | SMALLINT | 故障内容 | (L70) 可空 (0x36故障) |
| **type_l** | SMALLINT | 执行方式 | 可空 (0x0F下发) |
| **type_h** | SMALLINT | 执行内容 | 可空 (0x0F下发) |
| **details** | JSONB | 业务详情数据 | 存储不定长设备列表、故障信息等 |
| **extra** | JSONB | 扩展信息 | 存储上游传入的extra扩展字段；如未提供则为空对象 |

**主键定义**: `(ts_ms, guid)`
**索引定义**: 备注带index的字段为需要索引的字段，用于提高查询效率。

### 3.2 字典定义
**Action Type (记录行为类型)**:
- 枚举值：（ACK和下发控制是0x0F的特殊情况，用户操作和设备回路状态是0x36的枚举值）
    - ACK：ACK是0x0F的上报独有的，所以如果0F且Direction为上报，就标记为ACK
    - 下发控制：0x0F的Direction为下发指令，记录为下发控制
    - 用户操作：0x36上报 的开关、温控器等客户操作设备产生的，属于用户操作
    - 设备回路状态：0x36上报 的灯光、继电器回路等变化等受控设备，属于设备回路状态
        - 用户操作和设备回路状态的具体区分表（根据本行数据的dev_type来区分），注意，这张表是根据dev_type来区分的，所以dev_type不能改变，否则会导致数据错误，另外这个表要写入env配置文件，以数组形式保存，随时可以更改：
            |dev_type|名称|描述|Action Type|
            |---|---|---|---|
            |0|Dev_Host_Invalid|无效设备（也可以被认为是场景）|无效|
            |1|Dev_Host_HVout|强电继电器（输出状态）|设备回路状态|
            |2|Dev_Host_LVinput|弱电输入（输入状态）|用户操作|
            |3|Dev_Host_LVoutput|弱电输出（输出状态）|设备回路状态|
            |4|Dev_Host_Service|服务信息|设备回路状态|
            |5|Dev_NodeCurtain|干节点窗帘|设备回路状态|
            |6|DEV_RS485_SWT|开关|用户操作|
            |7|DEV_RS485_TEMP|空调|用户操作|
            |8|DEV_RS485_INFRARED|红外感应|用户操作|
            |9|DEV_RS485_AirDetect|空气质量检测设备|设备回路状态|
            |10|DEV_RS485_CARD|插卡取电|用户操作|
            |11|DEV_RS485_HEATER|地暖|用户操作|
            |12|Dev_RCU_NET|RCU 设备网络 - 没使用||
            |13|DEV_RS485_CURTAIN|窗帘|设备回路状态|
            |14|DEV_RS485_RELAY|继电器|设备回路状态|
            |15|DEV_RS485_IR_SEND|红外发送|设备回路状态|
            |16|DEV_RS485_DIMMING|调光驱动|设备回路状态|
            |17|DEV_RS485_TRAIC|可控硅调光（可控硅状态）|设备回路状态|
            |18|DEV_RS485_STRIP|灯带（灯带状态） --2025-11-24 取消|无效|
            |19|DEV_RS485_CoreCtrl|中控|无效|
            |20|DEV_RS485_WxLock|微信锁 （福 瑞狗的蓝牙锁 默认 0 地址）|无效|
            |21|DEV_RS485_MUSIC|背景音乐（背景音乐状态）|设备回路状态|
            |22|DEV_NET_ROOMSTATE|房态下发|无效|
            |23|Dev_Host_PWMLight|主机本地 调光|无效|
            |24|DEV_RS485_PWM|485PWM 调光（ PWM 调光状态）|无效|
            |25|DEV_PB_LED|总线调光（ PBLED 调光状态） - 没使用 -|无效|
            |26|DEV_RCU_POWER|RCU 电源|无效|
            |27|DEV_RS485_A9_IO_SWT|A9IO 开关|用户操作|
            |28|DEV_RS485_A9_IO_EXP|A9IO 扩展|设备回路状态|
            |29|DEV_RS485_A9_IO_POWER|A9IO 电源|设备回路状态|
            |30|DEV_RS485_RFGatewayCycle|无线网关轮询（用于轮询控制轮询设备；给无线网关下发配置和询问网关状态）|无效|
            |31|DEV_RS485_RFGatewayHost|无线网关主动（用于主动控制主动设备）|无效|
            |32|DEV_RS485_RFGatewayDoor|无线门磁|用户操作|
            |33|DEV_RS485_AirReveal|空气参数显示设备|设备回路状态|
            |34|DEV_RS485_RFGatewayRelayPir|无线继电器红外|设备回路状态|
            |35|Dev_Host_TimeCtrl|时间同步|设备回路状态|
            |36|Dev_Rs458_MonitorCtrl|监控控制|无效|
            |37|Dev_Rs458_RotaryCtrl|旋钮开关控制|用户操作|
            |38|Dev_BUS_C5IO|CSIO - 类型|设备回路状态|
            |39|Dev_RS485_CardState|插卡状态虚拟设备|设备回路状态|
            |40|DEV_RS485_FreshAir|485 新风设备|用户操作|
            |41|DEV_RS485_FaceMach|485 人脸机|用户操作|
            |42|DEV_Center_Control|中控|无效|
            |43|DEV_Domain_Control|域控|无效|
            |44|DEV_RS485_LCD|LCD|设备回路状态|
            |45|DEV_Virtual_NoCard|无卡断电 --2025-11-24 取消|无效|
            |46|DEV_Virtual_Card|无卡取电 2|用户操作|
            |47|DEV_Virtual_Time|虚拟时间设备|设备回路状态|
            |48|Dev_Rs485_PB20|PLC 总控|设备回路状态|
            |49|Dev_Rs485_PB20_LD|PLC 设备 - 恒流调光设备|设备回路状态|
            |50|Dev_Rs485_PB20_LS|PLC 设备 - 恒压调光设备|设备回路状态|
            |51|Dev_Rs485_PB20_Relay|PLC 设备 - 继电器设备|设备回路状态|
            |52|DEV_Virtual_ColorTemp|色温调节功能|设备回路状态|
            |53|Dev_485_BLE_Music|蓝牙音频|设备回路状态|
            |54|DEV_Carbon_Saved|碳达人|用户操作|
            |55|Dev_Scene_Restore|场景还原|用户操作|
            |56|Dev_Virtual_GlobalSet|全局设置|设备回路状态|
            |57|Dev_Energy_Monitor|能耗检测|设备回路状态|
            |241|Dev_BUS_C5IO|CSIO - 类型|设备回路状态|

**Direction (方向)**:
- `"上报"`: Upload
- `"下发"`: Download

## 4. 数据解析与存储映射

### 4.1 0x36 上报数据 (设备状态/故障)
*   **命令字**: "0x36"
*   **拆分逻辑**: 根据 `project.md` 说明，一条 UDP 可能包含多个设备状态，需拆分为多条记录入库，每条记录填充 `dev_type` 等字段。同时将完整的不定长列表存入 `details` 以便追溯。
*   **Action Type**: 4 (设备回路状态)

**Mapping**:
- `sys_lock_status` -> P0
- `report_count` -> P7
- `dev_type`, `dev_addr`... -> 从 P8~P13 循环解析，每组生成一条 DB 记录
- `details`: `{ "all_devices": [...], "all_faults": [...] }`
- `extra`: `{ "raw_hex": "..." }`

### 4.2 0x0F 下发数据 (控制指令)
*   **命令字**: "0x0F"
*   **Action Type**: 2 (下发控制)
*   **存储逻辑**: 主要是控制指令，通常作为单条记录存储。若包含多个设备控制，可选择存第一条到字段，或仅存入 JSON。根据 "0x0F不定长存为JSON" 的需求，主要依赖 `details` 字段。

**Mapping**:
- `details`: `{ "control_params": [ ... ] }`
- `extra`: `{ "raw_hex": "..." }`

### 4.3 0x0F 上报数据 (ACK)
*   **命令字**: "0x0F"
*   **Action Type**: "0FACK" (ACK)

**Mapping**:
- `details`: `{ "ack_code": "0x00" }`
- `extra`: `{ "raw_hex": "..." }`
