摘要

针对仓库自动化场景中 WCS(仓库控制系统)与硬件设备的通信需求,结合团队前端技术栈,选型 Electron 作为桌面客户端框架,实现串口、TCP 两种核心通信方式及自动化更新机制。本文简洁阐述方案选型、核心实现及注意事项,为工业场景 WCS 客户端开发提供可落地参考。

1. 需求背景与核心目标

1.1 业务与技术背景

WCS 是仓库自动化的核心,负责调度传送带、AGV 等硬件设备,实现业务系统与硬件的双向交互。现场硬件主要支持串口、TCP Server 通信,不兼容 HTTP 协议,因此需开发桌面客户端(exe 形式)。

1.2 核心目标

  • 实现串口、TCP 与硬件的稳定通信;
  • 提供简洁运维 UI 界面;
  • 支持自动化版本更新,降低多站点运维成本;
  • 适配多站点本地部署场景。

2. 核心概念与协议基础

2.1 串口通信核心协议

串口通信是工业硬件主流交互方式,常用协议对比如下:

协议传输方式最大传输距离适用场景
RS-232全双工~ 15 米近距离外设连接
RS-422全双工~ 1200 米长距离点对点传输
RS-485半双工~ 1800 米工业多节点组网

2.2 核心通信方式

现场硬件核心依赖串口TCP Server 通信,是本次客户端开发的重点适配对象。

3. 技术选型与整体架构

3.1 客户端框架选型

结合前端技术栈、更新需求,对比主流框架后选型 Electron,核心优势:匹配前端技术、更新机制成熟、生态完善、性能适配本地部署场景。

3.2 整体架构

本架构自顶向下分为客户端层、业务服务层、本地服务层、硬件设备层四层结构,实现从业务操作到硬件控制的全链路打通:

  • 客户端层:由 PDA 应用、FMS 门户、设备控制台组成,面向现场作业人员与运维人员提供操作入口。
  • 业务服务层:以 ASM 服务与 SLDS 服务为核心,处理业务逻辑、站内管理、SCADA(监督控制与数据采集系统)工单流转与离线模式调度。
  • 本地服务层:包含 WCS、ASM 离线系统、Kepware(工业自动化通信平台)工业数据采集服务及设备适配层,实现业务指令下发、硬件数据采集、离线缓存与协议转换。
  • 硬件设备层:以 PLC 控制器为核心,对接 ASM 自动化设备,执行实际分拣、搬运、控制等物理动作。

整体流程为:上层业务系统下发指令 → WCS 接收并转换 → 通过适配层与 Kepware 分别实现指令控制与数据采集 → PLC 驱动硬件执行动作,同时支持离线模式保障现场作业连续性。

硬件设备层

本地服务层

业务服务层

客户端层

ASM 服务

SLDS 服务

站内管理

工单数据

PDA 应用

FMS 门户

设备控制台

离线模式

业务操作

参数配置

SCADA 单

ASM 离线系统

WCS

Kepware数据采集

设备适配层

PLC 控制器
自动化执行设备

3.3 客户端通信架构

Electron 客户端一边通过 HTTP 对接后端,一边通过串口、TCP 连接硬件,架构如下:

Http 协议

COM 1 串口

TCP 协议

COM 2 串口

IPC 通信

BE 服务

Electron 客户端

扫描头设备

称重设备

渲染进程(UI 界面)

4. 串口通信实现

4.1 技术选型:SerialPort

选用 SerialPort 库,支持多平台,适配工业串口设备,可快速实现数据收发与异常处理。该库广泛应用于物联网、工业传感器、医疗设备等场景,是 JavaScript 与硬件固件交互的成熟方案。

4.2 核心参数与代码

核心参数:波特率(常用 115200)、数据位(8 位)、奇偶校验(none)、停止位(1 位)、超时(1000 - 3000 ms)。

const { SerialPort } = require('serialport');

// 串口配置(工业标准参数)
const SERIAL_CONFIG = {
  path: process.platform === 'win32' ? 'COM4' : '/dev/ttyUSB1',
  baudRate: 115200,
  dataBits: 8,
  parity: 'none',
  stopBits: 1,
  flowControl: false,
  timeout: 1500
};

// 初始化串口实例
const serialPort = new SerialPort(SERIAL_CONFIG);

/**
 * 监听硬件上报数据
 */
serialPort.on('data', (buffer) => {
  const data = buffer.toString('ascii');
  console.log('串口数据:', data);
  mainWindow.webContents.send('serial:data-received', data);
});

