hgrabber-sdk 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. hgrabber_sdk-0.1.0/.dockerignore +17 -0
  2. hgrabber_sdk-0.1.0/.gitignore +7 -0
  3. hgrabber_sdk-0.1.0/.python-version +1 -0
  4. hgrabber_sdk-0.1.0/Dockerfile +34 -0
  5. hgrabber_sdk-0.1.0/PKG-INFO +316 -0
  6. hgrabber_sdk-0.1.0/README.md +308 -0
  7. hgrabber_sdk-0.1.0/examples/continuous_sync.py +20 -0
  8. hgrabber_sdk-0.1.0/examples/linux_smoke.py +16 -0
  9. hgrabber_sdk-0.1.0/examples/list_devices.py +11 -0
  10. hgrabber_sdk-0.1.0/examples/multi_camera_action_ptp.py +34 -0
  11. hgrabber_sdk-0.1.0/examples/software_trigger_async.py +24 -0
  12. hgrabber_sdk-0.1.0/pyproject.toml +23 -0
  13. hgrabber_sdk-0.1.0/src/hgrabber_sdk/__init__.py +46 -0
  14. hgrabber_sdk-0.1.0/src/hgrabber_sdk/_runtime.py +212 -0
  15. hgrabber_sdk-0.1.0/src/hgrabber_sdk/_sdk.py +126 -0
  16. hgrabber_sdk-0.1.0/src/hgrabber_sdk/camera.py +853 -0
  17. hgrabber_sdk-0.1.0/src/hgrabber_sdk/config.py +321 -0
  18. hgrabber_sdk-0.1.0/src/hgrabber_sdk/discovery.py +143 -0
  19. hgrabber_sdk-0.1.0/src/hgrabber_sdk/errors.py +19 -0
  20. hgrabber_sdk-0.1.0/src/hgrabber_sdk/frames.py +137 -0
  21. hgrabber_sdk-0.1.0/src/hgrabber_sdk/group.py +315 -0
  22. hgrabber_sdk-0.1.0/src/hgrabber_sdk/py.typed +1 -0
  23. hgrabber_sdk-0.1.0/src/hgrabber_sdk/vendor/MvImport/CameraParams_const.py +82 -0
  24. hgrabber_sdk-0.1.0/src/hgrabber_sdk/vendor/MvImport/CameraParams_header.py +1289 -0
  25. hgrabber_sdk-0.1.0/src/hgrabber_sdk/vendor/MvImport/MvCameraControl_class.py +1153 -0
  26. hgrabber_sdk-0.1.0/src/hgrabber_sdk/vendor/MvImport/MvErrorDefine_const.py +67 -0
  27. hgrabber_sdk-0.1.0/src/hgrabber_sdk/vendor/MvImport/PixelType_header.py +258 -0
  28. hgrabber_sdk-0.1.0/src/hgrabber_sdk/vendor/MvImport/__init__.py +1 -0
  29. hgrabber_sdk-0.1.0/src/hgrabber_sdk/vendor/__init__.py +1 -0
  30. hgrabber_sdk-0.1.0/tests/test_import.py +103 -0
  31. hgrabber_sdk-0.1.0/uv.lock +869 -0
