2019-02-14 04:35:12 +00:00
|
|
|
"""Support for Neato Connected Vacuums."""
|
2018-06-21 01:46:15 +00:00
|
|
|
from datetime import timedelta
|
2019-03-21 05:56:46 +00:00
|
|
|
import logging
|
|
|
|
|
2019-10-06 18:10:11 +00:00
|
|
|
from pybotvac.exceptions import NeatoRobotException
|
|
|
|
|
2019-02-23 21:55:55 +00:00
|
|
|
import voluptuous as vol
|
2017-11-03 13:25:26 +00:00
|
|
|
|
|
|
|
from homeassistant.components.vacuum import (
|
2019-07-31 19:25:30 +00:00
|
|
|
ATTR_STATUS,
|
|
|
|
DOMAIN,
|
|
|
|
STATE_CLEANING,
|
|
|
|
STATE_DOCKED,
|
|
|
|
STATE_ERROR,
|
|
|
|
STATE_IDLE,
|
|
|
|
STATE_PAUSED,
|
|
|
|
STATE_RETURNING,
|
|
|
|
SUPPORT_BATTERY,
|
|
|
|
SUPPORT_CLEAN_SPOT,
|
|
|
|
SUPPORT_LOCATE,
|
|
|
|
SUPPORT_MAP,
|
|
|
|
SUPPORT_PAUSE,
|
|
|
|
SUPPORT_RETURN_HOME,
|
|
|
|
SUPPORT_START,
|
|
|
|
SUPPORT_STATE,
|
|
|
|
SUPPORT_STOP,
|
|
|
|
StateVacuumDevice,
|
|
|
|
)
|
2019-10-02 16:33:47 +00:00
|
|
|
from homeassistant.const import ATTR_ENTITY_ID, ATTR_MODE
|
2019-02-23 21:55:55 +00:00
|
|
|
import homeassistant.helpers.config_validation as cv
|
2019-03-21 05:56:46 +00:00
|
|
|
from homeassistant.helpers.service import extract_entity_ids
|
|
|
|
|
2019-10-06 11:05:51 +00:00
|
|
|
from .const import (
|
2019-07-31 19:25:30 +00:00
|
|
|
ACTION,
|
|
|
|
ALERTS,
|
|
|
|
ERRORS,
|
|
|
|
MODE,
|
|
|
|
NEATO_LOGIN,
|
2019-10-06 11:05:51 +00:00
|
|
|
NEATO_DOMAIN,
|
2019-07-31 19:25:30 +00:00
|
|
|
NEATO_MAP_DATA,
|
|
|
|
NEATO_PERSISTENT_MAPS,
|
|
|
|
NEATO_ROBOTS,
|
2019-10-06 18:10:11 +00:00
|
|
|
SCAN_INTERVAL_MINUTES,
|
2019-07-31 19:25:30 +00:00
|
|
|
)
|
2017-11-03 13:25:26 +00:00
|
|
|
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
2019-10-06 18:10:11 +00:00
|
|
|
SCAN_INTERVAL = timedelta(minutes=SCAN_INTERVAL_MINUTES)
|
2018-06-27 20:55:27 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
SUPPORT_NEATO = (
|
|
|
|
SUPPORT_BATTERY
|
|
|
|
| SUPPORT_PAUSE
|
|
|
|
| SUPPORT_RETURN_HOME
|
|
|
|
| SUPPORT_STOP
|
|
|
|
| SUPPORT_START
|
|
|
|
| SUPPORT_CLEAN_SPOT
|
|
|
|
| SUPPORT_STATE
|
|
|
|
| SUPPORT_MAP
|
|
|
|
| SUPPORT_LOCATE
|
|
|
|
)
|
|
|
|
|
|
|
|
ATTR_CLEAN_START = "clean_start"
|
|
|
|
ATTR_CLEAN_STOP = "clean_stop"
|
|
|
|
ATTR_CLEAN_AREA = "clean_area"
|
|
|
|
ATTR_CLEAN_BATTERY_START = "battery_level_at_clean_start"
|
|
|
|
ATTR_CLEAN_BATTERY_END = "battery_level_at_clean_end"
|
|
|
|
ATTR_CLEAN_SUSP_COUNT = "clean_suspension_count"
|
|
|
|
ATTR_CLEAN_SUSP_TIME = "clean_suspension_time"
|
2019-10-07 06:30:49 +00:00
|
|
|
ATTR_CLEAN_PAUSE_TIME = "clean_pause_time"
|
|
|
|
ATTR_CLEAN_ERROR_TIME = "clean_error_time"
|
|
|
|
ATTR_LAUNCHED_FROM = "launched_from"
|
2019-07-31 19:25:30 +00:00
|
|
|
|
|
|
|
ATTR_NAVIGATION = "navigation"
|
|
|
|
ATTR_CATEGORY = "category"
|
|
|
|
ATTR_ZONE = "zone"
|
|
|
|
|
|
|
|
SERVICE_NEATO_CUSTOM_CLEANING = "neato_custom_cleaning"
|
|
|
|
|
|
|
|
SERVICE_NEATO_CUSTOM_CLEANING_SCHEMA = vol.Schema(
|
|
|
|
{
|
|
|
|
vol.Required(ATTR_ENTITY_ID): cv.entity_ids,
|
|
|
|
vol.Optional(ATTR_MODE, default=2): cv.positive_int,
|
|
|
|
vol.Optional(ATTR_NAVIGATION, default=1): cv.positive_int,
|
|
|
|
vol.Optional(ATTR_CATEGORY, default=4): cv.positive_int,
|
|
|
|
vol.Optional(ATTR_ZONE): cv.string,
|
|
|
|
}
|
|
|
|
)
|
2019-02-23 21:55:55 +00:00
|
|
|
|
2017-11-03 13:25:26 +00:00
|
|
|
|
2019-10-06 11:05:51 +00:00
|
|
|
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
|
2017-11-03 13:25:26 +00:00
|
|
|
"""Set up the Neato vacuum."""
|
2019-10-06 11:05:51 +00:00
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
async def async_setup_entry(hass, entry, async_add_entities):
|
|
|
|
"""Set up Neato vacuum with config entry."""
|
2017-11-03 13:25:26 +00:00
|
|
|
dev = []
|
|
|
|
for robot in hass.data[NEATO_ROBOTS]:
|
|
|
|
dev.append(NeatoConnectedVacuum(hass, robot))
|
2019-02-23 21:55:55 +00:00
|
|
|
|
|
|
|
if not dev:
|
|
|
|
return
|
|
|
|
|
2017-11-03 13:25:26 +00:00
|
|
|
_LOGGER.debug("Adding vacuums %s", dev)
|
2019-10-06 11:05:51 +00:00
|
|
|
async_add_entities(dev, True)
|
2017-11-03 13:25:26 +00:00
|
|
|
|
2019-02-23 21:55:55 +00:00
|
|
|
def neato_custom_cleaning_service(call):
|
|
|
|
"""Zone cleaning service that allows user to change options."""
|
|
|
|
for robot in service_to_entities(call):
|
|
|
|
if call.service == SERVICE_NEATO_CUSTOM_CLEANING:
|
|
|
|
mode = call.data.get(ATTR_MODE)
|
|
|
|
navigation = call.data.get(ATTR_NAVIGATION)
|
|
|
|
category = call.data.get(ATTR_CATEGORY)
|
|
|
|
zone = call.data.get(ATTR_ZONE)
|
2019-07-31 19:25:30 +00:00
|
|
|
robot.neato_custom_cleaning(mode, navigation, category, zone)
|
2019-02-23 21:55:55 +00:00
|
|
|
|
|
|
|
def service_to_entities(call):
|
|
|
|
"""Return the known devices that a service call mentions."""
|
|
|
|
entity_ids = extract_entity_ids(hass, call)
|
2019-07-31 19:25:30 +00:00
|
|
|
entities = [entity for entity in dev if entity.entity_id in entity_ids]
|
2019-02-23 21:55:55 +00:00
|
|
|
return entities
|
|
|
|
|
2019-10-06 11:05:51 +00:00
|
|
|
hass.services.async_register(
|
2019-07-31 19:25:30 +00:00
|
|
|
DOMAIN,
|
|
|
|
SERVICE_NEATO_CUSTOM_CLEANING,
|
|
|
|
neato_custom_cleaning_service,
|
|
|
|
schema=SERVICE_NEATO_CUSTOM_CLEANING_SCHEMA,
|
|
|
|
)
|
2019-02-23 21:55:55 +00:00
|
|
|
|
2017-11-03 13:25:26 +00:00
|
|
|
|
2018-08-18 18:20:32 +00:00
|
|
|
class NeatoConnectedVacuum(StateVacuumDevice):
|
2018-01-21 06:35:38 +00:00
|
|
|
"""Representation of a Neato Connected Vacuum."""
|
2017-11-03 13:25:26 +00:00
|
|
|
|
|
|
|
def __init__(self, hass, robot):
|
2018-01-21 06:35:38 +00:00
|
|
|
"""Initialize the Neato Connected Vacuum."""
|
2017-11-03 13:25:26 +00:00
|
|
|
self.robot = robot
|
2019-10-07 06:30:49 +00:00
|
|
|
self.neato = hass.data.get(NEATO_LOGIN)
|
|
|
|
self._available = self.neato.logged_in if self.neato is not None else False
|
2019-09-03 18:35:00 +00:00
|
|
|
self._name = f"{self.robot.name}"
|
2017-11-03 13:25:26 +00:00
|
|
|
self._status_state = None
|
|
|
|
self._clean_state = None
|
|
|
|
self._state = None
|
|
|
|
self._mapdata = hass.data[NEATO_MAP_DATA]
|
2019-10-07 06:30:49 +00:00
|
|
|
self._clean_time_start = None
|
|
|
|
self._clean_time_stop = None
|
|
|
|
self._clean_area = None
|
|
|
|
self._clean_battery_start = None
|
|
|
|
self._clean_battery_end = None
|
|
|
|
self._clean_susp_charge_count = None
|
|
|
|
self._clean_susp_time = None
|
|
|
|
self._clean_pause_time = None
|
|
|
|
self._clean_error_time = None
|
|
|
|
self._launched_from = None
|
2018-10-12 06:40:45 +00:00
|
|
|
self._battery_level = None
|
2018-10-12 22:33:13 +00:00
|
|
|
self._robot_serial = self.robot.serial
|
2019-02-23 21:55:55 +00:00
|
|
|
self._robot_maps = hass.data[NEATO_PERSISTENT_MAPS]
|
|
|
|
self._robot_boundaries = {}
|
|
|
|
self._robot_has_map = self.robot.has_persistent_maps
|
2019-10-06 11:05:51 +00:00
|
|
|
self._robot_stats = None
|
2017-11-03 13:25:26 +00:00
|
|
|
|
|
|
|
def update(self):
|
|
|
|
"""Update the states of Neato Vacuums."""
|
2019-10-06 18:10:11 +00:00
|
|
|
if self.neato is None:
|
|
|
|
_LOGGER.error("Error while updating vacuum")
|
|
|
|
self._state = None
|
|
|
|
self._available = False
|
|
|
|
return
|
2019-10-06 11:05:51 +00:00
|
|
|
|
2017-11-03 13:25:26 +00:00
|
|
|
try:
|
2019-10-06 18:10:11 +00:00
|
|
|
_LOGGER.debug("Running Neato Vacuums update")
|
|
|
|
if self._robot_stats is None:
|
|
|
|
self._robot_stats = self.robot.get_robot_info().json()
|
|
|
|
self.neato.update_robots()
|
2017-11-03 13:25:26 +00:00
|
|
|
self._state = self.robot.state
|
2018-10-12 06:40:45 +00:00
|
|
|
self._available = True
|
2019-10-06 18:10:11 +00:00
|
|
|
except NeatoRobotException as ex:
|
|
|
|
if self._available: # print only once when available
|
|
|
|
_LOGGER.error("Neato vacuum connection error: %s", ex)
|
2017-11-03 13:25:26 +00:00
|
|
|
self._state = None
|
2018-10-12 06:40:45 +00:00
|
|
|
self._available = False
|
2017-11-03 13:25:26 +00:00
|
|
|
return
|
2019-10-06 18:10:11 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
_LOGGER.debug("self._state=%s", self._state)
|
|
|
|
if "alert" in self._state:
|
|
|
|
robot_alert = ALERTS.get(self._state["alert"])
|
2019-01-10 21:56:10 +00:00
|
|
|
else:
|
|
|
|
robot_alert = None
|
2019-07-31 19:25:30 +00:00
|
|
|
if self._state["state"] == 1:
|
|
|
|
if self._state["details"]["isCharging"]:
|
2018-08-18 18:20:32 +00:00
|
|
|
self._clean_state = STATE_DOCKED
|
2019-07-31 19:25:30 +00:00
|
|
|
self._status_state = "Charging"
|
|
|
|
elif (
|
|
|
|
self._state["details"]["isDocked"]
|
|
|
|
and not self._state["details"]["isCharging"]
|
|
|
|
):
|
2018-08-18 18:20:32 +00:00
|
|
|
self._clean_state = STATE_DOCKED
|
2019-07-31 19:25:30 +00:00
|
|
|
self._status_state = "Docked"
|
2017-11-03 13:25:26 +00:00
|
|
|
else:
|
2018-08-18 18:20:32 +00:00
|
|
|
self._clean_state = STATE_IDLE
|
2019-07-31 19:25:30 +00:00
|
|
|
self._status_state = "Stopped"
|
2018-12-27 17:57:38 +00:00
|
|
|
|
|
|
|
if robot_alert is not None:
|
|
|
|
self._status_state = robot_alert
|
2019-07-31 19:25:30 +00:00
|
|
|
elif self._state["state"] == 2:
|
2018-12-27 17:57:38 +00:00
|
|
|
if robot_alert is None:
|
2018-08-18 18:20:32 +00:00
|
|
|
self._clean_state = STATE_CLEANING
|
2017-11-03 13:25:26 +00:00
|
|
|
self._status_state = (
|
2019-07-31 19:25:30 +00:00
|
|
|
MODE.get(self._state["cleaning"]["mode"])
|
|
|
|
+ " "
|
|
|
|
+ ACTION.get(self._state["action"])
|
|
|
|
)
|
2017-11-03 13:25:26 +00:00
|
|
|
else:
|
2018-12-27 17:57:38 +00:00
|
|
|
self._status_state = robot_alert
|
2019-07-31 19:25:30 +00:00
|
|
|
elif self._state["state"] == 3:
|
2018-08-18 18:20:32 +00:00
|
|
|
self._clean_state = STATE_PAUSED
|
2019-07-31 19:25:30 +00:00
|
|
|
self._status_state = "Paused"
|
|
|
|
elif self._state["state"] == 4:
|
2018-08-18 18:20:32 +00:00
|
|
|
self._clean_state = STATE_ERROR
|
2019-07-31 19:25:30 +00:00
|
|
|
self._status_state = ERRORS.get(self._state["error"])
|
2017-11-03 13:25:26 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
self._battery_level = self._state["details"]["charge"]
|
2019-05-18 08:27:05 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
if not self._mapdata.get(self._robot_serial, {}).get("maps", []):
|
2017-11-03 13:25:26 +00:00
|
|
|
return
|
2019-10-07 06:30:49 +00:00
|
|
|
|
|
|
|
mapdata = self._mapdata[self._robot_serial]["maps"][0]
|
|
|
|
self._clean_time_start = (mapdata["start_at"].strip("Z")).replace("T", " ")
|
|
|
|
self._clean_time_stop = (mapdata["end_at"].strip("Z")).replace("T", " ")
|
|
|
|
self._clean_area = mapdata["cleaned_area"]
|
|
|
|
self._clean_susp_charge_count = mapdata["suspended_cleaning_charging_count"]
|
|
|
|
self._clean_susp_time = mapdata["time_in_suspended_cleaning"]
|
|
|
|
self._clean_pause_time = mapdata["time_in_pause"]
|
|
|
|
self._clean_error_time = mapdata["time_in_error"]
|
|
|
|
self._clean_battery_start = mapdata["run_charge_at_start"]
|
|
|
|
self._clean_battery_end = mapdata["run_charge_at_end"]
|
|
|
|
self._launched_from = mapdata["launched_from"]
|
2017-11-03 13:25:26 +00:00
|
|
|
|
2019-02-23 21:55:55 +00:00
|
|
|
if self._robot_has_map:
|
2019-07-31 19:25:30 +00:00
|
|
|
if self._state["availableServices"]["maps"] != "basic-1":
|
2019-03-09 22:06:35 +00:00
|
|
|
if self._robot_maps[self._robot_serial]:
|
2019-07-18 17:22:05 +00:00
|
|
|
allmaps = self._robot_maps[self._robot_serial]
|
|
|
|
for maps in allmaps:
|
|
|
|
self._robot_boundaries = self.robot.get_map_boundaries(
|
2019-07-31 19:25:30 +00:00
|
|
|
maps["id"]
|
|
|
|
).json()
|
2019-02-23 21:55:55 +00:00
|
|
|
|
2017-11-03 13:25:26 +00:00
|
|
|
@property
|
|
|
|
def name(self):
|
|
|
|
"""Return the name of the device."""
|
|
|
|
return self._name
|
|
|
|
|
|
|
|
@property
|
|
|
|
def supported_features(self):
|
|
|
|
"""Flag vacuum cleaner robot features that are supported."""
|
|
|
|
return SUPPORT_NEATO
|
|
|
|
|
|
|
|
@property
|
|
|
|
def battery_level(self):
|
|
|
|
"""Return the battery level of the vacuum cleaner."""
|
2018-10-12 06:40:45 +00:00
|
|
|
return self._battery_level
|
|
|
|
|
|
|
|
@property
|
|
|
|
def available(self):
|
|
|
|
"""Return if the robot is available."""
|
|
|
|
return self._available
|
2017-11-03 13:25:26 +00:00
|
|
|
|
2019-10-07 06:30:49 +00:00
|
|
|
@property
|
|
|
|
def icon(self):
|
|
|
|
"""Return neato specific icon."""
|
|
|
|
return "mdi:robot-vacuum-variant"
|
|
|
|
|
2017-11-03 13:25:26 +00:00
|
|
|
@property
|
2018-08-18 18:20:32 +00:00
|
|
|
def state(self):
|
2017-11-03 13:25:26 +00:00
|
|
|
"""Return the status of the vacuum cleaner."""
|
2018-08-18 18:20:32 +00:00
|
|
|
return self._clean_state
|
2017-11-03 13:25:26 +00:00
|
|
|
|
2018-10-12 22:33:13 +00:00
|
|
|
@property
|
|
|
|
def unique_id(self):
|
|
|
|
"""Return a unique ID."""
|
|
|
|
return self._robot_serial
|
|
|
|
|
2017-11-03 13:25:26 +00:00
|
|
|
@property
|
2018-08-18 18:20:32 +00:00
|
|
|
def device_state_attributes(self):
|
2017-11-03 13:25:26 +00:00
|
|
|
"""Return the state attributes of the vacuum cleaner."""
|
|
|
|
data = {}
|
|
|
|
|
2018-08-18 18:20:32 +00:00
|
|
|
if self._status_state is not None:
|
|
|
|
data[ATTR_STATUS] = self._status_state
|
2019-10-07 06:30:49 +00:00
|
|
|
if self._clean_time_start is not None:
|
|
|
|
data[ATTR_CLEAN_START] = self._clean_time_start
|
|
|
|
if self._clean_time_stop is not None:
|
|
|
|
data[ATTR_CLEAN_STOP] = self._clean_time_stop
|
|
|
|
if self._clean_area is not None:
|
|
|
|
data[ATTR_CLEAN_AREA] = self._clean_area
|
|
|
|
if self._clean_susp_charge_count is not None:
|
|
|
|
data[ATTR_CLEAN_SUSP_COUNT] = self._clean_susp_charge_count
|
|
|
|
if self._clean_susp_time is not None:
|
|
|
|
data[ATTR_CLEAN_SUSP_TIME] = self._clean_susp_time
|
|
|
|
if self._clean_pause_time is not None:
|
|
|
|
data[ATTR_CLEAN_PAUSE_TIME] = self._clean_pause_time
|
|
|
|
if self._clean_error_time is not None:
|
|
|
|
data[ATTR_CLEAN_ERROR_TIME] = self._clean_error_time
|
|
|
|
if self._clean_battery_start is not None:
|
|
|
|
data[ATTR_CLEAN_BATTERY_START] = self._clean_battery_start
|
|
|
|
if self._clean_battery_end is not None:
|
|
|
|
data[ATTR_CLEAN_BATTERY_END] = self._clean_battery_end
|
|
|
|
if self._launched_from is not None:
|
|
|
|
data[ATTR_LAUNCHED_FROM] = self._launched_from
|
2017-11-03 13:25:26 +00:00
|
|
|
|
|
|
|
return data
|
|
|
|
|
2019-10-06 11:05:51 +00:00
|
|
|
@property
|
|
|
|
def device_info(self):
|
|
|
|
"""Device info for neato robot."""
|
|
|
|
return {
|
|
|
|
"identifiers": {(NEATO_DOMAIN, self._robot_serial)},
|
|
|
|
"name": self._name,
|
|
|
|
"manufacturer": self._robot_stats["data"]["mfg_name"],
|
|
|
|
"model": self._robot_stats["data"]["modelName"],
|
|
|
|
"sw_version": self._state["meta"]["firmware"],
|
|
|
|
}
|
|
|
|
|
2018-08-18 18:20:32 +00:00
|
|
|
def start(self):
|
|
|
|
"""Start cleaning or resume cleaning."""
|
2019-10-06 18:10:11 +00:00
|
|
|
try:
|
|
|
|
if self._state["state"] == 1:
|
|
|
|
self.robot.start_cleaning()
|
|
|
|
elif self._state["state"] == 3:
|
|
|
|
self.robot.resume_cleaning()
|
|
|
|
except NeatoRobotException as ex:
|
|
|
|
_LOGGER.error("Neato vacuum connection error: %s", ex)
|
2017-11-03 13:25:26 +00:00
|
|
|
|
2018-08-18 18:20:32 +00:00
|
|
|
def pause(self):
|
|
|
|
"""Pause the vacuum."""
|
2019-10-06 18:10:11 +00:00
|
|
|
try:
|
|
|
|
self.robot.pause_cleaning()
|
|
|
|
except NeatoRobotException as ex:
|
|
|
|
_LOGGER.error("Neato vacuum connection error: %s", ex)
|
2017-11-03 13:25:26 +00:00
|
|
|
|
|
|
|
def return_to_base(self, **kwargs):
|
|
|
|
"""Set the vacuum cleaner to return to the dock."""
|
2019-10-06 18:10:11 +00:00
|
|
|
try:
|
|
|
|
if self._clean_state == STATE_CLEANING:
|
|
|
|
self.robot.pause_cleaning()
|
|
|
|
self._clean_state = STATE_RETURNING
|
|
|
|
self.robot.send_to_base()
|
|
|
|
except NeatoRobotException as ex:
|
|
|
|
_LOGGER.error("Neato vacuum connection error: %s", ex)
|
2017-11-03 13:25:26 +00:00
|
|
|
|
|
|
|
def stop(self, **kwargs):
|
|
|
|
"""Stop the vacuum cleaner."""
|
2019-10-06 18:10:11 +00:00
|
|
|
try:
|
|
|
|
self.robot.stop_cleaning()
|
|
|
|
except NeatoRobotException as ex:
|
|
|
|
_LOGGER.error("Neato vacuum connection error: %s", ex)
|
2017-11-03 13:25:26 +00:00
|
|
|
|
2018-07-18 10:19:38 +00:00
|
|
|
def locate(self, **kwargs):
|
|
|
|
"""Locate the robot by making it emit a sound."""
|
2019-10-06 18:10:11 +00:00
|
|
|
try:
|
|
|
|
self.robot.locate()
|
|
|
|
except NeatoRobotException as ex:
|
|
|
|
_LOGGER.error("Neato vacuum connection error: %s", ex)
|
2019-01-07 19:03:22 +00:00
|
|
|
|
|
|
|
def clean_spot(self, **kwargs):
|
|
|
|
"""Run a spot cleaning starting from the base."""
|
2019-10-06 18:10:11 +00:00
|
|
|
try:
|
|
|
|
self.robot.start_spot_cleaning()
|
|
|
|
except NeatoRobotException as ex:
|
|
|
|
_LOGGER.error("Neato vacuum connection error: %s", ex)
|
2019-02-23 21:55:55 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
def neato_custom_cleaning(self, mode, navigation, category, zone=None, **kwargs):
|
2019-02-23 21:55:55 +00:00
|
|
|
"""Zone cleaning service call."""
|
|
|
|
boundary_id = None
|
|
|
|
if zone is not None:
|
2019-07-31 19:25:30 +00:00
|
|
|
for boundary in self._robot_boundaries["data"]["boundaries"]:
|
|
|
|
if zone in boundary["name"]:
|
|
|
|
boundary_id = boundary["id"]
|
2019-02-23 21:55:55 +00:00
|
|
|
if boundary_id is None:
|
|
|
|
_LOGGER.error(
|
2019-07-31 19:25:30 +00:00
|
|
|
"Zone '%s' was not found for the robot '%s'", zone, self._name
|
|
|
|
)
|
2019-02-23 21:55:55 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
self._clean_state = STATE_CLEANING
|
2019-10-06 18:10:11 +00:00
|
|
|
try:
|
|
|
|
self.robot.start_cleaning(mode, navigation, category, boundary_id)
|
|
|
|
except NeatoRobotException as ex:
|
|
|
|
_LOGGER.error("Neato vacuum connection error: %s", ex)
|