Skip to content

feat: add Conga vacuum support — bump to v0.3.0b2#74

Open
sca075 wants to merge 6 commits intomainfrom
dev
Open

feat: add Conga vacuum support — bump to v0.3.0b2#74
sca075 wants to merge 6 commits intomainfrom
dev

Conversation

@sca075
Copy link
Owner

@sca075 sca075 commented Mar 9, 2026

feat: add Conga vacuum support — bump to v0.3.0b2

  • Add CongaMapImageHandler: scales Conga JSON (pixelSize, canvas size,
    entity coordinates) by ×5 before the Hypfer render pipeline, producing
    solid filled rooms and correctly positioned entities without post-upscale
  • Add CongaImageDraw: thin subclass of HypferImageDraw; coordinate scaling
    handled entirely in the handler
  • Add ImageData.is_conga_map() for detection via congaPixels field presence
  • Export CongaMapImageHandler and ImageData in public API (init.py)
  • Add tests/test_conga.py: detection, image generation, room extraction,
    calibration data (4-point vacuum↔map pairs), room data structure
  • Fix ALLOWED_IMAGE_FORMAT dict formatting in const.py
  • Bump version 0.2.9 → 0.3.0b0

Summary by CodeRabbit

  • New Features

    • Added first-class support for Conga vacuum maps: automatic detection, scaling, and improved rendering.
    • Image handling now accepts Conga-specific pixel data when present.
    • New Conga-specific drawing and map handler to render Conga maps consistently.
  • Chores

    • Version bumped to 0.3.0b2.
    • Minor formatting and import reorganizations (no behavioral changes).

- Add CongaMapImageHandler: scales Conga JSON (pixelSize, canvas size,
  entity coordinates) by ×5 before the Hypfer render pipeline, producing
  solid filled rooms and correctly positioned entities without post-upscale
- Add CongaImageDraw: thin subclass of HypferImageDraw; coordinate scaling
  handled entirely in the handler
- Add ImageData.is_conga_map() for detection via congaPixels field presence
- Export CongaMapImageHandler and ImageData in public API (__init__.py)
- Add tests/test_conga.py: detection, image generation, room extraction,
  calibration data (4-point vacuum↔map pairs), room data structure
- Fix ALLOWED_IMAGE_FORMAT dict formatting in const.py
- Bump version 0.2.9 → 0.3.0b0
@sca075 sca075 self-assigned this Mar 9, 2026
@sca075 sca075 added the enhancement New feature or request label Mar 9, 2026
@coderabbitai
Copy link

coderabbitai bot commented Mar 9, 2026

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds Conga vacuum support: new CongaMapImageHandler and CongaImageDraw, Conga-aware pixel handling in ImageData (fallback to congaPixels), CameraShared.is_conga flag and utilities path for Conga JSON handling, public exports updated, and version bumped to 0.3.0b2.

Changes

Cohort / File(s) Summary
Public API / Init
SCR/valetudo_map_parser/__init__.py
Bumps package version and re-exports CongaMapImageHandler and ImageData, updating __all__.
Conga handler & drawing
SCR/valetudo_map_parser/conga_handler.py, SCR/valetudo_map_parser/conga_draw.py
Adds CongaMapImageHandler (scales Conga JSON and delegates rendering) and CongaImageDraw with CONGA_SCALE = 5.
Map data
SCR/valetudo_map_parser/map_data.py
ImageData now falls back to congaPixels when compressedPixels is missing to support Conga maps.
Handler utilities & config
SCR/valetudo_map_parser/config/utils.py, SCR/valetudo_map_parser/config/shared.py
_generate_new_image prefers async_get_conga_from_json if present; CameraShared gains is_conga and small formatting/signature tweaks.
Minor formatting / logging
SCR/valetudo_map_parser/const.py, SCR/valetudo_map_parser/reimg_draw.py
Cosmetic formatting and a simplified log call; no behavior changes.
Project metadata
pyproject.toml
Version bumped to 0.3.0b2.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant CongaHandler as CongaMapImageHandler
    participant MapData as ImageData
    participant BaseHandler as HypferMapImageHandler
    participant Draw as CongaImageDraw

    Caller->>CongaHandler: async_get_image_from_json(m_json)
    CongaHandler->>MapData: is_conga_map(m_json)?
    alt conga detected
        CongaHandler->>CongaHandler: _scale_conga_json(m_json, CONGA_SCALE)
        CongaHandler->>BaseHandler: async_get_image_from_json(scaled_json)
    else not conga
        CongaHandler->>BaseHandler: async_get_image_from_json(m_json)
    end
    BaseHandler->>Draw: render layers/entities
    Draw-->>BaseHandler: Image
    BaseHandler-->>CongaHandler: Image
    CongaHandler-->>Caller: Image
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • shared updated #21 — touches config/shared.py and adds CameraShared attributes; likely overlaps on is_conga and shared configuration changes.
  • Memory optimize. #19 — modifies image generation/resizing utilities; overlaps with _generate_new_image changes and image sourcing logic.

