mDNS (multicast DNS / DNS-SD) advertises services on the local network under *.local. names.
NetNeighbor uses zeroconf browsing callbacks; it does not perform an active LAN scan.
Typical service types discovered:
| Type | Meaning |
|---|---|
_http._tcp |
Web UI |
_smb._tcp, _microsoft-ds._tcp |
File sharing |
_ssh._tcp |
SSH |
_ftp._tcp |
FTP |
_telnet._tcp |
Telnet |
_esp3d._tcp |
ESP3D firmware |
| Area | File / symbol | Role |
|---|---|---|
| Provider | discovery/mdns.py |
MDNSDiscovery — zeroconf browser/listener, TXT decode, host aggregation |
| Contract | discovery/base.py |
BaseDiscovery._emit("device", payload) → normalized dict to manager |
| Orchestration | discovery/manager.py |
Receives mdns payloads, applies overrides, stores and notifies |
| Mapping hints | data/device_types.json |
Per-service defaults (type, icon, default_port) |
| UI payload | utils/details_payload.py |
build_mdns_payload — per-service sections for the Services tab |
| Rules | config/mdns_rules.json |
TXT → summary line mappings and optional type_rules |
- Service types from
data/device_types.json(mdnssection) are browsed immediately. - DNS-SD enumeration (
_services._dns-sd._udp) runs in background to catch unlisted types. - Enumeration repeats on a timer and on
refresh()— no types need to be listed statically.
mDNS announces per-service. NetNeighbor aggregates services to one logical host entry:
- Track per-service payloads
(service_type, instance_name) - Map each service to a host key (prefer IP, fallback hostname)
- Emit an aggregated payload with all services under
metadata["services"]
A device like ESP3D exposing both _esp3d._tcp and _telnet._tcp appears as one entry
with both services visible in the Details dialog.
A presentation URL is built only if _http._tcp is actually present. Port numbers alone do not imply HTTP — this avoids wrong browser links for non-HTTP services on common ports.
- Raw
ServiceInfo.textis decoded preserving duplicate keys and ordering →metadata["services"][].txt_records - A flat
metadata["txt"](last-key-wins) is kept for type heuristics - Details dialog shows one expandable row per service with TXT pairs nested under it
Type starts from device_types.json, refined by heuristics (fluidnc→cnc, synology/qnap→nas, etc.), then type_rules in mdns_rules.json.
A host stays online while at least one tracked service remains. Removing one service updates the aggregated payload; offline is emitted only when all services are gone — avoids flapping for multi-service hosts.
Lets you map TXT keys onto summary lines and extend type classification without Python changes.
User overlay: ~/.config/netneighbor/mdns_rules.json — merged with bundled defaults.
See COMMUNITY_OVERRIDES.md.
Ordered list; each entry emits at most one first-tab detail row.
| Field | Type | Meaning |
|---|---|---|
label |
string | Detail column heading (match SSDP wording to enable cross-protocol merge) |
keys |
list | TXT key aliases, priority order, case-insensitive |
Evaluated after fixed heuristics. First match wins.
| Field | Type | Meaning |
|---|---|---|
contains_any |
list | Lowercase substrings searched in service key, name, and TXT pairs |
type |
string | Internal type id (e.g. nas, router) |
- Add
summary_from_txtentries matching your devices' actual TXT keys (check Services tab in Details). - Use the same
labelas SSDP counterparts so SSDP+mDNS detail rows merge correctly. - Add
type_ruleswith specificcontains_anybefore generic ones. - Validate:
python -m json.tool config/mdns_rules.json - Restart the app (rules are cached at startup).
- Enable
mdnsin~/.config/netneighbor/logging.json - Details dialog → Services tab: verify TXT records, services list, URL present only when
_http._tcpexists
SSDP.md— parallel SSDP pipelineCOMMUNITY_OVERRIDES.md— user overlay rulesBACKEND_ARCHITECTURE.md— discovery manager overview