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
187 lines (164 loc) • 6.19 kB
JavaScript
/**
* 亖米(Symi)协议 - 灯光设备处理
* 设备类型:0x01
* 支持操作类型:
* 0x00: 单灯控制
* 0x02: 单色调光控制
* 0x03: 双色温调光控制
* 0x04: RGBW调光控制
* 0x05: 灯光多灯控制
*/
const DEVICE_TYPE = 0x01; // 灯光设备类型
// 操作类型定义
const OPERATION_TYPES = {
SINGLE_SWITCH: 0x00, // 单灯控制
SINGLE_DIM: 0x02, // 单色调光控制
DUAL_TEMP_DIM: 0x03, // 双色温调光控制
RGBW_DIM: 0x04, // RGBW调光控制
MULTI_LIGHT: 0x05 // 灯光多灯控制
};
/**
* 缓冲区数据转对象
* @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 !== 0x03 && obj.dataType !== 0x04) return null;
obj.type = obj.dataType === 0x03 ? 'set' : 'report';
obj.deviceTypeName = 'light';
// 根据操作码解析具体操作
switch (obj.operationCode) {
case OPERATION_TYPES.SINGLE_SWITCH:
// 单灯控制:操作信息为开关状态
obj.action = 'switch';
obj.val = data[12] === 1 ? 'on' : 'off';
break;
case OPERATION_TYPES.SINGLE_DIM:
// 单色调光:操作信息为亮度百分比
obj.action = 'brightness';
obj.val = data[12]; // 0-100
break;
case OPERATION_TYPES.DUAL_TEMP_DIM:
// 双色温调光:第一字节色温,第二字节亮度
obj.action = 'dual_temp';
obj.colorTemp = data[12]; // 色温 0-100
obj.brightness = data[13]; // 亮度 0-100
obj.val = {
color_temp: obj.colorTemp,
brightness: obj.brightness
};
break;
case OPERATION_TYPES.RGBW_DIM:
// RGBW调光:红、绿、蓝、白
obj.action = 'rgbw';
obj.red = data[12];
obj.green = data[13];
obj.blue = data[14];
obj.white = data[15];
obj.val = {
rgb_color: [obj.red * 255 / 100, obj.green * 255 / 100, obj.blue * 255 / 100],
brightness: obj.white * 255 / 100
};
break;
default:
// 默认作为开关处理
obj.action = 'switch';
obj.val = data[12] === 1 ? 'on' : 'off';
}
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.SINGLE_SWITCH,
operationData: Buffer.alloc(1)
};
// 根据HA状态设置操作信息
if (obj.state === 'on' || obj.state === 'off') {
// 简单开关控制
frame.operationCode = OPERATION_TYPES.SINGLE_SWITCH;
frame.operationData[0] = obj.state === 'on' ? 1 : 0;
} else if (obj.attributes) {
if (obj.attributes.brightness !== undefined) {
if (obj.attributes.color_temp !== undefined) {
// 双色温调光
frame.operationCode = OPERATION_TYPES.DUAL_TEMP_DIM;
frame.operationData = Buffer.alloc(2);
frame.operationData[0] = Math.round(obj.attributes.color_temp / 500 * 100); // 色温映射
frame.operationData[1] = Math.round(obj.attributes.brightness / 255 * 100); // 亮度
} else if (obj.attributes.rgb_color !== undefined) {
// RGBW调光
frame.operationCode = OPERATION_TYPES.RGBW_DIM;
frame.operationData = Buffer.alloc(4);
const [r, g, b] = obj.attributes.rgb_color;
frame.operationData[0] = Math.round(r / 255 * 100); // 红
frame.operationData[1] = Math.round(g / 255 * 100); // 绿
frame.operationData[2] = Math.round(b / 255 * 100); // 蓝
frame.operationData[3] = Math.round(obj.attributes.brightness / 255 * 100); // 白/亮度
} else {
// 单色调光
frame.operationCode = OPERATION_TYPES.SINGLE_DIM;
frame.operationData[0] = Math.round(obj.attributes.brightness / 255 * 100);
}
} else {
// 默认开关控制
frame.operationData[0] = obj.state === 'on' ? 1 : 0;
}
}
return frame;
}
module.exports = {
buf2obj,
obj2buf,
DEVICE_TYPE,
OPERATION_TYPES
};