Poem

🐰
I nibbled at pixels, found a conga line,
Scaled each hop steady so the map would shine.
I asked "is_conga?" and helpers replied,
Brushes and bytes in a hopping glide.
Hooray for clearer maps and a joyful stride!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the primary change: adding Conga vacuum support with a version bump to v0.3.0b2.
Docstring Coverage ✅ Passed Docstring coverage is 91.67% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch dev

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.

@sca075 sca075 temporarily deployed to valetudo_map_parser_pypi March 9, 2026 21:19 — with GitHub Actions Inactive
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: 4

🤖 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/__init__.py`:
- Around line 1-2: Update the module docstring in __init__.py so the advertised
version matches pyproject.toml: change the version text in the top-level module
string (the triple-quoted docstring in SCR/valetudo_map_parser/__init__.py) from
"0.2.6" to "0.3.0b0" ensuring the exact new version token is used so docs and
quick source inspection reflect the current release.

In `@SCR/valetudo_map_parser/config/shared.py`:
- Around line 154-159: The set_content_type method currently only accepts keys
from ALLOWED_IMAGE_FORMAT (e.g., "pil","png","jpeg") but defaults to
"image/pil", so calling get_content_type() (which returns MIME values) and
passing that back into set_content_type resets formats to PIL; update
set_content_type to accept either a key or a MIME value: if new_image_format is
in ALLOWED_IMAGE_FORMAT keys, set self._image_format =
ALLOWED_IMAGE_FORMAT[new_image_format]; else if new_image_format is in
ALLOWED_IMAGE_FORMAT.values(), set self._image_format = new_image_format;
otherwise fall back to a sensible default (e.g., ALLOWED_IMAGE_FORMAT["pil"]) to
avoid the unexpected reset; reference function set_content_type,
ALLOWED_IMAGE_FORMAT and get_content_type when making the change.

In `@SCR/valetudo_map_parser/config/utils.py`:
- Around line 83-98: Add a factory function that centralizes handler selection
by calling ImageData.detect_vacuum_type(json_data) and branching on its return
value to instantiate the correct handler: when it returns "conga" return a
CongaMapImageHandler(shared) instance, when "rand256" return
ReImageHandler(shared) (or the existing Re/Rand handler), otherwise return
HypferMapImageHandler(shared); replace existing direct instantiations (e.g.,
places creating HypferMapImageHandler(shared) directly) to use this new factory
so CongaMapImageHandler can be reached via the detector.

In `@SCR/valetudo_map_parser/map_data.py`:
- Around line 300-303: The code only falls back to congaPixels when
compressed_pixels is exactly None, which misses upstream payloads that provide
an empty list; change the condition in the ImageData parsing so empty
compressed_pixels is treated the same as missing data (e.g., replace "if
compressed_pixels is None:" with a falsy check like "if not
compressed_pixels:"), then build pixels from json_obj.get("pixels") or
json_obj.get("congaPixels", []) and call
ImageData._convert_pixels_to_compressed(pixels) as before.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5e71a0d0-95da-49f4-85fb-baa104afb09d

📥 Commits

Reviewing files that changed from the base of the PR and between 05e56f4 and d6029aa.

📒 Files selected for processing (7)
  • SCR/valetudo_map_parser/__init__.py
  • SCR/valetudo_map_parser/config/shared.py
  • SCR/valetudo_map_parser/config/utils.py
  • SCR/valetudo_map_parser/const.py
  • SCR/valetudo_map_parser/map_data.py
  • SCR/valetudo_map_parser/reimg_draw.py
  • pyproject.toml

Comment on lines +1 to +2
"""Valetudo map parser.
Version: 0.2.7"""
Version: 0.2.6"""
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Update the module header version to match the release.

This file still advertises 0.2.6, while pyproject.toml was bumped to 0.3.0b0. Keeping them aligned avoids stale metadata in generated docs and quick source inspection.

Proposed fix
-"""Valetudo map parser.
-Version: 0.2.6"""
+"""Valetudo map parser.
+Version: 0.3.0b0"""
📝 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.

Suggested change
"""Valetudo map parser.
Version: 0.2.7"""
Version: 0.2.6"""
"""Valetudo map parser.
Version: 0.3.0b0"""
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@SCR/valetudo_map_parser/__init__.py` around lines 1 - 2, Update the module
docstring in __init__.py so the advertised version matches pyproject.toml:
change the version text in the top-level module string (the triple-quoted
docstring in SCR/valetudo_map_parser/__init__.py) from "0.2.6" to "0.3.0b0"
ensuring the exact new version token is used so docs and quick source inspection
reflect the current release.

