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
146 lines (129 loc) • 3.85 kB
JavaScript
/**
* 亖米(Symi)协议 - 面板设备处理
* 支持屏显面板等设备,这是一个新的设备类型
*/
/**
* 缓冲区数据转对象
* @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 &&
(protocolData.devAddress * 4 - 4 + protocolData.devChannel) === obj.address) {
return protocolData;
} else {
return null;
}
}
/**
* 协议解析
* @param {Buffer} data 15字节数据帧
*/
function _protocol(data) {
if (!data || data.length < 15) return null;
let obj = {};
// 解析数据帧结构
obj.localAddress = data[1]; // 本地地址
obj.type = _getTypeFromByte(data[2]); // 消息类型
obj.devAddress = data[6]; // 设备地址
obj.devChannel = data[7]; // 设备通道
obj.info = data[12]; // 状态信息
obj.code = data[11]; // 代码
// 只处理set类型的消息
if (obj.type !== 'set') return null;
// 面板设备可能有多种状态
obj.val = obj.info === 1 ? 'on' : 'off';
obj.deviceType = 'panel';
// 面板设备可能包含额外的信息
obj.panelData = {
address: obj.devAddress,
channel: obj.devChannel,
code: obj.code,
rawInfo: obj.info
};
return obj;
}
/**
* 根据字节值获取消息类型
* @param {number} byte
*/
function _getTypeFromByte(byte) {
switch (byte) {
case 0x01:
return 'response';
case 0x02:
return 'query';
case 0x03:
return 'set';
case 0x04:
return 'report';
default:
return 'unknown';
}
}
/**
* 根据消息类型获取字节值
* @param {string} type
*/
function _getByteFromType(type) {
switch (type) {
case 'response':
return 0x01;
case 'query':
return 0x02;
case 'set':
return 0x03;
case 'report':
return 0x04;
default:
return 0x04; // 默认为report
}
}
/**
* 对象转缓冲区
* @param {object} obj HA状态对象
* @param {object} obj1 节点对象
*/
function obj2buf(obj, obj1) {
if (obj1.entity_id === obj.entity_id) {
// 构建状态反馈数据帧
let buf = [
0x00, // 帧头将由主处理器设置
obj1.uid, // 本地地址
_getByteFromType('report'), // 消息类型:report
15, // 数据长度
1, // 固定值
0, // 保留
2, // 设备地址(根据channel计算)
1, // 设备通道(根据channel计算)
0, // 保留
0, // 保留
0, // 保留
0, // 代码
obj.state === 'on' ? 1 : 0, // 状态信息
0, // CRC将由主处理器计算
0 // 帧尾将由主处理器设置
];
// 根据按键地址计算设备地址和通道
let channel = obj1.address || 1;
if (channel >= 1 && channel <= 8) {
buf[6] = 1; // 设备类型1
buf[7] = channel; // 直接使用按键编号作为通道
}
// 面板设备可能需要特殊的状态处理
if (obj.attributes && obj.attributes.brightness) {
// 如果有亮度属性,可以在这里处理
buf[11] = Math.round(obj.attributes.brightness / 255 * 100); // 转换为百分比
}
return buf;
} else {
return null;
}
}
module.exports = {
buf2obj,
obj2buf
};