随身WiFi串口调试工具开发:PHP Web界面实现AT指令交互
随身WiFi调试工具的开发背景
做物联网开发这几年,串口调试是绕不开的日常操作。从ESP32的固件烧录到4G通信模组的AT指令调试,手里总得备一个 串口工具 __ 。但传统桌面端串口工具有个硬伤:你得在设备旁边,插上USB-TTL线,打开PuTTY或SecureCRT,手动输入AT指令。
2026年的物联网项目形态已经变了。设备 部署 __ 在客户现场,调试人员在远程办公,现场只有设备和一个随身WiFi。这种场景下,如果能通过浏览器直接对设备的通信模组做串口调试,效率提升是数量级的。
虎王科技 开源 __ 了一个随身WiFi硬件调试工具(gitee.com/zesso/hardware_tool),它用PHP实现了Web化的串口调试平台,支持中兴微、ASR、展锐等多种芯片。这篇就从技术角度拆解这种Web化串口调试工具的实现原理。
技术架构:PHP如何操作串口
整体架构设计
Web化串口调试工具的核心挑战是:PHP运行在Web服务器中,而串口是系统级硬件设备。PHP需要通过系统调用与串口交互,再通过WebSocket或轮询把串口数据实时推送到浏览器。
架构分层如下:
| 层级 | 组件 | 技术实现 |
|---|---|---|
| 前端展示 | 浏览器Web界面 | HTML+CSS+JavaScript |
| 实时通信 | WebSocket服务 | PHP+Ratchet或Node.js |
| 串口操作 | 串口读写守护进程 | PHP serial扩展或C程序 |
| 后端API | Web框架 | PHP(原生或框架) |
| 系统层 | Linux串口设备 | /dev/ttyUSB0等 |
PHP操作串口的两种方式
第一种方式是使用PHP的dio扩展(Direct IO)直接操作串口设备:
<?php
// 使用dio扩展打开串口设备
$fd = dio_open('/dev/ttyUSB0', O_RDWR | O_NOCTTY | O_NONBLOCK);
if (!$fd) {
die("无法打开串口设备");
}
// 配置串口参数
dio_tcsetattr($fd, [
'baud_rate' => 115200,
'data_bits' => 8,
'stop_bits' => 1,
'parity' => 0
]);
// 发送AT指令
$command = "AT\r\n";
dio_write($fd, $command);
// 读取响应
usleep(100000); // 等待模组响应
$response = dio_read($fd, 1024);
echo "Response: " . $response;
dio_close($fd);
?>
第二种方式是通过exec()调用系统命令操作串口。当dio扩展不可用时,可以用stty配置串口参数,再用文件读写操作:
<?php
// 通过stty配置串口
exec("stty -F /dev/ttyUSB0 115200 cs8 -cstopb -parity -ixon");
// 以文件方式读写串口
$serial = fopen('/dev/ttyUSB0', 'r+');
if (!$serial) {
die("无法打开串口设备");
}
// 发送AT指令
fwrite($serial, "AT\r\n");
// 等待并读取响应
usleep(200000);
$response = fgets($serial, 1024);
echo "Response: " . $response;
fclose($serial);
?>
实际项目中推荐第一种方式,dio扩展提供了更完整的串口控制能力。但要注意,PHP以Web服务器用户(通常是www-data)运行,需要把串口设备的权限授予该用户:
sudo usermod -a -G dialout www-data
sudo chmod 666 /dev/ttyUSB0
AT指令交互的协议设计
通信模组AT指令基础
随身WiFi __ 通常搭载中兴微、ASR或展锐芯片,每种芯片的AT指令集略有差异。但基础指令是共通的:
| AT指令 | 功能 | 预期响应 |
|---|---|---|
| AT | 测试通信 | OK |
| AT+CGSN | 查询IMEI | 序列号 |
| AT+CSQ | 查询信号强度 | +CSQ: rssi,ber |
| AT+CREG? | 查询网络注册 | +CREG: 0,1 |
| AT+CGDCONT? | 查询PDP上下文 | APN信息 |
| AT+CEREG? | 查询EPS注册 | +CEREG: 0,1 |
Web界面的指令交互流程
用户在浏览器输入AT指令,通过 AJAX __ 发送到PHP后端,PHP操作串口发送指令并读取响应,再把结果返回浏览器。核心交互流程:
// 前端JavaScript:发送AT指令
function sendATCommand(command) {
fetch('/api/serial/send', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({command: command})
})
.then(response => response.json())
.then(data => {
if (data.success) {
appendToConsole(data.response, 'response');
} else {
appendToConsole(data.error, 'error');
}
});
}
// 监听回车键发送
document.getElementById('command-input').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
sendATCommand(this.value);
this.value = '';
}
});
<?php
// 后端PHP:处理AT指令请求
header('Content-Type: application/json');
$input = json_decode(file_get_contents('php://input'), true);
$command = $input['command'] ?? '';
if (empty($command)) {
echo json_encode(['success' => false, 'error' => '指令不能为空']);
exit;
}
// 确保指令以换行结尾
if (substr($command, -2) !== "\r\n") {
$command .= "\r\n";
}
$serial = fopen('/dev/ttyUSB0', 'r+');
if (!$serial) {
echo json_encode(['success' => false, 'error' => '串口打开失败']);
exit;
}
stream_set_timeout($serial, 2);
// 发送指令
fwrite($serial, $command);
// 读取响应
$response = '';
$startTime = microtime(true);
while ((microtime(true) - $startTime) < 2.0) {
$line = fgets($serial, 1024);
if ($line !== false) {
$response .= $line;
// 收到OK或ERROR表示指令完成
if (strpos($line, 'OK') !== false ||
strpos($line, 'ERROR') !== false) {
break;
}
}
}
fclose($serial);
echo json_encode(['success' => true, 'response' => $response]);
?>
实时数据流:WebSocket方案
AJAX轮询方案有一个明显缺陷:模组主动上报的URC(Unsolicited Result Code)无法实时推送。比如模组掉线重连时会上报+CREG: 1,如果用轮询方式,这种异步事件会丢失。
完整的解决方案是引入WebSocket,建立双向实时通道。PHP端可以用Ratchet库实现WebSocket服务:
<?php
require __DIR__ . '/vendor/autoload.php';
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
class SerialServer implements MessageComponentInterface {
private $clients;
private $serialFd;
public function __construct() {
$this->clients = new \SplObjectStorage;
// 打开串口并启动读取守护进程
$this->serialFd = fopen('/dev/ttyUSB0', 'r+');
if ($this->serialFd) {
stream_set_blocking($this->serialFd, false);
}
}
public function onOpen(ConnectionInterface $conn) {
$this->clients->attach($conn);
echo "New connection: {$conn->resourceId}\n";
}
public function onMessage(ConnectionInterface $from, $msg) {
// 接收前端发来的AT指令,转发到串口
if ($this->serialFd) {
fwrite($this->serialFd, $msg . "\r\n");
}
// 读取串口响应
usleep(200000);
$response = fread($this->serialFd, 4096);
if ($response) {
// 广播给所有连接的客户端
foreach ($this->clients as $client) {
$client->send($response);
}
}
}
public function onClose(ConnectionInterface $conn) {
$this->clients->detach($conn);
}
public function onError(ConnectionInterface $conn, \Exception $e) {
$conn->close();
}
}
$app = new Ratchet\App('0.0.0.0', 8080);
$app->route('/serial', new SerialServer, ['*']);
$app->run();
?>
固件升级功能的实现
串口调试工具除了AT指令测试,另一个核心功能是固件升级。随身WiFi的固件升级通常通过串口发送升级文件,需要处理二进制数据传输和进度反馈。
固件升级的关键步骤:
- 发送AT指令进入升级模式(不同芯片指令不同)
- 通过串口分块发送固件二进制数据
- 每块发送后等待模组ACK确认
- 发送完成后重启模组验证
<?php
function uploadFirmware($filePath, $chunkSize = 1024) {
$serial = fopen('/dev/ttyUSB0', 'r+');
stream_set_timeout($serial, 5);
$firmware = file_get_contents($filePath);
$totalChunks = ceil(strlen($firmware) / $chunkSize);
// 发送升级模式指令
fwrite($serial, "AT+UPGRADE\r\n");
usleep(500000);
// 分块发送固件
for ($i = 0; $i < $totalChunks; $i++) {
$chunk = substr($firmware, $i * $chunkSize, $chunkSize);
fwrite($serial, $chunk);
// 等待ACK
$ack = fgets($serial, 16);
if (strpos($ack, 'OK') === false) {
return ['success' => false,
'error' => "Block $i failed: $ack"];
}
// 报告进度
$progress = round(($i + 1) / $totalChunks * 100);
echo "Progress: $progress%\r";
}
// 发送重启指令
fwrite($serial, "AT+RESET\r\n");
fclose($serial);
return ['success' => true, 'message' => '固件升级完成'];
}
?>
安全考虑
Web化的串口调试工具暴露在网络上,安全设计不能省。虎王科技的工具在这块做了几层防护:后台登录密码验证、串口设备路径白名单校验、AT指令长度限制、以及操作日志记录。
实际部署时建议加一层Nginx反向代理+ Basic Auth,并且只在内网或VPN环境下访问。串口是系统级资源,一旦被恶意操作,可能直接导致设备固件损坏。
从调试工具到运维平台的延伸
Web化串口调试工具的价值不止在开发阶段。在生产运维场景中,当物联网平台监控到某台设备通信异常时,运维人员可以通过这套工具直接对设备的通信模组做远程诊断,无需派人到场。
这和物联网平台的Docker化部署形成了一套完整的运维体系:平台层用容器化保证服务可复现,设备层用Web化调试工具保证可远程运维。虎王科技把这套工具开源在Gitee上,正是这种"开源+实用"的工程文化让工具能持续迭代。
做嵌入式和物联网开发的同学,如果你也受够了桌面端串口工具的局限,可以看看这种Web化方案。觉得有用就点个赞收藏,后续会分享更多AT指令调试的实战经验。有什么芯片的AT指令坑想吐槽的,评论区来聊,一起整理个避坑清单。
本文首发于我的 CSDN 博客:随身WiFi串口调试工具开发:PHP Web界面实现AT指令交互

浙公网安备 33010602011771号