Skip to content

Commit 08c84f3

Browse files
committed
adding sdk info for imswitch
1 parent cfade58 commit 08c84f3

5 files changed

Lines changed: 335 additions & 0 deletions

File tree

docs/usage/disc/holobox/index.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,23 @@ These pages are written for **high-school students and their teachers**. You don
2020
![](./IMAGES/heroholo.jpg)
2121
**Show:** As part of the holobox you can build a Mach Zehnder Interferometer, where the camera acquires fringes.
2222

23+
24+
25+
26+
```
27+
Universität Münster
28+
Mathematisch-Naturwissenschaftliche Fakultät
29+
Institut der Didaktik für Physik
30+
Masterarbeit zum Thema:
31+
Entwicklung von Unterrichtsmaterialien für
32+
Experimente zur digitalen Inline-Holografie.
33+
Development of Teaching Materials for Experiments in Digital Inline Holography.
34+
Vorgelegt von:
35+
Clara Hofmann
36+
Hermannstraße 41, 48151 Münster
37+
clara.hofmann@uni-muenster.de
38+
```
39+
2340
## Where do I start?
2441

2542
This documentation is following Diataxis (https://diataxis.fr/) and is split into four kinds of page. Pick the one that matches what you want **right now**:

docs/usage/disc/infinity-addon/ABBE.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ You can access this model through the [openuc2 configurator](https://youseetoo.g
3636
![](./IMAGES/abbe_experiment.png)
3737

3838

39+
![](./IMAGES/abbesetup_new.png)
40+
3941
### Optical principle in a compact form
4042

4143
#### 1) Infinity-corrected imaging
2.89 MB
Loading
Lines changed: 316 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,316 @@
1+
# Accessing and Controlling an openUC2 / ImSwitch System (SDK)
2+
3+
## 1. Introduction
4+
5+
Every openUC2 microscope runs **ImSwitch**, a Python control server that exposes the
6+
complete instrument — stages, cameras, illumination, autofocus, acquisition workflows —
7+
over a **self-documenting HTTP REST API** plus a **Socket.IO real-time channel**.
8+
9+
There are four supported ways to work with the system, in increasing order of invasiveness:
10+
11+
| # | Approach | Use when |
12+
|---|----------|----------|
13+
| 1 | **REST API** (HTTP/JSON, OpenAPI 3 using swagger/fastapi) | Any language, any platform. The primary integration surface. |
14+
| 2 | **`imswitchclient`** (Python SDK, ) | You work in Python / Jupyter and want typed convenience wrappers. Src: http://github.com/openUC2/imswitchclient |
15+
| 3 | **Socket.IO / streaming channels** | You need live images, position updates, or state change notifications. |
16+
| 4 | **Plugin SDK / own controller** | You want to add new functionality *inside* the server and have it appear automatically in the API and UI. (testing phase) |
17+
18+
Below that sits the firmware layer ([UC2-ESP32](http://github.com/youseetoo/uc2-esp32) -> http://onlinelibrary.wiley.com/doi/full/10.1111/jmi.70147 over [USB-serial](http://github.com/openUC2/UC2-REST) or CAN ), which you normally should *not* address directly — ImSwitch owns the hardware connection.
19+
20+
Nothing needs to be recompiled or patched to control the microscope from outside. If you only want to *drive* the instrument, option 1 or 2 is the recommended path. If you want to *extend* it, option 4 is the recommended path — it survives ImSwitch updates, whereas forking the core does not (this is not yet mature enough to really recommend this path). In any case, you can also get in touch with us and we can try to help you out! :)
21+
22+
23+
## 2. Architecture in one picture
24+
25+
```
26+
Your application (Python / LabVIEW / C# / MATLAB / browser / …)
27+
│ HTTP+JSON (REST) │ Socket.IO (events, frames)
28+
▼ ▼
29+
┌────────────────────────────────────────────────────────────┐
30+
│ ImSwitch server — FastAPI + uvicorn, port 8001 │
31+
│ │
32+
│ Controllers (PositionerController, ExperimentController,│
33+
│ LiveViewController, UC2ConfigController …) │
34+
│ every @APIExport method → one REST endpoint │
35+
│ │
36+
│ Managers (detectors, positioners, lasers, LED matrix …) │
37+
└────────────────────────────────────────────────────────────┘
38+
│ UC2-REST (USB-serial / CAN-Open) │ vendor SDKs
39+
▼ ▼
40+
UC2 ESP32 electronics Cameras (Daheng, HIK,
41+
(motors, lasers, LEDs, focus) Basler, picamera2, MMCore …)
42+
```
43+
44+
The key design point: **the REST API is generated, not hand-written.** A controller method decorated with `@APIExport` is automatically published as an HTTP route and automatically appears in the OpenAPI schema. There is therefore no risk of the API and the implementation drifting apart, and adding a feature to the software adds it to the API for free.
45+
46+
47+
## 3. Connecting
48+
49+
| Item | Default |
50+
|------|---------|
51+
| Port | `8001` (`--http-port`) |
52+
| Transport | http with a self-signed certificate; `--no-ssl` switches to HTTP. The official Docker image starts with SSL disabled. |
53+
| API base path | `/imswitch/api` |
54+
| OpenAPI schema | `http://<host>:8001/imswitch/openapi.json` |
55+
| Interactive Swagger UI | `http://<host>:8001/imswitch/api/docs` |
56+
| Web UI | `http://<host>:8001/imswitch/ui/index.html` |
57+
| Socket.IO path | `/imswitch/socket.io` |
58+
| CORS | open (`*`) — browser clients can call the API directly |
59+
60+
**Start here:** open the Swagger UI in a browser against a running microscope. It lists every endpoint available on *that* specific instrument, with parameters, types and a "Try it out" button. This is the authoritative, always-current API reference — more complete than any static document we could ship, because the endpoint set depends on which controllers the setup configuration activates.
61+
62+
![](./IMAGES/swagger.png)
63+
64+
Two useful discovery endpoints:
65+
66+
```
67+
GET /imswitch/api/version → {"version": "2.1.x"}
68+
GET /imswitch/api/getAvailableControllers → {"availableControllers": [...]}
69+
```
70+
71+
72+
## 4. Option 1 — the REST API
73+
74+
### 4.1 URL convention
75+
76+
```
77+
<scheme>://<host>:8001/imswitch/api/<ControllerName>/<methodName>
78+
```
79+
80+
The controller name and the method name are exactly the Python class and method names.
81+
82+
### 4.2 Parameter conventions
83+
84+
* **GET** endpoints (the default) take parameters as **query string** arguments; Python argument names are used verbatim, and defaults are honoured.
85+
* **POST** endpoints take a **JSON body** matching the declared Pydantic model.
86+
* Return values are JSON-serialised Python return values.
87+
88+
### 4.3 Examples
89+
90+
(Assuming the microscope's IP is 192.168.1.50 - yours might be different and can be found e.g. by an IP scanner)
91+
92+
```bash
93+
# List the configured stages
94+
curl -k "http://192.168.1.50:8001/imswitch/api/PositionerController/getPositionerNames"
95+
96+
# Read all axis positions
97+
curl -k "http://192.168.1.50:8001/imswitch/api/PositionerController/getPositionerPositions"
98+
99+
# Move X by 100 µm, relative, blocking
100+
curl -k "http://192.168.1.50:8001/imswitch/api/PositionerController/movePositioner\
101+
?positionerName=ESP32Stage&axis=X&dist=100&isAbsolute=false&isBlocking=true"
102+
103+
# Switch on an illumination source at a given power
104+
curl -k "http://192.168.1.50:8001/imswitch/api/LaserController/setLaserActive?laserName=LED&active=true"
105+
curl -k "http://192.168.1.50:8001/imswitch/api/LaserController/setLaserValue?laserName=LED&value=512"
106+
```
107+
108+
### 4.4 Scope of the API
109+
110+
Roughly **700 endpoints** across ~60 controllers are currently exported. The functional
111+
groups most integrators need:
112+
113+
| Controller | Purpose |
114+
|-----------|---------|
115+
| `PositionerController` | XYZ/A stage motion, homing, speed, limits, step size |
116+
| `LaserController`, `LEDMatrixController` | illumination on/off, intensity, patterns |
117+
| `SettingsController`, `MMCoreController` | camera exposure, gain, ROI, binning, pixel format |
118+
| `RecordingController` | snapshots (incl. `snapNumpyToFastAPI` for a direct image response), video/stack recording |
119+
| `LiveViewController` | live stream start/stop, protocol and compression selection |
120+
| `ExperimentController` | multi-dimensional acquisition: tiles, z-stacks, timelapse, channels |
121+
| `WorkflowController` | queued/scripted step sequences |
122+
| `AutofocusController`, `FocusLockController` | software autofocus and closed-loop focus hold |
123+
| `HistoScanController`, `TilingController`, `StageMapController` | large-area scanning and stitching |
124+
| `UC2ConfigController` | firmware/electronics configuration, setup file management, OTA update |
125+
| `StorageController`, FileManager routes | data browsing, download, disk usage |
126+
127+
### 4.5 Client generation for other languages
128+
129+
Because a valid OpenAPI 3 schema is served, you can generate a typed client for C#, Java, TypeScript, Rust, LabVIEW-friendly wrappers etc. directly (more information here https://openapi-generator.tech/):
130+
131+
```bash
132+
openapi-generator-cli generate \
133+
-i http://<host>:8001/imswitch/openapi.json \
134+
-g csharp -o ./imswitch-csharp-client
135+
```
136+
137+
This is the recommended route for non-Python environments — we do not maintain hand-written clients for other languages.
138+
139+
140+
## 5. Option 2 — the Python SDK (`imswitchclient`)
141+
142+
A thin, dependency-light wrapper around the REST API, published on PyPI.
143+
144+
* Source: <http://github.com/openUC2/imswitchclient>
145+
* Install: `pip install imswitchclient`
146+
147+
```python
148+
import imswitchclient.ImSwitchClient as imc
149+
import matplotlib.pyplot as plt
150+
151+
client = imc.ImSwitchClient(host="192.168.1.50", port=8001, ishttp=True)
152+
153+
stage = client.positionersManager.getAllDeviceNames()[0]
154+
pos = client.positionersManager.getPositionerPositions()[stage]
155+
156+
client.lasersManager.setLaserActive("LED", True)
157+
client.lasersManager.setLaserValue("LED", 512)
158+
159+
client.positionersManager.movePositioner(stage, "X", pos["X"] + 50,
160+
is_absolute=True, is_blocking=True)
161+
162+
frame = client.recordingManager.snapNumpyToFastAPI() # returns a NumPy array
163+
plt.imshow(frame); plt.show()
164+
```
165+
166+
The client is organised into managers (`positionersManager`, `lasersManager`,
167+
`recordingManager`, `settingsManager`, `viewManager`, `experimentController`,
168+
`mdaController`, `objectiveController`, `histoscanManager`, `communicationManager`) plus a
169+
`socketClient` for live events.
170+
171+
Two caveats worth stating:
172+
173+
* The SDK is a **convenience layer, not a superset**. It covers the common operations; it does not wrap all ~700 endpoints. Anything not wrapped is reachable with `client.get_json("/SomeController/someMethod", payload={...})` or `client.post_json(...)` using the same session and base URL.
174+
* Runnable examples, including Google Colab notebooks, live in the `examples/` folder of that repository (autofocus, DPC, stitching, stage calibration, MDA).
175+
176+
177+
## 6. Option 3 — real-time data and events
178+
179+
REST is request/response. For anything continuous, use the Socket.IO channel on the same port and host, path `/imswitch/socket.io`.
180+
181+
### 6.1 State and signal events
182+
183+
Internal signals are broadcast as MessagePack-encoded payloads on the event `signal_msgpack`, with the structure `{"signal": "<SignalName>", "args": ...}`. On connect, the server announces its capabilities on `server_capabilities` (`messagepack`, `binary_streaming`, `protocol_version`).
184+
185+
### 6.2 Image streaming
186+
187+
Live frames are delivered on a `frame` event with an explicit `frame_ack` back-pressure handshake — the server only sends the next frame once the client acknowledges the previous one, which prevents queue build-up on slow links.
188+
189+
Four stream protocols are selectable at runtime through `LiveViewController`:
190+
191+
| Protocol | Notes |
192+
|----------|-------|
193+
| `binary` | raw pixels, LZ4 or Zstd lossless compression, optional subsampling — use this for quantitative work |
194+
| `jpeg` | lossy, low bandwidth |
195+
| `mjpeg` | browser-friendly |
196+
| `webrtc` | lowest latency for viewing |
197+
198+
Relevant endpoints: `getStreamStatus`, `getCurrentStreamProtocol`, and the setters for protocol, compression algorithm/level, subsampling factor and throttle interval.
199+
200+
For single quantitative images, prefer the REST snapshot endpoint over the live stream — it returns the full-bit-depth frame without stream-side subsampling.
201+
202+
203+
## 7. Option 4 — extending the software
204+
205+
If your requirement is *"we need a function that does not exist yet"*, do not fork the core. There are two supported extension mechanisms.
206+
207+
### 7.1 Add an endpoint to an existing/own controller (current stable branch)
208+
209+
Any method decorated with `@APIExport` in a controller becomes an HTTP endpoint at `/imswitch/api/<ControllerName>/<methodName>` on the next start. Nothing else is required — no route registration, no schema editing.
210+
211+
```python
212+
from imswitch.imcommon.model import APIExport
213+
214+
class MyController(ImConWidgetController):
215+
216+
@APIExport() # → GET
217+
def getSomething(self, name: str = "default") -> dict:
218+
return {"value": 42}
219+
220+
@APIExport(requestType="POST") # → POST, JSON body
221+
def doSomething(self, body: MyRequestModel):
222+
...
223+
224+
@APIExport(asyncExecution=True) # for `async def` methods
225+
async def doSomethingSlow(self):
226+
...
227+
```
228+
229+
Decorator options: `requestType` (`"GET"`/`"POST"`), `asyncExecution`, `runOnUIThread`.
230+
231+
### 7.2 Plugin system v2 — the forward-looking path
232+
233+
:::danger
234+
⚠️ WARNING
235+
236+
The plugin system is still under development.
237+
:::
238+
239+
240+
A plugin SDK is in development on the `feature/pluginsystemV2` branch. It defines a **stable public API surface** so that third-party extensions no longer depend on ImSwitch internals:
241+
242+
```python
243+
from imswitch.plugin_sdk import PluginController, APIExport, Event
244+
245+
class MyPlugin(PluginController):
246+
sig_measurement = Event("measurement", schema={"value": "float"})
247+
248+
@APIExport(method="POST", path="/measure")
249+
def measure(self):
250+
cam = self.ctx.hardware.detector("main") # role-based, not device names
251+
stage = self.ctx.hardware.positioner("xy")
252+
...
253+
self.sig_measurement.emit({"value": 42.0})
254+
```
255+
256+
Properties of the plugin system:
257+
258+
* `imswitch.plugin_sdk` is the **only** module a plugin is allowed to import; everything else (`imcontrol`, `imcommon`, `MasterController`) is host-private and may change.
259+
* The SDK is versioned independently of the host (`sdk_min` in `plugin.toml`), with a backwards-compatibility guarantee inside a major version.
260+
* Hardware is requested by **role** (`detector:main`, `positioner:xy`) declared in `plugin.toml` and resolved by the host against the active setup file — plugins never hard-code device names.
261+
* Routes mount under `/plugin/<name>/api/…`, events under the Socket.IO namespace `/plugin/<name>`, and a React micro-frontend bundle under `/plugin/<name>/ui/` so a plugin can contribute its own UI panel.
262+
* Discovery is via the `imswitch.plugins` Python entry-point group (pip-installable), or by dropping a package into the directory given by `IMSWITCH_PLUGIN_DIR` (default `/opt/imswitch/plugins`, bind-mountable in Docker).
263+
* Declared permissions (`camera_read`, `camera_settings`, `file_write`, `network_egress`) make a plugin's footprint explicit.
264+
265+
**Recommendation:** if you plan substantial new functionality, target the plugin SDK and tell us early — the interface is not yet frozen and we would rather accommodate a concrete integration requirement than break one.
266+
267+
268+
## 8. Other available interfaces
269+
270+
| Interface | Status | Notes |
271+
|-----------|--------|-------|
272+
| **Jupyter kernel** | available | ImSwitch can start with an embedded kernel (`--with-kernel`, default port 8888) giving direct in-process scripting against the live instrument. |
273+
| **SiLA 2** | experimental | `SiLa2Controller`, based on `unitelabs-cdk`, for lab-automation environments that standardise on SiLA. |
274+
| **Micro-Manager / MMCore** | available | Cameras and devices can be driven through MMCore; `MMCoreController` exposes their properties over REST. Useful if your stack is already Micro-Manager-based. |
275+
| **Arkitekt / Hypha** | experimental | Controllers exist for integration into these distributed bio-imaging frameworks. |
276+
| **OME-Zarr / OME-TIFF output** | available | Acquisitions are written in standard formats; downstream analysis needs no ImSwitch dependency. |
277+
| **UC2-REST (firmware)** | available, not recommended for integrators | Direct USB-serial or CAN-Open access to the ESP32 electronics via the `uc2-rest` / `uc2canopen` Python packages. Only relevant if you build your own control software instead of using ImSwitch; the port is exclusively held by ImSwitch while it runs. |
278+
279+
280+
## 9. Deployment notes
281+
282+
* ImSwitch normally runs in **Docker** on the microscope's embedded computer (Raspberry Pi 5 or comparable) and starts automatically. Your software can be on any machine on the network. => checkout https://github.com/openUC2/os-rpi/ for more information
283+
* Relevant ports: `8001` (API + Socket.IO), `8888` (Jupyter), `3232`/`3333` (ESP32 OTA).
284+
* The default TLS certificate is self-signed — HTTP clients need certificate verification disabled, or run with `--no-ssl` on a trusted network.
285+
* There is currently **no authentication layer**. Treat the API as trusted-network-only, or place it behind a reverse proxy that terminates TLS and handles auth. This is a known gap and is on the roadmap; tell us if you have a specific requirement.
286+
* Hardware configuration (which camera, stage, illumination, calibration) lives in a JSON setup file that can be read and written through `UC2ConfigController` — so provisioning can be automated too.
287+
288+
289+
## 10. Stability and versioning
290+
291+
Honest assessment of what you can build on:
292+
293+
| Layer | Stability |
294+
|-------|-----------|
295+
| REST URL scheme (`/imswitch/api/<Controller>/<method>`) | stable |
296+
| Existing endpoint names and signatures | stable in practice; individual endpoints may gain optional parameters. Breaking renames are rare and go through release notes. |
297+
| OpenAPI schema | authoritative — always generate against the instrument you target |
298+
| Socket.IO event names and payload shapes | mostly stable; the frame/streaming protocol is still evolving |
299+
| `imswitchclient` API | stable for the wrapped subset |
300+
| `imswitch.plugin_sdk` | **not yet frozen** (SDK 1.0.0 on a feature branch) |
301+
| Internal modules (`imcontrol`, `imcommon`) | no compatibility guarantee — do not import from a plugin |
302+
303+
We pin ImSwitch versions in the Docker image, so a deployed instrument does not changeunder you. Please tell us which version you validate against.
304+
305+
## 11. Links
306+
307+
| Resource | URL |
308+
|----------|-----|
309+
| ImSwitch (openUC2 fork), main branch | <http://github.com/openUC2/ImSwitch/tree/master/imswitch> |
310+
| Plugin system v2 branch | <http://github.com/openUC2/ImSwitch/tree/feature/pluginsystemV2> |
311+
| Python client SDK | <http://github.com/openUC2/imswitchclient> |
312+
| Client on PyPI | <http://pypi.org/project/imswitchclient/> |
313+
| Additional developer docs | `docs/` folder in the ImSwitch repository |
314+
| Live API reference | `http://<your-microscope>:8001/imswitch/api/docs` |
315+
| openUC2 project | <http://openuc2.com> |
316+
729 KB
Loading

0 commit comments

Comments
 (0)