Conversation
…e code quality to 10/10 - Add dock_state attribute to track docking station operations (self_cleaning, emptying, etc.) - Refactor map_data.py to reduce complexity (extract helper methods) - Refactor drawable_elements.py to use dictionary-driven loops - Fix exception handling in hypfer_draw.py (use specific exceptions) - Remove commented-out code from hypfer_draw.py Quality improvements: - Pylint score: 10.00/10 (perfect score) - Fixed W0718: Replace broad Exception with specific exceptions - Fixed R0912: Reduce branches from 16→6 (map_data) and 14→10 (drawable_elements) - Fixed R1702: Reduce nested blocks from 7→3 (map_data) - All code formatted with ruff and isort Modified files: - SCR/valetudo_map_parser/const.py - SCR/valetudo_map_parser/__init__.py - SCR/valetudo_map_parser/config/shared.py - SCR/valetudo_map_parser/config/status_text/status_text.py - SCR/valetudo_map_parser/map_data.py - SCR/valetudo_map_parser/hypfer_draw.py - SCR/valetudo_map_parser/config/drawable_elements.py Tests: ✅ All passing (440.8ms image generation) fix: Convert float device_info values to integers (Pi4 compatibility) fix: Correct calibration points coordinate swap ## Pi4 Float to Integer Conversion On Raspberry Pi 4 and other systems, Home Assistant can pass device_info configuration values as floats (e.g., 255.0, 100.0) even when they should be integers. This caused "TypeError: 'float' object cannot be interpreted as an integer" when AutoCrop initialization accessed these values. Changes: - Convert offset values (offset_top, offset_down, offset_left, offset_right) to int - Convert size values (vacuum_status_size, mop_path_width) to int with error handling - Update TrimsData.from_dict(), from_json(), and from_list() to convert trim values to int - Update TrimCropData.from_dict() and from_list() to convert trim values to int Note: Color alpha values intentionally remain as floats in device_info and are converted to integers only when creating final RGBA tuples, so color handling is unaffected. ## Calibration Points Coordinate Swap Fix Fixed critical bug where X and Y coordinates were swapped in calibration points calculation. The crop_area format is [left, up, right, down], but get_vacuum_points() was incorrectly mapping crop_area[0] (left) to x and crop_area[1] (up) to y. Corrected mapping: - crop_area[1] (up) → x (was crop_area[0]) - crop_area[0] (left) → y (was crop_area[1]) Impact: - Robot position on map is now correctly placed - Touch-to-go coordinates work correctly - Room detection reports the correct room - Fixes issue where robot at x:3464, y:3262 was showing [3162, 3442] instead of [3442, 3162] ## Test Fixes - Fix typo in tests/test.py: trim_left 240.0 → 2400.0 ## Version - Bump version from 0.2.3 to 0.2.4b1 for beta testing in Home Assistant Files modified: - pyproject.toml - SCR/valetudo_map_parser/__init__.py - SCR/valetudo_map_parser/config/shared.py - SCR/valetudo_map_parser/config/types.py - SCR/valetudo_map_parser/config/utils.py - tests/test.py Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
- Fix active_list alignment in map_data.py: append 0 on conversion failure instead of skipping - Remove duplicate color_mop_move and alpha_mop_move keys in tests/test.py Ensures segment-to-active-zone index correspondence and eliminates dict key override issues. Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
… version 0.2.4b3 release 🐛 Critical Bug Fixes: - Fixed calibration points not updating when map rotation changes * Removed incorrect rotation reordering logic in get_vacuum_points() * Calibration data now recalculates on every image generation * Ensures coordinate mapping works correctly at all rotation angles - Fixed segment alignment bug in map_data.py - Fixed rotation change handling to prevent "Invalid crop region" errors * Added rotation tracking to FloorData class * Detects when saved rotation differs from current rotation * Automatically resets trims for recalculation when rotation changes * Prevents errors when user changes rotation with saved floor data ✨ Implementation Details: - Added rotation: int field to FloorData class - update_trims() now saves current image_rotate with trims - On reload, compares saved rotation with current rotation - If different, resets trims to defaults and lets auto-crop recalculate - Logs rotation changes for debugging ✨ Updates: - Version bumped to 0.2.4b3 - Updated mvcrender dependency to 0.1.0 https://github.com/sca075/mvcrender/releases/tag/v0.1.0 - Comprehensive documentation updates (README.md, CHANGELOG.md) - New test: test_reload_rotation_change.py ✅ Quality Gate: - Pylint: 10.00/10 - All checks passed - Tests: PASSED * test_autocrop_floor.py: Calibration points correctly change with rotation * test_reload_rotation_change.py: Rotation change detection working, trims reset and recalculated * test.py: Image generation 432.6ms avg 📝 Modified Files: - SCR/valetudo_map_parser/config/types.py (rotation field in FloorData) - SCR/valetudo_map_parser/config/utils.py (update_trims with rotation, calibration fixes) - SCR/valetudo_map_parser/config/shared.py (rotation change detection) - tests/test_reload_rotation_change.py (new test) - pyproject.toml (version bump, mvcrender 0.1.0) - README.md (version and features update) - CHANGELOG.md (comprehensive v0.2.4 release notes with rotation change handling) Ready for Home Assistant testing. Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
…rop_area mapping
CRITICAL FIX: Fixed TrimsData.from_list() mapping where crop_area indices
were completely backwards, causing impossible trim values (trim_left > trim_right)
and broken calibration points.
The crop_area format is [left, up, right, down], so the correct mapping is:
- crop_area[0] → trim_left (was incorrectly mapped to trim_up)
- crop_area[1] → trim_up (was incorrectly mapped to trim_left)
- crop_area[2] → trim_right (was incorrectly mapped to trim_down)
- crop_area[3] → trim_down (was incorrectly mapped to trim_right)
This bug caused:
- Calibration points to be completely wrong
- Click-to-go to send vacuum to wrong locations
- Room boundaries to be incorrect
- All coordinate mapping features to fail
Test verification (test_autocrop_floor.py):
✅ All trim values now satisfy: trim_left < trim_right and trim_up < trim_down
✅ Calibration points correctly track vacuum position across rotations
✅ Robot position consistent: {'x': 3231, 'y': 3275, 'angle': 90.0}
Modified:
- SCR/valetudo_map_parser/config/types.py (lines 333-345)
Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
…rop_area mapping
CRITICAL FIX: Fixed TrimsData.from_list() mapping where crop_area indices
were completely backwards, causing impossible trim values (trim_left > trim_right)
and broken calibration points.
The crop_area format is [left, up, right, down], so the correct mapping is:
- crop_area[0] → trim_left (was incorrectly mapped to trim_up)
- crop_area[1] → trim_up (was incorrectly mapped to trim_left)
- crop_area[2] → trim_right (was incorrectly mapped to trim_down)
- crop_area[3] → trim_down (was incorrectly mapped to trim_right)
This bug caused:
- Calibration points to be completely wrong
- Click-to-go to send vacuum to wrong locations
- Room boundaries to be incorrect
- All coordinate mapping features to fail
Test verification (test_autocrop_floor.py):
✅ All trim values now satisfy: trim_left < trim_right and trim_up < trim_down
✅ Calibration points correctly track vacuum position across rotations
✅ Robot position consistent: {'x': 3231, 'y': 3275, 'angle': 90.0}
Modified:
- SCR/valetudo_map_parser/config/types.py (lines 333-345)
Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
CRITICAL FIX: Fixed calibration coordinate system mismatch between NumPy (y,x) and Home Assistant (x,y). NumPy uses (row, column) indexing while Home Assistant expects standard Cartesian (x, y) coordinates. Changes: - Swapped X and Y coordinates in get_vacuum_points() to compensate for the coordinate system difference - Fixed TrimsData.from_list() to correctly map crop_area indices - Added detailed logging for calibration calculation debugging The Problem: - mvcrender outputs crop_area in NumPy (y, x) format - Home Assistant expects (x, y) Cartesian coordinates - Without the swap, calibration points had X and Y reversed - This caused click-to-go to send vacuum to wrong locations The Solution: In get_vacuum_points(), we now swap coordinates: x = crop_area[1] + offset_y (use 'up' for x) y = crop_area[0] + offset_x (use 'left' for y) Impact: - Calibration points now correctly map image pixels to vacuum coordinates - Click-to-go functionality works correctly - All rotation angles (0°, 90°, 180°, 270°) produce correct calibration Test Results: ✅ test_autocrop_floor.py passes with correct calibration for all rotations ✅ Coordinates now match Home Assistant's expected format Modified: - SCR/valetudo_map_parser/config/utils.py (get_vacuum_points) - SCR/valetudo_map_parser/config/types.py (TrimsData.from_list) - SCR/valetudo_map_parser/hypfer_handler.py (added logging) Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
…e code quality to 10/10 - Add dock_state attribute to track docking station operations (self_cleaning, emptying, etc.) - Refactor map_data.py to reduce complexity (extract helper methods) - Refactor drawable_elements.py to use dictionary-driven loops - Fix exception handling in hypfer_draw.py (use specific exceptions) - Remove commented-out code from hypfer_draw.py Quality improvements: - Pylint score: 10.00/10 (perfect score) - Fixed W0718: Replace broad Exception with specific exceptions - Fixed R0912: Reduce branches from 16→6 (map_data) and 14→10 (drawable_elements) - Fixed R1702: Reduce nested blocks from 7→3 (map_data) - All code formatted with ruff and isort Modified files: - SCR/valetudo_map_parser/const.py - SCR/valetudo_map_parser/__init__.py - SCR/valetudo_map_parser/config/shared.py - SCR/valetudo_map_parser/config/status_text/status_text.py - SCR/valetudo_map_parser/map_data.py - SCR/valetudo_map_parser/hypfer_draw.py - SCR/valetudo_map_parser/config/drawable_elements.py Tests: ✅ All passing (440.8ms image generation) fix: Convert float device_info values to integers (Pi4 compatibility) fix: Correct calibration points coordinate swap ## Pi4 Float to Integer Conversion On Raspberry Pi 4 and other systems, Home Assistant can pass device_info configuration values as floats (e.g., 255.0, 100.0) even when they should be integers. This caused "TypeError: 'float' object cannot be interpreted as an integer" when AutoCrop initialization accessed these values. Changes: - Convert offset values (offset_top, offset_down, offset_left, offset_right) to int - Convert size values (vacuum_status_size, mop_path_width) to int with error handling - Update TrimsData.from_dict(), from_json(), and from_list() to convert trim values to int - Update TrimCropData.from_dict() and from_list() to convert trim values to int Note: Color alpha values intentionally remain as floats in device_info and are converted to integers only when creating final RGBA tuples, so color handling is unaffected. ## Calibration Points Coordinate Swap Fix Fixed critical bug where X and Y coordinates were swapped in calibration points calculation. The crop_area format is [left, up, right, down], but get_vacuum_points() was incorrectly mapping crop_area[0] (left) to x and crop_area[1] (up) to y. Corrected mapping: - crop_area[1] (up) → x (was crop_area[0]) - crop_area[0] (left) → y (was crop_area[1]) Impact: - Robot position on map is now correctly placed - Touch-to-go coordinates work correctly - Room detection reports the correct room - Fixes issue where robot at x:3464, y:3262 was showing [3162, 3442] instead of [3442, 3162] ## Test Fixes - Fix typo in tests/test.py: trim_left 240.0 → 2400.0 ## Version - Bump version from 0.2.3 to 0.2.4b1 for beta testing in Home Assistant Files modified: - pyproject.toml - SCR/valetudo_map_parser/__init__.py - SCR/valetudo_map_parser/config/shared.py - SCR/valetudo_map_parser/config/types.py - SCR/valetudo_map_parser/config/utils.py - tests/test.py Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
… version 0.2.4b3 release 🐛 Critical Bug Fixes: - Fixed calibration points not updating when map rotation changes * Removed incorrect rotation reordering logic in get_vacuum_points() * Calibration data now recalculates on every image generation * Ensures coordinate mapping works correctly at all rotation angles - Fixed segment alignment bug in map_data.py - Fixed rotation change handling to prevent "Invalid crop region" errors * Added rotation tracking to FloorData class * Detects when saved rotation differs from current rotation * Automatically resets trims for recalculation when rotation changes * Prevents errors when user changes rotation with saved floor data ✨ Implementation Details: - Added rotation: int field to FloorData class - update_trims() now saves current image_rotate with trims - On reload, compares saved rotation with current rotation - If different, resets trims to defaults and lets auto-crop recalculate - Logs rotation changes for debugging ✨ Updates: - Version bumped to 0.2.4b3 - Updated mvcrender dependency to 0.1.0 https://github.com/sca075/mvcrender/releases/tag/v0.1.0 - Comprehensive documentation updates (README.md, CHANGELOG.md) - New test: test_reload_rotation_change.py ✅ Quality Gate: - Pylint: 10.00/10 - All checks passed - Tests: PASSED * test_autocrop_floor.py: Calibration points correctly change with rotation * test_reload_rotation_change.py: Rotation change detection working, trims reset and recalculated * test.py: Image generation 432.6ms avg 📝 Modified Files: - SCR/valetudo_map_parser/config/types.py (rotation field in FloorData) - SCR/valetudo_map_parser/config/utils.py (update_trims with rotation, calibration fixes) - SCR/valetudo_map_parser/config/shared.py (rotation change detection) - tests/test_reload_rotation_change.py (new test) - pyproject.toml (version bump, mvcrender 0.1.0) - README.md (version and features update) - CHANGELOG.md (comprehensive v0.2.4 release notes with rotation change handling) Ready for Home Assistant testing. 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>
…the calibration steps we downgraded it to 0.8.0 to fit the current implementation. Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
…the calibration steps we downgraded it to 0.8.0 to fit the current implementation. Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
…ices Version 0.2.4 - Production Ready Release Major Changes: - Python 3.12+ support (Home Assistant compatible) - Converted all logging to DEBUG level (32 instances across 9 files) - Modernized Rand256 calibration with match/case pattern - Code cleanup: removed 40 lines of unnecessary comments Library Logging Best Practices: - All LOGGER.info → LOGGER.debug (3 instances) - All LOGGER.warning → LOGGER.debug (29 instances) - Applications now control library log output - Production logs stay clean unless DEBUG enabled Code Quality: - Pylint: 9.99/10 - Ruff: All checks passed - isort: All imports sorted - Tests: All passing - calibration working at all rotations Modified Files: - SCR/valetudo_map_parser/config/shared.py (6 logging conversions) - SCR/valetudo_map_parser/config/utils.py (6 logging conversions + comment cleanup) - SCR/valetudo_map_parser/rand256_handler.py (3 logging conversions) - SCR/valetudo_map_parser/reimg_draw.py (4 logging conversions) - SCR/valetudo_map_parser/hypfer_draw.py (7 logging conversions) - SCR/valetudo_map_parser/hypfer_handler.py (2 logging conversions) - SCR/valetudo_map_parser/config/colors.py (2 logging conversions) - SCR/valetudo_map_parser/config/drawable.py (1 logging conversion) - SCR/valetudo_map_parser/rooms_handler.py (1 logging conversion) Breaking Changes: None Dependencies: mvcrender==0.0.9 (Python 3.12 compatible) Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
…ices Version 0.2.4 - Production Ready Release Major Changes: - Python 3.12+ support (Home Assistant compatible) - Converted all logging to DEBUG level (32 instances across 9 files) - Modernized Rand256 calibration with match/case pattern - Code cleanup: removed 40 lines of unnecessary comments Library Logging Best Practices: - All LOGGER.info → LOGGER.debug (3 instances) - All LOGGER.warning → LOGGER.debug (29 instances) - Applications now control library log output - Production logs stay clean unless DEBUG enabled Code Quality: - Pylint: 9.99/10 - Ruff: All checks passed - isort: All imports sorted - Tests: All passing - calibration working at all rotations Modified Files: - SCR/valetudo_map_parser/config/shared.py (6 logging conversions) - SCR/valetudo_map_parser/config/utils.py (6 logging conversions + comment cleanup) - SCR/valetudo_map_parser/rand256_handler.py (3 logging conversions) - SCR/valetudo_map_parser/reimg_draw.py (4 logging conversions) - SCR/valetudo_map_parser/hypfer_draw.py (7 logging conversions) - SCR/valetudo_map_parser/hypfer_handler.py (2 logging conversions) - SCR/valetudo_map_parser/config/colors.py (2 logging conversions) - SCR/valetudo_map_parser/config/drawable.py (1 logging conversion) - SCR/valetudo_map_parser/rooms_handler.py (1 logging conversion) Breaking Changes: None Dependencies: mvcrender==0.0.9 (Python 3.12 compatible) Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
Added pylint disable comments for dynamic method calls that exist in subclasses. Changes: - Line 215: get_rooms_attributes() - exists in Rand256Handler subclass - Line 223: async_get_rooms_attributes() - exists in HypferHandler subclass Both methods are safely checked with hasattr() before use, but pylint cannot detect dynamic method resolution in base classes. The disable comments are properly documented to explain why the methods exist at runtime. Quality Gate: - Pylint: 10.00/10 (improved from 9.77/10) - Ruff: All checks passed - isort: All imports sorted - Tests: All passing Breaking Changes: None Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
Added pylint disable comments for dynamic method calls that exist in subclasses. Changes: - Line 215: get_rooms_attributes() - exists in Rand256Handler subclass - Line 223: async_get_rooms_attributes() - exists in HypferHandler subclass Both methods are safely checked with hasattr() before use, but pylint cannot detect dynamic method resolution in base classes. The disable comments are properly documented to explain why the methods exist at runtime. Quality Gate: - Pylint: 10.00/10 (improved from 9.77/10) - Ruff: All checks passed - isort: All imports sorted - Tests: All passing Breaking Changes: None Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
- Update numpy (>=2.0.0), Pillow (>=12.0.0), scipy (>=1.17.0) for HA compatibility - Optimize memory: clear persistent buffer after auto-crop (0.12 MB/frame growth) - Fix dock_state display to work independently of vacuum_state - Improve test configuration with ENABLE_PIL_SHOW and SAVE_FIRST_FRAME flags - Code quality: All checks pass (Ruff ✓, isort ✓, Pylint 10/10) Performance: 106ms avg per frame, 0.12 MB/frame memory growth (3x better than target) Signed-off-by: SCA075 <82227818+sca075@users.noreply.github.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds explicit exports, new obstacle-link configuration and public utilities, broadens dock_state inclusion in status text, refines image-processing memory handling and logging, bumps package and dependency versions, augments tests (image/overlay/profiling), and adds IDE project files. Changes
Sequence Diagram(s)(omitted — changes are primarily API additions, memory/logging tweaks, tests, and config; no new multi-component control flow requiring a sequence diagram) Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
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>
There was a problem hiding this comment.
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_handler.py (1)
458-461:⚠️ Potential issue | 🟡 MinorPotential
NameErrorindelstatement if calibration loop has zero iterations.Line 461 does
del vacuum_points, map_points, calibration_point, rotation_angle. Ifvacuum_pointsormap_pointsare empty, theforloop at line 458 never executes, leavingcalibration_pointundefined. Thedelwould then raiseNameError.This is a pre-existing issue (not introduced by this PR), but since you're touching this method, it's worth a minor fix:
Proposed fix
for vacuum_point, map_point in zip(vacuum_points, map_points): calibration_point = {"vacuum": vacuum_point, "map": map_point} calibration_data.append(calibration_point) - del vacuum_points, map_points, calibration_point, rotation_angle # free memory. + del vacuum_points, map_points, rotation_angle # free memory. return calibration_data
🧹 Nitpick comments (3)
SCR/valetudo_map_parser/rand256_handler.py (1)
117-123: Downgrading image-creation errors to debug may hide actionable failures.In
extract_room_properties, catchingRuntimeError | ValueErrorand logging atdebuglevel means any real data-parsing issue will be invisible at default log levels. Since the function returnsNone(which the type hint declares asRoomsProperties), callers silently get no rooms. Consider keeping at least aLOGGER.infoorLOGGER.warningfor the first occurrence, and usingdebugonly for subsequent/expected failures.That said, the PR description indicates this is an intentional project-wide verbosity reduction and testing confirms it works, so this is a soft observation.
SCR/valetudo_map_parser/hypfer_draw.py (1)
311-315: Minor:dict.get()never raisesKeyError— theexceptblock is dead code.
entity_dict.get("charger_location")returnsNoneon missing key rather than raisingKeyError. The same applies toentity_dict.get("robot_position")on line 611. Theseexcept KeyErrorblocks are unreachable. This is pre-existing and not introduced by this PR, but worth noting if you're doing a cleanup pass.SCR/valetudo_map_parser/config/utils.py (1)
120-130: Consider keeping at leastwarninglevel for unexpected exceptions in the image pipeline.These exceptions (ValueError, TypeError, AttributeError, KeyError, RuntimeError) in
async_get_imagerepresent genuine failures in the image generation pipeline. Downgrading them todebugmeans operators won't see them unless they explicitly enable debug logging, making production troubleshooting harder. The graceful fallback tolast_imageis good, but silent failures can mask regressions.A middle ground: log at
warningbut throttle (e.g., only on the first occurrence or every Nth frame).
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In @.idea/vcs.xml:
- Around line 1-7: Remove IDE config files from VCS and add a .gitignore that
excludes them: create a .gitignore at repo root containing a rule for ".idea/"
(and any other editor files you want ignored), then stop tracking the already
committed IDE files (e.g., .idea/vcs.xml, .idea/misc.xml, .idea/modules.xml) by
running git rm --cached on those paths (do not delete local files), and commit
the .gitignore plus the removal commit with a clear message.
In `@tests/test_autocrop_floor.py`:
- Line 220: The tests call overlay1.show(), overlay2.show(), overlay3.show(),
and overlay4.show() unconditionally which can hang in headless CI; guard each
.show() call with the ENABLE_PIL_SHOW flag used in tests/test.py (e.g., if
ENABLE_PIL_SHOW: overlay1.show()), or remove the calls entirely—update the code
paths that invoke overlay1.show, overlay2.show, overlay3.show, and overlay4.show
to follow that pattern so the display is only executed when ENABLE_PIL_SHOW is
truthy.
- Around line 74-88: Replace the bare except clauses used when loading fonts
with a specific exception type so system-level interrupts aren't swallowed:
update the two try/except blocks that call ImageFont.truetype (the blocks
assigning font and title_font) to catch OSError (or Exception if broader)
instead of a bare except, keeping the fallback to ImageFont.load_default()
unchanged and preserving the behavior of draw.textbbox and draw.text that use
font/title_font.
🧹 Nitpick comments (2)
.idea/runConfigurations/test_py.xml (1)
1-24: IDE-specific run configuration should not be committed.This
.idea/file is a personal IntelliJ/PyCharm run configuration. Committing it pollutes the repo for contributors using other editors and can cause merge noise. Add.idea/to.gitignoreand remove this file from tracking.echo ".idea/" >> .gitignore git rm --cached -r .idea/tests/test_autocrop_floor.py (1)
75-77: macOS-specific font path will always fall back on Linux/CI.
/System/Library/Fonts/Helvetica.ttconly exists on macOS. On Linux CI or other platforms this silently falls back toload_default(), which may produce different visual output. Consider using a bundled font (the repo already hasSCR/valetudo_map_parser/config/fonts/FiraSans.ttfper the test config intests/test.pyLine 342) or making the path configurable.Also applies to: 85-88
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <project version="4"> | ||
| <component name="VcsDirectoryMappings"> | ||
| <mapping directory="" vcs="Git" /> | ||
| <mapping directory="$PROJECT_DIR$" vcs="Git" /> | ||
| </component> | ||
| </project> No newline at end of file |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if .gitignore exists and whether .idea is already listed
if [ -f .gitignore ]; then
echo "=== .gitignore exists ==="
grep -n '.idea' .gitignore || echo ".idea is NOT in .gitignore"
else
echo ".gitignore does not exist"
fi
# Check if other .idea files are also tracked
echo ""
echo "=== Checking tracked .idea files ==="
git ls-files '.idea/' 2>/dev/null | head -20Repository: sca075/Python-package-valetudo-map-parser
Length of output: 395
Remove IDE configuration files and add .gitignore.
.idea/ files are IDE-specific settings that shouldn't be tracked. No .gitignore currently exists in this repository, and multiple .idea/ files are already committed (.idea/vcs.xml, .idea/misc.xml, .idea/modules.xml, etc.). Create a .gitignore file with .idea/ listed and remove these files from version control.
🤖 Prompt for AI Agents
In @.idea/vcs.xml around lines 1 - 7, Remove IDE config files from VCS and add a
.gitignore that excludes them: create a .gitignore at repo root containing a
rule for ".idea/" (and any other editor files you want ignored), then stop
tracking the already committed IDE files (e.g., .idea/vcs.xml, .idea/misc.xml,
.idea/modules.xml) by running git rm --cached on those paths (do not delete
local files), and commit the .gitignore plus the removal commit with a clear
message.
| try: | ||
| font = ImageFont.truetype("/System/Library/Fonts/Helvetica.ttc", 12) | ||
| except: | ||
| font = ImageFont.load_default() | ||
|
|
||
| bbox = draw.textbbox((label_x, label_y), label, font=font) | ||
| draw.rectangle(bbox, fill="white", outline="black") | ||
| draw.text((label_x, label_y), label, fill="black", font=font) | ||
|
|
||
| # Add title | ||
| title = f"Rotation {rotation}° - Calibration Overlay" | ||
| try: | ||
| title_font = ImageFont.truetype("/System/Library/Fonts/Helvetica.ttc", 16) | ||
| except: | ||
| title_font = ImageFont.load_default() |
There was a problem hiding this comment.
Bare except: clauses — use except Exception: or except OSError:.
Bare except: catches KeyboardInterrupt, SystemExit, etc., which can hide real problems during test runs and make debugging difficult.
Proposed fix
try:
font = ImageFont.truetype("/System/Library/Fonts/Helvetica.ttc", 12)
- except:
+ except OSError:
font = ImageFont.load_default() try:
title_font = ImageFont.truetype("/System/Library/Fonts/Helvetica.ttc", 16)
- except:
+ except OSError:
title_font = ImageFont.load_default()📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| try: | |
| font = ImageFont.truetype("/System/Library/Fonts/Helvetica.ttc", 12) | |
| except: | |
| font = ImageFont.load_default() | |
| bbox = draw.textbbox((label_x, label_y), label, font=font) | |
| draw.rectangle(bbox, fill="white", outline="black") | |
| draw.text((label_x, label_y), label, fill="black", font=font) | |
| # Add title | |
| title = f"Rotation {rotation}° - Calibration Overlay" | |
| try: | |
| title_font = ImageFont.truetype("/System/Library/Fonts/Helvetica.ttc", 16) | |
| except: | |
| title_font = ImageFont.load_default() | |
| try: | |
| font = ImageFont.truetype("/System/Library/Fonts/Helvetica.ttc", 12) | |
| except OSError: | |
| font = ImageFont.load_default() | |
| bbox = draw.textbbox((label_x, label_y), label, font=font) | |
| draw.rectangle(bbox, fill="white", outline="black") | |
| draw.text((label_x, label_y), label, fill="black", font=font) | |
| # Add title | |
| title = f"Rotation {rotation}° - Calibration Overlay" | |
| try: | |
| title_font = ImageFont.truetype("/System/Library/Fonts/Helvetica.ttc", 16) | |
| except OSError: | |
| title_font = ImageFont.load_default() |
🤖 Prompt for AI Agents
In `@tests/test_autocrop_floor.py` around lines 74 - 88, Replace the bare except
clauses used when loading fonts with a specific exception type so system-level
interrupts aren't swallowed: update the two try/except blocks that call
ImageFont.truetype (the blocks assigning font and title_font) to catch OSError
(or Exception if broader) instead of a bare except, keeping the fallback to
ImageFont.load_default() unchanged and preserving the behavior of draw.textbbox
and draw.text that use font/title_font.
| overlay1 = draw_calibration_overlay(image1, cal_points_270, 270) | ||
| overlay1.save("/tmp/autocrop_rotation_270_overlay.png") | ||
| print(f"✅ Saved Image 1 overlay to /tmp/autocrop_rotation_270_overlay.png") | ||
| overlay1.show() |
There was a problem hiding this comment.
overlay.show() calls are not gated behind ENABLE_PIL_SHOW.
tests/test.py introduced the ENABLE_PIL_SHOW flag specifically to avoid GUI overhead and headless-environment failures, but this file unconditionally calls .show() on every overlay. This will fail or hang in headless CI and is inconsistent with the approach taken in the main test file.
Proposed fix — guard or remove the `.show()` calls
overlay1.save("/tmp/autocrop_rotation_270_overlay.png")
print(f"✅ Saved Image 1 overlay to /tmp/autocrop_rotation_270_overlay.png")
- overlay1.show()
+ # overlay1.show() # Use ENABLE_PIL_SHOW or remove for CI compatibilityApply the same pattern to overlay2.show(), overlay3.show(), and overlay4.show().
Also applies to: 229-229, 238-238, 247-247
🤖 Prompt for AI Agents
In `@tests/test_autocrop_floor.py` at line 220, The tests call overlay1.show(),
overlay2.show(), overlay3.show(), and overlay4.show() unconditionally which can
hang in headless CI; guard each .show() call with the ENABLE_PIL_SHOW flag used
in tests/test.py (e.g., if ENABLE_PIL_SHOW: overlay1.show()), or remove the
calls entirely—update the code paths that invoke overlay1.show, overlay2.show,
overlay3.show, and overlay4.show to follow that pattern so the display is only
executed when ENABLE_PIL_SHOW is truthy.
# Conflicts: # pyproject.toml
Add support for custom IP address, port, and protocol configuration for obstacle image links to enable reverse proxy and HTTPS endpoints. Changes: - Add three new configuration constants: CONF_OBSTACLE_LINK_IP, CONF_OBSTACLE_LINK_PORT, CONF_OBSTACLE_LINK_PROTOCOL - Update CameraShared class to accept custom obstacle link parameters in device_info - Modify _compose_obstacle_links() method to use custom parameters with fallback to vacuum_ips - Add validation for port (int conversion) and IP (empty string check) - Export new constants in __init__.py for mqtt_vacuum_camera integration - Maintain full backward compatibility (all parameters optional) Testing: - Tested with custom endpoint: https://192.168.1.100:180 - Tested fallback behavior with None values - 10 frames generated successfully, avg 155.9ms - All 17 obstacle links correctly formatted Quality: - Ruff: All checks passed ✅ - Pylint: 9.96/10 (1 warning: too-many-branches in update_shared_data) Version: 0.2.5b0 (beta release)
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@SCR/valetudo_map_parser/config/shared.py`:
- Around line 174-186: The current guard returns None when vacuum_host_ip is
falsy even if a custom_ip is provided; update the check in the function that
builds obstacle_links (references: obstacle_links, vacuum_host_ip, custom_ip,
custom_protocol, custom_port) so it only returns None when obstacles is falsy OR
both vacuum_host_ip and custom_ip are falsy (e.g., require at least one of
vacuum_host_ip or custom_ip). Also relax the caller-side gating in
generate_attributes (references: generate_attributes, self.vacuum_ips) so it
permits execution when a custom_ip is supplied even if self.vacuum_ips is empty.
| obstacle_links = [] | ||
| if not obstacles or not vacuum_host_ip: | ||
| return None | ||
|
|
||
| # Determine which IP/port/protocol to use | ||
| ip_to_use = custom_ip if custom_ip else vacuum_host_ip | ||
| protocol_to_use = custom_protocol if custom_protocol else "http" | ||
|
|
||
| # Build base URL | ||
| if custom_port: | ||
| base_url = f"{protocol_to_use}://{ip_to_use}:{custom_port}" | ||
| else: | ||
| base_url = f"{protocol_to_use}://{ip_to_use}" |
There was a problem hiding this comment.
Guard on vacuum_host_ip may block valid custom-IP-only configurations.
Line 175 returns None when vacuum_host_ip is falsy, even if custom_ip is provided. Combined with the caller (line 265) gating on self.vacuum_ips, users who configure a custom IP but lack vacuum_ips will never get obstacle links generated. If custom IP is meant to be an independent alternative (not just an override), the guard should also consider custom_ip.
Suggested fix
- if not obstacles or not vacuum_host_ip:
+ if not obstacles or not (vacuum_host_ip or custom_ip):
return NoneAnd in generate_attributes, relax the caller guard similarly if needed.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| obstacle_links = [] | |
| if not obstacles or not vacuum_host_ip: | |
| return None | |
| # Determine which IP/port/protocol to use | |
| ip_to_use = custom_ip if custom_ip else vacuum_host_ip | |
| protocol_to_use = custom_protocol if custom_protocol else "http" | |
| # Build base URL | |
| if custom_port: | |
| base_url = f"{protocol_to_use}://{ip_to_use}:{custom_port}" | |
| else: | |
| base_url = f"{protocol_to_use}://{ip_to_use}" | |
| obstacle_links = [] | |
| if not obstacles or not (vacuum_host_ip or custom_ip): | |
| return None | |
| # Determine which IP/port/protocol to use | |
| ip_to_use = custom_ip if custom_ip else vacuum_host_ip | |
| protocol_to_use = custom_protocol if custom_protocol else "http" | |
| # Build base URL | |
| if custom_port: | |
| base_url = f"{protocol_to_use}://{ip_to_use}:{custom_port}" | |
| else: | |
| base_url = f"{protocol_to_use}://{ip_to_use}" |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@SCR/valetudo_map_parser/config/shared.py` around lines 174 - 186, The current
guard returns None when vacuum_host_ip is falsy even if a custom_ip is provided;
update the check in the function that builds obstacle_links (references:
obstacle_links, vacuum_host_ip, custom_ip, custom_protocol, custom_port) so it
only returns None when obstacles is falsy OR both vacuum_host_ip and custom_ip
are falsy (e.g., require at least one of vacuum_host_ip or custom_ip). Also
relax the caller-side gating in generate_attributes (references:
generate_attributes, self.vacuum_ips) so it permits execution when a custom_ip
is supplied even if self.vacuum_ips is empty.
…ization Fixed API inconsistency where data["image"] structure was only populated when bytes_format=True, causing KeyError in mqtt_vacuum_camera when accessing data["image"]["size"] with bytes_format=False. Added JPEG output format support to enable direct PIL→JPEG conversion for MJPEG streaming, eliminating the inefficient PIL→PNG→PIL→JPEG double conversion. Changes: - Modified _process_new_image() to always call shared.to_dict() (SCR/valetudo_map_parser/config/utils.py:186) - Updated _convert_to_binary() to support JPEG format via shared.image_format (SCR/valetudo_map_parser/config/utils.py:205-221) - Added pil_to_jpeg_bytes() function for RGBA→RGB→JPEG conversion (SCR/valetudo_map_parser/config/utils.py:1001-1006) - Updated to_dict() docstring to clarify API contract (SCR/valetudo_map_parser/config/shared.py:294-308) - Exported pil_to_jpeg_bytes and pil_to_png_bytes in __init__.py - Added test_bytes_format_consistency.py to verify API consistency - Bumped version to 0.2.5b1 Format Support: - "image/pil" (default): bytes_format=True → PNG bytes - "image/png": bytes_format=True → PNG bytes - "image/jpeg": bytes_format=True → JPEG bytes - All formats: bytes_format=False → PIL Image object Impact: - Enables mqtt_vacuum_camera PR #419 MJPEG optimization - Reduces CPU usage and memory allocations for streaming - data["image"]["size"] now always available for calibration - Backward compatible: existing code unchanged Test: ✅ test_bytes_format_consistency.py passes
There was a problem hiding this comment.
Actionable comments posted: 3
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/config/shared.py (1)
76-76:⚠️ Potential issue | 🟠 Major
binary_imagetype annotation is out of date — it can now hold aPIL Image.
_convert_to_binaryassignsself.shared.binary_image = new_image(aPIL Image) whenbytes_format=False, but the annotation still readsbytes | None. The updatedto_dict()docstring acknowledges this, but the annotation on the attribute itself misleads type checkers and callers.📝 Proposed fix
- self.binary_image: bytes | None = None + self.binary_image: bytes | Image | None = None🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@SCR/valetudo_map_parser/config/shared.py` at line 76, The attribute self.binary_image is annotated as bytes | None but can also hold a PIL Image; update the annotation on the SharedConfig (or relevant class) to include the PIL Image type (e.g., bytes | PIL.Image.Image | None or bytes | Image | None) and add the appropriate import from PIL (from PIL import Image or from PIL.Image import Image) so type checkers match the behavior in _convert_to_binary and the to_dict() docstring.
🧹 Nitpick comments (2)
tests/test_bytes_format_consistency.py (1)
16-16:sys.pathmanipulation is a test-infrastructure code smell.Inserting the project root into
sys.pathat test time indicates the package is not properly installed in the test environment. The canonical fix is to install the package in development mode (pip install -e .) so imports resolve naturally without runtime path hacking.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/test_bytes_format_consistency.py` at line 16, Remove the runtime sys.path manipulation (the sys.path.insert(...) call) from the tests and stop relying on test-time path hacks; instead ensure the package is installed in the test environment (e.g., add a step in your local/CI test setup to run pip install -e . or configure tox/pytest to install the package in editable mode) so imports resolve naturally without the sys.path.insert call.SCR/valetudo_map_parser/config/utils.py (1)
106-109: Stale@param bytes_formatdocstring.The docstring says
"convert to PNG bytes"but the new_convert_to_binarycan also produce JPEG bytes.📝 Proposed fix
- `@param` bytes_format: If True, also convert to PNG bytes and store in shared.binary_image + `@param` bytes_format: If True, convert to bytes (JPEG or PNG per shared.image_format) and store in shared.binary_image; if False, store the PIL Image directly🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@SCR/valetudo_map_parser/config/utils.py` around lines 106 - 109, Update the stale docstring for the function that documents parameters m_json, destinations, bytes_format, and text_enabled (the docstring block in utils.py) to reflect that bytes_format no longer always produces PNG and that _convert_to_binary can produce JPEG as well; change the bytes_format description to say something like "If True, also convert to binary image bytes (PNG or JPEG) and store in shared.binary_image" and ensure any mention of PNG is replaced with a neutral "binary image bytes" (or lists both PNG/JPEG) so the docstring accurately matches the behavior of _convert_to_binary.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@SCR/valetudo_map_parser/config/utils.py`:
- Around line 1008-1012: Add a docstring to pil_to_jpeg_bytes matching the
sibling pil_to_png_bytes (e.g., "Convert PIL Image to JPEG bytes.") and ensure
the intermediate RGB image from pil_img.convert("RGB") is explicitly closed to
avoid leaking resources; for example, assign pil_img.convert("RGB") to a local
variable (e.g., rgb_img) and use a try/finally or context manager to save
rgb_img to io.BytesIO and then call rgb_img.close() in the finally block,
keeping the existing signature and behavior of pil_to_jpeg_bytes.
In `@tests/test_bytes_format_consistency.py`:
- Around line 35-42: The device_info dict in the test uses wrong keys so
update_shared_data cannot read them; change the test's keys to match the
constants used by update_shared_data (use ATTR_ROTATE/"rotate_image" instead of
"image_rotate", CONF_AUTO_ZOOM/"auto_zoom" instead of "image_auto_zoom", and
keep CONF_ASPECT_RATIO/"aspect_ratio"), so that update_shared_data(device_info)
reads the intended values rather than falling back to DEFAULT_VALUES; locate the
device_info declaration in tests/test_bytes_format_consistency.py and rename the
keys accordingly.
- Line 26: The test function test_bytes_format_consistency is defined as async
but lacks the pytest-asyncio marker and the project lacks pytest-asyncio as a
dev dependency; add pytest-asyncio to dev dependencies (e.g., under
[tool.poetry.group.dev.dependencies]) and annotate the test with
`@pytest.mark.asyncio` above async def test_bytes_format_consistency() so pytest
runs it as an async test.
---
Outside diff comments:
In `@SCR/valetudo_map_parser/config/shared.py`:
- Line 76: The attribute self.binary_image is annotated as bytes | None but can
also hold a PIL Image; update the annotation on the SharedConfig (or relevant
class) to include the PIL Image type (e.g., bytes | PIL.Image.Image | None or
bytes | Image | None) and add the appropriate import from PIL (from PIL import
Image or from PIL.Image import Image) so type checkers match the behavior in
_convert_to_binary and the to_dict() docstring.
---
Duplicate comments:
In `@SCR/valetudo_map_parser/config/shared.py`:
- Around line 174-175: The guard that skips obstacle link creation incorrectly
bails when vacuum_host_ip is falsy even though a user-specified obstacle_link_ip
or custom_ip should allow links; change the condition around obstacle_links (and
any early return) to check for the presence of obstacle_link_ip or
custom_ip/custom_port/custom_protocol or vacuum_host_ip instead of just `not
vacuum_host_ip`, and update generate_attributes (which currently gates on
self.vacuum_ips) to also accept and use obstacle_link_ip/custom_ip when
self.vacuum_ips is empty so obstacle links are produced even for custom-IP-only
deployments (refer to obstacle_links, vacuum_host_ip, obstacle_link_ip,
custom_ip/custom_port/custom_protocol, generate_attributes, and
self.vacuum_ips).
---
Nitpick comments:
In `@SCR/valetudo_map_parser/config/utils.py`:
- Around line 106-109: Update the stale docstring for the function that
documents parameters m_json, destinations, bytes_format, and text_enabled (the
docstring block in utils.py) to reflect that bytes_format no longer always
produces PNG and that _convert_to_binary can produce JPEG as well; change the
bytes_format description to say something like "If True, also convert to binary
image bytes (PNG or JPEG) and store in shared.binary_image" and ensure any
mention of PNG is replaced with a neutral "binary image bytes" (or lists both
PNG/JPEG) so the docstring accurately matches the behavior of
_convert_to_binary.
In `@tests/test_bytes_format_consistency.py`:
- Line 16: Remove the runtime sys.path manipulation (the sys.path.insert(...)
call) from the tests and stop relying on test-time path hacks; instead ensure
the package is installed in the test environment (e.g., add a step in your
local/CI test setup to run pip install -e . or configure tox/pytest to install
the package in editable mode) so imports resolve naturally without the
sys.path.insert call.
| _LOGGER = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| async def test_bytes_format_consistency(): |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check for asyncio configuration in common config files
echo "=== Checking pyproject.toml for asyncio config ==="
rg -A 5 "asyncio_mode|pytest-asyncio" pyproject.toml 2>/dev/null || echo "No asyncio config found"
echo -e "\n=== Checking pytest.ini ==="
cat pytest.ini 2>/dev/null || echo "No pytest.ini found"
echo -e "\n=== Checking setup.cfg ==="
cat setup.cfg 2>/dev/null || echo "No setup.cfg found"
echo -e "\n=== Checking conftest.py ==="
fd "conftest.py" --exec cat {} \; 2>/dev/null || echo "No conftest.py found"
echo -e "\n=== Listing test files ==="
fd "test_bytes_format_consistency.py" --exec cat {} \;Repository: sca075/Python-package-valetudo-map-parser
Length of output: 5509
🏁 Script executed:
#!/bin/bash
# Check dependencies in pyproject.toml
echo "=== Checking for pytest-asyncio in dependencies ==="
rg -A 30 "\[project\]" pyproject.toml | head -60
rg -A 50 "dependencies|dev-dependencies|optional-dependencies" pyproject.tomlRepository: sca075/Python-package-valetudo-map-parser
Length of output: 968
Add @pytest.mark.asyncio decorator and pytest-asyncio to dev dependencies.
async def test_bytes_format_consistency() has no asyncio marker. The project also lacks pytest-asyncio in dev dependencies. Without both, pytest will collect but not properly execute this coroutine as an async test; it runs only via the if __name__ == "__main__" path.
Proposed fix
- Add
pytest-asyncioto dev dependencies inpyproject.toml:
[tool.poetry.group.dev.dependencies]
pytest-asyncio = "*"- Add the decorator to the test:
+import pytest
+
+@pytest.mark.asyncio
async def test_bytes_format_consistency():🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tests/test_bytes_format_consistency.py` at line 26, The test function
test_bytes_format_consistency is defined as async but lacks the pytest-asyncio
marker and the project lacks pytest-asyncio as a dev dependency; add
pytest-asyncio to dev dependencies (e.g., under
[tool.poetry.group.dev.dependencies]) and annotate the test with
`@pytest.mark.asyncio` above async def test_bytes_format_consistency() so pytest
runs it as an async test.
| device_info = { | ||
| "image_rotate": 0, | ||
| "image_auto_zoom": True, | ||
| "image_ref_height": 1080, | ||
| "image_ref_width": 1920, | ||
| "user_language": "en", | ||
| "aspect_ratio": "None", | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Find the constants and their values
rg -n "ATTR_ROTATE|CONF_ASPECT_RATIO|CONF_AUTO_ZOOM" --type py -B 2 -A 0 | head -50Repository: sca075/Python-package-valetudo-map-parser
Length of output: 2822
🏁 Script executed:
#!/bin/bash
# Also search for where these constants are defined
rg -n "(ATTR_ROTATE|CONF_ASPECT_RATIO|CONF_AUTO_ZOOM)\s*=" --type pyRepository: sca075/Python-package-valetudo-map-parser
Length of output: 284
🏁 Script executed:
#!/bin/bash
# Find the test file and examine its full context
find . -name "test_bytes_format_consistency.py" -type fRepository: sca075/Python-package-valetudo-map-parser
Length of output: 125
🏁 Script executed:
#!/bin/bash
# Look for update_shared_data function to understand what it expects
rg -n "def update_shared_data" --type py -A 30Repository: sca075/Python-package-valetudo-map-parser
Length of output: 2824
🏁 Script executed:
#!/bin/bash
# Get the full test file content
cat -n ./tests/test_bytes_format_consistency.py | head -80Repository: sca075/Python-package-valetudo-map-parser
Length of output: 3541
🏁 Script executed:
#!/bin/bash
# Get the complete update_shared_data function
rg -n "def update_shared_data" --type py -A 50Repository: sca075/Python-package-valetudo-map-parser
Length of output: 4623
🏁 Script executed:
#!/bin/bash
# Also check for any other constants that might be used
rg -n "CONF_|ATTR_" SCR/valetudo_map_parser/const.py --type py | head -40Repository: sca075/Python-package-valetudo-map-parser
Length of output: 1668
🏁 Script executed:
#!/bin/bash
# Check CameraSharedManager init method
rg -n "class CameraSharedManager" --type py -A 20Repository: sca075/Python-package-valetudo-map-parser
Length of output: 1791
🏁 Script executed:
#!/bin/bash
# Check the __init__ method of CameraSharedManager
rg -n "def __init__" SCR/valetudo_map_parser/config/shared.py -A 15 | head -60Repository: sca075/Python-package-valetudo-map-parser
Length of output: 1477
Device info keys don't match the constants expected by update_shared_data.
update_shared_data reads configuration via ATTR_ROTATE = "rotate_image", CONF_AUTO_ZOOM = "auto_zoom", and CONF_ASPECT_RATIO = "aspect_ratio". The test's device_info dict uses mismatched keys: "image_rotate" (should be "rotate_image"), "image_auto_zoom" (should be "auto_zoom"), and "aspect_ratio" (correct). When device_info.get(constant) is called in update_shared_data, the mismatched keys aren't found, so the function falls back to DEFAULT_VALUES, causing the test to pass with unintended default values rather than the test-provided config.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@tests/test_bytes_format_consistency.py` around lines 35 - 42, The device_info
dict in the test uses wrong keys so update_shared_data cannot read them; change
the test's keys to match the constants used by update_shared_data (use
ATTR_ROTATE/"rotate_image" instead of "image_rotate", CONF_AUTO_ZOOM/"auto_zoom"
instead of "image_auto_zoom", and keep CONF_ASPECT_RATIO/"aspect_ratio"), so
that update_shared_data(device_info) reads the intended values rather than
falling back to DEFAULT_VALUES; locate the device_info declaration in
tests/test_bytes_format_consistency.py and rename the keys accordingly.
Add support for configurable image output formats (PIL, PNG, JPEG) with proper API: - Add set_content_type() and get_content_type() methods to CameraShared - Validates format against ALLOWED_IMAGE_FORMAT constant - Makes _image_format private attribute for proper encapsulation - Implement match-case logic in _convert_to_binary() for all formats - image/jpeg → pil_to_jpeg_bytes() with RGB conversion - image/png → pil_to_png_bytes() - image/pil → pil_to_pil_bytes() - Add ALLOWED_IMAGE_FORMAT constant to const.py - Centralized format definitions: pil, png, jpeg - Exported in __init__.py for mqtt_vacuum_camera usage - Add pil_to_pil_bytes() conversion function - Completes trio of image conversion utilities - All three functions exported in __init__.py - Bump version: 0.2.5b1 → 0.2.5b2 This API is for programmer use in mqtt_vacuum_camera, not end-user configuration.
- Added automatic content type selection in _convert_to_binary():
* MAP_VIEW mode → JPEG format (optimized for map images)
* OBSTACLE_VIEW mode → PNG format (preserves obstacle details)
- Implementation is library-safe:
* Works with CameraModes constants (CameraModes.MAP_VIEW)
* Works with direct string values ("map_view")
* Added CameraModes to utils.py imports
- Version bump: 0.2.5b2 → 0.2.5b3
* Updated pyproject.toml
* Updated __init__.py
Quality checks:
- Ruff: All checks passed!
- isort: All imports properly sorted
- Pylint: 9.98/10 (no new issues)
Version Updates: - Bumped from 0.2.5b3 to stable 0.2.5 - Updated pyproject.toml and __init__.py CHANGELOG Updates: - Added comprehensive entries for all beta versions: * 0.2.5b0: Customizable obstacle image links * 0.2.5b1: JPEG format support and API consistency fixes * 0.2.5b2: Image format configuration with ALLOWED_IMAGE_FORMAT * 0.2.5b3: Reverted automatic content type selection * 0.2.5: Stable release Code Changes: - Reverted experimental automatic content type selection from utils.py - Removed CameraModes import (no longer needed) - Content type selection remains manual via set_content_type() method - Code formatted with ruff Quality: - isort: All imports properly sorted - ruff: Code formatted - Library maintains backward compatibility
chore:
Update dependencies to match Home Assistant 2025.x requirements:
Fix memory optimization in hypfer_handler:
Fix dock_state display logic:
Improve test configuration:
Code quality improvements:
Performance: 100 frames @ 106ms avg, Memory: 0.12 MB/frame growth
Quality Gate:
Summary by CodeRabbit
Version Release
New Features
Performance
Tests
Chores