Skip to content

Commit f48c8bf

Browse files
committed
Regenerate pi-deployment bundle
1 parent b6d83d3 commit f48c8bf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+6490
-227
lines changed

pi-deployment/api/README.md

Lines changed: 151 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22

33
This folder contains the **network API layer** that exposes Rio hardware control and telemetry over HTTP/REST and WebSockets. It is designed to run alongside the existing Flask UI (`../rio-webapp/`) and provides a machine-readable interface for Jupyter notebooks, scripts, and external applications.
44

5-
**⚠️ Important:** The API currently uses **plain FastAPI** (standard REST endpoints). It is **NOT Web of Things (WoT) compatible**.
5+
**✅ Web of Things (WoT) Compatible:** The API uses **LabThings FastAPI** to expose controllers as WoT-compliant Things.
66

7-
- `labthings-fastapi` is installed as a dependency but **not used** in the code
8-
- The API uses standard FastAPI routes (`@app.get`, `@app.post`, etc.)
9-
- No LabThings "Things", "Properties", "Actions", or "Events" are exposed
10-
- WoT compatibility is planned as a future enhancement (see "Future enhancements" section)
7+
- Controllers are wrapped as LabThings Things (FlowThing, HeaterThing, CameraThing, etc.)
8+
- Auto-generated Thing Descriptions (TD) for each Thing
9+
- Standard WoT properties, actions, and events
10+
- OpenAPI/Swagger documentation + Thing Description JSON
11+
- Custom endpoints remain at `/api/` prefix for backward compatibility
1112

1213
## Quick Start
1314

@@ -27,15 +28,24 @@ This folder contains the **network API layer** that exposes Rio hardware control
2728
# Or directly
2829
python -m api.main
2930
```
31+
Optional pump enable (USB serial):
32+
```bash
33+
export RIO_PUMP_ENABLED=true
34+
# export RIO_PUMP_PORT=/dev/ttyUSB0
35+
```
3036

3137
3. **Test the API:**
3238
```bash
3339
curl http://localhost:8000/api/system/health
40+
# Or test WoT Thing:
41+
curl http://localhost:8000/flow/
3442
```
3543

3644
4. **View API documentation:**
3745
- Swagger UI: http://localhost:8000/docs
3846
- ReDoc: http://localhost:8000/redoc
47+
- Thing Descriptions: http://localhost:8000/thing_descriptions/
48+
- Individual Thing: http://localhost:8000/flow/ (FlowThing TD)
3949

4050
### Raspberry Pi Deployment
4151

@@ -53,6 +63,11 @@ This folder contains the **network API layer** that exposes Rio hardware control
5363
export RIO_SIMULATION=false
5464
python3 -m api.main
5565
```
66+
Optional pump enable (USB serial):
67+
```bash
68+
export RIO_PUMP_ENABLED=true
69+
# export RIO_PUMP_PORT=/dev/ttyUSB0
70+
```
5671

