Device Control API
Device Control Client
- class neoruntime_ipc_sdk.device.DeviceStatus(soc_temp_c: 'float', mcu_temp_c: 'float', light_sensor: 'int', ptz_pan_pos: 'int', ptz_tilt_pos: 'int', zoom_pos: 'int', focus_pos: 'int', autofocus_enabled: 'bool', ircut_mode: 'IrCutMode', white_light_level: 'int', ir_led_on: 'bool', mcu_version: 'str', mcu_uptime_ms: 'int')[source]
Bases:
object- soc_temp_c: float
- mcu_temp_c: float
- light_sensor: int
- ptz_pan_pos: int
- ptz_tilt_pos: int
- zoom_pos: int
- focus_pos: int
- autofocus_enabled: bool
- ircut_mode: IrCutMode
- white_light_level: int
- ir_led_on: bool
- mcu_version: str
- mcu_uptime_ms: int
- __init__(soc_temp_c, mcu_temp_c, light_sensor, ptz_pan_pos, ptz_tilt_pos, zoom_pos, focus_pos, autofocus_enabled, ircut_mode, white_light_level, ir_led_on, mcu_version, mcu_uptime_ms)
- class neoruntime_ipc_sdk.device.DeviceEvent(type: 'EventType', timestamp_ns: 'int', gpio_pin: 'int' = 0, gpio_value: 'bool' = False, light_sensor_value: 'int' = 0, temperature: 'float' = 0.0)[source]
Bases:
object- class EventType(value)[source]
Bases:
Enum- GPIO_CHANGE = 0
- LIGHT_SENSOR_CHANGE = 1
- TEMPERATURE_ALERT = 2
- PTZ_MOVE_COMPLETE = 3
- FOCUS_COMPLETE = 4
- type: EventType
- timestamp_ns: int
- gpio_pin: int = 0
- gpio_value: bool = False
- light_sensor_value: int = 0
- temperature: float = 0.0
- __init__(type, timestamp_ns, gpio_pin=0, gpio_value=False, light_sensor_value=0, temperature=0.0)
- class neoruntime_ipc_sdk.device.AfJob(accepted, job_id, message)[source]
Bases:
objectResult of starting an autofocus job (native AF RPCs).
- accepted: bool
- job_id: int
- message: str
- __init__(accepted, job_id, message)
- class neoruntime_ipc_sdk.device.AfStatus(job_id, operation, state, progress, busy, anchor_valid, requested_ratio, effective_ratio, zoom_pos, focus_pos, best_focus, metric, confidence, reproducibility, estimated_distance_m, elapsed_ms, error_code, message)[source]
Bases:
objectFull snapshot of the autofocus engine state.
- job_id: int
- operation: str
- state: str
- progress: float
- busy: bool
- anchor_valid: bool
- requested_ratio: float
- effective_ratio: float
- zoom_pos: int
- focus_pos: int
- best_focus: int
- metric: float
- confidence: float
- reproducibility: float
- estimated_distance_m: float
- elapsed_ms: int
- error_code: int
- message: str
- __init__(job_id, operation, state, progress, busy, anchor_valid, requested_ratio, effective_ratio, zoom_pos, focus_pos, best_focus, metric, confidence, reproducibility, estimated_distance_m, elapsed_ms, error_code, message)
- class neoruntime_ipc_sdk.device.AfMeasurement(focus_energy, mean_luma, frame_id)[source]
Bases:
objectPer-window focus telemetry from the last AF measurement.
- focus_energy: list
- mean_luma: list
- frame_id: int
- __init__(focus_energy, mean_luma, frame_id)
- class neoruntime_ipc_sdk.device.DeviceClient(endpoint=None)[source]
Bases:
GrpcClientDevice Control Client
- Usage:
dev = DeviceClient()
dev.set_white_light(80) dev.set_ir_led(True) dev.set_ircut(IrCutMode.NIGHT)
dev.pan_left(speed=50) dev.call_preset(3)
dev.zoom_in() dev.focus_auto()
- set_white_light(level)[source]
- set_ir_led(on)[source]
- set_ircut(mode)[source]
- pan_left(speed=50)[source]
- pan_right(speed=50)[source]
- pan_stop()[source]
- tilt_up(speed=50)[source]
- tilt_down(speed=50)[source]
- tilt_stop()[source]
- ptz_stop()[source]
- save_preset(preset_id)[source]
- call_preset(preset_id)[source]
- zoom_in(speed=50)[source]
- zoom_out(speed=50)[source]
- zoom_stop()[source]
- zoom(speed)[source]
- set_zoom_level(level)[source]
- focus_in(speed=50)[source]
- focus_out(speed=50)[source]
- focus_stop()[source]
- focus(speed)[source]
- focus_auto(enable=True)[source]
- set_focus_level(level)[source]
- get_lens_status()[source]
- set_lens_limits(zoom_limit=None, focus_limit=None)[source]
Set lens axis position limits.
- Parameters:
Example:
dev.set_lens_limits(zoom_limit={"min_pos": 0, "max_pos": 1000}) dev.set_lens_limits( zoom_limit={"min_pos": 0, "max_pos": 1000}, focus_limit={"min_pos": 0, "max_pos": 800}, )
- oneshot_autofocus(timeout=20.0)[source]
Perform a single autofocus cycle: enable → wait for convergence → disable.
This is a composite operation that: 1. Enables continuous autofocus 2. Polls lens status until focus motor settles (or timeout) 3. Disables continuous autofocus
- Parameters:
timeout (float) – Maximum seconds to wait for focus convergence (default: 20.0)
- Raises:
RuntimeError – If autofocus fails to converge within timeout
TimeoutError – If focus motor does not settle within timeout
- start_oneshot_af()[source]
Start a one-shot autofocus job and return its handle immediately.
Unlike
oneshot_autofocus()(a blocking composite over the legacy SetAutofocus RPC), this returns at once; pair it withget_autofocus_status()to poll for convergence.
- start_zoom_follow(ratio)[source]
Start continuous autofocus locked to a zoom ratio.
- Parameters:
ratio (float) – Zoom ratio the focus engine should track (e.g. 1.5).
- get_autofocus_status()[source]
Snapshot of the autofocus engine (job, progress, lens positions).
- cancel_autofocus(job_id=0)[source]
Cancel an autofocus job.
- Parameters:
job_id (int) – Job to cancel; 0 (default) cancels the active job.
- set_af_windows(enabled, windows, stream_id='main')[source]
Set autofocus measurement windows for a stream.
- get_af_measurement()[source]
Latest per-window focus telemetry (focus energy / luma).
- set_wiegand_out(channel, enable)[source]
Enable or disable a Wiegand output channel.
- get_wiegand_out(channel)[source]
Get the enabled state of a Wiegand output channel.
- rs485_init(baudrate, config='')[source]
Initialize RS-485 serial interface.
- rs485_deinit()[source]
Deinitialize RS-485 serial interface.
- lens_reset_zero(zoom=True, focus=True)[source]
- control_iris(open)[source]
- set_iris_target(target)[source]
- lens_init()[source]
- lens_goto_ratio_distance(zoom_ratio, focus_distance_m)[source]
- gpio_set(pin, value)[source]
- gpio_get(pin)[source]
- get_device_status()[source]
- subscribe_events()[source]
DeviceClient
- class neoruntime_ipc_sdk.DeviceClient(endpoint=None)[source]
Bases:
GrpcClientDevice Control Client
- Usage:
dev = DeviceClient()
dev.set_white_light(80) dev.set_ir_led(True) dev.set_ircut(IrCutMode.NIGHT)
dev.pan_left(speed=50) dev.call_preset(3)
dev.zoom_in() dev.focus_auto()
- set_white_light(level)[source]
- set_ir_led(on)[source]
- set_ircut(mode)[source]
- pan_left(speed=50)[source]
- pan_right(speed=50)[source]
- pan_stop()[source]
- tilt_up(speed=50)[source]
- tilt_down(speed=50)[source]
- tilt_stop()[source]
- ptz_stop()[source]
- save_preset(preset_id)[source]
- call_preset(preset_id)[source]
- zoom_in(speed=50)[source]
- zoom_out(speed=50)[source]
- zoom_stop()[source]
- zoom(speed)[source]
- set_zoom_level(level)[source]
- focus_in(speed=50)[source]
- focus_out(speed=50)[source]
- focus_stop()[source]
- focus(speed)[source]
- focus_auto(enable=True)[source]
- set_focus_level(level)[source]
- get_lens_status()[source]
- set_lens_limits(zoom_limit=None, focus_limit=None)[source]
Set lens axis position limits.
- Parameters:
Example:
dev.set_lens_limits(zoom_limit={"min_pos": 0, "max_pos": 1000}) dev.set_lens_limits( zoom_limit={"min_pos": 0, "max_pos": 1000}, focus_limit={"min_pos": 0, "max_pos": 800}, )
- oneshot_autofocus(timeout=20.0)[source]
Perform a single autofocus cycle: enable → wait for convergence → disable.
This is a composite operation that: 1. Enables continuous autofocus 2. Polls lens status until focus motor settles (or timeout) 3. Disables continuous autofocus
- Parameters:
timeout (float) – Maximum seconds to wait for focus convergence (default: 20.0)
- Raises:
RuntimeError – If autofocus fails to converge within timeout
TimeoutError – If focus motor does not settle within timeout
- start_oneshot_af()[source]
Start a one-shot autofocus job and return its handle immediately.
Unlike
oneshot_autofocus()(a blocking composite over the legacy SetAutofocus RPC), this returns at once; pair it withget_autofocus_status()to poll for convergence.
- start_zoom_follow(ratio)[source]
Start continuous autofocus locked to a zoom ratio.
- Parameters:
ratio (float) – Zoom ratio the focus engine should track (e.g. 1.5).
- get_autofocus_status()[source]
Snapshot of the autofocus engine (job, progress, lens positions).
- cancel_autofocus(job_id=0)[source]
Cancel an autofocus job.
- Parameters:
job_id (int) – Job to cancel; 0 (default) cancels the active job.
- set_af_windows(enabled, windows, stream_id='main')[source]
Set autofocus measurement windows for a stream.
- get_af_measurement()[source]
Latest per-window focus telemetry (focus energy / luma).
- set_wiegand_out(channel, enable)[source]
Enable or disable a Wiegand output channel.
- get_wiegand_out(channel)[source]
Get the enabled state of a Wiegand output channel.
- rs485_init(baudrate, config='')[source]
Initialize RS-485 serial interface.
- rs485_deinit()[source]
Deinitialize RS-485 serial interface.
- lens_reset_zero(zoom=True, focus=True)[source]
- control_iris(open)[source]
- set_iris_target(target)[source]
- lens_init()[source]
- lens_goto_ratio_distance(zoom_ratio, focus_distance_m)[source]
- gpio_set(pin, value)[source]
- gpio_get(pin)[source]
- get_device_status()[source]
- subscribe_events()[source]
Data Types
DeviceStatus
- class neoruntime_ipc_sdk.DeviceStatus(soc_temp_c: 'float', mcu_temp_c: 'float', light_sensor: 'int', ptz_pan_pos: 'int', ptz_tilt_pos: 'int', zoom_pos: 'int', focus_pos: 'int', autofocus_enabled: 'bool', ircut_mode: 'IrCutMode', white_light_level: 'int', ir_led_on: 'bool', mcu_version: 'str', mcu_uptime_ms: 'int')[source]
- __init__(soc_temp_c, mcu_temp_c, light_sensor, ptz_pan_pos, ptz_tilt_pos, zoom_pos, focus_pos, autofocus_enabled, ircut_mode, white_light_level, ir_led_on, mcu_version, mcu_uptime_ms)
DeviceEvent
- class neoruntime_ipc_sdk.DeviceEvent(type: 'EventType', timestamp_ns: 'int', gpio_pin: 'int' = 0, gpio_value: 'bool' = False, light_sensor_value: 'int' = 0, temperature: 'float' = 0.0)[source]
- class EventType(value)[source]
- GPIO_CHANGE = 0
- LIGHT_SENSOR_CHANGE = 1
- TEMPERATURE_ALERT = 2
- PTZ_MOVE_COMPLETE = 3
- FOCUS_COMPLETE = 4
- __init__(type, timestamp_ns, gpio_pin=0, gpio_value=False, light_sensor_value=0, temperature=0.0)
IrCutMode
Usage Examples
Light Control
from neoruntime_ipc_sdk import DeviceClient, IrCutMode
dev = DeviceClient()
# White light control
dev.set_white_light(0) # Off
dev.set_white_light(50) # 50% brightness
dev.set_white_light(100) # 100% brightness
# IR LED control
dev.set_ir_led(True) # On
dev.set_ir_led(False) # Off
# IR cut filter control
dev.set_ircut(IrCutMode.DAY) # Day mode (filter on)
dev.set_ircut(IrCutMode.NIGHT) # Night mode (filter off)
dev.set_ircut(IrCutMode.AUTO) # Auto mode
PTZ Control
# Pan movement
dev.pan_left(speed=50) # Move left
dev.pan_right(speed=50) # Move right
dev.pan_stop() # Stop horizontal movement
# Tilt movement
dev.tilt_up(speed=50) # Move up
dev.tilt_down(speed=50) # Move down
dev.tilt_stop() # Stop vertical movement
# Stop all PTZ movement
dev.ptz_stop()
Preset Control
# Save preset
dev.save_preset(1) # Save current position to preset 1
# Call preset
dev.call_preset(1) # Move to preset 1
Lens Control
# Lens initialization
dev.lens_init() # Initialize lens module
# Zoom
dev.zoom_in(speed=50) # Zoom in
dev.zoom_out(speed=50) # Zoom out
dev.zoom_stop() # Stop zoom
# Set zoom level (0.0 ~ 1.0)
dev.set_zoom_level(0.5) # 50% zoom position
# Focus
dev.focus_in(speed=50) # Far focus
dev.focus_out(speed=50) # Near focus
dev.focus_stop() # Stop focus
# Set focus level (0.0 ~ 1.0)
dev.set_focus_level(0.5) # 50% focus position
# Auto focus
dev.focus_auto(enable=True) # Enable auto focus
dev.focus_auto(enable=False) # Disable auto focus
# One-shot auto focus (composite: enable → wait for convergence → disable)
dev.oneshot_autofocus(timeout=20.0)
# Zoom + focus linked move (by optical zoom ratio and focus distance)
dev.lens_goto_ratio_distance(zoom_ratio=2.0, focus_distance_m=3.0)
# Iris control
dev.control_iris(open=True) # Open iris
dev.set_iris_target(128) # Set iris target value
# Lens reset zero
dev.lens_reset_zero(zoom=True, focus=True) # Reset both axes
# Set lens limits
dev.set_lens_limits(zoom_limit={"min_pos": 0, "max_pos": 1000})
dev.set_lens_limits(
zoom_limit={"min_pos": 0, "max_pos": 1000},
focus_limit={"min_pos": 0, "max_pos": 800},
)
# Get lens status
status = dev.get_lens_status()
print(f"Zoom pos: {status['zoom_pos']}")
print(f"Focus pos: {status['focus_pos']}")
print(f"Zoom state: {status['zoom_state']}") # 0=not ready, 1=idle, 2=moving
print(f"Autofocus: {status['autofocus_enabled']}")
GPIO Control
# Read GPIO
value = dev.gpio_get(12)
print(f"GPIO 12 state: {'high' if value else 'low'}")
# Write GPIO
dev.gpio_set(21, True) # Set high
dev.gpio_set(21, False) # Set low
# Control relay
dev.gpio_set(22, True) # Turn on relay
Wiegand Control
# Set Wiegand output
dev.set_wiegand_out(channel=0, enable=True) # Enable Wiegand channel 0
dev.set_wiegand_out(channel=1, enable=False) # Disable Wiegand channel 1
# Query Wiegand output state
enabled = dev.get_wiegand_out(channel=0)
print(f"Wiegand channel 0: {'enabled' if enabled else 'disabled'}")
RS-485 Serial Control
# Initialize RS-485
dev.rs485_init(baudrate=9600)
# Transmit data
dev.rs485_tx(b"hello")
# Deinitialize
dev.rs485_deinit()
Getting Device Status
# Get full status
status = dev.get_device_status()
print(f"SoC temperature: {status.soc_temp_c}°C")
print(f"MCU temperature: {status.mcu_temp_c}°C")
print(f"Light sensor: {status.light_sensor}")
print(f"White light: {status.white_light_level}%")
print(f"IR LED: {'on' if status.ir_led_on else 'off'}")
print(f"IR-Cut: {status.ircut_mode}")
print(f"PTZ position: Pan={status.ptz_pan_pos}, Tilt={status.ptz_tilt_pos}")
print(f"Zoom position: {status.zoom_pos}")
print(f"Focus position: {status.focus_pos}")
print(f"Auto focus: {'enabled' if status.autofocus_enabled else 'disabled'}")
print(f"MCU version: {status.mcu_version}")
print(f"MCU uptime: {status.mcu_uptime_ms}ms")
Monitoring Device Events
# Subscribe to device events
for event in dev.subscribe_events():
print(f"Event type: {event.type}")
print(f"Timestamp: {event.timestamp_ns}")
if event.type == DeviceEvent.EventType.GPIO_CHANGE:
print(f"GPIO pin: {event.gpio_pin}, value: {event.gpio_value}")
elif event.type == DeviceEvent.EventType.LIGHT_SENSOR_CHANGE:
print(f"Light sensor value: {event.light_sensor_value}")
elif event.type == DeviceEvent.EventType.TEMPERATURE_ALERT:
print(f"Temperature alert: {event.temperature}°C")
elif event.type == DeviceEvent.EventType.PTZ_MOVE_COMPLETE:
print("PTZ move complete")
elif event.type == DeviceEvent.EventType.FOCUS_COMPLETE:
print("Focus complete")
Context Manager
# Use context manager for automatic connection management
with DeviceClient() as dev:
dev.set_white_light(80)
status = dev.get_device_status()
print(f"Light: {status.white_light_level}%")
Error Handling
try:
dev.set_white_light(150) # Invalid value
except RuntimeError as e:
print(f"Setting failed: {e}")
try:
value = dev.gpio_get(99) # Invalid pin
except RuntimeError as e:
print(f"GPIO read failed: {e}")