feat: SPE Expert amplifier control (serial/TCP) — OPERATE toggle + live status

Implements the SPE Application Programmer's Guide protocol: packets
0x55 0x55 0x55|CNT|DATA|CHK (sum%256), OPERATE key 0x0D (toggles STANDBY/OPERATE)
and STATUS request 0x90 whose 0xAA-framed reply is a 19-field CSV (mode, RX/TX,
band, power level, output W, SWR, V/I, temp, warnings, alarms). internal/spe
polls status ~1/s over USB serial (go.bug.st/serial, 8N1) or TCP (RS232-to-
Ethernet bridge) — same codec, different transport.

Wired via startPGXL (starts the SPE client for spe* types), bindings GetSPEStatus
/ SPESetOperate, and a live status card + OPERATE/STANDBY toggle in the Amplifier
settings panel. Only the two example-anchored commands are sent (safe); other
keystroke codes were ambiguous in the guide's table. Untested on hardware.
This commit is contained in:
2026-07-20 17:59:24 +02:00
parent 666b933114
commit 2e39615554
6 changed files with 438 additions and 11 deletions
+5
View File
@@ -11,6 +11,7 @@ import {awardref} from '../models';
import {cluster} from '../models';
import {extsvc} from '../models';
import {powergenius} from '../models';
import {spe} from '../models';
import {solar} from '../models';
import {winkeyer} from '../models';
import {alerts} from '../models';
@@ -406,6 +407,8 @@ export function GetRotatorHeading():Promise<main.RotatorHeading>;
export function GetRotatorSettings():Promise<main.RotatorSettings>;
export function GetSPEStatus():Promise<spe.Status>;
export function GetSecretStatus():Promise<main.SecretStatus>;
export function GetSlotStats():Promise<qso.SlotStats>;
@@ -716,6 +719,8 @@ export function RotatorStop():Promise<void>;
export function RunBackupNow():Promise<string>;
export function SPESetOperate(arg1:boolean):Promise<void>;
export function SaveADIFFile():Promise<string>;
export function SaveADIFMonitor(arg1:main.ADIFMonitorConfig):Promise<void>;
+8
View File
@@ -770,6 +770,10 @@ export function GetRotatorSettings() {
return window['go']['main']['App']['GetRotatorSettings']();
}
export function GetSPEStatus() {
return window['go']['main']['App']['GetSPEStatus']();
}
export function GetSecretStatus() {
return window['go']['main']['App']['GetSecretStatus']();
}
@@ -1390,6 +1394,10 @@ export function RunBackupNow() {
return window['go']['main']['App']['RunBackupNow']();
}
export function SPESetOperate(arg1) {
return window['go']['main']['App']['SPESetOperate'](arg1);
}
export function SaveADIFFile() {
return window['go']['main']['App']['SaveADIFFile']();
}
+47
View File
@@ -4108,6 +4108,53 @@ export namespace solar {
}
export namespace spe {
export class Status {
connected: boolean;
last_error?: string;
model?: string;
operate: boolean;
tx: boolean;
input?: string;
band?: string;
power_level?: string;
output_w: number;
swr_atu: number;
swr_ant: number;
volt_pa: number;
curr_pa: number;
temp_c: number;
warnings?: string;
alarms?: string;
static createFrom(source: any = {}) {
return new Status(source);
}
constructor(source: any = {}) {
if ('string' === typeof source) source = JSON.parse(source);
this.connected = source["connected"];
this.last_error = source["last_error"];
this.model = source["model"];
this.operate = source["operate"];
this.tx = source["tx"];
this.input = source["input"];
this.band = source["band"];
this.power_level = source["power_level"];
this.output_w = source["output_w"];
this.swr_atu = source["swr_atu"];
this.swr_ant = source["swr_ant"];
this.volt_pa = source["volt_pa"];
this.curr_pa = source["curr_pa"];
this.temp_c = source["temp_c"];
this.warnings = source["warnings"];
this.alarms = source["alarms"];
}
}
}
export namespace udp {
export class Config {