Power Control Example¶
This example demonstrates how to control device power using both VeSync smart outlets and CyberPower PDUs. Power control is fundamental for device testing - you’ll use it to boot devices, trigger resets, and safely power down hardware.
VeSync Smart Outlet Control¶
VeSync provides cloud-connected smart outlets that can be controlled remotely. This example shows how to use them with labgrid.
What You’ll Need:
VeSync account with one or more smart outlets
VeSync outlet name (configured in your VeSync account)
Account credentials (email and password)
Configuration File (target.yaml):
targets:
my_fpga_board:
resources:
VesyncOutlet:
outlet_names: 'FPGA Board Power' # Name of outlet in VeSync app
username: 'your_email@example.com'
password: 'your_password'
delay: 5.0 # Seconds to wait between off and on during cycle
drivers:
VesyncPowerDriver: {}
Basic Usage Script:
from labgrid import Environment
# Load target configuration
env = Environment("target.yaml")
target = env.get_target("my_fpga_board")
# Get the power driver
power = target.get_driver("VesyncPowerDriver")
# Activate the driver
target.activate(power)
# Turn on the device
print("Powering on device...")
power.on()
# Do some work with the device...
# (run tests, interact with serial console, etc.)
# Power off the device
print("Powering off device...")
power.off()
# Deactivate the driver
target.deactivate(power)
Power Cycle Operation (reset device):
from labgrid import Environment
import time
env = Environment("target.yaml")
target = env.get_target("my_fpga_board")
power = target.get_driver("VesyncPowerDriver")
target.activate(power)
# Power cycle: off -> wait -> on
print("Performing power cycle (reset)...")
power.cycle() # Automatically handles delay configured in resource
# Wait for device to fully boot
time.sleep(10)
print("Device reset complete")
target.deactivate(power)
Multiple Outlets:
VeSync supports controlling multiple outlets from a single driver:
targets:
test_rack:
resources:
VesyncOutlet:
outlet_names: 'Board A,Board B,Board C' # Comma-separated outlet names
username: 'your_email@example.com'
password: 'your_password'
delay: 5.0
drivers:
VesyncPowerDriver: {}
from labgrid import Environment
env = Environment("target.yaml")
target = env.get_target("test_rack")
power = target.get_driver("VesyncPowerDriver")
target.activate(power)
# All configured outlets are controlled together
print("Powering on all outlets...")
power.on() # Powers on: Board A, Board B, Board C
print("Powering off all outlets...")
power.off() # Powers off: Board A, Board B, Board C
target.deactivate(power)
CyberPower PDU Control¶
CyberPower PDUs provide industrial-grade power distribution with SNMP control. This is more reliable than cloud-connected outlets for critical testing environments.
What You’ll Need:
CyberPower PDU (tested on PDU15SWHVIEC8FNET and similar)
PDU hostname/IP address
SNMP community string (default is typically “public”)
Outlet number (usually 1-8)
Configuration File (target.yaml):
targets:
lab_device:
resources:
CyberPowerOutlet:
hostname: '192.168.1.100'
outlet_number: 1 # Outlet 1-8
snmp_version: '2c'
community: 'public'
drivers:
CyberPowerDriver: {}
Basic Usage Script:
from labgrid import Environment
# Load target configuration
env = Environment("target.yaml")
target = env.get_target("lab_device")
# Get the power driver
power = target.get_driver("CyberPowerDriver")
# Activate the driver
target.activate(power)
# Turn on the outlet
print("Powering on via CyberPower PDU outlet 1...")
power.on()
# Work with device...
# Power off
print("Powering off...")
power.off()
target.deactivate(power)
Multi-Outlet Control:
targets:
multi_outlet_system:
resources:
CyberPowerOutlet:
hostname: '192.168.1.100'
outlet_number: 1 # Can create multiple resources for different outlets
snmp_version: '2c'
community: 'public'
CyberPowerOutlet@board_b_power:
hostname: '192.168.1.100'
outlet_number: 2
snmp_version: '2c'
community: 'public'
drivers:
CyberPowerDriver: {}
CyberPowerDriver@board_b:
cyberpoweroutlet: CyberPowerOutlet@board_b_power
from labgrid import Environment
env = Environment("target.yaml")
target = env.get_target("multi_outlet_system")
# Get drivers for each outlet
power_a = target.get_driver("CyberPowerDriver")
power_b = target.get_driver("CyberPowerDriver@board_b")
target.activate(power_a)
target.activate(power_b)
# Control outlets independently
print("Powering on board A...")
power_a.on()
print("Powering on board B...")
power_b.on()
# Later...
print("Powering off board A...")
power_a.off()
target.deactivate(power_a)
target.deactivate(power_b)
Error Handling Patterns¶
Graceful Power Management with Error Recovery:
from labgrid import Environment
import time
def safe_power_control(target, outlet_name, command, retries=3):
"""Safely control power with error handling and retries."""
for attempt in range(retries):
try:
power = target.get_driver("VesyncPowerDriver")
target.activate(power)
if command == "on":
power.on()
elif command == "off":
power.off()
elif command == "cycle":
power.cycle()
target.deactivate(power)
print(f"Power {command} successful for {outlet_name}")
return True
except Exception as e:
print(f"Power control failed (attempt {attempt+1}/{retries}): {e}")
time.sleep(5) # Wait before retry
print(f"Failed to power {command} {outlet_name} after {retries} attempts")
return False
# Usage
env = Environment("target.yaml")
target = env.get_target("my_fpga_board")
safe_power_control(target, "my_fpga_board", "cycle")
Power Down with Validation:
from labgrid import Environment
import time
def ensure_powered_off(target, timeout=30):
"""Ensure device is powered off with validation."""
power = target.get_driver("VesyncPowerDriver")
target.activate(power)
try:
# Try graceful shutdown first
shell = target.get_driver("ADIShellDriver")
if target.get(shell):
try:
shell.sendline("poweroff")
time.sleep(5)
except:
pass
# Force power off if needed
power.off()
time.sleep(2)
print("Device powered off successfully")
except Exception as e:
print(f"Error powering off: {e}")
finally:
target.deactivate(power)
Monitoring Power State During Test:
from labgrid import Environment
import time
def run_test_with_power_monitoring(target, test_func, timeout=300):
"""Run test with periodic power state checks."""
power = target.get_driver("VesyncPowerDriver")
target.activate(power)
start_time = time.time()
try:
# Run test function
test_func()
except Exception as e:
print(f"Test failed: {e}")
# Power cycle on test failure
print("Performing emergency power cycle...")
power.cycle()
raise
finally:
elapsed = time.time() - start_time
print(f"Test completed in {elapsed:.1f} seconds")
target.deactivate(power)
Integration with Boot Strategies¶
Power control is usually managed automatically by boot strategies, but you can also use it directly:
Manual Power Control Before Strategy:
from labgrid import Environment
from adi_lg_plugins.strategies.bootfpgasoc import Status
env = Environment("target.yaml")
target = env.get_target("my_device")
# Ensure device is powered off before boot
power = target.get_driver("VesyncPowerDriver")
target.activate(power)
power.off()
target.deactivate(power)
# Now use strategy to boot (which handles power on)
strategy = target.get_strategy("BootFPGASoC")
strategy.transition("shell")
# Device now booted and at shell
shell = target.get_driver("ADIShellDriver")
shell.run_command("uname -a")
# Cleanup - strategy handles power down
strategy.transition("soft_off")
Power Cycling Between Tests:
from labgrid import Environment
import time
env = Environment("target.yaml")
target = env.get_target("my_device")
power = target.get_driver("VesyncPowerDriver")
strategy = target.get_strategy("BootFPGASoC")
def run_test_cycle(test_number):
"""Run a single test cycle with power management."""
print(f"\nTest cycle {test_number}")
# Ensure clean start with power cycle
target.activate(power)
power.cycle()
target.deactivate(power)
time.sleep(5)
# Boot device
strategy.transition("shell")
# Run tests
shell = target.get_driver("ADIShellDriver")
result = shell.run_command("./test_suite.sh")
print(f"Test result: {result}")
# Clean shutdown
strategy.transition("soft_off")
return "PASS" in result
# Run multiple test cycles
for cycle in range(5):
try:
success = run_test_cycle(cycle + 1)
print(f"Cycle {cycle+1}: {'PASSED' if success else 'FAILED'}")
except Exception as e:
print(f"Cycle {cycle+1}: ERROR - {e}")
# Ensure power is off on error
try:
target.get_driver("VesyncPowerDriver").off()
except:
pass
Complete Working Example¶
target.yaml:
targets:
test_device:
resources:
VesyncOutlet:
outlet_names: 'Test Device'
username: 'your_email@example.com'
password: 'your_password'
delay: 5.0
SerialPort:
port: '/dev/ttyUSB0'
baudrate: 115200
drivers:
VesyncPowerDriver: {}
ADIShellDriver:
console: SerialPort
prompt: 'root@.*:.*#'
login_prompt: 'login:'
username: 'root'
password: 'analog'
login_timeout: 60
test_power_control.py:
from labgrid import Environment
import time
def test_power_on_off():
"""Test basic power on/off operations."""
env = Environment("target.yaml")
target = env.get_target("test_device")
power = target.get_driver("VesyncPowerDriver")
# Test power on
print("Test 1: Power on")
target.activate(power)
power.on()
time.sleep(2)
assert power is not None # Device should be on
print(" PASSED")
# Test power off
print("Test 2: Power off")
power.off()
time.sleep(2)
assert power is not None # Device should be off
print(" PASSED")
target.deactivate(power)
def test_power_cycle():
"""Test power cycle (reset) operation."""
env = Environment("target.yaml")
target = env.get_target("test_device")
power = target.get_driver("VesyncPowerDriver")
print("Test 3: Power cycle")
target.activate(power)
# Perform cycle
power.cycle()
time.sleep(15) # Wait for device to boot
# Check device is booted
shell = target.get_driver("ADIShellDriver")
target.activate(shell)
output = shell.run_command("uname -a")
assert len(output) > 0
print(" Device booted after cycle")
print(" PASSED")
target.deactivate(shell)
target.deactivate(power)
if __name__ == "__main__":
test_power_on_off()
test_power_cycle()
print("\nAll tests passed!")
Troubleshooting¶
VeSync Login Fails:
Error: Failed to login to VeSync account
Solutions:
- Verify email and password are correct
- Check that account is not locked (too many login attempts)
- Ensure outlet is visible in VeSync app
- Verify outlet name matches exactly (case-sensitive)
CyberPower PDU Connection Failed:
Error: SNMP connection to PDU failed
Solutions:
- Verify PDU hostname/IP is reachable: ping 192.168.1.100
- Confirm SNMP is enabled on PDU
- Check community string (usually "public")
- Verify outlet number (typically 1-8)
- Check firewall allows SNMP (UDP port 161)
Power Command Times Out:
Error: Power command did not complete in time
Solutions:
- Check network connectivity
- Verify VeSync/PDU is accessible
- Try cycling power manually to verify hardware works
- Increase timeout in configuration
See Also¶
Common Use Cases - Common use cases and patterns
Drivers API - Driver API reference
Resources API - Resource configuration reference
Shell Commands Example - Shell command execution examples
Complete Boot Cycle Example - Complete boot workflow