Skip to content

Add mop mode path width adjustment for Hypfer vacuums#42

Merged
sca075 merged 30 commits intomainfrom
dev_main
Jan 21, 2026
Merged

Add mop mode path width adjustment for Hypfer vacuums#42
sca075 merged 30 commits intomainfrom
dev_main

Conversation

@sca075
Copy link
Owner

@sca075 sca075 commented Jan 21, 2026

  • Path width adjusts to robot_size - 2 when mop_mode=True (default: 5px)
  • Cache robot_size in ImageDraw for performance
  • Update handler to use cached robot_size
  • Test with mop_mode enabled in test.py

When mop mode is active, path width visually represents mop coverage area.

Summary by CodeRabbit

  • New Features

    • Added wood and tile material colors to map visualization.
    • Introduced a mop mode toggle that adjusts path rendering width; path/robot rendering now respects reported robot size.
    • Map element colors now use a consistent, deterministic ordering for predictable visuals.
  • Refactor

    • Removed a redundant image overlay routine to streamline rendering.
  • Documentation

    • Project version and requirements updated in docs.

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

Signed-off-by: Sandro Cantarella <sandro@Sandros-Mac-mini.fritz.box>
Signed-off-by: Sandro Cantarella <sandro@79f3d049-9006-400d-9954-2e5dcd250fa9.fritz.box>
Signed-off-by: Sandro Cantarella <sandro@Sandros-Mac-mini.fritz.box>
Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
…it bump version in pyproject.toml added to __init__.py Trims and Floor Data

Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
…ses old key trims_data

Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
- Add CARPET drawable element with configurable color and alpha
- Implement carpet zone parsing from Valetudo JSON (PolygonMapEntity)
- Add carpet rendering with customizable color (default: 50% of room_0)
- Support disable_carpets flag to toggle carpet visibility
- Fix COLORS list order to match base_color_keys mapping
- Fix floor rendering to use correct MAP_BACKGROUND color
- Add carpet color configuration to device_info

Fixes color index mismatch that affected carpet and floor color updates

Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
from_list

Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
Fixes carpet color/alpha from device_info not being applied due to
missing DrawableElement.CARPET entry in update_from_device_info().

Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
…tial implementation attempt and is not needed since we're using the simpler approach of passing color_carpet directly from device_info to the zones() drawing method.

Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
- Path width adjusts to robot_size - 2 when mop_mode=True (default: 5px)
- Cache robot_size in ImageDraw for performance
- Update handler to use cached robot_size
- Test with mop_mode enabled in test.py

When mop mode is active, path width visually represents mop coverage area.

Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
@sca075 sca075 self-assigned this Jan 21, 2026
@sca075 sca075 added the enhancement New feature or request label Jan 21, 2026
@coderabbitai
Copy link

coderabbitai bot commented Jan 21, 2026

📝 Walkthrough

Walkthrough

Adds named color indices and a curated public color array, extends COLORS with material entries (wood, tile), removes a material overlay helper, moves material overlay usage into drawing code, adds CameraShared.mop_mode, and makes path width and robot radius use image-provided robot_size.

Changes

Cohort / File(s) Summary
Colors & Constants
SCR/valetudo_map_parser/config/colors.py, SCR/valetudo_map_parser/const.py
Introduces ColorIndex(IntEnum) and public color_array; appends material_wood and material_tile to COLORS. Ensure enum order aligns with base_color_keys and consumers relying on numeric indices.
Material rendering
SCR/valetudo_map_parser/config/material.py
Removed MaterialTileRenderer.apply_overlay_on_region. Confirm callers now use the updated overlay flow (tile_block usage) in drawing code.
Drawing & Image handling
SCR/valetudo_map_parser/hypfer_draw.py, SCR/valetudo_map_parser/hypfer_handler.py, SCR/valetudo_map_parser/reimg_draw.py, SCR/valetudo_map_parser/rand256_handler.py
hypfer_draw uses ColorIndex for material colors and caches robot_size; path width calculation now depends on mop_mode. Several modules lowered info logs to debug. Verify path sizing, robot radius source (imd.robot_size) and material overlay invocation.
Shared config & utils
SCR/valetudo_map_parser/config/shared.py, SCR/valetudo_map_parser/config/utils.py, SCR/valetudo_map_parser/config/drawable_elements.py
Added CameraShared.mop_mode: bool (default False); status text color selection switched to ColorIndex.TEXT; several toggling/info logs reduced to debug. Check propagation of mop_mode and updated color index usage.
Packaging & Docs
README.md, pyproject.toml, SCR/valetudo_map_parser/__init__.py
Bumped package version and README requirements (Python 3.13, updated deps). Module version docstring updated. No functional code changes.

