Serial Studio 实战:三种方式实时可视化 HUAWEI K5161H LTE 调制解调器信号质量
【免费下载链接】Serial-StudioOpen-source telemetry dashboard. Supports UART, BLE, MQTT, Modbus, CAN Bus and more.项目地址: https://gitcode.com/GitHub_Trending/se/Serial-Studio
本指南以 Serial Studio 官方示例examples/LTE modem为主线,讲解如何将 HUAWEI K5161H LTE 调制解调器通过内置 Web API 采集到的小区信号质量数据(Cell ID、RSRQ、RSRP、RSSI、SINR),分别经虚拟串口(UART)、MQTT、UDP Socket三种传输通道送入 Serial Studio,并在仪表盘中自动渲染为实时图表。读完本文,你将掌握 socat 虚拟串口、Mosquitto MQTT 代理、UDP 数据报三种数据接入方式的完整配置流程,理解示例中帧格式与项目文件LTE Modem.ssproj的对应关系,并能结合 Serial Studio 底层数据流水线原理排查"有数据无图表"之类的常见问题。

一、场景与技术方案概览
HUAWEI K5161H 是一款支持 Web 管理界面的 LTE 调制解调器,其固件提供 HTTP API 端点http://192.168.9.1/api/device/signal,以 XML 形式返回当前小区信号参数。示例中的三个 Python 脚本(lte_serial.py、lte_mqtt.py、lte_udp.py)都使用requests库轮询该端点,解析出 5 个核心指标并打包成数据帧发送出去:
| 数据集 | 含义 | 单位 | 帧内索引(Index) |
|---|---|---|---|
| Cell id | 服务小区标识 | 无 | 1 |
| RSRQ | 参考信号接收质量 | dB | 2 |
| RSRP | 参考信号接收功率 | dBm | 3 |
| RSSI | 接收信号强度指示 | dBm | 4 |
| SINR | 信号与干扰加噪声比 | dB | 5 |
三个脚本生成的帧格式完全一致,并统一使用项目定义的起始与结束序列包裹:
/*{cell} ,{rsrq},{rsrp},{rssi},{sinr}*/其中/*与*/正是 LTE Modem.ssproj 中配置的frameStart与frameEnd帧定界符(frameDetection: 1,即"起始+结束定界符"模式)。帧内每个字段用英文逗号分隔,位置顺序与上表索引一一对应,例如:
/*12345 ,-12,-97,-75,-5*/二、前置准备:安装 Serial Studio 与 Python 依赖
示例在 Arch Linux 上构建与验证,获取 Serial Studio 的方式有三条路径:
- AppImage:下载官方发布的 AppImage 直接运行;
- AUR 包:通过 AUR 助手一键安装:
yay -S serial-studio-bin - 源码构建:克隆仓库后用 CMake 构建(仓库根目录的 CMakeLists.txt 即构建入口)。
三个 Python 脚本均依赖requests库发起 HTTP 轮询,在 Arch Linux 上安装:
sudo pacman -S python-requests关于示例脚本的自动依赖引导:三个脚本开头都内嵌了_ensure_deps()引导逻辑——首次运行时会在脚本旁创建私有虚拟环境.venv(若示例位于只读安装目录,则回退到~/.serial-studio/example-venvs),并在其中通过pip安装缺失依赖后重新执行自身。这样既不会改动系统 Python 环境(兼容 PEP 668 "externally managed" 约束),也意味着你其实无需手工pacman安装脚本依赖;按各方法章节直接python lte_xxx.py即可。
三、方法一:虚拟串口(Virtual Serial Port)
思路:用socat创建一对互联的虚拟串口,Python 脚本把数据写入ttyV1,Serial Studio 监听ttyV0,模拟真实的 UART 收发链路。
3.1 创建虚拟串口
- 安装
socat:sudo pacman -S socat - 创建一对关联的虚拟串口,
ttyV0用于 Serial Studio 监听,ttyV1用于脚本写入:socat -d -d pty,rawer,echo=0,link=/tmp/ttyV0,b9600 pty,rawer,echo=0,link=/tmp/ttyV1,b9600参数含义:
pty,rawer表示以 raw 模式创建伪终端(不做行缓冲处理),echo=0关闭回显,link=指定符号链接路径,b9600设定波特率 9600。-d -d输出调试信息。 - 验证虚拟串口:从一个终端
cat /tmp/ttyV0监听,在另一个终端写入测试数据:cat /tmp/ttyV0echo 100 > /tmp/ttyV1若监听终端打印出
100,说明链路已打通。 - 安装 Python 串口库(脚本引导程序会自动完成,也可手动安装):
sudo pacman -S python-pyserial - 运行串口发送脚本:
python lte_serial.py脚本以 5 秒为周期(
cycle_time = 5)轮询调制解调器 API,将解析结果写入/tmp/ttyV1,控制台会实时打印形如12-30-45 CELL=12345 RSRQ=-12 RSRP=-97 RSSI=-75 SINR=-5的日志。
3.2 Serial Studio 串口端配置
- 启动 Serial Studio。
- 进入DEVICE SETUP→ I/O Interface 选择UART/COM。
- 进入FRAME PARSING→ 选择Parse via Project File(按项目文件解析)。
- 选择项目文件
LTE Modem.ssproj。 - 手动填写COM Port为
/tmp/ttyV0并回车确认。 - 选择Baud Rate为 9600(与 socat 及脚本中的
serial_speed = 9600保持一致)。 - 点击右上角Connect建立连接。
首帧数据到达后,Serial Studio 会自动打开仪表盘并按项目文件的配置绘制图表。