Comment on lines +154 to 159
def set_content_type(self, new_image_format: str = "image/pil") -> None:
"""Set image format / content type"""
if new_image_format not in ALLOWED_IMAGE_FORMAT.keys():
self._image_format = "image/pil"
return
self._image_format = ALLOWED_IMAGE_FORMAT.get(new_image_format)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Accept MIME values here or change the default to a format key.

Line 154 defaults to "image/pil", but Line 156 only accepts the keys from ALLOWED_IMAGE_FORMAT ("pil", "png", "jpeg"). That means round-tripping get_content_type() back into set_content_type() will unexpectedly reset PNG/JPEG back to PIL.

Proposed fix
-    def set_content_type(self, new_image_format: str = "image/pil") -> None:
-        """Set image format / content type"""
-        if new_image_format not in ALLOWED_IMAGE_FORMAT.keys():
-            self._image_format = "image/pil"
-            return
-        self._image_format = ALLOWED_IMAGE_FORMAT.get(new_image_format)
+    def set_content_type(self, new_image_format: str = "pil") -> None:
+        """Set image format / content type."""
+        if new_image_format in ALLOWED_IMAGE_FORMAT.values():
+            self._image_format = new_image_format
+            return
+        self._image_format = ALLOWED_IMAGE_FORMAT.get(new_image_format, "image/pil")
🤖 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 154 - 159, The
set_content_type method currently only accepts keys from ALLOWED_IMAGE_FORMAT
(e.g., "pil","png","jpeg") but defaults to "image/pil", so calling
get_content_type() (which returns MIME values) and passing that back into
set_content_type resets formats to PIL; update set_content_type to accept either
a key or a MIME value: if new_image_format is in ALLOWED_IMAGE_FORMAT keys, set
self._image_format = ALLOWED_IMAGE_FORMAT[new_image_format]; else if
new_image_format is in ALLOWED_IMAGE_FORMAT.values(), set self._image_format =
new_image_format; otherwise fall back to a sensible default (e.g.,
ALLOWED_IMAGE_FORMAT["pil"]) to avoid the unexpected reset; reference function
set_content_type, ALLOWED_IMAGE_FORMAT and get_content_type when making the
change.

Comment on lines +83 to +98
@staticmethod
def detect_vacuum_type(json_data: dict) -> str:
"""Detect the vacuum type from the raw JSON map data.

Returns:
'conga' — Conga vacuum (congaPixels present in layers)
'hypfer' — Standard Hypfer/Valetudo vacuum
'rand256' — Rand256 / Valetudo Re vacuum (rrm key present)
"""
if not isinstance(json_data, dict):
return "hypfer"
if "rrm" in json_data or json_data.get("__class") == "RRMap":
return "rand256"
if ImageData.is_conga_map(json_data):
return "conga"
return "hypfer"
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Definitions and call sites for detect_vacuum_type():"
rg -n -C2 '\bdetect_vacuum_type\s*\(' --type=py

echo
echo "References to concrete handler classes:"
rg -n -C3 '\bCongaMapImageHandler\b|\bHypferMapImageHandler\b|\bReImageHandler\b' --type=py

echo
echo "Potential factory/selection code:"
rg -n -C4 'detect_vacuum_type|CongaMapImageHandler|HypferMapImageHandler|ReImageHandler|handler' --type=py

Repository: sca075/Python-package-valetudo-map-parser

Length of output: 50397


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== CALL SITES for detect_vacuum_type() ==="
rg -n 'detect_vacuum_type\(' --type=py | grep -v 'def detect_vacuum_type'

echo
echo "=== IMPORTS of BaseHandler.detect_vacuum_type ==="
rg -n 'from.*detect_vacuum_type|import.*detect_vacuum_type' --type=py

echo
echo "=== Check main __init__.py for handler factory logic ==="
head -200 SCR/valetudo_map_parser/__init__.py | tail -120

Repository: sca075/Python-package-valetudo-map-parser

Length of output: 128


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Checking __init__.py for handler initialization logic ==="
cat SCR/valetudo_map_parser/__init__.py | head -250 | tail -100

echo
echo "=== Check for RRMapParser class (main entry point) ==="
fd -t f "RRMapParser" . --type py 2>/dev/null | head -5

echo
echo "=== Search for RRMapParser definition ==="
rg -n 'class RRMapParser' --type=py -A 30

Repository: sca075/Python-package-valetudo-map-parser

Length of output: 2472


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== RRMapParser class definition ==="
rg -n 'class RRMapParser' --type=py -A 50

echo
echo "=== Search for where handlers are instantiated in main code ==="
rg -n 'HypferMapImageHandler\(|CongaMapImageHandler\(|ReImageHandler\(' --type=py | grep -v test | grep -v '\.pyc'

Repository: sca075/Python-package-valetudo-map-parser

Length of output: 4510


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Public methods accepting json_data in handlers ==="
rg -n 'def.*json_data' --type=py -B 2 -A 3 | head -80

echo
echo "=== Check if detect_vacuum_type is referenced in comments/docstrings ==="
rg -i 'detect.*vacuum|vacuum.*detect' --type=py -B 2 -A 2

echo
echo "=== Look for async_get_image entry points in handlers ==="
rg -n 'async def async_get_image' --type=py -A 5 | head -60

Repository: sca075/Python-package-valetudo-map-parser

Length of output: 7386


This detector is not integrated into handler selection—CongaMapImageHandler cannot be instantiated.

The detect_vacuum_type() method has no call sites in the codebase. Handler instantiation occurs directly (e.g., HypferMapImageHandler(shared)), not through a factory that branches on the detected vacuum type. Without wiring this detector into the handler selection path, Conga support remains unreachable despite the handler and detector both existing.

To activate Conga support, add a factory or entry point that:

  1. Calls detect_vacuum_type(json_data)
  2. Branches on the result to instantiate CongaMapImageHandler when the return value is "conga"
  3. Falls back to HypferMapImageHandler or ReImageHandler for other types
🤖 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 83 - 98, Add a factory
function that centralizes handler selection by calling
ImageData.detect_vacuum_type(json_data) and branching on its return value to
instantiate the correct handler: when it returns "conga" return a
CongaMapImageHandler(shared) instance, when "rand256" return
ReImageHandler(shared) (or the existing Re/Rand handler), otherwise return
HypferMapImageHandler(shared); replace existing direct instantiations (e.g.,
places creating HypferMapImageHandler(shared) directly) to use this new factory
so CongaMapImageHandler can be reached via the detector.

Comment on lines 300 to 303
compressed_pixels = json_obj.get("compressedPixels")
if compressed_pixels is None:
pixels = json_obj.get("pixels", [])
pixels = json_obj.get("pixels") or json_obj.get("congaPixels", [])
compressed_pixels = ImageData._convert_pixels_to_compressed(pixels)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Treat empty compressedPixels the same as missing data.

Right now the Conga fallback only runs when compressedPixels is None. If an upstream payload serializes that field as [] instead of omitting it, Line 302 never looks at congaPixels and the layer is recorded as empty.

Proposed fix
-        compressed_pixels = json_obj.get("compressedPixels")
-        if compressed_pixels is None:
+        compressed_pixels = json_obj.get("compressedPixels")
+        if not compressed_pixels:
             pixels = json_obj.get("pixels") or json_obj.get("congaPixels", [])
             compressed_pixels = ImageData._convert_pixels_to_compressed(pixels)
📝 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.

Suggested change
compressed_pixels = json_obj.get("compressedPixels")
if compressed_pixels is None:
pixels = json_obj.get("pixels", [])
pixels = json_obj.get("pixels") or json_obj.get("congaPixels", [])
compressed_pixels = ImageData._convert_pixels_to_compressed(pixels)
compressed_pixels = json_obj.get("compressedPixels")
if not compressed_pixels:
pixels = json_obj.get("pixels") or json_obj.get("congaPixels", [])
compressed_pixels = ImageData._convert_pixels_to_compressed(pixels)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@SCR/valetudo_map_parser/map_data.py` around lines 300 - 303, The code only
falls back to congaPixels when compressed_pixels is exactly None, which misses
upstream payloads that provide an empty list; change the condition in the
ImageData parsing so empty compressed_pixels is treated the same as missing data
(e.g., replace "if compressed_pixels is None:" with a falsy check like "if not
compressed_pixels:"), then build pixels from json_obj.get("pixels") or
json_obj.get("congaPixels", []) and call
ImageData._convert_pixels_to_compressed(pixels) as before.

sca075 added 3 commits March 10, 2026 08:21
- Add CongaMapImageHandler: scales Conga JSON (pixelSize, canvas size,
  entity coordinates) by ×5 before the Hypfer render pipeline, producing
  solid filled rooms and correctly positioned entities without post-upscale
- Add CongaImageDraw: thin subclass of HypferImageDraw; coordinate scaling
  handled entirely in the handler
- Add ImageData.is_conga_map() for detection via congaPixels field presence
- Export CongaMapImageHandler and ImageData in public API (__init__.py)
- Add tests/test_conga.py: detection, image generation, room extraction,
  calibration data (4-point vacuum↔map pairs), room data structure
- Fix ALLOWED_IMAGE_FORMAT dict formatting in const.py
- Bump version 0.2.9 → 0.3.0b0
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.

🧹 Nitpick comments (1)
SCR/valetudo_map_parser/conga_handler.py (1)

46-52: Scale pixelSize from the payload, not from an assumption.

Line 47 hardcodes pixelSize to scale, while the rest of the method multiplies source values. That stays correct only while every Conga map remains pixelSize == 1; using the incoming value keeps the transform self-consistent and avoids future skew if a payload variant changes.

♻️ Proposed fix
         scaled = copy.deepcopy(m_json)
-        scaled["pixelSize"] = scale
+        scaled["pixelSize"] = int(scaled.get("pixelSize", 1)) * scale
         size = scaled.get("size", {})
         scaled["size"] = {
             "x": int(size.get("x", 800)) * scale,
             "y": int(size.get("y", 800)) * scale,
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@SCR/valetudo_map_parser/conga_handler.py` around lines 46 - 52, The code
currently sets scaled["pixelSize"] = scale which assumes the incoming payload's
pixelSize is 1; instead read the incoming value from m_json and multiply it by
scale so the transform stays self-consistent. Change the assignment to compute
original_pixel = int(m_json.get("pixelSize", 1)) and set scaled["pixelSize"] =
original_pixel * scale (leaving the existing size scaling logic as-is),
referencing the variables scaled, m_json, pixelSize, scale, and size to locate
the change in conga_handler.py.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@SCR/valetudo_map_parser/conga_handler.py`:
- Around line 46-52: The code currently sets scaled["pixelSize"] = scale which
assumes the incoming payload's pixelSize is 1; instead read the incoming value
from m_json and multiply it by scale so the transform stays self-consistent.
Change the assignment to compute original_pixel = int(m_json.get("pixelSize",
1)) and set scaled["pixelSize"] = original_pixel * scale (leaving the existing
size scaling logic as-is), referencing the variables scaled, m_json, pixelSize,
scale, and size to locate the change in conga_handler.py.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c3eb75cf-f6af-47d6-8a49-582c4a23fec0

📥 Commits

Reviewing files that changed from the base of the PR and between d6029aa and 3642f36.

📒 Files selected for processing (2)
  • SCR/valetudo_map_parser/conga_draw.py
  • SCR/valetudo_map_parser/conga_handler.py

@sca075 sca075 deployed to valetudo_map_parser_pypi March 10, 2026 07:27 — with GitHub Actions Active
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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pyproject.toml`:
- Line 3: The pyproject.toml version field is set to "0.3.0b1" but the PR states
the intended prerelease is "v0.3.0b0"; update the version string in
pyproject.toml (version = "0.3.0b1") to the correct prerelease identifier to
match the release plan and ensure package metadata stays in sync with the
package __init__.py (e.g., the __version__ or VERSION constant) so tags and
published artifacts use the intended prerelease number.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 82684260-a66d-4f6e-9f56-5425a6c4b490