/**
 * 发送指令到硬件(统一格式)
 * @param {string} cmd 原始指令
 */
function sendSerialCmd(cmd) {
  if (!serialPort.isOpen) {
    console.error('串口未连接');
    return;
  }
  const formatCmd = `CMD_V1.3.0:${cmd}`;
  serialPort.write(formatCmd, (err) => {
    if (err) console.error('指令发送失败:', err.message);
  });
}

/**
 * 统一异常捕获
 */
serialPort.on('error', (err) => {
  console.error('串口异常:', err.message);
});

4.3 模拟测试方案

开发阶段用 SerialPortMock 离线调试,模拟硬件数据收发,提升开发效率:

const { SerialPortMock } = require('serialport');

// 创建虚拟设备
SerialPortMock.binding.createPort('/dev/MOCK_DEVICE', { echo: true });

// 初始化模拟串口
const mockPort = new SerialPortMock({
  path: '/dev/MOCK_DEVICE',
  baudRate: 115200
});

// 定时模拟硬件数据上报
setInterval(() => {
  mockPort.port.emitData('DEVICE_STATUS:OK,VALUE:456,VERSION:1.3.0');
}, 2000);

5. TCP 通信实现

5.1 技术选型:Node.js net 模块

采用 Node.js 原生 net 模块,无需额外依赖,适配硬件 TCP Server 模式,保证长连接稳定性。

5.2 核心代码实现

const net = require('net');
const { mainWindow } = require('./electron');

// TCP 连接配置
const TCP_CONFIG = {
  host: '192.168.1.101',
  port: 8081,
  reconnectInterval: 3000
};

let tcpClient = new net.Socket();
let reconnectTimer = null;

/**
 * TCP 连接方法
 */
function connectTcpServer() {
  tcpClient.connect(TCP_CONFIG.port, TCP_CONFIG.host, () => {
    clearInterval(reconnectTimer);
    console.log('TCP 连接成功');
    tcpClient.write('INIT_CONNECTION_V1.3.0');
  });
}

/**
 * 接收硬件数据
 */
tcpClient.on('data', (buffer) => {
  const data = buffer.toString('ascii');
  mainWindow.webContents.send('tcp:data-received', data);
});

/**
 * 断开自动重连机制
 */
tcpClient.on('close', () => {
  console.log('TCP 连接断开,尝试重连...');
  tcpClient.destroy();
  tcpClient = new net.Socket();
  reconnectTimer = setInterval(connectTcpServer, TCP_CONFIG.reconnectInterval);
});

/**
 * TCP 异常捕获
 */
tcpClient.on('error', (err) => {
  console.error('TCP 异常:', err.message);
});

// 启动连接
connectTcpServer();

6. 自动更新机制(electron-updater)

6.1 更新流程

无新版本

有新版本

稍后

立即安装

启动客户端

检查线上版本

进入主界面

后台下载

询问安装

退出安装

自动重启

6.2 核心实现

将安装包、version.json 上传至 CDN,客户端启动时比对版本,后台下载更新,完成后弹窗提示安装。

const { autoUpdater, dialog } = require('electron-updater');

// 启动版本检查
autoUpdater.checkForUpdatesAndNotify();

/**
 * 新版本下载完成后提示
 */
autoUpdater.on('update-downloaded', (info) => {
  dialog.showMessageBox({
    title: '更新就绪',
    message: `新版本 ${info.version} 已下载,是否立即安装?`,
    buttons: ['立即安装', '稍后']
  }).then(({ response }) => {
    if (response === 0) autoUpdater.quitAndInstall();
  });
});

/**
 * 更新失败提示
 */
autoUpdater.on('error', (err) => {
  dialog.showMessageBox({
    type: 'error',
    title: '更新失败',
    message: `自动更新异常:${err.message}`
  });
});

7. 方案总结与注意事项

7.1 技术栈概览

模块技术选型核心价值
桌面框架Electron匹配前端,快速开发
串口通信SerialPort工业级稳定适配
TCP 通信Node.js net 模块原生无依赖,适配长连接
自动更新electron-updater开箱即用,适配多站点

7.2 核心优势

开发效率高、硬件兼容性强、运维成本低、稳定性适配工业场景。

7.3 注意事项

  • 精简 Electron 打包依赖,提升启动速度;
  • 限制 Node.js 权限,避免安全风险;
  • 适配不同系统串口权限(Windows 配置权限、Linux 加入 dialout 组);
  • 开启日志记录,便于异常排查。

附录:参考资料

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