feat: sample Raspberry Pi primary interface traffic rates
This commit is contained in:
@@ -55,3 +55,7 @@ Logs follow the system journal retention policy; no additional database is creat
|
||||
## Naming and compatibility
|
||||
|
||||
This project targets Raspberry Pi. Other Linux platforms are not covered by its support claim and may have separately maintained adapters. Repository naming does not change the existing `pigway-agent` adapter ID or `pigway-pi-control` service, configuration and API identifiers.
|
||||
|
||||
## v3.8.0 网络流量
|
||||
|
||||
主接口每个网络采集周期读取 sysfs 的 rx_bytes/tx_bytes,以单调时间差计算字节/秒,API 新增 rx_bytes_per_second 和 tx_bytes_per_second。首次采样、接口切换、计数器重置或读取失败返回空值;不修改监控告警、硬件插件控制或 API 可选安装行为。2026-10-14 已在 Gateway 部署,实机上下行速率与 Console 标准历史指标验证通过。
|
||||
|
||||
+6
-3
@@ -1,14 +1,17 @@
|
||||
ecf1884bb89b86ed4573d4d922a971abde43772bf7b2ffa6a999a12fbfb72caf .gitignore
|
||||
d0e219b4b02b073f83e17ba3bb6e8c96dd4152ecdf11d946d53319613097e294 README.md
|
||||
56b7a3ed6a6a8dbbcf02a80b6219a5e6aab0df2ef04cdff90895784c311e5cfa README.md
|
||||
64a9708701f8c8d872a587e8a2845afff463797b06a2791319daadd705933d31 README.zh-CN.md
|
||||
852889cbbf57d5e857794432426e3343b5d08b1395b3098a6e19fd648b4f4267 app/pigway_pi_control.py
|
||||
c5853f283c0951b43f2bacbc49e66c26d3a605a184d427828e042eb9236d2740 app/network_rates.py
|
||||
003e6766552823e8cd8ec56888c385d0607df0c14ab7dff166472fcf6914ff9c app/pigway_pi_control.py
|
||||
757eb6a83ca07740a2389af9b51c6fd5d940b4eb86abbc603f231409416d45db app/pigway_pi_control_api.py
|
||||
3a8a368bbf299eb2d6cccc968a4aacf070058bddebdc5176083a97ac579d720d app/plugin_api.py
|
||||
d5a783b64a10fa43191a813ef73ef8f762e359b0bd42ec155724fa46216298b0 config/pigway-pi-control.conf
|
||||
9d45f22221012a7fdb3406ce74a6113f618e9930fe460efb3869efd099e3b1d8 docs/DEPLOYMENT-v3.8.0-2026-10-14.md
|
||||
e3bf3e7070ea62c0526791bed922688c3fb49fee36ca9c375d080119968feb72 docs/HARDWARE_PLUGIN_API.md
|
||||
b54ec1f3e9fb15473910686c54142a85d387e44ea5df427a4cf1b06052e789b3 docs/RASPBERRY_PI_OS_TRIXIE_FRESH_INSTALL.md
|
||||
9222a2b6a38f6b6d7d88b30c05413c68c05f69ee499c8479eca05ee7c62e87c3 docs/RASPBERRY_PI_OS_TRIXIE_FRESH_INSTALL.zh-CN.md
|
||||
d2706de954d0c3f1b4311c1bac52ef09b912919b96126fa6000a88786e969438 install.sh
|
||||
c104443a4c951ea7916f74473510362f684df7d916bf2a436b779513ba3fe396 install.sh
|
||||
8a593c290da5bd0d037aee86c35264512afd574a2a0f60f2c29e9db63e0109bd systemd/pigway-pi-control-api.service
|
||||
1cb55de6b104a233066495e9786319305fa4f1b6f25483c108ab4f5ac9aa5700 systemd/pigway-pi-control.service
|
||||
8b97229abfb31c68464eb5754bc3a8fec7a6a78e216d74a86b7cc89486700740 tests/test_network_rates.py
|
||||
9f59e7313ee58e687ae6dd29d175c67082674254ac5c5f54168b2735b64c20a4 uninstall.sh
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
"""Sample interface counters without summing physical and virtual interfaces."""
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class NetworkRates:
|
||||
def __init__(self, root='/sys/class/net'):
|
||||
self.root = Path(root)
|
||||
self.previous = None
|
||||
|
||||
def sample(self, interface, now):
|
||||
try:
|
||||
if not re.fullmatch(r'[\w.:-]{1,64}', interface):
|
||||
raise ValueError('invalid interface')
|
||||
directory = self.root / interface / 'statistics'
|
||||
rx = int((directory / 'rx_bytes').read_text())
|
||||
tx = int((directory / 'tx_bytes').read_text())
|
||||
if rx < 0 or tx < 0:
|
||||
raise ValueError('negative counter')
|
||||
except (OSError, ValueError, TypeError):
|
||||
self.previous = None
|
||||
return None, None
|
||||
previous = self.previous
|
||||
self.previous = interface, now, rx, tx
|
||||
if previous is None or previous[0] != interface or now <= previous[1]:
|
||||
return None, None
|
||||
elapsed = now - previous[1]
|
||||
return (None if rx < previous[2] else (rx - previous[2]) / elapsed,
|
||||
None if tx < previous[3] else (tx - previous[3]) / elapsed)
|
||||
@@ -1,11 +1,12 @@
|
||||
#!/usr/bin/env python3
|
||||
import time,socket,subprocess,configparser,signal,re,argparse,json,os,platform
|
||||
from pathlib import Path
|
||||
APP_VERSION="3.7.2"
|
||||
APP_VERSION="3.8.0"
|
||||
import sys
|
||||
sys.path.append("/usr/local/share/pigway-pi-control")
|
||||
from shutil import disk_usage
|
||||
from plugin_api import Publisher,registered,discover
|
||||
from network_rates import NetworkRates
|
||||
|
||||
CFG="/etc/pigway-pi-control.conf"
|
||||
STATUS_PATH="/run/pigway-pi-control/status.json"
|
||||
@@ -104,6 +105,8 @@ prev_cpu=None
|
||||
page=0; page_since=time.monotonic()
|
||||
cpu_hi=mem_hi=0
|
||||
net_ok=link_ok=True
|
||||
network_rates=NetworkRates()
|
||||
net_rx_bytes_per_second=None; net_tx_bytes_per_second=None
|
||||
net_iface=""; net_kind="NET"; net_metric="DOWN"; net_speed_mbps=None; ip_label="IP4"; ip="NO IP"
|
||||
link_failure_since=internet_failure_since=None
|
||||
wifi_weak_since=None; wifi_weak_active=False
|
||||
@@ -435,6 +438,8 @@ def write_status(cpu,temp,mem,disk):
|
||||
"power":health,
|
||||
"network":{"interface":net_iface,"kind":net_kind,"metric":net_metric,
|
||||
"link_speed_mbps":net_speed_mbps,
|
||||
"rx_bytes_per_second":net_rx_bytes_per_second,
|
||||
"tx_bytes_per_second":net_tx_bytes_per_second,
|
||||
"signal_percent":signal,
|
||||
"ip_label":ip_label,"ip":ip,"link":bool(link_ok),"internet":bool(net_ok)},
|
||||
"watches":[{"type":w[0],"name":w[1],"target":w[2],"up":bool(ok)}
|
||||
@@ -484,6 +489,7 @@ try:
|
||||
if now>=monitor_ready_at and now-last_net >= NETWORK_INTERVAL:
|
||||
old_id=(net_iface,ip)
|
||||
net_iface,net_kind,net_metric,net_speed_mbps,ip_label,ip=primary_network()
|
||||
net_rx_bytes_per_second,net_tx_bytes_per_second=network_rates.sample(net_iface,now)
|
||||
raw_link_ok=ip!="NO IP"; raw_net_ok=internet() if raw_link_ok else False
|
||||
if raw_link_ok:
|
||||
link_failure_since=None;link_ok=True
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
# Agent v3.8.0 网络流量
|
||||
|
||||
2026-10-14 Gateway 已部署。单独的 NetworkRates 模块读取主接口 sysfs 计数器;网络更新周期计算速率,写入已有状态/API。首次采样、接口切换、复位、读取失败不伪造零值。idle 返回真实 0。安装器加入模块依赖,保持 API 可选安装。采样测试覆盖初始、零流量、传输、复位、切换及失效;Python 编译、安装器语法检查通过。实机服务 active,状态版本 3.8.0、eth0 上传/下载数值有效,未发现本轮循环错误;Console 两设备在线,接入插件生成对应历史指标。
|
||||
|
||||
旧程序备份 `/home/way/pigway-agent-backup-v3.8.0-20261014/pigway-pi-control`,目录 0700。仅更新监控程序和新增模块并重启监控服务,没有变更硬件插件或 API 配置。
|
||||
+2
-1
@@ -12,13 +12,14 @@ for arg in "$@"; do
|
||||
*) echo "ERROR: unknown option: $arg (hardware is installed separately)" >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
for required in app/pigway_pi_control.py app/plugin_api.py app/pigway_pi_control_api.py config/pigway-pi-control.conf systemd/pigway-pi-control.service systemd/pigway-pi-control-api.service; do
|
||||
for required in app/pigway_pi_control.py app/plugin_api.py app/network_rates.py app/pigway_pi_control_api.py config/pigway-pi-control.conf systemd/pigway-pi-control.service systemd/pigway-pi-control-api.service; do
|
||||
[ -f "$required" ] || { echo "ERROR: required file missing: $required" >&2; exit 1; }
|
||||
done
|
||||
[ "$(id -u)" -eq 0 ] || { echo 'ERROR: run installer as root' >&2; exit 1; }
|
||||
# The monitor has no I2C, GPIO, Pillow, smbus2 or cooling-board requirement.
|
||||
command -v python3 >/dev/null || { apt-get update; apt-get install -y python3; }
|
||||
mkdir -p /usr/local/share/pigway-pi-control
|
||||
install -m 0644 app/network_rates.py /usr/local/share/pigway-pi-control/network_rates.py
|
||||
install -m 0644 app/plugin_api.py /usr/local/share/pigway-pi-control/plugin_api.py
|
||||
install -m 0755 app/pigway_pi_control.py /usr/local/sbin/pigway-pi-control
|
||||
install -m 0755 app/pigway_pi_control_api.py /usr/local/sbin/pigway-pi-control-api
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import sys,unittest,tempfile
|
||||
from pathlib import Path
|
||||
sys.path.insert(0,str(Path(__file__).resolve().parents[1]/'app'))
|
||||
from network_rates import NetworkRates
|
||||
|
||||
class RatesTests(unittest.TestCase):
|
||||
def test_initial_idle_transfer_reset_and_switch(self):
|
||||
with tempfile.TemporaryDirectory() as root:
|
||||
def write(interface,rx,tx):
|
||||
p=Path(root)/interface/'statistics';p.mkdir(parents=True,exist_ok=True)
|
||||
(p/'rx_bytes').write_text(str(rx));(p/'tx_bytes').write_text(str(tx))
|
||||
write('eth0',1000,2000);sampler=NetworkRates(root)
|
||||
self.assertEqual(sampler.sample('eth0',10),(None,None))
|
||||
self.assertEqual(sampler.sample('eth0',15),(0,0))
|
||||
write('eth0',1500,3000)
|
||||
self.assertEqual(sampler.sample('eth0',20),(100,200))
|
||||
write('eth0',10,20)
|
||||
self.assertEqual(sampler.sample('eth0',25),(None,None))
|
||||
write('wlan0',100,200)
|
||||
self.assertEqual(sampler.sample('wlan0',30),(None,None))
|
||||
self.assertEqual(sampler.sample('missing',35),(None,None))
|
||||
self.assertEqual(sampler.sample('eth0',40),(None,None))
|
||||
self.assertEqual(sampler.sample('../eth0',45),(None,None))
|
||||
Reference in New Issue
Block a user