From 339db6f95f310ac5a084af6332ac8f3ebedb6157 Mon Sep 17 00:00:00 2001 From: XuJiacheng Date: Tue, 3 Feb 2026 09:26:01 +0800 Subject: [PATCH] =?UTF-8?q?feat(processor):=20=E6=B7=BB=E5=8A=A0=E5=BE=AA?= =?UTF-8?q?=E7=8E=AF=E5=90=8D=E7=A7=B0=E8=87=AA=E5=8A=A8=E7=94=9F=E6=88=90?= =?UTF-8?q?=E7=9A=84=E9=85=8D=E7=BD=AE=E5=BC=80=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增环境变量 ENABLE_LOOP_NAME_AUTO_GENERATION 用于控制当缓存未命中时是否自动生成循环名称。当设置为 false 时,系统将不再生成 [类型-地址-回路] 格式的备用名称,而是直接返回 null。更新了配置文件、处理器逻辑并添加了相应的单元测试。 --- bls-rcu-action-backend/.env | 2 + bls-rcu-action-backend/.env.example | 2 + bls-rcu-action-backend/src/config/config.js | 3 +- bls-rcu-action-backend/src/processor/index.js | 8 +++- .../tests/feature_flag_loop_name.test.js | 47 +++++++++++++++++++ .../tests/processor.test.js | 4 +- .../feature-loop-name-enrichment.md | 2 +- .../feature-toggle-loop-name-generation.md | 22 +++++++++ .../2026-02-03-loop-name-features/summary.md | 27 +++++++++++ 9 files changed, 112 insertions(+), 5 deletions(-) create mode 100644 bls-rcu-action-backend/tests/feature_flag_loop_name.test.js rename openspec/changes/{ => archive/2026-02-03-loop-name-features}/feature-loop-name-enrichment.md (98%) create mode 100644 openspec/changes/archive/2026-02-03-loop-name-features/feature-toggle-loop-name-generation.md create mode 100644 openspec/changes/archive/2026-02-03-loop-name-features/summary.md diff --git a/bls-rcu-action-backend/.env b/bls-rcu-action-backend/.env index c676618..9d0ed66 100644 --- a/bls-rcu-action-backend/.env +++ b/bls-rcu-action-backend/.env @@ -34,3 +34,5 @@ REDIS_DB=15 REDIS_CONNECT_TIMEOUT_MS=5000 ACTION_TYPE_DEV_TYPE_RULES='[{"dev_type":0,"name":"无效设备(也可以被认为是场景)","action_type":"无效"},{"dev_type":1,"name":"强电继电器(输出状态)","action_type":"设备回路状态"},{"dev_type":2,"name":"弱电输入(输入状态)","action_type":"用户操作"},{"dev_type":3,"name":"弱电输出(输出状态)","action_type":"设备回路状态"},{"dev_type":4,"name":"服务信息","action_type":"设备回路状态"},{"dev_type":5,"name":"干节点窗帘","action_type":"设备回路状态"},{"dev_type":6,"name":"开关","action_type":"用户操作"},{"dev_type":7,"name":"空调","action_type":"用户操作"},{"dev_type":8,"name":"红外感应","action_type":"用户操作"},{"dev_type":9,"name":"空气质量检测设备","action_type":"设备回路状态"},{"dev_type":10,"name":"插卡取电","action_type":"用户操作"},{"dev_type":11,"name":"地暖","action_type":"用户操作"},{"dev_type":12,"name":"RCU 设备网络 - 没使用","action_type":""},{"dev_type":13,"name":"窗帘","action_type":"设备回路状态"},{"dev_type":14,"name":"继电器","action_type":"设备回路状态"},{"dev_type":15,"name":"红外发送","action_type":"设备回路状态"},{"dev_type":16,"name":"调光驱动","action_type":"设备回路状态"},{"dev_type":17,"name":"可控硅调光(可控硅状态)","action_type":"设备回路状态"},{"dev_type":18,"name":"灯带(灯带状态) --2025-11-24 取消","action_type":"无效"},{"dev_type":19,"name":"中控","action_type":"无效"},{"dev_type":20,"name":"微信锁 (福 瑞狗的蓝牙锁 默认 0 地址)","action_type":"无效"},{"dev_type":21,"name":"背景音乐(背景音乐状态)","action_type":"设备回路状态"},{"dev_type":22,"name":"房态下发","action_type":"无效"},{"dev_type":23,"name":"主机本地 调光","action_type":"无效"},{"dev_type":24,"name":"485PWM 调光( PWM 调光状态)","action_type":"无效"},{"dev_type":25,"name":"总线调光( PBLED 调光状态) - 没使用 -","action_type":"无效"},{"dev_type":26,"name":"RCU 电源","action_type":"无效"},{"dev_type":27,"name":"A9IO 开关","action_type":"用户操作"},{"dev_type":28,"name":"A9IO 扩展","action_type":"设备回路状态"},{"dev_type":29,"name":"A9IO 电源","action_type":"设备回路状态"},{"dev_type":30,"name":"无线网关轮询(用于轮询控制轮询设备;给无线网关下发配置和询问网关状态)","action_type":"无效"},{"dev_type":31,"name":"无线网关主动(用于主动控制主动设备)","action_type":"无效"},{"dev_type":32,"name":"无线门磁","action_type":"用户操作"},{"dev_type":33,"name":"空气参数显示设备","action_type":"设备回路状态"},{"dev_type":34,"name":"无线继电器红外","action_type":"设备回路状态"},{"dev_type":35,"name":"时间同步","action_type":"设备回路状态"},{"dev_type":36,"name":"监控控制","action_type":"无效"},{"dev_type":37,"name":"旋钮开关控制","action_type":"用户操作"},{"dev_type":38,"name":"CSIO - 类型","action_type":"设备回路状态"},{"dev_type":39,"name":"插卡状态虚拟设备","action_type":"设备回路状态"},{"dev_type":40,"name":"485 新风设备","action_type":"用户操作"},{"dev_type":41,"name":"485 人脸机","action_type":"用户操作"},{"dev_type":42,"name":"中控","action_type":"无效"},{"dev_type":43,"name":"域控","action_type":"无效"},{"dev_type":44,"name":"LCD","action_type":"设备回路状态"},{"dev_type":45,"name":"无卡断电 --2025-11-24 取消","action_type":"无效"},{"dev_type":46,"name":"无卡取电 2","action_type":"用户操作"},{"dev_type":47,"name":"虚拟时间设备","action_type":"设备回路状态"},{"dev_type":48,"name":"PLC 总控","action_type":"设备回路状态"},{"dev_type":49,"name":"PLC 设备 - 恒流调光设备","action_type":"设备回路状态"},{"dev_type":50,"name":"PLC 设备 - 恒压调光设备","action_type":"设备回路状态"},{"dev_type":51,"name":"PLC 设备 - 继电器设备","action_type":"设备回路状态"},{"dev_type":52,"name":"色温调节功能","action_type":"设备回路状态"},{"dev_type":53,"name":"蓝牙音频","action_type":"设备回路状态"},{"dev_type":54,"name":"碳达人","action_type":"用户操作"},{"dev_type":55,"name":"场景还原","action_type":"用户操作"},{"dev_type":56,"name":"全局设置","action_type":"设备回路状态"},{"dev_type":57,"name":"能耗检测","action_type":"设备回路状态"},{"dev_type":241,"name":"CSIO - 类型","action_type":"设备回路状态"}]' + +ENABLE_LOOP_NAME_AUTO_GENERATION=false diff --git a/bls-rcu-action-backend/.env.example b/bls-rcu-action-backend/.env.example index 72c0dfb..3eff700 100644 --- a/bls-rcu-action-backend/.env.example +++ b/bls-rcu-action-backend/.env.example @@ -27,3 +27,5 @@ REDIS_PASSWORD= REDIS_DB=0 REDIS_PROJECT_NAME=my-project REDIS_API_BASE_URL=http://localhost:3000 + +ENABLE_LOOP_NAME_AUTO_GENERATION=true diff --git a/bls-rcu-action-backend/src/config/config.js b/bls-rcu-action-backend/src/config/config.js index f5c7acf..24a0a0e 100644 --- a/bls-rcu-action-backend/src/config/config.js +++ b/bls-rcu-action-backend/src/config/config.js @@ -52,5 +52,6 @@ export const config = { db: parseNumber(process.env.REDIS_DB, 0), projectName: process.env.REDIS_PROJECT_NAME || 'bls-rcu-action', apiBaseUrl: process.env.REDIS_API_BASE_URL || `http://localhost:${parseNumber(process.env.PORT, 3000)}` - } + }, + enableLoopNameAutoGeneration: process.env.ENABLE_LOOP_NAME_AUTO_GENERATION === 'true' }; diff --git a/bls-rcu-action-backend/src/processor/index.js b/bls-rcu-action-backend/src/processor/index.js index f7c6928..5800ac8 100644 --- a/bls-rcu-action-backend/src/processor/index.js +++ b/bls-rcu-action-backend/src/processor/index.js @@ -1,6 +1,7 @@ import { createGuid } from '../utils/uuid.js'; import { kafkaPayloadSchema } from '../schema/kafkaPayload.js'; import projectMetadata from '../cache/projectMetadata.js'; +import { config } from '../config/config.js'; const normalizeDirection = (value) => { if (!value) return null; @@ -241,7 +242,12 @@ export const buildRowsFromPayload = (rawPayload) => { const cachedName = projectMetadata.getLoopName(deviceId, devType, devAddr, devLoop); if (cachedName) return cachedName; - // 2. Fallback: [TypeName-Addr-Loop] + // 2. Check config for auto-generation + if (!config.enableLoopNameAutoGeneration) { + return null; + } + + // 3. Fallback: [TypeName-Addr-Loop] const typeName = getDevTypeName(devType); if (!typeName) return null; // Should have a name if devType is valid diff --git a/bls-rcu-action-backend/tests/feature_flag_loop_name.test.js b/bls-rcu-action-backend/tests/feature_flag_loop_name.test.js new file mode 100644 index 0000000..d2df1b1 --- /dev/null +++ b/bls-rcu-action-backend/tests/feature_flag_loop_name.test.js @@ -0,0 +1,47 @@ +import { describe, it, expect, beforeEach, afterEach } from 'vitest'; +import { buildRowsFromPayload } from '../src/processor/index.js'; +import { config } from '../src/config/config.js'; + +describe('Feature Toggle: Loop Name Auto Generation', () => { + const basePayload = { + ts_ms: 1700000000000, + hotel_id: 1001, + room_id: '8001', + device_id: 'dev_001', + direction: '上报', + cmd_word: '0x36', + frame_id: 1, + udp_raw: '00', + sys_lock_status: 0, + report_count: 0, + fault_count: 0, + device_list: [ + { dev_type: 1, dev_addr: 10, dev_loop: 1, dev_data: 100 } + ] + }; + + let originalConfigValue; + + beforeEach(() => { + originalConfigValue = config.enableLoopNameAutoGeneration; + }); + + afterEach(() => { + config.enableLoopNameAutoGeneration = originalConfigValue; + }); + + it('should generate loop_name when flag is true', () => { + config.enableLoopNameAutoGeneration = true; + const rows = buildRowsFromPayload(basePayload); + // Expect format: [1强电继电器(输出状态)-10-1] + // The exact name depends on the map, but it should contain brackets and numbers + expect(rows[0].loop_name).toBeDefined(); + expect(rows[0].loop_name).toMatch(/^\[1.*-10-1\]$/); + }); + + it('should NOT generate loop_name when flag is false', () => { + config.enableLoopNameAutoGeneration = false; + const rows = buildRowsFromPayload(basePayload); + expect(rows[0].loop_name).toBeNull(); + }); +}); diff --git a/bls-rcu-action-backend/tests/processor.test.js b/bls-rcu-action-backend/tests/processor.test.js index 664c406..f094b9d 100644 --- a/bls-rcu-action-backend/tests/processor.test.js +++ b/bls-rcu-action-backend/tests/processor.test.js @@ -223,7 +223,7 @@ describe('Processor Logic', () => { const rows = buildRowsFromPayload(payload); expect(rows[0].loop_name).toBe('Main Chandelier'); - // dev_type 1 is 'Dev_Host_HVout' - expect(rows[1].loop_name).toBe('[1Dev_Host_HVout-10-2]'); + // dev_type 1 is '强电继电器(输出状态)' + expect(rows[1].loop_name).toBe('[1强电继电器(输出状态)-10-2]'); }); }); diff --git a/openspec/changes/feature-loop-name-enrichment.md b/openspec/changes/archive/2026-02-03-loop-name-features/feature-loop-name-enrichment.md similarity index 98% rename from openspec/changes/feature-loop-name-enrichment.md rename to openspec/changes/archive/2026-02-03-loop-name-features/feature-loop-name-enrichment.md index 2d7a390..15cbb43 100644 --- a/openspec/changes/feature-loop-name-enrichment.md +++ b/openspec/changes/archive/2026-02-03-loop-name-features/feature-loop-name-enrichment.md @@ -1,6 +1,6 @@ # Feature: Loop Name Enrichment -**Status**: Proposed +**Status**: Implemented **Date**: 2026-02-02 ## Summary diff --git a/openspec/changes/archive/2026-02-03-loop-name-features/feature-toggle-loop-name-generation.md b/openspec/changes/archive/2026-02-03-loop-name-features/feature-toggle-loop-name-generation.md new file mode 100644 index 0000000..696efc7 --- /dev/null +++ b/openspec/changes/archive/2026-02-03-loop-name-features/feature-toggle-loop-name-generation.md @@ -0,0 +1,22 @@ +# Feature: Feature Toggle Loop Name Generation + +**Status**: Implemented +**Date**: 2026-02-03 + +## Summary +Add a configuration switch to control the fallback behavior for `loop_name` generation. Currently, when cache lookup fails, the system auto-generates a name using the format `[Type-Addr-Loop]`. This change allows users to enable or disable this fallback behavior via an environment variable. + +## Requirements +1. **Configuration**: + - Add `ENABLE_LOOP_NAME_AUTO_GENERATION` to environment variables. + - Default behavior should match existing logic (enable generation) if not specified, but user requested explicit control. + - If `true`: Perform concatenation `[dev_type名称+'-'+dev_addr+'-'+dev_loop]`. + - If `false`: Do not generate name, leave `loop_name` as null (or whatever default is appropriate, likely null). + +2. **Processor Logic**: + - In `getLoopNameWithFallback`, check the configuration flag before applying the fallback generation logic. + +## Implementation Plan +1. **Config**: Update `src/config/config.js` to parse `ENABLE_LOOP_NAME_AUTO_GENERATION`. +2. **Env**: Update `.env` and `.env.example`. +3. **Processor**: Update `src/processor/index.js` to respect the flag. diff --git a/openspec/changes/archive/2026-02-03-loop-name-features/summary.md b/openspec/changes/archive/2026-02-03-loop-name-features/summary.md new file mode 100644 index 0000000..71eb82a --- /dev/null +++ b/openspec/changes/archive/2026-02-03-loop-name-features/summary.md @@ -0,0 +1,27 @@ +# Summary of Changes: Loop Name Features + +**Date**: 2026-02-03 +**Status**: Archived + +## Overview +This archive contains the specifications and proposals for the Loop Name Enrichment and Auto-Generation features. These features enhance the RCU Action Server by enriching event data with descriptive loop names derived from project metadata or fallback generation logic. + +## Included Changes + +### 1. [Feature: Loop Name Enrichment](./feature-loop-name-enrichment.md) +- **Goal**: Enrich `rcu_action_events` with `loop_name` by looking up cached metadata from `temporary_project` tables. +- **Key Components**: + - `ProjectMetadataCache`: Loads rooms and loops data daily. + - `loop_name` column added to `rcu_action_events` table. + - Processor logic updated to perform lookup. + +### 2. [Feature: Feature Toggle Loop Name Generation](./feature-toggle-loop-name-generation.md) +- **Goal**: Provide a configuration switch to control the fallback behavior when cache lookup fails. +- **Key Components**: + - `ENABLE_LOOP_NAME_AUTO_GENERATION` env var. + - Logic to generate `[Type-Addr-Loop]` format only if enabled. + - Default behavior is `true` (enabled). + +## Implementation Status +- All proposed features have been implemented and verified via unit tests. +- Configuration variables are documented in `.env.example`.