UNPKG

node-red-contrib-symi

Version:

Node-RED nodes for smart home device communication with Home Assistant integration, supporting HassKit, Clowire, Alive, LF and complete Symi protocols

150 lines (127 loc) 4.17 kB
/** * 亖米(Symi)协议 - 地暖设备处理 * 设备类型:0x05 * 支持操作类型: * 0x01: 电源控制 * 0x02: 温度控制 */ const DEVICE_TYPE = 0x05; // 地暖设备类型 // 操作类型定义 const OPERATION_TYPES = { POWER: 0x01, // 电源控制 TEMPERATURE: 0x02 // 温度控制 }; /** * 缓冲区数据转对象 * @param {Buffer} data 命令缓冲 * @param {object} obj 节点对象 */ function buf2obj(data, obj) { const protocolData = _protocol(data); if (!protocolData) return null; protocolData.uid = obj.entity_id; // 检查设备匹配 if (obj.uid === protocolData.localAddress && obj.address === protocolData.deviceAddress && obj.channel === protocolData.deviceChannel) { return protocolData; } else { return null; } } /** * 协议解析 * @param {Buffer} data 数据帧 */ function _protocol(data) { if (!data || data.length < 15) return null; let obj = {}; // 解析数据帧结构 obj.localAddress = data[1]; // 本地地址 obj.dataType = data[2]; // 数据类型 obj.dataLength = data[3]; // 数据长度 obj.deviceType = data[4]; // 设备类型 obj.brandId = data[5]; // 品牌ID obj.deviceAddress = data[6]; // 设备地址 obj.deviceChannel = data[7]; // 设备通道 obj.roomNumber = data[8]; // 房间号 obj.roomType = data[9]; // 房间类型 obj.roomId = data[10]; // 房间ID obj.operationCode = data[11]; // 操作码 // 检查设备类型 if (obj.deviceType !== DEVICE_TYPE) return null; // 处理查询响应(包含完整状态信息) if (obj.dataType === 0x01 && data.length >= 17) { obj.type = 'query_response'; obj.deviceTypeName = 'climate'; obj.powerState = data[12] === 1 ? 'heat' : 'off'; obj.targetTemp = data[13]; obj.currentTemp = data[14]; obj.val = { state: obj.powerState, hvac_mode: obj.powerState, temperature: obj.targetTemp, current_temperature: obj.currentTemp }; return obj; } // 只处理设置和上报类型的消息 if (obj.dataType !== 0x03 && obj.dataType !== 0x04) return null; obj.type = obj.dataType === 0x03 ? 'set' : 'report'; obj.deviceTypeName = 'climate'; // 根据操作码解析具体操作 switch (obj.operationCode) { case OPERATION_TYPES.POWER: // 电源控制 obj.action = 'power'; obj.val = data[12] === 1 ? 'heat' : 'off'; break; case OPERATION_TYPES.TEMPERATURE: // 温度控制 obj.action = 'temperature'; obj.val = data[12]; // 温度值 break; default: return null; } return obj; } /** * 对象转缓冲区 * @param {object} obj HA状态对象 * @param {object} obj1 节点对象 */ function obj2buf(obj, obj1) { if (obj1.entity_id !== obj.entity_id) return null; // 构建基础帧结构 let frame = { localAddress: obj1.uid, dataType: 0x04, // 上报 deviceType: DEVICE_TYPE, brandId: 0x00, deviceAddress: obj1.address, deviceChannel: obj1.channel || 0x00, roomNumber: 0x00, roomType: 0x00, roomId: 0x00, operationCode: OPERATION_TYPES.POWER, operationData: Buffer.alloc(1) }; // 根据HA状态设置操作信息 if (obj.state === 'heat' || obj.state === 'off') { // 电源控制 frame.operationCode = OPERATION_TYPES.POWER; frame.operationData[0] = obj.state === 'heat' ? 1 : 0; } else if (obj.attributes && obj.attributes.temperature !== undefined) { // 温度控制 frame.operationCode = OPERATION_TYPES.TEMPERATURE; frame.operationData[0] = Math.round(obj.attributes.temperature); } return frame; } module.exports = { buf2obj, obj2buf, DEVICE_TYPE, OPERATION_TYPES };