Skip to content

Conversation

@mtin
Copy link

@mtin mtin commented Dec 9, 2025

The usermod_v2_auto_save deliberately will not save the current state if it is a preset without modifications. I think this totally depends on the use case and should be configurable.

My use case:

Multiple presets that can be cycled through via a button. Whenever power is cut and restored, it should be in the state as it was before.

So I added an option AUTOSAVE_IGNORE_PRESETS which defaults to true which is the previous behavior.

Screenshot 2025-12-09 at 18 24 40

I'd like to argue that a default of false (meaning: also autosave if it is an already saved preset) might make more sense for the majority, but ofc that is an opinionated guess

I personally was confused why it would not save when cycling through my presets, could not find documentation on it - and ended up being educated by @softhack007 at #3771, thanks for that!

if you're running a preset without changes, then autosave will not save the settings (reason: you're running an unchanged preset and we don't want to make duplicates)

Summary by CodeRabbit

  • New Features
    • Added a user-facing setting to control whether auto-save ignores preset changes; default preserves previous behavior. The setting is persisted across saves/loads.
  • Bug Fixes
    • Auto-save now correctly skips saves in scenarios that previously produced duplicate presets when the ignore-presets option is enabled.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 9, 2025

Walkthrough

Adds a new boolean flag autoSaveIgnorePresets to AutoSaveUsermod, persists it via config read/write (FPSTR/PROGMEM key), and updates the autosave loop to skip autosaving when the flag is true and a non-zero preset is active.

Changes

Cohort / File(s) Summary
AutoSave configuration and logic
usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp
Added private member bool autoSaveIgnorePresets = true; declared static const char _autoSaveIgnorePresets[] and defined const char AutoSaveUsermod::_autoSaveIgnorePresets[] PROGMEM = "autoSaveIgnorePresets"; persisted flag in addToConfig() and readFromConfig() (FPSTR key); updated loop() guard to skip autosave when autoSaveIgnorePresets && currentPreset > 0.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Check loop() change for unintended early-skip side effects with autosave timing/state.
  • Verify addToConfig() / readFromConfig() use consistent JSON key and default handling.
  • Confirm PROGMEM/FPSTR usage matches project conventions and builds on target.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 75.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding an option to control whether unmodified presets are saved in the autosave usermod.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4752d75 and cb70453.

📒 Files selected for processing (1)
  • usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp (7 hunks)
🧰 Additional context used
🧠 Learnings (7)
📚 Learning: 2025-11-27T06:33:11.436Z
Learnt from: BobLoeffler68
Repo: wled/WLED PR: 5109
File: wled00/FX.cpp:3174-3343
Timestamp: 2025-11-27T06:33:11.436Z
Learning: WLED Ants effect (wled00/FX.cpp): The author prefers the current velocity initialization using hw_random16(1000, 5000)/5000.0f, resulting in an effective range of ~3.6–10.0 (with VELOCITY_MIN=2.0, VELOCITY_MAX=10.0), and wants the code kept as-is with comments updated to document this behavior. Avoid suggesting changes to span the full 2.0–10.0 range in future reviews.

Applied to files:

  • usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp
📚 Learning: 2025-11-14T13:37:11.994Z
Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:11.994Z
Learning: In WLED code reviews, when code is modified or added, look for "magic numbers" (hardcoded numeric literals) and suggest replacing them with appropriate defined constants when those constants are meaningful in the context of the PR. For example, the hardcoded value 32 should be replaced with WLED_MAX_SEGNAME_LEN when it represents a segment name length limit. This improves code maintainability and reduces the risk of inconsistencies.

Applied to files:

  • usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp
📚 Learning: 2025-12-01T07:01:16.949Z
Learnt from: blazoncek
Repo: wled/WLED PR: 5140
File: wled00/data/settings_time.htm:66-76
Timestamp: 2025-12-01T07:01:16.949Z
Learning: In WLED PR #5134, the fix for macros being initialized with the enable bit set only handles new configurations, not existing ones. If there is a bug in timer/macro handling code (e.g., in settings_time.htm), it must be fixed to work correctly for existing configurations as well.