四、方法二:MQTT
注意:MQTT 驱动属于 Serial Studio Pro 功能,需要 Pro 许可证(试用或付费)才能使用,免费版不包含该 I/O 接口(仓库文档 Data-Flow.md 明确列出 MQTT 属于 Pro 功能)。
思路:Python 脚本作为 MQTT 发布者把数据帧发布到本地 Mosquitto 代理的lte主题,Serial Studio 以 MQTT 订阅者身份订阅该主题。
4.1 搭建 MQTT Broker
- 安装 Mosquitto:
sudo pacman -S mosquitto - 以默认配置启动代理(
--verbose便于观察收发日志):mosquitto --verbose - 用自带客户端验证代理工作正常:
mosquitto_pub -m "abcd,100,50,75,89" -t "lte" - 安装 Python MQTT 客户端库 paho:
sudo pacman -S python-paho-mqtt - 运行 MQTT 发布脚本:
python lte_mqtt.py脚本会连接
127.0.0.1:1883(mqtt_broker_ip/mqtt_broker_port),并每隔 5 秒把解析后的数据帧发布到主题lte。
4.2 Serial Studio MQTT 端配置
- 启动 Serial Studio。
- 进入DEVICE SETUP→ I/O Interface 选择MQTT Subscriber。
- 进入FRAME PARSING→ 选择Parse via Project File。
- 选择项目文件
LTE Modem.ssproj。 - 设置Hostname为
127.0.0.1。 - 设置Port为
1883。 - 设置Topic Filter为
lte。 - 设置Keep Alive (s)为
600。 - 点击Connect。
MQTT 驱动会把每个匹配主题的消息整块送入帧读取器,相当于把串口字节流换成了 MQTT 负载字节流,后续的帧检测与解析逻辑完全一致。需要了解 MQTT 驱动的完整参数语义(如+/#通配符、MQTT 版本、TLS 选项、Keep Alive 含义等)可阅读仓库文档 Drivers-MQTT.md——其中说明 Keep Alive 是空闲时两次 PING 报文之间的秒数,默认 60,示例中放大到 600 是为了低频遥测场景下减少心跳。
五、方法三:UDP Socket
UDP 方式最简洁:脚本直接把数据帧以数据报形式发往本机 5005 端口,Serial Studio 开启网络 Socket 监听即可。
运行 UDP 发送脚本:
python lte_udp.py脚本创建socket(AF_INET, SOCK_DGRAM),每隔 5 秒执行sock.sendto(data_frame.encode("utf-8"), ("127.0.0.1", 5005))。
Serial Studio UDP 端配置
- 启动 Serial Studio。
- 进入DEVICE SETUP→ I/O Interface 选择Network Socket。
- 进入FRAME PARSING→ 选择Parse via Project File。
- 选择项目文件
LTE Modem.ssproj。 - 选择Socket Type为UDP。
- 设置Remote Address为
127.0.0.1。 - 设置Local Port为
5005。 - 点击右上角Connect。

值得说明的是,项目文件 LTE Modem.ssproj 中sources[0].connection已经预置了 UDP 相关默认值:socketTypeIndex: 1(UDP)、udpLocalPort: 5005、udpRemotePort: 5005、address: "127.0.0.1",与 README 中的手工配置步骤完全吻合。UDP 属于面向无连接、无重传的数据报协议,适合"每个数据包自带一条完整读数"的遥测场景,恰好匹配本示例"一帧一条数据"的数据形状;关于 UDP 与 TCP 的选择依据可进一步参考仓库文档 Drivers-Network.md。
六、数据帧与项目文件的对应关系
理解帧格式与项目文件如何对接,是排错的关键。LTE Modem.ssproj的核心配置如下:
- 帧定界:
frameStart: "/*"、frameEnd: "*/"、frameDetection: 1(起始 + 结束定界符模式),decoder: 0(Plain Text / UTF-8 解码); - 帧解析器:内嵌 JavaScript 解析函数,按逗号拆分帧内容:
function parse(frame) { return frame.split(','); }解析返回的数组元素按**帧索引(Frame Index)**映射到数据集;
- 五个数据集:Cell id(索引 1)、RSRQ(索引 2,单位 dB,绘图范围 -20~0)、RSRP(索引 3,单位 dBm,绘图范围 -120~-70)、RSSI(索引 4,单位 dBm,绘图范围 -100~-50)、SINR(索引 5,单位 dB,绘图范围 -20~30),其中后四个开启了
graph: true实时曲线; - 绘图参数:
plotTimeRange: 60(时间窗口 60 秒)、pointCount: 1000(每个数据集保留的历史采样点数上限); - 仪表盘组织:所有数据集归属于标题为 "Data Grid" 的
datagrid分组,项目标题为 "HUAWEI K5161H"。
也就是说,脚本里f"/*{cell} ,{rsrq},{rsrp},{rssi},{sinr}*/"这一行同时决定了三个传输通道的线上字节形态,而项目文件决定了这些字节如何被切帧、拆分并映射到可视化数据集。
七、脚本内部实现剖析
三个脚本结构几乎相同,差异只在最后一步的发送通道,非常适合作为"同一数据多路复用"的参考模板:
- HTTP 轮询与 XML 解析:
requests.get(url_api).text取得 XML 文本,ET.XML()解析为元素树,get_value(marker)通过tree.find(marker).text读取字段文本,再用正则r"(\-|)(\d+)(\.?)(\d*)"提取带符号数值(兼容负数和整数/小数),因此rsrq这类可能返回小数(如-12.5)的字段会先经float()再取整; - 公共配置:
url_api = "http://192.168.9.1/api/device/signal"(调制解调器管理地址)、cycle_time = 5(轮询/发送周期,秒)。如果你的调制解调器网关地址不同,直接修改该常量即可; - 发送通道差异:
- 串口版 lte_serial.py:
serial.Serial(port="/tmp/ttyV1", baudrate=9600, bytesize=8, timeout=2, stopbits=STOPBITS_ONE),随后serialPort.write(data_frame.encode("utf-8")); - MQTT 版 lte_mqtt.py:
paho.Client()连接127.0.0.1:1883,随后mqttc.publish("lte", data_frame); - UDP 版 lte_udp.py:
socket(AF_INET, SOCK_DGRAM),随后sock.sendto(data_frame.encode("utf-8"), ("127.0.0.1", 5005))。
- 串口版 lte_serial.py:
值得注意的是,脚本虽然额外解析了pci、mode、ulbandwidth、dlbandwidth、band、ulfrequency、dlfrequency等字段,但并未纳入发送帧——这正是项目文件只定义 5 个数据集的原因。若需扩展指标,只需在帧中追加字段并在项目文件里新增对应数据集。
八、数据在 Serial Studio 中的流动路径
为了理解"为何首帧到达后仪表盘自动打开、曲线自动绘制",需要了解 Serial Studio 的通用数据流水线(详见仓库文档 Data-Flow.md):
设备/脚本 → 驱动(UART / MQTT / UDP) → 输入缓冲区 → 帧读取器 → 帧构建器(parse) → 仪表盘- 驱动层只负责字节搬运:UART、MQTT、Network 驱动都只是把字节交给帧读取器,不做任何解析;
- 帧读取器按定界符切帧:本项目使用"起始 + 结束定界符"模式(
/*…*/),这与 MQTT 驱动"一条消息即一个字节块"的特性天然契合——每个 MQTT 负载通常恰好包含一帧,所以按定界符切帧依然可靠; - 帧构建器调用
parse(frame):在 Project File 模式下,切出的帧会传给项目内嵌的 JavaScript 解析函数(frame.split(',')),返回值按帧索引映射到数据集,随后驱动仪表盘刷新。
基于这一流水线,"有数据无图表"的常见原因就是定界符不匹配(设备发\r\n而项目只配了\n)或解析返回的数组元素数量/顺序与数据集索引不一致——排查时应先看串口/终端原始字节,再核对frameStart/frameEnd与parse()的输出。
九、故障排查速查表
| 现象 | 排查方向 |
|---|---|
| 控制台无数据 | 检查驱动配置:串口路径/波特率、MQTT 主机/端口/主题过滤、UDP 地址/端口是否与脚本端一致 |
| 控制台有数据但仪表盘无图 | 确认 FRAME PARSING 是否选择 Parse via Project File;核对定界符是否与脚本帧格式一致(/*与*/) |
| 数据显示乱码 | 波特率不匹配(socat、脚本、Serial Studio 三者必须都是 9600)、解码器选错 |
| 部分帧丢失/切帧错乱 | 帧定界符不匹配,检查脚本拼接的帧是否严格以/*开头、以*/结尾 |
| 曲线不更新但数值冻结 | 解析函数返回的数组比数据集索引期望的更短,检查parse()拆分结果 |
将以上三种传输方式对比即可发现:串口方式模拟真实 UART 链路、适合设备只有串口输出的场景;MQTT 方式通过代理解耦发布与订阅、适合多订阅端复用同一数据源(需 Pro 许可);UDP 方式最轻量、适合局域网内低开销遥测。示例代码与项目文件均可在仓库examples/LTE modem目录下直接查阅复用。
【免费下载链接】Serial-StudioOpen-source telemetry dashboard. Supports UART, BLE, MQTT, Modbus, CAN Bus and more.项目地址: https://gitcode.com/GitHub_Trending/se/Serial-Studio
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考