feat: HAMLOG.online upload and confirmations, Yaesu antenna, a named port holder
HAMLOG.online is a seventh external service: one API key, one ADIF record per QSO, immediate / delayed / on-close like the rest. They publish no API documentation, so the protocol is read from THEIR OWN client — the HAMLOG Agent (github.com/hamlogonline/Agent), which is the authoritative source short of asking them: POST https://hamlog.online/api/agent/ {"ADIFADD": {"APIKEY": k, "ADIFDATA": record}} → {"STATUS":"OK"} {"KEYSTATUS": {"APIKEY": k}} → {"STATUS":"OK","CALLSIGN":…} Success is STATUS == OK, not "no ERROR field": their failure carries ERROR and no STATUS, and reading an unknown reply — a proxy page, a maintenance notice — as an acceptance is how a contact goes missing without anyone noticing. KEYSTATUS buys something no other service here offers: the key can be checked BEFORE the first QSO, and the answer names the account. A key pasted from another callsign is caught in the settings panel rather than through a week of silent refusals. Their confirmations are also an award source now, ticked like LoTW rather than expressed through "custom". It reads the ADIF extras, not a column: the standard names a field for hamlog.EU and none for hamlog.ONLINE, and borrowing the other site's field would write a falsehood into every exported log. Three plausible key names from their own export are accepted too, so nobody has to rename a column by hand after an export. Yaesu gains antenna selection (AN), remembered per band — the antenna picked on a band comes back with it, with no table to fill in anywhere. Rigs with one socket never answer AN and never show the row; the log says which case it is. And a serial port that is refused now names its likely holder. OmniRig stays resident once activated and keeps the port of the rig configured in it, so a native backend never gets it — "Serial port busy" alone accused nobody, and an FTDX10 spent a morning being blamed for it.
This commit is contained in:
+48
-1
@@ -109,7 +109,7 @@ type Def struct {
|
||||
Emission []string `json:"emission,omitempty"` // CW | DIGITAL | PHONE (empty = all)
|
||||
|
||||
// --- Confirmation ---
|
||||
Confirm []string `json:"confirm"` // worked-confirmed: lotw|qsl|eqsl|qrzcom|custom
|
||||
Confirm []string `json:"confirm"` // worked-confirmed: lotw|qsl|eqsl|qrzcom|hamlog|custom
|
||||
Validate []string `json:"validate,omitempty"` // validated/granted sources
|
||||
// The "custom" source, for confirmations OpsLog has no dedicated column for:
|
||||
// ConfirmField names a QSO field or an ADIF extras key, ConfirmValue the
|
||||
@@ -1481,6 +1481,18 @@ func confirmed(q *qso.QSO, sources []string, d *Def) bool {
|
||||
if isYes(q.QRZComDownloadStatus) {
|
||||
return true
|
||||
}
|
||||
case "hamlog":
|
||||
// HAMLOG.online, a first-class source rather than something to express
|
||||
// through "custom" — its confirmations feed its own award programme
|
||||
// and operators reach for it the same way they reach for LoTW.
|
||||
//
|
||||
// Read from the ADIF EXTRAS, not a column: the ADIF standard names a
|
||||
// field for hamlog.EU (HAMLOGEU_QSO_UPLOAD_STATUS) and none for
|
||||
// hamlog.ONLINE, and borrowing the other site's field would write a
|
||||
// falsehood into every exported log.
|
||||
if hamlogConfirmed(q) {
|
||||
return true
|
||||
}
|
||||
case "custom":
|
||||
if customConfirmed(q, d) {
|
||||
return true
|
||||
@@ -1490,6 +1502,41 @@ func confirmed(q *qso.QSO, sources []string, d *Def) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// HamlogQSLKey is where a HAMLOG.online confirmation is recorded, as an ADIF
|
||||
// extras key. Exported and re-imported like any other extra, so the state
|
||||
// survives a move to another logger and back.
|
||||
const HamlogQSLKey = "APP_OPSLOG_HAMLOG_QSL"
|
||||
|
||||
// hamlogAltKeys are the shapes an ADIF exported BY hamlog.online might use.
|
||||
//
|
||||
// Their site publishes no field name, so rather than demand that an operator
|
||||
// rename a column by hand after every export, the ones an export could
|
||||
// plausibly carry are accepted too. Costs three map lookups; saves a support
|
||||
// thread that would end in "edit your ADIF".
|
||||
var hamlogAltKeys = []string{"APP_HAMLOG_QSL", "APP_HAMLOGONLINE_QSL", "HAMLOG_QSL_RCVD"}
|
||||
|
||||
// hamlogConfirmed reports whether a QSO carries a HAMLOG.online confirmation.
|
||||
//
|
||||
// Any non-empty value counts, except an explicit "N": their export could carry
|
||||
// a date, a Y, or a match id, and demanding one of them would silently confirm
|
||||
// nothing on the two shapes we guessed wrong.
|
||||
func hamlogConfirmed(q *qso.QSO) bool {
|
||||
if q == nil || q.Extras == nil {
|
||||
return false
|
||||
}
|
||||
for _, k := range append([]string{HamlogQSLKey}, hamlogAltKeys...) {
|
||||
v := strings.TrimSpace(q.Extras[k])
|
||||
if v == "" {
|
||||
continue
|
||||
}
|
||||
if strings.EqualFold(v, "N") || strings.EqualFold(v, "NO") {
|
||||
continue
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// customConfirmed answers the operator-defined confirmation source: the field
|
||||
// named by ConfirmField, optionally required to hold one of ConfirmValue's
|
||||
// comma-separated values.
|
||||
|
||||
Reference in New Issue
Block a user