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

278 lines (247 loc) 7.48 kB
/** * 亖米(Symi)协议 - 空调设备处理 * 设备类型:0x02 * 支持操作类型: * 0x01: 电源控制 * 0x02: 模式控制 * 0x03: 风速控制 * 0x04: 温度控制 */ const DEVICE_TYPE = 0x02; // 空调设备类型 // 操作类型定义 const OPERATION_TYPES = { POWER: 0x01, // 电源控制 MODE: 0x02, // 模式控制 FAN_SPEED: 0x03, // 风速控制 TEMPERATURE: 0x04 // 温度控制 }; // 空调模式定义 const HVAC_MODES = { AUTO: 0x00, // 自动 COOL: 0x01, // 制冷 DRY: 0x02, // 抽湿 FAN_ONLY: 0x03, // 送风 HEAT: 0x04 // 制热 }; // 风速定义 const FAN_SPEEDS = { AUTO: 0x00, // 自动 LOW: 0x01, // 低风速 MEDIUM: 0x02, // 中风速 HIGH: 0x03 // 高风速 }; /** * 缓冲区数据转对象 * @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 >= 19) { obj.type = 'query_response'; obj.deviceTypeName = 'climate'; obj.powerState = data[12] === 1 ? 'on' : 'off'; obj.mode = _getModeFromByte(data[13]); obj.fanSpeed = _getFanSpeedFromByte(data[14]); obj.targetTemp = data[15]; obj.currentTemp = data[16]; obj.val = { state: obj.powerState, hvac_mode: obj.mode, fan_mode: obj.fanSpeed, 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 ? 'on' : 'off'; break; case OPERATION_TYPES.MODE: // 模式控制 obj.action = 'mode'; obj.val = _getModeFromByte(data[12]); break; case OPERATION_TYPES.FAN_SPEED: // 风速控制 obj.action = 'fan_speed'; obj.val = _getFanSpeedFromByte(data[12]); break; case OPERATION_TYPES.TEMPERATURE: // 温度控制 obj.action = 'temperature'; obj.val = data[12]; // 温度值 break; default: return null; } return obj; } /** * 根据字节值获取模式 * @param {number} byte */ function _getModeFromByte(byte) { switch (byte) { case HVAC_MODES.AUTO: return 'auto'; case HVAC_MODES.COOL: return 'cool'; case HVAC_MODES.DRY: return 'dry'; case HVAC_MODES.FAN_ONLY: return 'fan_only'; case HVAC_MODES.HEAT: return 'heat'; default: return 'auto'; } } /** * 根据模式获取字节值 * @param {string} mode */ function _getByteFromMode(mode) { switch (mode) { case 'auto': return HVAC_MODES.AUTO; case 'cool': return HVAC_MODES.COOL; case 'dry': return HVAC_MODES.DRY; case 'fan_only': return HVAC_MODES.FAN_ONLY; case 'heat': return HVAC_MODES.HEAT; default: return HVAC_MODES.AUTO; } } /** * 根据字节值获取风速 * @param {number} byte */ function _getFanSpeedFromByte(byte) { switch (byte) { case FAN_SPEEDS.AUTO: return 'auto'; case FAN_SPEEDS.LOW: return 'low'; case FAN_SPEEDS.MEDIUM: return 'medium'; case FAN_SPEEDS.HIGH: return 'high'; default: return 'auto'; } } /** * 根据风速获取字节值 * @param {string} fanSpeed */ function _getByteFromFanSpeed(fanSpeed) { switch (fanSpeed) { case 'auto': return FAN_SPEEDS.AUTO; case 'low': return FAN_SPEEDS.LOW; case 'medium': return FAN_SPEEDS.MEDIUM; case 'high': return FAN_SPEEDS.HIGH; default: return FAN_SPEEDS.AUTO; } } /** * 对象转缓冲区 * @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 === 'on' || obj.state === 'off') { // 电源控制 frame.operationCode = OPERATION_TYPES.POWER; frame.operationData[0] = obj.state === 'on' ? 1 : 0; } else if (obj.attributes) { if (obj.attributes.hvac_mode !== undefined) { // 模式控制 frame.operationCode = OPERATION_TYPES.MODE; frame.operationData[0] = _getByteFromMode(obj.attributes.hvac_mode); } else if (obj.attributes.fan_mode !== undefined) { // 风速控制 frame.operationCode = OPERATION_TYPES.FAN_SPEED; frame.operationData[0] = _getByteFromFanSpeed(obj.attributes.fan_mode); } else if (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, HVAC_MODES, FAN_SPEEDS };