electron与报警灯通信(usb转串口)


上篇文章我们搭建了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个坑:

  1. IpcRenderer.invokeipcMain.handle 发送了无法被克隆的对象。请确保传递基础数据类型,或在过程中进行序列化和反序列化。
    • 错误信息:IpcRenderer.invoke Error: An object could not be cloned.
  2. 端口被占用。只要关闭占用该端口就行。

代码实现

代码量有点大,我摘取一些核心代码做简单的讲解,想看更具体,直接去我仓库pull。

首先我们先理解一个概念。electron分为主进程渲染进程,ui代码都是写在渲染进程的,而通信需要写在主进程,那么
2个进程的通信,就需要用ipcRendereripcMain

  • 渲染进程发送: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,和报警灯的通信搞定啦。

我的微信公众号: 梨的前端小屋


文章作者: 梨啊梨
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 梨啊梨 !
  目录