From 2365bf89acaea17e01e75adab28ebc325509d2ad Mon Sep 17 00:00:00 2001 From: Josef Zweck <24647999+zweckj@users.noreply.github.com> Date: Wed, 13 Nov 2024 09:23:34 +0100 Subject: [PATCH 1/7] Area switch names, cleanup --- .gitignore | 1 + custom_components/mammotion/strings.json | 5 +- custom_components/mammotion/switch.py | 50 ++++++++++--------- .../mammotion/translations/cs.json | 3 ++ .../mammotion/translations/de.json | 3 ++ .../mammotion/translations/en.json | 3 ++ .../mammotion/translations/fr.json | 3 ++ .../mammotion/translations/it.json | 3 ++ .../mammotion/translations/nl.json | 3 ++ .../mammotion/translations/pl.json | 3 ++ .../mammotion/translations/ro.json | 3 ++ 11 files changed, 55 insertions(+), 25 deletions(-) diff --git a/.gitignore b/.gitignore index 696ef65..d351f1a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # pytest .pytest_cache .cache +.venv # GITHUB Proposed Python stuff: *.py[cod] diff --git a/custom_components/mammotion/strings.json b/custom_components/mammotion/strings.json index aa6a97b..3617f66 100644 --- a/custom_components/mammotion/strings.json +++ b/custom_components/mammotion/strings.json @@ -140,6 +140,9 @@ } }, "switch": { + "area": { + "name": "Area {name}" + }, "blade_status": { "name": "Blades on/off" }, @@ -362,4 +365,4 @@ "message": "Failed to send command to the mower." } } -} \ No newline at end of file +} diff --git a/custom_components/mammotion/switch.py b/custom_components/mammotion/switch.py index e7eed3a..d0c0a7d 100644 --- a/custom_components/mammotion/switch.py +++ b/custom_components/mammotion/switch.py @@ -1,5 +1,8 @@ +"""Support for Mammotion switches.""" + +from collections.abc import Awaitable, Callable from dataclasses import dataclass -from typing import Any, Awaitable, Callable, cast +from typing import Any from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription from homeassistant.core import HomeAssistant, callback @@ -18,32 +21,34 @@ class MammotionSwitchEntityDescription(SwitchEntityDescription): """Describes Mammotion switch entity.""" key: str - set_fn: Callable[[MammotionDataUpdateCoordinator, bool], Awaitable[None]] @dataclass(frozen=True, kw_only=True) -class MammotionUpdateSwitchEntityDescription(SwitchEntityDescription): +class MammotionAsyncSwitchEntityDescription(MammotionSwitchEntityDescription): """Describes Mammotion switch entity.""" - key: str set_fn: Callable[[MammotionDataUpdateCoordinator, bool], Awaitable[None]] + + +@dataclass(frozen=True, kw_only=True) +class MammotionUpdateSwitchEntityDescription(MammotionAsyncSwitchEntityDescription): + """Describes Mammotion switch entity.""" + is_on_func: Callable[[MammotionDataUpdateCoordinator], bool] @dataclass(frozen=True, kw_only=True) -class MammotionConfigSwitchEntityDescription(SwitchEntityDescription): +class MammotionConfigSwitchEntityDescription(MammotionSwitchEntityDescription): """Describes Mammotion Config switch entity.""" - key: str set_fn: Callable[[MammotionDataUpdateCoordinator, bool], None] @dataclass(frozen=True, kw_only=True) -class MammotionConfigAreaSwitchEntityDescription(SwitchEntityDescription): +class MammotionConfigAreaSwitchEntityDescription(MammotionSwitchEntityDescription): """Describes the Areas entities.""" - key: str - area: int + area: str set_fn: Callable[[MammotionDataUpdateCoordinator, bool, int], None] @@ -68,12 +73,12 @@ class MammotionConfigAreaSwitchEntityDescription(SwitchEntityDescription): ), ) -SWITCH_ENTITIES: tuple[MammotionSwitchEntityDescription, ...] = ( - MammotionSwitchEntityDescription( +SWITCH_ENTITIES: tuple[MammotionAsyncSwitchEntityDescription, ...] = ( + MammotionAsyncSwitchEntityDescription( key="blade_status", set_fn=lambda coordinator, value: coordinator.async_start_stop_blades(value), ), - MammotionSwitchEntityDescription( + MammotionAsyncSwitchEntityDescription( key="side_led", set_fn=lambda coordinator, value: coordinator.async_set_sidelight(int(value)), ), @@ -91,7 +96,7 @@ class MammotionConfigAreaSwitchEntityDescription(SwitchEntityDescription): MammotionConfigSwitchEntityDescription( key="rain_tactics", set_fn=lambda coordinator, value: setattr( - coordinator.operation_settings, "rain_tactics", cast(value, int) + coordinator.operation_settings, "rain_tactics", int(value) ), ), ) @@ -119,20 +124,18 @@ def add_entities() -> None: existing_name: AreaHashNameList = next( (area for area in area_name if str(area.hash) == str(area_id)), None ) - name = ( - existing_name.name - if (existing_name is None or existing_name != "") - else f"Area {area_id}" - ) + name = existing_name.name if existing_name else f"{area_id}" base_area_switch_entity = MammotionConfigAreaSwitchEntityDescription( key=f"{area_id}", + translation_key="area", + translation_placeholders={"name": name}, area=area_id, name=f"{name}", - set_fn=lambda coord, - bool_val, - value: coord.operation_settings.areas.append(value) - if bool_val - else coord.operation_settings.areas.remove(value), + set_fn=lambda coord, bool_val, value: ( + coord.operation_settings.areas.append(value) + if bool_val + else coord.operation_settings.areas.remove(value) + ), ) switch_entities.append( MammotionConfigAreaSwitchEntity( @@ -276,7 +279,6 @@ def __init__( super().__init__(coordinator, entity_description.key) self.coordinator = coordinator self.entity_description = entity_description - self._attr_translation_key = entity_description.key # TODO this should not need to be cast. self._attr_extra_state_attributes = {"hash": entity_description.area} # TODO grab defaults from operation_settings diff --git a/custom_components/mammotion/translations/cs.json b/custom_components/mammotion/translations/cs.json index dedc36c..5d95e9f 100644 --- a/custom_components/mammotion/translations/cs.json +++ b/custom_components/mammotion/translations/cs.json @@ -152,6 +152,9 @@ } }, "switch": { + "area": { + "name": "Oblast {name}" + }, "blade_status": { "name": "Zapnutí/vypnutí nožů" }, diff --git a/custom_components/mammotion/translations/de.json b/custom_components/mammotion/translations/de.json index 2e721e2..04ed143 100644 --- a/custom_components/mammotion/translations/de.json +++ b/custom_components/mammotion/translations/de.json @@ -152,6 +152,9 @@ } }, "switch": { + "area": { + "name": "Bereich {name}" + }, "blade_status": { "name": "Klingen An/Aus" }, diff --git a/custom_components/mammotion/translations/en.json b/custom_components/mammotion/translations/en.json index 7e546aa..95de257 100644 --- a/custom_components/mammotion/translations/en.json +++ b/custom_components/mammotion/translations/en.json @@ -152,6 +152,9 @@ } }, "switch": { + "area": { + "name": "Area {name}" + }, "blade_status": { "name": "Blades on/off" }, diff --git a/custom_components/mammotion/translations/fr.json b/custom_components/mammotion/translations/fr.json index f6290f7..e980b67 100644 --- a/custom_components/mammotion/translations/fr.json +++ b/custom_components/mammotion/translations/fr.json @@ -152,6 +152,9 @@ } }, "switch": { + "area": { + "name": "Zone {name}" + }, "blade_status": { "name": "Lames On/Off" }, diff --git a/custom_components/mammotion/translations/it.json b/custom_components/mammotion/translations/it.json index 97afd7a..0d99516 100644 --- a/custom_components/mammotion/translations/it.json +++ b/custom_components/mammotion/translations/it.json @@ -152,6 +152,9 @@ } }, "switch": { + "area": { + "name": "Zona {name}" + }, "blade_status": { "name": "Lame On/Off" }, diff --git a/custom_components/mammotion/translations/nl.json b/custom_components/mammotion/translations/nl.json index 380d834..05232da 100644 --- a/custom_components/mammotion/translations/nl.json +++ b/custom_components/mammotion/translations/nl.json @@ -152,6 +152,9 @@ } }, "switch": { + "area": { + "name": "Zones {name}" + }, "blade_status": { "name": "Maai Messen aan/uit" }, diff --git a/custom_components/mammotion/translations/pl.json b/custom_components/mammotion/translations/pl.json index db2c908..abaf446 100644 --- a/custom_components/mammotion/translations/pl.json +++ b/custom_components/mammotion/translations/pl.json @@ -152,6 +152,9 @@ } }, "switch": { + "area": { + "name": "Obszar {name}" + }, "blade_status": { "name": "Ostrza wł/wył" }, diff --git a/custom_components/mammotion/translations/ro.json b/custom_components/mammotion/translations/ro.json index d71daa7..8a28bf4 100644 --- a/custom_components/mammotion/translations/ro.json +++ b/custom_components/mammotion/translations/ro.json @@ -152,6 +152,9 @@ } }, "switch": { + "area": { + "name": "Suprafață {name}" + }, "blade_status": { "name": "Lame pornite/oprite" }, From 083f689d813f6d4b164c91bf470fcee68bd7e899 Mon Sep 17 00:00:00 2001 From: Josef Zweck <24647999+zweckj@users.noreply.github.com> Date: Wed, 13 Nov 2024 09:31:58 +0100 Subject: [PATCH 2/7] mypy fix --- custom_components/mammotion/switch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/mammotion/switch.py b/custom_components/mammotion/switch.py index d0c0a7d..202a013 100644 --- a/custom_components/mammotion/switch.py +++ b/custom_components/mammotion/switch.py @@ -121,7 +121,7 @@ def add_entities() -> None: new_areas = (set(areas) | set(area_name_hashes)) - added_areas if new_areas: for area_id in new_areas: - existing_name: AreaHashNameList = next( + existing_name: AreaHashNameList | None = next( (area for area in area_name if str(area.hash) == str(area_id)), None ) name = existing_name.name if existing_name else f"{area_id}" From c1cd481b2f3545cdbc3bb61405984229b70313f6 Mon Sep 17 00:00:00 2001 From: Josef Zweck <24647999+zweckj@users.noreply.github.com> Date: Wed, 13 Nov 2024 09:37:02 +0100 Subject: [PATCH 3/7] cleanup init --- custom_components/mammotion/__init__.py | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/custom_components/mammotion/__init__.py b/custom_components/mammotion/__init__.py index 39bab9e..bef7316 100644 --- a/custom_components/mammotion/__init__.py +++ b/custom_components/mammotion/__init__.py @@ -8,17 +8,8 @@ from homeassistant.helpers import device_registry as dr from .const import ( - CONF_ACCOUNTNAME, - CONF_AEP_DATA, - CONF_AUTH_DATA, - CONF_CONNECT_DATA, - CONF_DEVICE_DATA, - CONF_REGION_DATA, CONF_RETRY_COUNT, - CONF_SESSION_DATA, - CONF_USE_WIFI, DEFAULT_RETRY_COUNT, - DOMAIN, ) from .coordinator import MammotionDataUpdateCoordinator @@ -74,7 +65,7 @@ async def _async_update_listener(hass: HomeAssistant, entry: ConfigEntry) -> Non async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Unload a config entry.""" - unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS) - if unload_ok: + + if unload_ok:= await hass.config_entries.async_unload_platforms(entry, PLATFORMS) await entry.runtime_data.manager.remove_device(entry.runtime_data.device_name) return unload_ok From f7ee39aae4e04300a26b4494ae76fd80184a0440 Mon Sep 17 00:00:00 2001 From: Josef Zweck <24647999+zweckj@users.noreply.github.com> Date: Wed, 13 Nov 2024 09:53:52 +0100 Subject: [PATCH 4/7] icons --- custom_components/mammotion/device_tracker.py | 1 - custom_components/mammotion/icons.json | 71 +++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/custom_components/mammotion/device_tracker.py b/custom_components/mammotion/device_tracker.py index 3409287..e10791f 100644 --- a/custom_components/mammotion/device_tracker.py +++ b/custom_components/mammotion/device_tracker.py @@ -32,7 +32,6 @@ class MammotionTracker(MammotionBaseEntity, TrackerEntity, RestoreEntity): _attr_force_update = False _attr_translation_key = "device_tracker" - _attr_icon = "mdi:robot-mower" def __init__(self, coordinator: MammotionDataUpdateCoordinator) -> None: """Initialize the Tracker.""" diff --git a/custom_components/mammotion/icons.json b/custom_components/mammotion/icons.json index fd96c40..bf45b18 100644 --- a/custom_components/mammotion/icons.json +++ b/custom_components/mammotion/icons.json @@ -1,5 +1,39 @@ { "entity": { + "device_tracker": { + "device_tracker": { + "default": "mdi:map-marker-radius" + } + }, + "button": { + "start_map_sync": { + "default": "mdi:map-clock" + }, + "resync_rtk_dock": { + "default": "mdi:sync" + }, + "release_from_dock": { + "default": "mdi:ray-start-arrow" + }, + "emergency_nudge_forward": { + "default": "mdi:arrow-up" + }, + "emergency_nudge_left": { + "default": "mdi:arrow-left" + }, + "emergency_nudge_right": { + "default": "mdi:arrow-right" + }, + "emergency_nudge_back": { + "default": "mdi:arrow-down" + }, + "cancel_task": { + "default": "mdi:cancel" + }, + "clear_all_mapdata": { + "default": "mdi:map-marker-remove" + } + }, "sensor": { "gps_stars": { "default": "mdi:satellite-uplink" @@ -22,6 +56,43 @@ "position_mode": { "default": "mdi:map-marker" } + }, + "switch": { + "area": { + "default": "mdi:texture-box" + }, + "blade_status": { + "default": "mdi:saw-blade" + }, + "is_mow": { + "default": "mdi:mower", + "state": { + "off": "mdi:mower", + "on": "mdi:mower-on" + } + }, + "is_dump": { + "default": "mdi:dump-truck" + }, + "is_edge": { + "default": "mdi:border-outside" + }, + "rain_tactics": { + "default": "mdi:weather-rainy" + }, + "side_led": { + "default": "mdi:led-off", + "state": { + "off": "mdi:led-off", + "on": "mdi:led-on" + } + }, + "perimeter_first_on_off": { + "default": "mdi:dots-square" + }, + "schedule_updates": { + "default": "mdi:update" + } } } } From 6262a74d21bece91ba18854c8c65c42b1c84894f Mon Sep 17 00:00:00 2001 From: Josef Zweck <24647999+zweckj@users.noreply.github.com> Date: Wed, 13 Nov 2024 09:55:12 +0100 Subject: [PATCH 5/7] remove update method --- custom_components/mammotion/switch.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/custom_components/mammotion/switch.py b/custom_components/mammotion/switch.py index 202a013..e03f948 100644 --- a/custom_components/mammotion/switch.py +++ b/custom_components/mammotion/switch.py @@ -303,6 +303,3 @@ async def async_turn_off(self, **kwargs: Any) -> None: int(self.entity_description.area), ) self.async_write_ha_state() - - async def async_update(self) -> None: - """Update the entity state.""" From be0ecc2ecaa5742d85a329d81630adea96ae8498 Mon Sep 17 00:00:00 2001 From: Josef Zweck <24647999+zweckj@users.noreply.github.com> Date: Wed, 13 Nov 2024 09:57:22 +0100 Subject: [PATCH 6/7] remove static source type --- custom_components/mammotion/device_tracker.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/custom_components/mammotion/device_tracker.py b/custom_components/mammotion/device_tracker.py index e10791f..f30170c 100644 --- a/custom_components/mammotion/device_tracker.py +++ b/custom_components/mammotion/device_tracker.py @@ -32,6 +32,7 @@ class MammotionTracker(MammotionBaseEntity, TrackerEntity, RestoreEntity): _attr_force_update = False _attr_translation_key = "device_tracker" + _attr_source_type = SourceType.GPS def __init__(self, coordinator: MammotionDataUpdateCoordinator) -> None: """Initialize the Tracker.""" @@ -66,8 +67,3 @@ def longitude(self) -> float | None: def battery_level(self) -> int | None: """Return the battery level of the device.""" return self.coordinator.data.report_data.dev.battery_val - - @property - def source_type(self) -> SourceType: - """Return the source type, e.g., GPS or router, of the device.""" - return SourceType.GPS From 549bfd55e64eb6b530eead0905275ced72bb46d0 Mon Sep 17 00:00:00 2001 From: Josef Zweck <24647999+zweckj@users.noreply.github.com> Date: Thu, 14 Nov 2024 05:33:09 +0100 Subject: [PATCH 7/7] Update switch.py Co-authored-by: Michael Arthur --- custom_components/mammotion/switch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/mammotion/switch.py b/custom_components/mammotion/switch.py index e03f948..eef6ced 100644 --- a/custom_components/mammotion/switch.py +++ b/custom_components/mammotion/switch.py @@ -124,7 +124,7 @@ def add_entities() -> None: existing_name: AreaHashNameList | None = next( (area for area in area_name if str(area.hash) == str(area_id)), None ) - name = existing_name.name if existing_name else f"{area_id}" + name = existing_name.name if (existing_name and existing_name.name) else f"{area_id}" base_area_switch_entity = MammotionConfigAreaSwitchEntityDescription( key=f"{area_id}", translation_key="area",