Skip to content

Extended Wordclock#5586

Open
Zippochonda wants to merge 13 commits into
wled:mainfrom
Zippochonda:main
Open

Extended Wordclock#5586
Zippochonda wants to merge 13 commits into
wled:mainfrom
Zippochonda:main

Conversation

@Zippochonda
Copy link
Copy Markdown

@Zippochonda Zippochonda commented May 9, 2026

Extend the wordclock to 11X11 LEDs

Summary by CodeRabbit

  • New Features

    • Added 11x11 grid support and a meander-wiring toggle for an alternate wiring pattern
    • Improved wiring-mode selection and persistence for wiring-related settings
  • Documentation

    • Updated README with 11x11 grid details, meander wiring explanation, and corrected label
    • Added Home Assistant configuration examples (REST command, sensor, and template switch)

Review Change Stack

Added a Link to the source of the SVG
Mapping wrong at 11x11 ---> eins
Added map for a 2d Matrix in Meanderwiring
Added meander wiring for a 2d Matrix 11x11
Add the Status of the usermod in JSON, so that you can switch off and on the Usermod remotely for Example with Home Assistant
Added the integration into Homeassist
Added HA Configuration
Added a new configuration option for meander wiring and updated documentation to reflect changes.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 9, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 27f7ac09-e00a-42f3-a2da-a41b511b2e49

📥 Commits

Reviewing files that changed from the base of the PR and between fb2ca04 and f7146b1.

📒 Files selected for processing (1)
  • usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp
🚧 Files skipped from review as they are similar to previous changes (1)
  • usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp

Walkthrough

The Word Clock usermod now supports 11x11 grid wiring modes alongside existing configurations. New LED mask lookup tables enable four wiring combinations (normal, meander, 11x11, 11x11-meander). Display logic branches on configuration flags to select appropriate tables. Config serialization restructures state persistence to use nested JSON objects with meanderWiring and wiring11x11 keys. Documentation and Home Assistant integration examples are added.

Changes

Word Clock 11x11 Grid & Meander Wiring

Layer / File(s) Summary
Configuration & Constants
usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp
New eleven flag and mask-size macros for 11x11 normal/meander variants added to configuration.
LED Mask Lookup Tables
usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp
Four new lookup tables (maskMinutes11, maskMinutes11Mea, maskHours11, maskHours11Mea) define LED positions for 11x11 wiring; minute mask updated for normal wiring early ranges.
Minute Dot Indices
usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp
Minute-dot LED indices changed to {112, 114, 116, 118} used by setSingleMinuteDots().
Display Logic
usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp
setHours() and setMinutes() branch on meander and eleven flags to select appropriate mask table.
State & Config Persistence
usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp
JSON state wraps active field in nested WordClockUsermod object; config file stores meanderWiring and wiring11x11 under WordClockUsermod.
Usermod Registration & Documentation
usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp, usermods/usermod_v2_word_clock/readme.md
Registration switched to REGISTER_USERMOD(usermod_v2_word_clock); macro form. README: corrected displayItIs label, added meanderwiring option, 11x11 Grid subsection, and a Home Assistant Configuration section with REST command/sensor/template switch examples.

🎯 3 (Moderate) | ⏱️ ~22 minutes

Suggested reviewers

  • netmindz
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Extended Wordclock' is partially related to the changeset. It correctly identifies that the wordclock is being extended, but does not clarify the main addition (11×11 grid support), making it somewhat vague about the specific enhancement. Consider using a more specific title such as 'Add 11×11 grid support to wordclock usermod' or 'Extend wordclock with alternate wiring and 11×11 grid mode' to better convey the primary changes.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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
Copy Markdown
Contributor

@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: 3

🧹 Nitpick comments (2)
usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp (2)

459-463: ⚡ Quick win

Move repeated JSON keys to PROGMEM constants and avoid RAM string literals.

Line 460/471/474 adds repeated raw key strings ("WordClockUsermod", "active"). In usermods, these should be shared static const char[] PROGMEM keys (used via FPSTR/F) to reduce RAM pressure.