📥 Commits

Reviewing files that changed from the base of the PR and between 3642f36 and 608af44.

📒 Files selected for processing (2)
  • SCR/valetudo_map_parser/__init__.py
  • pyproject.toml

sca075 added 2 commits March 10, 2026 22:14
- Add CongaMapImageHandler subclassing HypferMapImageHandler with
  JSON coordinate scaling (pixelSize=1 → 5) via async_get_conga_from_json
- Add CongaImageDraw subclassing HypferImageDraw as Conga draw engine
- Add is_conga: bool = False to CameraShared for vacuum type detection
- Route Conga in BaseHandler._generate_new_image via hasattr duck-typing
- Remove is_conga_map() from ImageData and detect_vacuum_type() from
  BaseHandler — detection is mqtt_vacuum_camera's responsibility
- Export CongaMapImageHandler and ImageData from public API
@sca075 sca075 changed the title feat: add Conga vacuum support — bump to v0.3.0b0 feat: add Conga vacuum support — bump to v0.3.0b2 Mar 10, 2026
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

♻️ Duplicate comments (2)
SCR/valetudo_map_parser/map_data.py (1)

288-291: ⚠️ Potential issue | 🟡 Minor

Treat empty compressedPixels as missing data too.

The Conga fallback still only runs when compressedPixels is None. If an upstream payload sends compressedPixels: [], this path never reads congaPixels and the layer is stored empty.

