基于树莓派打造轻量级网络流量监控仪表盘

📅 2026/8/19 1:32:08
基于树莓派打造轻量级网络流量监控仪表盘
1. 项目缘起为什么我们需要一个“流量控制迷你板”在任何一个涉及网络设备、服务器集群或者家庭智能网关的运维场景里流量监控都是一个绕不开的核心需求。我们总想知道当前网络带宽占用多少哪个IP地址或应用在“吃”流量有没有异常突发流量导致网络卡顿传统的做法要么是登录到路由器或交换机的管理后台在一堆复杂的菜单里翻找要么是部署一套像Zabbix、PrometheusGrafana这样的专业监控系统。前者操作繁琐信息不直观后者功能强大但部署和维护成本高对于个人工作室、小型办公室或者只是想实时看一眼网络状态的极客来说有点“杀鸡用牛刀”的感觉。于是一个轻量级、可视化、即插即用的“流量控制迷你板”Traffic Control Mini Board的想法就诞生了。它的核心目标很简单在一块小屏幕上实时、直观地展示关键网络接口的流量数据让你一眼就能掌握网络脉搏。你可以把它放在路由器旁边、服务器机架上甚至书桌一角无需打开任何电脑或手机APP就能获得最直接的状态反馈。这不仅仅是数据的展示更是一种对网络环境的“感知”延伸。我最初做这个项目就是因为受够了每次网络一卡顿就要手忙脚乱地开电脑、输命令就想有个像汽车仪表盘一样的东西能随时告诉我“网速”这个重要指标。2. 核心组件选型硬件与软件的黄金搭配要实现这个迷你仪表盘我们需要从硬件和软件两个层面进行选型。选型的原则是低成本、易获取、低功耗、社区支持好。2.1 硬件基石单板计算机与显示屏主控板的选择是项目的起点。经过对比树莓派 Zero 2 W成为了我的首选。理由很充分首先它足够“迷你”尺寸只有65mm x 30mm非常适合嵌入小型外壳其次性能对于我们的需求绰绰有余其四核ARM处理器足以流畅运行一个轻量级Linux系统和我们的监控程序最关键的是它内置了Wi-Fi和蓝牙无需额外配件就能联网获取数据或进行配置。当然如果你手头有树莓派3B/4B或者类似性能的Orange Pi、Rock Pi等开发板也完全没问题只是体积和功耗会稍大一些。接下来是“面子工程”——显示屏。为了追求极致的迷你化和即视感我选择了一块1.3英寸的IPS液晶屏分辨率是240x240。这个尺寸比传统的2.4或3.5英寸屏小很多但显示流量曲线和数字信息足够了。它通常通过SPI接口与树莓派连接驱动成熟在Raspbian系统下有现成的驱动和库支持。这种屏幕功耗极低且IPS材质可视角度广从各个方向看都很清晰。当然如果你希望显示更多信息比如多个接口的并列对比可以选择稍大一点的1.54或2.0英寸屏原理是相通的。硬件清单小结主控板树莓派 Zero 2 W推荐或同类单板计算机。显示屏1.3英寸 IPS SPI接口液晶屏240x240。其他Micro SD卡8GB以上、Micro USB电源线、可选的外壳和排线。2.2 软件栈构建从系统到可视化硬件搭好了我们需要给它注入灵魂。软件栈的选择决定了项目的稳定性和易用性。操作系统方面Raspberry Pi OS Lite32位是最稳妥的选择。它是一个无桌面环境的精简版系统资源占用小通过SSH即可管理完美契合我们“后台运行、专注显示”的需求。流量数据从哪里来在Linux系统中网络接口的收发字节数都记录在/proc/net/dev这个虚拟文件里。我们不需要复杂的嗅探或抓包只需定期比如每秒读取这个文件计算相邻两次读取的字节数差值就能得到实时的流量速率。这是最底层、最可靠的数据来源。如何让数据“活”起来我们需要一个程序来负责三件事1. 定时采集流量数据2. 进行必要的计算如单位转换、速率计算3. 在屏幕上绘制出直观的图表和数字。这里有几个备选方案Python PIL/Pillow 硬件SPI驱动库这是最灵活、最受社区欢迎的方案。Python语法简洁拥有海量的库。我们可以用psutil库方便地获取网络IO数据用PILPython Imaging Library来绘制图形和文字再通过屏幕厂商提供的SPI库如st7789驱动库将图像刷新到屏幕上。这个方案可控性极高你可以自定义任何样式的图表、颜色和布局。使用现成的仪表盘软件像Grafana这样的专业工具虽然强大但将其移植到小屏幕并实现自包含运行配置相当复杂。而一些为嵌入式设备设计的轻量级UI框架如LVGL功能强大但学习曲线较陡。对于我们这个单一功能的项目来说有点重。因此我强烈推荐使用Python方案。它平衡了开发效率、灵活性和资源消耗。我们写的脚本将作为一个后台服务systemd service持续运行实现7x24小时监控。3. 实战开发一步步打造你的流量仪表盘理论说再多不如动手做一遍。下面我将以树莓派 Zero 2 W 和 1.3英寸 SPI屏幕为例详细拆解从系统准备到代码运行的每一个步骤。3.1 系统准备与硬件连接首先在你的电脑上使用 Raspberry Pi Imager 工具将 Raspberry Pi OS Lite 镜像烧录到 Micro SD卡中。烧录完成后先别急着拔卡。为了能无头启动无显示器键盘我们需要在SD卡的boot分区在电脑上可直接访问做两件事新建一个名为ssh的空文件无后缀以启用SSH服务。新建一个名为wpa_supplicant.conf的文件内容如下用于自动连接Wi-FicountryCN ctrl_interfaceDIR/var/run/wpa_supplicant GROUPnetdev update_config1 network{ ssid你的Wi-Fi名称 psk你的Wi-Fi密码 key_mgmtWPA-PSK }将ssid和psk替换成你自家的信息。如果你的网络没有密码key_mgmt设为NONE并去掉psk行。完成以上操作后将SD卡插入树莓派连接屏幕最后上电。屏幕可能会亮起或闪一下但此时还没有我们的程序所以不会有内容显示。接下来在你的电脑上使用SSH客户端如PuTTY或终端命令ssh piraspberrypi.local连接树莓派。默认用户名是pi密码是raspberry。首次登录后会提示修改密码请务必修改。3.2 驱动屏幕与安装Python环境连接成功后首先更新系统并安装必要的软件包sudo apt update sudo apt upgrade -y sudo apt install python3-pip python3-venv python3-pil python3-numpy -y然后我们需要安装屏幕的驱动库。对于常见的ST7789V驱动芯片的1.3寸屏可以使用st7789这个Python库。同时我们还需要psutil来获取系统信息。pip3 install st7789 psutil注意有些屏幕可能需要先启用SPI接口并加载设备树覆盖Device Tree Overlay。你可以通过运行sudo raspi-config进入Interface Options-SPI选择Yes来启用。但很多针对树莓派优化的屏幕库如st7789已经内置了相关设置在代码中初始化时会自动处理。如果屏幕点亮后白屏或花屏可以查阅屏幕卖家提供的资料确认是否需要额外的配置。3.3 核心代码解析与编写现在我们来编写核心的Python脚本比如命名为traffic_monitor.py。这个脚本的逻辑是初始化屏幕 - 进入无限循环 - 获取流量数据 - 计算速率 - 在内存中绘制图像 - 将图像刷新到屏幕。#!/usr/bin/env python3 import time import psutil from PIL import Image, ImageDraw, ImageFont import ST7789 as st7789 # 导入屏幕驱动库名称可能因库而异 # 1. 初始化屏幕 # 以下参数需要根据你的具体屏幕型号调整请参考屏幕库的文档 disp st7789.ST7789( height240, width240, rotation90, # 屏幕旋转角度根据你的安装方向调整 port0, cs0, # 片选引脚 dc24, # 数据/命令引脚 spi_speed_hz60 * 1000 * 1000 # SPI速度 ) disp.begin() # 2. 准备绘图对象和字体 # 创建一个与屏幕同大小的黑色背景图像 image Image.new(RGB, (disp.width, disp.height), (0, 0, 0)) draw ImageDraw.Draw(image) # 尝试加载中文字体如果不行则使用默认字体 try: font ImageFont.truetype(/usr/share/fonts/truetype/wqy/wqy-microhei.ttc, 18) except: font ImageFont.load_default() font_small ImageFont.truetype(/usr/share/fonts/truetype/wqy/wqy-microhei.ttc, 14) if font in locals() else ImageFont.load_default() # 3. 初始化变量 # 监控的网卡名称通常是 eth0 (有线) 或 wlan0 (无线)。使用 ifconfig 命令查看。 INTERFACE eth0 prev_bytes_sent 0 prev_bytes_recv 0 history_length 60 # 记录60个历史数据点过去60秒 upload_history [0] * history_length download_history [0] * history_length def get_network_speed(interface): 获取指定接口的瞬时上传下载速度字节/秒 global prev_bytes_sent, prev_bytes_recv counters psutil.net_io_counters(pernicTrue).get(interface) if not counters: return 0, 0 current_sent counters.bytes_sent current_recv counters.bytes_recv # 计算差值字节数 delta_sent current_sent - prev_bytes_sent delta_recv current_recv - prev_bytes_recv # 更新上一次的字节数 prev_bytes_sent current_sent prev_bytes_recv current_recv # 返回速度字节/秒。注意这里假设函数每秒被调用一次。 # 如果调用间隔不是1秒需要除以时间间隔。 return delta_sent, delta_recv def draw_speed_graph(draw, history, color, y_offset, max_speed): 绘制速度历史曲线图 graph_width 200 graph_height 80 graph_x 20 graph_y y_offset # 绘制背景框 draw.rectangle([graph_x, graph_y, graph_xgraph_width, graph_ygraph_height], outline(50,50,50), width1) if max_speed 0: max_speed 1 # 避免除零错误 points [] for i, value in enumerate(history): x graph_x int((i / (history_length - 1)) * graph_width) # 归一化高度留一点顶部边距 y graph_y graph_height - int((value / max_speed) * (graph_height - 5)) points.append((x, y)) if len(points) 1: draw.line(points, fillcolor, width2) def format_speed(bytes_per_sec): 将字节/秒格式化为易读的字符串如 KB/s, MB/s if bytes_per_sec 1024: return f{bytes_per_sec:.1f} B/s elif bytes_per_sec 1024 * 1024: return f{bytes_per_sec / 1024:.1f} KB/s else: return f{bytes_per_sec / (1024 * 1024):.1f} MB/s # 4. 主循环 print(流量监控仪表盘已启动按 CtrlC 退出。) try: while True: # 获取当前速度 up_speed, down_speed get_network_speed(INTERFACE) # 更新历史数据先进先出 upload_history.pop(0) download_history.pop(0) upload_history.append(up_speed) download_history.append(down_speed) # 计算当前历史数据的最大值用于动态调整曲线比例 max_history max(max(upload_history), max(download_history), 1) # --- 开始绘制新的一帧 --- # 清空画布用黑色填充 draw.rectangle([0, 0, disp.width, disp.height], fill(0, 0, 0)) # 绘制标题 draw.text((10, 5), f接口: {INTERFACE}, fontfont, fill(255, 255, 255)) # 绘制实时速度文本 draw.text((20, 35), f↑ {format_speed(up_speed)}, fontfont, fill(0, 255, 0)) # 上传用绿色 draw.text((20, 60), f↓ {format_speed(down_speed)}, fontfont, fill(0, 150, 255)) # 下载用蓝色 # 绘制上传/下载历史曲线 draw_speed_graph(draw, upload_history, (0, 255, 0), 100, max_history) # 上传曲线 draw_speed_graph(draw, download_history, (0, 150, 255), 190, max_history) # 下载曲线位置在下 # 将绘制好的图像显示到屏幕上 disp.display(image) # 等待1秒 time.sleep(1) except KeyboardInterrupt: print(\n程序被用户中断。) disp.reset() # 清理屏幕 disp.cleanup()代码关键点解析数据采集与计算psutil.net_io_counters(pernicTrue)返回每个网络接口累计的字节数。我们每秒调用一次用当前值减去上一秒的值就得到了这一秒内的流量字节数即速度字节/秒。这是最核心的计算逻辑。历史记录与曲线我们使用两个固定长度的列表 (upload_history,download_history) 来存储最近60秒的速度值。每次绘制时将这些值归一化到图表的高度连接成线就形成了动态曲线。曲线图的最大值 (max_history) 是动态计算的这样图表能自适应流量高峰始终充满画面。绘图与刷新所有绘制操作都在内存中的Image对象上完成。先画背景再画文字最后画曲线。完成一帧的所有绘制后调用disp.display(image)一次性刷新到屏幕。这种方式双缓冲可以避免屏幕闪烁。资源管理脚本被CtrlC中断时会执行disp.reset()和disp.cleanup()这是一个好习惯确保GPIO引脚被正确释放避免下次启动时出现问题。3.4 设置为自启动服务我们肯定不希望每次树莓派重启后都要手动登录运行脚本。将其设置为系统服务是最佳实践。创建一个服务文件sudo nano /etc/systemd/system/traffic-board.service写入以下内容[Unit] DescriptionTraffic Control Mini Board Service Afternetwork.target [Service] Typesimple Userpi WorkingDirectory/home/pi ExecStart/usr/bin/python3 /home/pi/traffic_monitor.py Restartalways RestartSec10 StandardOutputjournal StandardErrorjournal [Install] WantedBymulti-user.target保存退出后启用并启动这个服务sudo systemctl daemon-reload sudo systemctl enable traffic-board.service sudo systemctl start traffic-board.service现在你的流量迷你板就已经在后台默默运行了。你可以通过sudo systemctl status traffic-board.service查看运行状态或者sudo journalctl -u traffic-board.service -f实时查看日志。4. 进阶优化与个性化定制基础功能实现后我们可以根据个人需求进行各种“魔改”让这块小板子更加好用。4.1 监控多网卡与数据聚合如果你的设备有多个活跃接口比如eth0和wlan0你可能想同时监控或者监控它们的总和。修改get_network_speed函数和主循环逻辑即可。INTERFACES [eth0, wlan0] # 监控多个接口 def get_aggregated_speed(interfaces): total_up 0 total_down 0 for iface in interfaces: up, down get_network_speed_single(iface) # 假设这是获取单个接口速度的函数 total_up up total_down down return total_up, total_down然后在主循环中调用这个聚合函数并将结果显示为“总上传/总下载”。你还可以在屏幕上划分区域分别显示每个接口的速度这需要对UI布局进行重新设计。4.2 添加流量统计与阈值告警除了实时速度每日/每周的流量消耗也是有用的信息。我们可以将每秒的速度累加起来保存到文件或简单的数据库中如SQLite。同时可以设置速度阈值当超过阈值时改变屏幕颜色如变红或让某个LED闪烁如果接了LED的话进行告警。TOTAL_FILE /home/pi/traffic_total.json ALERT_THRESHOLD_KBPS 1024 * 10 # 告警阈值例如 10 MB/s daily_total_up 0 daily_total_down 0 # 在主循环中累加 daily_total_up up_speed / (1024*1024) # 转换为MB daily_total_down down_speed / (1024*1024) # 每小时或每天保存一次到文件 if time.time() - last_save_time 3600: save_totals_to_file() # 阈值判断 if up_speed ALERT_THRESHOLD_KBPS * 1024 or down_speed ALERT_THRESHOLD_KBPS * 1024: draw.rectangle([0,0,disp.width, disp.height], outline(255,0,0), width5) # 画一个红色边框4.3 美化UI与信息丰富化当前的UI比较朴素。你可以利用PIL的强大功能进行美化使用更美观的字体安装并引用一些等宽或设计字体。绘制更精致的图表将折线图改为面积图添加网格线在曲线旁边标注峰值。显示更多系统信息在屏幕空白处可以轮播显示CPU温度、内存使用率、系统负载、磁盘空间等信息。psutil库可以轻松获取这些数据。添加交互功能通过外接一个按钮短按切换显示的信息页面如从流量切换到系统状态长按重置流量统计等。4.4 功耗与稳定性优化对于需要长期24小时运行的项目稳定性至关重要。降低CPU占用我们的主循环是time.sleep(1)每秒刷新一次对于流量监控来说足够流畅且CPU占用极低通常1%。不要尝试毫秒级刷新毫无必要且增加功耗。防止内存泄漏确保在循环中创建的大对象如图像对象被正确复用或释放。我们的代码中Image和ImageDraw对象是在循环外创建的每次只是覆盖内容这是正确的做法。看门狗与自动恢复虽然我们设置了Restartalways但极端情况下服务可能僵死。可以考虑使用硬件看门狗如果主板支持或者写一个简单的监控脚本定期检查服务状态并重启。电源选择使用质量可靠的5V/2A以上的电源适配器。如果担心停电可以为树莓派配备一个小型UPS不间断电源模块。5. 项目总结与延伸思考经过从硬件选型、系统配置、代码编写到服务部署的完整流程一个功能实用、外观小巧的流量控制迷你板就真正落地了。它静静地立在你的网络设备旁用跳动的曲线和数字为你提供最直观的网络状态感知。这个项目的价值不仅在于结果更在于过程——它完整地串联起了嵌入式Linux开发、Python应用编程、系统服务管理和硬件交互等多个环节。在实际部署和使用的几个月里我积累了几点非常具体的经验第一关于网卡名称的“坑”。在最新的Raspberry Pi OS中有线网卡的默认名称可能不再是eth0而是根据MAC地址生成的类似enx00e04c680f6a这样的名字。使用ip addr或ifconfig命令查看准确的接口名并相应修改脚本中的INTERFACE变量。否则你的屏幕将永远显示零流量。第二SPI屏幕的初始化参数是关键。不同厂家、不同批次的屏幕其驱动芯片、复位引脚RST、数据/命令引脚DC可能不同。如果屏幕点亮后白屏、花屏或者颜色错乱第一要怀疑的就是初始化ST7789对象时的参数dc,rst,rotation等。务必以屏幕卖家提供的示例代码或资料为准。有时还需要在/boot/config.txt中添加设备树覆盖dtoverlay配置。第三后台服务的日志很重要。将服务标准输出重定向到journal后一定要学会使用journalctl命令查看日志。当屏幕不显示时首先sudo systemctl status traffic-board.service看服务是否在运行然后sudo journalctl -u traffic-board.service -n 50查看最近50行日志里面很可能藏着导入错误、权限错误或者硬件初始化失败的线索。这个迷你板本身是一个完美的起点它的可能性远不止于流量监控。其本质是一个基于小型Linux系统和显示屏的通用信息展示终端。你可以很容易地修改Python脚本将其变成一个服务器状态看板显示CPU、内存、磁盘、服务状态。智能家居中枢显示器通过MQTT订阅家庭物联网设备的状态并展示。日历与天气站结合网络API显示日程和实时天气。CI/CD构建状态指示灯监控Jenkins或GitLab CI的流水线状态用颜色表示成功/失败。硬件上你也可以升级为电子墨水屏e-ink以实现超低功耗常显或者增加物理按钮、旋钮来增强交互。软件上可以考虑用更高效的编程语言如Go重写核心循环或者用Web技术如Flask 本地浏览器来构建UI实现更复杂的数据展示和远程配置。从一块小小的屏幕开始连接上网络与数据它就成为了你透视数字世界的一个窗口。这种将抽象数据转化为具象感知的过程正是嵌入式项目和创客精神的魅力所在。希望这个详细的构建指南能帮助你顺利打造出属于自己的那一块“网络仪表盘”。