KDEAmbi/lessons_learned.md

8.2 KiB

Lessons Learned: Hyperion Processor Module

This document captures key insights, challenges, and solutions encountered during the development and testing of the HyperionProcessor module.

1. Importance of Incremental Testing and Visualization

  • Challenge: Initial attempts to debug the HyperionProcessor's output were hampered by a lack of clear visual feedback. Printing raw color values (#RRGGBB) to the console was not intuitive, and the initial ASCII visualization was difficult to interpret without proper color support or dynamic updates.
  • Solution: Breaking down the problem into smaller, verifiable steps proved crucial. First, confirming the WaylandGrabber and HyperionGrabber were correctly capturing and scaling images (via QLabel display) isolated the issue to the processing pipeline. Then, visualizing the intermediate step of black border detection (showing the cropped image) provided immediate confirmation of that component's functionality.
  • Lesson: For complex image processing or graphical tasks, robust visual debugging tools that show intermediate steps are invaluable. They allow for quick identification and isolation of issues, significantly accelerating the development process.

2. Understanding Qt's Logging and Console Output

  • Challenge: qDebug() and qInfo() messages were not appearing in the console during initial test_hyperion_processor runs, leading to confusion about whether the code was executing or producing any output.
  • Solution: Explicitly configuring QLoggingCategory::setFilterRules() and adding QCoreApplication::processEvents() calls did not immediately resolve the issue in a simple console application. Ultimately, switching to std::cout and std::cerr for direct console output bypassed Qt's logging system and guaranteed visibility.
  • Lesson: When working with Qt in a console-only context, especially for quick tests, direct std::cout/std::cerr can be more reliable for immediate feedback than relying solely on Qt's logging framework, which might require more extensive setup for console redirection.

3. Robustness of Image Processing to Input Variations

  • Challenge: The HyperionProcessor initially produced dark, almost black LED colors when tested with frames/frame_000.png. This led to initial concerns about the BlackBorderDetector or getAverageColor logic.

  • Solution: Visual inspection of frame_000.png revealed it was indeed mostly black. This confirmed that the HyperionProcessor was functioning correctly based on its input. The subsequent live testing with grabberconfigurator (showing the scaled screen) confirmed the entire capture pipeline was working.

  • Lesson: Always validate input data. An unexpected output might not indicate a bug in the processing logic but rather an issue with the input data itself. Using real-world or representative input is critical for accurate testing.

4. Iterative Refinement of Visualization

  • Challenge: The initial ASCII visualization of LED colors was not clear enough for the user to interpret effectively.
  • Solution: Iteratively refining the visualization based on user feedback (e.g., switching from ASCII to QLabel for cropped image, then adding thicker outlines and a frame) significantly improved its utility. The ability to dynamically adjust the visualization (e.g., frameThickness, penThickness) allowed for rapid iteration and better understanding.
  • Lesson: User feedback is paramount for effective tool development, especially for visual debugging tools. Start simple, but be prepared to iterate and enhance based on what makes the tool most useful to the end-user.

5. Command Line Option Parsing

  • Challenge: QCommandLineOption definitions using {"option-name"} syntax caused parsing errors, leading to options not being recognized and default values being used (e.g., totalLeds=0).
  • Solution: Explicitly using QStringList() << "option-name" for option names resolved the parsing ambiguity.
  • Lesson: Pay close attention to framework-specific syntax for command-line argument parsing. Ambiguities can lead to silent failures and incorrect program behavior.

6. Pixel Sampling for LED Mapping

  • Challenge: Initial buildLedMap implementation sampled only a single pixel row/column for each LED, resulting in dark average colors even with vibrant screen content, as screen edges are often dark.
  • Solution: Modified buildLedMap to sample a region of pixels (e.g., 5% of content height/width) for each LED. This provides a more representative average color for the LED's area.
  • Lesson: Accurate pixel sampling is crucial for effective Ambilight. Sampling a region rather than a single line provides a more robust and visually appealing color representation, especially for dynamic screen content.

7. Debugging QPainter Drawing Issues

  • Challenge: QPainter drawing of filled rectangles and text was not visible, despite HyperionProcessor producing correct colors.
  • Solution: Isolated drawing of LED regions by temporarily removing the croppedImage drawing. This confirmed that the QPainter was indeed drawing, but the croppedImage was likely covering the drawn elements. The issue was not with the QPainter itself, but with the drawing order and the opacity of the croppedImage.
  • Lesson: When debugging drawing issues, isolate components. Temporarily removing layers or elements can quickly pinpoint where the drawing problem lies. Ensure drawing order and opacity are correctly managed to achieve the desired visual effect.

8. External Interference (KWin Script)

  • Challenge: Persistent issues with dark LED colors and inconsistent black border detection, despite extensive debugging of the HyperionProcessor and BlackBorderDetector.
  • Diagnosis: The problem was traced to an interfering KWin script (on KDE Plasma Wayland). KWin scripts can overlay or modify screen content in ways that are invisible to screen grabbers, leading to unexpected input images.
  • Solution: Disabling the interfering KWin script immediately resolved the issues, allowing the grabberconfigurator to display correct and vibrant LED colors.
  • Lesson: When debugging screen capture or visual processing issues, always consider external factors like display server configurations, window managers, and overlay applications. These can silently alter the input data, leading to misleading debugging results within the application itself.

9. WLED Integration and Testing

  • Challenge: Integrating the WledClient into grabberconfigurator and verifying direct WLED communication.
  • Solution: Added WledClient instance, command-line options for WLED address/port, and called setLedsColor with calculated LED colors. This sets up the pipeline for sending data directly to the WLED device.
  • Lesson: Modular design allows for easy integration of different components. The grabberconfigurator now serves as a complete testbed for the entire Ambilight pipeline, from screen capture to WLED output.

10. Main Application Refactoring and Environment Variable Configuration

  • Challenge: Consolidating the screen grabbing, Hyperion processing, and WLED communication into the main Hyperion_Grabber_Wayland_QT application and configuring it via environment variables.
  • Solution: Refactored main.cpp to remove command-line parsing and instead read all configuration parameters (WLED address/port, LED layout, Hyperion algorithm parameters, grabber settings) from environment variables. Implemented a QTimer to control the frame processing rate.
  • Lesson: Centralizing configuration via environment variables provides flexibility and simplifies deployment. Using a timer for frame processing ensures a consistent update rate for the LEDs, independent of the grabber's frame rate.

[Commit: e31f154] - feat: Implement and verify HyperionProcessor with live visualization [Commit: 478828b] - docs: Add lesson learned about KWin script interference [Commit: 60bcfb0] - feat: Integrate WledClient into grabberconfigurator for direct WLED communication [Commit: <CURRENT_COMMIT_HASH>] - feat: Refactor main application for environment variable configuration