docs/en/openthread/Multicasting.rst
######################## IPv6 Multicast on Thread ########################
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.
.. list-table:: :header-rows: 1 :widths: 28 18 54
subscribeMulticast(), beginMulticast(), or joinMulticastGroup()beginPacket(group, port) / endPacket() or CoAP client sendSending to ff03::abcd does not require joining that group. Only nodes that
listen for group traffic must subscribe.
OThread)These methods call OpenThread otIp6SubscribeMulticastAddress() /
otIp6UnsubscribeMulticastAddress():
.. code-block:: arduino
bool subscribeMulticast(const IPAddress &group);
bool unsubscribeMulticast(const IPAddress &group);
group must be an IPv6 multicast address (first byte 0xFF).OThread singleton after OThread.begin().stop().See also :doc:openthread_core (subscribeMulticast / unsubscribeMulticast).
Reference counting
Membership is reference-counted:
.. list-table:: :widths: 45 55
subscribeMulticast(g)g; refcount = 1gunsubscribeMulticast(g) while refcount > 1ggOThreadUDP.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.
OThreadUDPbeginMulticast(group, port) (UDP receivers)
.. code-block:: arduino
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 :doc:openthread_udp.
begin(port) only (senders and unicast receivers)
.. code-block:: arduino
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
.. code-block:: arduino
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.
OThreadCoAPServerServers that receive multicast CoAP requests must join the group after
begin():
.. code-block:: arduino
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)
sendNonBlocking() for fire-and-forget.req.isMulticast()
before resp.send().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.
.. list-table:: :header-rows: 1 :widths: 34 66
setConfirmable(true)sendNonBlocking()CoAP_Light_Switch switch)Servers need joinMulticastGroup() to receive group CoAP; group requests are
NON — skip resp.send() when req.isMulticast(). See :ref:coap_con_non
in :doc:openthread_coap 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 :doc:openthread_coap.
CLI sketches join groups with:
.. code-block:: text
ipmaddr add ff03::abcd
Equivalent to subscribeMulticast() for application traffic. Pair with
udp bind in UDP examples.
.. list-table:: :header-rows: 1 :widths: 12 28 60
ff02::ff03::ff03::abcd)ff05::ff05::abcd)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).
Before OThread.end():
OThreadCoAPServer.stop() / destroy CoAP clientsOThreadUDP.stop() (unsubscribes after beginMulticast())unsubscribeMulticast() for any remaining groupsOThread.end()See :doc:openthread (Shutdown Order) and the Native
StackShutdown example <https://github.com/espressif/arduino-esp32/tree/master/libraries/OpenThread/examples/Native/StackShutdown>_.
Native API
.. list-table:: :header-rows: 1 :widths: 22 14 14 50
UDP Light Switch <https://github.com/espressif/arduino-esp32/tree/master/libraries/OpenThread/examples/Native/UDP/UDP_Light_Switch>_lightOThreadUDP.beginMulticast(ff03::abcd, 5051)UDP Light Switch <https://github.com/espressif/arduino-esp32/tree/master/libraries/OpenThread/examples/Native/UDP/UDP_Light_Switch>_switchUdp.begin(5051) + send to ff03::abcd (no subscribe)CoAP Light Switch <https://github.com/espressif/arduino-esp32/tree/master/libraries/OpenThread/examples/Native/CoAP/CoAP_Light_Switch>_lightOThreadCoAPServer.joinMulticastGroup(ff03::abcd)CoAP Light Switch <https://github.com/espressif/arduino-esp32/tree/master/libraries/OpenThread/examples/Native/CoAP/CoAP_Light_Switch>_switchPUT via sendNonBlocking()Native UDP_SensorNetwork uses unicast to the Leader RLOC, not application
multicast.
CLI API
.. list-table:: :header-rows: 1 :widths: 22 18 14 46
UDP sensor collector <https://github.com/espressif/arduino-esp32/tree/master/libraries/OpenThread/examples/CLI/UDP/udp_sensor_collector>_ipmaddr add ff03::abcd + udp bindUDP sensor node <https://github.com/espressif/arduino-esp32/tree/master/libraries/OpenThread/examples/CLI/UDP/udp_sensor_node>_udp send ff03::abcd 5050 ...CoAP lamp <https://github.com/espressif/arduino-esp32/tree/master/libraries/OpenThread/examples/CLI/COAP/coap_lamp>_ff05::abcdCoAP switch <https://github.com/espressif/arduino-esp32/tree/master/libraries/OpenThread/examples/CLI/COAP/coap_switch>_ff05::abcdDocumentation sample
:doc:openthread_udp includes a minimal receiver with beginMulticast(ff03::1, 7).
.. code-block:: text
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()
Multicasting.md <https://github.com/espressif/arduino-esp32/blob/master/libraries/OpenThread/Multicasting.md>_ — Markdown copy in the library tree.openthread_core — subscribeMulticast / unsubscribeMulticast API.openthread_udp — OThreadUDP including beginMulticast.openthread_coap — CoAP multicast and RFC notes.openthread — overview and shutdown order.