Sequence Diagram(s)

sequenceDiagram
    participant Caller as Caller
    participant Draw as HypferDraw
    participant Colors as ColorIndex/Colors
    participant Mat as MaterialTileRenderer
    participant Image as Image Pixels

    Caller->>Draw: request map render (segments, paths)
    Draw->>Colors: lookup material colors (MATERIAL_WOOD/TILE)
    Draw->>Mat: call tile_block() to generate material texture
    Mat-->>Draw: return material texture array
    Draw->>Draw: compute path width (robot_size, mop_mode)
    Draw->>Image: blend material texture into segment pixels (alpha)
    Draw->>Image: draw paths with computed width
    Image-->>Caller: rendered image
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰
I hop and paint the map anew,
Wood and tile now join the view.
Paths grow thin when mop’s in play,
Robot size leads the way.
Tiny paws, a brighter day.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add mop mode path width adjustment for Hypfer vacuums' directly describes a key functional change in the PR—mop mode path width adjustment—which is implemented in hypfer_draw.py and shared.py with the addition of mop_mode attribute and dynamic path width computation.
Docstring Coverage ✅ Passed Docstring coverage is 86.36% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing touches
  • 📝 Generate docstrings

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

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
SCR/valetudo_map_parser/hypfer_handler.py (1)

262-273: Inconsistent robot_size patterns between handlers.
hypfer_draw caches robot_size at initialization (line 27), while reimg_draw reads directly from self.img_h.shared.robot_size on each use (line 343). If robot_size is updated dynamically via batch_update, the Hypfer handler won't reflect the change. Consider reading directly from shared like reimg_draw does, or adding a fallback:

Suggested fallback
                 radius=self.imd.robot_size or self.shared.robot_size or 25,
SCR/valetudo_map_parser/map_data.py (1)

878-890: Missing "materials" in update_from_dict allowed set.

The materials field was added to HyperMapData (line 805) and is handled in from_dict (line 869), but it's missing from the allowed set in update_from_dict. This prevents updating the materials field via this method.

🐛 Proposed fix
         allowed = {
             "json_data",
             "json_id",
             "obstacles",
             "paths",
             "image_size",
             "areas",
             "pixel_size",
             "entity_dict",
             "layers",
             "active_zones",
             "virtual_walls",
+            "materials",
         }
🤖 Fix all issues with AI agents
In `@SCR/valetudo_map_parser/config/material.py`:
- Around line 210-223: Remove the dead static method apply_overlay_on_region
from the Material class: it is unused and duplicates blending behavior
implemented in _apply_material_overlay in hypfer_draw.py; delete the entire
method definition (including its reference to MaterialTileRenderer.tile_block
and the mask-based assignment) to eliminate unused code and rely on the existing
alpha blending implementation instead.
🧹 Nitpick comments (2)
SCR/valetudo_map_parser/hypfer_draw.py (2)

136-139: Magic numbers for color array indices reduce maintainability.

Hardcoding indices 10 and 11 for wood and tile colors creates a fragile coupling. If base_colors_array order changes in colors.py, this code will silently use wrong colors.

Consider defining named constants (e.g., COLOR_INDEX_WOOD = 10, COLOR_INDEX_TILE = 11) in a shared location, or accessing colors by a more explicit mechanism.

♻️ Suggested improvement
+# At module level or in a constants file
+COLOR_INDEX_WOOD = 10
+COLOR_INDEX_TILE = 11
+
 # In _process_room_layer:
                         material_colors = MaterialColors(
-                            wood_rgba=self.img_h.shared.user_colors[10],
-                            tile_rgba=self.img_h.shared.user_colors[11]
+                            wood_rgba=self.img_h.shared.user_colors[COLOR_INDEX_WOOD],
+                            tile_rgba=self.img_h.shared.user_colors[COLOR_INDEX_TILE]
                         )