Proposed fix
-        compressed_pixels = json_obj.get("compressedPixels")
-        if compressed_pixels is None:
+        compressed_pixels = json_obj.get("compressedPixels")
+        if not compressed_pixels:
             pixels = json_obj.get("pixels") or json_obj.get("congaPixels", [])
             compressed_pixels = ImageData._convert_pixels_to_compressed(pixels)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@SCR/valetudo_map_parser/map_data.py` around lines 288 - 291, The code only
falls back to congaPixels when compressed_pixels is None, so an upstream empty
array compressedPixels: [] is treated as present and prevents using congaPixels;
update the condition in the map parsing logic to treat empty lists as missing
(e.g., check for falsy or len==0) so that when compressed_pixels is None or
empty you retrieve pixels = json_obj.get("pixels") or
json_obj.get("congaPixels", []) and call
ImageData._convert_pixels_to_compressed(pixels) to populate compressed_pixels.
SCR/valetudo_map_parser/config/shared.py (1)

155-160: ⚠️ Potential issue | 🟡 Minor

Accept MIME values here or change the default.

get_content_type() returns MIME values, but this setter still only accepts the short keys from ALLOWED_IMAGE_FORMAT. Passing the current content type back into set_content_type() will silently reset PNG/JPEG outputs to PIL.

Proposed fix
-    def set_content_type(self, new_image_format: str = "image/pil") -> None:
-        """Set image format / content type"""
-        if new_image_format not in ALLOWED_IMAGE_FORMAT.keys():
-            self._image_format = "image/pil"
-            return
-        self._image_format = ALLOWED_IMAGE_FORMAT.get(new_image_format)
+    def set_content_type(self, new_image_format: str = "pil") -> None:
+        """Set image format / content type."""
+        if new_image_format in ALLOWED_IMAGE_FORMAT:
+            self._image_format = ALLOWED_IMAGE_FORMAT[new_image_format]
+            return
+        if new_image_format in ALLOWED_IMAGE_FORMAT.values():
+            self._image_format = new_image_format
+            return
+        self._image_format = ALLOWED_IMAGE_FORMAT["pil"]
🤖 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 155 - 160,
set_content_type currently only accepts short keys from ALLOWED_IMAGE_FORMAT and
resets when passed a MIME string; update it to accept either the mapping keys or
the MIME values returned by get_content_type. In set_content_type (and using
ALLOWED_IMAGE_FORMAT and _image_format), check: if new_image_format is a key =>
set _image_format to ALLOWED_IMAGE_FORMAT[new_image_format]; else if
new_image_format is one of ALLOWED_IMAGE_FORMAT.values() => set _image_format to
new_image_format; otherwise fall back to the default ("image/pil" or the chosen
canonical default) and return. Ensure the stored _image_format is always the
MIME string.
🤖 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/conga_handler.py`:
- Around line 32-35: The Conga handler constructor does not set the shared flag;
in the __init__ method of the Conga handler (the def __init__(self, shared_data:
CameraShared) -> None: constructor that currently calls
super().__init__(shared_data) and creates CongaImageDraw(self)), set
shared_data.is_conga = True to keep CameraShared.is_conga synchronized with the
active handler; update that constructor to assign the flag immediately after
calling super().__init__ (and consider leaving a brief comment noting the state
synchronization).

---

Duplicate comments:
In `@SCR/valetudo_map_parser/config/shared.py`:
- Around line 155-160: set_content_type currently only accepts short keys from
ALLOWED_IMAGE_FORMAT and resets when passed a MIME string; update it to accept
either the mapping keys or the MIME values returned by get_content_type. In
set_content_type (and using ALLOWED_IMAGE_FORMAT and _image_format), check: if
new_image_format is a key => set _image_format to
ALLOWED_IMAGE_FORMAT[new_image_format]; else if new_image_format is one of
ALLOWED_IMAGE_FORMAT.values() => set _image_format to new_image_format;
otherwise fall back to the default ("image/pil" or the chosen canonical default)
and return. Ensure the stored _image_format is always the MIME string.

In `@SCR/valetudo_map_parser/map_data.py`:
- Around line 288-291: The code only falls back to congaPixels when
compressed_pixels is None, so an upstream empty array compressedPixels: [] is
treated as present and prevents using congaPixels; update the condition in the
map parsing logic to treat empty lists as missing (e.g., check for falsy or
len==0) so that when compressed_pixels is None or empty you retrieve pixels =
json_obj.get("pixels") or json_obj.get("congaPixels", []) and call
ImageData._convert_pixels_to_compressed(pixels) to populate compressed_pixels.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a237c16e-24d2-4243-bbce-35410d38c7b7

