No description
- Rust 99.5%
- Shell 0.5%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
- Add pctrl CLI binary (src/bin/pctrl.rs) with clap subcommands and exit codes - Add blocking serial helper (src/serial/blocking.rs) used by the CLI - Add lib.rs crate root re-exporting protocol and serial modules - Add integration tests (tests/cli_test.rs, tests/sweep_test.rs) - tests/sweep_test.rs sweeps 1200–115200 baud to find a working rate; skips gracefully without hardware, set PCTRL_DEVICE to run against the inverter - Add agent.md with codebase context, known issues, and run instructions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
| src | ||
| tests | ||
| voltronic@b6466cb682 | ||
| .gitignore | ||
| agent.md | ||
| Cargo.lock | ||
| Cargo.toml | ||
| PROTOCOL.md | ||
| README.md | ||
| test_commands.sh | ||
| THREAD_SUMMARY.md | ||
| TODO.md | ||
pctrl - Solar Inverter Control
A Rust GUI application for controlling and monitoring solar power inverters (specifically the Zola ESS 5k inverter) via serial communication.
Features
Core Functionality
- Serial Communication - Non-blocking serial I/O in separate thread with automatic port discovery
- Protocol Commands - One-click buttons for QPIRI (device info) and QPIGS (general status)
- Automatic Response Parsing - Responses automatically parsed into strongly-typed structures
- Response Buffering - Handles fragmented responses across multiple serial reads with timeout detection
- Real-time Monitoring - Live connection status and device parameter display
- Command History - Navigate previous commands with up/down arrow keys
- Console Logging - All communication logged for debugging
Supported Commands
Query Commands
- QPIRI - Query Device Rating Information (30 fields including voltages, currents, battery config, system settings)
- QPIGS - Query General Status (24 fields including real-time voltages, currents, power, temperature, charging status)
- QMOD - Query Device Mode (returns current operating mode: Line/Battery/Standby/Fault/Power Saving)
- QMUCHGCR - Query Available Utility Max Charging Currents (returns list of valid charging current values)
Control Commands
- MUCHGC - Set Utility Max Charging Current (configure max charging current from grid, with ACK/NAK response)
Protocol Features
- CRC-16-XMODEM validation with reserved character escaping
- Type-safe command serialization and response deserialization
- Comprehensive error handling with detailed error messages
- Automatic CRC calculation - no manual CRC entry needed
- Timeout detection - Detects incomplete responses (1 second timeout)
- Fragmentation handling - Reassembles responses split across multiple reads
Quick Start
Building
# Check compilation
cargo check
# Build debug version
cargo build
# Build release version
cargo build --release
# Run application
cargo run
Usage
-
Connect to Inverter
- Application will auto-discover serial ports
- Select your inverter's port from dropdown (e.g.,
/dev/tty.usbserial-*) - Choose baud rate (typically 2400 for Zola ESS 5k)
- Click "Connect"
-
Query Device Information
- Click "Query Device Info (QPIRI)" to get device ratings and configuration
- Click "Query General Status (QPIGS)" to get real-time status
- Click "Query Mode (QMOD)" to get current operating mode
- Responses are automatically parsed and displayed in human-readable format
-
Configure Charging Current (Control Command)
- Click "Query Available Currents" to get list of valid charging current values
- Select machine number (typically 0 for single-unit installations)
- Choose desired charging current from dropdown
- Click "Set Max Charging Current" to apply
- ACK response indicates success, NAK indicates rejection
-
Manual Commands
- Type commands in the text field for advanced usage
- Use up/down arrows to navigate command history
Architecture
Component Overview
┌─────────────────────────────────────────────────────────────┐
│ GUI (iced framework) │
│ - Connection controls │
│ - Protocol command buttons │
│ - Console output │
└────────────┬────────────────────────────────────────────────┘
│ Message Passing (mpsc channels)
↓
┌─────────────────────────────────────────────────────────────┐
│ Serial Worker Thread │
│ - Manages serial port connection │
│ - Automatic protocol parsing │
│ - Non-blocking I/O │
└────────────┬────────────────────────────────────────────────┘
│
↓
┌─────────────────────────────────────────────────────────────┐
│ Serial Port → Inverter │
└─────────────────────────────────────────────────────────────┘
Project Structure
pctrl/
├── Cargo.toml
├── README.md
├── PROTOCOL.md # Protocol implementation details
├── TODO.md # Outstanding tasks
├── src/
│ ├── main.rs # GUI application (520 lines)
│ ├── serial/
│ │ └── mod.rs # Serial communication (200 lines)
│ └── protocol/
│ ├── mod.rs # Public API
│ ├── crc.rs # CRC-16-XMODEM implementation
│ ├── commands.rs # Command definitions
│ ├── responses.rs # Response structures (30+ fields)
│ ├── parser.rs # Response parsing
│ └── serializer.rs # Command serialization
└── tests/
└── protocol_integration_test.rs
Message Flow
Sending Commands:
User clicks button
→ Message::QueryDeviceInfoPressed
→ SerialCommand::SendCommand(ProtocolCommand::QueryDeviceRatingInfo)
→ serialize_command() [automatic CRC]
→ Serial Port → Inverter
Receiving Responses:
Inverter → Serial Port
→ bytes received
→ parse_qpiri_response() or parse_qpigs_response()
→ SerialMessage::QpiriResponse or QpigsResponse
→ GUI displays structured data
GUI Layout
┌─────────────────────────────────────────────────────────────┐
│ Connection Settings │
│ Serial Port: [/dev/tty.usbserial-XXXX ▼] │
│ Baud Rate: [2400 ▼] [Connect] │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Protocol Commands │
│ [Query Device Info (QPIRI)] [Query General Status (QPIGS)]│
│ [Query Mode (QMOD)] │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Command │
│ [Enter command...] [Send] │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Console Output │
│ ───────────────────────────────────────────────────────────│
│ Connected to /dev/tty.usbserial-XXXX │
│ > QPIRI (Query Device Info) │
│ < QPIRI Response Parsed: │
│ Grid Rating: 230.0V / 21.7A │
│ AC Output Rating: 230.0V / 21.7A / 50.0Hz │
│ Battery: 48.0V (type: Lithium Ion) │
│ ... │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Status: Connected: /dev/tty.usbserial-XXXX │
└─────────────────────────────────────────────────────────────┘
Dependencies
[dependencies]
iced = "0.14" # Cross-platform GUI framework
serialport = "4.3" # Serial port communication
tokio = "1" # Async runtime
async-std = "1.12" # Async utilities
notify = "6.1" # Filesystem monitoring for port discovery
System Requirements
- Rust 1.70+ (2021 edition)
- Platform Support:
- ✅ macOS (primary development platform)
- ✅ Linux (should work, needs testing)
- ✅ Windows (should work, needs testing)
Example Output
QPIRI Response (Device Rating Information)
< QPIRI Response Parsed:
Grid Rating: 230.0V / 21.7A
AC Output Rating: 230.0V / 21.7A / 50.0Hz
AC Output Power: 5000VA / 5000W
Battery: 48.0V (recharge: 46.0V, under: 42.0V, bulk: 56.4V, float: 54.0V)
Battery Type: Lithium Ion (LFP)
Max Charging Current: 60A (AC: 30A)
Input Voltage Range: Appliance
Output Source Priority: Solar-Battery-Grid
Charger Source Priority: Solar First
Parallel Max: 6
Machine Type: Hybrid
Topology: Transformerless
Output Mode: Single Machine
PV OK Condition: As long as one unit has connected PV
PV Power Balance: PV input max power will be the max charged power
QPIGS Response (General Status)
< QPIGS Response Parsed:
Grid: 230.1V / 50.0Hz
AC Output: 230.0V / 50.0Hz / 1200VA / 1100W
Output Load: 22%
Bus Voltage: 360V
Battery: 52.4V / 15A charging / 85% capacity
Battery Discharge Current: 0A
Inverter Temperature: 42°C
PV Input: 380.5V / 8.2A / 3120W
Battery Voltage from SCC: 52.5V
Charging Mode: Charging with SCC
Load: ON
Battery Voltage Steady: true
Solar Feed Status: Normal
Country Regulation: Germany
QMOD Response (Device Mode)
< QMOD Response Parsed:
Device Mode: Line (Grid)
Development Status
✅ Completed
- Serial communication layer with automatic port discovery
- Complete QPIRI, QPIGS, and QMOD protocol implementation
- Automatic response parsing with CRC validation
- GUI with protocol command buttons
- Command history and console logging
- Physical disconnect detection
🚧 In Progress
See TODO.md for detailed task list
Contributing
When adding new protocol commands:
- Add command variant to
ProtocolCommandenum insrc/protocol/commands.rs - Implement
command_string()to return the command name - Create response structure in
src/protocol/responses.rs - Implement parser in
src/protocol/parser.rs - Add
SerialMessagevariant insrc/serial/mod.rs - Update serial worker to parse new response type
- Add GUI button and handler in
src/main.rs - Add display logic for response
Example pattern already implemented for QPIRI and QPIGS commands.
License
See LICENSE file for details.
Documentation
- README.md (this file) - Overview, building, usage
- PROTOCOL.md - Detailed protocol implementation
- TODO.md - Outstanding tasks and future enhancements