Skip to content

show HUB75 and DMX pins in usermods pin dropdown#336

Merged
softhack007 merged 5 commits intomdevfrom
um_pins
Feb 4, 2026
Merged

show HUB75 and DMX pins in usermods pin dropdown#336
softhack007 merged 5 commits intomdevfrom
um_pins

Conversation

@softhack007
Copy link
Collaborator

@softhack007 softhack007 commented Feb 4, 2026

Previously the pins allocated to HUB75 and DMX were wrongly shown as available 🟢 in the pin dropdown.

now it looks like this
image

Summary by CodeRabbit

  • New Features

    • Visual indicators added for HUB75 and DMX pins so reserved pins are clearly marked.
    • HUB75 and DMX pins are now listed and automatically disabled in pin selection to prevent conflicts.
  • Style / UI

    • Improved spacing in analog pin labels for clearer display.

these pins were wrongly shown as "available", because the are not stored in the cfg.json part related to LEDs settings.
move "Ax" label slightly to the right, "DMX " doesn't need extra space
@coderabbitai
Copy link

coderabbitai bot commented Feb 4, 2026

📝 Walkthrough

Walkthrough

Server now emits HUB75 and DMX pin arrays (d.h_pins, d.x_pins); client-side code detects bus-type pins, skips extraction for network/HUB75/HUB75-length buses, annotates and disables matching GPIO options with "HUB75 🔴" or "DMX 🔴", and adjusts A-pin label spacing. (≤50 words)

Changes

