Build a ShellyDevice that addresses the device via an explicit
host[:port] string rather than info.ip. info still carries the
device identity (model, generation, mac, …); base_host is only used
to build the HTTP/RPC URLs, so it can carry a port that info.ip cannot.
Probe a device by host[:port] string, fetching /shelly and
classifying the outcome uniformly with every other transport path:
unreachable/non-success -> Network (or Auth for 401/403), a JSON body
that fails to decode -> Parse, and a JSON body that decodes but does
not describe a Shelly device -> Parse as well (reachable, answered,
just not a Shelly). A /shelly response that DOES describe a Shelly, on
a host that isn’t an IP address (hostname/mDNS) -> Unsupported: the
device is real, so this must not collapse into the “not a Shelly” case.
This is what lets a caller distinguish “nothing there” (Network/Err)
from “something else is there” (Parse/Err still, but a different
variant) from “a Shelly is there but this client can’t address it yet”
(Unsupported/Err) from “a Shelly is there” (Ok).