Suggested change
+    static const char kWordClockUsermod[] PROGMEM;
+    static const char kActive[] PROGMEM;
...
-      JsonObject usermodJson = root.createNestedObject("WordClockUsermod");
-      usermodJson["active"] = usermodActive;
+      JsonObject usermodJson = root.createNestedObject(FPSTR(kWordClockUsermod));
+      usermodJson[FPSTR(kActive)] = usermodActive;
...
-      JsonObject usermodJson = root["WordClockUsermod"];
+      JsonObject usermodJson = root[FPSTR(kWordClockUsermod)];
...
-       if (usermodJson.containsKey("active")) {
-        usermodActive = usermodJson["active"].as<bool>();
+       if (usermodJson.containsKey(FPSTR(kActive))) {
+        usermodActive = usermodJson[FPSTR(kActive)].as<bool>();

As per coding guidelines: "usermods/**/*.{cpp,h,hpp}: Store repeated strings as static const char[] PROGMEM in usermods" and "Use F(\"string\") for string constants in C++ to save RAM on ESP8266".

Also applies to: 471-477

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp` around lines 459 -
463, The JSON keys "WordClockUsermod" and "active" are repeated as RAM string
literals when creating usermodJson (root.createNestedObject) and assigning
usermodJson["active"] = usermodActive; replace these raw literals with shared
PROGMEM string constants (e.g. static const char[] PROGMEM) and use FPSTR(...)
or F("...") when passing them to createNestedObject and JsonObject access to
avoid RAM usage; update all occurrences (including the other instances around
lines where usermodJson is built/updated) to reference the new constants.

30-38: ⚡ Quick win

Replace new mask-size macros with typed constexpr constants.

The added #define mask sizes on Line 30 and Line 33-38 should be static constexpr to keep type safety and scope local to the class.

Suggested change
-    `#define` maskSizeLeds        121
-    `#define` maskSizeMinutes11   12
-    `#define` maskSizeMinutes11Mea   12
-    `#define` maskSizeHours11    6
-    `#define` maskSizeHours11Mea    6
+    static constexpr uint16_t maskSizeLeds = 121;
+    static constexpr uint8_t maskSizeMinutes11 = 12;
+    static constexpr uint8_t maskSizeMinutes11Mea = 12;
+    static constexpr uint8_t maskSizeHours11 = 6;
+    static constexpr uint8_t maskSizeHours11Mea = 6;

As per coding guidelines: "Prefer constexpr over #define for compile-time constants in C++".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp` around lines 30 -
38, Replace the preprocessor macros (maskSizeLeds, maskSizeMinutes,
maskSizeMinutesMea, maskSizeMinutes11, maskSizeMinutes11Mea, maskSizeHours,
maskSizeHoursMea, maskSizeHours11, maskSizeHours11Mea) with typed constexpr
variables (e.g., static constexpr std::size_t) declared in the appropriate scope
(class or anonymous namespace) so they are type-safe and have limited scope; set
maskSizeLeds to 121 and the minute/hour masks to 12/6 respectively and ensure
they are marked static constexpr to keep linkage local.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@usermods/usermod_v2_word_clock/readme.md`:
- Line 8: The README contains spelling/parameter typos: rename the parameter
label "diplayItIs" to "displayItIs" and correct the words "integreated" to
"integrated" and "Grafics" to "Graphics" in the document so users won't copy
incorrect names; update every occurrence (e.g., the README entries around the
"displayItIs" description and the section headers/text mentioning "integreated"
and "Grafics") to the corrected spellings to keep docs and config names
consistent.
- Around line 55-56: The fenced code block starting with the line "# 1. REST
command to send on/off commands to the WLED usermod" should include a YAML
language tag; update the opening fence from ``` to ```yaml so the block is
```yaml followed by that header line, ensuring proper rendering and lint
compliance in readme.md.

In `@usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp`:
- Around line 559-560: The code now reads the new key F("meanderWiring") but has
no fallback for older configs; update the load so getJsonValue is attempted
against the new key and, if that fails or is missing, fall back to the original
key (e.g., F("meander") or the old name used previously) when populating the
meander variable — use the same pattern around top[...] and getJsonValue so
configComplete is combined correctly; reference getJsonValue, top,
F("meanderWiring"), and the meander variable to locate where to add the fallback
read and preserve backward compatibility.

---

Nitpick comments:
In `@usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp`:
- Around line 459-463: The JSON keys "WordClockUsermod" and "active" are
repeated as RAM string literals when creating usermodJson
(root.createNestedObject) and assigning usermodJson["active"] = usermodActive;
replace these raw literals with shared PROGMEM string constants (e.g. static
const char[] PROGMEM) and use FPSTR(...) or F("...") when passing them to
createNestedObject and JsonObject access to avoid RAM usage; update all
occurrences (including the other instances around lines where usermodJson is
built/updated) to reference the new constants.
- Around line 30-38: Replace the preprocessor macros (maskSizeLeds,
maskSizeMinutes, maskSizeMinutesMea, maskSizeMinutes11, maskSizeMinutes11Mea,
maskSizeHours, maskSizeHoursMea, maskSizeHours11, maskSizeHours11Mea) with typed
constexpr variables (e.g., static constexpr std::size_t) declared in the
appropriate scope (class or anonymous namespace) so they are type-safe and have
limited scope; set maskSizeLeds to 121 and the minute/hour masks to 12/6
respectively and ensure they are marked static constexpr to keep linkage local.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 18ad6de6-2a54-4793-98c6-497e9302c684

📥 Commits

Reviewing files that changed from the base of the PR and between 37623ed and 6dc9bee.

⛔ Files ignored due to path filters (1)
  • usermods/usermod_v2_word_clock/de_DE_s1.svg is excluded by !**/*.svg
📒 Files selected for processing (2)
  • usermods/usermod_v2_word_clock/readme.md
  • usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp

Comment thread usermods/usermod_v2_word_clock/readme.md Outdated
Comment thread usermods/usermod_v2_word_clock/readme.md
Comment on lines +559 to +560
configComplete &= getJsonValue(top[F("meanderWiring")], meander);
configComplete &= getJsonValue(top[F("wiring11x11")], eleven);
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot May 9, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Preserve backward compatibility when reading renamed config keys.

Line 559 switched to meanderWiring, but there is no fallback for existing cfg.json installations that still store the previous key. On upgrade, users can silently lose the setting until manually re-saved.

Suggested change
-      configComplete &= getJsonValue(top[F("meanderWiring")], meander);
+      if (!getJsonValue(top[F("meanderWiring")], meander)) {
+        getJsonValue(top[F("meander")], meander); // backward compatibility
+        configComplete = false;
+      }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp` around lines 559 -
560, The code now reads the new key F("meanderWiring") but has no fallback for
older configs; update the load so getJsonValue is attempted against the new key
and, if that fails or is missing, fall back to the original key (e.g.,
F("meander") or the old name used previously) when populating the meander
variable — use the same pattern around top[...] and getJsonValue so
configComplete is combined correctly; reference getJsonValue, top,
F("meanderWiring"), and the meander variable to locate where to add the fallback
read and preserve backward compatibility.

✅ Addressed in commit f7146b1

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

the suggested change seems wrong, the previous config key was actually "Meander wiring?" not "meander".

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@softhack007, you're absolutely right — I apologize for the error. Looking at the diff, the old key was clearly F("Meander wiring?"), not F("meander"). The correct backward-compatibility fallback should be:

if (!getJsonValue(top[F("meanderWiring")], meander)) {
  getJsonValue(top[F("Meander wiring?")], meander); // backward compatibility
  configComplete = false;
}

Thank you for the correction!

ʕ •ₒ• ʔ


✏️ Learnings added
Learnt from: softhack007
Repo: wled/WLED PR: 5586
File: usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp:0-0
Timestamp: 2026-05-10T13:43:45.937Z
Learning: In `usermods/usermod_v2_word_clock/usermod_v2_word_clock.cpp`, the previous config key for the meander wiring setting was `"Meander wiring?"` (not `"meander"`). When adding backward-compatibility fallbacks for renamed config keys in this file, use `F("Meander wiring?")` as the old key, not `F("meander")`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: softhack007
Repo: wled/WLED PR: 5355
File: wled00/util.cpp:635-638
Timestamp: 2026-02-07T16:06:08.677Z
Learning: PSRAM-related compilation guards should enable PSRAM code only for ESP32 variants that actually include PSRAM: ESP32-C61, ESP32-C5, and ESP32-P4. Exclude ESP32-C3, ESP32-C6, and ESP8266 from these guards. Apply this rule across the codebase (not just wled00/util.cpp) by reviewing and updating PSRAM guards/macros in all relevant files (C/C++ headers and sources).

Learnt from: softhack007
Repo: wled/WLED PR: 4838
File: lib/NeoESP32RmtHI/src/NeoEsp32RmtHIMethod.cpp:30-35
Timestamp: 2026-03-27T12:33:48.499Z
Learning: In C/C++ preprocessor conditionals (`#if`, `#elif`) GCC/Clang treat `&&` as short-circuit evaluated during preprocessing. This means guards like `#if defined(ARDUINO_ARCH_ESP32) && ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)` are safe even if the macro/function-like macro on the RHS (e.g., `ESP_IDF_VERSION_VAL`) is not defined on some targets, because the RHS will not be expanded when the LHS is false (e.g., `defined(...)` evaluates to 0). During code review, avoid flagging such cases as “undefined function-like macro invocation” if they are protected by short-circuiting `defined(...) && ...`/`||` logic; some tools like cppcheck may not model this and can produce false positives. Also, don’t suggest refactoring that moves ESP32-specific includes/headers (e.g., `esp_idf_version.h`) outside of these guarded preprocessor blocks, since that will break targets (e.g., ESP8266) where the headers don’t exist.

Learnt from: softhack007
Repo: wled/WLED PR: 4843
File: usermods/elastic_collisions/Elastic_Collisions.cpp:1-1
Timestamp: 2026-05-06T22:10:27.517Z
Learning: In C/C++, do not flag precedence issues for expressions that mix additive operators (`+`, `-`) with shift operators (`<<`, `>>`) based on the assumption that shifts bind tighter. Per C/C++ operator precedence, `+`/`-` have higher precedence than `<<`/`>>` (e.g., `x - edge0 << 8` parses as `(x - edge0) << 8`). When reviewing WLED (and other) fixed-point/bit-manipulation code, confirm the intended parse using cppreference before reporting a precedence bug for mixed `-`/`+` and `<<`/`>>` expressions.

Corrected typos and improved clarity in readme.
Added backward compatibility for meander wiring configuration.
@DedeHai
Copy link
Copy Markdown
Collaborator

DedeHai commented May 10, 2026

please revert unnecessary changes.
also why change the meander config parameter?

configComplete &= getJsonValue(top[F("ledOffset")], ledOffset);
configComplete &= getJsonValue(top[F("Meander wiring?")], meander);
if (!getJsonValue(top[F("meanderWiring")], meander)) {
getJsonValue(top[F("meander")], meander); // backward compatibility
Copy link
Copy Markdown
Member

@softhack007 softhack007 May 10, 2026

Choose a reason for hiding this comment

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

looks like your fallback should actually be "Meander wiring?", not "meander" ?
lessons learned: AI suggestions are sometimes very wrong 😉

`configuration.yaml`
```
# 1. REST command to send on/off commands to the WLED usermod
rest_command:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

rest = "JSON API" ?

@softhack007 softhack007 added effect usermod usermod related labels May 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effect usermod usermod related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants