Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minor Refactoring and Fixes. #195

Merged
merged 4 commits into from
Jun 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions custom_components/mqtt_vacuum_camera/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
CONF_VACUUM_IDENTIFIERS,
DOMAIN,
)

from .utils.users_data import (
async_get_translations_vacuum_id,
async_rename_room_description,
Expand Down Expand Up @@ -230,7 +229,6 @@ async def async_migrate_entry(hass, config_entry: config_entries.ConfigEntry):
async def async_setup_entry(
hass: core.HomeAssistant, entry: config_entries.ConfigEntry
) -> bool:

"""Set up platform from a ConfigEntry."""
hass.data.setdefault(DOMAIN, {})
hass_data = dict(entry.data)
Expand Down Expand Up @@ -301,7 +299,7 @@ def find_vacuum_files(directory) -> list[str] or None:
# noinspection PyCallingNonCallable
async def async_setup(hass: core.HomeAssistant, config: dict) -> bool:
"""Set up the Valetudo Camera Custom component from yaml configuration."""

async def handle_homeassistant_stop(event):
"""Handle Home Assistant stop event."""
_LOGGER.info("Home Assistant is stopping. Writing down the rooms data.")
Expand Down
2 changes: 1 addition & 1 deletion custom_components/mqtt_vacuum_camera/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@
"iot_class": "local_polling",
"issue_tracker": "https://github.com/sca075/mqtt_vacuum_camera/issues",
"requirements": ["pillow==10.3.0", "numpy"],
"version": "2024.07.0b2"
"version": "2024.07.0"
}
5 changes: 2 additions & 3 deletions custom_components/mqtt_vacuum_camera/repairs.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@

from __future__ import annotations

import voluptuous as vol

from homeassistant import data_entry_flow
from homeassistant.components.repairs import RepairsFlow
from homeassistant.core import HomeAssistant
import voluptuous as vol


class Issue1RepairFlow(RepairsFlow):
Expand All @@ -17,7 +16,7 @@ async def async_step_init(
) -> data_entry_flow.FlowResult:
"""Handle the first step of a fix flow."""

return await (self.async_step_confirm())
return await self.async_step_confirm()

