Skip to content

Conversation

freakintoddles2
Copy link
Contributor

@freakintoddles2 freakintoddles2 commented Sep 2, 2025

I updated the checkboxes on Percent effect to support three new modes to automatically illuminate a % of the LEDs in a segment:

  • % of minute
  • % of hour
  • % of day

This allows you to create dynamic effects based on these timescales. e.g. custom abstract clock displays. Personally I did this because I am creating a visual daily 'clock' for my kids with physical markers on it for "dad is done with work" and "Bed time" etc. I added minute/hour at the suggestion of others, but now this makes it suitable for true clock functionality which is nice -- and with much more flexibility than the other 'clock' mode option.

The effect is designed to fill the segment during the last 'tick' of the time period. At rollover (e.g. second 60/0) it intentionally shows SEGLEN lit for one tick to represent the completed period, then move to 1 LED at second 1. This avoids a visually empty segment at rollover and matches the cadence of a ticking hand (…58, 59, 60/0 full, 1, 2…).

This also deprecates/repurposes the previous 'use single color' checkbox. This appeared to be completely redundant and unnecessary since it is easy to just set the palette to 'color 1' which achieves the exact same effect.

Summary by CodeRabbit

  • New Features

    • Percent effect now offers time-based progress options: % of Minute, % of Hour, and % of Day.
    • When a time option is selected, LEDs display elapsed-period progress with automatic period handling and smooth transitions.
    • When time options are off, percent rendering uses a refined gradient and smoother per-LED transitions.
  • Documentation

    • Mode label updated to include the new time-based Percent options.

I updated the checkboxes on Percent effect to support three new modes to automatically illuminate a % of the LEDs in a segment:
- % of minute
- % of hour
- % of day
This allows you to create dynamic effects based on these timescales. e.g. custom abstract clock displays. 
Personally I did this because I am creating a visual daily 'clock' for my kids with physical markers on it for "dad is done with work" and "Bed time" etc. I added minute/hour at the suggestion of others, but now this makes it suitable for true clock functionality which is nice -- and with much more flexibility than the other 'clock' mode option. 

This also deprecates the previous 'use single color' checkbox. I deemed this to be unnecessary since it is easy to just set the palette to 'color 1' which achieves the exact same effect.
Copy link
Contributor

coderabbitai bot commented Sep 2, 2025

Walkthrough

Adds optional time-based progress rendering to the Percent FX mode (minute/hour/day) that maps elapsed time to lit LEDs; refactors the non-time path to recompute normalized percent and simplify per-LED palette/unlit filling; updates the mode metadata string to expose the new time options.

Changes

Cohort / File(s) Summary of Changes
Percent mode rendering logic
wled00/FX.cpp
Added time-based rendering in mode_percent: computes period (60/3600/86400s) and elapsed from localTime, maps inclusive LED count, clamps to [1, SEGLEN], fills first LEDs from palette and others with unlit color, returns FRAMETIME early. Refactored non-time path to recompute normalized percent (0–200), derive active LEDs, apply mirrored gradient for percent ≥100, and simplify per-LED palette vs unlit assignment while preserving smoothing via aux1/size.
Mode metadata update
wled00/FX.cpp
Modified static const char _data_FX_MODE_PERCENT[] PROGMEM to include “% of Minute, % of Hour, % of Day” options in the Percent mode metadata string.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@freakintoddles2 freakintoddles2 changed the title Update FX.cpp Update Percent effect to add optional % of time modes Sep 2, 2025
@freakintoddles2
Copy link
Contributor Author

@DedeHai here's the PR I mentioned, and a vid of it in action

Screen_Recording_2025-08-28_at_2.07.18_PM.mov

Copy link
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: 2

🧹 Nitpick comments (2)
wled00/FX.cpp (2)

3894-3897: Update the function header comment to match new 0–200 behavior

The comment still says “Intensity values from 0-100,” but the code now supports 0–200 for the mirrored phase. Update the doc to avoid user confusion.

Apply this diff:

- * Intensity values from 0-100 turn on the leds.
+ * Intensity:
+ *   0–100  -> grow from 0% to 100%
+ *   101–200 -> mirror: shrink from 100% back toward 0%

3940-3966: Smoothing step can overshoot on speed=255; cap to segment length

With speed=255, size=255. On small segments this can jump SEGENV.aux1 far past active_leds in one frame. Consider clamping size to SEGLEN (or a fraction thereof) to keep transitions smooth across all lengths.

Example:

-  unsigned size = (1 + ((SEGMENT.speed * SEGLEN) >> 11));
-  if (SEGMENT.speed == 255) size = 255;
+  unsigned size = (1 + ((SEGMENT.speed * SEGLEN) >> 11));
+  if (SEGMENT.speed == 255) size = SEGLEN; // avoid overshoot on short segments
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 666a59f and 2e65090.

📒 Files selected for processing (1)
  • wled00/FX.cpp (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
wled00/{*.cpp,!(html_*)*.h}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use spaces (2 per level) for C++ source and header files

Files:

  • wled00/FX.cpp
🧠 Learnings (3)
📓 Common learnings
Learnt from: DedeHai
PR: wled/WLED#4798
File: wled00/FX.cpp:7531-7533
Timestamp: 2025-08-26T11:51:21.817Z
Learning: In WLED PR #4798, DedeHai confirmed that certain gamma-related calls in FX.cpp/FX_fcn.cpp/particle systems are intentional for effect-level shaping (e.g., brightness curves, TV sim, Pride 2015 pre-mix), distinct from final output gamma. Do not flag or remove these in future reviews; add comments when feasible to clarify intent.
📚 Learning: 2025-08-26T11:51:21.817Z
Learnt from: DedeHai
PR: wled/WLED#4798
File: wled00/FX.cpp:7531-7533
Timestamp: 2025-08-26T11:51:21.817Z
Learning: In WLED PR #4798, DedeHai confirmed that certain gamma-related calls in FX.cpp/FX_fcn.cpp/particle systems are intentional for effect-level shaping (e.g., brightness curves, TV sim, Pride 2015 pre-mix), distinct from final output gamma. Do not flag or remove these in future reviews; add comments when feasible to clarify intent.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-06-15T09:59:52.720Z
Learnt from: netmindz
PR: wled/WLED#4728
File: wled00/FX.h:378-378
Timestamp: 2025-06-15T09:59:52.720Z
Learning: In WLED's FX.h, MODE_COUNT represents the highest FX_MODE_ ID + 1, not the total count of FX_MODE_ definitions. This is because some effects may have been removed but their IDs are not reused, creating gaps in the numbering sequence. MODE_COUNT is used for array bounds and range checking.

Applied to files:

  • wled00/FX.cpp
🧬 Code graph analysis (1)
wled00/FX.cpp (1)
wled00/src/dependencies/time/Time.cpp (6)
  • second (77-80)
  • second (77-77)
  • minute (72-75)
  • minute (72-72)
  • hour (49-52)
  • hour (49-49)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: wled_build / Build Environments (esp32_eth)
  • GitHub Check: wled_build / Build Environments (esp32dev)
  • GitHub Check: wled_build / Build Environments (esp32s3_4M_qspi)
  • GitHub Check: wled_build / Build Environments (esp32s3dev_8MB_opi)
  • GitHub Check: wled_build / Build Environments (lolin_s2_mini)
  • GitHub Check: wled_build / Build Environments (usermods)
  • GitHub Check: wled_build / Build Environments (esp32s3dev_16MB_opi)
  • GitHub Check: wled_build / Build Environments (esp32_wrover)
  • GitHub Check: wled_build / Build Environments (nodemcuv2)
🔇 Additional comments (1)
wled00/FX.cpp (1)

3978-3979: Confirm UI metadata/backward compatibility for repurposed checkboxes

Switching from “One color” to “% of Minute/Hour/Day” changes checkbox semantics and saved presets. Verify:

  • the new labels appear in the UI as intended,
  • existing presets using “One color” won’t silently flip on a time mode,
  • JSON API metadata consumers tolerate the new fields.

I can help write a quick preset-migration note or guard in the effect to ignore time flags if a legacy preset sets palette==“color 1”.

@DedeHai DedeHai self-assigned this Sep 2, 2025
@DedeHai
Copy link
Collaborator

DedeHai commented Sep 3, 2025

I like it! I am just not too sure the percent effect should be repurposed like this i.e. maybe this should be an effect in its own right. I think percent is quite an old effect and it must stay backwards compatible, meaning repurposing a checkmark is not a good idea or an update to 0.16 will break peoples presets. We should try to avoid that as much as possible.
I know you considered using a slider and one checkmark, that would allow to use one checkmark and one slider (custom3, named m/h/d ) but I also think that is confusing. As a user I would also not be looking to find a clock feature in an FX called "percent". It could be an alias, like the twinkle FX that use a base effect and several functions built on top of that base (or just call the base with different parameters) to avoid code duplication.
If this were its own effect, do you have any additional ideas that could be realized with it? It would allow to add seconds for example. You know I am a fan of versatile and configurable effects if you ever tried one of my PS effects ;)

Copy link
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: 1

🧹 Nitpick comments (4)
wled00/FX.cpp (4)

3900-3913: Make time-mode selection explicit and mutually exclusive

If multiple checks are set, check3 silently overrides the rest. Make the priority explicit and avoid redundant assignments.

-  if (SEGMENT.check1 || SEGMENT.check2 || SEGMENT.check3) {
-    uint32_t period  = 60U;                             // Minute default
-    uint32_t elapsed = (uint32_t)second(localTime);
-
-    if (SEGMENT.check2) {                               // Hour
-      period  = 3600U;
-      elapsed = (uint32_t)minute(localTime) * 60U + (uint32_t)second(localTime);
-    }
-    if (SEGMENT.check3) {                               // Day
-      period  = 86400U;
-      elapsed = (uint32_t)hour(localTime) * 3600U
-              + (uint32_t)minute(localTime) * 60U
-              + (uint32_t)second(localTime);
-    }
+  if (SEGMENT.check1 || SEGMENT.check2 || SEGMENT.check3) {
+    uint32_t period, elapsed;
+    if (SEGMENT.check3) {                               // Day
+      period  = 86400U;
+      elapsed = (uint32_t)hour(localTime) * 3600U
+              + (uint32_t)minute(localTime) * 60U
+              + (uint32_t)second(localTime);
+    } else if (SEGMENT.check2) {                        // Hour
+      period  = 3600U;
+      elapsed = (uint32_t)minute(localTime) * 60U + (uint32_t)second(localTime);
+    } else {                                            // Minute
+      period  = 60U;
+      elapsed = (uint32_t)second(localTime);
+    }

3899-3903: Document unsynced-time behavior to avoid “fixes” later

Add a note that 00:00:00 (unsynced RTC) intentionally renders full for one tick.

   // --- Time modes (if any of Minute/Hour/Day checks are active) ---
+  // Note: when localTime is not yet synced (00:00:00), we intentionally show a full bar
+  // for one tick to avoid an “empty” rollover frame (clock semantics).

3928-3936: Avoid double pass over SEGLEN in time path

Fill background once, then paint lit portion.

-    // lit portion
-    for (unsigned i = 0; i < lit; i++) {
-      SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
-    }
-    // unlit portion
-    for (unsigned i = lit; i < SEGLEN; i++) {
-      SEGMENT.setPixelColor(i, SEGCOLOR(1));
-    }
+    SEGMENT.fill(SEGCOLOR(1));
+    for (unsigned i = 0; i < lit; i++) {
+      SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0));
+    }

3939-3945: Initialize smoothing accumulator on first call

Prevent inherited state when switching into Percent mode.

-  // Normal percent mode (when all time options are unchecked) 
+  // Normal percent mode (when all time options are unchecked)
+  if (SEGENV.call == 0) SEGENV.aux1 = 0;

