You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/advanced/compiling-wled.md
-14Lines changed: 0 additions & 14 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -75,20 +75,6 @@ Once you've confirmed VSCode with Platformio is set up correctly, you can add/de
75
75
7. Put your `-D` overrides on this new line, giving each `-D` it's own new line.
76
76
8. Compile your freshly customized WLED image!
77
77
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).
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))_
9
10
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.
12
12
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)
14
16
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.
16
23
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:
18
27
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
21
35
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:
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
-
classMyMod : publicUsermod {
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
-
voidmode_myEffect() {
204
-
// ... set pixel colors using SEGMENT, SEGENV, SEGLEN, SEGCOLOR(n), etc. ...
205
-
}
206
-
staticconstchar _data_FX_MODE_MY_EFFECT[] PROGMEM = "My Effect@Speed,Intensity;!,!;!;01";
// 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:
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)`.
245
37
246
38
### Timing
247
39
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:
249
41
```cpp
250
42
long lastTime = 0;
251
43
int delayMs = 2000; //we want to do something every 2 seconds
@@ -265,22 +57,22 @@ void userLoop()
265
57
You can use Segments from your code to set different parts of the strip to different colors or effects.
266
58
This can be very useful for highly customized installations, clocks, ...
267
59
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.
269
61
270
-
To edit the color and effect configuration of a segment, use:
62
+
To edit the configuration of a segment, use:
271
63
```cpp
272
-
Segment& seg = strip.getSegment(id);
64
+
WS2812FX::Segment& seg = strip.getSegment(id);
273
65
//set color (i=0 is primary, i=1 secondary i=2 tertiary)
0 commit comments