feat: 添加回路名称字段并实现元数据缓存查询

在 RCU 事件处理中新增回路名称(loop_name)字段,用于标识具体设备回路。
- 在 rcu_action_events 表中添加 loop_name 字段
- 新增项目元数据缓存模块,每日从 temporary_project 表刷新房间与回路信息
- 处理消息时,根据 device_id、dev_addr 等字段查询缓存获取回路名称
- 若缓存未命中,则根据设备类型规则生成兜底名称
- 更新环境变量、文档及测试用例以适配新功能
This commit is contained in:
2026-02-02 19:43:49 +08:00
parent 0e6c5c3cc3
commit 4e0f5213db
12 changed files with 660 additions and 117 deletions

View File

@@ -0,0 +1,113 @@
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const readmePath = path.resolve(__dirname, '../../docs/readme.md');
const envPath = path.resolve(__dirname, '../.env');
const processorPath = path.resolve(__dirname, '../src/processor/index.js');
try {
const readmeContent = fs.readFileSync(readmePath, 'utf8');
const lines = readmeContent.split('\n');
const rules = [];
let inTable = false;
for (const line of lines) {
const trimmed = line.trim();
// Detect start of table (approximately)
if (trimmed.includes('|dev_type|名称|描述|Action Type|')) {
inTable = true;
continue;
}
// Skip separator line
if (inTable && trimmed.includes('|---|')) {
continue;
}
// Process table rows
if (inTable && trimmed.startsWith('|') && trimmed.endsWith('|')) {
const parts = trimmed.split('|').map(p => p.trim());
// parts[0] is empty, parts[1] is dev_type, parts[2] is name, parts[3] is description, parts[4] is action_type
if (parts.length >= 5) {
const devTypeStr = parts[1];
const description = parts[3];
const actionType = parts[4];
if (!devTypeStr || isNaN(parseInt(devTypeStr))) {
continue;
}
const devType = parseInt(devTypeStr, 10);
rules.push({
dev_type: devType,
name: description, // Use description as name per user request
action_type: actionType
});
}
} else if (inTable && trimmed === '') {
// Empty line might mean end of table, but let's be loose
} else if (inTable && !trimmed.startsWith('|')) {
// End of table
inTable = false;
}
}
// Sort by dev_type
rules.sort((a, b) => a.dev_type - b.dev_type);
console.log(`Found ${rules.length} rules.`);
// 1. Generate JSON for .env
const envJson = JSON.stringify(rules);
// Read existing .env
let envContent = fs.readFileSync(envPath, 'utf8');
const envKey = 'ACTION_TYPE_DEV_TYPE_RULES';
// Replace or Append
const envLine = `${envKey}='${envJson}'`;
const regex = new RegExp(`^${envKey}=.*`, 'm');
if (regex.test(envContent)) {
envContent = envContent.replace(regex, envLine);
} else {
envContent += `\n${envLine}`;
}
fs.writeFileSync(envPath, envContent, 'utf8');
console.log('Updated .env');
// 2. Generate Object for src/processor/index.js
// We need to construct the object string manually to match the code style
const mapLines = rules.map(r => {
// Escape single quotes in name if present
const safeName = r.name.replace(/'/g, "\\'");
return ` ${r.dev_type}: { name: '${safeName}', action: '${r.action_type}' }`;
});
const mapString = `const defaultDevTypeActionMap = {\n${mapLines.join(',\n')}\n};`;
let processorContent = fs.readFileSync(processorPath, 'utf8');
// Regex to replace the object.
const processorRegex = /const defaultDevTypeActionMap = \{[\s\S]*?\};/m;
if (processorRegex.test(processorContent)) {
processorContent = processorContent.replace(processorRegex, mapString);
fs.writeFileSync(processorPath, processorContent, 'utf8');
console.log('Updated src/processor/index.js');
} else {
console.error('Could not find defaultDevTypeActionMap in src/processor/index.js');
}
} catch (err) {
console.error('Error:', err);
}

View File

@@ -27,12 +27,16 @@ CREATE TABLE IF NOT EXISTS rcu_action.rcu_action_events (
type_h SMALLINT,
details JSONB,
extra JSONB,
loop_name VARCHAR(255),
PRIMARY KEY (ts_ms, guid)
) PARTITION BY RANGE (ts_ms);
ALTER TABLE rcu_action.rcu_action_events
ADD COLUMN IF NOT EXISTS device_id VARCHAR(32) NOT NULL DEFAULT '';
ALTER TABLE rcu_action.rcu_action_events
ADD COLUMN IF NOT EXISTS loop_name VARCHAR(255);
-- Indexes for performance
CREATE INDEX IF NOT EXISTS idx_rcu_action_hotel_id ON rcu_action.rcu_action_events (hotel_id);
CREATE INDEX IF NOT EXISTS idx_rcu_action_room_id ON rcu_action.rcu_action_events (room_id);