Publish LumaOps source
This commit is contained in:
@@ -0,0 +1,274 @@
|
||||
# LumaOps source audit
|
||||
|
||||
Status: completed on 2026-07-14 against the imported OpenRGB 1.0rc3 source tree.
|
||||
|
||||
## Scope and method
|
||||
|
||||
The supplied archive was imported unchanged as commit `a15d499` and tagged
|
||||
`upstream-openrgb-1.0rc3` before LumaOps work started. The audit covered the
|
||||
build definition, command-line startup, SDK client/server implementation,
|
||||
protocol structures, settings and profile persistence, plugin loading, Linux
|
||||
hardware access, and the network-lighting controllers named in the project
|
||||
brief.
|
||||
|
||||
The imported tree contains 2,237 tracked files, including 1,045 C++ sources,
|
||||
943 headers, 37 Qt UI definitions, 189 controller directories, and 201 detector
|
||||
implementations. OpenRGB vendors or embeds several dependencies, including
|
||||
hidapi, libusb, mbedTLS, httplib, hueplusplus, libe131, mdns, and nlohmann JSON.
|
||||
|
||||
Files reviewed in detail include:
|
||||
|
||||
- `README.md`, `CONTRIBUTING.md`, `LICENSE`, and `OpenRGB.pro`
|
||||
- all required documents under `Documentation/`
|
||||
- `NetworkServer.*`, `NetworkClient.*`, and `NetworkProtocol.*`
|
||||
- `PluginManager.*`, `SettingsManager.*`, and `ProfileManager.*`
|
||||
- `cli.*`, `ResourceManager.*`, and platform startup sources
|
||||
- the controller and detector sources for the network protocols listed below
|
||||
|
||||
## Confirmed versions
|
||||
|
||||
| Component | Version | Source of truth |
|
||||
| --- | --- | --- |
|
||||
| OpenRGB | 1.0rc3 | `OpenRGB.pro` sets `SUFFIX = 1.0rc3` |
|
||||
| SDK protocol | 5 | `NetworkProtocol.h` sets `OPENRGB_SDK_PROTOCOL_VERSION 5` |
|
||||
| Plugin API | 4 | `OpenRGBPluginInterface.h` sets `OPENRGB_PLUGIN_API_VERSION 4` |
|
||||
|
||||
The LumaOps adapter must negotiate protocol 5. A peer that returns a different
|
||||
version is reported as incompatible instead of silently interpreting a newer or
|
||||
older packet layout.
|
||||
|
||||
## Licensing and contribution constraints
|
||||
|
||||
OpenRGB is distributed under GPL-2.0. The source files commonly use the
|
||||
`GPL-2.0-or-later` SPDX identifier. All upstream license files, copyright
|
||||
notices, and SPDX headers remain intact. LumaOps is part of the combined work
|
||||
and is therefore also published under GPL-2.0-or-later in this repository.
|
||||
|
||||
`CONTRIBUTING.md` makes the human contributor responsible for submitted code
|
||||
and disallows AI authorship or co-authorship metadata. Commits use the existing
|
||||
repository identity and do not add AI attribution trailers.
|
||||
|
||||
Anyone distributing a LumaOps image must make the corresponding source,
|
||||
including the exact OpenRGB modifications and build instructions, available
|
||||
under the GPL. Merely running the software privately does not trigger source
|
||||
distribution obligations.
|
||||
|
||||
## Build and headless operation
|
||||
|
||||
### Upstream Linux build
|
||||
|
||||
`Documentation/Compiling.md` describes a qmake/Qt 5 build. The significant
|
||||
Debian/Ubuntu build dependencies are Qt 5 development tools, a C++ toolchain,
|
||||
pkg-config, libusb, hidapi, and mbedTLS. The upstream sequence is equivalent to:
|
||||
|
||||
```sh
|
||||
mkdir build
|
||||
cd build
|
||||
qmake ../OpenRGB.pro
|
||||
make -j"$(nproc)"
|
||||
```
|
||||
|
||||
OpenRGB is still linked with Qt libraries in a headless build, but it creates a
|
||||
`QApplication` only when the GUI flag is selected. It therefore runs without an
|
||||
X11/Wayland display when started in server mode.
|
||||
|
||||
### Verified headless command
|
||||
|
||||
The CLI parser and platform startup code confirm this production command:
|
||||
|
||||
```sh
|
||||
openrgb \
|
||||
--server \
|
||||
--server-host 127.0.0.1 \
|
||||
--server-port 6742 \
|
||||
--config /config/openrgb \
|
||||
--noautoconnect
|
||||
```
|
||||
|
||||
The directory passed to `--config` must exist before startup. `--server-host`
|
||||
must always be explicit because OpenRGB otherwise defaults to `0.0.0.0`.
|
||||
`--nodetect` must not be supplied: it would defeat the required local hardware
|
||||
inventory. Starting with no server/CLI action would select the graphical UI.
|
||||
|
||||
The Linux startup path initializes `ResourceManager`, starts the internal
|
||||
server, waits for device detection, and then remains in
|
||||
`WaitWhileServerOnline()`. There is one upstream gap relevant to containers:
|
||||
SIGINT/SIGTERM handlers are registered only in the GUI startup branch. LumaOps
|
||||
therefore carries a small isolated patch that installs the same shutdown handler
|
||||
for headless server mode. This lets the supervisor stop OpenRGB cleanly instead
|
||||
of relying on the operating system's abrupt default termination.
|
||||
|
||||
The production container must verify at runtime that port 6742 is listening on
|
||||
loopback and must never publish or expose it through Docker.
|
||||
|
||||
## SDK protocol audit
|
||||
|
||||
The SDK is an unauthenticated binary TCP protocol. It is appropriate only as an
|
||||
internal process boundary in the same container; it is not an internet or LAN
|
||||
security boundary.
|
||||
|
||||
Packets start with a 16-byte header:
|
||||
|
||||
1. magic bytes `ORGB`;
|
||||
2. 32-bit device index;
|
||||
3. 32-bit packet ID;
|
||||
4. 32-bit payload length.
|
||||
|
||||
The implementation serializes the protocol's integers and packed structures in
|
||||
the native little-endian layout used by the x86_64 target. Notable request IDs
|
||||
are controller count (`0`), controller data (`1`), protocol negotiation (`40`),
|
||||
client name (`50`), device-list-changed (`100`), rescan (`140`), profile list and
|
||||
operations (`150`-`153`), and plugin operations (`200`-`201`). Update requests
|
||||
cover mode, device/zone/LED colours, custom mode, resizing zones, and segment
|
||||
changes.
|
||||
|
||||
Protocol 5 adds zone flags, controller flags, effects-only zones, alternative
|
||||
LED names, and segment-clear/add operations. The controller-data response is a
|
||||
nested variable-length structure containing strings, modes, zones, segments,
|
||||
LEDs, and colours. This makes strict bounds checking mandatory.
|
||||
|
||||
The internal adapter will enforce:
|
||||
|
||||
- exact-length reads and the `ORGB` magic value;
|
||||
- protocol-5 negotiation before normal traffic;
|
||||
- a configurable hard maximum packet size (default 16 MiB);
|
||||
- bounded collection counts and bounded, NUL-terminated strings;
|
||||
- controller, zone, LED, mode, speed, brightness, and colour validation;
|
||||
- controller identity checks instead of trusting a stale device index;
|
||||
- one serialized write queue plus per-device locks;
|
||||
- connection and command timeouts, bounded reconnect backoff, and cancellation;
|
||||
- no write side effects during inventory;
|
||||
- safe handling of device-list change notifications and OpenRGB restarts.
|
||||
|
||||
The server source also checks controller indexes and validates declared payload
|
||||
sizes for update packets. LumaOps performs the same checks before transmitting,
|
||||
so malformed application input never reaches OpenRGB.
|
||||
|
||||
### Existing Python client evaluation
|
||||
|
||||
The current `openrgb-python` package was inspected at upstream commit
|
||||
`dbbe58336268e273e2604f6f10b9e2f2003d6d84`. It still declares protocol version
|
||||
4, does not implement the protocol-5 surface required by this release, does not
|
||||
provide the required rescan request, and contains receive paths that use a
|
||||
single unbounded socket read for a declared packet length. Its repository also
|
||||
does not provide the parser/serialization test coverage required here.
|
||||
|
||||
Decision: LumaOps uses a small first-party SDK protocol-5 adapter behind a
|
||||
connector interface. No other application layer imports packet structures.
|
||||
This keeps the binary protocol auditable and lets tests replay captured and
|
||||
synthetic packets without replacing the real production adapter.
|
||||
|
||||
## Settings, profiles, and plugins
|
||||
|
||||
On Linux, OpenRGB normally stores data under `$XDG_CONFIG_HOME/OpenRGB` or
|
||||
`$HOME/.config/OpenRGB`. With the verified command above, all OpenRGB-owned
|
||||
state is instead rooted at `/config/openrgb`:
|
||||
|
||||
| Data | Location |
|
||||
| --- | --- |
|
||||
| Main settings | `/config/openrgb/OpenRGB.json` |
|
||||
| Normal profiles | `/config/openrgb/*.orp` |
|
||||
| Controller size profile | `/config/openrgb/sizes.ors` |
|
||||
| User plugins | `/config/openrgb/plugins/` |
|
||||
| System plugins | build-time platform directory, normally `/usr/lib/openrgb/plugins` |
|
||||
|
||||
Profiles match controller identity fields rather than relying only on discovery
|
||||
order. Profile deletion removes the corresponding profile file. Settings are
|
||||
written directly as JSON and OpenRGB itself does not make an atomic backup, so
|
||||
LumaOps backs up the OpenRGB directory together with its own data before
|
||||
restores, migrations, or destructive maintenance.
|
||||
|
||||
Plugin enablement is stored in the `Plugins` section of `OpenRGB.json`. A plugin
|
||||
must match Plugin API 4 exactly. User-supplied plugins execute native code in the
|
||||
OpenRGB process and are therefore treated as trusted administrator extensions,
|
||||
not as sandboxed add-ons.
|
||||
|
||||
Some network-controller configuration is also stored in `OpenRGB.json`. It can
|
||||
include credentials such as a Philips Hue username/client key or Espurna API
|
||||
key. `/config/openrgb` must therefore receive the same restrictive filesystem
|
||||
permissions, backup handling, and diagnostic redaction as LumaOps secrets.
|
||||
|
||||
LumaOps state is deliberately separate under `/config/lumaops` and `/data` so
|
||||
OpenRGB upstream files and application migrations have independent lifecycles.
|
||||
|
||||
## Existing OpenRGB network support
|
||||
|
||||
The audit distinguishes automatic discovery from controllers that are created
|
||||
from manually saved settings even when their source class is named a detector.
|
||||
|
||||
| Family | Existing OpenRGB path | Transport and discovery notes |
|
||||
| --- | --- | --- |
|
||||
| DDP | DDP network controller | Manual target stored in settings; UDP, default port 4048 |
|
||||
| E1.31/sACN | E1.31 controller | Manual unicast/multicast configuration; standard E1.31 UDP transport |
|
||||
| Philips Hue | Hue controller via hueplusplus | Bridge discovery plus manual bridge data; REST/entertainment setup; username and client key are persistent secrets |
|
||||
| Philips WiZ | WiZ controller | UDP port 38899 |
|
||||
| Nanoleaf | Nanoleaf controller | HTTP API for setup/state and external-control UDP streaming; external port may be negotiated, with 60222 used by supported paths |
|
||||
| LIFX | LIFX controller | LAN protocol over UDP port 56700 |
|
||||
| Govee | Govee controller | LAN discovery multicast `239.255.255.250:4001`, local discovery port 4002, control UDP port 4003 |
|
||||
| TP-Link Kasa | Kasa controller | Local TCP protocol on port 9999 |
|
||||
| Yeelight | Yeelight controller | LAN discovery/manual target; TCP port 55443 |
|
||||
| Espurna | Espurna controller | Manual IP/port/API key; HTTP-style API over TCP |
|
||||
| Elgato lighting | Key Light and Light Strip controllers | Local HTTP/TCP API on port 9123 |
|
||||
|
||||
Host networking may be needed for broadcast, multicast, or mDNS discovery on an
|
||||
Unraid host. Bridge networking remains the default. A host-network deployment
|
||||
still binds the SDK to `127.0.0.1`; only the LumaOps web port is intended for LAN
|
||||
access.
|
||||
|
||||
Native WLED and Home Assistant connectors remain outside OpenRGB and use the
|
||||
same LumaOps capability model. Duplicate ownership is prevented by assigning
|
||||
one management owner per physical device.
|
||||
|
||||
## Hardware access on Linux and Unraid
|
||||
|
||||
### USB
|
||||
|
||||
OpenRGB needs access to hidraw/libusb devices. A normal Linux installation can
|
||||
install generated udev rules at `/usr/lib/udev/rules.d/60-openrgb.rules`. In a
|
||||
container, the host kernel still owns udev and permissions. The supported
|
||||
deployment passes `/dev/bus/usb` explicitly and, where needed, selected hidraw
|
||||
devices. Running the whole container as privileged or mounting all of `/dev` is
|
||||
not the production default.
|
||||
|
||||
### SMBus/I2C
|
||||
|
||||
The host loads `i2c-dev` plus its chipset driver, commonly `i2c-i801` on Intel
|
||||
or `i2c-piix4` on AMD. Only discovered `/dev/i2c-*` nodes that are actually
|
||||
needed are passed through. Some boards require vendor-specific modules; some
|
||||
kernel/ACPI workarounds can be unsafe and are documented as diagnostics rather
|
||||
than enabled automatically. SPD-related controllers can conflict with kernel
|
||||
memory sensor drivers, so LumaOps does not unload modules or write to SMBus as
|
||||
part of inventory.
|
||||
|
||||
### Serial devices
|
||||
|
||||
Optional serial controllers use individually mapped `/dev/ttyUSB*` or
|
||||
`/dev/ttyACM*` devices. Their group/permission requirements remain host-specific.
|
||||
|
||||
The first-run inventory is read-only. Actual validation starts with one selected
|
||||
device, a static low-intensity colour, and a low command frequency.
|
||||
|
||||
## Architectural conclusions
|
||||
|
||||
1. Preserve the upstream source layout and keep LumaOps under `lumaops/`,
|
||||
`docker/`, `docs/`, and `tests/`.
|
||||
2. Carry only the documented headless signal patch and unambiguous HID-interface
|
||||
fallback in OpenRGB Core; keep all other policy, persistence, connectors, and UI
|
||||
work outside the core.
|
||||
3. Build OpenRGB from the imported source in the production multi-stage image.
|
||||
4. Run OpenRGB and FastAPI under a real init/supervisor; serve the built React
|
||||
application from FastAPI so only one web port is public.
|
||||
5. Use an internal protocol-5 adapter for production and a clearly marked mock
|
||||
adapter only for tests and intentional development mode.
|
||||
6. Store stable LumaOps UUIDs from a fingerprint of durable identity fields plus
|
||||
persisted identity aliases; never expose discovery order as identity.
|
||||
7. Keep OpenRGB at `127.0.0.1:6742`, including under host networking, and reject
|
||||
non-loopback production configuration unless an administrator explicitly
|
||||
opts into the documented remote-endpoint risk.
|
||||
8. Treat both `/config/openrgb` and `/config/lumaops` as sensitive persistent
|
||||
state and redact them from diagnostics.
|
||||
9. Model connector capabilities generically so WLED, Home Assistant, MQTT,
|
||||
remote agents, and future protocols do not require brand-specific UI paths.
|
||||
|
||||
This audit clears the project to proceed with the LumaOps architecture and MVP
|
||||
implementation while retaining OpenRGB 1.0rc3 as the actual hardware engine.
|
||||
Reference in New Issue
Block a user