@@ -0,0 +1,17 @@
1
+ .git/
2
+ .venv/
3
+ .pytest_cache/
4
+ __pycache__/
5
+ *.py[cod]
6
+ dist/
7
+ build/
8
+ *.egg-info/
9
+ .mypy_cache/
10
+ .ruff_cache/
11
+
12
+ # Keep native MVS runtimes out of build context by default.
13
+ mvs/
14
+ mvs-runtime/
15
+ docker/mvs/
16
+ docker/mvs-runtime/
17
+
@@ -0,0 +1,7 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.py[cod]
4
+ .pytest_cache/
5
+ dist/
6
+ build/
7
+ *.egg-info/
@@ -0,0 +1 @@
1
+ 3.12
@@ -0,0 +1,34 @@
1
+ # syntax=docker/dockerfile:1
2
+
3
+ ARG PYTHON_VERSION=3.12
4
+ FROM python:${PYTHON_VERSION}-slim-bookworm
5
+
6
+ ENV PYTHONDONTWRITEBYTECODE=1
7
+ ENV PYTHONUNBUFFERED=1
8
+ ENV LD_LIBRARY_PATH=/opt/mvs/64:/opt/mvs/aarch64:/opt/mvs/armhf:/opt/mvs
9
+
10
+ RUN apt-get update \
11
+ && apt-get install -y --no-install-recommends \
12
+ ca-certificates \
13
+ iproute2 \
14
+ iputils-ping \
15
+ libglib2.0-0 \
16
+ libgomp1 \
17
+ libstdc++6 \
18
+ libusb-1.0-0 \
19
+ libx11-6 \
20
+ libxext6 \
21
+ udev \
22
+ && rm -rf /var/lib/apt/lists/*
23
+
24
+ WORKDIR /app
25
+
26
+ COPY pyproject.toml README.md ./
27
+ COPY src ./src
28
+ COPY tests ./tests
29
+ COPY examples ./examples
30
+
31
+ RUN python -m pip install --no-cache-dir --upgrade pip \
32
+ && python -m pip install --no-cache-dir -e . pytest
33
+
34
+ CMD ["python", "-m", "pytest", "-q"]
@@ -0,0 +1,316 @@
1
+ Metadata-Version: 2.4
2
+ Name: hgrabber-sdk
3
+ Version: 0.1.0
4
+ Summary: Pythonic Hikrobot MVS camera SDK wrapper for USB3 and GigE cameras
5
+ Requires-Python: >=3.10
6
+ Requires-Dist: numpy>=1.24
7
+ Description-Content-Type: text/markdown
8
+
9
+ # hgrabber-sdk
10
+
11
+ Small Python wrapper around Hikrobot MVS `MvCameraControl` for USB3 and GigE cameras.
12
+
13
+ The package vendors the official generated Python `MvImport` files from:
14
+
15
+ `C:\Program Files (x86)\MVS\Development\Samples\Python\MvImport`
16
+
17
+ The native Hikrobot MVS runtime is not bundled in this package. Install MVS separately on the
18
+ target machine, or point the package at the native library with `HIK_CAMERA_SDK_MVS_LIBRARY`.
19
+
20
+ ## Setup with uv
21
+
22
+ This project is configured for `uv` and pins Python through `.python-version`.
23
+
24
+ ```bash
25
+ pip install hgrabber-sdk
26
+ ```
27
+
28
+ ```powershell
29
+ uv sync --dev
30
+ uv run python -c "import hgrabber_sdk; print(hgrabber_sdk.__all__)"
31
+ uv run pytest
32
+ uv run python examples/list_devices.py
33
+ ```
34
+
35
+ The import check does not load the native Hikrobot runtime. Commands that enumerate or open cameras
36
+ load `MvCameraControl` lazily.
37
+
38
+ ## Native MVS runtime
39
+
40
+ Install Hikrobot MVS from the official installer for the target OS.
41
+
42
+ The loader checks these locations in order:
43
+
44
+ - `HIK_CAMERA_SDK_MVS_LIBRARY`: full path to `MvCameraControl.dll` or `libMvCameraControl.so`.
45
+ - Windows: the standard MVS runtime folder under `Common Files\MVS\Runtime`, then normal `PATH`.
46
+ - Linux: `MVCAM_COMMON_RUNENV` pointing to a runtime root that contains `64/libMvCameraControl.so`,
47
+ `aarch64/libMvCameraControl.so`, or another matching architecture directory. Common install paths
48
+ such as `/opt/MVS/lib` are also checked.
49
+
50
+ Windows override example:
51
+
52
+ ```powershell
53
+ $env:HIK_CAMERA_SDK_MVS_LIBRARY = "C:\Program Files (x86)\Common Files\MVS\Runtime\Win64_x64\MvCameraControl.dll"
54
+ ```
55
+
56
+ Linux root example:
57
+
58
+ ```bash
59
+ export MVCAM_COMMON_RUNENV=/opt/MVS/lib
60
+ ```
61
+
62
+ Linux exact library override:
63
+
64
+ ```bash
65
+ export HIK_CAMERA_SDK_MVS_LIBRARY=/opt/MVS/lib/64/libMvCameraControl.so
66
+ ```
67
+
68
+ ## Build and publish
69
+
70
+ Build a pure Python wheel. It contains the wrapper code only, not Hikrobot's native runtime:
71
+
72
+ ```powershell
73
+ uv sync --dev
74
+ uv build
75
+ uv run --dev twine check dist\*
76
+ ```
77
+
78
+ Upload to TestPyPI first, then PyPI:
79
+
80
+ ```powershell
81
+ uv run --dev twine upload --repository testpypi dist\*.whl
82
+ uv run --dev twine upload dist\*.whl
83
+ ```
84
+
85
+ ## Linux Docker Smoke Test
86
+
87
+ Build the Linux image and run package tests without native MVS libraries:
88
+
89
+ ```bash
90
+ docker build -t hgrabber-sdk-linux .
91
+ docker run --rm hgrabber-sdk-linux
92
+ ```
93
+
94
+ To test the native Hikrobot SDK and camera discovery, install or extract the Linux MVS runtime on
95
+ the host and mount the runtime directory into `/opt/mvs`. The mounted directory must contain the
96
+ architecture subdirectory expected by the loader, for example:
97
+
98
+ ```text
99
+ /path/to/mvs-runtime/
100
+ 64/libMvCameraControl.so
101
+ ```
102
+
103
+ GigE camera discovery is easiest with host networking:
104
+
105
+ ```bash
106
+ docker run --rm --network host \
107
+ -e MVCAM_COMMON_RUNENV=/opt/mvs \
108
+ -v /path/to/mvs-runtime:/opt/mvs:ro \
109
+ hgrabber-sdk-linux \
110
+ python examples/linux_smoke.py
111
+ ```
112
+
113
+ For USB cameras, run on a real Linux host and pass USB devices through:
114
+
115
+ ```bash
116
+ docker run --rm --network host --privileged \
117
+ -e MVCAM_COMMON_RUNENV=/opt/mvs \
118
+ -v /dev/bus/usb:/dev/bus/usb \
119
+ -v /path/to/mvs-runtime:/opt/mvs:ro \
120
+ hgrabber-sdk-linux \
121
+ python examples/linux_smoke.py
122
+ ```
123
+
124
+ Docker Desktop/WSL may not expose industrial USB/GigE cameras reliably; use a native Linux host
125
+ for hardware validation.
126
+
127
+ ## Supported flows
128
+
129
+ - USB3 and GigE discovery by serial number, user name, model name, or GigE IP.
130
+ - Synchronous grabbing with `GetImageBuffer`.
131
+ - Async polling worker.
132
+ - `asyncio` methods for non-blocking application code.
133
+ - Native SDK image callback mode.
134
+ - Continuous acquisition.
135
+ - Software trigger.
136
+ - Hardware line trigger: `Line0`, `Line1`, `Line2`, `Line3`, with activation, delay, cache, debouncer.
137
+ - GigE action trigger: `Action1` with device/group keys and broadcast address.
138
+ - PTP helpers for GigE: enable `GevIEEE1588`, wait for `Master`/`Slave`, latch timestamp, scheduled action command.
139
+ - Multi-camera group API.
140
+ - Direct GenICam feature passthrough for extra settings.
141
+
142
+ ## Quick start
143
+
144
+ ```python
145
+ from hgrabber_sdk import HikCamera
146
+
147
+ config = (
148
+ HikCamera.builder("left")
149
+ .usb("02K09720174")
150
+ .settings(exposure_us=8000, gain=4.0, pixel_format="BayerRG8")
151
+ .continuous()
152
+ .build()
153
+ )
154
+
155
+ with HikCamera(config) as camera:
156
+ frame = camera.grab(timeout_ms=1000)
157
+ print(frame.width, frame.height, frame.pixel_format, frame.image.shape)
158
+ ```
159
+
160
+ ## Software trigger
161
+
162
+ ```python
163
+ from hgrabber_sdk import HikCamera
164
+
165
+ config = (
166
+ HikCamera.builder("top")
167
+ .gige("192.168.10.20")
168
+ .software_trigger()
169
+ .settings(exposure_us=6000, gain=2.0)
170
+ .build()
171
+ )
172
+
173
+ with HikCamera(config) as camera:
174
+ frame = camera.grab() # sends TriggerSoftware, then waits for the frame
175
+ ```
176
+
177
+ ## Threaded streaming
178
+
179
+ ```python
180
+ from hgrabber_sdk import HikCamera
181
+
182
+ def on_frame(frame):
183
+ print(frame.camera_name, frame.frame_number, frame.device_timestamp)
184
+
185
+ config = HikCamera.builder("preview").usb("SERIAL").continuous().build()
186
+
187
+ with HikCamera(config) as camera:
188
+ camera.start_stream(on_frame)
189
+ frame = camera.next_frame(timeout_ms=1000)
190
+ ```
191
+
192
+ `start_async` and `stop_async` are kept as compatibility aliases for the threaded API.
193
+
194
+ ## Asyncio grabbing
195
+
196
+ All blocking SDK calls have `asyncio` wrappers. They run the MVS calls in worker threads, so
197
+ `MV_CC_GetImageBuffer`, software trigger, PTP waits, and action commands do not block the event loop.
198
+
199
+ ```python
200
+ import asyncio
201
+ from hgrabber_sdk import HikCamera
202
+
203
+
204
+ async def main():
205
+ config = (
206
+ HikCamera.builder("cam")
207
+ .gige("192.168.10.20")
208
+ .software_trigger()
209
+ .build()
210
+ )
211
+
212
+ async with HikCamera(config) as camera:
213
+ frame = await camera.async_grab(timeout_ms=1000)
214
+ print(frame.frame_number)
215
+
216
+
217
+ asyncio.run(main())
218
+ ```
219
+
220
+ For continuous streaming into an `asyncio.Queue`:
221
+
222
+ ```python
223
+ async with HikCamera(config) as camera:
224
+ frames = await camera.async_start_stream(queue_size=4)
225
+ frame = await asyncio.wait_for(frames.get(), timeout=2.0)
226
+ await camera.async_stop_stream(frames)
227
+ ```
228
+
229
+ ## Native SDK callback
230
+
231
+ ```python
232
+ config = (
233
+ HikCamera.builder("callback")
234
+ .gige("192.168.10.21")
235
+ .sdk_callback()
236
+ .continuous()
237
+ .build()
238
+ )
239
+ ```
240
+
241
+ Callback mode registers `MV_CC_RegisterImageCallBackEx` before `MV_CC_StartGrabbing`.
242
+
243
+ ## Line trigger
244
+
245
+ ```python
246
+ config = (
247
+ HikCamera.builder("io")
248
+ .usb("SERIAL")
249
+ .line_trigger("Line0", activation="RisingEdge", delay_us=0, line_debouncer_us=50)
250
+ .build()
251
+ )
252
+ ```
253
+
254
+ For line-scan cameras, set another trigger selector:
255
+
256
+ ```python
257
+ .line_trigger("Line1", selector="LineStart")
258
+ ```
259
+
260
+ ## Multi-camera GigE action/PTP
261
+
262
+ ```python
263
+ from hgrabber_sdk import HikCamera, HikCameraGroup
264
+
265
+ left = (
266
+ HikCamera.builder("left")
267
+ .gige("192.168.10.21")
268
+ .ptp(wait_synchronized=True)
269
+ .action_trigger(device_key=1, group_key=1, group_mask=1)
270
+ .build()
271
+ )
272
+ right = (
273
+ HikCamera.builder("right")
274
+ .gige("192.168.10.22")
275
+ .ptp(wait_synchronized=True)
276
+ .action_trigger(device_key=1, group_key=1, group_mask=1)
277
+ .build()
278
+ )
279
+
280
+ with HikCameraGroup([left, right]) as cameras:
281
+ cameras.start_async(queue_size=4)
282
+ results = cameras.issue_action_after(delay_ticks=10_000_000)
283
+ frames = {name: camera.next_frame(timeout_ms=2000) for name, camera in cameras.cameras.items()}
284
+ ```
285
+
286
+ Asyncio group variant:
287
+
288
+ ```python
289
+ async with HikCameraGroup([left, right]) as cameras:
290
+ queues = await cameras.async_start_stream(queue_size=4)
291
+ await cameras.async_issue_action_after(delay_ticks=10_000_000)
292
+ frames = {
293
+ name: await asyncio.wait_for(queue.get(), timeout=2.0)
294
+ for name, queue in queues.items()
295
+ }
296
+ ```
297
+
298
+ `delay_ticks` is in camera timestamp ticks. On most GigE Vision PTP setups this is nanoseconds,
299
+ but validate this against the exact camera model before using scheduled actions in production.
300
+
301
+ ## Raw feature passthrough
302
+
303
+ Any extra GenICam feature can be passed through the builder:
304
+
305
+ ```python
306
+ config = (
307
+ HikCamera.builder("cam")
308
+ .gige("192.168.10.20")
309
+ .feature("GammaEnable", True)
310
+ .feature("Gamma", 0.7)
311
+ .feature("AcquisitionBurstFrameCount", 3)
312
+ .build()
313
+ )
314
+ ```
315
+
316
+ String values are first attempted as enum symbols and then as string nodes.
@@ -0,0 +1,308 @@
1
+ # hgrabber-sdk
2
+
3
+ Small Python wrapper around Hikrobot MVS `MvCameraControl` for USB3 and GigE cameras.
4
+
5
+ The package vendors the official generated Python `MvImport` files from:
6
+
7
+ `C:\Program Files (x86)\MVS\Development\Samples\Python\MvImport`
8
+
9
+ The native Hikrobot MVS runtime is not bundled in this package. Install MVS separately on the
10
+ target machine, or point the package at the native library with `HIK_CAMERA_SDK_MVS_LIBRARY`.
11
+
12
+ ## Setup with uv
13
+
14
+ This project is configured for `uv` and pins Python through `.python-version`.
15
+
16
+ ```bash
17
+ pip install hgrabber-sdk
18
+ ```
19
+
20
+ ```powershell
21
+ uv sync --dev
22
+ uv run python -c "import hgrabber_sdk; print(hgrabber_sdk.__all__)"
23
+ uv run pytest
24
+ uv run python examples/list_devices.py
25
+ ```
26
+
27
+ The import check does not load the native Hikrobot runtime. Commands that enumerate or open cameras
28
+ load `MvCameraControl` lazily.
29
+
30
+ ## Native MVS runtime
31
+
32
+ Install Hikrobot MVS from the official installer for the target OS.
33
+
34
+ The loader checks these locations in order:
35
+
36
+ - `HIK_CAMERA_SDK_MVS_LIBRARY`: full path to `MvCameraControl.dll` or `libMvCameraControl.so`.
37
+ - Windows: the standard MVS runtime folder under `Common Files\MVS\Runtime`, then normal `PATH`.
38
+ - Linux: `MVCAM_COMMON_RUNENV` pointing to a runtime root that contains `64/libMvCameraControl.so`,
39
+ `aarch64/libMvCameraControl.so`, or another matching architecture directory. Common install paths
40
+ such as `/opt/MVS/lib` are also checked.
41
+
42
+ Windows override example:
43
+
44
+ ```powershell
45
+ $env:HIK_CAMERA_SDK_MVS_LIBRARY = "C:\Program Files (x86)\Common Files\MVS\Runtime\Win64_x64\MvCameraControl.dll"
46
+ ```
47
+
48
+ Linux root example:
49
+
50
+ ```bash
51
+ export MVCAM_COMMON_RUNENV=/opt/MVS/lib
52
+ ```
53
+
54
+ Linux exact library override:
55
+
56
+ ```bash
57
+ export HIK_CAMERA_SDK_MVS_LIBRARY=/opt/MVS/lib/64/libMvCameraControl.so
58
+ ```
59
+
60
+ ## Build and publish
61
+
62
+ Build a pure Python wheel. It contains the wrapper code only, not Hikrobot's native runtime:
63
+
64
+ ```powershell
65
+ uv sync --dev
66
+ uv build
67
+ uv run --dev twine check dist\*
68
+ ```
69
+
70
+ Upload to TestPyPI first, then PyPI:
71
+
72
+ ```powershell
73
+ uv run --dev twine upload --repository testpypi dist\*.whl
74
+ uv run --dev twine upload dist\*.whl
75
+ ```
76
+
77
+ ## Linux Docker Smoke Test
78
+
79
+ Build the Linux image and run package tests without native MVS libraries:
80
+
81
+ ```bash
82
+ docker build -t hgrabber-sdk-linux .
83
+ docker run --rm hgrabber-sdk-linux
84
+ ```
85
+
86
+ To test the native Hikrobot SDK and camera discovery, install or extract the Linux MVS runtime on
87
+ the host and mount the runtime directory into `/opt/mvs`. The mounted directory must contain the
88
+ architecture subdirectory expected by the loader, for example:
89
+
90
+ ```text
91
+ /path/to/mvs-runtime/
92
+ 64/libMvCameraControl.so
93
+ ```
94
+
95
+ GigE camera discovery is easiest with host networking:
96
+
97
+ ```bash
98
+ docker run --rm --network host \
99
+ -e MVCAM_COMMON_RUNENV=/opt/mvs \
100
+ -v /path/to/mvs-runtime:/opt/mvs:ro \
101
+ hgrabber-sdk-linux \
102
+ python examples/linux_smoke.py
103
+ ```
104
+
105
+ For USB cameras, run on a real Linux host and pass USB devices through:
106
+
107
+ ```bash
108
+ docker run --rm --network host --privileged \
109
+ -e MVCAM_COMMON_RUNENV=/opt/mvs \
110
+ -v /dev/bus/usb:/dev/bus/usb \
111
+ -v /path/to/mvs-runtime:/opt/mvs:ro \
112
+ hgrabber-sdk-linux \
113
+ python examples/linux_smoke.py
114
+ ```
115
+
116
+ Docker Desktop/WSL may not expose industrial USB/GigE cameras reliably; use a native Linux host
117
+ for hardware validation.
118
+
119
+ ## Supported flows
120
+
121
+ - USB3 and GigE discovery by serial number, user name, model name, or GigE IP.
122
+ - Synchronous grabbing with `GetImageBuffer`.
123
+ - Async polling worker.
124
+ - `asyncio` methods for non-blocking application code.
125
+ - Native SDK image callback mode.
126
+ - Continuous acquisition.
127
+ - Software trigger.
128
+ - Hardware line trigger: `Line0`, `Line1`, `Line2`, `Line3`, with activation, delay, cache, debouncer.
129
+ - GigE action trigger: `Action1` with device/group keys and broadcast address.
130
+ - PTP helpers for GigE: enable `GevIEEE1588`, wait for `Master`/`Slave`, latch timestamp, scheduled action command.
131
+ - Multi-camera group API.
132
+ - Direct GenICam feature passthrough for extra settings.
133
+
134
+ ## Quick start
135
+
136
+ ```python
137
+ from hgrabber_sdk import HikCamera
138
+
139
+ config = (
140
+ HikCamera.builder("left")
141
+ .usb("02K09720174")
142
+ .settings(exposure_us=8000, gain=4.0, pixel_format="BayerRG8")
143
+ .continuous()
144
+ .build()
145
+ )
146
+
147
+ with HikCamera(config) as camera:
148
+ frame = camera.grab(timeout_ms=1000)
149
+ print(frame.width, frame.height, frame.pixel_format, frame.image.shape)
150
+ ```
151
+
152
+ ## Software trigger
153
+
154
+ ```python
155
+ from hgrabber_sdk import HikCamera
156
+
157
+ config = (
158
+ HikCamera.builder("top")
159
+ .gige("192.168.10.20")
160
+ .software_trigger()
161
+ .settings(exposure_us=6000, gain=2.0)
162
+ .build()
163
+ )
164
+
165
+ with HikCamera(config) as camera:
166
+ frame = camera.grab() # sends TriggerSoftware, then waits for the frame
167
+ ```
168
+
169
+ ## Threaded streaming
170
+
171
+ ```python
172
+ from hgrabber_sdk import HikCamera
173
+
174
+ def on_frame(frame):
175
+ print(frame.camera_name, frame.frame_number, frame.device_timestamp)
176
+
177
+ config = HikCamera.builder("preview").usb("SERIAL").continuous().build()
178
+
179
+ with HikCamera(config) as camera:
180
+ camera.start_stream(on_frame)
181
+ frame = camera.next_frame(timeout_ms=1000)
182
+ ```
183
+
184
+ `start_async` and `stop_async` are kept as compatibility aliases for the threaded API.
185
+
186
+ ## Asyncio grabbing
187
+
188
+ All blocking SDK calls have `asyncio` wrappers. They run the MVS calls in worker threads, so
189
+ `MV_CC_GetImageBuffer`, software trigger, PTP waits, and action commands do not block the event loop.
190
+
191
+ ```python
192
+ import asyncio
193
+ from hgrabber_sdk import HikCamera
194
+
195
+
196
+ async def main():
197
+ config = (
198
+ HikCamera.builder("cam")
199
+ .gige("192.168.10.20")
200
+ .software_trigger()
201
+ .build()
202
+ )
203
+
204
+ async with HikCamera(config) as camera:
205
+ frame = await camera.async_grab(timeout_ms=1000)
206
+ print(frame.frame_number)
207
+
208
+
209
+ asyncio.run(main())
210
+ ```
211
+
212
+ For continuous streaming into an `asyncio.Queue`:
213
+
214
+ ```python
215
+ async with HikCamera(config) as camera:
216
+ frames = await camera.async_start_stream(queue_size=4)
217
+ frame = await asyncio.wait_for(frames.get(), timeout=2.0)
218
+ await camera.async_stop_stream(frames)
219
+ ```
220
+
221
+ ## Native SDK callback
222
+
223
+ ```python
224
+ config = (
225
+ HikCamera.builder("callback")
226
+ .gige("192.168.10.21")
227
+ .sdk_callback()
228
+ .continuous()
229
+ .build()
230
+ )
231
+ ```
232
+
233
+ Callback mode registers `MV_CC_RegisterImageCallBackEx` before `MV_CC_StartGrabbing`.
234
+
235
+ ## Line trigger
236
+
237
+ ```python
238
+ config = (
239
+ HikCamera.builder("io")
240
+ .usb("SERIAL")
241
+ .line_trigger("Line0", activation="RisingEdge", delay_us=0, line_debouncer_us=50)
242
+ .build()
243
+ )
244
+ ```
245
+
246
+ For line-scan cameras, set another trigger selector:
247
+
248
+ ```python
249
+ .line_trigger("Line1", selector="LineStart")
250
+ ```
251
+
252
+ ## Multi-camera GigE action/PTP
253
+
254
+ ```python
255
+ from hgrabber_sdk import HikCamera, HikCameraGroup
256
+
257
+ left = (
258
+ HikCamera.builder("left")
259
+ .gige("192.168.10.21")
260
+ .ptp(wait_synchronized=True)
261
+ .action_trigger(device_key=1, group_key=1, group_mask=1)
262
+ .build()
263
+ )
264
+ right = (
265
+ HikCamera.builder("right")
266
+ .gige("192.168.10.22")
267
+ .ptp(wait_synchronized=True)
268
+ .action_trigger(device_key=1, group_key=1, group_mask=1)
269
+ .build()
270
+ )
271
+
272
+ with HikCameraGroup([left, right]) as cameras:
273
+ cameras.start_async(queue_size=4)
274
+ results = cameras.issue_action_after(delay_ticks=10_000_000)
275
+ frames = {name: camera.next_frame(timeout_ms=2000) for name, camera in cameras.cameras.items()}
276
+ ```
277
+
278
+ Asyncio group variant:
279
+
280
+ ```python
281
+ async with HikCameraGroup([left, right]) as cameras:
282
+ queues = await cameras.async_start_stream(queue_size=4)
283
+ await cameras.async_issue_action_after(delay_ticks=10_000_000)
284
+ frames = {
285
+ name: await asyncio.wait_for(queue.get(), timeout=2.0)
286
+ for name, queue in queues.items()
287
+ }
288
+ ```
289
+
290
+ `delay_ticks` is in camera timestamp ticks. On most GigE Vision PTP setups this is nanoseconds,
291
+ but validate this against the exact camera model before using scheduled actions in production.
292
+
293
+ ## Raw feature passthrough
294
+
295
+ Any extra GenICam feature can be passed through the builder:
296
+
297
+ ```python
298
+ config = (
299
+ HikCamera.builder("cam")
300
+ .gige("192.168.10.20")
301
+ .feature("GammaEnable", True)
302
+ .feature("Gamma", 0.7)
303
+ .feature("AcquisitionBurstFrameCount", 3)
304
+ .build()
305
+ )
306
+ ```
307
+
308
+ String values are first attempted as enum symbols and then as string nodes.
@@ -0,0 +1,20 @@
1
+ from hgrabber_sdk import HikCamera
2
+
3
+
4
+ def main() -> None:
5
+ config = (
6
+ HikCamera.builder("cam")
7
+ .usb("PUT_SERIAL_HERE")
8
+ .settings(exposure_us=8000, gain=4.0, pixel_format="BayerRG8")
9
+ .continuous()
10
+ .build()
11
+ )
12
+
13
+ with HikCamera(config) as camera:
14
+ frame = camera.grab(timeout_ms=1000)
15
+ print(frame.frame_number, frame.width, frame.height, frame.pixel_format)
16
+
17
+
18
+ if __name__ == "__main__":
19
+ main()
20
+