Skip to content

Commit 42eb63e

Browse files
feat(api): extend GET /instruments with classes and channel paths from manifests
- Reads manifest instrument_class features.channels - Builds channel URLs for each class Co-authored-by: openhands <openhands@all-hands.dev>
1 parent f92ad5a commit 42eb63e

6 files changed

Lines changed: 64 additions & 34 deletions

File tree

benchmesh-serial-service/src/benchmesh_service/api.py

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import os
22
import json
3-
from typing import Any
3+
from typing import Any, Dict, List
44
from fastapi import FastAPI, HTTPException, Response
5-
from .serial_manager import SerialManager
5+
from .serial_manager import SerialManager, _load_manifest
66
from .config import load_config
77

88
app = FastAPI(title="BenchMesh Serial Service", version="0.1.0")
@@ -89,9 +89,50 @@ def get_status():
8989
def list_instruments():
9090
global _manager
9191
items = []
92-
if _manager and getattr(_manager, 'registry', None):
93-
for dev_id, data in _manager.registry.items():
94-
items.append({"id": dev_id, "IDN": data.get("IDN")})
92+
if not _manager:
93+
return items
94+
95+
registry = getattr(_manager, 'registry', {}) or {}
96+
for dev in _manager.devices:
97+
dev_id = dev.get('id')
98+
if not dev_id:
99+
continue
100+
entry: Dict[str, Any] = {"id": dev_id}
101+
reg_data = registry.get(dev_id, {})
102+
if 'IDN' in reg_data:
103+
entry['IDN'] = reg_data['IDN']
104+
105+
# Attempt to populate classes/channels from manifest based on device driver and model
106+
try:
107+
driver_key = dev.get('driver')
108+
manifest = _load_manifest(driver_key) if driver_key else None
109+
except Exception:
110+
manifest = None
111+
classes_list: List[Dict[str, Any]] = []
112+
if isinstance(manifest, dict):
113+
models = manifest.get('models') or {}
114+
model_key = dev.get('model')
115+
model_cfg = None
116+
if model_key and isinstance(models.get(model_key), dict):
117+
model_cfg = models.get(model_key)
118+
elif isinstance(models, dict) and models:
119+
# fallback to first model entry
120+
model_cfg = next(iter(models.values()))
121+
if isinstance(model_cfg, dict):
122+
inst_class_block = model_cfg.get('instrument_class') or {}
123+
for klass, klass_cfg in inst_class_block.items():
124+
features = (klass_cfg or {}).get('features') or {}
125+
channels = int(features.get('channels', 1) or 1)
126+
# Build channel paths
127+
ch_paths = [f"/instruments/{klass}/{dev_id}/{i+1}" for i in range(max(1, channels))]
128+
classes_list.append({
129+
"class": klass,
130+
"channels": ch_paths,
131+
})
132+
if classes_list:
133+
entry['classes'] = classes_list
134+
135+
items.append(entry)
95136
return items
96137

97138

benchmesh-serial-service/src/benchmesh_service/drivers/owon_dge/manifest.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@
1616
"reol": "\r",
1717
"def_conn_ver_command": "*IDN?"
1818
},
19+
"pooling": [
20+
{
21+
"method": "poll_status",
22+
"interval": 0.9
23+
}
24+
],
1925
"instrument_class": {
2026
"AFG": {
2127
"features": {

benchmesh-serial-service/src/benchmesh_service/drivers/owon_oel/manifest.json

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,24 +18,8 @@
1818
},
1919
"pooling": [
2020
{
21-
"command": "MEAS:VOLT?",
22-
"name": "output_voltage_1",
23-
"every": 0.9
24-
},
25-
{
26-
"command": "MEAS:CURR?",
27-
"name": "output_current_1",
28-
"every": 0.9
29-
},
30-
{
31-
"command": "MEAS:POWer?",
32-
"name": "output_power_1",
33-
"every": 0.9
34-
},
35-
{
36-
"command": "MEAS:ALL:INFO?",
37-
"name": "output_status_1",
38-
"every": 0.9
21+
"method": "poll_status",
22+
"interval": 0.9
3923
}
4024
],
4125
"instrument_class": {

benchmesh-serial-service/src/benchmesh_service/drivers/owon_spm/manifest.json

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,14 @@
1919
},
2020
"pooling": [
2121
{
22-
"command": "read_status",
23-
"name": "status_1",
24-
"every": 0.9
22+
"method": "poll_status",
23+
"interval": 0.9
2524
}
2625
],
2726
"instrument_class": {
2827
"PSU": {
2928
"features": {
30-
"channels": 1,
29+
"channels": 2,
3130
"memory_banks": 4,
3231
"memory_storage": [
3332
"V",

benchmesh-serial-service/src/benchmesh_service/drivers/owon_xdm/manifest.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@
1616
"reol": "\r",
1717
"def_conn_ver_command": "*IDN?"
1818
},
19+
"pooling": [
20+
{
21+
"method": "poll_status",
22+
"interval": 0.9
23+
}
24+
],
1925
"instrument_class": {
2026
"DMM": {
2127
"features": {

benchmesh-serial-service/src/benchmesh_service/drivers/tenma_72/manifest.json

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,7 @@
1818
},
1919
"pooling": [
2020
{
21-
"method": "read_output_voltage",
22-
"name": "output_voltage_1",
23-
"interval": 0.9
24-
},
25-
{
26-
"method": "read_output_current",
27-
"name": "output_current_1",
21+
"method": "poll_status",
2822
"interval": 0.9
2923
}
3024
],

0 commit comments

Comments
 (0)