Skip to content

Commit 358bddb

Browse files
committed
revert "community usermods" addition - WLEDMM does not yet support them
1 parent 0732641 commit 358bddb

4 files changed

Lines changed: 32 additions & 280 deletions

File tree

docs/advanced/community-usermods.md

Lines changed: 0 additions & 26 deletions
This file was deleted.

docs/advanced/compiling-wled.md

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -75,20 +75,6 @@ Once you've confirmed VSCode with Platformio is set up correctly, you can add/de
7575
7. Put your `-D` overrides on this new line, giving each `-D` it's own new line.
7676
8. Compile your freshly customized WLED image!
7777

78-
### Adding usermods
79-
80-
To include one or more usermods in your build, add a `custom_usermods` line to your environment in `platformio_override.ini`:
81-
82-
```ini
83-
[env:esp32dev_temperature]
84-
extends = env:esp32dev
85-
custom_usermods =
86-
audioreactive
87-
Temperature
88-
```
89-
90-
Each name corresponds to a folder under `usermods/`. No other file editing is required — usermods self-register when compiled in. For full details, including how to add external usermods from a git repository and how to write your own, see [Custom Features](/advanced/custom-features).
91-
9278
### Flashing the compiled binary
9379

9480
!!! tip

docs/advanced/custom-features.md

Lines changed: 32 additions & 239 deletions
Original file line numberDiff line numberDiff line change
@@ -5,247 +5,39 @@ hide:
55
# - toc
66
---
77

