IPv6 Multicast on Thread
About
This page explains how to join and leave IPv6 multicast groups on the Thread interface with the OpenThread Arduino library: stack-level APIs, UDP and CoAP wrappers, timing, shutdown, and which shipped examples use each pattern.
Multicast lets one sender reach many receivers on the mesh without listing each
node’s unicast address. Application demos in this tree often use realm-local
groups (ff03::/16) so every node in the partition can participate.
Send vs receive
Role |
Subscribe? |
Typical API |
|---|---|---|
Receiver — must accept packets to a group address |
Yes |
|
Sender — only transmits to a group address |
No |
UDP |
Sending to ff03::abcd does not require joining that group. Only nodes that
listen for group traffic must subscribe.
Stack-level API (OThread)
These methods call OpenThread otIp6SubscribeMulticastAddress() /
otIp6UnsubscribeMulticastAddress():
bool subscribeMulticast(const IPAddress &group);
bool unsubscribeMulticast(const IPAddress &group);
groupmust be an IPv6 multicast address (first byte0xFF).Call on the global
OThreadsingleton afterOThread.begin().Best practice: subscribe after attach (role Child, Router, or Leader).
Pair every subscribe with unsubscribe before shutdown, or use a wrapper that unsubscribes in
stop().
See also OpenThread Class (subscribeMulticast / unsubscribeMulticast).
Reference counting
Membership is reference-counted:
First |
OpenThread joins |
Another subscribe to the same |
Refcount only |
|
Refcount only |
Last unsubscribe for |
OpenThread leaves |
OThreadUDP.beginMulticast() and OThreadCoAPServer.joinMulticastGroup()
can share the same group. The refcount table is mutex-protected.
Query membership with getMulticastAddressCount(), getMulticastAddress(),
getAllMulticastAddresses(), and clearMulticastAddressCache() when the role
or membership changes.
UDP: OThreadUDP
beginMulticast(group, port) (UDP receivers)
OThreadUDP Udp;
const uint8_t groupBytes[16] = {0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xab, 0xcd};
IPAddress group(IPv6, groupBytes); // ff03::abcd
Udp.beginMulticast(group, 5051);
// parsePacket() / read() in loop()
Udp.stop(); // unsubscribes and closes the socket
Internally: begin(port) then OThread.subscribeMulticast(group).
stop() calls unsubscribeMulticast() for that group. The socket also
receives unicast on the same port (for example ACK replies).
See OThreadUDP Class.
begin(port) only (senders and unicast receivers)
Udp.begin(5051);
Udp.beginPacket(multicastGroup, 5051);
Udp.write(...);
Udp.endPacket();
Use on clients that send to a multicast group but do not receive group traffic. Bind a local port when expecting unicast replies.
Manual subscribe + bind
Udp.begin(5050);
OThread.subscribeMulticast(group);
// ...
OThread.unsubscribeMulticast(group);
Udp.stop();
Prefer beginMulticast() unless sharing one subscription across several
sockets or toggling membership without closing the socket.
CoAP: OThreadCoAPServer
Servers that receive multicast CoAP requests must join the group after
begin():
OThreadCoAPServer.on("Lamp", OT_COAP_METHOD_GET | OT_COAP_METHOD_PUT, onLamp);
OThreadCoAPServer.begin();
OThreadCoAPServer.joinMulticastGroup(LAMP_GROUP); // e.g. ff03::abcd
joinMulticastGroup()→OThread.subscribeMulticast().leaveMulticastGroup(group)drops one reference at runtime.stop()leaves all groups recorded by the server.
CoAP multicast behavior (RFC 7252)
Clients: use non-confirmable (NON) multicast requests (§8.1);
sendNonBlocking()for fire-and-forget.Servers: do not reply to multicast (§8.2); check
req.isMulticast()beforeresp.send().Unicast to one server: use blocking
client.PUT(...)/GET(...).
Multicast and CON
CON and multicast cannot be combined. For destinations 0xFF…, the client
always sends NON, even if setConfirmable(true) (RFC 7252 §8.1). CON
retransmission and setTimeout() tuning do not apply to multicast sends.
Client call |
Multicast behavior |
|---|---|
Blocking method + |
Forced NON; may block for first reply only |
|
NON, no wait ( |
Confirmed command to one device |
Unicast CON to that node’s address |
Servers need joinMulticastGroup() to receive group CoAP; group requests are
NON — skip resp.send() when req.isMulticast(). See Confirmable vs non-confirmable (CON / NON)
in OThreadCoAP APIs for the full CON/NON guide.
OThreadCoAPSecureServer has no joinMulticastGroup(). Use plain
OThreadCoAPServer on port 5683 for multicast, secure server on 5684
for commands, or OThread.subscribeMulticast() at the stack level.
See OThreadCoAP APIs.
CLI equivalent
CLI sketches join groups with:
ipmaddr add ff03::abcd
Equivalent to subscribeMulticast() for application traffic. Pair with
udp bind in UDP examples.
Multicast scopes
Prefix |
Scope |
Examples in this library |
|---|---|---|
|
Link-local (one hop) |
Rare in demos |
|
Realm-local (whole partition) |
Native UDP/CoAP light switch ( |
|
Site-local |
CLI CoAP lamp/switch ( |
Align network key, channel, group address, and scope when mixing CLI and
Native boards. Built-in groups such as ff03::1 appear in address listings;
application demos often use a custom suffix (for example ff03::abcd).
Shutdown order
Before OThread.end():
OThreadCoAPServer.stop()/ destroy CoAP clientsOThreadUDP.stop()(unsubscribes afterbeginMulticast())Direct
unsubscribeMulticast()for any remaining groupsOThread.end()
See OpenThread (Shutdown Order) and the Native StackShutdown example.
Examples that use multicast
Native API
Example |
Sketch |
Role |
Mechanism |
|---|---|---|---|
|
Receiver |
|
|
|
Sender |
|
|
|
Receiver |
|
|
|
Sender |
NON multicast |
Native UDP_SensorNetwork uses unicast to the Leader RLOC, not application
multicast.
CLI API
Example |
Sketch |
Role |
Mechanism |
|---|---|---|---|
collector |
Receiver |
|
|
sensor |
Sender |
|
|
lamp |
Receiver |
CLI multicast |
|
switch |
Sender |
CON CoAP PUT to |
Documentation sample
OThreadUDP Class includes a minimal receiver with beginMulticast(ff03::1, 7).
Quick reference
Receiver (UDP) → Udp.beginMulticast(group, port)
Receiver (CoAP) → CoAPServer.joinMulticastGroup(g)
Sender → beginPacket(group, port) — no subscribe
Stack / advanced → OThread.subscribeMulticast(g)
Runtime leave → leaveMulticastGroup(g) or unsubscribeMulticast(g)
Teardown → Udp.stop() / CoAPServer.stop()
See also
Multicasting.md — Markdown copy in the library tree.
OpenThread Class —
subscribeMulticast/unsubscribeMulticastAPI.OThreadUDP Class —
OThreadUDPincludingbeginMulticast.OThreadCoAP APIs — CoAP multicast and RFC notes.
OpenThread — overview and shutdown order.