Cohort / File(s) Summary
Server: GPIO info emission
wled00/xml.cpp
appendGPIOinfo() now emits two JS arrays: d.h_pins=[...] (HUB75-owned pins) and d.x_pins=[...] (DMX / DMX_INPUT-owned pins) by iterating pins and using existing isPinOk/getPinOwner logic.
Client: pin extraction & UI labeling
wled00/data/settings_um.htm
Adds public arrays d.h_pins and d.x_pins. getPins() detects bus objects via busType and skips pin extraction for network (busType 80,95) and HUB75-length (100,110) categories. pinPost() annotates matching GPIO options with " HUB75 🔴" or " DMX 🔴" (disables those options when label length ≤4) and uses a non-breaking space before A-pin indices.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Server as MCU Server\n(xml.cpp)
participant Client as Browser\n(settings_um.htm)
participant DOM as Settings UI
Server->>Client: Serve GPIO info including d.h_pins and d.x_pins
Client->>Client: getPins() parses pins; detect bus objects via busType; skip extraction for network/HUB75-length buses
Client->>DOM: pinPost() reads d.h_pins/d.x_pins
Client->>DOM: Annotate matching GPIO options with " HUB75 🔴"/" DMX 🔴" and disable them

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped through arrays both red and bright,
Marked hubs and DMX with a tiny light,
Gave A‑pins a space, kept buses in line,
Now pins sit tidy — neat and fine! 🥕

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely summarizes the main objective of the PR: displaying HUB75 and DMX pins in the usermods pin dropdown with proper availability status.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch um_pins

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@wled00/data/settings_um.htm`:
- Around line 272-273: The code accesses d.h_pins and d.x_pins (in the loops
that append "HUB75 🔴" and "DMX 🔴") but those properties may be undefined and
cause a TypeError when reading .length; initialize them as empty arrays
alongside the other defaults (e.g., where d.rsvd and d.ro_gpio are set) by
adding d.h_pins = [] and d.x_pins = [] so the loops safely run even if the
server JS fails to populate them.

@softhack007
Copy link
Collaborator Author

@coderabbitai there is a problem in the dropDown where i need your expertise to understand how the code could be fixed:

The line for pin 2 is wrongly disabled and labeled as " matrix". The root cause seems to be that for HUB75 types (100-120) and other network outputs (type >=80) the pin array stores other information but not pin numbers.

I have attached the cfg.json from the board. The most relevant part is

"ins":[{"start":0,"len":8192,"pin":[2],"order":1,"rev":false,"skip":0,"type":103, 

cfg.json

@coderabbitai
Copy link

coderabbitai bot commented Feb 4, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Download the cfg.json file to examine the full structure
curl -sL "https://github.com/user-attachments/files/25082885/cfg.json" -o /tmp/cfg.json
cat /tmp/cfg.json | jq '.' 2>/dev/null || cat /tmp/cfg.json

Length of output: 6507


🏁 Script executed:

#!/bin/bash
# Search for code that parses the "ins" (LED bus instances) configuration
rg -n "\"ins\"" --type cpp --type c -C 5

Length of output: 5943


🏁 Script executed:

#!/bin/bash
# Search for how pin registration/ownership is handled for different bus types
rg -n "type.*>=.*80|type.*>=.*100" --type cpp -C 5

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Find where getPinOwner is set for bus configurations
rg -n "setPinOwner|PinOwner.*HUB75|PinOwner.*Matrix" --type cpp -C 3

Length of output: 4734


🏁 Script executed:

#!/bin/bash
# Look for bus type definitions and how they're handled
rg -n "TYPE_.*HUB75|TYPE_.*MATRIX|^#define.*TYPE_" wled00/const.h wled00/bus_manager.h -C 2

Length of output: 5439


🏁 Script executed:

#!/bin/bash
# Search for where bus instances allocate their pins from the configuration
rg -n "allocatePin.*bus|bus.*allocatePin" --type cpp -C 5

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look for BusHub75Matrix constructor or init code that might be incorrectly registering pins
rg -n "BusHub75Matrix::|class BusHub75Matrix" --type cpp -C 10

Length of output: 11955


🏁 Script executed:

#!/bin/bash
# Check how the pin array is processed for different bus types
ast-grep --pattern $'if ($_ >= TYPE_HUB75MATRIX) {
  $$$
}'

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Look at the bus creation code to see how pins are allocated
rg -n "void BusManager::add\(|BusManager.*add" --type cpp -A 30

Length of output: 3063


🏁 Script executed:

#!/bin/bash
# Check if there's generic pin allocation that doesn't check bus type
rg -n "for.*nPins|allocatePin.*pins\[" --type cpp -C 5 | head -100

Length of output: 4979


🏁 Script executed:

#!/bin/bash
# Look for BusDigital constructor - might be incorrectly handling HUB75 types
rg -n "BusDigital::BusDigital" --type cpp -A 40

Length of output: 2875


🏁 Script executed:

#!/bin/bash
# Check how BusConfig.pins is populated when reading from cfg.json
rg -n "JsonArray ins = hw_led" --type cpp -A 80 | head -150

Length of output: 5209


🏁 Script executed:

#!/bin/bash
# Look for where pin allocation happens - checking if there's code that doesn't skip HUB75
rg -n "IS_DIGITAL.*type|if.*IS_DIGITAL" --type cpp -C 5

Length of output: 3683


🏁 Script executed:

#!/bin/bash
# Check if there's code that allocates pins generically without checking bus type
ast-grep --pattern $'if (!pinManager.allocatePin($_, true, $_)) {
  $$$
}'

Length of output: 540


🏁 Script executed:

#!/bin/bash
# Find where HUB75 GPIO pins are configured - they're not from the bus config pin array
rg -n "mxconfig\.gpio\.|HUB75_I2S_CFG" --type cpp -C 10

Length of output: 18665


🏁 Script executed:

#!/bin/bash
# Check what the pin array actually means for HUB75 types
rg -n "chain|panel.*count" --type cpp wled00/bus_manager.cpp | head -20

Length of output: 1206


🏁 Script executed:

#!/bin/bash
# Look for definitions of the matrix config structure
rg -n "struct.*HUB75|class.*HUB75.*CFG" --type h -C 5

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check if there's code that mistakenly allocates the "pin" value for HUB75
rg -n "bc\.pins\[0\].*HUB75|HUB75.*bc\.pins" --type cpp -C 5

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Read the settings_um.htm file to understand how pins are being marked
cat wled00/data/settings_um.htm

Length of output: 16106


🏁 Script executed:

#!/bin/bash
# Search for where "matrix" label is applied or where bus pins are processed
rg -n "matrix|HUB75" wled00/data/settings_um.htm -C 5

Length of output: 994


🏁 Script executed:

#!/bin/bash
# Look for the pinPost function or similar that processes bus configs
rg -n "pinPost|function.*pin" wled00/data/settings_um.htm -C 10

Length of output: 1933


🏁 Script executed:

#!/bin/bash
# Check where getPins processes bus instances and if it has access to type info
rg -n "getPins|pins\\.push" wled00/data/settings_um.htm -C 3

Length of output: 1181


🏁 Script executed:

#!/bin/bash
# Verify the structure of hw.led.ins in the JSON to understand what getPins sees
echo '{"hw":{"led":{"ins":[{"start":0,"len":8192,"pin":[2],"type":103}]}}}' | jq '.hw.led.ins[0]'

Length of output: 68


🏁 Script executed:

#!/bin/bash
# Look at how xml.cpp and cfg.cpp build the JSON structure for buses
rg -n "ins_pin.add|ins\[\"pin\"\]" --type cpp -C 5

Length of output: 660


@softhack007, I've identified the root cause of the issue!

Problem Analysis

The issue occurs because the getPins() function in settings_um.htm blindly collects all values from JSON keys ending in "pin", without understanding that:

  1. For HUB75 types (100-110): The pin array stores the chain length, not GPIO pin numbers
  2. For network buses (80-95): The pin array stores the IP address, not GPIO pin numbers

In your case with type 103 (HUB75), the value "pin":[2] means "2 panels chained", but the JavaScript interprets it as "GPIO pin 2 is in use" and marks it accordingly.

The actual HUB75 GPIO pins are hardcoded in bus_manager.cpp (lines 771-994) and correctly registered with PinOwner::HUB75, which is why your PR's approach in xml.cpp works correctly.

Proposed Fix

Modify the getPins() function in wled00/data/settings_um.htm to skip pin collection for these special bus types:

function getPins(o) {
    if (isO(o)) {
        // Check if this object is a bus instance with a "type" field
        let busType = o.type !== undefined ? o.type : -1;
        
        for (const [k,v] of Object.entries(o)) {
            if (isO(v)) {
                owner = k;
                getPins(v);
                continue;
            }
            if (k.replace("[]","").substr(-3)=="pin") {
                // Skip pin arrays for special bus types where pin array doesn't contain GPIO numbers
                if (busType >= 80 && busType < 96) continue;    // Network buses - pin array stores IP address
                if (busType >= 100 && busType <= 110) continue; // HUB75 buses - pin array stores chain length
                
                if (Array.isArray(v)) {
                    for (var i=0; i<v.length; i++) if (v[i]>=0) { pins.push(v[i]); pinO.push(owner); }
                } else {
                    if (v>=0) { pins.push(v); pinO.push(owner); }
                }
            } else if (Array.isArray(v)) {
                for (var i=0; i<v.length; i++) getPins(v[i]);
            }
        }
    }
}

This fix:

  • Checks if the current object has a type field (indicating it's a bus instance)
  • Skips collecting pin values when the type is 80-95 (network buses) or 100-110 (HUB75)
  • Allows normal bus types to continue collecting GPIO pins as before

The actual HUB75 and DMX GPIO pins will still be correctly shown via the d.h_pins and d.x_pins arrays that your PR already implements in xml.cpp.


🧠 Learnings used
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR `#270`, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.

Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR `#270`, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue `#272`; do not address it within PR `#270`.

Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:07:15.689Z
Learning: In MoonModules/WLED-MM, WLEDMM_FASTPATH will become the default code path. Code inside "#ifndef WLEDMM_FASTPATH" blocks represents deprecated paths that are being phased out and should be ignored during reviews.