Also applies to: 3967-3975

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 2e65090 and c5e29ad.

📒 Files selected for processing (1)
  • wled00/FX.cpp (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
wled00/{*.cpp,!(html_*)*.h}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use spaces (2 per level) for C++ source and header files

Files:

  • wled00/FX.cpp
🧠 Learnings (6)
📓 Common learnings
Learnt from: freakintoddles2
PR: wled/WLED#4904
File: wled00/FX.cpp:3915-3930
Timestamp: 2025-09-02T19:42:57.475Z
Learning: WLED wled00/FX.cpp::mode_percent — For time-based options (% of Minute/Hour/Day), behavior is clock-like: at rollover (elapsed==0) intentionally show SEGLEN lit for one tick to represent completion, then move to 1 LED at the next second. This is by design (not a progress bar) and should not be “fixed”.
Learnt from: freakintoddles2
PR: wled/WLED#4904
File: wled00/FX.cpp:3901-3913
Timestamp: 2025-09-02T19:36:49.513Z
Learning: In FX.cpp mode_percent time-based options (% of Minute/Hour/Day), do not guard against invalid RTC; showing a full bar with unsynced time is intentional to avoid confusing UX.
📚 Learning: 2025-09-02T19:42:57.475Z
Learnt from: freakintoddles2
PR: wled/WLED#4904
File: wled00/FX.cpp:3915-3930
Timestamp: 2025-09-02T19:42:57.475Z
Learning: WLED wled00/FX.cpp::mode_percent — For time-based options (% of Minute/Hour/Day), behavior is clock-like: at rollover (elapsed==0) intentionally show SEGLEN lit for one tick to represent completion, then move to 1 LED at the next second. This is by design (not a progress bar) and should not be “fixed”.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-09-02T19:36:49.513Z
Learnt from: freakintoddles2
PR: wled/WLED#4904
File: wled00/FX.cpp:3901-3913
Timestamp: 2025-09-02T19:36:49.513Z
Learning: In FX.cpp mode_percent time-based options (% of Minute/Hour/Day), do not guard against invalid RTC; showing a full bar with unsynced time is intentional to avoid confusing UX.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-08-26T11:51:21.817Z
Learnt from: DedeHai
PR: wled/WLED#4798
File: wled00/FX.cpp:7531-7533
Timestamp: 2025-08-26T11:51:21.817Z
Learning: In WLED PR #4798, DedeHai confirmed that certain gamma-related calls in FX.cpp/FX_fcn.cpp/particle systems are intentional for effect-level shaping (e.g., brightness curves, TV sim, Pride 2015 pre-mix), distinct from final output gamma. Do not flag or remove these in future reviews; add comments when feasible to clarify intent.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-06-15T09:59:52.720Z
Learnt from: netmindz
PR: wled/WLED#4728
File: wled00/FX.h:378-378
Timestamp: 2025-06-15T09:59:52.720Z
Learning: In WLED's FX.h, MODE_COUNT represents the highest FX_MODE_ ID + 1, not the total count of FX_MODE_ definitions. This is because some effects may have been removed but their IDs are not reused, creating gaps in the numbering sequence. MODE_COUNT is used for array bounds and range checking.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-08-31T03:38:14.114Z
Learnt from: BobLoeffler68
PR: wled/WLED#4891
File: wled00/FX.cpp:3333-3349
Timestamp: 2025-08-31T03:38:14.114Z
Learning: WLED PacMan effect (wled00/FX.cpp): Keep pacmancharacters_t position fields as signed int (not int16_t). Maintainer preference (blazoncek) prioritizes avoiding potential overhead/regressions over minor RAM savings. Avoid type shrinking here unless memory pressure is demonstrated.

Applied to files:

  • wled00/FX.cpp
🧬 Code graph analysis (1)
wled00/FX.cpp (1)
wled00/src/dependencies/time/Time.cpp (6)
  • second (77-80)
  • second (77-77)
  • minute (72-75)
  • minute (72-72)
  • hour (49-52)
  • hour (49-49)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (17)
  • GitHub Check: wled_build / Build Environments (usermods)
  • GitHub Check: wled_build / Build Environments (lolin_s2_mini)
  • GitHub Check: wled_build / Build Environments (esp32s3_4M_qspi)
  • GitHub Check: wled_build / Build Environments (esp32s3dev_16MB_opi)
  • GitHub Check: wled_build / Build Environments (esp01_1m_full_compat)
  • GitHub Check: wled_build / Build Environments (esp32s3dev_8MB_opi)
  • GitHub Check: wled_build / Build Environments (esp01_1m_full)
  • GitHub Check: wled_build / Build Environments (esp32_eth)
  • GitHub Check: wled_build / Build Environments (esp32_wrover)
  • GitHub Check: wled_build / Build Environments (nodemcuv2_160)
  • GitHub Check: wled_build / Build Environments (esp8266_2m_160)
  • GitHub Check: wled_build / Build Environments (nodemcuv2_compat)
  • GitHub Check: wled_build / Build Environments (esp01_1m_full_160)
  • GitHub Check: wled_build / Build Environments (esp8266_2m)
  • GitHub Check: wled_build / Build Environments (esp32dev)
  • GitHub Check: wled_build / Build Environments (esp8266_2m_compat)
  • GitHub Check: wled_build / Build Environments (nodemcuv2)
🔇 Additional comments (1)
wled00/FX.cpp (1)

3915-3926: LGTM on clock rollover semantics

The inclusive mapping with full bar at rollover and minimum one lit otherwise matches the intended “clock” UX.

Comment on lines +3978 to 3979
static const char _data_FX_MODE_PERCENT[] PROGMEM = "Percent@,% of fill,,,,% of Minute,% of Hour,% of Day;!,!;!";

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Don’t break existing Percent presets: restore old metadata, add a new alias for time modes

Repurposing check1/check2/check3 here will flip on time-based behavior for users who previously saved “One color” in Percent, breaking presets on upgrade. Keep Percent unchanged and expose the new clock modes as a separate alias (same implementation) to preserve backward compatibility.

Apply this diff to keep old Percent UI and add a new metadata string for the alias:

-static const char _data_FX_MODE_PERCENT[] PROGMEM = "Percent@,% of fill,,,,% of Minute,% of Hour,% of Day;!,!;!";
+static const char _data_FX_MODE_PERCENT[] PROGMEM = "Percent@,% of fill,,,,One color;!,!;!";
+static const char _data_FX_MODE_PERCENT_TIME[] PROGMEM = "Percent (Time)@,% of fill,,,,% of Minute,% of Hour,% of Day;!,!;!";

Then register the alias alongside the original (outside this hunk, in WS2812FX::setupEffectData right after addEffect(FX_MODE_PERCENT, …)):

// keep the original Percent
addEffect(FX_MODE_PERCENT, &mode_percent, _data_FX_MODE_PERCENT);
// add a new effect ID at the end for time-based Percent (no code duplication)
addEffect(255, &mode_percent, _data_FX_MODE_PERCENT_TIME);

This preserves legacy presets while making the new time-based options discoverable.

🤖 Prompt for AI Agents
In wled00/FX.cpp around lines 3978-3979, the change repurposed the Percent
metadata which will break existing saved Percent presets; restore the original
_data_FX_MODE_PERCENT string exactly as it was and add a new metadata string
(e.g. _data_FX_MODE_PERCENT_TIME) containing the time-mode fields, then do not
change Percent's behavior or its check1/check2/check3 usage. After the existing
addEffect(FX_MODE_PERCENT, &mode_percent, _data_FX_MODE_PERCENT) call in
WS2812FX::setupEffectData, register an alias by calling addEffect with a new
unused effect ID (example 255) that points to the same mode handler but uses the
new _data_FX_MODE_PERCENT_TIME metadata so the time-based options are
discoverable without altering legacy presets.

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.

2 participants