Connecting to Devices
This guide explains how to discover and connect to piezosystem jena devices using psj-lib.
Connection Overview
psj-lib supports two connection methods:
Serial (USB): Direct USB connection using virtual COM port
Telnet (Ethernet): Network connection via Telnet protocol
The same high-level API is used regardless of transport type, allowing seamless switching between connection methods.
Final connectivity support depends on the specific device model.
Quick Start
The fastest way to connect:
import asyncio
from psj_lib import DDriveDevice, TransportType
async def main():
# Connect via Serial
device = DDriveDevice(TransportType.SERIAL, "COM3") # Windows
# device = DDriveDevice(TransportType.SERIAL, "/dev/ttyUSB0") # Linux
async with device:
# Device is now connected
print(f"Connected to {device.device_id}")
asyncio.run(main())
Device Discovery
Automatic Device Discovery
The discover_devices() method automatically finds connected devices:
import asyncio
from psj_lib import DDriveDevice, DiscoverFlags
async def discover():
# Discover all connected d-Drive devices
devices = await DDriveDevice.discover_devices()
for device in devices:
print(f"Device: {device.device_id}")
print(f"Address: {device.address}")
print(f"Type: {device.transport_type}")
print("---")
asyncio.run(discover())
Example Output:
Device: d-Drive
Address: COM3
Type: TransportType.SERIAL
---
Using Discovery with Connection
Complete discovery and connection example:
from psj_lib import DDriveDevice
async def discover_and_connect():
# Discover devices
devices = await DDriveDevice.discover_devices()
if not devices:
print("No devices found")
return
# Get first device (already created and ready to connect)
device = devices[0]
# Method 1: Connect with async context manager
async with device:
print(f"Connected to {device.device_id}")
channels = device.channels
print(f"Available channels: {len(channels)}")
# Method 2: Manual open/close
await device.connect()
try:
print(f"Connected to {device.device_id}")
# Use device...
finally:
await device.disconnect()
Serial Connection
Serial Port Identification
Windows:
Ports are named COM1, COM2, COM3, etc.
Check Device Manager → Ports (COM & LPT) to find your device.
Linux:
Ports are typically /dev/ttyUSB0, /dev/ttyACM0, etc.
Use ls /dev/ttyUSB* /dev/ttyACM* to list ports.
macOS:
Ports appear as /dev/cu.usbserial-* or /dev/tty.usbserial-*.
Use ls /dev/cu.* /dev/tty.* to list ports.
Creating a Serial Connection
from psj_lib import DDriveDevice, TransportType
async def connect_serial():
# Create device (not connected yet)
device = DDriveDevice(TransportType.SERIAL, "COM3")
# Connect using context manager (recommended)
async with device:
# Device is now open and connected
print(f"Connected to {device.device_id}")
# Access channels
for channel in device.channels:
status = await channel.status_register.read()
print(f"Channel {channel.channel_id}: {status}")
# Device automatically disconnected when exiting context
Manual Connection Management
If you need manual control over connection lifecycle:
async def manual_connection():
device = DDriveDevice(TransportType.SERIAL, "COM3")
try:
# Manually open connection
await device.open()
print("Device opened")
# Use device...
channels = device.channels
finally:
# Always close when done
await device.close()
print("Device closed")
Serial Port Settings
psj-lib automatically configures serial port settings. Most devices use:
Baud Rate: 115200
Data Bits: 8
Stop Bits: 1
Parity: None
Flow Control: None
For NV-family devices, identification is performed at 19200 baud and transport settings are adjusted by the driver as needed.
Connection Patterns
Context Manager Pattern (Recommended)
The context manager automatically handles connection lifecycle:
async def safe_connection():
device = DDriveDevice(TransportType.SERIAL, "COM3")
async with device:
# Connection opens here
channels = device.channels
# Do work with device
for channel in channels:
await channel.closed_loop_controller.set(True)
# Connection closes here (even if exception occurs)
Long-Running Connection
For applications that keep device connected:
class ControlSystem:
def __init__(self, port: str):
self.device = DDriveDevice(TransportType.SERIAL, port)
async def start(self):
await self.device.open()
print("System started")
async def stop(self):
await self.device.close()
print("System stopped")
async def move_channel(self, channel_id: int, position: float):
channel = self.device.channels[channel_id]
await channel.setpoint.set(position)
# Usage
system = ControlSystem("COM3")
await system.start()
# Use system...
await system.move_channel(0, 50.0)
# Clean shutdown
await system.stop()
Multiple Devices
Managing multiple devices simultaneously:
async def multi_device():
# Create multiple devices
device1 = DDriveDevice(TransportType.SERIAL, "COM3")
device2 = DDriveDevice(TransportType.TELNET, "192.168.1.100")
# Connect both
async with device1, device2:
# Both devices connected
# Parallel operations
await asyncio.gather(
device1.channels[0].setpoint.set(30.0),
device2.channels[0].setpoint.set(60.0)
)
Error Handling
Connection Failures
Handle connection errors gracefully:
from psj_lib import DeviceError, ProtocolError
async def safe_connect():
device = DDriveDevice(TransportType.SERIAL, "COM3")
try:
async with device:
print("Connected successfully")
# Use device...
except (DeviceError, ProtocolError) as e:
print(f"Failed to connect: {e}")
# Try alternative port or notify user
except Exception as e:
print(f"Unexpected error: {e}")
Timeout Configuration
Set timeout for connection attempts:
async def connect_with_timeout():
device = DDriveDevice(TransportType.SERIAL, "COM3")
try:
# Wait up to 5 seconds for connection
async with asyncio.timeout(5.0):
await device.connect()
print("Connected")
except asyncio.TimeoutError:
print("Connection timeout - check device power and cables")
Reconnection Logic
Implement automatic reconnection:
async def connect_with_retry(port: str, max_attempts: int = 3):
device = DDriveDevice(TransportType.SERIAL, port)
for attempt in range(max_attempts):
try:
await device.open()
print(f"Connected on attempt {attempt + 1}")
return device
except (DeviceError, ProtocolError):
print(f"Attempt {attempt + 1} failed")
if attempt < max_attempts - 1:
await asyncio.sleep(2.0) # Wait before retry
raise DeviceConnectionError(f"Failed after {max_attempts} attempts")
Verification
After connecting, verify device is ready:
async def verify_connection():
device = DDriveDevice(TransportType.SERIAL, "COM3")
async with device:
print(f"Device Info: {device.device_info}")
# Check channels discovered
print(f"Channels: {len(device.channels)}")
# Read status from each channel
for channel in device.channels:
status = await channel.status_register.get()
print(f"Channel {channel.id}:")
print(f" Closed loop: {status.closed_loop_state}")
print(f" Temperature: {await channel.temperature.get():.1f}°C")
Best Practices
Use Context Managers: Always use
async withfor automatic cleanupCheck Discovery: Use discovery before hardcoding ports/addresses
Handle Errors: Always catch and handle connection errors
Verify Connection: Read device info after connecting
Clean Shutdown: Ensure
close()is called or use context managerNetwork Stability: Use Telnet for permanent installations, Serial for development
Timeout Protection: Set reasonable timeouts for all operations
Single Connection: Don’t open multiple connections to same device
Troubleshooting
“Device Not Found”
Symptom: Discovery returns empty list
Solutions:
Check device is powered on
Verify cable connections
Check correct transport type (Serial vs Telnet)
Try manual port/address specification
Verify drivers installed (Serial)
Check network connectivity (Telnet)
“Permission Denied” (Linux Serial)
Symptom: Cannot open serial port
Solution: Add user to dialout group:
sudo usermod -a -G dialout $USER
# Log out and back in
“Connection Timeout”
Symptom: Connection attempts timeout
Solutions:
Verify device is not already connected by another application
Check baud rate (should be auto-detected)
Try power cycling the device
For Telnet: verify IP address and network connectivity
“Port Already in Use”
Symptom: Serial port locked by another application
Solutions:
Close any other applications using the device
Check for zombie processes:
lsof | grep ttyUSB(Linux)Disconnect and reconnect USB cable
Restart computer as last resort
Next Steps
Now that you can connect to devices:
Learn basic operations: Getting Started
Explore d-Drive features: d-Drive and 30DV50/300
See working examples: Examples