feat(processor): 添加循环名称自动生成的配置开关

新增环境变量 ENABLE_LOOP_NAME_AUTO_GENERATION 用于控制当缓存未命中时是否自动生成循环名称。当设置为 false 时,系统将不再生成 [类型-地址-回路] 格式的备用名称,而是直接返回 null。更新了配置文件、处理器逻辑并添加了相应的单元测试。
This commit is contained in:
2026-02-03 09:26:01 +08:00
parent 4e0f5213db
commit 339db6f95f
9 changed files with 112 additions and 5 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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'
};

View File

@@ -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

View File

@@ -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();
});
});

View File

@@ -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]');
});
});