Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
152 commits
Select commit Hold shift + click to select a range
27d3420
Build each usermod in isolation
netmindz Jan 22, 2025
0e7d5dd
Build each usermod in isolation
netmindz Jan 22, 2025
04c7eac
Use JSON for usermods list
netmindz Jan 22, 2025
b3af04d
Use JSON for usermods list
netmindz Jan 22, 2025
b1b2eea
Use JSON for usermods list
netmindz Jan 22, 2025
8d4c911
Fix typo in env name
netmindz Jan 22, 2025
5f19608
Merge branch 'usermod-libs' into usermod-libs-matrix
netmindz Jan 22, 2025
7d48bba
build usermod_esp32
netmindz Jan 22, 2025
74672e2
Verify each usermod on change
netmindz Jan 22, 2025
99108f9
Swap ordering to see if naming is then clearer
netmindz Jan 22, 2025
199529a
Also run if the workflow changes
netmindz Jan 22, 2025
3a31d5d
Merge branch 'usermod-libs' into usermod-libs-matrix
netmindz Feb 7, 2025
e7e0eb0
Pinwheel Rework
Brandon502 Feb 14, 2025
80061e8
Pinwheel: Use sin/cos16_t
Brandon502 Feb 25, 2025
2012317
initial version, basically working but repetitive patterns, work in p…
DedeHai Mar 3, 2025
9553425
some speed improvements using better hash, scaling is still off...
DedeHai Mar 4, 2025
5e80730
3D works but needs finetuning to match old looks
DedeHai Mar 7, 2025
4ecc531
updated scaling, improved hashing, updated rotozoomer to not use a bu…
DedeHai Mar 8, 2025
a6d9a82
Merge pull request #4480 from willmmiles/usermod-libs
netmindz Mar 11, 2025
95dcb03
updated scaling
DedeHai Mar 12, 2025
229e7b9
added ranges, removed unused code
DedeHai Mar 12, 2025
494b72c
Merge remote-tracking branch 'upstream/main' into perlin_noise
DedeHai Mar 12, 2025
d2b7e47
add legacy defines for compatibility, reverted test changes in rotozo…
DedeHai Mar 14, 2025
a70bfa0
Merge pull request #4596 from Dschogo/patch-1
blazoncek Mar 15, 2025
6303151
Fix typo in build.yml
marcone Mar 22, 2025
befff2f
Merge pull request #4605 from marcone/patch-1
netmindz Mar 22, 2025
ed6efe4
Merge pull request #4551 from Brandon502/PinwheelRework
netmindz Mar 23, 2025
f328713
Fix typo
marcone Mar 23, 2025
86393e0
Merge pull request #4608 from marcone/patch-2
blazoncek Mar 23, 2025
a0d1a8c
Use enum class for json endpoint subtypes
willmmiles Mar 22, 2025
e21a09c
Separate FS write from serializeConfig
willmmiles Mar 23, 2025
9c8f8c6
Rename 'doSerializeConfig' to 'configNeedsWrite'
willmmiles Mar 23, 2025
22e2b6f
Have json/cfg return live config
willmmiles Mar 23, 2025
36cb1ca
settings_um: Use live config
willmmiles Mar 23, 2025
e76e9a3
Merge pull request #4594 from DedeHai/perlin_noise
DedeHai Mar 26, 2025
7e87891
Update USERMOD BME68X to version 1.0.2
gsieben Mar 28, 2025
1492f1c
usermod_v2_HttpPullLightControl: Fix build
willmmiles Mar 29, 2025
af1a966
usermod/word-clock-matrix: Fix build
willmmiles Mar 29, 2025
16525c2
usermod/BME68X_v2: Fix macro collision
willmmiles Mar 29, 2025
468ef50
usermods/rgb-rotary-encoder: Enable usermod
willmmiles Mar 29, 2025
d03604b
usermods/MAX17048_v2: Fix precision variable type
willmmiles Mar 29, 2025
035d4ae
usermods\MAX17048_v2: Fix readme
willmmiles Mar 29, 2025
e2c919d
Fixup usermods_v2_four_line_display_ALT
willmmiles Mar 29, 2025
ff99c7d
Convert usermods/usermod_v2_brightness_follow_sun
willmmiles Mar 29, 2025
1cd3a97
usermods: Fix 7sd_reloaded cross module binding
willmmiles Mar 29, 2025
fab80f4
Fix up usermod dep checking scripts
willmmiles Mar 29, 2025
62d3e15
usermod/SN_Photoresistor: Fix invalid initializer
willmmiles Mar 29, 2025
c3ab562
Update usermods/usermod_v2_brightness_follow_sun/library.json
willmmiles Mar 29, 2025
f719ee5
Update usermods/usermod_v2_four_line_display_ALT/library.json
willmmiles Mar 29, 2025
fbbb369
Update usermods/usermod_v2_rotary_encoder_ui_ALT/library.json
willmmiles Mar 29, 2025
7db52d7
Fix incorrect json value in all usermods
willmmiles Mar 29, 2025
b0b3196
Merge pull request #4620 from gsieben/USERMOD-BME68X-Update-to-Versio…
willmmiles Mar 29, 2025
354a0ae
Merge remote-tracking branch 'upstream/main' into more-usermod-fixes
willmmiles Mar 29, 2025
b941654
Allow clock overlay to use LED beyond 255
blazoncek Mar 29, 2025
e979c58
Merge pull request #4609 from willmmiles/usermod-cfg-live
netmindz Apr 6, 2025
02f14ba
Updates to particle system (#4630)
DedeHai Apr 15, 2025
ca7d7d9
Only disable Arduino OTA when using -D WLED_DISABLE_OTA
blazoncek Apr 20, 2025
c661d8f
Merge pull request #4627 from blazoncek/overlay-fix
blazoncek Apr 20, 2025
3538684
Removed PS memory manager and some minor improvements (#4651)
DedeHai Apr 20, 2025
8baf0fd
Add UI logic to hide ArduinoOTA checkbox and remove configuration items
blazoncek Apr 20, 2025
ee9ac94
Segment layering & effect blending improvements
blazoncek Apr 22, 2025
10b925a
bugfix in enumerating buttons and busses (#4657)
DedeHai Apr 23, 2025
0f321bf
Compilation fixes
blazoncek Apr 23, 2025
7f2b6a3
More compilation fixes.
blazoncek Apr 23, 2025
f1d52a8
Bump h11 from 0.14.0 to 0.16.0
dependabot[bot] Apr 24, 2025
410025f
Merge pull request #4661 from wled/dependabot/pip/h11-0.16.0
netmindz Apr 25, 2025
adb9b77
Merge branch 'main' into usermod-libs-matrix
netmindz Apr 26, 2025
7852ff5
Build for each chipset
netmindz Apr 26, 2025
b77881f
Build for each chipset
netmindz Apr 26, 2025
fbb7ef7
fix custom_usermods setting
netmindz Apr 26, 2025
6c4d049
force new line
netmindz Apr 26, 2025
19ba257
usermod_esp32s3
netmindz Apr 26, 2025
92db9e0
fix envs
netmindz Apr 26, 2025
f1c88bc
fix envs
netmindz Apr 26, 2025
c934776
Address issues reported
blazoncek Apr 26, 2025
125a21d
Comment
blazoncek Apr 26, 2025
f721efc
fixed wrong gravity setting, added option for no trail (#4665)
DedeHai Apr 28, 2025
d10714d
Merge pull request #4623 from willmmiles/more-usermod-fixes
netmindz Apr 30, 2025
7998650
Fix up usermod libArchive settings
willmmiles Mar 29, 2025
6464c62
load_usermods: Enforce CPPPATH type
willmmiles May 1, 2025
d9b086c
Bugfixes in PS, improvements to PS Fireworks 1D (#4673)
DedeHai May 1, 2025
a8dd243
Revert "Usermods: Remove libArchive"
willmmiles May 7, 2025
849d5e6
Add libArchive to other usermods
willmmiles May 7, 2025
ee38641
load_usermods: Make missing libArchive an error
willmmiles May 7, 2025
0fe722e
add new effect: PS Galaxy
DedeHai May 9, 2025
891115e
bugfix
DedeHai May 9, 2025
5fe7663
comment
DedeHai May 9, 2025
608aff1
slight speed improvement, fixed indentation
DedeHai May 10, 2025
40653b0
Merge pull request #4682 from DedeHai/PS_galaxy
netmindz May 10, 2025
b5a710d
Fixed markdownlint errors
srg74 May 11, 2025
42d9a41
Fixed markdownlint errors #2
srg74 May 11, 2025
cbe7d06
Merge pull request #4683 from srg74/main
netmindz May 11, 2025
d381108
AR: add compile-time flag for "Automatic Gain Control" option
Arcitec May 13, 2025
d9ad4ec
improved & refactored Android FX (#4522)
DedeHai May 19, 2025
66ad27a
add support for up to 10 ESPNow remotes (#4654)
DedeHai May 19, 2025
25223c4
fixed bouncing bug (#4694)
DedeHai May 19, 2025
999637f
Validate usermods at link time
willmmiles May 19, 2025
24ab295
Add unambiguous usermod list to info
willmmiles May 19, 2025
ac61eb4
validate_usermods: Fix inverted check
willmmiles May 19, 2025
817157b
Change to set LWT only once
zuckschwerdt May 22, 2025
c693f63
Fix running initMqtt twice on bootup
zuckschwerdt May 22, 2025
358e38e
validate_usermods: Ensure map file is created
willmmiles May 22, 2025
242df4b
validate_usermods: Fix old ESP32 platform
willmmiles May 22, 2025
7ea510e
validate_usermods: Improve message
willmmiles May 22, 2025
792a7aa
load_usermods: Resolve folder paths
willmmiles May 22, 2025
75cd411
Improve all-usermod handling
willmmiles May 24, 2025
aa28769
Merge pull request #4652 from wled/disable-ota
blazoncek May 24, 2025
0a7d3a9
load_usermods: Simplify load code
willmmiles May 25, 2025
75c95d8
usermods/*/setup_deps.py: Check lib_deps for deps
willmmiles May 25, 2025
309c8d6
Generalize module link validation
willmmiles May 25, 2025
e80a7c6
usermod_v2_HttpPullLightControl: Add usermod object
willmmiles May 25, 2025
f362315
Usermod script cleanup
willmmiles May 25, 2025
f26733c
Merge pull request #4697 from zuckschwerdt/fix-mqttlwtonce
netmindz May 26, 2025
db22936
Merge pull request #4698 from zuckschwerdt/fix-initmqtttwice
netmindz May 26, 2025
4a3af81
Merge pull request #4669 from willmmiles/4597-usermods-not-building
willmmiles May 27, 2025
23a51e0
Merge pull request #4658 from wled/layers
blazoncek Jun 1, 2025
a87b562
update to distortionwave FX (#4693)
DedeHai Jun 6, 2025
8b65d87
fix particle brightness distribution with new gamma correction (#4710)
DedeHai Jun 7, 2025
ab28b6d
Update crude parallel I2S detection
willmmiles Jun 7, 2025
fc7d4df
Added new "effect usermod"
mryndzionek Jun 8, 2025
00eb406
add pre-applied gamma to c3g & fastled palettes to match original loo…
DedeHai Jun 8, 2025
9805ae5
PS Fire: added sparks for better looks (#4714)
DedeHai Jun 8, 2025
caeda96
PS bugfix: do not increase saturation of palette colors (#4715)
DedeHai Jun 8, 2025
00d1fcc
bugfixes: grouping and missing libArchive (#4718)
DedeHai Jun 9, 2025
24e71cc
Bump requests from 2.32.3 to 2.32.4
dependabot[bot] Jun 10, 2025
ea231cb
Fixed "Flow Stripe" FX and added palette support
DedeHai Jun 10, 2025
05f0630
add inverse gamma 32 function and fix colors in pride (#4722)
DedeHai Jun 11, 2025
2a0e78c
Merge pull request #4721 from wled/dependabot/pip/requests-2.32.4
netmindz Jun 14, 2025
65f2ced
Bump brace-expansion from 1.1.11 to 1.1.12
dependabot[bot] Jun 14, 2025
201d049
Update pr-merge.yaml
netmindz Jun 14, 2025
f442d58
Update pr-merge.yaml
netmindz Jun 14, 2025
80c40f6
Update pr-merge.yaml
netmindz Jun 14, 2025
a50b4f5
Merge pull request #4731 from wled/dependabot/npm_and_yarn/brace-expa…
netmindz Jun 14, 2025
7835550
Merge branch 'main' into usermod-libs-matrix
netmindz Jun 14, 2025
728b1e8
Merge pull request #4723 from DedeHai/Flow_Stripe_FX_fix
netmindz Jun 14, 2025
3a413a5
Merge pull request #4713 from willmmiles/parallel-i2s-ui-missing
willmmiles Jun 14, 2025
65a79d4
Fix build_flags and lib_deps for usermods#
netmindz Jun 14, 2025
b0dd969
Add missing ${esp32_idf_V4.lib_deps} to usermods lib_deps
netmindz Jun 14, 2025
42bf8fb
Update pr-merge.yaml
netmindz Jun 14, 2025
d2d5c42
Merge pull request #4690 from Arcitec/ar-agc-control
netmindz Jun 14, 2025
a6f5080
Update usermods/platformio_override.usermods.ini
netmindz Jun 15, 2025
e97723d
Use existing board envs for usermod build
willmmiles Jun 16, 2025
1c4141a
Exclude PWM_fan
netmindz Jun 28, 2025
7cc5c87
Fixing Si7021_MQTT_HA
netmindz Jun 28, 2025
b187f94
use extreme_partitions
netmindz Jun 28, 2025
5163fbf
Merge branch 'main' into usermod-libs-matrix
netmindz Jun 28, 2025
a2e9e2b
Update buzzer to default to 21 if GPIO 32 is not defined
netmindz Jun 28, 2025
b1ed99d
Disable BME68X_v2
netmindz Jun 28, 2025
0ba0587
Exclude BME68X_v2
netmindz Jun 28, 2025
9099b13
Fix deps for Si7021_MQTT_HA
netmindz Jun 28, 2025
db55fec
Merge branch 'usermod-libs-matrix' of github.com:netmindz/WLED into u…
netmindz Jun 28, 2025
e227d01
Exclude pixels_dice_tray until we can limit what the CI builds, respe…
netmindz Jun 28, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:


build:
name: Build Enviornments
name: Build Environments
runs-on: ubuntu-latest
needs: get_default_envs
strategy:
Expand Down
27 changes: 22 additions & 5 deletions .github/workflows/pr-merge.yaml
Original file line number Diff line number Diff line change
@@ -1,16 +1,33 @@
name: Notify Discord on PR Merge
on:
workflow_dispatch:
pull_request:
types: [closed]

jobs:
notify:
runs-on: ubuntu-latest
steps:
- name: Send Discord notification
shell: bash
- name: Get User Permission
id: checkAccess
uses: actions-cool/check-user-permission@v2
with:
require: write
username: ${{ github.triggering_actor }}
env:
DISCORD_WEBHOOK_BETA_TESTERS: ${{ secrets.DISCORD_WEBHOOK_BETA_TESTERS }}
if: github.event.pull_request.merged == true
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Check User Permission
if: steps.checkAccess.outputs.require-result == 'false'
run: |
echo "${{ github.triggering_actor }} does not have permissions on this repo."
echo "Current permission level is ${{ steps.checkAccess.outputs.user-permission }}"
echo "Job originally triggered by ${{ github.actor }}"
exit 1
- name: Checkout code
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha }} # This is dangerous without the first access check
- name: Send Discord notification
# if: github.event.pull_request.merged == true
run: |
curl -H "Content-Type: application/json" -d '{"content": "Pull Request #{{ github.event.pull_request.number }} merged by {{ github.actor }}"}' $DISCORD_WEBHOOK_BETA_TESTERS
curl -H "Content-Type: application/json" -d '{"content": "Pull Request ${{ github.event.pull_request.number }} merged by ${{ github.actor }}"}' ${{ secrets.DISCORD_WEBHOOK_BETA_TESTERS }}
71 changes: 71 additions & 0 deletions .github/workflows/usermods.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: Usermod CI

on:
push:
paths:
- usermods/**
- .github/workflows/usermods.yml

jobs:

get_usermod_envs:
name: Gather Usermods
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
cache: 'pip'
- name: Install PlatformIO
run: pip install -r requirements.txt
- name: Get default environments
id: envs
run: |
echo "usermods=$(find usermods/ -name library.json | xargs dirname | xargs -n 1 basename | jq -R | grep -v PWM_fan | grep -v BME68X_v2| grep -v pixels_dice_tray | jq --slurp -c)" >> $GITHUB_OUTPUT
outputs:
usermods: ${{ steps.envs.outputs.usermods }}


build:
name: Build Enviornments
runs-on: ubuntu-latest
needs: get_usermod_envs
strategy:
fail-fast: false
matrix:
usermod: ${{ fromJSON(needs.get_usermod_envs.outputs.usermods) }}
environment: [usermods_esp32, usermods_esp32c3, usermods_esp32s2, usermods_esp32s3]
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- run: npm ci
- name: Cache PlatformIO
uses: actions/cache@v4
with:
path: |
~/.platformio/.cache
~/.buildcache
build_output
key: pio-${{ runner.os }}-${{ matrix.environment }}-${{ hashFiles('platformio.ini', 'pio-scripts/output_bins.py') }}-${{ hashFiles('wled00/**', 'usermods/**') }}
restore-keys: pio-${{ runner.os }}-${{ matrix.environment }}-${{ hashFiles('platformio.ini', 'pio-scripts/output_bins.py') }}-
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
cache: 'pip'
- name: Install PlatformIO
run: pip install -r requirements.txt
- name: Add usermods environment
run: |
cp -v usermods/platformio_override.usermods.ini platformio_override.ini
echo >> platformio_override.ini
echo "custom_usermods = ${{ matrix.usermod }}" >> platformio_override.ini
cat platformio_override.ini
- name: Build firmware
run: pio run -e ${{ matrix.environment }}
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

98 changes: 43 additions & 55 deletions pio-scripts/load_usermods.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
Import('env')
import os.path
from collections import deque
from pathlib import Path # For OS-agnostic path manipulation
from platformio.package.manager.library import LibraryPackageManager
from click import secho
from SCons.Script import Exit
from platformio.builder.tools.piolib import LibBuilderBase

usermod_dir = Path(env["PROJECT_DIR"]) / "usermods"
all_usermods = [f for f in usermod_dir.iterdir() if f.is_dir() and f.joinpath('library.json').exists()]
usermod_dir = Path(env["PROJECT_DIR"]).resolve() / "usermods"

if env['PIOENV'] == "usermods":
# Add all usermods
env.GetProjectConfig().set(f"env:usermods", 'custom_usermods', " ".join([f.name for f in all_usermods]))

def find_usermod(mod: str):
# Utility functions
def find_usermod(mod: str) -> Path:
"""Locate this library in the usermods folder.
We do this to avoid needing to rename a bunch of folders;
this could be removed later
Expand All @@ -22,51 +19,36 @@ def find_usermod(mod: str):
return mp
mp = usermod_dir / f"{mod}_v2"
if mp.exists():
return mp
return mp
mp = usermod_dir / f"usermod_v2_{mod}"
if mp.exists():
return mp
raise RuntimeError(f"Couldn't locate module {mod} in usermods directory!")

def is_wled_module(dep: LibBuilderBase) -> bool:
"""Returns true if the specified library is a wled module
"""
return usermod_dir in Path(dep.src_dir).parents or str(dep.name).startswith("wled-")

## Script starts here
# Process usermod option
usermods = env.GetProjectOption("custom_usermods","")

# Handle "all usermods" case
if usermods == '*':
usermods = [f.name for f in usermod_dir.iterdir() if f.is_dir() and f.joinpath('library.json').exists()]
else:
usermods = usermods.split()

if usermods:
# Inject usermods in to project lib_deps
proj = env.GetProjectConfig()
deps = env.GetProjectOption('lib_deps')
src_dir = proj.get("platformio", "src_dir")
src_dir = src_dir.replace('\\','/')
mod_paths = {mod: find_usermod(mod) for mod in usermods.split()}
usermods = [f"{mod} = symlink://{path}" for mod, path in mod_paths.items()]
proj.set("env:" + env['PIOENV'], 'lib_deps', deps + usermods)
# Force usermods to be installed in to the environment build state before the LDF runs
# Otherwise we won't be able to see them until it's too late to change their paths for LDF
# Logic is largely borrowed from PlaformIO internals
not_found_specs = []
for spec in usermods:
found = False
for storage_dir in env.GetLibSourceDirs():
#print(f"Checking {storage_dir} for {spec}")
lm = LibraryPackageManager(storage_dir)
if lm.get_package(spec):
#print("Found!")
found = True
break
if not found:
#print("Missing!")
not_found_specs.append(spec)
if not_found_specs:
lm = LibraryPackageManager(
env.subst(os.path.join("$PROJECT_LIBDEPS_DIR", "$PIOENV"))
)
for spec in not_found_specs:
#print(f"LU: forcing install of {spec}")
lm.install(spec)

symlinks = [f"symlink://{find_usermod(mod).resolve()}" for mod in usermods]
env.GetProjectConfig().set("env:" + env['PIOENV'], 'lib_deps', env.GetProjectOption('lib_deps') + symlinks)

# Utility function for assembling usermod include paths
def cached_add_includes(dep, dep_cache: set, includes: deque):
""" Add dep's include paths to includes if it's not in the cache """
if dep not in dep_cache:
if dep not in dep_cache:
dep_cache.add(dep)
for include in dep.get_include_dirs():
if include not in includes:
Expand All @@ -82,13 +64,6 @@ def cached_add_includes(dep, dep_cache: set, includes: deque):

# Our new wrapper
def wrapped_ConfigureProjectLibBuilder(xenv):
# Update usermod properties
# Set libArchive before build actions are added
for um in (um for um in xenv.GetLibBuilders() if usermod_dir in Path(um.src_dir).parents):
build = um._manifest.get("build", {})
build["libArchive"] = False
um._manifest["build"] = build

# Call the wrapped function
result = old_ConfigureProjectLibBuilder.clone(xenv)()

Expand All @@ -102,12 +77,25 @@ def wrapped_ConfigureProjectLibBuilder(xenv):
for dep in result.depbuilders:
cached_add_includes(dep, processed_deps, extra_include_dirs)

for um in [dep for dep in result.depbuilders if usermod_dir in Path(dep.src_dir).parents]:
# Add the wled folder to the include path
um.env.PrependUnique(CPPPATH=wled_dir)
# Add WLED's own dependencies
for dir in extra_include_dirs:
um.env.PrependUnique(CPPPATH=dir)
broken_usermods = []
for dep in result.depbuilders:
if is_wled_module(dep):
# Add the wled folder to the include path
dep.env.PrependUnique(CPPPATH=str(wled_dir))
# Add WLED's own dependencies
for dir in extra_include_dirs:
dep.env.PrependUnique(CPPPATH=str(dir))
# Enforce that libArchive is not set; we must link them directly to the executable
if dep.lib_archive:
broken_usermods.append(dep)

if broken_usermods:
broken_usermods = [usermod.name for usermod in broken_usermods]
secho(
f"ERROR: libArchive=false is missing on usermod(s) {' '.join(broken_usermods)} -- modules will not compile in correctly",
fg="red",
err=True)
Exit(1)

return result

Expand Down
92 changes: 92 additions & 0 deletions pio-scripts/validate_modules.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import re
from pathlib import Path # For OS-agnostic path manipulation
from typing import Iterable
from click import secho
from SCons.Script import Action, Exit
from platformio.builder.tools.piolib import LibBuilderBase


def is_wled_module(env, dep: LibBuilderBase) -> bool:
"""Returns true if the specified library is a wled module
"""
usermod_dir = Path(env["PROJECT_DIR"]).resolve() / "usermods"
return usermod_dir in Path(dep.src_dir).parents or str(dep.name).startswith("wled-")


def read_lines(p: Path):
""" Read in the contents of a file for analysis """
with p.open("r", encoding="utf-8", errors="ignore") as f:
return f.readlines()


def check_map_file_objects(map_file: list[str], dirs: Iterable[str]) -> set[str]:
""" Identify which dirs contributed to the final build

Returns the (sub)set of dirs that are found in the output ELF
"""
# Pattern to match symbols in object directories
# Join directories into alternation
usermod_dir_regex = "|".join([re.escape(dir) for dir in dirs])
# Matches nonzero address, any size, and any path in a matching directory
object_path_regex = re.compile(r"0x0*[1-9a-f][0-9a-f]*\s+0x[0-9a-f]+\s+\S+[/\\](" + usermod_dir_regex + r")[/\\]\S+\.o")

found = set()
for line in map_file:
matches = object_path_regex.findall(line)
for m in matches:
found.add(m)
return found


def count_usermod_objects(map_file: list[str]) -> int:
""" Returns the number of usermod objects in the usermod list """
# Count the number of entries in the usermods table section
return len([x for x in map_file if ".dtors.tbl.usermods.1" in x])


def validate_map_file(source, target, env):
""" Validate that all modules appear in the output build """
build_dir = Path(env.subst("$BUILD_DIR"))
map_file_path = build_dir / env.subst("${PROGNAME}.map")

if not map_file_path.exists():
secho(f"ERROR: Map file not found: {map_file_path}", fg="red", err=True)
Exit(1)

# Identify the WLED module source directories
module_lib_builders = [builder for builder in env.GetLibBuilders() if is_wled_module(env, builder)]

if env.GetProjectOption("custom_usermods","") == "*":
# All usermods build; filter non-platform-OK modules
module_lib_builders = [builder for builder in module_lib_builders if env.IsCompatibleLibBuilder(builder)]
else:
incompatible_builders = [builder for builder in module_lib_builders if not env.IsCompatibleLibBuilder(builder)]
if incompatible_builders:
secho(
f"ERROR: Modules {[b.name for b in incompatible_builders]} are not compatible with this platform!",
fg="red",
err=True)
Exit(1)

# Extract the values we care about
modules = {Path(builder.build_dir).name: builder.name for builder in module_lib_builders}
secho(f"INFO: {len(modules)} libraries linked as WLED optional/user modules")

# Now parse the map file
map_file_contents = read_lines(map_file_path)
usermod_object_count = count_usermod_objects(map_file_contents)
secho(f"INFO: {usermod_object_count} usermod object entries")

confirmed_modules = check_map_file_objects(map_file_contents, modules.keys())
missing_modules = [modname for mdir, modname in modules.items() if mdir not in confirmed_modules]
if missing_modules:
secho(
f"ERROR: No object files from {missing_modules} found in linked output!",
fg="red",
err=True)
Exit(1)
return None

Import("env")
env.Append(LINKFLAGS=[env.subst("-Wl,--Map=${BUILD_DIR}/${PROGNAME}.map")])
env.AddPostAction("$BUILD_DIR/${PROGNAME}.elf", Action(validate_map_file, cmdstr='Checking linked optional modules (usermods) in map file'))
3 changes: 2 additions & 1 deletion platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ extra_scripts =
pre:pio-scripts/user_config_copy.py
pre:pio-scripts/load_usermods.py
pre:pio-scripts/build_ui.py
post:pio-scripts/validate_modules.py ;; double-check the build output usermods
; post:pio-scripts/obj-dump.py ;; convenience script to create a disassembly dump of the firmware (hardcore debugging)

# ------------------------------------------------------------------------------
Expand Down Expand Up @@ -659,5 +660,5 @@ build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_
lib_deps = ${esp32_idf_V4.lib_deps}
monitor_filters = esp32_exception_decoder
board_build.flash_mode = dio
; custom_usermods = *every folder with library.json* -- injected by pio-scripts/load_usermods.py
custom_usermods = * ; Expands to all usermods in usermods folder
board_build.partitions = ${esp32.extreme_partitions} ; We're gonna need a bigger boat
2 changes: 1 addition & 1 deletion platformio_override.sample.ini
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ lib_deps = ${esp8266.lib_deps}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags} ${esp8266.build_flags}
;
; *** To use the below defines/overrides, copy and paste each onto it's own line just below build_flags in the section above.
; *** To use the below defines/overrides, copy and paste each onto its own line just below build_flags in the section above.
;
; Set a release name that may be used to distinguish required binary for flashing
; -D WLED_RELEASE_NAME=\"ESP32_MULTI_USREMODS\"
Expand Down
Loading