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

163 lines (144 loc) 4.72 kB
/** * 串口通信类 * 支持RS485/RS232串口通信 */ const { SerialPort } = require('serialport'); const { ReadlineParser } = require('@serialport/parser-readline'); const EventEmitter = require('events'); class SerialConnection extends EventEmitter { constructor(options = {}) { super(); this.options = { path: options.path || '/dev/ttyUSB0', baudRate: options.baudRate || 9600, dataBits: options.dataBits || 8, stopBits: options.stopBits || 1, parity: options.parity || 'none', autoOpen: false, ...options }; this.port = null; this.parser = null; this.isConnected = false; this.reconnectTimer = null; this.reconnectInterval = 5000; // 5秒重连间隔 } /** * 连接串口 */ connect() { return new Promise((resolve, reject) => { try { this.port = new SerialPort(this.options); // 设置解析器(如果需要按行解析) if (this.options.useLineParser) { this.parser = this.port.pipe(new ReadlineParser({ delimiter: '\r\n' })); this.parser.on('data', (data) => { this.emit('data', Buffer.from(data)); }); } else { this.port.on('data', (data) => { this.emit('data', data); }); } this.port.on('open', () => { this.isConnected = true; this.emit('connect'); console.log(`串口已连接: ${this.options.path}`); resolve(); }); this.port.on('close', () => { this.isConnected = false; this.emit('disconnect'); console.log(`串口已断开: ${this.options.path}`); this.scheduleReconnect(); }); this.port.on('error', (err) => { this.isConnected = false; this.emit('error', err); console.error(`串口错误: ${err.message}`); this.scheduleReconnect(); }); // 打开串口 this.port.open(); } catch (error) { reject(error); } }); } /** * 断开串口连接 */ disconnect() { return new Promise((resolve) => { if (this.reconnectTimer) { clearTimeout(this.reconnectTimer); this.reconnectTimer = null; } if (this.port && this.port.isOpen) { this.port.close(() => { this.isConnected = false; resolve(); }); } else { this.isConnected = false; resolve(); } }); } /** * 发送数据 * @param {Buffer|string} data 要发送的数据 */ write(data) { return new Promise((resolve, reject) => { if (!this.isConnected || !this.port || !this.port.isOpen) { reject(new Error('串口未连接')); return; } this.port.write(data, (err) => { if (err) { reject(err); } else { resolve(); } }); }); } /** * 计划重连 */ scheduleReconnect() { if (this.reconnectTimer) { return; } this.reconnectTimer = setTimeout(() => { this.reconnectTimer = null; console.log(`尝试重连串口: ${this.options.path}`); this.connect().catch(() => { // 重连失败,继续计划下次重连 }); }, this.reconnectInterval); } /** * 获取可用串口列表 */ static async listPorts() { try { const ports = await SerialPort.list(); return ports.map(port => ({ path: port.path, manufacturer: port.manufacturer, serialNumber: port.serialNumber, pnpId: port.pnpId, locationId: port.locationId, productId: port.productId, vendorId: port.vendorId })); } catch (error) { console.error('获取串口列表失败:', error); return []; } } } module.exports = SerialConnection;