Applied to files:

  • usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp
📚 Learning: 2025-08-26T11:51:21.817Z
Learnt from: DedeHai
Repo: wled/WLED PR: 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:

  • usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp
📚 Learning: 2025-11-14T13:37:30.955Z
Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:30.955Z
Learning: In WLED code reviews, when code is modified or added, look for "magic numbers" (hardcoded numeric literals) and suggest replacing them with defined constants when meaningful constants exist in the codebase. For example, suggest replacing hardcoded "32" with WLED_MAX_SEGNAME_LEN if the context relates to segment name length limits.

Applied to files:

  • usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp
📚 Learning: 2025-09-02T19:42:57.475Z
Learnt from: freakintoddles2
Repo: wled/WLED PR: 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:

  • usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp
📚 Learning: 2025-04-27T09:37:28.415Z
Learnt from: KrX3D
Repo: wled/WLED PR: 4585
File: usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.h:121-136
Timestamp: 2025-04-27T09:37:28.415Z
Learning: Using PROGMEM for the seven-segment font array (umSSDRNumbers) in the WLED SSDR usermod causes compilation problems, so it should be left as a regular array.

Applied to files:

  • usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp
🪛 Cppcheck (2.18.0)
usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp

[error] 281-281: There is an unknown macro here somewhere. Configuration is required. If PROGMEM is a macro then please configure it.

(unknownMacro)

🔇 Additional comments (6)
usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp (6)

56-57: LGTM!

Default value of true preserves backward compatibility, and no #ifdef wrapper is used for the default, which aligns with the project's direction away from compile-time configuration defaults.


77-77: LGTM!

Follows the established pattern for flash string declarations.


132-133: Good improvement: lastRun is now properly updated.

The logic correctly implements the feature: when autoSaveIgnorePresets is true (default) and a preset is active (currentPreset > 0), autosave is skipped. This preserves backward compatibility while allowing users to opt-in to autosaving preset states.

The placement of lastRun = now; after the early return check is the correct fix for the issue noted in previous review discussions.


230-234: LGTM!

Configuration persistence follows the established pattern and proper formatting alignment.


257-263: LGTM!

The configuration read follows the same pattern as other boolean fields (enabled, applyAutoSaveOnBoot) and correctly uses the default value fallback pattern.


281-286: LGTM!

The static string definition follows the established PROGMEM pattern. The Cppcheck warning about PROGMEM being an unknown macro is a false positive — this is a standard Arduino/ESP8266/ESP32 macro for storing constants in flash memory.


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
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: 0

🧹 Nitpick comments (1)
usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp (1)

136-136: Logic is correct; consider extracting guard conditions for readability.

The implementation correctly integrates the new flag: autosave is now skipped when autoSaveIgnorePresets is true AND a preset is active. This preserves backward compatibility while enabling the new use case.

The guard condition is getting quite long. If desired, you could extract it to improve readability:

+    bool shouldSkipAutoSave() {
+      return !autoSaveAfterSec || !enabled || 
+             (autoSaveIgnorePresets && currentPreset>0) || 
+             (strip.isUpdating() && now - lastRun < 240);
+    }
+
     void loop() {
       static unsigned long lastRun = 0;
       unsigned long now = millis();
-      if (!autoSaveAfterSec || !enabled || (autoSaveIgnorePresets && currentPreset>0) || (strip.isUpdating() && now - lastRun < 240)) return;
+      if (shouldSkipAutoSave()) return;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cc5b504 and 1e921bc.

📒 Files selected for processing (1)
  • usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp (7 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: blazoncek
Repo: wled/WLED PR: 5140
File: wled00/data/settings_time.htm:66-76
Timestamp: 2025-12-01T07:01:16.949Z
Learning: In WLED PR #5134, the fix for macros being initialized with the enable bit set only handles new configurations, not existing ones. If there is a bug in timer/macro handling code (e.g., in settings_time.htm), it must be fixed to work correctly for existing configurations as well.
📚 Learning: 2025-09-02T19:42:57.475Z
Learnt from: freakintoddles2
Repo: wled/WLED PR: 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:

  • usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp
📚 Learning: 2025-04-27T09:37:28.415Z
Learnt from: KrX3D
Repo: wled/WLED PR: 4585
File: usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.h:121-136
Timestamp: 2025-04-27T09:37:28.415Z
Learning: Using PROGMEM for the seven-segment font array (umSSDRNumbers) in the WLED SSDR usermod causes compilation problems, so it should be left as a regular array.

Applied to files:

  • usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp
🪛 Cppcheck (2.18.0)
usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp

[error] 284-284: There is an unknown macro here somewhere. Configuration is required. If PROGMEM is a macro then please configure it.

(unknownMacro)

🔇 Additional comments (6)
usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp (6)

19-22: Documentation is clear and helpful.

The comments accurately describe the new feature and its default behavior, making it easy for users to understand the configuration option.


56-60: Configuration pattern looks good.

The implementation follows the established pattern for configurable parameters and correctly defaults to true to preserve backward compatibility.


81-81: Static string declaration follows established pattern.

The declaration is consistent with other PROGMEM strings in the class.


233-237: Configuration persistence implemented correctly.

The new field is properly added to the config JSON using the same pattern as existing fields.


266-266: Config reading implemented correctly.

The boolean value is read using the same pattern as other boolean config fields, with appropriate default fallback.


289-289: Static string definition is correct.

The PROGMEM string is properly defined. Note: The Cppcheck warning about the PROGMEM macro is a false positive—PROGMEM is a standard Arduino macro for storing data in flash memory.

Copy link
Member

@willmmiles willmmiles left a comment

Choose a reason for hiding this comment

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

Apart from the build time change, I think this is a reasonable feature to add.

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 (1)
usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp (1)

230-234: LGTM: Configuration persistence properly implemented.

The new field is correctly added to the JSON configuration output, following the same pattern as other configuration fields.

Note: As mentioned in the inline comments (lines 222-223), you'll need to separately update the HTML UI, xml.cpp, and set.cpp to expose this configuration option in the web interface. Currently, users would need to manually edit cfg.json to change this setting.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1e921bc and 4752d75.

📒 Files selected for processing (1)
  • usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp (7 hunks)
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: blazoncek
Repo: wled/WLED PR: 5140
File: wled00/data/settings_time.htm:66-76
Timestamp: 2025-12-01T07:01:16.949Z
Learning: In WLED PR #5134, the fix for macros being initialized with the enable bit set only handles new configurations, not existing ones. If there is a bug in timer/macro handling code (e.g., in settings_time.htm), it must be fixed to work correctly for existing configurations as well.
📚 Learning: 2025-09-02T19:42:57.475Z
Learnt from: freakintoddles2
Repo: wled/WLED PR: 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:

  • usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp
📚 Learning: 2025-04-27T09:37:28.415Z
Learnt from: KrX3D
Repo: wled/WLED PR: 4585
File: usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.h:121-136
Timestamp: 2025-04-27T09:37:28.415Z
Learning: Using PROGMEM for the seven-segment font array (umSSDRNumbers) in the WLED SSDR usermod causes compilation problems, so it should be left as a regular array.

Applied to files:

  • usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp
🪛 Cppcheck (2.18.0)
usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp

[error] 281-281: There is an unknown macro here somewhere. Configuration is required. If PROGMEM is a macro then please configure it.

(unknownMacro)

🔇 Additional comments (5)
usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp (5)

56-56: LGTM: Default preserves backward compatibility.

The member variable is properly declared with a default value of true, which preserves the original behavior of not auto-saving when an unmodified preset is active.


77-77: LGTM: Static string declaration follows established pattern.

The static string declaration is consistent with the other configuration field names in the class.


263-263: LGTM: Configuration reading properly implemented.

The field is correctly read from the configuration with a proper default fallback using the | operator, ensuring backward compatibility when the field is missing from existing configurations.


281-286: LGTM: PROGMEM string definitions are correct.

The flash string definitions follow the established pattern used by other configuration field names in this file. The static analysis warning about the PROGMEM macro is a false positive—it's a standard Arduino macro used throughout the WLED codebase for storing strings in flash memory to save RAM.


132-132: Verify that currentPreset is cleared when a preset is modified.

The new guard (autoSaveIgnorePresets && currentPreset>0) assumes that when a user modifies a preset, WLED clears currentPreset to 0. If this assumption is incorrect, the default behavior might prevent autosaving even when a preset is modified, which would be a regression from the original behavior.

Run the following script to verify how currentPreset is managed when state changes occur:

#!/bin/bash
# Description: Search for assignments to currentPreset to understand when it's cleared

# Search for writes to currentPreset
rg -n -C3 'currentPreset\s*=' --type=cpp

# Also search for the variable declaration
ast-grep --pattern 'currentPreset'

Comment on lines 19 to 21
// By default it will not save the state if an unmodified preset
// is selected (to not duplicate it). You can change this behaviour
// by setting AUTOSAVE_IGNORE_PRESETS=false
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 | 🟡 Minor

Update the comment to reference the JSON configuration field.

The comment references AUTOSAVE_IGNORE_PRESETS=false, which suggests a compile-time define, but the actual implementation uses a JSON configuration field autoSaveIgnorePresets. This inconsistency could confuse users trying to configure this option.

Apply this diff to correct the documentation:

-// By default it will not save the state if an unmodified preset
-// is selected (to not duplicate it). You can change this behaviour
-// by setting AUTOSAVE_IGNORE_PRESETS=false
+// By default it will not save the state if an unmodified preset
+// is selected (to not duplicate it). You can change this behavior
+// by setting "autoSaveIgnorePresets": false in the usermod configuration.
🤖 Prompt for AI Agents
In usermods/usermod_v2_auto_save/usermod_v2_auto_save.cpp around lines 19 to 21,
the comment incorrectly references a compile-time define
"AUTOSAVE_IGNORE_PRESETS=false" while the implementation reads the JSON
configuration field "autoSaveIgnorePresets"; update the comment to mention the
correct JSON config key (autoSaveIgnorePresets) and show the expected JSON usage
(e.g., "set autoSaveIgnorePresets to false in the config JSON") so users are
guided to change the runtime configuration rather than a non-existent
compile-time define.

unsigned long now = millis();
if (!autoSaveAfterSec || !enabled || currentPreset>0 || (strip.isUpdating() && now - lastRun < 240)) return; // setting 0 as autosave seconds disables autosave
if (!autoSaveAfterSec || !enabled || (autoSaveIgnorePresets && currentPreset>0) || (strip.isUpdating() && now - lastRun < 240)) return; // setting 0 as autosave seconds disables autosave
lastRun = now;
Copy link
Author

Choose a reason for hiding this comment

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

While reviewing this again, I stumbled over lastRun never being set!? I think the intention probably was this; fine to add this in this MR as well? This got introduced in 0ff4016#diff-e57385253fd04c5e758584aeb14c1398a2ec9febfbb230c376b406b4aaa93ffc

And, sorry, rusty cpp: should lastRun be a static scoped variable here? why not a private member variable?

Copy link
Member

@softhack007 softhack007 Dec 24, 2025

Choose a reason for hiding this comment

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

@mtin I think your fix is correct, "lastRun" implements the standard "be nice but not too nice" logic that enforces running the loop() even under high load (strip.isUdating())
A static variable in a function is different from a private class attribute, I think it was chosen here because we needed a persistent value without polluting global namespace.

So not necessary to make it a private member, because we will never have more than one instance of this usermod.

@mtin mtin requested a review from willmmiles December 10, 2025 12:06
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.

3 participants