172-183: Potential out-of-bounds array access relies on exception handling.

The slice at line 181 (img_np_array[row : row + pixel_size, c_start:c_end]) may exceed image dimensions if pixels are near edges. While the except block catches this gracefully, it may degrade performance due to repeated exception throwing for edge pixels.

Consider adding explicit bounds checking before the inner loop:

♻️ Optional bounds check
             for x, y, count in pixels:
                 row = y * pixel_size
                 col = x * pixel_size
+                img_h, img_w = img_np_array.shape[:2]
                 for i in range(count):
                     c_start = col + i * pixel_size
                     c_end = c_start + pixel_size
+                    # Skip pixels that would exceed image bounds
+                    if row + pixel_size > img_h or c_end > img_w:
+                        continue
                     overlay = MaterialTileRenderer.tile_block(
                         tile, row, row + pixel_size, c_start, c_end
                     )

…ileRenderer

Remove dead code from MaterialTileRenderer class in material.py:
- Deleted apply_overlay_on_region() static method (lines 210-223)
- Method was never called anywhere in the codebase
- Duplicated functionality already implemented in hypfer_draw._apply_material_overlay()
- Removed implementation used inferior mask-based assignment vs proper alpha blending

The active material overlay implementation in hypfer_draw.py continues to use:
- MaterialTileRenderer.get_tile() for tile generation
- MaterialTileRenderer.tile_block() for tile positioning
- Proper alpha blending: region[:] = (1 - alpha) * region + alpha * overlay

This cleanup eliminates 15 lines of unused code while maintaining all
functional material overlay capabilities.

Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
Replace all hardcoded user_colors[x] array indices with a ColorIndex IntEnum
to prevent breakage when color order changes and improve code maintainability.

Changes:
- Add ColorIndex IntEnum in config/colors.py with named constants for all
  user_colors array indices (WALL=0, ZONE_CLEAN=1, ROBOT=2, BACKGROUND=3,
  MOVE=4, CHARGER=5, CARPET=6, NO_GO=7, GO_TO=8, TEXT=9, MATERIAL_WOOD=10,
  MATERIAL_TILE=11)
- Add 'material_wood' and 'material_tile' to COLORS list in const.py to
  match the actual colors being initialized
- Replace user_colors[10] and user_colors[11] with ColorIndex.MATERIAL_WOOD
  and ColorIndex.MATERIAL_TILE in hypfer_draw.py
- Replace user_colors[8] with ColorIndex.TEXT in config/utils.py

Benefits:
- Self-documenting code with named constants instead of magic numbers
- Type-safe access to color indices
- Easy to maintain and reorder colors without breaking existing code
- Clear mapping between color names and their array positions

Tested: Hypfer test passes successfully with all colors initialized correctly
Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
Copy link

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
SCR/valetudo_map_parser/hypfer_draw.py (1)

419-433: Guard robot_size against None in mop-mode path width calculation.

If robot_size is None (when shared data is not initialized), self.robot_size - 2 will raise a TypeError. Consider a safe fallback to ensure path width is always valid.

🛠️ Suggested guard
-            if self.img_h.shared.mop_mode:
-                path_width = max(1, self.robot_size - 2)
-            else:
-                path_width = 5  # Default width
+            size = self.robot_size or 5
+            if self.img_h.shared.mop_mode:
+                path_width = max(1, size - 2)
+            else:
+                path_width = 5  # Default width
🤖 Fix all issues with AI agents
In `@SCR/valetudo_map_parser/config/colors.py`:
- Around line 5-6: ColorIndex values currently don't match the order that
initialize_user_colors() populates user_colors, causing misindexed colors; fix
by making initialize_user_colors() construct the user_colors list in the same
order as set_initial_colours() / base_color_keys: iterate base_color_keys (not
SupportedColor) and for each key look up the corresponding
SupportedColor/default value to append to user_colors so indices align with
ColorIndex, or alternatively remove usage of ColorIndex and switch all lookups
to enum-based access using SupportedColor; update references to user_colors,
ColorIndex and initialize_user_colors() accordingly to keep a single canonical
ordering.
♻️ Duplicate comments (2)
SCR/valetudo_map_parser/hypfer_draw.py (1)

