Skip to content

UDP Discovery ​

Periodically broadcast a "hello" datagram to a multicast group and listen for the same from peers. Deploy to two or more boards on the same WiFi network and watch them find each other. Uses the wifi, udp, and sys APIs.

Hardware ​

  • Two or more ESP32 boards with WiFi (one is enough to see the announcer logs, but you need at least two for actual discovery)
  • USB cables
  • A WiFi network. Both boards must join the same SSID.

Setup ​

Set your WiFi credentials as environment variables:

sh
pnpm mikro env set WIFI_SSID YourNetworkName --no-secret
pnpm mikro env set WIFI_PASSPHRASE
sh
npx mikro env set WIFI_SSID YourNetworkName --no-secret
npx mikro env set WIFI_PASSPHRASE
sh
yarn mikro env set WIFI_SSID YourNetworkName --no-secret
yarn mikro env set WIFI_PASSPHRASE
sh
bunx mikro env set WIFI_SSID YourNetworkName --no-secret
bunx mikro env set WIFI_PASSPHRASE

Code ​

ts
import {
env
} from 'mikro/env'
import {
sleep
} from 'mikro/sleep'
import {
deviceId
} from 'mikro/sys'
import {
bind
} from 'mikro/udp'
import {
wifi
} from 'mikro/wifi'
const
GROUP
= '224.0.0.251'
const
PORT
= 7654
const
ANNOUNCE_MS
= 2000
const
ssid
=
env
.
require
('WIFI_SSID')
const
passphrase
=
env
.
require
('WIFI_PASSPHRASE')
const
connected
= await
wifi
.
connect
({
ssid
,
passphrase
})
if (
connected
.
ok
) {
const
bound
= await
bind
({
port
:
PORT
,
family
: 'ipv4'})
if (
bound
.
ok
) {
const
sock
=
bound
.
value
const
joined
=
sock
.
joinMulticastGroup
({
address
:
GROUP
})
if (
joined
.
ok
) {
sock
.
onMessage
.
subscribe
(({
msg
,
from
}) => {
const
text
= new
TextDecoder
().
decode
(
msg
)
if (
text
===
deviceId
) return
console
.
log
('discovered %s at %s',
text
,
from
.
address
)
}) while (true) { await
sock
.
send
(
deviceId
, {
address
:
GROUP
,
port
:
PORT
,
family
: 'ipv4'})
await
sleep
(
ANNOUNCE_MS
)
} } } }

Walkthrough ​

  1. Multicast group. 224.0.0.251 is the mDNS group. Home routers reliably forward it because Bonjour, AirPlay, and Chromecast all depend on it; less common groups in 224.0.0.0/24 get silently dropped by some APs. The example uses port 7654 so it doesn't collide with system mDNS responders on 5353. Datagrams sent to the group are delivered to every host on the LAN that joined it, with no central server.

  2. Why join. joinMulticastGroup tells the kernel and switch fabric to deliver matching datagrams to this socket. Without it, the socket would only see unicast packets sent to its bound port. The group must be joined after the network interface is up, which is why it lives inside the wifi.connect ok-branch.

  3. Self-filter. Multicast loops back to the sender on the same host (and the same socket can join its own group), so onMessage will see the device's own announcements. Skip them by comparing against deviceId.

  4. Backpressure. Each socket has a bounded receive queue. A busy responder can override the default with bind({port, family, recvQueue: 32}). Drops are observable via socket.dropped.

  5. Reach. UDP multicast travels as far as the LAN allows: most home routers forward 224.0.0.0/4 within a single broadcast domain but not across VLANs or the public internet. For mesh-wide discovery, use Thread (IPv6 multicast routes across the mesh).

Run it ​

sh
pnpm install
pnpm mikro flash  # only needed once per board
pnpm mikro dev
sh
npm install
npx mikro flash  # only needed once per board
npx mikro dev
sh
yarn install
yarn mikro flash  # only needed once per board
yarn mikro dev
sh
bun install
bunx mikro flash  # only needed once per board
bunx mikro dev

Deploy to a second board and watch each console log the other's deviceId.

No second board? Run a Node peer ​

The example ships with scripts/peer.ts, a small Node program that joins the same multicast group, announces a name, and logs everything it hears. Requires Node 24+. Run it on a laptop attached to the same WiFi:

sh
pnpm run peer                # name defaults to laptop-<pid>
pnpm run peer -- --name desk # custom name
sh
npm run peer
npm run peer -- --name desk
sh
yarn run peer
yarn run peer --name desk
sh
bun run peer
bun run peer -- --name desk

The board will log discovered laptop-... at 192.168.x.y and the laptop will log the board's deviceId. Stop the peer with Ctrl-C.

View source on GitHub

Mikro.js is built with AI assistance, code and docs alike. Read the AI disclosure.