Skip to content

Conversation

@Liliputech
Copy link
Contributor

@Liliputech Liliputech commented Dec 24, 2024

There was a compile issue when trying to enable POV Image effect.
This small PR fixes the problem.

Summary by CodeRabbit

  • New Features

    • Added "POV Image" effect to render 24‑bit BMPs line‑by‑line for persistence‑of‑vision on a rotating LED segment; supports loading and per‑line playback with wrap and throttling.
  • Documentation

    • Added README with image preparation, upload path rules, rotation/RPM guidance, required 24‑bit uncompressed BMP format, RAM (~64 KB) limits, troubleshooting, and safety notes.
  • Chores / Refactor

    • Replaced prior PNG decoding flow with the new BMP/POV rendering path and removed the PNG dependency.

@DedeHai
Copy link
Collaborator

DedeHai commented Dec 25, 2024

did not try to compile, but generally looks ok to me.

@softhack007 softhack007 added the usermod usermod related label Dec 28, 2024
@softhack007
Copy link
Member

@Liliputech please do not force-push while you have a PR open for the the main WLED repo. It causes lots of crazy side-effects like lost review comments, auto-closed bug reports and broken links to code authors.

Liliputech force-pushed the pov_display branch from 3402a05 to 001b882 Compare3 days ago

@softhack007 softhack007 self-requested a review December 28, 2024 14:03
@softhack007 softhack007 added the in progress This pull request is currently being reviewed and, if necessary, modified label Dec 28, 2024
@softhack007
Copy link
Member

softhack007 commented Dec 28, 2024

@Liliputech I think the usermod needs some more fixing and improvements.

  • I've tried to compile it with our default esp32dev environment - even with your patches, compilation just fails inside the PNGdec library (bitbank2/PNGdec@^1.0.1).
    Reverting to bitbank2/[email protected] (i.e. pinned to version 1.0.1) allows me to successfully build.
  • The usermod really needs a readme.md file to explain how to use it
  • I like your effort to also make the usermod compatible with "MoonModules" style usermods :-)
  • I'm wondering why f and png and some other functions are declared globally, with names that simply "invite trouble".
    Normally everything should be defined inside the usermod class, unless there are very strong reasons to leave the class scope.
  • the line buffer in the draw function (uint16_t usPixels[SEGLEN]) seems much too large, which is another case of "invites trouble"
  • Do you know why setPixelColor is used, and not setPixelColorXY ? Is this POV usermod intended for 1D strips, or for 2D setups?

Btw, do you know who is "Arthur Suzuki"? he appears as the author of initial commit, but does not have a github account. He has directly committed the usermod into the Aircoookie repo, so he must be a maintainer? or maybe just a hacker who abused a security flaw in github?

@Liliputech
Copy link
Contributor Author

@Liliputech I think the usermod needs some more fixing and improvements.

Hi @softhack007 Thank you for your feedback :)
I'll make the requested changes as soon as I can (probably by the end of next week, to give a good start to 2025!)

* I've tried to compile it with our default esp32dev environment - even with your patches, compilation just fails inside the PNGdec library (bitbank2/PNGdec@^1.0.1).
  Reverting to bitbank2/[email protected] (i.e. pinned to version 1.0.1) allows me to successfully build.

Maybe I should try to fix that by updating my code to fit the new version of PNGDEC instead then.

* The usermod really needs a readme.md file to explain how to use it

Sure! And a couple pictures!

* I like your effort to also make the usermod compatible with "MoonModules" style usermods :-)

Glad you liked it :)

* I'm wondering why `f` and `png` and some other functions are declared globally, with names that simply "invite trouble".
  Normally everything should be defined inside the usermod class, unless there are very strong reasons to leave the class scope.

Got to fix this indeed.

* Do you know why `setPixelColor` is used, and not `setPixelColorXY` ? Is this POV usermod intended for 1D strips, or for 2D setups?

It is intended for 1D strip, the idea is to have an imaged displayed on a rotating strip.

* the line buffer in the draw function (`uint16_t usPixels[SEGLEN]`) seems much too large, which is another case of "invites trouble"

Unfortunately there is not much to be done here if you want to properly decode PNG.
The GetLineAsRGB565 from PNGDEC need to store each pixel of a line in an int16, and the whole line in an array of the corresponding length (picture width).
The idea is to have a whole line of pixel displayed on the strip. then another, etc...
If the strip is moving fast enough and given the image width equals the strip length, you can get floating images in the air, like an hologram.

Btw, do you know who is "Arthur Suzuki"? he appears as the author of initial commit, but does not have a github account. He has directly committed the usermod into the Aircoookie repo, so he must be a maintainer? or maybe just a hacker who abused a security flaw in github?

I am Arthur :) you can find the information elsewhere by searching for my nickname or profile picture ;)
AFAIK I'm not allowed to push straight or merge to Aircookie repo... Feel free to PM me if needed, I'd be happy to discuss with fellow WLED hackers! (sometime do when connected to discord, same nickname)
Have a nice 2025!
Arthur

@dosipod
Copy link
Contributor

dosipod commented Dec 31, 2024

@Liliputech Since you are fixing things might be consider adding a readme as it is strange the usermod even got merged without one

@Liliputech
Copy link
Contributor Author

Actually I'm thinking about re-using the routines provided by the "image_loader.cpp" file provided by the GIF decoder effect. That would make a lot more sense :)

@Liliputech
Copy link
Contributor Author

* I'm wondering why fandpng and some other functions are declared globally, with names that simply "invite trouble". Normally everything should be defined inside the usermod class, unless there are very strong reasons to leave the class scope.

I can't reuse the routines from image_loader.cpp because the functions signatures are too different...
And unfortunately I cannot make most of the routine as method of a class because the compiler is complaining of non-static functions and variables :
wled00/../usermods/pov_display/usermod_pov_display.h:11:120: error: invalid use of non-static member function 'void PovDisplay::draw(PNGDRAW*)

I will just rename my methods in a more explicit and non-conflicting way and provide a README.

@Liliputech
Copy link
Contributor Author

just to mention, the functions will only be compiled if the USERMOD_POV_DISPLAY flag is set, which for most wled user won't be the case. I don't think this usermod will have that much impact on other things in wled codebase.

@github-actions
Copy link

github-actions bot commented Jun 9, 2025

Hey! This pull request has been open for quite some time without any new comments now. It will be closed automatically in a week if no further activity occurs.
Thank you for contributing to WLED! ❤️

@github-actions github-actions bot added the stale This issue will be closed soon because of prolonged inactivity label Jun 9, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jun 9, 2025

Walkthrough