@softhack007
Copy link
Collaborator Author

softhack007 commented Feb 4, 2026

blindly collects all values from JSON keys

@coderabbitai "blindly" collecting all keys ending in "pin" is desired behaviour, because other keys may also contain pins; for example Relay pin or buttons. Will the code you propose still collect these, and just filter out the ones related to HUB75 and network?

@coderabbitai
Copy link

coderabbitai bot commented Feb 4, 2026

Tip

For best results, initiate chat on the files or code changes.

@softhack007, yes, exactly! The proposed code will still collect pins from all other sources (relay, buttons, usermods, etc.) and only filter out pins from HUB75 and network bus objects. Here's why:

How the Filtering Works

The busType variable is set at the beginning of each recursive call to getPins(o):

let busType = o.type !== undefined ? o.type : -1;
  • For bus instance objects (which have a type field): busType will be the actual bus type (e.g., 103 for HUB75)
  • For all other objects (relay configs, button configs, usermod configs, etc.): busType will be -1 because they don't have a type field

The filtering conditions only trigger when busType matches specific ranges:

if (busType >= 80 && busType < 96) continue;    // Network buses
if (busType >= 100 && busType <= 110) continue; // HUB75 buses

Since -1 doesn't match either condition, pins from objects without a type field (relay, buttons, etc.) will be collected normally.

