diff --git a/cmd/server/observer_mail.go b/cmd/server/observer_mail.go index baef4715..c51cf33f 100644 --- a/cmd/server/observer_mail.go +++ b/cmd/server/observer_mail.go @@ -75,8 +75,9 @@ func (a *authService) observerCredentialsMail(u *users.User, username, password // firmwareServer is the mqtt1.server value for the Dutch-MeshCore firmware. // For a bare host the firmware picks the scheme from the port alone (8883 -// mqtts, 443 wss, anything else mqtt), so the scheme is always given. The -// firmware then appends mqtt1.port itself. +// mqtts, 443 wss, anything else mqtt) and appends mqtt1.port itself. Firmware +// before the merge 32dd8ad (2026-10-19) does not accept a scheme in the +// server, so the host stays bare unless the port would pick the wrong scheme. func firmwareServer(o observerLoginSettings) string { scheme := "mqtt" if o.transport == "websockets" { @@ -85,5 +86,15 @@ func firmwareServer(o observerLoginSettings) string { if o.tls { scheme += "s" } + inferred := "mqtt" + switch o.port { + case 8883: + inferred = "mqtts" + case 443: + inferred = "wss" + } + if scheme == inferred { + return o.host + } return scheme + "://" + o.host } diff --git a/cmd/server/observer_mail_test.go b/cmd/server/observer_mail_test.go index 72a9c280..44efd751 100644 --- a/cmd/server/observer_mail_test.go +++ b/cmd/server/observer_mail_test.go @@ -59,20 +59,29 @@ password = "p"` // The firmware infers the scheme of a bare host from the port alone (8883 // mqtts, 443 wss, else mqtt: MQTTBridge.cpp setupSlot), so the mail always // names the scheme the configured transport and TLS need. +// Firmware before the Dutch-MeshCore merge 32dd8ad (2026-10-19) does not parse a +// scheme in mqtt1.server and builds "://:" with proto taken +// from the port alone (8883 mqtts, 443 wss, else mqtt). A bare host works on +// both; the scheme is only written when the port would infer the wrong one. func TestFirmwareServerScheme(t *testing.T) { for _, c := range []struct { + port int transport string tls bool want string }{ - {"tcp", false, "mqtt://mqtt.example.org"}, - {"tcp", true, "mqtts://mqtt.example.org"}, - {"websockets", false, "ws://mqtt.example.org"}, - {"websockets", true, "wss://mqtt.example.org"}, + {1883, "tcp", false, "mqtt.example.org"}, + {8883, "tcp", true, "mqtt.example.org"}, + {443, "websockets", true, "mqtt.example.org"}, + {8884, "tcp", false, "mqtt.example.org"}, + {8884, "tcp", true, "mqtts://mqtt.example.org"}, + {8884, "websockets", false, "ws://mqtt.example.org"}, + {8884, "websockets", true, "wss://mqtt.example.org"}, + {8883, "tcp", false, "mqtt://mqtt.example.org"}, } { - o := observerLoginSettings{host: "mqtt.example.org", port: 8884, transport: c.transport, tls: c.tls} + o := observerLoginSettings{host: "mqtt.example.org", port: c.port, transport: c.transport, tls: c.tls} if got := firmwareServer(o); got != c.want { - t.Errorf("%s tls=%v: got %q, want %q", c.transport, c.tls, got, c.want) + t.Errorf("port %d %s tls=%v: got %q, want %q", c.port, c.transport, c.tls, got, c.want) } } } diff --git a/docs/observer-mqtt-logins.md b/docs/observer-mqtt-logins.md index 594ccd59..4cb88c2c 100644 --- a/docs/observer-mqtt-logins.md +++ b/docs/observer-mqtt-logins.md @@ -68,9 +68,11 @@ reverse proxy for everything except the broker. The credentials mail holds the login in four forms: a meshcoretomqtt `[[broker]]` block, the Dutch-MeshCore observer firmware commands, a Home Assistant meshcore-ha block, and the plain values. For the firmware the server -line always carries a scheme (`set mqtt1.server mqtts://mqtt.example.org`), because a bare host -makes the firmware choose the scheme from the port alone (8883 TLS, 443 secure websockets, -anything else plain MQTT). +line is the bare host (`set mqtt1.server mqtt.example.org`): the firmware chooses the scheme +from the port alone (8883 TLS, 443 secure websockets, anything else plain MQTT), and firmware +before 2026-10-19 does not accept a scheme in the server. Only when the port would pick the +wrong scheme (for example TLS on 8884) does the mail write one (`mqtts://mqtt.example.org`), +which needs firmware from 2026-10-19 or later. Websockets: meshcoretomqtt connects with websocket path `/`, EMQX listens on `/mqtt` by default. Match the listener path to your uploaders, or use `tcp`.