Adds a 24‑bit uncompressed BMP loader and shared ~64KB buffer, a POV renderer that maps BMP rows to an LED strip, integrates BMP‑based POV image effect into the pov_display usermod (replacing PNG decoding), adds usage docs, and removes the PNGdec dependency.

Changes

Cohort / File(s) Summary
Documentation
usermods/pov_display/README.md
New README describing the "POV Image" effect: image preparation (rotate 90°), 24‑bit uncompressed BMP requirement, upload and absolute path usage, RPM guidance, RAM (~64KB) constraints, troubleshooting, and safety notes.
BMP image handling
usermods/pov_display/bmpimage.h, usermods/pov_display/bmpimage.cpp
New BMPimage class and implementation: validates/parses 24‑bit uncompressed BMPs, supports top‑down/bottom‑up heights, computes 4‑byte row padding, enforces size fit to fixed BUF_SIZE (~64KB), exposes init/clear/load/unload, line() and pixelColor() accessors, stores filename/metadata, and exposes a shared RAM buffer as extern byte * _buffer.
POV core
usermods/pov_display/pov.h, usermods/pov_display/pov.cpp
New POV class: holds a BMPimage, showLine() renders a 3‑byte BGR line to LEDs (converts to CRGB), loadImage() to init/load BMP, showNextLine() to advance/wrap rendering, plus accessors currentImage(), getFilename(), and timeSinceUpdate().
Usermod integration & effect
usermods/pov_display/pov_display.cpp
Replaces PNG decoding flow with POV/BMP rendering: adds global POV s_pov, loads segment names ending in .bmp, throttles load attempts, moves effect descriptor to file scope, refactors PovDisplayUsermod to constructor/stateful lifecycle (setup/loop/getId), removes PNGdec usage and PNG file logic, and updates global usermod instantiation.
Build config / manifest
usermods/pov_display/library.json, platformio_override.sample.ini
Removed bitbank2/PNGdec dependency from the pov_display manifest and removed a commented PNGdec lib_deps entry in the platformio override sample; added "platforms": ["espressif32"] to library.json.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • softhack007
  • DedeHai
  • willmmiles

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ 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 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.

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/pov_display/README.md (1)

3-3: Minor writing improvements and URL formatting.

Consider these improvements for better readability:

-The whole goal of the project is to use images like the one found on this website : https://visualpoi.zone/
+The whole goal of the project is to use images like the one found on this website: [https://visualpoi.zone/](https://visualpoi.zone/)
-The usermod also handles mirroring, which means you can "fold" a led strip in two to get the same image displayed on both side.
+The usermod also handles mirroring, which means you can "fold" an LED strip in two to get the same image displayed on both sides.
-The effect will first draw the first line of your image, then very rapidly display the second line, etc, until the last line, and then it will loop to the first line.
+The effect will first draw the first line of your image, then very rapidly display the second line, etc., until the last line, and then it will loop to the first line.
-To help you to use this project you could also use the GifPlayer from https://github.com/Manut38/WLED-GIFPlayer-html
-you would have to update the effect ID in the html file to reflect the effect ID of the "POV Image" effect though.
+To help you to use this project, you could also use the GifPlayer from [https://github.com/Manut38/WLED-GIFPlayer-html](https://github.com/Manut38/WLED-GIFPlayer-html).
+You would have to update the effect ID in the HTML file to reflect the effect ID of the "POV Image" effect, though.

Also applies to: 9-9, 10-10, 17-18

🧰 Tools
🪛 markdownlint-cli2 (0.17.2)

3-3: Bare URL used
null

(MD034, no-bare-urls)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 48958cc and ebd0000.

📒 Files selected for processing (3)
  • usermods/pov_display/README.md (1 hunks)
  • usermods/pov_display/usermod_pov_display.h (4 hunks)
  • wled00/usermods_list.cpp (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
wled00/usermods_list.cpp (1)
wled00/um_manager.cpp (2)
  • add (65-70)
  • add (65-65)
🪛 LanguageTool
usermods/pov_display/README.md

[grammar] ~9-~9: Did you mean “LED” (= diode, light)?
Context: ...mirroring, which means you can "fold" a led strip in two to get the same image disp...

(LED)


[style] ~10-~10: In American English, abbreviations like “etc.” require a period.
Context: ...n very rapidly display the second line, etc, until the last line, and then it will ...

(ETC_PERIOD)


[typographical] ~18-~18: It seems that a comma is missing.
Context: ... the effect ID of the "POV Image" effect though.

(THOUGH_COMMA)

🪛 markdownlint-cli2 (0.17.2)
usermods/pov_display/README.md

3-3: Bare URL used
null

(MD034, no-bare-urls)


17-17: Bare URL used
null

(MD034, no-bare-urls)

🔇 Additional comments (7)
wled00/usermods_list.cpp (1)

476-476: Constructor parameters align with usermod changes.

The updated constructor call correctly matches the new PovDisplayUsermod constructor signature that now accepts a name and enabled flag.

usermods/pov_display/README.md (1)

1-18: Great addition of missing documentation!

This README provides essential documentation for the POV Display usermod that was previously missing. The explanation of the persistence of vision effect and usage instructions will be very helpful for users.

🧰 Tools
🪛 LanguageTool

[grammar] ~9-~9: Did you mean “LED” (= diode, light)?
Context: ...mirroring, which means you can "fold" a led strip in two to get the same image disp...

(LED)


[style] ~10-~10: In American English, abbreviations like “etc.” require a period.
Context: ...n very rapidly display the second line, etc, until the last line, and then it will ...

(ETC_PERIOD)


[typographical] ~18-~18: It seems that a comma is missing.
Context: ... the effect ID of the "POV Image" effect though.

(THOUGH_COMMA)

🪛 markdownlint-cli2 (0.17.2)

3-3: Bare URL used
null

(MD034, no-bare-urls)


17-17: Bare URL used
null

(MD034, no-bare-urls)

usermods/pov_display/usermod_pov_display.h (5)

5-8: Good refactoring to avoid naming conflicts.

The renaming of global variables (pngpng_decoder, fpov_image) and the "Pov" prefix for functions addresses the feedback about potential naming conflicts with generic names.


9-16: Consistent function renaming implementation.

The file operation functions are consistently renamed with the "Pov" prefix and properly use the renamed global variables.


58-60: Proper file path construction.

The file path construction correctly prepends a "/" to the segment name to create a valid filesystem path.


69-85: Constructor follows WLED usermod patterns.

The new constructor accepting name and enabled parameters follows WLED usermod conventions and addresses the feedback about usermod initialization. The protected members also follow appropriate naming patterns.


7-7: Effect name maintains uppercase convention.

The effect name "POV Image" correctly maintains the uppercase convention used by other effects in WLED, consistent with previous feedback.

@DedeHai
Copy link
Collaborator

DedeHai commented Jun 9, 2025

@Liliputech can you please update it to latest main?

@github-actions github-actions bot removed the stale This issue will be closed soon because of prolonged inactivity label Jun 10, 2025
this usermod adds a new effect called "POV Image".
To get it to work:
- read the README :)
- upload a bmp image to the ESP filesystem using "/edit" url.
- select "POV Image" effect.
- set the filename (ie: "/myimage.bmp") as segment name.
- rotate the segment at approximately 20 RPM.
- enjoy the show!
@Liliputech
Copy link
Contributor Author

Hi sorry for the delay, I've reworked the usermod to make it better, and also rebased on current main.

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

🧹 Nitpick comments (11)
usermods/pov_display/pov.h (2)

10-15: Improve const-correctness of showLine

The line buffer is not modified; accept it as const to prevent accidental writes and allow passing const sources.

Apply this diff (paired with pov.cpp):

-        void showLine(byte * line, uint16_t size);
+        void showLine(const byte * line, uint16_t size);

16-18: Fix typos in comments and tighten signatures

  • Spelling: “Returns”, “returns”.
  • Prefer const char* for filename access; returning non-const exposes internal buffer to mutation.

Apply this diff:

-        /* Reads from file an image and making it current image */
-        bool loadImage(char * filename);
+        /* Reads an image from file and makes it the current image */
+        bool loadImage(const char * filename);

         /* Show next line of active image
-           Retunrs the index of next line to be shown (not yet shown!)
-           If it retunrs 0, it means we have completed showing the image and
+           Returns the index of the next line to be shown (not yet shown!)
+           If it returns 0, it means we have completed showing the image and
             next call will start again
         */
         int16_t showNextLine();
...
-        char * getFilename() {return image.getFilename();}
+        const char * getFilename() {return image.getFilename();}

Also applies to: 32-32, 20-22

usermods/pov_display/bmpimage.h (3)

6-23: Minor doc typos and clarity

Polish comments: fix “passign/usign”, clarify single shared buffer usage.

Apply this diff:

- * To initialize, call init(), passign to it name of a bitmap file
+ * To initialize, call init() passing it the name of a bitmap file
...
- * For performance reasons, before actually usign the image, you need to load
+ * For performance reasons, before actually using the image, you need to load
...
- * All load() operations use the same reserved buffer in RAM, so you can only
+ * All load() operations use a single shared buffer in RAM, so you can only

36-36: Make filename accessor const-correct

Avoid exposing a mutable pointer to internal storage.

Apply this diff:

-        char * getFilename() {return filename;};
+        const char * getFilename() const {return filename;};

48-49: Avoid exporting the global image buffer

Leaking _buffer via header couples unrelated code to this implementation detail and risks name collisions. Keep the buffer internal to the translation unit.

Apply this diff (and make the definition in bmpimage.cpp ‘static’):

-extern byte _buffer[];

And in bmpimage.cpp:

-byte _buffer[BUF_SIZE];
+static byte _buffer[BUF_SIZE];
usermods/pov_display/bmpimage.cpp (1)

108-114: Bounds-check line index before returning a row pointer

Defensive check avoids returning pointers past the buffer if misused.

Apply this diff:

-byte* BMPimage::line(uint16_t n){
-    if (_loaded) {
-        return (_buffer+n*_rowSize);
-    } else {
-        return NULL;
-    }
-}
+byte* BMPimage::line(uint16_t n){
+    if (!_loaded) return NULL;
+    if (n >= _height) return NULL;
+    return (_buffer + n * _rowSize);
+}
usermods/pov_display/pov_display.cpp (5)

2-2: Consider compile-gating the usermod include to avoid accidental builds when the usermod is disabled

If pov_display isn’t enabled, including "pov.h" can still trigger compilation in some setups. Wrapping the file (or at least the include) in a USERMOD_POV_DISPLAY guard makes the build more robust across different PlatformIO configs.

Example:

+#ifdef USERMOD_POV_DISPLAY
 #include "pov.h"

And add at the very end of the file:

#endif // USERMOD_POV_DISPLAY

4-4: Verify effect metadata string flags are correct for 1D-only usage

"POV Image@!;;;;" differs from the commonly used metadata patterns. If the previous variant ended with “;1” to indicate 1D or other flags, make sure removing it doesn’t regress UI controls or capability flags in WLED. If 1D-only is intended, double-check the last field semantics.

Would you like me to cross-check the effect string format against the current WLED effect metadata spec and propose the exact flags?


6-6: Limit the symbol scope of the global pov to avoid ODR/linkage collisions

Make pov internal to this translation unit. This avoids accidental external linkage and name collisions with other usermods.

Apply this diff:

-POV pov;
+static POV pov;

29-33: Use an initializer list for the constructor

Cleaner and avoids double assignments.

Apply this diff:

-  PovDisplayUsermod(const char *name, bool enabled) {
-    this->_name=name;
-    this->enabled = enabled;
-  }
+  PovDisplayUsermod(const char *name, bool enabled)
+    : enabled(enabled), _name(name) {}

41-50: Usermod enabled flag doesn’t gate the effect function

The effect is registered regardless of enabled state, and mode_pov_image runs independently of enabled. If “enabled=false” is intended to fully disable behavior, either:

  • Gate registration in setup() behind enabled, or
  • Have mode_pov_image check a shared flag (e.g., expose a function or static in this TU) and early-return when disabled.

I can wire mode_pov_image to a TU-scoped static volatile bool s_enabled that mirrors the usermod state if you want a minimal change.

📜 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 ebd0000 and 41f31b8.

📒 Files selected for processing (7)
  • usermods/pov_display/README.md (1 hunks)
  • usermods/pov_display/bmpimage.cpp (1 hunks)
  • usermods/pov_display/bmpimage.h (1 hunks)
  • usermods/pov_display/library.json (0 hunks)
  • usermods/pov_display/pov.cpp (1 hunks)
  • usermods/pov_display/pov.h (1 hunks)
  • usermods/pov_display/pov_display.cpp (1 hunks)
💤 Files with no reviewable changes (1)
  • usermods/pov_display/library.json
🧰 Additional context used
🧬 Code Graph Analysis (3)
usermods/pov_display/bmpimage.h (2)
usermods/pov_display/bmpimage.cpp (10)
  • load (91-106)
  • load (91-91)
  • line (108-114)
  • line (108-108)
  • pixelColor (116-131)
  • pixelColor (116-116)
  • init (18-79)
  • init (18-18)
  • clear (81-89)
  • clear (81-81)
usermods/pov_display/pov.h (1)
  • getFilename (32-32)
usermods/pov_display/pov.h (3)
usermods/pov_display/pov.cpp (7)
  • POV (3-3)
  • showLine (5-22)
  • showLine (5-5)
  • loadImage (24-29)
  • loadImage (24-24)
  • showNextLine (31-38)
  • showNextLine (31-31)
usermods/pov_display/bmpimage.cpp (2)
  • line (108-114)
  • line (108-108)
usermods/pov_display/bmpimage.h (1)
  • getFilename (36-36)
usermods/pov_display/pov.cpp (3)
usermods/pov_display/pov.h (1)
  • POV (6-38)
usermods/pov_display/bmpimage.cpp (2)
  • line (108-114)
  • line (108-108)
usermods/pov_display/pov_display.cpp (1)
  • strip (34-37)
🪛 LanguageTool
usermods/pov_display/README.md

[grammar] ~6-~6: There might be a mistake here.
Context: ... - resize your image, the height should be same number of pixels as your led strip...

(QB_NEW_EN)


[grammar] ~6-~6: There might be a mistake here.
Context: ...same number of pixels as your led strip. - rotate your image 90 degrees clockwise (...

(QB_NEW_EN)


[grammar] ~8-~8: There might be a mistake here.
Context: ...to the ESP filesystem using "/edit" url. - select "POV Image" effect. - set the seg...

(QB_NEW_EN)


[grammar] ~9-~9: There might be a mistake here.
Context: .../edit" url. - select "POV Image" effect. - set the segment name with the absolute p...

(QB_NEW_EN)


[grammar] ~10-~10: There might be a mistake here.
Context: ... path of the image (ie: "/myimage.bmp"). - rotate the segment at approximately 20 R...

(QB_NEW_EN)


[grammar] ~11-~11: There might be a mistake here.
Context: ...ate the segment at approximately 20 RPM. - enjoy the show!

(QB_NEW_EN)

🪛 markdownlint-cli2 (0.17.2)
usermods/pov_display/README.md

1-1: No space after hash on atx style heading

(MD018, no-missing-space-atx)

⏰ 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). (7)
  • GitHub Check: wled_build / Build Environments (esp32_wrover)
  • GitHub Check: wled_build / Build Environments (usermods)
  • GitHub Check: wled_build / Build Environments (esp32s3dev_8MB_opi)
  • GitHub Check: wled_build / Build Environments (esp32s3_4M_qspi)
  • GitHub Check: wled_build / Build Environments (esp32dev)
  • GitHub Check: wled_build / Build Environments (esp32s3dev_16MB_opi)
  • GitHub Check: wled_build / Build Environments (lolin_s2_mini)
🔇 Additional comments (7)
usermods/pov_display/pov.cpp (1)

31-38: Line-stepping logic is sound

showNextLine correctly wraps at image.height(), returns the next line index, and delegates size/row padding handling to showLine. Looks good.

usermods/pov_display/bmpimage.cpp (1)

18-61: Header parsing is reasonable for 24-bit uncompressed BMPs

Little-endian helpers and checks for signature, planes, depth (24), compression (0), and 4-byte row padding are correct for the targeted format.

usermods/pov_display/pov_display.cpp (5)

34-37: Confirm effect ID stability and duplicates when registering with 255

Hard-coding 255 can collide with other custom effects or future core additions. If the API supports auto-assignment or symbolic constants, prefer that. Also ensure setup() isn’t called multiple times (e.g., after a soft re-init) to avoid duplicate registration.

Would you like me to scan the tree to verify there are no other addEffect(255, ...) registrations and that 255 is free in current main?


52-54: LGTM: clean no-op on ESP-NOW messages

Returning false is appropriate if no handling is required.


56-58: LGTM: stable usermod ID

Using USERMOD_ID_POV_DISPLAY keeps it consistent with the core registry.


61-62: LGTM: static instance and registration

Static construction and REGISTER_USERMOD usage are consistent with typical WLED usermod patterns.


2-2: PNGdec dependency removed; no conflicting addEffect(255) usages

  • PNGdec only appears as a commented entry in platformio_override.sample.ini; it’s not in the active platformio.ini or anywhere else.
  • All calls to strip.addEffect(255, …) across usermods use 255 as the “auto-assign” sentinel for custom effects—this is by design and does not create conflicts.

No further action required.

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
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

♻️ Duplicate comments (1)
usermods/pov_display/README.md (1)

1-3: README added and core usage clarified — nice improvement

This addresses earlier feedback to document the usermod, clarifies BMP format constraints, and outlines step-by-step usage. Good job landing this.

🧹 Nitpick comments (4)
usermods/pov_display/README.md (4)

10-10: Clarify absolute path and case sensitivity for the filename

Explicitly call out that the path must start with “/” and is case-sensitive to prevent common misconfigurations.

-- Set the segment name to the absolute filesystem path of the image (e.g., “/myimage.bmp”).
+- Set the segment name to the absolute filesystem path of the image (e.g., “/myimage.bmp”).
+  The path is case-sensitive and must start with “/”.

11-12: Provide quick tuning guidance for RPM

A short note on tuning rotation speed helps users get from “it shows something” to “it looks correct”.

-- Rotate the segment at approximately 20 RPM.
+- Rotate the segment at approximately 20 RPM.
+  Tune as needed so that one full revolution maps to the image width (if the image appears stretched or compressed, adjust RPM slightly).

14-17: Quantify the 64 KB image limit with concrete examples and a mirroring tip

Concrete numbers reduce guesswork. Also add a quick fix if users see mirrored text.

 Notes:
 - Only 24-bit uncompressed BMP files are supported.
-- The image must fit into ~64 KB of RAM (width × height × 3 bytes, plus row padding to a 4-byte boundary).
+- The image must fit into ~64 KB of RAM (width × height × 3 bytes, plus row padding to a 4‑byte boundary).
+- Examples (approximate, excluding row padding):
+  - 128×128 (49,152 bytes) fits.
+  - 160×160 (76,800 bytes) does NOT fit.
+  - 96×192 (55,296 bytes) fits; padding may add a small overhead.
 - The path must be absolute.
+ - If the rendered image appears mirrored or upside‑down, rotate 90° the other way or flip horizontally in your editor and try again.

1-17: Add “Requirements”, “Troubleshooting”, and “Safety” sections

A few concise sections make first‑time setup smoother and nudge users toward safe operation of rotating rigs.

 ## POV Display usermod
@@
 - Enjoy the show!
 
 Notes:
@@
 - The path must be absolute.
+
+### Requirements
+- 1D rotating LED strip/segment (POV setup). Ensure the segment length equals the number of physical LEDs.
+- BMP image saved as 24‑bit, uncompressed (no alpha, no palette).
+- Sufficient free RAM (~64 KB) for the image buffer.
+
+### Troubleshooting
+- Nothing displays: verify the file exists at the exact absolute path (case‑sensitive) and is a 24‑bit uncompressed BMP.
+- Garbled colors or wrong orientation: re‑export as 24‑bit BMP and retry the rotation/flip guidance above.
+- Image too large: reduce width and/or height until it fits within ~64 KB (see examples).
+- Path issues: confirm you uploaded the file via the “/edit” URL and can see it in the filesystem browser.
+
+### Safety
+- Secure the rotating assembly and keep clear of moving parts.
+- Balance the strip/hub to minimize vibration before running at speed.
📜 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 41f31b8 and a5d1c37.

📒 Files selected for processing (3)
  • usermods/pov_display/README.md (1 hunks)
  • usermods/pov_display/bmpimage.cpp (1 hunks)
  • usermods/pov_display/pov.cpp (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • usermods/pov_display/bmpimage.cpp
  • usermods/pov_display/pov.cpp
🧰 Additional context used
🪛 LanguageTool
usermods/pov_display/README.md

[grammar] ~3-~3: Ensure spelling is correct
Context: ## POV Display usermod This usermod adds a new effect called “POV Image”. ...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

⏰ 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). (1)
  • GitHub Check: wled_build / Build Environments (usermods)

@Liliputech Liliputech requested a review from DedeHai August 24, 2025 14:20
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

♻️ Duplicate comments (1)
usermods/pov_display/pov_display.cpp (1)

10-24: Resolved: robust .bmp ends-with check and null-guard implemented

Nice fix. The ends-with, case-insensitive check and null-guard for mainseg.name address the fragility flagged earlier. Good adherence to the suggested approach.

🧹 Nitpick comments (6)
usermods/pov_display/pov_display.cpp (6)

6-6: Limit global symbol scope: make POV instance internal and less collision-prone

Prior reviews called out collisions from generic globals. The identifier pov is short and global; recommend internal linkage or a more specific name.

Apply this to keep the symbol TU-local and avoid clashes:

-POV pov;
+static POV s_pov;

And update uses:

-  const char* current = pov.getFilename();
+  const char* current = s_pov.getFilename();
@@
-     pov.showNextLine();
+     s_pov.showNextLine();
@@
-  pov.loadImage(segName);
+  s_pov.loadImage(segName);

Also applies to: 26-30, 32-33


32-33: Throttle repeated load attempts to avoid tight FS loops on missing/corrupt files

If loadImage fails (file missing/corrupt), this branch will be hit every frame, hammering the FS and starving other tasks. Throttle attempts.

Minimal in-function backoff:

-  pov.loadImage(segName);
+  static unsigned long s_lastLoadAttemptMs = 0;
+  unsigned long nowMs = millis();
+  // Retry at most twice per second if the image is not yet loaded.
+  if (nowMs - s_lastLoadAttemptMs < 500) return FRAMETIME;
+  s_lastLoadAttemptMs = nowMs;
+  pov.loadImage(segName);

If you adopt the s_pov rename above, switch pov.* to s_pov.* here as well.


36-41: Trim or use unused members (_name, initDone) to reduce footprint

  • _name is stored but not used anywhere.
  • initDone is only set, never read.

Either use them or drop to keep the usermod lean.

Suggested diff (also touches setup at Line 51):

 class PovDisplayUsermod : public Usermod {
 protected:
   bool enabled = false; //WLEDMM
-  const char *_name; //WLEDMM
-  bool initDone = false; //WLEDMM
+  // const char *_name; //WLEDMM (unused)
+  // bool initDone = false; //WLEDMM (unused)
   unsigned long lastTime = 0; //WLEDMM
 public:

And in setup:

-    initDone=true;
+    // initDone removed (unused)

44-47: Prefer member-initializer list for clarity and correct init order

Cleaner and avoids temporary default-inits.

-  PovDisplayUsermod(const char *name, bool enabled) {
-    this->_name=name;
-    this->enabled = enabled;
-  }
+  PovDisplayUsermod(const char *name, bool enabled)
+    : enabled(enabled) /*, _name(name)*/ {}

If you keep _name, include it in the initializer list as shown in the comment.


55-65: Loop guard pattern is fine; consider removing dead debug to keep code tight

The isUpdating guard and heartbeat are fine. The commented Serial println can be dropped to reduce noise.


67-69: Avoid unused-parameter warnings in onEspNowMessage

Mark parameters as unused to keep builds warning-clean across toolchains.

-  bool onEspNowMessage(uint8_t* sender, uint8_t* payload, uint8_t len) override {
-    return false;
-  }
+  bool onEspNowMessage(uint8_t* sender, uint8_t* payload, uint8_t len) override {
+    (void)sender; (void)payload; (void)len;
+    return false;
+  }
📜 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 aeb19e8 and 0ce9ac6.

📒 Files selected for processing (3)
  • usermods/pov_display/pov.cpp (1 hunks)
  • usermods/pov_display/pov.h (1 hunks)
  • usermods/pov_display/pov_display.cpp (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • usermods/pov_display/pov.h
  • usermods/pov_display/pov.cpp
🧰 Additional context used
🧬 Code graph analysis (1)
usermods/pov_display/pov_display.cpp (2)
usermods/TetrisAI_v2/TetrisAI_v2.cpp (1)
  • strip (236-239)
usermods/PWM_fan/PWM_fan.cpp (1)
  • enabled (215-223)
⏰ 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). (1)
  • GitHub Check: wled_build / Build Environments (usermods)
🔇 Additional comments (4)
usermods/pov_display/pov_display.cpp (4)

4-4: Effect data string looks consistent

The PROGMEM data string for the effect follows existing usermod patterns. No issues.


49-52: Effect registration looks standard

Registering the effect in setup with id 255 mirrors other usermods (e.g., TetrisAI). No concerns.


71-73: getId implementation is standard

No issues.


76-77: Instantiation and registration look correct; default disabled is a sensible choice

Static instance + registration pattern matches other usermods. No concerns.

@DedeHai
Copy link
Collaborator

DedeHai commented Aug 24, 2025

Thanks for the update.
I have no way to test this. Can you extend the readme a little? like what setup is needed (LED type? how does the image relate to LEDs etc.). A video of the UM in action would be helpful too.

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

♻️ Duplicate comments (1)
usermods/pov_display/pov_display.cpp (1)

9-24: Nice hardening: null‑guard and case‑insensitive .bmp ends‑with check

This addresses the previous fragility around strstr(".bmp") and potential null dereference of the current filename. Looks good.

Also applies to: 26-30

🧹 Nitpick comments (8)
usermods/pov_display/README.md (4)

7-16: Add a short “Build/Enable” section so users know how to compile this usermod

Right now the README assumes the effect is present. Please add explicit build steps (PlatformIO build_flags, macro) so newcomers can enable it without digging into WLED docs.

Apply this patch near the top (right after the heading) to add a concise section:

@@
 ## POV Display usermod
 
+### Build/Enable
+- Build WLED with this usermod enabled. If you use PlatformIO, add to your environment in `platformio_override.ini`:
+  - `build_flags = -D USERMOD_POV_DISPLAY`
+- Recompile and flash. After enabling, the “POV Image” effect appears in the effects list.
+- No external PNGdec library is required; BMP decoding is built-in.
+
 To get it working:

18-27: Clarify extension handling, main‑segment usage, and absolute paths

The code accepts “.bmp” case‑insensitively and currently reads the file path from the main segment’s name. Making this explicit prevents confusion in multi‑segment setups.

Apply:

 Notes:
-- Only 24-bit uncompressed BMP files are supported.
+- Only 24-bit uncompressed BMP files are supported. Filenames must end with “.bmp” (case-insensitive; “.BMP” is fine).
 - The image must fit into ~64 KB of RAM (width × height × 3 bytes, plus row padding to a 4-byte boundary).
@@
-- The path must be absolute.
+- The path must be absolute.
+- The POV Image effect currently reads the image path from the main segment’s name. Use the main segment for POV Image, or ensure other segments are disabled.

20-25: Add the exact BMP row-size formula to help users size images correctly

You already mention 4‑byte row padding. Including the canonical formula removes guesswork.

-- The image must fit into ~64 KB of RAM (width × height × 3 bytes, plus row padding to a 4-byte boundary).
+- The image must fit into ~64 KB of RAM (width × height × 3 bytes, plus row padding to a 4‑byte boundary; rowSize = ((24*width + 31) / 32) * 4).

33-37: Troubleshooting: add a tip for uppercase extensions and main‑segment requirement

Small clarity boost for common pitfalls.

 - Nothing displays: verify the file exists at the exact absolute path (case‑sensitive) and is a 24‑bit uncompressed BMP.
+- Nothing displays: verify the file exists at the exact absolute path (case‑sensitive), ends with “.bmp” or “.BMP”, and is a 24‑bit uncompressed BMP. Confirm the filename is set on the main segment.
usermods/pov_display/pov_display.cpp (4)

9-14: Use the current segment instead of the main segment for better multi‑segment behavior

Right now the effect reads the path from the main segment’s name, which can be surprising if the effect is applied to a non‑main segment. Using the active rendering segment keeps behavior consistent with other WLED effects.

Apply:

-  Segment& mainseg = strip.getMainSegment();
-  const char* segName = mainseg.name;
+  Segment& seg = SEGMENT; // use the current segment being rendered
+  const char* segName = seg.name;
   if (!segName) {
      return FRAMETIME;
    }

If you intentionally want “main segment only,” please keep this code and explicitly state that in the README (suggested in my README comment).


32-38: Skip repeated load attempts when the file is missing to reduce FS churn

A lightweight existence check avoids hammering the filesystem for non‑existent paths between retries.

   // Retry at most twice per second if the image is not yet loaded.
   if (nowMs - s_lastLoadAttemptMs < 500) return FRAMETIME;
   s_lastLoadAttemptMs = nowMs;
+  // Avoid spamming FS if the file doesn't exist
+  if (!WLED_FS.exists(segName)) return FRAMETIME;
   s_pov.loadImage(segName);

41-68: Trim unused usermod state (enabled/initDone/lastTime) or make it purposeful

The usermod’s loop is effectively a no‑op and the extra state adds noise. Either remove the unused members and the loop override, or wire “enabled” to a config flag/UM menu.

Minimal cleanup option:

 class PovDisplayUsermod : public Usermod {
 protected:
-  bool enabled = false; //WLEDMM
-  const char *_name; //WLEDMM
-  bool initDone = false; //WLEDMM
-  unsigned long lastTime = 0; //WLEDMM
+  const char *_name; //WLEDMM
 public:
@@
   void loop() override {
-    // if usermod is disabled or called during strip updating just exit
-    // NOTE: on very long strips strip.isUpdating() may always return true so update accordingly
-    if (!enabled || strip.isUpdating()) return;
-
-    // do your magic here
-    if (millis() - lastTime > 1000) {
-      lastTime = millis();
-    }
+    if (strip.isUpdating()) return;
   }

Or, if you prefer to keep the fields for MoonModules conventions, mark them as [[maybe_unused]] to avoid warnings.


74-75: Constructor flag is misleading; the usermod registers the effect regardless

Since setup() adds the effect unconditionally and loop() is a no‑op, passing false for enabled doesn’t change behavior. Consider setting it true or removing the flag to avoid confusion.

-static PovDisplayUsermod pov_display("POV Display", false);
+static PovDisplayUsermod pov_display("POV Display", true);
📜 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 0ce9ac6 and 4ef95ee.

⛔ Files ignored due to path filters (1)
  • usermods/pov_display/pov_display.gif is excluded by !**/*.gif
📒 Files selected for processing (3)
  • platformio_override.sample.ini (0 hunks)
  • usermods/pov_display/README.md (1 hunks)
  • usermods/pov_display/pov_display.cpp (1 hunks)
💤 Files with no reviewable changes (1)
  • platformio_override.sample.ini
🧰 Additional context used
🧬 Code graph analysis (1)
usermods/pov_display/pov_display.cpp (2)
usermods/TetrisAI_v2/TetrisAI_v2.cpp (1)
  • strip (236-239)
usermods/Animated_Staircase/Animated_Staircase.cpp (1)
  • enabled (345-352)
🪛 LanguageTool
usermods/pov_display/README.md

[grammar] ~25-~25: There might be a mistake here.
Context: ...rizontally in your editor and try again. - The path must be absolute. ### Requirem...

(QB_NEW_EN)


[grammar] ~30-~30: There might be a mistake here.
Context: ...it, uncompressed (no alpha, no palette). - Sufficient free RAM (~64 KB) for the ima...

(QB_NEW_EN)


[grammar] ~33-~33: There might be a mistake here.
Context: ...r the image buffer. ### Troubleshooting - Nothing displays: verify the file exists...

(QB_NEW_EN)


[grammar] ~34-~34: There might be a mistake here.
Context: ...itive) and is a 24‑bit uncompressed BMP. - Garbled colors or wrong orientation: re‑...

(QB_NEW_EN)


[grammar] ~35-~35: There might be a mistake here.
Context: ... retry the rotation/flip guidance above. - Image too large: reduce width and/or hei...

(QB_NEW_EN)

⏰ 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). (12)
  • GitHub Check: wled_build / Build Environments (esp32_eth)
  • GitHub Check: wled_build / Build Environments (usermods)
  • GitHub Check: wled_build / Build Environments (esp32s3_4M_qspi)
  • GitHub Check: wled_build / Build Environments (esp32_wrover)
  • GitHub Check: wled_build / Build Environments (esp32c3dev)
  • GitHub Check: wled_build / Build Environments (esp32s3dev_16MB_opi)
  • GitHub Check: wled_build / Build Environments (lolin_s2_mini)
  • 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 (nodemcuv2_compat)
  • GitHub Check: wled_build / Build Environments (esp32dev)
  • GitHub Check: wled_build / Build Environments (esp01_1m_full_160)

@Liliputech
Copy link
Contributor Author

Thanks for the update. I have no way to test this. Can you extend the readme a little? like what setup is needed (LED type? how does the image relate to LEDs etc.). A video of the UM in action would be helpful too.

I've addressed this comment, added a small gif image to show it working in motion, added some information to the readme, fixed all suggestions from coderabbit :)

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

♻️ Duplicate comments (1)
usermods/pov_display/README.md (1)

7-7: Fix Markdown heading spacing (MD018).

Add a space after the hashes.

Apply this diff:

-###How does it work?
+### How does it work?
🧹 Nitpick comments (2)
usermods/pov_display/README.md (2)

20-21: Remove duplicate note about absolute path.

Line 20 already states case sensitivity and leading “/”. The separate “The path must be absolute.” repeats the same rule.

Apply this diff:

-- The path must be absolute.

Also applies to: 33-33


35-39: Call out board/memory support explicitly (ESP32 vs ESP8266).

Given the ~64 KB image buffer requirement, clarify recommended/unsupported boards to prevent confusion.

Apply this diff:

 ### Requirements
 - 1D rotating LED strip/segment (POV setup). Ensure the segment length equals the number of physical LEDs.
+- ESP32 build recommended; ESP8266 usually lacks sufficient free RAM for the ~64 KB image buffer.
 - BMP image saved as 24‑bit, uncompressed (no alpha, no palette).
 - Sufficient free RAM (~64 KB) for the image buffer.

If ESP8266 can be supported with smaller images, adjust the wording to “ESP32 recommended; ESP8266 works only with very small images” and add the tested max dimensions.

📜 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 4ef95ee and 4cb6e8f.

📒 Files selected for processing (1)
  • usermods/pov_display/README.md (1 hunks)
🧰 Additional context used
🪛 LanguageTool
usermods/pov_display/README.md

[grammar] ~8-~8: There might be a mistake here.
Context: ...f pixel from an image stored on the ESP. It will display the image row after row ...

(QB_NEW_EN)


[grammar] ~10-~10: Ensure spelling is correct
Context: ...image floating in the air thanks to the persistance of vision. It only works with RGB leds,...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[grammar] ~10-~10: There might be a mistake here.
Context: ...air thanks to the persistance of vision. It only works with RGB leds, without gro...

(QB_NEW_EN)


[grammar] ~11-~11: Ensure spelling is correct
Context: ...y works with RGB leds, without grouping nor spacing. The best results are obtained ...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)


[grammar] ~11-~11: There might be a mistake here.
Context: ... RGB leds, without grouping nor spacing. The best results are obtained with high-...

(QB_NEW_EN)


[grammar] ~32-~32: There might be a mistake here.
Context: ...rizontally in your editor and try again. - The path must be absolute. ### Requirem...

(QB_NEW_EN)


[grammar] ~37-~37: There might be a mistake here.
Context: ...it, uncompressed (no alpha, no palette). - Sufficient free RAM (~64 KB) for the ima...

(QB_NEW_EN)


[grammar] ~40-~40: There might be a mistake here.
Context: ...r the image buffer. ### Troubleshooting - Nothing displays: verify the file exists...

(QB_NEW_EN)


[grammar] ~41-~41: There might be a mistake here.
Context: ...itive) and is a 24‑bit uncompressed BMP. - Garbled colors or wrong orientation: re‑...

(QB_NEW_EN)


[grammar] ~42-~42: There might be a mistake here.
Context: ... retry the rotation/flip guidance above. - Image too large: reduce width and/or hei...

(QB_NEW_EN)

🪛 markdownlint-cli2 (0.17.2)
usermods/pov_display/README.md

7-7: No space after hash on atx style heading

(MD018, no-missing-space-atx)

⏰ 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). (2)
  • GitHub Check: wled_build / Build Environments (usermods)
  • GitHub Check: wled_build / Build Environments (esp32s3dev_8MB_opi)
🔇 Additional comments (1)
usermods/pov_display/README.md (1)

1-6: Nice doc pass; aligns with BMP-only POV flow.

Good job documenting the workflow (rotate, upload via /edit, absolute path, 24‑bit BMP) and adding visuals. This addresses prior feedback about PNGdec and clarifies constraints.

@DedeHai
Copy link
Collaborator

DedeHai commented Aug 25, 2025

looks good.
does this work on all platforms including ESP8266?
if ESP8266 does not have nough RAM or is too slow it should be excluded with an #ifdef / #error

@willmmiles
Copy link
Member

looks good. does this work on all platforms including ESP8266? if ESP8266 does not have nough RAM or is too slow it should be excluded with an #ifdef / #error

I'd prefer instead to specify the supported platform(s) in library.json. Avoid #ifdef wherever possible!

@Liliputech
Copy link
Contributor Author

looks good. does this work on all platforms including ESP8266? if ESP8266 does not have nough RAM or is too slow it should be excluded with an #ifdef / #error

I've restrained to esp32, maybe it could work on esp8266 but I don't have the hardware at hand.

Liliputech and others added 2 commits August 26, 2025 11:03
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
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

♻️ Duplicate comments (2)
usermods/pov_display/README.md (2)

7-7: Fix MD018: add a space after the heading hashes

Markdownlint flags “###How does it work?” (missing space). Please insert a space.

-###How does it work?
+### How does it work?

10-12: Use consistent terminology: “LED strip” (not “pixel segment”)

Earlier feedback clarified we rotate the LED strip, not a segment. Line 10 still says “pixel segment.” Suggest aligning wording.

-If you move the pixel segment at the right speed, you will see the full image floating in the air thanks to the persistence of vision.
+If you move the LED strip at the right speed, you will see the full image floating in the air thanks to the persistence of vision.
🧹 Nitpick comments (5)
usermods/pov_display/README.md (5)

17-23: Tighten upload/path bullets and mention the Speed slider for tuning

Combine the absolute-path and case-sensitive notes into one bullet to reduce repetition, and mention the Speed slider for practical RPM tuning.

-- Upload a BMP image (24-bit, uncompressed) to the ESP filesystem using the “/edit” URL.
+- Upload a BMP image (24‑bit, uncompressed) to the device filesystem via “/edit”.
 - Select the “POV Image” effect.
-- Set the segment name to the absolute filesystem path of the image (e.g., “/myimage.bmp”).
-- The path is case-sensitive and must start with “/”.
+- Set the segment name to the absolute, case‑sensitive filesystem path (must start with “/”), e.g., “/myimage.bmp”.
 - Rotate the pixel strip at approximately 20 RPM.
-- Tune as needed so that one full revolution maps to the image width (if the image appears stretched or compressed, adjust RPM slightly).
+- Tune as needed so that one full revolution maps to the image width. If the image appears stretched or compressed, adjust RPM slightly using the Speed slider.

25-34: Clarify memory math and remove duplicate “absolute path” note

  • Provide the exact row-stride formula for BMP padding.
  • Drop the duplicate absolute-path reminder already covered above.
 Notes:
 - Only 24-bit uncompressed BMP files are supported.
-- The image must fit into ~64 KB of RAM (width × height × 3 bytes, plus row padding to a 4-byte boundary).
+- Memory usage ≈ rowStride × height, where rowStride = ((width × 3 + 3) & ~3) bytes (rows are padded to a 4‑byte boundary). Aim to keep total ≤ ~64 KB.
 - Examples (approximate, excluding row padding):
   - 128×128 (49,152 bytes) fits.
   - 160×160 (76,800 bytes) does NOT fit.
   - 96×192 (55,296 bytes) fits; padding may add a small overhead.
-- If the rendered image appears mirrored or upside‑down, rotate 90° the other way or flip horizontally in your editor and try again.
-- The path must be absolute.
+- If the rendered image appears mirrored or upside‑down, rotate 90° counter‑clockwise or flip horizontally in your editor and try again.

35-39: State supported platforms explicitly (matches PR discussion)

Since the usermod targets ESP32 and ESP8266 is not supported/tested, call this out in Requirements to set expectations. Also aligns with reviewer requests.

 ### Requirements
 - 1D rotating LED strip/segment (POV setup). Ensure the segment length equals the number of physical LEDs.
+- Platform: ESP32 (tested). ESP8266 currently not supported.
 - BMP image saved as 24‑bit, uncompressed (no alpha, no palette).
 - Sufficient free RAM (~64 KB) for the image buffer.

If this is inaccurate, adjust to reflect the exact set of supported boards.


40-45: Add two common troubleshooting tips (2D mode and wrong file type)

Users often have 2D mapping enabled or accidentally upload PNG/JPG. Adding these bullets will prevent confusion.

 ### Troubleshooting
 - Nothing displays: verify the file exists at the exact absolute path (case‑sensitive) and is a 24‑bit uncompressed BMP.
 - Garbled colors or wrong orientation: re‑export as 24‑bit BMP and retry the rotation/flip guidance above.
 - Image too large: reduce width and/or height until it fits within ~64 KB (see examples).
 - Path issues: confirm you uploaded the file via the “/edit” URL and can see it in the filesystem browser.
+ - No output when using 2D: disable 2D matrix mapping; use a 1D segment with grouping=1 and spacing=0.
+ - Wrong file type: ensure the filename ends with .bmp (PNG/JPG are not supported).

46-48: Optional: add one more safety bullet

Minor but helpful.

 ### Safety
 - Secure the rotating assembly and keep clear of moving parts.
 - Balance the strip/hub to minimize vibration before running at speed.
+ - Wear eye protection and keep cables and clothing clear of the rotating path.
📜 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 4cb6e8f and 9275b6c.

📒 Files selected for processing (4)
  • usermods/pov_display/README.md (1 hunks)
  • usermods/pov_display/bmpimage.cpp (1 hunks)
  • usermods/pov_display/bmpimage.h (1 hunks)
  • usermods/pov_display/library.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • usermods/pov_display/bmpimage.h
  • usermods/pov_display/library.json
  • usermods/pov_display/bmpimage.cpp
🧰 Additional context used
🪛 LanguageTool
usermods/pov_display/README.md

[grammar] ~8-~8: There might be a mistake here.
Context: ... pixels from an image stored on the ESP. It displays the image row by row at a hi...

(QB_NEW_EN)


[grammar] ~32-~32: There might be a mistake here.
Context: ...rizontally in your editor and try again. - The path must be absolute. ### Requirem...

(QB_NEW_EN)


[grammar] ~37-~37: There might be a mistake here.
Context: ...it, uncompressed (no alpha, no palette). - Sufficient free RAM (~64 KB) for the ima...

(QB_NEW_EN)


[grammar] ~40-~40: There might be a mistake here.
Context: ...r the image buffer. ### Troubleshooting - Nothing displays: verify the file exists...

(QB_NEW_EN)


[grammar] ~41-~41: There might be a mistake here.
Context: ...itive) and is a 24‑bit uncompressed BMP. - Garbled colors or wrong orientation: re‑...

(QB_NEW_EN)


[grammar] ~42-~42: There might be a mistake here.
Context: ... retry the rotation/flip guidance above. - Image too large: reduce width and/or hei...

(QB_NEW_EN)

🪛 markdownlint-cli2 (0.17.2)
usermods/pov_display/README.md

7-7: No space after hash on atx style heading

(MD018, no-missing-space-atx)

🔇 Additional comments (1)
usermods/pov_display/README.md (1)

1-48: Overall: Clear, concise README that matches the BMP-based POV refactor

Good job documenting the workflow, constraints (24‑bit BMP, ~64KB), and safety. The examples and step list are practical and align with the PR’s move away from PNGdec. A few small nits below will polish it further.

@DedeHai
Copy link
Collaborator

DedeHai commented Aug 26, 2025

a buffer of 64k is off limits for ESP8266, it has less than 20k of free heap, so restriction is ok.

@Liliputech
Copy link
Contributor Author

ok, applied all suggested changes, if everything is fine this is ready to merge for me!

@DedeHai DedeHai merged commit da7f107 into wled:main Aug 29, 2025
20 checks passed
@Liliputech Liliputech deleted the pov_display branch August 30, 2025 02:15
@Liliputech
Copy link
Contributor Author

thank you very much for your approval!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

in progress This pull request is currently being reviewed and, if necessary, modified usermod usermod related

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants