Serial Cables HYDRA Controller - User's Manual

Serial Cables HYDRA Controller
User's Manual
Python Library for PCIe Gen6 HYDRA JBOF Systems
Version 1.0.0 | November 2025

# 1. Introduction

The Serial Cables HYDRA Controller is a comprehensive Python library designed for controlling and monitoring Serial Cables PCIe Gen6 HYDRA 8-Bay Passive JBOF (Just a Bunch of Flash) enclosures. This library provides complete hardware control, environmental monitoring, and alerting capabilities through a serial CLI interface.

## Key Features

- Complete Hardware Control: Full implementation of all documented MCU commands
- Environmental Monitoring: Real-time temperature, voltage, current, and power monitoring
- SSD Slot Management: Individual and bulk control of all 8 SSD slots
- LED Control: Host and fault LED management for visual status indication
- Fan Control: PWM speed control and monitoring of cooling fans
- I2C/SMBus Communication: Direct device access for advanced diagnostics
- Comprehensive Logging: CSV data logging for long-term analysis
- Alert System: Configurable thresholds for proactive monitoring

## Hardware Compatibility

Parameter | Specification
--- | ---
Model | Serial Cables PCIe Gen6 8-Bay Passive JBOF
Firmware Version | 0.0.2 and above
Connection Interface | USB Type-C serial interface
Serial Configuration | 115200 baud, 8N1
Operating Systems | Windows, Linux, macOS
Python Version | 3.7 and above

# 2. Installation

## System Requirements

- Python 3.7 or higher
- pyserial >= 3.5
- USB Type-C cable for JBOF connection
- Appropriate serial port drivers (usually automatic)

## Installation Methods

### From PyPI (Recommended)

Install the latest stable version from the Python Package Index:

pip install serialcables-hydra

### Verification

Verify your installation by importing the library:

python -c "from serialcables_hydra import JBOFController; print('Installation successful')"
Success: If the import completes without errors, your installation is ready to use.

# 3. Quick Start Guide

## Basic Connection and Monitoring

This example demonstrates the essential operations for connecting to and monitoring your HYDRA JBOF:

from serialcables_hydra import JBOFController, PowerState # Initialize controller (adjust port for your system) controller = JBOFController(port='COM3') # Windows # controller = JBOFController(port='/dev/ttyUSB0') # Linux # Connect to HYDRA system if controller.connect(): print("Connected to HYDRA JBOF successfully!") # Get system information sys_info = controller.get_system_info() print(f"Model: {sys_info.model}") print(f"Firmware: {sys_info.firmware_version}") print(f"Serial Number: {sys_info.serial_number}") # Check slot status slots = controller.show_slot_info() print("\nSlot Status:") for slot in slots: status = "SSD Present" if slot.present else "Empty" print(f"Slot {slot.slot_number}: {status}") # Get environmental data env_data = controller.get_environmental_data() print(f"\nEnvironmental Status:") print(f"PSU Voltage: {env_data['voltages']['psu_12v']:.2f}V") print(f"MCU Temperature: {env_data['temperatures']['mcu']:.1f}°C") print(f"Fan 1 Speed: {env_data['fan_speeds']['fan_1']} RPM") # Disconnect when done controller.disconnect() else: print("Failed to connect to HYDRA JBOF")

## Essential SSD Management

Control power and monitor individual SSD slots:

from serialcables_hydra import JBOFController, PowerState import time controller = JBOFController(port='COM3') controller.connect() # Check current power status power_status = controller.get_slot_power_status() print("Current slot power status:") for slot_num, status in power_status.items(): print(f"Slot {slot_num}: {status}") # Power cycle slot 1 (if SSD is present) print("\nPower cycling slot 1...") controller.slot_power(1, PowerState.OFF) time.sleep(2) # Wait for clean shutdown controller.slot_power(1, PowerState.ON) # Control LED for visual indication controller.control_host_led(1, PowerState.ON) # Turn on LED time.sleep(3) controller.control_host_led(1, PowerState.OFF) # Turn off LED controller.disconnect()
Important: Always ensure SSDs are properly shut down before powering off slots to prevent data corruption. The library provides safe power cycling with appropriate delays.

# 4. Hardware Setup

## Physical Connection

1. Power Connection: Ensure the HYDRA JBOF is properly connected to power and powered on
2. USB Connection: Connect the USB Type-C cable between your computer and the JBOF's management port
3. SSD Installation: Install NVMe SSDs in the desired slots (1-8)
4. PCIe Connection: Connect PCIe cables from the host system to the JBOF

## Serial Port Identification

### Windows

- Open Device Manager
- Expand "Ports (COM & LPT)"
- Look for "USB Serial Port" or similar device
- Note the COM port number (e.g., COM3, COM4)

### Linux

# List available serial ports ls /dev/tty* # Check for USB serial devices ls /dev/ttyUSB* /dev/ttyACM* # View detailed information dmesg | grep tty

### macOS

# List serial ports ls /dev/tty.* # Look for USB serial devices ls /dev/tty.usbserial-* /dev/tty.usbmodem-*

## Permissions Setup (Linux/macOS)

Grant access to serial ports:

# Temporary permission sudo chmod 666 /dev/ttyUSB0 # Permanent solution - add user to dialout group sudo usermod -a -G dialout $USER # Log out and back in for changes to take effect
Note: The exact port name may vary depending on your system configuration and connected devices. Always verify the correct port before connecting.

# 5. API Reference

## Core Classes

### JBOFController / HydraController

Main controller class for HYDRA JBOF interaction. Both class names are equivalent and can be used interchangeably.

#### Constructor

JBOFController(port: str, baudrate: int = 115200, timeout: float = 1.0)

Parameter | Type | Default | Description
--- | --- | --- | ---
port | str | Required | Serial port path (e.g., 'COM3', '/dev/ttyUSB0')
baudrate | int | 115200 | Serial communication baud rate
timeout | float | 1.0 | Command timeout in seconds

## System Control Methods

### connect() → bool

Establish serial connection to the JBOF system.

controller = JBOFController('COM3') if controller.connect(): print("Connection successful")

### disconnect()

Close the serial connection and clean up resources.

controller.disconnect()

### system_power(state: PowerState) → bool

Control main system power state.

# Power on the system controller.system_power(PowerState.ON) # Power off the system controller.system_power(PowerState.OFF)

### reset() → bool

Perform a soft reset of the MCU.

controller.reset()

## Slot Management Methods

### slot_power(slot: Union[int, str], state: PowerState) → bool

Control power for specific slot(s).

# Power on slot 1 controller.slot_power(1, PowerState.ON) # Power off slot 3 controller.slot_power(3, PowerState.OFF) # Power on all slots controller.slot_power('all', PowerState.ON)

### get_slot_power_status() → Dict[int, str]

Retrieve current power status for all slots.

status = controller.get_slot_power_status() for slot_num, power_state in status.items(): print(f"Slot {slot_num}: {power_state}")

### show_slot_info() → List[SlotInfo]

Get detailed information about all slots.

slots = controller.show_slot_info() for slot in slots: print(f"Slot {slot.slot_number}:") print(f" Present: {slot.present}") print(f" Paddle Card: {slot.paddle_card}") print(f" Temperature: {slot.temperature}°C")

## Environmental Monitoring Methods

### get_environmental_data() → Dict

Retrieve comprehensive environmental data.

env_data = controller.get_environmental_data() # Access temperatures for location, temp in env_data['temperatures'].items(): print(f"{location}: {temp:.1f}°C") # Access voltages for rail, voltage in env_data['voltages'].items(): print(f"{rail}: {voltage:.2f}V") # Access fan speeds for fan, rpm in env_data['fan_speeds'].items(): print(f"{fan}: {rpm} RPM")

### get_system_info() → SystemInfo

