MatterEx.MDNS (matter_ex v0.3.0)

Copy Markdown View Source

mDNS responder GenServer for DNS-SD service discovery.

Opens a multicast UDP socket on port 5353 (configurable), joins the mDNS multicast group (224.0.0.251), and responds to DNS queries for registered services. Sends gratuitous announcements when services are added or removed.

Includes Matter-specific helpers for building commissioning discovery service configurations.

Example

{:ok, mdns} = MatterEx.MDNS.start_link(
  hostname: "matter_ex-device",
  addresses: [{192, 168, 1, 100}]
)

# Advertise a Matter commissioning service
service = MatterEx.MDNS.commissioning_service(
  port: 5540,
  discriminator: 3840,
  vendor_id: 0xFFF1,
  product_id: 0x8001,
  device_name: "Test Light"
)

MatterEx.MDNS.advertise(mdns, service)

Summary

Functions

Register a service for advertisement. Sends a gratuitous announcement.

Returns a specification to start this module under a supervisor.

Build service configuration for Matter commissioning discovery.

Compute the Matter compressed fabric identifier.

Build service configuration for Matter operational discovery.

Get the port the mDNS responder is listening on.

Start the mDNS responder.

Update TXT records for an existing service.

Remove a service by instance name. Sends goodbye announcement (TTL=0).

Functions

advertise(server, opts)

@spec advertise(
  GenServer.server(),
  keyword()
) :: :ok

Register a service for advertisement. Sends a gratuitous announcement.

Options:

  • :service — service type (e.g. "_matterc._udp.local")
  • :instance — instance name (e.g. "MATTER-0F00")
  • :port — service port (e.g. 5540)
  • :txt — TXT record entries (e.g. ["D=3840", "CM=1"])
  • :subtypes — subtype service names for additional PTR records (optional)

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

commissioning_service(opts)

@spec commissioning_service(keyword()) :: keyword()

Build service configuration for Matter commissioning discovery.

Returns keyword list suitable for advertise/2.

Options:

  • :port — UDP port the Matter node listens on (required)
  • :discriminator — 12-bit commissioning discriminator (required)
  • :vendor_id — 16-bit vendor ID (required)
  • :product_id — 16-bit product ID (required)
  • :device_name — human-readable device name (optional)
  • :device_type — device type ID (optional)
  • :commissioning_mode — 1 (basic) or 2 (enhanced), default 1

compressed_fabric_id(root_public_key, fabric_id)

@spec compressed_fabric_id(binary(), non_neg_integer()) :: binary()

Compute the Matter compressed fabric identifier.

Uses HKDF-SHA256 with the 64-byte x||y coordinates of the root public key (stripping the 0x04 SEC1 uncompressed prefix) as IKM, the fabric ID (big-endian 64-bit) as salt, and "CompressedFabric" as info. Returns 8 bytes.

operational_service(opts)

@spec operational_service(keyword()) :: keyword()

Build service configuration for Matter operational discovery.

After commissioning, the device advertises on _matter._tcp.local with a compressed fabric ID + node ID instance name. chip-tool uses this to find the device for CASE session establishment.

Options:

  • :port — UDP port the Matter node listens on (required)
  • :compressed_fabric_id — 8-byte compressed fabric identifier (required)
  • :node_id — operational node ID (required)

port(server)

@spec port(GenServer.server()) :: non_neg_integer()

Get the port the mDNS responder is listening on.

start_link(opts \\ [])

@spec start_link(keyword()) :: GenServer.on_start()

Start the mDNS responder.

Options:

  • :hostname — local hostname without .local suffix (default: auto-generated)
  • :port — mDNS port (default: 5353, use 0 for OS-assigned in tests)
  • :addresses — list of IP tuples to advertise (default: auto-detect)
  • :interface — optional interface name to auto-detect and advertise from, e.g. "wlan0"
  • :name — GenServer name

update_txt(server, instance, txt_entries)

@spec update_txt(GenServer.server(), String.t(), [String.t()]) :: :ok

Update TXT records for an existing service.

withdraw(server, instance)

@spec withdraw(GenServer.server(), String.t()) :: :ok

Remove a service by instance name. Sends goodbye announcement (TTL=0).