No description
  • Rust 99.5%
  • Shell 0.5%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Thomas Eichinger e07699a43c add pctrl CLI, sweep test, and agent context
- 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>
2026-06-28 13:29:58 -07:00
src add pctrl CLI, sweep test, and agent context 2026-06-28 13:29:58 -07:00
tests add pctrl CLI, sweep test, and agent context 2026-06-28 13:29:58 -07:00
voltronic@b6466cb682 add pctrl CLI, sweep test, and agent context 2026-06-28 13:29:58 -07:00
.gitignore initial commit 2025-12-30 17:31:24 -08:00
agent.md add pctrl CLI, sweep test, and agent context 2026-06-28 13:29:58 -07:00
Cargo.lock add pctrl CLI, sweep test, and agent context 2026-06-28 13:29:58 -07:00
Cargo.toml add pctrl CLI, sweep test, and agent context 2026-06-28 13:29:58 -07:00
PROTOCOL.md initial commit 2025-12-30 17:31:24 -08:00
README.md initial commit 2025-12-30 17:31:24 -08:00
test_commands.sh initial commit 2025-12-30 17:31:24 -08:00
THREAD_SUMMARY.md initial commit 2025-12-30 17:31:24 -08:00
TODO.md initial commit 2025-12-30 17:31:24 -08:00

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

  1. 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"
  2. 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
  3. 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
  4. 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:

  1. Add command variant to ProtocolCommand enum in src/protocol/commands.rs
  2. Implement command_string() to return the command name
  3. Create response structure in src/protocol/responses.rs
  4. Implement parser in src/protocol/parser.rs
  5. Add SerialMessage variant in src/serial/mod.rs
  6. Update serial worker to parse new response type
  7. Add GUI button and handler in src/main.rs
  8. 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