Get complete system information.

sys_info = controller.get_system_info() print(f"Company: {sys_info.company}") print(f"Model: {sys_info.model}") print(f"Serial Number: {sys_info.serial_number}") print(f"Firmware: {sys_info.firmware_version}")

## LED Control Methods

### control_host_led(slot: Union[int, str], state: PowerState) → bool

Control host LED on EDSFF drives.

# Turn on host LED for slot 1 controller.control_host_led(1, PowerState.ON) # Turn off host LED for all slots controller.control_host_led('all', PowerState.OFF)

### control_fault_led(slot: Union[int, str], state: PowerState) → bool

Control fault LED indicators.

# Signal fault condition on slot 2 controller.control_fault_led(2, PowerState.ON)

## Fan Control Methods

### set_fan_speed(fan_id: int, duty_cycle: int) → bool

Set fan PWM duty cycle for speed control.

# Set fan 1 to 75% speed controller.set_fan_speed(1, 75) # Set fan 2 to maximum speed controller.set_fan_speed(2, 100) # Set fan 1 to minimum speed controller.set_fan_speed(1, 30)
Caution: Setting fan speed too low may result in overheating. Monitor temperatures when adjusting fan speeds.

## Advanced Features

### I2C/SMBus Communication

#### i2c_read(address: int, slot: int, register: int, length: int) → List[int]

Read data from I2C/SMBus devices connected to SSD slots.

# Read 8 bytes from device 0x50, register 0x00 on slot 1 data = controller.i2c_read(0x50, 1, 0x00, 8) if data: hex_data = ' '.join(f'{b:02X}' for b in data) print(f"Data read: {hex_data}")

#### i2c_write(address: int, slot: int, data: List[int]) → bool

Write data to I2C/SMBus devices.

# Write data to device 0x50 on slot 1 data = [0x00, 0x01, 0x02, 0x03] success = controller.i2c_write(0x50, 1, data)

### Control Buzzer

from serialcables_hydra import BuzzerState # Turn buzzer on controller.control_buzzer(BuzzerState.ON) # Turn buzzer off controller.control_buzzer(BuzzerState.OFF) # Enable buzzer for alerts controller.control_buzzer(BuzzerState.ENABLE)

### Additional Reset Functions

#### smbus_reset(slot: Union[int, str]) → bool

Send SMBus reset signal to selected slot(s).

controller.smbus_reset(1) # Reset SMBus for slot 1 controller.smbus_reset('all') # Reset SMBus for all slots

#### ssd_reset(slot: Union[int, str], channel: Optional[str] = None) → bool

Send PERST# reset signal to selected slot(s).

controller.ssd_reset(1) # Reset both channels for slot 1 controller.ssd_reset(2, 'a') # Reset only channel A for slot 2 controller.ssd_reset(3, 'b') # Reset only channel B for slot 3

# 6. Monitoring and Alerting

## Real-time Monitoring

The HYDRA controller provides comprehensive monitoring capabilities for proactive system management.

### Continuous Monitoring Loop

from serialcables_hydra import JBOFController, BuzzerState import time def continuous_monitor(port, duration=300): controller = JBOFController(port) controller.connect() start_time = time.time() alert_count = 0 print("Starting continuous monitoring...") print("Press Ctrl+C to stop") try: while time.time() - start_time < duration: env_data = controller.get_environmental_data() # Monitor temperatures for location, temp in env_data['temperatures'].items(): if temp > 55: # Critical temperature print(f"CRITICAL: High temperature {location}: {temp:.1f}°C") controller.control_buzzer(BuzzerState.ON) alert_count += 1 elif temp > 45: # Warning temperature print(f"WARNING: Elevated temperature {location}: {temp:.1f}°C") # Monitor voltages psu_voltage = env_data['voltages']['psu_12v'] if psu_voltage < 11.5 or psu_voltage > 12.5: print(f"WARNING: PSU voltage out of range: {psu_voltage:.2f}V") alert_count += 1 # Monitor fan speeds for fan, rpm in env_data['fan_speeds'].items(): if rpm < 3000: print(f"ALERT: Low fan speed {fan}: {rpm} RPM") controller.control_buzzer(BuzzerState.ON) alert_count += 1 # Display current status every 30 seconds if int(time.time() - start_time) % 30 == 0: print(f"Status: {alert_count} alerts, PSU: {psu_voltage:.2f}V") time.sleep(5) # Check every 5 seconds except KeyboardInterrupt: print("\nMonitoring stopped by user") finally: controller.control_buzzer(BuzzerState.OFF) controller.disconnect() print(f"Monitoring complete. Total alerts: {alert_count}") # Run monitoring for 5 minutes continuous_monitor('COM3', duration=300)

