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

Add multi map handling to roborock #1596

Merged
merged 23 commits into from
Dec 5, 2022
Merged
Show file tree
Hide file tree
Changes from 6 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
31 changes: 31 additions & 0 deletions miio/integrations/vacuum/roborock/tests/test_vacuum.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,36 @@ def __init__(self, *args, **kwargs):
"end_hour": 8,
}
]
self.dummies["multi_maps"] = [
{
"max_multi_map": 4,
"max_bak_map": 1,
"multi_map_count": 3,
"map_info": [
{
"mapFlag": 0,
"add_time": 1664448893,
"length": 10,
"name": "Downstairs",
"bak_maps": [{"mapFlag": 4, "add_time": 1663577737}],
},
{
"mapFlag": 1,
"add_time": 1663580330,
"length": 8,
"name": "Upstairs",
"bak_maps": [{"mapFlag": 5, "add_time": 1663577752}],
},
{
"mapFlag": 2,
"add_time": 1663580384,
"length": 5,
"name": "Attic",
"bak_maps": [{"mapFlag": 6, "add_time": 1663577765}],
},
],
}
]

self.return_values = {
"get_status": lambda x: [self.state],
Expand All @@ -86,6 +116,7 @@ def __init__(self, *args, **kwargs):
"miIO.info": "dummy info",
"get_clean_record": lambda x: [[1488347071, 1488347123, 16, 0, 0, 0]],
"get_dnd_timer": lambda x: self.dummies["dnd_timer"],
"get_multi_maps_list": lambda x: self.dummies["multi_maps"],
}

super().__init__(args, kwargs)
Expand Down
34 changes: 34 additions & 0 deletions miio/integrations/vacuum/roborock/vacuum.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import contextlib
import datetime
import enum
import json
import logging
import math
Expand Down Expand Up @@ -46,6 +47,7 @@
CleaningSummary,
ConsumableStatus,
DNDStatus,
MultiMapList,
SoundInstallStatus,
SoundStatus,
Timer,
Expand Down Expand Up @@ -131,6 +133,8 @@ def __init__(
):
super().__init__(ip, token, start_id, debug, model=model)
self.manual_seqnum = -1
self._multi_maps: Optional[MultiMapList] = None
self._multi_map_enum = None
rytilahti marked this conversation as resolved.
Show resolved Hide resolved

@command()
def start(self):
Expand Down Expand Up @@ -361,6 +365,36 @@ def map(self):
# returns ['retry'] without internet
return self.send("get_map_v1")

@command()
def get_multi_maps(self, skip_cache=False) -> MultiMapList:
starkillerOG marked this conversation as resolved.
Show resolved Hide resolved
"""Return list of multi maps."""
if self._multi_maps is not None and not skip_cache:
return self._multi_maps

self._multi_maps = MultiMapList(self.send("get_multi_maps_list")[0])
return self._multi_maps

@command()
def multi_map_enum(self, skip_cache=False) -> Optional[enum.Enum]:
"""Enum of the available map names."""
rytilahti marked this conversation as resolved.
Show resolved Hide resolved
starkillerOG marked this conversation as resolved.
Show resolved Hide resolved
if self._multi_map_enum is not None and not skip_cache:
return self._multi_map_enum

multi_maps = self.get_multi_maps()

self._multi_map_enum = enum.Enum("multi_map_enum", multi_maps.map_name_dict)
return self._multi_map_enum

@command(click.argument("multi_map_id", type=int))
def load_multi_map(self, multi_map_id: int):
"""Change the current map used."""
return self.send("load_multi_map", [multi_map_id])[0] == "ok"

@command()
def load_multi_map_by_enum(self, multi_map_enum):
"""Change the current map used by enum."""
return self.load_multi_map(multi_map_enum.value)
starkillerOG marked this conversation as resolved.
Show resolved Hide resolved

@command(click.argument("start", type=bool))
def edit_map(self, start):
"""Start map editing?"""
Expand Down
62 changes: 62 additions & 0 deletions miio/integrations/vacuum/roborock/vacuumcontainers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import logging
from datetime import datetime, time, timedelta
from enum import IntEnum
from typing import Any, Dict, List, Optional, Union
Expand All @@ -12,6 +13,8 @@

from .vacuum_enums import MopIntensity, MopMode

_LOGGER = logging.getLogger(__name__)


def pretty_area(x: float) -> float:
return int(x) / 1000000
Expand Down Expand Up @@ -94,6 +97,46 @@ def pretty_area(x: float) -> float:
}


class MultiMapList(DeviceStatus):
"""Contains a information about the maps/floors of the vacuum."""

def __init__(self, data: Dict[str, Any]) -> None:
# {'max_multi_map': 4, 'max_bak_map': 1, 'multi_map_count': 3, 'map_info': [
rytilahti marked this conversation as resolved.
Show resolved Hide resolved
# {'mapFlag': 0, 'add_time': 1664448893, 'length': 10, 'name': 'Downstairs', 'bak_maps': [{'mapFlag': 4, 'add_time': 1663577737}]},
# {'mapFlag': 1, 'add_time': 1663580330, 'length': 8, 'name': 'Upstairs', 'bak_maps': [{'mapFlag': 5, 'add_time': 1663577752}]},
# {'mapFlag': 2, 'add_time': 1663580384, 'length': 5, 'name': 'Attic', 'bak_maps': [{'mapFlag': 6, 'add_time': 1663577765}]}
# ]}
self.data = data
if self.map_count != len(self.data["map_info"]):
_LOGGER.warning("Roborock multi_map_count does not equal amount of maps")
starkillerOG marked this conversation as resolved.
Show resolved Hide resolved

self._map_name_dict = {}
for idx, map in enumerate(self.data["map_info"]):
self._map_name_dict[map["name"]] = map["mapFlag"]
if map["mapFlag"] != idx:
_LOGGER.warning("Roborock mapFlag does not equal map_info list index")
starkillerOG marked this conversation as resolved.
Show resolved Hide resolved

@property
def map_count(self) -> int:
"""Amount of multi maps stored."""
return self.data["multi_map_count"]

@property
def map_id_list(self) -> List[int]:
"""List of multi map ids."""
return list(self._map_name_dict.values())

@property
def map_list(self) -> List[Dict[str, Any]]:
"""List of map info."""
return self.data["map_info"]

@property
def map_name_dict(self) -> Dict[str, int]:
"""Dictionary of map names (keys) with there ids (values)."""
return self._map_name_dict


class VacuumStatus(VacuumDeviceStatus):
"""Container for status reports from the vacuum."""

Expand Down Expand Up @@ -284,6 +327,20 @@ def map(self) -> bool:
"""Map token."""
return bool(self.data["map_present"])

@property
@setting(
"Multi map",
choices_attribute="multi_map_enum",
setter_name="load_multi_map_by_enum",
icon="mdi:floor-plan",
)
def multi_map_id(self) -> int:
"""The id of the current map with regards to the multi map feature,

[3,7,11,15] -> [0,1,2,3].
"""
return int((self.data["map_status"] + 1) / 4 - 1)

@property
def in_zone_cleaning(self) -> bool:
"""Return True if the vacuum is in zone cleaning mode."""
Expand Down Expand Up @@ -502,6 +559,11 @@ def area(self) -> float:
"""Total cleaned area."""
return pretty_area(self.data["area"])

@property
def multi_map_id(self) -> int:
starkillerOG marked this conversation as resolved.
Show resolved Hide resolved
"""Map id used (multi map feature) during the cleaning run."""
return self.data.get("map_flag", 0)

@property
def error_code(self) -> int:
"""Error code."""
Expand Down