上篇文章我们搭建了electron基础架构,文章在这 基于 Vite + Vue 3 + Electron 创建桌面端应。今天这篇文章我们实现报警灯的串口通信。然后下一篇会讲解electron打包遇到的坑(因为涉及到原生(C/C++)扩展和需要编译底层模块,花了大半天时间才解决)
项目demo我放在码云上了,地址是:https://gitee.com/pearpear/electron-demo-alarm-lamp
最终效果:
报警灯串口通信协议
首先明确串口控制协议,我这里的协议这样的
- OFF: “AA27”,
- GREEN: “AA14”,
- YELLOW: “AA12”,
- RED: “AA11”,
- RED2: “AA110001”, // 红灯闪烁模式
- BUZZERON: “AA18”, // 开启蜂鸣器
- BUZZEROFF: “AA28”, // 关闭蜂鸣器
- ALLON: “AA1F”, // 灯、蜂鸣器全部开启
- ALLOFF: “AA2F”, // 灯、蜂鸣器全部关闭
我需要将字符串2位一个拆分,然后用Buffer.from转成Buffer对象,比如第一个AA27,拆分成[0xAA],[0x27],以此类推。
确保设备连接正常
报警灯连接电脑,然后在电脑的设备管理器=>端口中能正确读取出来,如果设备没有识别,那需要安装驱动。
包括设备的
波特率,数据位,停止位,校验位,都要确保正确。
安装serialport包
npm install serialport
这个包主要用于和串行端口进行通信。
开发过程中踩到下面2个坑:
IpcRenderer.invoke
或 ipcMain.handle
发送了无法被克隆的对象。请确保传递基础数据类型,或在过程中进行序列化和反序列化。
- 错误信息:
IpcRenderer.invoke Error: An object could not be cloned.
- 端口被占用。只要关闭占用该端口就行。
代码实现
代码量有点大,我摘取一些核心代码做简单的讲解,想看更具体,直接去我仓库pull。
首先我们先理解一个概念。electron分为主进程和渲染进程,ui代码都是写在渲染进程的,而通信需要写在主进程,那么
2个进程的通信,就需要用ipcRenderer和ipcMain。
- 渲染进程发送:ipcRenderer.invoke
- 主进程接收:ipcMain.handle
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| LedControl.vue
// 从主进程获取串口列表 await ipcRenderer.invoke('get-ports');
// 发送连接串口命令 await ipcRenderer.invoke('connect-port', { port: this.selectedDevice, options: { baudRate: 9600, // 波特率 dataBits: 8, // 数据位 stopBits: 1, // 停止位 parity: 'none' // 校验位 } });
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| main.js
// 主进程接收到渲染进程的请求,获取串口列表 ipcMain.handle('get-ports', async () => { try { const ports = await serialPort.getPortsList(); return ports; // 返回串口列表 } catch (error) { console.error('获取串口列表失败:', error); throw error; } });
// 主进程接收到渲染进程的请求,连接串口 ipcMain.handle('connect-port', async (event, { port, options }) => { try { await serialPort.connect(port, options); ledController = new LedController(serialPort); // 实例化 LED 控制器 return true; } catch (error) { console.error('连接串口失败:', error); throw error; } });
|
1 2 3 4 5 6 7 8 9 10 11
| serialPort.js
// 确定是否能获取到设备的串口 async getPortsList() { try { return await SerialPort.list(); } catch (error) { console.error('获取串口列表失败:', error); throw error; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| ledController.js
// 对命令格式进行转换处理 buildCommand(data) { // 构建命令数组 const hexArrays = this.convertStringToHexArrays(data); const result = hexArrays.map(subArray => subArray[0]); const command = Buffer.from([ ...result ]); return command; }
// 发送命令 async sendCommand(data) { try { const command = this.buildCommand(data); await this.serialPort.sendData(command); return true; } catch (error) { console.error('发送命令失败:', error); throw error; } }
|
ok,和报警灯的通信搞定啦。
我的微信公众号: 梨的前端小屋