### Alert Thresholds

Parameter | Warning Level | Critical Level
--- | --- | ---
Temperature | 45°C | 55°C
PSU Voltage | < 11.5V or > 12.5V | < 11.0V or > 13.0V
Fan Speed | < 3000 RPM | < 1000 RPM
Current | > 80% rated | > 95% rated

## Data Logging

Implement data logging for historical analysis and trending:

import csv import datetime from serialcables_hydra import JBOFController def log_environmental_data(port, log_file, interval=60, duration=3600): controller = JBOFController(port) controller.connect() # Create CSV file with headers with open(log_file, 'w', newline='') as csvfile: fieldnames = ['timestamp', 'mcu_temp', 'psu_voltage', 'fan1_rpm', 'fan2_rpm', 'slot1_temp', 'slot1_power'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() start_time = time.time() while time.time() - start_time < duration: env_data = controller.get_environmental_data() slots = controller.show_slot_info() # Log current data log_entry = { 'timestamp': datetime.datetime.now().isoformat(), 'mcu_temp': env_data['temperatures']['mcu'], 'psu_voltage': env_data['voltages']['psu_12v'], 'fan1_rpm': env_data['fan_speeds']['fan_1'], 'fan2_rpm': env_data['fan_speeds']['fan_2'], 'slot1_temp': slots[0].temperature if slots else 0, 'slot1_power': slots[0].power if slots else 0 } writer.writerow(log_entry) csvfile.flush() # Ensure data is written print(f"Logged data at {log_entry['timestamp']}") time.sleep(interval) controller.disconnect() print(f"Data logging complete. File saved: {log_file}") # Log data every minute for 1 hour log_environmental_data('COM3', 'hydra_log.csv', interval=60, duration=3600)

# 7. Troubleshooting

## Connection Issues

### Problem: Cannot Connect to Serial Port

# Test port availability import serial try: ser = serial.Serial('COM3', 115200, timeout=1) print("Port is available") ser.close() except serial.SerialException as e: print(f"Port error: {e}")

#### Solutions:

- Verify Port Name: Double-check the correct port identifier for your system
- Check Cable Connection: Ensure USB Type-C cable is securely connected
- Driver Installation: Install or update USB-to-serial drivers if needed
- Permission Issues: On Linux/macOS, ensure user has permission to access serial ports
- Port in Use: Close any other applications that might be using the port

### Problem: Commands Timeout

#### Solutions:

- Increase timeout value in constructor: JBOFController('COM3', timeout=5.0)
- Check baud rate matches device configuration (115200)
- Verify firmware compatibility (version 0.0.2+)

### Problem: Inconsistent Responses

#### Solutions:

- Add delays between commands for busy systems
- Implement retry logic for critical operations
- Check for electrical interference near USB cable

## Hardware Issues

### Problem: SSD Not Detected

#### Diagnostic Steps:

# Check slot status slots = controller.show_slot_info() for slot in slots: print(f"Slot {slot.slot_number}: Present={slot.present}, Power={slot.power_status}") # Verify power status power_status = controller.get_slot_power_status() print("Power status:", power_status) # Check clock signals clock_status = controller.check_clock_input() print("Clock status:", clock_status)