📥 Commits

Reviewing files that changed from the base of the PR and between 608af44 and 119c125.

📒 Files selected for processing (4)
  • SCR/valetudo_map_parser/config/shared.py
  • SCR/valetudo_map_parser/config/utils.py
  • SCR/valetudo_map_parser/conga_handler.py
  • SCR/valetudo_map_parser/map_data.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • SCR/valetudo_map_parser/config/utils.py

Comment on lines +32 to +35
def __init__(self, shared_data: CameraShared) -> None:
"""Initialise the Conga image handler."""
super().__init__(shared_data)
self.imd = CongaImageDraw(self)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Assignments and reads of is_conga:\n'
rg -n -C2 '\bis_conga\b'

printf '\nConga handler construction sites:\n'
rg -n -C2 '\bCongaMapImageHandler\s*\('

Repository: sca075/Python-package-valetudo-map-parser

Length of output: 925


Set shared_data.is_conga = True in the Conga handler constructor to keep state synchronized.

CameraShared.is_conga is initialized to False and is never set to True when the Conga handler is active. While the flag is not currently read elsewhere in the codebase, keeping shared state synchronized with the active handler is a valid code hygiene practice.

Suggested fix
     def __init__(self, shared_data: CameraShared) -> None:
         """Initialise the Conga image handler."""
         super().__init__(shared_data)
+        self.shared.is_conga = True
         self.imd = CongaImageDraw(self)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@SCR/valetudo_map_parser/conga_handler.py` around lines 32 - 35, The Conga
handler constructor does not set the shared flag; in the __init__ method of the
Conga handler (the def __init__(self, shared_data: CameraShared) -> None:
constructor that currently calls super().__init__(shared_data) and creates
CongaImageDraw(self)), set shared_data.is_conga = True to keep
CameraShared.is_conga synchronized with the active handler; update that
constructor to assign the flag immediately after calling super().__init__ (and
consider leaving a brief comment noting the state synchronization).

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.

♻️ Duplicate comments (1)
SCR/valetudo_map_parser/__init__.py (1)

2-2: ⚠️ Potential issue | 🟡 Minor

Align the module docstring version with the release metadata.

Line 2 advertises 0.3.0b2, but this PR’s stated release target is 0.3.0b0. Please keep the header in sync with the package version so source inspection and generated docs do not report a different build.

#!/bin/bash
# Verify that package metadata and source-advertised versions agree.
# Expected result: the same version token appears in package metadata and this module docstring.

fd -HI 'pyproject.toml|setup.cfg|setup.py' .
rg -n '(^version\s*=)|(__version__\s*=)|(^Version: )' pyproject.toml setup.cfg setup.py SCR 2>/dev/null
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@SCR/valetudo_map_parser/__init__.py` at line 2, Update the module docstring
version string in SCR/valetudo_map_parser/__init__.py (the "Version: 0.3.0b2"
header) to match the release metadata token (0.3.0b0) so source-advertised
version aligns with package metadata; check the package metadata file
(pyproject.toml / setup.cfg / setup.py) for the canonical version and change the
Version header in __init__.py to that exact token, and re-run the provided
verification commands to confirm all version tokens match.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@SCR/valetudo_map_parser/__init__.py`:
- Line 2: Update the module docstring version string in
SCR/valetudo_map_parser/__init__.py (the "Version: 0.3.0b2" header) to match the
release metadata token (0.3.0b0) so source-advertised version aligns with
package metadata; check the package metadata file (pyproject.toml / setup.cfg /
setup.py) for the canonical version and change the Version header in __init__.py
to that exact token, and re-run the provided verification commands to confirm
all version tokens match.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 17467792-e2da-4d2c-b9af-628238b35f33

📥 Commits

Reviewing files that changed from the base of the PR and between 119c125 and 1ad1428.

📒 Files selected for processing (2)
  • SCR/valetudo_map_parser/__init__.py
  • pyproject.toml
🚧 Files skipped from review as they are similar to previous changes (1)
  • pyproject.toml

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