5772
3. **Test from Pi:**
5873
```bash
@@ -75,12 +90,11 @@ This folder contains the **network API layer** that exposes Rio hardware control
7590

7691
**For detailed Pi installation and Jupyter access guide, see:** `../../docs/api_pi_testing_guide.md`
7792

78-
Note: the API client library and notebooks are not included in the deployment bundle.
79-
See the source repo at `software/api/client/README.md` for the client and examples.
93+
See `client/README.md` for the Python client library and example notebooks.
8094

8195
## What belongs here / what does not
8296

83-
- **Belongs here**: FastAPI routes, WebSocket handlers, request/response schemas (Pydantic models), API configuration, and streaming aggregators.
97+
- **Belongs here**: LabThings Thing classes, ThingServer setup, WebSocket handlers, request/response schemas (Pydantic models), API configuration, and streaming aggregators.
8498
- **Does not belong here**: Hardware drivers (belongs in `../drivers/`), device controllers (belongs in `../controllers/`), Flask routes (belongs in `../rio-webapp/`), and browser JavaScript (belongs in `../rio-webapp/static/`).
8599

86100
## Architecture and integration
@@ -93,10 +107,12 @@ The API layer sits **above** the device controllers (`../controllers/`) and **be
93107
└──────────────┬──────────────────────┘
94108
│ HTTP/REST + WebSocket
95109
┌──────────────▼──────────────────────┐
96-
│ software/api/ (this folder) │
97-
│ - FastAPI routes │
110+
│ software/api/ (this folder) │
111+
│ - LabThings ThingServer (WoT) │
112+
│ - Thing classes (FlowThing, etc.) │
98113
│ - WebSocket aggregator │
99114
│ - Request/response schemas │
115+
│ - Legacy /api/control/* routes │
100116
└──────────────┬──────────────────────┘
101117
│ Controller methods
102118
┌──────────────▼──────────────────────┐
@@ -114,28 +130,47 @@ The API **does not** call drivers directly; it calls into the controller layer,
114130

115131
## Key components
116132

117-
### `main.py`FastAPI application and routes
133+
### `main.py`LabThings ThingServer and routes
118134

119-
- **Entry point**: `create_app()` returns a FastAPI instance with all routes registered.
135+
- **Entry point**: `create_app()` returns a FastAPI instance with LabThings ThingServer integration.
120136
- **Controller initialization**: Controllers are instantiated at import time (similar to `software/main.py`) so capabilities reflect actual hardware availability.
121-
- **REST endpoints**:
137+
- **WoT Things** (auto-generated routes by LabThings):
138+
- `/flow/` — FlowThing (flow/pressure control)
139+
- `/heater/` — HeaterThing (heater control)
140+
- `/camera/` — CameraThing (camera and strobe control)
141+
- `/droplet/` — DropletThing (droplet detection)
142+
- `/pump/` — PumpThing (placeholder for future pump support)
143+
- **Custom endpoints** (backward compatibility):
122144
- `/api/system/health` — Health check
123145
- `/api/system/capabilities` — Available modules
124146
- `/api/config/channels` — Channel metadata (names, liquid types, calibration factors)
125-
- `/api/control/flow/*` — Flow/pressure control
126-
- `/api/control/heater/*` — Heater control
127-
- `/api/control/camera/*` — Camera control (resolution, ROI, snapshot)
128-
- `/api/control/strobe/*` — Strobe control (enable, hold, timing)
129-
- `/api/control/droplet/*` — Droplet detection control
130-
- `/api/control/pump/*` — Syringe pump control (placeholder, returns 501 until driver implemented)
131-
- `/api/streams/camera/snapshot` — JPEG snapshot endpoint
147+
- `/api/streams/aggregate` — WebSocket aggregator for sensor data
132148
- `/api/data/capture/*` — On-demand CSV capture control
149+
- **WoT endpoints** (auto-generated):
150+
- `/thing_descriptions/` — All Thing Descriptions
151+
- `/docs` — OpenAPI/Swagger UI
152+
- `/openapi.json` — OpenAPI specification
153+
154+
### `things/` — LabThings Thing classes
155+
156+
WoT-compliant Thing classes that wrap controllers:
157+
- **`flow_thing.py`**: FlowThing — flow/pressure control (properties: `state`, actions: `set_pressure`, `set_flow`, `set_mode`, `set_pi_consts`)
158+
- **`heater_thing.py`**: HeaterThing — heater control (properties: `state`, actions: `set_temp`, `set_pid`, `set_stir`)
159+
- **`camera_thing.py`**: CameraThing — camera/strobe control (actions: `snapshot`, `set_resolution`, `set_roi`, `strobe_enable`, etc.)
160+
- **`droplet_thing.py`**: DropletThing — droplet detection (properties: `status`, `statistics`, `histogram`, actions: `start`, `stop`)
161+
- **`pump_thing.py`**: PumpThing — placeholder for future pump support
162+
163+
Each Thing exposes:
164+
- **Properties**: Readable state (e.g., `GET /flow/state`)
165+
- **Actions**: Invocable methods (e.g., `POST /flow/set_pressure`)
166+
- **Thing Description**: Machine-readable WoT TD at `/flow/`, `/heater/`, etc.
133167

134168
### `schemas.py` — Request/response models
135169

136-
Pydantic models for all API requests and responses. These provide:
170+
Pydantic models for API requests and responses. Used by both Things and custom endpoints:
137171
- **Type validation**: Automatic validation of request bodies and query parameters
138172
- **OpenAPI documentation**: FastAPI auto-generates OpenAPI/Swagger docs from these models
173+
- **Thing Descriptions**: LabThings uses these models in WoT TD generation
139174
- **Clear contracts**: Explicit data structures for clients
140175

141176
Key models:
@@ -237,16 +272,21 @@ channels:
237272
- `POST /api/control/heater/set_temp` — Set target temperature
238273
- `POST /api/control/heater/pid` — Enable/disable PID
239274
- `POST /api/control/heater/stir` — Enable/disable stirrer
275+
- `POST /api/control/heater/power_limit` — Set heater power limit (%)
276+
- `POST /api/control/heater/autotune` — Start/stop autotune
240277

241278
### Camera/Strobe control
242279
- `GET /api/streams/camera/snapshot` — Get JPEG snapshot
243280
- `POST /api/control/camera/set_resolution` — Set display resolution
244281
- `POST /api/control/camera/set_snapshot_resolution` — Set snapshot resolution mode
245282
- `POST /api/control/camera/roi` — Set ROI
246283
- `POST /api/control/camera/roi/clear` — Clear ROI
284+
- `GET /api/control/camera/state` — Get camera state (for remote UI)
285+
- `POST /api/control/camera/select` — Select camera backend
247286
- `POST /api/control/strobe/enable` — Enable/disable strobe
248287
- `POST /api/control/strobe/hold` — Enable/disable hold mode
249288
- `POST /api/control/strobe/timing` — Set strobe timing (period, wait)
289+
- `GET /api/control/strobe/state` — Get strobe state (for remote UI)
250290

251291
### Droplet detection
252292
- `POST /api/control/droplet/start` — Start detection
@@ -256,11 +296,17 @@ channels:
256296
- `GET /api/control/droplet/statistics` — Get statistics
257297
- `GET /api/control/droplet/performance` — Get performance metrics
258298

259-
### Pump control (placeholder)
260-
- `GET /api/control/pump/state/{pump}` — Get pump state (returns 501)
261-
- `POST /api/control/pump/set_flow` — Set flow (returns 501)
262-
- `POST /api/control/pump/set_diameter` — Set diameter (returns 501)
263-
- ... (all pump endpoints return 501 until driver implemented)
299+
### Pump control (USB serial)
300+
- `GET /api/control/pump/state/{pump}` — Get pump state
301+
- `POST /api/control/pump/set_flow` — Set flow
302+
- `POST /api/control/pump/set_diameter` — Set diameter
303+
- `POST /api/control/pump/set_direction` — Set direction (infuse/withdraw)
304+
- `POST /api/control/pump/set_state` — Start/stop
305+
- `POST /api/control/pump/set_unit` — Set unit
306+
- `POST /api/control/pump/set_gearbox` — Set gearbox
307+
- `POST /api/control/pump/set_microstep` — Set microstep
308+
- `POST /api/control/pump/set_threadrod` — Set threadrod
309+
- `POST /api/control/pump/set_enable` — Enable/disable
264310

265311
### Streaming and capture
266312
- `WS /api/streams/aggregate` — WebSocket aggregator (flow/pressure/heater telemetry)
@@ -272,7 +318,7 @@ channels:
272318

273319
### Python client library
274320

275-
A lightweight client library is available at `../client/api_client.py`:
321+
A lightweight client library is available at `client/api_client.py`:
276322
- `RioClient` — REST API client with error handling and retry logic
277323
- `RioStreamClient` — WebSocket aggregator client with thread-safe message queue
278324

@@ -292,11 +338,11 @@ for msg in stream.iter_messages(timeout=10.0):
292338
print(f"{msg['topic']}: {msg['value']}")
293339
```
294340

295-
See the source repo at `software/api/client/README.md` for complete client documentation.
341+
See `client/README.md` for complete documentation.
296342

297343
### Jupyter notebooks
298344

299-
Two example notebooks are available in the source repo under `software/api/client/notebooks/`:
345+
Two example notebooks are available in `software/api/client/notebooks/` (repo root path):
300346

301347
1. **`tutorial.ipynb`** — Step-by-step learning notebook:
302348
- REST API control (flow, heater, camera)
@@ -310,6 +356,74 @@ Two example notebooks are available in the source repo under `software/api/clien
310356
- Camera snapshot capture
311357
- Emergency stop button
312358

359+
### Testing with Jupyter Notebooks in Simulation Mode
360+
361+
To test the API using Jupyter notebooks in simulation mode (without hardware):
362+
363+
1. **Start the API server in simulation mode** (in a terminal):
364+
```bash
365+
cd software
366+
export RIO_SIMULATION=true
367+
python -m api.main
368+
```
369+
The server will start on `http://localhost:8000`. You should see:
370+
```
371+
INFO: Uvicorn running on http://0.0.0.0:8000
372+
```
373+
374+
2. **Install Jupyter** (if not already installed in your environment):
375+
```bash
376+
pip install jupyter jupyterlab ipywidgets matplotlib pandas numpy
377+
```
378+
379+
3. **Open a Jupyter notebook** (in a new terminal, same environment):
380+
```bash
381+
cd software
382+
# Make sure you're in the same environment (rio-simulation)
383+
mamba activate rio-simulation # if not already activated
384+
jupyter notebook
385+
```
386+
Or use JupyterLab:
387+
```bash
388+
jupyter lab
389+
```
390+
391+
3. **Navigate to the client notebooks**:
392+
- Open `api/client/notebooks/tutorial.ipynb` or `api/client/notebooks/interactive_control.ipynb`
393+
- Or create a new notebook
394+
395+
4. **Set up the client in the notebook**:
396+
```python
397+
import sys
398+
# Add client library to path
399+
sys.path.insert(0, '/path/to/rio-controller/software')
400+
401+
from api.client import RioClient, RioStreamClient
402+
403+
# Connect to local API server
404+
API_BASE_URL = "http://localhost:8000"
405+
client = RioClient(base_url=API_BASE_URL)
406+
407+
# Test connection
408+
health = client.health()
409+
print(f"API Status: {health['status']}")
410+
print(f"Simulation Mode: {health['simulation']}")
411+
```
412+
413+
5. **Run the notebook cells**:
414+
- The notebooks will work with the simulation API
415+
- Flow, pressure, and heater controllers will use simulated hardware
416+
- Camera will use simulated frames (synthetic droplets)
417+
- All API endpoints are available and functional
418+
419+
**Note**: Keep the API server running in the terminal while using the notebook. If you stop the server, restart it and the notebook will reconnect automatically.
420+
421+
**Troubleshooting**:
422+
- **Connection refused**: Make sure the API server is running (`python -m api.main`)
423+
- **Module not found**: Make sure `software/` is in your Python path (see step 4)
424+
- **Import errors**: Install client dependencies: `pip install requests websocket-client`
425+
- **Notebook dependencies**: For plotting and widgets: `pip install matplotlib pandas numpy ipywidgets`
426+
313427
## Testing
314428

315429
API tests are in `../tests/test_api_streams.py`. Run with:
@@ -335,13 +449,13 @@ FastAPI automatically generates OpenAPI documentation. When the API server is ru
335449
## Dependencies
336450

337451
API-specific dependencies are in `requirements-api.txt`:
338-
- `fastapi==0.95.2` — Web framework (currently using plain FastAPI, not LabThings)
339-
- `uvicorn[standard]==0.21.1` — ASGI server
340-
- `labthings-fastapi==0.0.6` — **Installed but not used** (for future WoT integration)
341-
- `pydantic==1.10.14` — Data validation
342-
- `pyyaml` — Config file loading
452+
- `fastapi[all]>=0.115.0` — Web framework (supports Pydantic 2.x)
453+
- `uvicorn[standard]>=0.30.0` — ASGI server (compatible with FastAPI 0.115+)
454+
- `labthings-fastapi>=0.0.6` — **LabThings/WoT framework** (requires Pydantic 2.x)
455+
- `pydantic>=2.10.0` — Data validation (Pydantic 2.x, required by LabThings)
456+
- `pyyaml>=6.0` — Config file loading
343457

344-
**Current status:** The API uses standard FastAPI routes and does not expose LabThings "Things", "Properties", "Actions", or "Events". The `labthings-fastapi` package is included for future migration to WoT-compliant endpoints.
458+
**Current status:** The API uses LabThings ThingServer to expose controllers as WoT-compliant Things. Each controller is wrapped in a Thing class that exposes properties and actions according to the Web of Things standard.
345459

346460
Install with:
347461
```bash
@@ -414,11 +528,11 @@ client.capture_stop()
414528

415529
## Future enhancements
416530

417-
- **LabThings/WoT integration**: Expose Things, Properties, Actions, Events (WoT-compliant)
418531
- **Authentication**: Token-based or basic auth for LAN security
419532
- **Remote adapters**: Configuration-driven split-host deployment (Pi + external PC)
420-
- **Pump driver**: Implement syringe pump driver/controller to enable pump endpoints
533+
- **Pump driver**: Implement syringe pump driver/controller to enable PumpThing
421534
- **UI adapters**: Flask UI calls API instead of controllers directly (single-owner rule)
535+
- **ThingClient migration**: Update client library to use LabThings ThingClient for auto-generated clients
422536

423537
## AI-generated notice
424538

0 commit comments

Comments
 (0)