#### Solutions:

- Verify SSD is properly seated in slot
- Check power connections to JBOF
- Ensure PCIe cables are connected
- Power cycle the affected slot

### Problem: High Temperature Alerts

#### Diagnostic Steps:

# Check all temperature sensors env_data = controller.get_environmental_data() for location, temp in env_data['temperatures'].items(): status = "CRITICAL" if temp > 55 else "WARNING" if temp > 45 else "OK" print(f"{location}: {temp:.1f}°C [{status}]") # Check fan operation for fan, rpm in env_data['fan_speeds'].items(): status = "LOW" if rpm < 3000 else "OK" print(f"{fan}: {rpm} RPM [{status}]")

#### Solutions:

- Verify fans are operating at appropriate speeds
- Check for obstructed airflow
- Reduce ambient temperature if possible
- Consider reducing SSD workload temporarily

## Software Issues

### Problem: Import Errors

# Verify installation pip show serialcables-hydra # Check Python path import sys print("Python path:", sys.path) # Test basic import try: from serialcables_hydra import JBOFController print("Import successful") except ImportError as e: print(f"Import failed: {e}")

### Problem: Permission Denied (Linux/macOS)

# Check current user groups groups # Add user to dialout group sudo usermod -a -G dialout $USER # Alternative: temporary permission sudo chmod 666 /dev/ttyUSB0

## Diagnostic Tools

### System Health Check

def system_health_check(port): """Comprehensive system health check""" try: controller = JBOFController(port) if not controller.connect(): print("[FAILED] Connection failed") return False print("[SUCCESS] Connection successful") # Run built-in diagnostics diag_results = controller.run_diagnostics() print("\nDiagnostic Results:") for device, status in diag_results.items(): symbol = "[OK]" if status == "OK" else "[FAIL]" print(f"{symbol} {device}: {status}") # Check environmental status env_data = controller.get_environmental_data() print("\nEnvironmental Status:") # Temperature check temps_ok = all(temp < 50 for temp in env_data['temperatures'].values()) print(f"[{'OK' if temps_ok else 'WARN'}] Temperatures: {'OK' if temps_ok else 'Elevated'}") # Fan check fans_ok = all(rpm > 3000 for rpm in env_data['fan_speeds'].values()) print(f"[{'OK' if fans_ok else 'FAIL'}] Fans: {'OK' if fans_ok else 'Low Speed'}") # Voltage check voltage = env_data['voltages']['psu_12v'] voltage_ok = 11.5 <= voltage <= 12.5 print(f"[{'OK' if voltage_ok else 'WARN'}] PSU Voltage: {voltage:.2f}V {'OK' if voltage_ok else 'Out of Range'}") controller.disconnect() return True except Exception as e: print(f"[FAILED] Health check failed: {e}") return False # Run health check system_health_check('COM3')

# 8. Examples

## Complete System Management

This example demonstrates comprehensive system management including monitoring, alerts, and automated responses:

from serialcables_hydra import JBOFController, PowerState, BuzzerState import time import logging # Configure logging logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') logger = logging.getLogger(__name__) class HydraSystemManager: def __init__(self, port, temp_warning=45, temp_critical=55): self.controller = JBOFController(port) self.temp_warning = temp_warning self.temp_critical = temp_critical self.alert_count = 0 def connect(self): """Establish connection and perform initial checks""" if not self.controller.connect(): logger.error("Failed to connect to JBOF") return False logger.info("Connected to JBOF successfully") # Initial system check sys_info = self.controller.get_system_info() logger.info(f"System: {sys_info.model} (FW: {sys_info.firmware_version})") return True def monitor_system(self, duration=3600): """Monitor system for specified duration""" start_time = time.time() last_alert_time = 0 logger.info(f"Starting system monitoring for {duration} seconds") try: while time.time() - start_time < duration: env_data = self.controller.get_environmental_data() current_time = time.time() # Temperature monitoring max_temp = max(env_data['temperatures'].values()) if max_temp > self.temp_critical: self.handle_critical_temperature(max_temp) elif max_temp > self.temp_warning: self.handle_temperature_warning(max_temp) # Fan monitoring min_fan_speed = min(env_data['fan_speeds'].values()) if min_fan_speed < 1000: self.handle_fan_failure(min_fan_speed) elif min_fan_speed < 3000: self.handle_fan_warning(min_fan_speed) # Voltage monitoring voltage = env_data['voltages']['psu_12v'] if not (11.5 <= voltage <= 12.5): self.handle_voltage_warning(voltage) # Log status every 5 minutes if current_time - last_alert_time > 300: logger.info(f"Status: Temp={max_temp:.1f}°C, Voltage={voltage:.2f}V, " f"Fans={min_fan_speed}RPM, Alerts={self.alert_count}") last_alert_time = current_time time.sleep(30) # Check every 30 seconds except KeyboardInterrupt: logger.info("Monitoring stopped by user") finally: self.controller.control_buzzer(BuzzerState.OFF) logger.info(f"Monitoring complete. Total alerts: {self.alert_count}") def handle_critical_temperature(self, temp): """Handle critical temperature condition""" logger.critical(f"CRITICAL TEMPERATURE: {temp:.1f}°C") self.controller.control_buzzer(BuzzerState.ON) self.alert_count += 1 # Increase fan speeds to maximum self.controller.set_fan_speed(1, 100) self.controller.set_fan_speed(2, 100) logger.info("Fan speeds increased to maximum") def handle_temperature_warning(self, temp): """Handle temperature warning""" logger.warning(f"Temperature warning: {temp:.1f}°C") self.alert_count += 1 def handle_fan_failure(self, rpm): """Handle fan failure""" logger.critical(f"FAN FAILURE: {rpm} RPM") self.controller.control_buzzer(BuzzerState.ON) self.alert_count += 1 def handle_fan_warning(self, rpm): """Handle fan speed warning""" logger.warning(f"Low fan speed: {rpm} RPM") self.alert_count += 1 def handle_voltage_warning(self, voltage): """Handle voltage out of range""" logger.warning(f"Voltage out of range: {voltage:.2f}V") self.alert_count += 1 def power_cycle_slot(self, slot_number): """Safely power cycle a specific slot""" logger.info(f"Power cycling slot {slot_number}") # Turn on indicator LED self.controller.control_host_led(slot_number, PowerState.ON) # Power off self.controller.slot_power(slot_number, PowerState.OFF) logger.info(f"Slot {slot_number} powered off") time.sleep(5) # Wait for clean shutdown # Power on self.controller.slot_power(slot_number, PowerState.ON) logger.info(f"Slot {slot_number} powered on") time.sleep(3) # Turn off indicator LED self.controller.control_host_led(slot_number, PowerState.OFF) def disconnect(self): """Clean disconnection""" if self.controller: self.controller.disconnect() logger.info("Disconnected from JBOF") # Usage example if __name__ == "__main__": manager = HydraSystemManager('COM3', temp_warning=45, temp_critical=55) if manager.connect(): try: # Monitor system for 1 hour manager.monitor_system(duration=3600) finally: manager.disconnect()

## Automated Slot Testing

Automated testing routine for all populated slots:

def automated_slot_test(port): """Comprehensive automated slot testing""" controller = JBOFController(port) if not controller.connect(): print("Connection failed") return print("Starting automated slot testing...") # Get initial slot status slots = controller.show_slot_info() populated_slots = [slot for slot in slots if slot.present] if not populated_slots: print("No SSDs detected for testing") controller.disconnect() return print(f"Testing {len(populated_slots)} populated slots") test_results = [] for slot in populated_slots: slot_num = slot.slot_number print(f"\nTesting Slot {slot_num}...") test_result = { 'slot': slot_num, 'initial_temp': slot.temperature, 'power_cycle_success': False, 'led_test_success': False, 'final_temp': None } try: # Test LED control print(" Testing LED control...") controller.control_host_led(slot_num, PowerState.ON) time.sleep(2) controller.control_host_led(slot_num, PowerState.OFF) test_result['led_test_success'] = True print(" [SUCCESS] LED test passed") # Test power cycling print(" Testing power cycle...") initial_power = controller.get_slot_power_status()[slot_num] # Power off controller.slot_power(slot_num, PowerState.OFF) time.sleep(3) off_power = controller.get_slot_power_status()[slot_num] # Power on controller.slot_power(slot_num, PowerState.ON) time.sleep(5) final_power = controller.get_slot_power_status()[slot_num] if initial_power == 'on' and off_power == 'off' and final_power == 'on': test_result['power_cycle_success'] = True print(" [SUCCESS] Power cycle test passed") else: print(f" [FAILED] Power cycle test failed: {initial_power}→{off_power}→{final_power}") # Get final temperature updated_slots = controller.show_slot_info() final_slot = next(s for s in updated_slots if s.slot_number == slot_num) test_result['final_temp'] = final_slot.temperature except Exception as e: print(f" ❌ Test failed: {e}") test_results.append(test_result) time.sleep(2) # Brief pause between slot tests # Print summary print("\n" + "="*50) print("TEST SUMMARY") print("="*50) for result in test_results: slot_num = result['slot'] led_status = "PASS" if result['led_test_success'] else "FAIL" power_status = "PASS" if result['power_cycle_success'] else "FAIL" temp_change = result['final_temp'] - result['initial_temp'] if result['final_temp'] else 0 print(f"Slot {slot_num}:") print(f" LED Test: {led_status}") print(f" Power Test: {power_status}") print(f" Temperature: {result['initial_temp']:.1f}°C → {result['final_temp']:.1f}°C ({temp_change:+.1f}°C)") print() # Overall results total_tests = len(test_results) led_passes = sum(1 for r in test_results if r['led_test_success']) power_passes = sum(1 for r in test_results if r['power_cycle_success']) print(f"Overall Results:") print(f" LED Tests: {led_passes}/{total_tests} passed") print(f" Power Tests: {power_passes}/{total_tests} passed") controller.disconnect() return test_results # Run automated testing results = automated_slot_test('COM3')

# 9. Command Line Tools

The HYDRA Controller package includes command-line tools for system monitoring and control.

## hydra-monitor

Continuous monitoring tool with real-time display and alerting.

### Basic Usage

# Basic monitoring hydra-monitor --port COM3 # Monitor with custom settings hydra-monitor --port /dev/ttyUSB0 --interval 30 --duration 3600 # Monitor with logging hydra-monitor --port COM3 --log hydra_data.csv --interval 60 # Monitor with custom alert thresholds hydra-monitor --port COM3 --temp-warning 50 --temp-critical 60 --fan-min 4000

### Command Options

Option | Description | Default
--- | --- | ---
--port | Serial port path | Required
--interval | Monitoring interval (seconds) | 30
--duration | Total duration (seconds, 0=infinite) | 0
--log | CSV log file path | None
--temp-warning | Temperature warning threshold (°C) | 45
--temp-critical | Temperature critical threshold (°C) | 55
--fan-min | Minimum fan speed (RPM) | 3000
--voltage-min | Minimum voltage (V) | 11.5
--voltage-max | Maximum voltage (V) | 12.5

## hydra-cli

Command-line interface for direct system control and status queries.

### Available Commands

# System status hydra-cli --port COM3 status # Power control hydra-cli --port COM3 power-on --slot 1 hydra-cli --port COM3 power-off --slot 2 hydra-cli --port COM3 power-cycle --slot 3 # Environmental data hydra-cli --port COM3 environment hydra-cli --port COM3 temperatures hydra-cli --port COM3 fans # LED control hydra-cli --port COM3 led-on --slot 1 hydra-cli --port COM3 led-off --slot all # Diagnostics hydra-cli --port COM3 diagnostics hydra-cli --port COM3 version