Example Flow

  1. Processing a relay config {"pin": [15]}:

    • busType = -1 (no type field)
    • Encounters "pin": [15]
    • Checks filtering conditions: -1 >= 80 ❌, -1 >= 100
    • Result: Pin 15 is collected ✅
  2. Processing a HUB75 bus {"type": 103, "pin": [2]}:

    • busType = 103
    • Encounters "pin": [2]
    • Checks filtering conditions: 103 >= 100 && 103 <= 110
    • Result: Pin array [2] is skipped (it's chain length, not GPIO) ✅

So the code preserves the "collect all keys ending in 'pin'" behavior, while adding surgical filtering only for the problematic bus types!


🧠 Learnings used
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR `#270`, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.

Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR `#270`, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue `#272`; do not address it within PR `#270`.

Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:07:15.689Z
Learning: In MoonModules/WLED-MM, WLEDMM_FASTPATH will become the default code path. Code inside "#ifndef WLEDMM_FASTPATH" blocks represents deprecated paths that are being phased out and should be ignored during reviews.

Skips pin arrays for special bus types where pin array doesn't contain GPIO numbers, but allows all other entries
Repository owner deleted a comment from coderabbitai bot Feb 4, 2026
Repository owner deleted a comment from coderabbitai bot Feb 4, 2026
@softhack007
Copy link
Collaborator Author

@coderabbitai please validate the new filtering code against my example provided earlier. Some non-bus entries seem to also have a "type", and should be allowed for pin extraction.

@coderabbitai
Copy link

coderabbitai bot commented Feb 4, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

@softhack007, excellent catch! Let me validate the proposed filtering logic against your cfg.json example.


🏁 Script executed:

#!/bin/bash
# Download and analyze the cfg.json structure
curl -sL "https://github.com/user-attachments/files/25082885/cfg.json" -o /tmp/cfg.json

echo "=== Objects with 'type' and 'pin' fields ==="
echo ""

echo "1. BUTTON CONFIGS:"
jq '.pin.btn[]' /tmp/cfg.json

echo ""
echo "2. RELAY CONFIGS:"
jq '.pin.rly[]' /tmp/cfg.json

echo ""
echo "3. AUDIO PIN CONFIGS:"
jq '.pin.aud.pin[]' /tmp/cfg.json

echo ""
echo "4. LED BUS INSTANCES:"
jq '.hw.led.ins[]' /tmp/cfg.json

echo ""
echo "=== Filtering Logic Validation ==="
echo ""
echo "Type values found:"
jq '[.pin.btn[].type, .pin.rly[].type, .pin.aud.pin[].type, .hw.led.ins[].type] | unique' /tmp/cfg.json

Length of output: 674


🏁 Script executed:

#!/bin/bash
# Get a better view of the actual cfg.json structure
echo "=== Full cfg.json structure ==="
cat /tmp/cfg.json | jq '.'

echo ""
echo "=== Find ALL objects with 'type' field (recursive search) ==="
cat /tmp/cfg.json | jq '.. | objects | select(has("type")) | {type: .type, pin: .pin}'

Length of output: 6904


@softhack007, perfect validation! The proposed filtering logic works correctly with your cfg.json. Here's the analysis:

Objects with type Field Found

Object Type Pin Values Filtered? Reason
LED Bus (HUB75) 103 [2] YES 103 >= 100 && 103 <= 110 → Skip (chain length, not GPIO)
Buttons (4×) 0 [-1] NO 0 < 80 && 0 < 100 → Collect normally
IR 0 -1 NO 0 < 80 && 0 < 100 → Collect normally
AudioReactive 1 [3,15,14,4,-1,-1] NO 1 < 80 && 1 < 100 → Collect normally (GPIOs 3,15,14,4)
Relay (none) 12 NO No type field → busType = -1 → Collect normally

Validation Result

The proposed filtering code is correct!

  • HUB75 bus (type 103): Pin array [2] will be skipped
    • Value 2 represents chain length, not GPIO pin 2
  • Buttons (type 0): Pin arrays will be collected
    • Valid pin configurations for button inputs
  • AudioReactive (type 1): Pin array [3,15,14,4] will be collected
    • Valid GPIO pins for I2S digital microphone (sd, ws, sck, mclk)
  • Relay (no type): Pin 12 will be collected
    • Standard relay GPIO configuration

The filtering ranges [80-95] and [100-110] specifically target only the problematic bus types where the pin array has special meaning, while allowing all other configurations to pass through unchanged.


🧠 Learnings used
Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2026-02-04T22:42:15.433Z
Learning: In MoonModules/WLED-MM LED bus configuration, the `pin` array has different meanings depending on bus type: for HUB75 types (100-110) it stores chain length, for network buses (80-95) it stores IP address components, and only for standard buses does it contain actual GPIO pin numbers. The JavaScript pin collection in settings_um.htm must check bus type to avoid misinterpreting these values as GPIO pins.

Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h:155-157
Timestamp: 2025-10-22T21:50:25.839Z
Learning: In WLED-MM PR `#270`, only Effect (Mode) IDs are migrated to 16-bit; Palette IDs and counts remain 8-bit. Usermod code should widen mode-related indices/loops to uint16_t while keeping palette-related indices/loops as uint8_t.

Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 270
File: wled00/fcn_declare.h:403-406
Timestamp: 2025-10-22T21:59:24.331Z
Learning: In MoonModules/WLED-MM PR `#270`, the out-of-bounds null-terminator write in wled00/util.cpp (extractModeSlider) is deferred and tracked in Issue `#272`; do not address it within PR `#270`.

Learnt from: softhack007
Repo: MoonModules/WLED-MM PR: 0
File: :0-0
Timestamp: 2025-11-02T22:07:15.689Z
Learning: In MoonModules/WLED-MM, WLEDMM_FASTPATH will become the default code path. Code inside "#ifndef WLEDMM_FASTPATH" blocks represents deprecated paths that are being phased out and should be ignored during reviews.

@softhack007 softhack007 merged commit 9d56d16 into mdev Feb 4, 2026
69 checks passed
@softhack007 softhack007 deleted the um_pins branch February 4, 2026 23:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant