Skip to content

Source: DevicePlugin.h

DevicePlugin

How a foreign lighting or IoT system hooks into MoonLight's device discovery.

Functions

Return Name Description
void setDeviceName inline Copy a name in, truncating explicitly so the read is bounded.

setDeviceName

inline

inline void setDeviceName(DiscoveredDevice & d, const char * src)

Copy a name in, truncating explicitly so the read is bounded.

DevicePlugin

class DevicePlugin
src/core/system/DevicePlugin.h:53

One interop plugin: a stateless singleton turning a presence datagram into a device.

Public Methods

virtual ~DevicePlugin() = default : Destroyed through this interface, since the module holds plugins by base pointer.

virtual const char * label() const : A short label for logs and the UI, with flash-literal lifetime.

virtual uint16_t discoveryPort() const : The UDP port this ecosystem broadcasts presence on, which every bundled plugin shares.

virtual bool classifyPacket(const uint8_t * data, size_t len, const uint8_t srcIp, DiscoveredDevice & out) const : Claim and classify a datagram, or decline it so another plugin may try.

DiscoveredDevice

struct DiscoveredDevice
src/core/system/DevicePlugin.h:41

A device a plugin recognized, the address coming from the datagram and the rest from the plugin.

Public Attributes

DevType type = DevType::Generic : which ecosystem it belongs to

char name = {} : its display name, truncated to fit

MmPlugin

class MmPlugin
src/core/system/DevicePlugin.h:72

Inherits: DevicePlugin

Claims a presence packet that carries the MoonLight marker, so a peer is typed as one.

Public Methods

virtual inline const char * label() const override : Names this plugin in logs and the UI.

virtual inline uint16_t discoveryPort() const override : The shared presence port.

virtual inline bool classifyPacket(const uint8_t * data, size_t len, const uint8_t srcIp, DiscoveredDevice & out) const override : Claim and classify a datagram, or decline it so another plugin may try.

WledPlugin

class WledPlugin
src/core/system/DevicePlugin.h:91

Inherits: DevicePlugin

Claims any valid WLED presence packet that carries no MoonLight marker.

Public Methods

virtual inline const char * label() const override : Names this plugin in logs and the UI.

virtual inline uint16_t discoveryPort() const override : The shared presence port.

virtual inline bool classifyPacket(const uint8_t * data, size_t len, const uint8_t srcIp, DiscoveredDevice & out) const override : Claim and classify a datagram, or decline it so another plugin may try.

More info

DevicesModule owns the device model and the UDP discovery listener and stays domain-neutral, while each plugin teaches it to recognize one ecosystem from a presence broadcast. That is the adapter pattern, the same shape the list-source seam and the factory's register-by-name use. The core is generic and the per-system knowledge lives with its plugin, so a new system is one new file rather than a core edit.

Discovery is passive

A plugin declares the broadcast port it listens on and classifies a received datagram into a device.

This replaced an mDNS query path, which destabilized our own mDNS advertising: a query for a service we also host exhausts the IDF mDNS pool. mDNS is now advertise-only, so the WLED app and Home Assistant still find us, and discovery never queries.

Sized for a control half it does not yet have

The seam covers the discovery half, with two concrete plugins that prove it is not shaped to one system. It is sized to also carry a control half, a per-plugin command that translates something like setting brightness into a system's own protocol, without reshaping. That is why the discovered device stays plain data and the iteration is generic.

Why the MoonLight plugin is listed first

A MoonLight device broadcasts a WLED-valid packet, so the WLED apps list it, stamped with a sentinel in the version field. Its plugin claims a packet only when that marker is present, and the WLED plugin declines a packet that carries it. Order gives the more specific plugin its chance first.