fix(relays): the generic HTTP board never sent its URLs; cluster filters start off

buildDeviceDriver had no case for "httpgen", so the generic board fell through
to the WebSwitch driver: it polled an address it had never been given, reported
itself offline, greyed out every relay button, and sent none of the configured
URLs. Nothing in the interface said so — the board was configured, saved and
listed, and simply did nothing. deviceKey did not cover the URLs either, so once
that is fixed, correcting a typo in one would still have handed back the cached
driver holding the old address until a restart.

Two shapes of home-made switch could not be described at all:

  - a bit-mask board whose four URLs differ by one character
    (/Set0/1, /Set0/2, /Set0/4, /Set0/8) — {value} in the pattern now takes the
    number from the per-relay box, keeping the address in one place;
  - a board numbering its channels from zero — {relay-1}, since giving up the
    pattern for eight hand-typed URLs was the only alternative.

The pattern decides what the per-relay boxes hold, and the grid says which as
soon as {value} is typed: guessing per box ("does this look like a URL?") would
change meaning on a typo, which is not a thing to do to something wired to an
antenna. A URL typed without a scheme gets http:// like the named boards get
from relayBase; https:// is passed through untouched.

Host and the connection test are gone for this type. It has no address of its
own — its relays may each live on a different box — and no status to read, so a
test could only ever answer "OK, 4 relays". Save was greyed out without a host,
which made a complete configuration of four full URLs impossible to store.

Cluster filters no longer persist across launches. A band lock set weeks earlier
is invisible to whoever set it: the counter reads 76 spots live, the grid is
empty, and the search goes to the cluster instead. Nobody loses work by
re-ticking a chip. Grouping and the panel state still persist — they change how
spots look, never whether they appear.
This commit is contained in:
2026-08-15 23:53:32 +02:00
parent be0326c862
commit fe2affc72f
9 changed files with 346 additions and 73 deletions
+18 -2
View File
@@ -57,9 +57,9 @@ import (
"hamlog/internal/relaydev"
"hamlog/internal/rigctld"
"hamlog/internal/rotator/dcu1"
"hamlog/internal/rotator/spid"
"hamlog/internal/rotator/gs232"
"hamlog/internal/rotator/pst"
"hamlog/internal/rotator/spid"
"hamlog/internal/rotgenius"
"hamlog/internal/scp"
"hamlog/internal/settings"
@@ -14757,6 +14757,13 @@ func buildDeviceDriver(d StationDevice) relaydev.Device {
case "usbrelay":
// Host carries the COM port (e.g. "COM5"); CH340/LCUS "A0" serial protocol.
return relaydev.NewSerialRelay(d.Host, deviceRelayCount(d))
case "httpgen":
// The whole board lives in its URLs — Host is not used at all, which is
// why it may be left empty. Leaving this case out is what made the
// generic board fall through to the WebSwitch driver below: it answered
// the WebSwitch's own address, never sent one configured URL, and
// reported itself offline so every relay button stayed greyed out.
return relaydev.NewHTTPGeneric(d.OnURLs, d.OffURLs, d.OnPat, d.OffPat, d.User, d.Pass, deviceRelayCount(d))
default:
return relaydev.NewWebswitch(d.Host)
}
@@ -14765,7 +14772,16 @@ func buildDeviceDriver(d StationDevice) relaydev.Device {
// deviceKey is the config signature that, when unchanged, lets us reuse a device's
// open driver (and its OS handle) instead of rebuilding it every poll.
func deviceKey(d StationDevice) string {
return fmt.Sprintf("%s|%s|%s|%s|%d", d.Type, d.Host, d.User, d.Pass, deviceRelayCount(d))
k := fmt.Sprintf("%s|%s|%s|%s|%d", d.Type, d.Host, d.User, d.Pass, deviceRelayCount(d))
if d.Type == "httpgen" {
// The generic board's entire configuration is its URLs, and none of it is
// in the signature above. Correcting a typo in one of them would have
// handed back the cached driver still holding the wrong address, so the
// fix appeared to do nothing until OpsLog was restarted.
k += "|" + d.OnPat + "|" + d.OffPat +
"|" + strings.Join(d.OnURLs, "\x1f") + "|" + strings.Join(d.OffURLs, "\x1f")
}
return k
}
// driverFor returns the cached, still-open driver for a device, building it once