Resolve the PoE standard to a short code (af/at/bt) and a long label. 802.3bt (Type 3/4) introduced classes 5-8, so any class >=5 is bt. Otherwise the dot3 'power-type' field distinguishes Type 2 (802.3at) from Type 1 (802.3af); when it's absent we fall back to the class (class 4 requir
(power_type, class_num)
| 308 | |
| 309 | |
| 310 | def _speedtest_error(res, meta): |
| 311 | """Turn a speedtest client failure into something actionable. 'Cannot |
| 312 | retrieve speedtest configuration / urlopen error timed out' means it could |
| 313 | not reach speedtest.net at all — when we bound the socket to an interface |
| 314 | that is the prime suspect, otherwise it is plain no-internet/blocked.""" |
| 315 | raw = (res['err'] or res['out'] or 'speedtest failed').strip() |
| 316 | low = raw.lower() |
| 317 | if 'retrieve speedtest configuration' in low or 'urlopen error' in low: |
| 318 | if meta.get('bound'): |
| 319 | return (f"Could not reach speedtest.net with the test pinned to " |
| 320 | f"{meta.get('interface')}, even though that interface can reach the " |
| 321 | f"internet. speedtest.net may be blocked on that path, or the link " |
| 322 | f"dropped mid-test — try Auto to compare. [{raw}]") |
| 323 | return (f"Could not reach speedtest.net — no internet on this host, or " |
| 324 | f"speedtest.net is blocked/unreachable from here. [{raw}]") |
| 325 | return raw |
| 326 | |
| 327 | |
| 328 | def _iface_has_default_route(iface): |