Compare commits

...
3 Commits
5 changed files with 24 additions and 4 deletions
+5
View File
@@ -0,0 +1,5 @@
# pigway-console-adapter-raspberry-pi v1.3.0
2026-10-15 已与 Console v2.4.0 部署。声明每秒缓存读取并透传 Agent 的 system/network 真实采样时间。树莓派网络仍每 5 秒采样,历史去重验证通过。
生产两设备在线。认证 API 连续观测确认树莓派缓存每秒、网络 5 秒、NAS 实时约 10 秒;最近三个网络 10 秒历史桶各 2 个样本,没有每秒重复入库。Console 保留原名称、证书、存储缓存和一年历史策略。部署详情见 Console [生产记录](https://tea.pigway.com/way/pigway-device-console/src/branch/main/docs/DEPLOYMENT-v2.4.0-2026-10-15.md)。
+2
View File
@@ -32,3 +32,5 @@ v1.1.0 已与 Console v2.1.0 部署,真实树莓派在线并开始记录历史
当前网络卡片以实时上下行速率为主文字,详见 [v1.2.1 部署记录](DEPLOYMENT-v1.2.1-2026-10-14.md)。 当前网络卡片以实时上下行速率为主文字,详见 [v1.2.1 部署记录](DEPLOYMENT-v1.2.1-2026-10-14.md)。
网络连接文案统一为接口链路状态,见 [v1.2.2](DEPLOYMENT-v1.2.2-2026-10-14.md)。 网络连接文案统一为接口链路状态,见 [v1.2.2](DEPLOYMENT-v1.2.2-2026-10-14.md)。
生产 v1.3.0 与按设备周期采集的核验见 [部署记录](DEPLOYMENT-v1.3.0-2026-10-15.md)。
+2 -2
View File
@@ -1,7 +1,7 @@
{ {
"id": "pigway-agent", "id": "pigway-agent",
"name": "PIGWay Raspberry Pi Agent", "name": "PIGWay Raspberry Pi Agent",
"version": "1.3.0", "version": "1.3.2",
"protocol_version": 1, "protocol_version": 1,
"entrypoint": "worker.py", "entrypoint": "worker.py",
"runtime": "python3", "runtime": "python3",
@@ -40,6 +40,6 @@
}, },
"legacy_connection_fields": true, "legacy_connection_fields": true,
"collection": { "collection": {
"interval_seconds": 1 "interval_seconds": 4
} }
} }
+9 -1
View File
@@ -56,6 +56,14 @@ def request(device, endpoint, method='GET', payload=None, query=None):
raise AdapterError('RESULT_UNKNOWN' if method == 'PUT' else 'DEVICE_UNAVAILABLE') from None raise AdapterError('RESULT_UNKNOWN' if method == 'PUT' else 'DEVICE_UNAVAILABLE') from None
def collection_interval(value):
declaration = value.get('collection', {})
interval = declaration.get('interval_seconds') if isinstance(declaration, dict) else None
if not isinstance(interval, (int, float)) or isinstance(interval, bool) or not math.isfinite(interval) or not 1 <= interval <= 3600:
interval = MANIFEST['collection']['interval_seconds']
return max(MANIFEST['collection']['interval_seconds'], interval)
def collect(device): def collect(device):
value = request(device, '/status') value = request(device, '/status')
if not isinstance(value.get('system'), dict) or not isinstance(value.get('machine'), dict): if not isinstance(value.get('system'), dict) or not isinstance(value.get('machine'), dict):
@@ -88,7 +96,7 @@ def collect(device):
return {'schema_version': 1, 'observed_at': value.get('timestamp'), return {'schema_version': 1, 'observed_at': value.get('timestamp'),
'identity': {'reported_name': value['machine'].get('name'), 'category': 'host', 'identity': {'reported_name': value['machine'].get('name'), 'category': 'host',
'details': value.get('device', {})}, 'details': value.get('device', {})},
'collection': value.get('collection', MANIFEST['collection']), 'collection': {'interval_seconds': collection_interval(value)},
'capabilities': MANIFEST['capabilities'], 'metrics': metrics, 'capabilities': MANIFEST['capabilities'], 'metrics': metrics,
'resources': [{'id': 'host', 'type': 'host'}], 'resources': [{'id': 'host', 'type': 'host'}],
'alerts': value.get('display', {}).get('alerts', []), 'alerts': value.get('display', {}).get('alerts', []),
+6 -1
View File
@@ -21,9 +21,14 @@ class MetricsTests(unittest.TestCase):
self.assertEqual(values['network_rx_bytes_per_second'],0) self.assertEqual(values['network_rx_bytes_per_second'],0)
self.assertEqual(values['network_tx_bytes_per_second'],1234) self.assertEqual(values['network_tx_bytes_per_second'],1234)
self.assertEqual(next(m['observed_at'] for m in result['metrics'] if m['key']=='network_tx_bytes_per_second'),120) self.assertEqual(next(m['observed_at'] for m in result['metrics'] if m['key']=='network_tx_bytes_per_second'),120)
self.assertEqual(result['collection']['interval_seconds'],1) self.assertEqual(result['collection']['interval_seconds'],4)
self.assertTrue(result['alerts_complete']) self.assertTrue(result['alerts_complete'])
def test_collection_minimum_and_slower_device(self):
self.assertEqual(worker.collection_interval({'collection':{'interval_seconds':1}}),4)
self.assertEqual(worker.collection_interval({'collection':{'interval_seconds':5}}),5)
self.assertEqual(worker.collection_interval({'collection':{'interval_seconds':True}}),4)
def test_absent_or_boolean_fields_not_invented(self): def test_absent_or_boolean_fields_not_invented(self):
value={'system': {'cpu_percent': True}, 'machine':{}, 'network': {'link_speed_mbps': None, 'rx_bytes_per_second':float('nan'), 'tx_bytes_per_second':True}} value={'system': {'cpu_percent': True}, 'machine':{}, 'network': {'link_speed_mbps': None, 'rx_bytes_per_second':float('nan'), 'tx_bytes_per_second':True}}
with patch.object(worker,'request',return_value=value): result=worker.collect({}) with patch.object(worker,'request',return_value=value): result=worker.collect({})