### Output Formats

# Default human-readable output hydra-cli --port COM3 status # JSON output for scripting hydra-cli --port COM3 status --format json # CSV output for data analysis hydra-cli --port COM3 environment --format csv

## Integration with Scripts

Example shell script for automated monitoring:

#!/bin/bash # HYDRA monitoring script PORT="/dev/ttyUSB0" LOG_DIR="/var/log/hydra" DATE=$(date +%Y%m%d_%H%M%S) # Create log directory mkdir -p $LOG_DIR # Start background monitoring hydra-monitor --port $PORT --log "$LOG_DIR/hydra_$DATE.csv" --duration 86400 & MONITOR_PID=$! echo "HYDRA monitoring started (PID: $MONITOR_PID)" echo "Log file: $LOG_DIR/hydra_$DATE.csv" # Function to check system status check_status() { hydra-cli --port $PORT status --format json > "$LOG_DIR/status_$DATE.json" # Check for critical conditions CRITICAL=$(hydra-cli --port $PORT temperatures | grep -c "CRITICAL") if [ $CRITICAL -gt 0 ]; then echo "CRITICAL: High temperature detected!" # Send alert (email, SMS, etc.) # mail -s "HYDRA Critical Alert" admin@company.com < "$LOG_DIR/status_$DATE.json" fi } # Check status every 5 minutes while kill -0 $MONITOR_PID 2>/dev/null; do check_status sleep 300 done echo "Monitoring completed"

# 10. Support

## Getting Help

For technical support and assistance with the Serial Cables HYDRA Controller:

### Contact Information

- HYDRA Specific Support: hydra@serialcables.com
- General Technical Support: support@serialcables.com
- Documentation: GitHub repository and PyPI package page
- Bug Reports: GitHub Issues tracker

## Before Contacting Support

Please gather the following information to help expedite support:

### System Information

from serialcables_hydra import JBOFController # Collect system information for support def collect_support_info(port): info = { 'library_version': '1.0.0', 'python_version': None, 'platform': None, 'jbof_info': None, 'connection_status': False } # Python and platform info import sys, platform info['python_version'] = sys.version info['platform'] = platform.platform() try: controller = JBOFController(port) if controller.connect(): info['connection_status'] = True sys_info = controller.get_system_info() info['jbof_info'] = { 'model': sys_info.model, 'firmware': sys_info.firmware_version, 'serial': sys_info.serial_number } controller.disconnect() except Exception as e: info['connection_error'] = str(e) return info # Generate support information support_data = collect_support_info('COM3') print("Support Information:") for key, value in support_data.items(): print(f"{key}: {value}")

### Information to Include

- Library version and Python version
- Operating system and platform details
- HYDRA JBOF model and firmware version
- Complete error messages and stack traces
- Steps to reproduce the issue
- Expected vs. actual behavior
- Serial port configuration and connection details

## Common Support Scenarios

### Hardware Compatibility

Verify your hardware is compatible:

- Confirm JBOF model is supported
- Check firmware version (0.0.2 or higher required)
- Verify USB Type-C cable functionality

### Performance Issues

For performance-related concerns:

- Monitor system resources during operation
- Check for thermal throttling or overheating
- Verify adequate power supply capacity
- Analyze environmental data trends

### Integration Support

For help integrating with your systems:

- Provide details about your application architecture
- Share relevant code snippets
- Describe integration requirements and constraints

## Community Resources

- GitHub Repository: Source code, examples, and issues
- PyPI Package Page: Installation and version information
- Documentation: Online documentation and API reference
- Release Notes: Change log and version history

## Feedback and Contributions

We welcome feedback and contributions to improve the HYDRA Controller library:

- Report bugs and suggest features via GitHub Issues
- Contribute code improvements through pull requests
- Share usage examples and best practices
- Help improve documentation and examples