async def async_step_confirm(
self, user_input: dict[str, str] | None = None
Expand Down
7 changes: 1 addition & 6 deletions custom_components/mqtt_vacuum_camera/utils/drawable.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,7 @@
from PIL import ImageDraw, ImageFont
import numpy as np

from custom_components.mqtt_vacuum_camera.types import (
Color,
NumpyArray,
PilPNG,
Point,
)
from custom_components.mqtt_vacuum_camera.types import Color, NumpyArray, PilPNG, Point

# import re

Expand Down
2 changes: 1 addition & 1 deletion custom_components/mqtt_vacuum_camera/utils/status_text.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
import json
import logging

from custom_components.mqtt_vacuum_camera.types import JsonType, PilPNG
from custom_components.mqtt_vacuum_camera.const import DOMAIN
from custom_components.mqtt_vacuum_camera.types import JsonType, PilPNG

_LOGGER: logging.Logger = logging.getLogger(__name__)
_LOGGER.propagate = True
Expand Down
4 changes: 1 addition & 3 deletions custom_components/mqtt_vacuum_camera/utils/users_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,9 +302,7 @@ async def async_rename_room_description(
# Get the languages to modify
language = await async_load_languages(storage_path)
_LOGGER.info(f"Languages to modify: {language}")
edit_path = hass.config.path(
f"custom_components/mqtt_vacuum_camera/translations"
)
edit_path = hass.config.path(f"custom_components/mqtt_vacuum_camera/translations")
_LOGGER.info(f"Editing the translations file for language: {language}")
data_list = await async_load_translations_json(hass, language)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
from isal import igzip, isal_zlib

from custom_components.mqtt_vacuum_camera.common import async_write_file_to_disk
from custom_components.mqtt_vacuum_camera.valetudo.rand256.rrparser import (
RRMapParser,
)
from custom_components.mqtt_vacuum_camera.valetudo.rand256.rrparser import RRMapParser

_LOGGER = logging.getLogger(__name__)
_QOS = 0
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,29 @@
"""
Image Utils Class for Valetudo Hypfer Image Handling.
This class is used to simplify the ImageHandler class.
Version: 2024.06.1
Version: 2024.07.0
"""

from __future__ import annotations

import logging

import numpy as np
from numpy import rot90

from custom_components.mqtt_vacuum_camera.types import NumpyArray
from custom_components.mqtt_vacuum_camera.types import Color, NumpyArray

_LOGGER = logging.getLogger(__name__)


class TrimError(Exception):
"""Exception raised for errors in the trim process."""

def __init__(self, message, image):
super().__init__(message)
self.image = image


class ImageUtils:
"""Image Utils Class for Valetudo Hypfer Image Handler."""

Expand Down Expand Up @@ -52,6 +61,24 @@ async def async_check_if_zoom_is_on(
]
return trimmed

async def async_image_margins(
self, image_array: NumpyArray, detect_colour: Color
) -> tuple[int, int, int, int]:
"""Crop the image based on the auto crop area."""
"""async_auto_trim_and_zoom_image"""

nonzero_coords = np.column_stack(np.where(image_array != list(detect_colour)))
# Calculate the trim box based on the first and last occurrences
min_y, min_x, _ = NumpyArray.min(nonzero_coords, axis=0)
max_y, max_x, _ = NumpyArray.max(nonzero_coords, axis=0)
del nonzero_coords
_LOGGER.debug(
f"{self.file_name}: Found trims max and min values (y,x) "
f"({int(max_y)}, {int(max_x)}) ({int(min_y)},{int(min_x)})..."
)

return min_y, min_x, max_x, max_y

async def async_rotate_the_image(
self, trimmed: NumpyArray, rotate: int
) -> NumpyArray:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Image Handler Class.
It returns the PIL PNG image frame relative to the Map Data extrapolated from the vacuum json.
It also returns calibration, rooms data to the card and other images information to the camera.
Version: 2024.06.2
Version: 2024.07.0
"""

from __future__ import annotations
Expand All @@ -11,7 +11,6 @@
import logging

from PIL import Image, ImageOps
import numpy as np

from custom_components.mqtt_vacuum_camera.types import (
CalibrationPoints,
Expand All @@ -27,6 +26,7 @@
from custom_components.mqtt_vacuum_camera.utils.img_data import ImageData
from custom_components.mqtt_vacuum_camera.valetudo.hypfer.handler_utils import (
ImageUtils as ImUtils,
TrimError,
)
from custom_components.mqtt_vacuum_camera.valetudo.hypfer.image_draw import (
ImageDraw as ImDraw,
Expand Down Expand Up @@ -78,6 +78,20 @@ def __init__(self, shared_data):
self.imd = ImDraw(self)
self.imu = ImUtils(self)

def check_trim(
self, trimmed_height, trimmed_width, margin_size, image_array, file_name, rotate
):
"""
Check if the trimming is okay.
"""
if trimmed_height <= margin_size or trimmed_width <= margin_size:
self.crop_area = [0, 0, image_array.shape[1], image_array.shape[0]]
self.img_size = (image_array.shape[1], image_array.shape[0])
raise TrimError(
f"Trimming failed at rotation {rotate}. Reverting to original image.",
image_array,
)

async def async_auto_trim_and_zoom_image(
self,
image_array: NumpyArray,
Expand All @@ -92,21 +106,8 @@ async def async_auto_trim_and_zoom_image(
try:
if not self.auto_crop:
# Find the coordinates of the first occurrence of a non-background color
nonzero_coords = np.column_stack(
np.where(image_array != list(detect_colour))
)
# Calculate the trim box based on the first and last occurrences
min_y, min_x, _ = np.min(nonzero_coords, axis=0)
max_y, max_x, _ = np.max(nonzero_coords, axis=0)
del nonzero_coords
_LOGGER.debug(
"{}: Found trims max and min values (y,x) ({}, {}) ({},{})...".format(
self.file_name,
int(max_y),
int(max_x),
int(min_y),
int(min_x),
)
min_y, min_x, max_x, max_y = await self.imu.async_image_margins(
image_array, detect_colour
)
# Calculate and store the trims coordinates with margins
self.trim_left = int(min_x) + self.offset_left - margin_size
Expand All @@ -122,20 +123,17 @@ async def async_auto_trim_and_zoom_image(
self.shared.image_ref_width = trimmed_width

# Test if the trims are okay or not
if trimmed_height <= margin_size or trimmed_width <= margin_size:
_LOGGER.debug(
f"{self.file_name}: Background colour not detected at rotation {rotate}."
try:
self.check_trim(
trimmed_height,
trimmed_width,
margin_size,
image_array,
self.file_name,
rotate,
)
pos_0 = 0
self.crop_area = [
pos_0,
pos_0,
image_array.shape[1],
image_array.shape[0],
]
self.img_size = (image_array.shape[1], image_array.shape[0])
del trimmed_width, trimmed_height
return image_array
except TrimError as e:
return e.image

# Store Crop area of the original image_array we will use from the next frame.
self.auto_crop = [
Expand All @@ -144,6 +142,7 @@ async def async_auto_trim_and_zoom_image(
self.trim_right,
self.trim_down,
]

# If it is needed to zoom the image.
trimmed = await self.imu.async_check_if_zoom_is_on(
image_array, margin_size, zoom
Expand Down
Loading