fix(rotator): put the SP/LP readout inside the compass itself
It went under the Station Control rotator; the compass that wanted it is the docked one beside the entry strip. Both are the same RotorCompass, so the readout moves INTO that component: every compass in the app carries it, and no caller draws its own. The bezel already showed the short path as a red marker, but a marker is a direction, not a number — and the numbers in the status bar are 10px, which is what prompted this. Clickable only when the caller passed onGoto, since a compass rendered without one cannot turn anything and a button that does nothing is worse than a label.
This commit is contained in:
+19
-17
@@ -65,23 +65,25 @@ const (
|
||||
// AutoUpload + UploadMode are common to all (timing is per-service, so the
|
||||
// user can run e.g. Club Log immediate and QRZ delayed).
|
||||
type ServiceConfig struct {
|
||||
APIKey string `json:"api_key"`
|
||||
URL string `json:"url"` // Cloudlog/Wavelog: base URL of the user's own instance
|
||||
StationID string `json:"station_id"` // Cloudlog/Wavelog: station profile (location) id
|
||||
Email string `json:"email"` // Club Log account email
|
||||
Username string `json:"username"` // LoTW website login (for confirmation download)
|
||||
Password string `json:"password"` // Club Log account / LoTW website password
|
||||
Callsign string `json:"callsign"` // Club Log / HRDLog logbook (owner) callsign
|
||||
Code string `json:"code"` // HRDLog: account upload code
|
||||
QTHNickname string `json:"qth_nickname"` // eQSL: QTH nickname (when the account has several)
|
||||
ForceStationCallsign string `json:"force_station_callsign"` // QRZ + LoTW: override STATION_CALLSIGN
|
||||
TQSLPath string `json:"tqsl_path"` // LoTW: path to tqsl.exe
|
||||
StationLocation string `json:"station_location"` // LoTW: TQSL Station Location name
|
||||
KeyPassword string `json:"key_password"` // LoTW: certificate private-key password (optional)
|
||||
UploadFlags []string `json:"upload_flags"` // LoTW: set of lotw_sent values that mean "ready to upload" — any of "N"/"R"
|
||||
WriteLog bool `json:"write_log"` // LoTW: pass -t to write a TQSL diagnostic log
|
||||
AutoUpload bool `json:"auto_upload"`
|
||||
UploadMode UploadMode `json:"upload_mode"`
|
||||
APIKey string `json:"api_key"`
|
||||
URL string `json:"url"` // Cloudlog/Wavelog: base URL of the user's own instance
|
||||
StationID string `json:"station_id"` // Cloudlog/Wavelog: station profile (location) id
|
||||
Email string `json:"email"` // Club Log account email
|
||||
Username string `json:"username"` // LoTW website login (for confirmation download)
|
||||
Password string `json:"password"` // Club Log account / LoTW website password
|
||||
Callsign string `json:"callsign"` // Club Log / HRDLog logbook (owner) callsign
|
||||
Code string `json:"code"` // HRDLog: account upload code
|
||||
QTHNickname string `json:"qth_nickname"` // eQSL: QTH nickname (when the account has several)
|
||||
ForceStationCallsign string `json:"force_station_callsign"` // QRZ + LoTW: override STATION_CALLSIGN
|
||||
TQSLPath string `json:"tqsl_path"` // LoTW: path to tqsl.exe
|
||||
StationLocation string `json:"station_location"` // LoTW: TQSL Station Location name
|
||||
KeyPassword string `json:"key_password"` // LoTW: certificate private-key password (optional)
|
||||
UploadFlags []string `json:"upload_flags"` // LoTW: set of lotw_sent values that mean "ready to upload" — any of "N"/"R"
|
||||
WriteLog bool `json:"write_log"` // LoTW: pass -t to write a TQSL diagnostic log
|
||||
AutoUpload bool `json:"auto_upload"`
|
||||
// OnAir: HRDLog only — publish the live frequency, mode and rig on the site.
|
||||
OnAir bool `json:"on_air"`
|
||||
UploadMode UploadMode `json:"upload_mode"`
|
||||
}
|
||||
|
||||
// normalised returns the config with whitespace trimmed and a valid upload
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
@@ -143,3 +144,59 @@ func TestHRDLog(ctx context.Context, client *http.Client, cfg ServiceConfig) (st
|
||||
}
|
||||
return fmt.Sprintf("Credentials accepted — %s", callsign), nil
|
||||
}
|
||||
|
||||
// hrdlogOnAirURL is HRDLog's live-status endpoint — what puts "F4BPO is on air
|
||||
// 14,074,000 FM IC-7300" on the site's front page.
|
||||
//
|
||||
// Endpoint and field names taken from HRDLog's own library (github.com/iw1qlh/
|
||||
// HRDLOG-net-library, HrdProtocol.SendOnAirAsync), not from guesswork: it posts
|
||||
// Frequency in Hz, Mode, Radio, Callsign, Code and App.
|
||||
//
|
||||
// HTTPS where that library uses plain HTTP. The upload code is a credential and
|
||||
// has no business crossing the network in clear; the sibling NewEntry endpoint
|
||||
// on the same host already serves TLS.
|
||||
const hrdlogOnAirURL = "https://robot.hrdlog.net/OnAir.aspx"
|
||||
|
||||
// SendHRDLogOnAir publishes the current frequency, mode and rig.
|
||||
//
|
||||
// Deliberately fire-and-forget in spirit: it is a status broadcast, so a
|
||||
// failure is logged and never surfaced as an error the operator must clear —
|
||||
// but the message is returned so the caller can log WHAT the site said rather
|
||||
// than only that something went wrong.
|
||||
func SendHRDLogOnAir(ctx context.Context, client *http.Client, callsign, code string, freqHz int64, mode, radio string) (string, error) {
|
||||
callsign = strings.ToUpper(strings.TrimSpace(callsign))
|
||||
code = strings.TrimSpace(code)
|
||||
if callsign == "" || code == "" {
|
||||
return "", fmt.Errorf("hrdlog: callsign and upload code required")
|
||||
}
|
||||
if freqHz <= 0 {
|
||||
return "", fmt.Errorf("hrdlog: no frequency to announce")
|
||||
}
|
||||
form := url.Values{}
|
||||
form.Set("Callsign", callsign)
|
||||
form.Set("Code", code)
|
||||
form.Set("App", hrdlogApp)
|
||||
form.Set("Frequency", strconv.FormatInt(freqHz, 10))
|
||||
form.Set("Mode", strings.TrimSpace(mode))
|
||||
form.Set("Radio", strings.TrimSpace(radio))
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, hrdlogOnAirURL, strings.NewReader(form.Encode()))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("hrdlog on-air: build request: %w", err)
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
if client == nil {
|
||||
client = &http.Client{Timeout: 15 * time.Second}
|
||||
}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("hrdlog on-air: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, _ := io.ReadAll(io.LimitReader(resp.Body, 32*1024))
|
||||
msg := strings.TrimSpace(string(body))
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return msg, fmt.Errorf("hrdlog on-air: http %d", resp.StatusCode)
|
||||
}
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user