8-
This page covers how to add custom functionality to WLED, either through usermods or by modifying the source directly.
8+
!!! warning
9+
_Note: this page is now out of date, see updated functionality in the code ([WLED/usermods/EXAMPLE](https://github.com/wled/WLED/tree/main/usermods/EXAMPLE))_
910

10-
!!! tip "New to building WLED?"
11-
See [Compiling WLED](/advanced/compiling-wled) first to get your build environment set up.
11+
This page is intended for those wishing to modify the WLED code to add their own functionality.
1212

13-
## Usermods
13+
### Basics
14+
Programming is done in the Arduino IDE. There is a special file, `usermod.cpp`, to write your own code.
15+
(however, if you think your code may be relevant to many users, feel free to code it in directly and open a pull request)
1416

15-
Usermods are self-contained modules you can add to a WLED build without touching core source files. WLED ships with many usermods in the `usermods/` directory (audio-reactive, temperature sensors, displays, rotary encoders, and more).
17+
This file has three empty methods:
18+
- `userSetup()` is called after loading settings but before connecting to WiFi.
19+
Use it to start own interfaces if it does not depend on WiFi (IR, Sensors, GPIOs,...).
20+
Also you can use it to load custom settings or to specify own server pages with the `server.on()` method.
21+
- `userConnected()` is called once WiFi is connected. Use it to connect to external servers or init interfaces using wiFi.
22+
- `userLoop()` is called by the main `loop()` function.
1623

17-
### Enabling usermods
24+
### Modify WLED values
25+
If you know what you're doing, you may choose to change the value of any global variable declared in `wled.h`.
26+
However, for basic color and brightness changes, these are the most important:
1827

19-
!!! info "Since WLED 16"
20-
The `custom_usermods` option replaced the old `usermods_list.cpp` approach. Each usermod now self-registers using the `REGISTER_USERMOD()` macro and declares its own dependencies in a `library.json`.
28+
Variable Name | Type | Purpose
29+
--- | --- | ---
30+
bri | byte (0-255) | Master Brightness (0 is off, 255 is maximum)
31+
col[0] | byte (0-255) | Red color value
32+
col[1] | byte (0-255) | Green color value
33+
col[2] | byte (0-255) | Blue color value
34+
col[3] | byte (0-255) | White color value
2135

22-
Add a `custom_usermods` entry to the relevant environment section in your `platformio_override.ini`:
23-
24-
```ini
25-
[env:esp32dev_temperature]
26-
extends = env:esp32dev ; base environment from platformio.ini
27-
custom_usermods =
28-
Temperature
29-
audioreactive
30-
```
31-
32-
Each line is either a PlatformIO `lib_def` reference or a folder name under `usermods/`. (As a convenience for old foldernames, `usermod_` or `_v2` may be omitted.) Enabled usermods will appear in the WLED build as the library names from their `library.json` files. Rebuild from PlatformIO and the usermods and their dependencies are automatically included, no other file edits needed.
33-
34-
#### Inheriting usermods from a base environment
35-
36-
Use PlatformIO variable substitution to extend a base environment's usermod list without repeating it:
37-
38-
```ini
39-
[env:esp32dev_with_extras]
40-
extends = env:esp32dev
41-
custom_usermods =
42-
${env:esp32dev.custom_usermods}
43-
RTC
44-
```
45-
46-
### Writing a usermod
47-
48-
The recommended approach is to keep your usermod in its own repository, separate from the WLED source tree. This lets you version and share it independently, and reference it from any WLED build without copying files.
49-
50-
#### 1. Fork the example repository
51-
52-
Fork [wled/wled-usermod-example](https://github.com/wled/wled-usermod-example) on GitHub. It contains a minimal `library.json` and a fully annotated example implementation — everything you need to get started. Rename the files and class to something descriptive, then add your code.
53-
54-
#### 2. Reference it locally during development
55-
56-
Clone your fork somewhere convenient — alongside your WLED checkout works well, since both projects can then be open in the same VS Code session:
57-
58-
```text
59-
~/projects/
60-
WLED/ ← the WLED source
61-
my-wled-usermod/ ← your fork
62-
library.json
63-
my_usermod.cpp
64-
```
65-
66-
In `platformio_override.ini`, point `custom_usermods` at the local clone using a `file://` URL:
67-
68-
```ini
69-
[env:esp32dev_my_usermod]
70-
extends = env:esp32dev
71-
custom_usermods =
72-
${env:esp32dev.custom_usermods}
73-
file:///home/you/projects/my-wled-usermod
74-
```
75-
76-
On Windows, use the `file:///C:/Users/you/...` form with forward slashes: `file:///C:/Users/you/projects/my-wled-usermod`.
77-
78-
PlatformIO will pick up your local changes on each build, and you can edit the usermod and WLED side-by-side without switching projects.
79-
80-
#### 3. Share it via git URL
81-
82-
Once your usermod is ready to share, others can reference it directly by URL — no local clone needed:
83-
84-
```ini
85-
custom_usermods =
86-
${env:esp32dev.custom_usermods}
87-
https://github.com/you/my-wled-usermod.git#main
88-
```
89-
90-
PlatformIO uses the `name` field from the repository's `library.json` to identify the library. If that name does not match the repository name in the URL, supply it explicitly:
91-
92-
```ini
93-
custom_usermods =
94-
MyMod = https://github.com/you/my-wled-usermod.git#main
95-
```
96-
97-
Once it's ready, consider adding it to the [Community Usermods](/advanced/community-usermods) index and tagging your repository with the [`wled-usermod`](https://github.com/topics/wled-usermod) GitHub topic so others can find it.
98-
99-
#### What's inside a usermod
100-
101-
A usermod repository contains two things: a **PlatformIO library manifest** (`library.json`) and one or more **C++ source files** implementing your functionality.
102-
103-
`library.json` tells PlatformIO how to build and link your module, and lists any external libraries it depends on. The only mandatory non-obvious setting is `"libArchive": false`, which tells PlatformIO to link the module directly into the firmware rather than treating it as an archive — without it, `REGISTER_USERMOD` won't work and the build will fail:
104-
105-
```json
106-
{
107-
"name": "my-wled-usermod",
108-
"build": { "libArchive": false },
109-
"dependencies": {
110-
"paulstoffregen/OneWire": "~2.3.8"
111-
}
112-
}
113-
```
114-
115-
Any libraries listed under `dependencies` are fetched automatically — no need to add them to `platformio_override.ini` by hand.
116-
117-
The C++ side extends the `Usermod` base class, overriding whichever lifecycle hooks you need, and calls `REGISTER_USERMOD()` at file scope to self-register:
118-
119-
```cpp
120-
#include "wled.h"
121-
122-
class MyMod : public Usermod {
123-
void setup() override {
124-
// called once at boot, before WiFi connects
125-
}
126-
127-
void connected() override {
128-
// called each time WiFi (re)connects
129-
}
130-
131-
void loop() override {
132-
// called every main-loop iteration — never use delay() here!
133-
if (millis() - lastTime > 2000) {
134-
lastTime = millis();
135-
// do something every 2 seconds
136-
}
137-
}
138-
139-
private:
140-
unsigned long lastTime = 0;
141-
};
142-
143-
static MyMod my_mod;
144-
REGISTER_USERMOD(my_mod); // self-registers — no usermods_list.cpp edits needed
145-
```
146-
147-
The `getId()` method is optional for most custom usermods — the base class returns `USERMOD_ID_UNSPECIFIED` by default. Override it only if another part of the firmware needs to identify your specific usermod.
148-
149-
The forked example file contains a fully annotated version of this covering persistent settings (`addToConfig` / `readFromConfig`), JSON state, MQTT, and more.
150-
151-
152-
#### Useful lifecycle methods
153-
154-
| Method | When called |
155-
|---|---|
156-
| `setup()` | Once at boot, after config is loaded, before WiFi |
157-
| `connected()` | Each time WiFi (re)connects |
158-
| `loop()` | Every main loop iteration |
159-
| `addToJsonInfo(root)` | When `/json/info` is requested |
160-
| `addToJsonState(root)` | When `/json/state` is requested |
161-
| `readFromJsonState(root)` | When a client POSTs to `/json/state` |
162-
| `addToConfig(root)` | When settings are saved (persist to `cfg.json`) |
163-
| `readFromConfig(root)` | At boot and after settings save |
164-
| `appendConfigData(Print& settingsScript)` | When the Usermod Settings page renders |
165-
| `handleOverlayDraw()` | Just before each LED strip update |
166-
| `handleButton(b)` | On button events (return `true` to consume) |
167-
| `onMqttConnect(sessionPresent)` | When MQTT connection is established (subscribe here) — wrap in `#ifndef WLED_DISABLE_MQTT` |
168-
| `onMqttMessage(topic, payload)` | On incoming MQTT message — wrap in `#ifndef WLED_DISABLE_MQTT` |
169-
| `onEspNowMessage(sender, payload, len)` | Called when an ESP-NOW message is received — can be used for usermod remote control |
170-
| `onUdpPacket(payload, len)` | Called when a UDP packet is received on the notification UDP port — can be used for usermod sync |
171-
| `onUpdateBegin(bool)` | Called prior to firmware update to request releasing memory; and after unsuccessful firmware update to resume |
172-
| `onStateChange(mode)` | Called when WLED state changes (see `CALL_MODE_*` definitions) |
173-
174-
The `onMqttConnect` and `onMqttMessage` overrides must be wrapped in `#ifndef WLED_DISABLE_MQTT` / `#endif` guards, since MQTT support is a compile-time option. The `multi_relay` usermod (`usermods/multi_relay`) is a well-structured in-tree example of the subscribe-in-connect / handle-in-message pattern.
175-
176-
#### Persistent settings
177-
178-
Use `addToConfig()` and `readFromConfig()` to store settings in `cfg.json`. WLED will expose them automatically on the Usermod Settings page:
179-
180-
```cpp
181-
void addToConfig(JsonObject& root) override {
182-
JsonObject top = root.createNestedObject(FPSTR(_name));
183-
top["myValue"] = myValue;
184-
}
185-
186-
bool readFromConfig(JsonObject& root) override {
187-
JsonObject top = root[FPSTR(_name)];
188-
bool ok = !top.isNull();
189-
ok &= getJsonValue(top["myValue"], myValue, 42 /*default*/);
190-
return ok; // return false to have WLED write defaults to disk
191-
}
192-
```
193-
194-
#### Adding custom effects
195-
196-
Writing effects as usermods is the recommended way to add new LED effects to a WLED build — no core source files need changing, and the effect can live in its own repository and be shared like any other usermod.
197-
198-
The `user_fx` usermod (`usermods/user_fx`) is the mainline example of this pattern and a convenient starting point. It bundles multiple effects in a single usermod and can be enabled with `custom_usermods = user_fx`. It has a [detailed README](https://github.com/wled/WLED/blob/main/usermods/user_fx/README.md) for creating effects. Fork it or use it as a template for your own effects usermod.
199-
200-
Each effect is a free `void` function paired with a PROGMEM metadata string, registered via `strip.addEffect()` in the usermod's `setup()`. Multiple effects can be registered from a single `setup()`:
201-
202-
```cpp
203-
void mode_myEffect() {
204-
// ... set pixel colors using SEGMENT, SEGENV, SEGLEN, SEGCOLOR(n), etc. ...
205-
}
206-
static const char _data_FX_MODE_MY_EFFECT[] PROGMEM = "My Effect@Speed,Intensity;!,!;!;01";
207-
208-
void setup() override {
209-
strip.addEffect(255, &mode_myEffect, _data_FX_MODE_MY_EFFECT);
210-
// 255 = "assign next available slot"; use a fixed ID for a permanent effect
211-
// call addEffect() again for each additional effect
212-
}
213-
```
214-
215-
See [effect metadata](/interfaces/json-api/#effect-metadata) for the format of the data string.
216-
217-
---
218-
219-
### Legacy v1 usermod (usermod.cpp)
220-
221-
!!! warning "Legacy"
222-
The v1 approach (`usermod.cpp`) predates the module system and only allows a single usermod per build. Use the v2 class-based approach above for new projects.
223-
224-
`wled00/usermod.cpp` contains three stub functions you can fill in:
225-
226-
- `userSetup()` — called after loading settings, before WiFi
227-
- `userConnected()` — called once WiFi is connected
228-
- `userLoop()` — called from the main loop
229-
230-
---
231-
232-
## Modifying WLED values directly
233-
234-
If you know what you're doing, you may change global variables declared in `wled.h`. For basic color and brightness:
235-
236-
| Variable | Type | Purpose |
237-
|---|---|---|
238-
| `bri` | `byte` (0–255) | Master brightness (0 = off) |
239-
| `col[0]` | `byte` (0–255) | Red |
240-
| `col[1]` | `byte` (0–255) | Green |
241-
| `col[2]` | `byte` (0–255) | Blue |
242-
| `col[3]` | `byte` (0–255) | White |
243-
244-
After changing a color call `colorUpdated(CALL_MODE_DIRECT_CHANGE)` to push it to the strip and notify sync targets, or `colorUpdated(CALL_MODE_NO_NOTIFY)` to skip the notification.
36+
After updating the color, you must call the `colorUpdated(int)` method. If you want to send a notification with the new color to other ESPs, use `colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE)`, otherwise `colorUpdated(NOTIFIER_CALL_MODE_NO_NOTIFY)`.
24537

24638
### Timing
24739

248-
If you'd just like a simple modification that requires timing (like sending a request every 2 seconds), please **never** use the `delay()` function in your `userLoop()`! It will block everything else and WLED will become unresponsive and effects won't work! Instead, try this:
40+
If you'd just like a simple modification that requires timing (like sending a request every 2 seconds), please **never** use the `delay()` function in your `userLoop()`! It will block everything else and WLED will become unresponsive and effects won't work! Instead, try this instead:
24941
```cpp
25042
long lastTime = 0;
25143
int delayMs = 2000; //we want to do something every 2 seconds
@@ -265,22 +57,22 @@ void userLoop()
26557
You can use Segments from your code to set different parts of the strip to different colors or effects.
26658
This can be very useful for highly customized installations, clocks, ...
26759

268-
To get a reference to a segment, use `strip.getSegment(id)`, where _id_ is the segment ID (0-based). To change a segment's boundaries, assign `seg.start` and `seg.stop` directly and then call `seg.markForReset()`.
60+
To set a segment, use `strip.setSegment(id, start, stop);`, where _id_ is the segment ID, _start_ is the first LED of the segment and _stop_ is the LED after the last one in the segment.
26961

270-
To edit the color and effect configuration of a segment, use:
62+
To edit the configuration of a segment, use:
27163
```cpp
272-
Segment& seg = strip.getSegment(id);
64+
WS2812FX::Segment& seg = strip.getSegment(id);
27365
//set color (i=0 is primary, i=1 secondary i=2 tertiary)
274-
seg.colors[i] = RGBW32(myRed, myGreen, myBlue, myWhite);
66+
seg.colors[i] = ((myWhite << 24) | ((myRed&0xFF) << 16) | ((myGreen&0xFF) << 8) | ((myBlue&0xFF)));
27567
//set effect config
276-
seg.mode = myFxId;
68+
seg.mode = myFxI;
27769
seg.speed = mySpeed;
27870
seg.intensity = myIntensity;
27971
seg.palette = myPaletteId;
28072
```
281-
Keep in mind that this will not cause interface updates. For that, you still need to use `colorUpdated(CALL_MODE_DIRECT_CHANGE)`
73+
Keep in mind that this will not cause interface updates as of 0.8.6. For that, you still need to use `colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE)`
28274

283-
### Create ARTI-FX
75+
### Create custom effects
28476

28577
It is possible to create your own effects and add them to the FX library.
28678
The relevant files for that are `FX.cpp` and `FX.h`.
@@ -305,6 +97,7 @@ Here is a step-by-step guide on how to make your effect:
30597
8. Compile, upload and enjoy! Your new effect will automatically be added to the list in the web ui.
30698

30799
If you programmed a nice effect you want to share, submit a pull request!
100+
308101
### Create a custom effect as usermod
309102

310103
!!! info "Since 0.14"

mkdocs.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,6 @@ nav:
125125
- Compiling WLED: advanced/compiling-wled.md
126126
- WLED Build Flags: advanced/buildflags.md
127127
- Custom Features: advanced/custom-features.md
128-
- Community Usermods: advanced/community-usermods.md
129128
- ESP32 Recovery: advanced/esp32-recovery.md
130129
- Mapping: advanced/mapping.md
131130
- Mixed 2D and 1D Setups: advanced/2d-1d-Mixed-Setup.md

0 commit comments

Comments
 (0)