fix(kpa): its own card, and no band-follow it does not need
Two things the wiring got wrong, both visible on screen. A KPA fell through to the PowerGenius branch of the amplifier card and was drawn as one — titled 'POWERGENIUSXL · ELECRAFT KPA1500', with a PowerGenius's meters and none of its own. It has a card now: OPERATE, ON and OFF, band, power, SWR, temperature, supply, and the fault across the end. The OPERATE button carries a tooltip saying it also clears the fault, because that is the button an operator already has under the cursor when they need it. And the band-follow option was offered on it. That option exists because an Acom POLLS a transceiver and has no command to be given a band, so following it needs a second serial port and a rig emulator answering those polls. The KPA has ^BN — OpsLog simply tells it, on the link it is already using, and only when the band CHANGES. The option is gone from the KPA and the telling is automatic. Also: Acom rather than ACOM everywhere it is read, which is how the company writes it. Identifiers, package names and log lines are left alone — renaming those is churn with no reader.
This commit is contained in:
@@ -47,7 +47,7 @@ function powerLevelLabel(pl?: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
type Amp = { id: string; name: string; type?: string; spe?: any; acom?: any; pgxl?: any };
|
||||
type Amp = { id: string; name: string; type?: string; spe?: any; acom?: any; kpa?: any; pgxl?: any };
|
||||
|
||||
export function AmpCard({ amp, flex, t }: { amp: Amp; flex: any; t: (k: string, v?: any) => string }) {
|
||||
// Peak-hold so the jittery VITA-49 meters read steadily (own ref per card).
|
||||
@@ -64,6 +64,7 @@ export function AmpCard({ amp, flex, t }: { amp: Amp; flex: any; t: (k: string,
|
||||
|
||||
const isSPE = !!amp.spe;
|
||||
const isACOM = !!amp.acom;
|
||||
const isKPA = !!amp.kpa;
|
||||
|
||||
if (isSPE) {
|
||||
const spe = amp.spe;
|
||||
@@ -127,7 +128,7 @@ export function AmpCard({ amp, flex, t }: { amp: Amp; flex: any; t: (k: string,
|
||||
if (isACOM) {
|
||||
const acom = amp.acom;
|
||||
return (
|
||||
<Card icon={Flame} ckey="amplifier" title={`${t('flxp.amplifier')} · ${amp.name || `ACOM${acom.model ? ' ' + acom.model : ''}`}`} accent="#ea580c">
|
||||
<Card icon={Flame} ckey="amplifier" title={`${t('flxp.amplifier')} · ${amp.name || `Acom${acom.model ? ' ' + acom.model : ''}`}`} accent="#ea580c">
|
||||
<div className="flex items-center gap-3 flex-wrap">
|
||||
<button type="button" disabled={!acom.connected}
|
||||
onClick={() => AmpOperate(amp.id, !acom.operate).catch(() => {})}
|
||||
@@ -168,6 +169,53 @@ export function AmpCard({ amp, flex, t }: { amp: Amp; flex: any; t: (k: string,
|
||||
);
|
||||
}
|
||||
|
||||
if (isKPA) {
|
||||
const kpa = amp.kpa;
|
||||
return (
|
||||
<Card icon={Flame} ckey="amplifier" title={`${t('flxp.amplifier')} · ${amp.name || kpa.model || 'Elecraft'}`} accent="#ea580c">
|
||||
<div className="flex items-center gap-3 flex-wrap">
|
||||
<button type="button" disabled={!kpa.connected}
|
||||
onClick={() => AmpOperate(amp.id, !kpa.operate).catch(() => {})}
|
||||
title={kpa.fault_text ? t('flxp.kpaClearsFault') : undefined}
|
||||
className={cn('px-4 py-2 rounded-lg text-sm font-extrabold tracking-wide border-2 transition-all disabled:opacity-30',
|
||||
kpa.operate ? 'bg-warning text-warning-foreground border-warning shadow-[0_0_14px] shadow-warning/50' : 'bg-card text-warning border-warning hover:bg-warning-muted')}>
|
||||
{kpa.operate ? 'OPERATE' : 'STANDBY'}
|
||||
</button>
|
||||
{/* The amplifier answers while its main supplies are off — a sleeping
|
||||
microcontroller stays awake for exactly that — so ON is offered
|
||||
over the network as well, unlike the SPE and Acom. */}
|
||||
<div className="inline-flex rounded-lg overflow-hidden border-2 border-success/70">
|
||||
<button type="button" disabled={!kpa.connected}
|
||||
onClick={() => AmpPower(amp.id, true).catch(() => {})}
|
||||
className="px-3 py-2 text-sm font-bold bg-card text-success hover:bg-success/15 disabled:opacity-30">ON</button>
|
||||
<button type="button" disabled={!kpa.connected}
|
||||
onClick={() => AmpPower(amp.id, false).catch(() => {})}
|
||||
className="px-3 py-2 text-sm font-bold bg-card text-danger border-l-2 border-success/70 hover:bg-danger/15 disabled:opacity-30">OFF</button>
|
||||
</div>
|
||||
<span className={cn('inline-flex items-center gap-1.5 text-sm', kpa.connected ? 'text-muted-foreground' : 'text-danger')}>
|
||||
<span className={cn('size-2 rounded-full', kpa.connected ? 'bg-success' : 'bg-danger')} />
|
||||
{kpa.connected ? (kpa.tuning ? t('flxp.kpaTuning') : (kpa.power_on ? 'ON' : 'OFF')) : t('flxp.acomOffline')}
|
||||
</span>
|
||||
{kpa.connected && (
|
||||
<span className="text-sm font-mono text-muted-foreground tabular-nums">
|
||||
{kpa.band ? `${kpa.band} · ` : ''}{kpa.fwd_w}W · SWR {Number(kpa.swr ?? 0).toFixed(1)} · {kpa.temp_c}°C · {kpa.volt_v}V {kpa.cur_a}A
|
||||
</span>
|
||||
)}
|
||||
<div className="flex-1" />
|
||||
{kpa.fault_text && (
|
||||
<span className="px-2 py-1 rounded bg-danger-muted text-danger-muted-foreground text-xs font-bold">⚠ {kpa.fault_text}</span>
|
||||
)}
|
||||
</div>
|
||||
{kpa.connected && (
|
||||
<MeterBar label={t('flxp.outputPower')} value={Number(kpa.fwd_w) || 0} unit="W"
|
||||
lo={0} hi={String(kpa.model).includes('500') ? 500 : 1500}
|
||||
display={`${Number(kpa.fwd_w) || 0} W`}
|
||||
segColor={(f) => (f > 0.9 ? '#dc2626' : f > 0.75 ? '#f59e0b' : '#ea580c')} />
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
// PowerGenius XL — OPERATE + meters ride on the Flex; fan mode on the GSCP link.
|
||||
const pg = amp.pgxl || {};
|
||||
const viaFlex = !!flex?.amp_available;
|
||||
|
||||
Reference in New Issue
Block a user