135-139: ColorIndex ordering dependency (see colors.py comment).

This block relies on shared.user_colors matching ColorIndex. If that ordering diverges, material overlays will pick the wrong colors.

SCR/valetudo_map_parser/config/utils.py (1)

16-16: ColorIndex ordering dependency (see colors.py comment).

Status text color indexing will be wrong if shared.user_colors ordering doesn’t match ColorIndex.

Also applies to: 206-210

…ovements

## Version Update
- Bumped version to 0.2.0 across pyproject.toml, __init__.py, and README.md

## Color System Enhancements

### ColorIndex Enum Implementation
- Created ColorIndex IntEnum with named constants for all user_colors array indices
- Replaced hardcoded numeric indices (user_colors[8], [10], [11]) with type-safe enum constants
- Prevents breakage when color order changes in the future
- Updated hypfer_draw.py to use ColorIndex.MATERIAL_WOOD and ColorIndex.MATERIAL_TILE
- Updated utils.py to use ColorIndex.TEXT for status text rendering

### Material Colors Refactoring
- Refactored MaterialTileRenderer to use MaterialColors dataclass
- Made material overlay colors (wood and tile) user-configurable via device_info
- Removed hardcoded class variables WOOD_RGBA/TILE_RGBA and set_colors()/reset_colors() methods
- All rendering methods now accept color parameters instead of using class state
- Added material color constants to DEFAULT_VALUES (color_material_wood, color_material_tile)
- Updated material overlay implementation to extract colors from shared.user_colors

### Color Initialization Fix
- Fixed initialize_user_colors() to use same base_color_keys order as set_initial_colours() and ColorIndex enum
- Prevents color index mismatches during initialization
- Added 'material_wood' and 'material_tile' to COLORS list in const.py

### Color Blending Implementation
- Implemented color blending for semi-transparent elements using mvcrender's sample_and_blend_color
- Applied blending to flag, obstacles, and charger elements when alpha < 255
- Optimized alpha blending to minimize temporary allocations in zone drawing

### Path Color Enhancements
- Updated default path color to more vibrant blue (50, 150, 255) for better visibility
- Implemented mop mode path width adjustment: path_width = max(1, robot_size - 2) when mop_mode=True
- Added robot_size caching in ImageDraw to reduce shared data access
- Path lines now support different colors when crossing different rooms

### Alpha Transparency Updates
- Updated default alpha values: path (200.0), walls (150.0)
- Semi-transparent elements (restricted areas, no-mop areas, predicted path) default to alpha=125.0

## Code Quality Improvements

### Logging Cleanup
- Converted 24+ INFO logs to DEBUG level across 5 files to reduce production log noise
  - hypfer_handler.py: 5 logs converted
  - rand256_handler.py: 4 logs converted
  - hypfer_draw.py: 1 log converted + fixed misleading else clause
  - reimg_draw.py: 8 logs converted + fixed else clause pattern
  - drawable_elements.py: 6 logs converted + removed duplicate logging
- Fixed misleading else-clause logging patterns in virtual walls and entity dict methods
- Removed duplicate log statements in enable_element/disable_element methods

### Dead Code Removal
- Removed unused material_mvcrender.py (test/alternative implementation)
- Removed unused apply_overlay_on_region() static method from MaterialTileRenderer

## Documentation Updates
- Updated Python requirement documentation from 3.12 to 3.13 in README.md
- Added complete dependency list with version constraints:
  - Pillow (>=10.3.0)
  - NumPy (>=1.26.4)
  - SciPy (>=1.12.0)
  - mvcrender (==0.0.7)

## Performance Optimizations
- Added mop_mode attribute to CameraShared class for tracking vacuum operation mode
- Cached robot_size in ImageDraw to avoid repeated shared data access
- Optimized color blending operations to reduce memory allocations

## Deferred Issues (Medium Priority)
- Pylint disabled in CI since refactoring (to be re-enabled)
- Potential null reference in _convert_to_binary when last_image is None
- Room ID indexing inconsistency (0-based vs 1-based)
- Potential race conditions in async shared data access
- Hardcoded /tmp/ paths in tests (Windows incompatible)
- Virtual walls logging pattern needs review

Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
@sca075 sca075 merged commit f9b7df6 into main Jan 21, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant