homeassistant-vorwerk/vacuum.py

234 lines
6.7 KiB
Python
Raw Permalink Normal View History

2021-03-20 16:11:04 +01:00
"""Support for Neato Connected Vacuums."""
2021-04-28 17:14:09 +02:00
from __future__ import annotations
2021-03-20 16:11:04 +01:00
import logging
2021-04-25 20:30:12 +02:00
from typing import Any
2021-03-20 16:11:04 +01:00
from pybotvac.exceptions import NeatoRobotException
2021-04-25 20:30:12 +02:00
from pybotvac.robot import Robot
2021-03-20 16:11:04 +01:00
import voluptuous as vol
from homeassistant.components.vacuum import (
ATTR_STATUS,
STATE_CLEANING,
2021-05-26 17:15:49 +02:00
STATE_DOCKED,
2021-03-20 16:11:04 +01:00
STATE_IDLE,
STATE_PAUSED,
SUPPORT_BATTERY,
SUPPORT_CLEAN_SPOT,
SUPPORT_LOCATE,
SUPPORT_PAUSE,
SUPPORT_RETURN_HOME,
SUPPORT_START,
SUPPORT_STATE,
SUPPORT_STOP,
StateVacuumEntity,
)
from homeassistant.const import ATTR_MODE
from homeassistant.helpers import config_validation as cv, entity_platform
2021-04-25 20:30:12 +02:00
from homeassistant.helpers.update_coordinator import (
CoordinatorEntity,
DataUpdateCoordinator,
)
2021-03-20 16:11:04 +01:00
from . import VorwerkState
2021-03-20 16:11:04 +01:00
from .const import (
2021-04-25 20:30:12 +02:00
ATTR_CATEGORY,
ATTR_NAVIGATION,
ATTR_ZONE,
2021-03-20 16:11:04 +01:00
VORWERK_DOMAIN,
2021-04-25 20:30:12 +02:00
VORWERK_ROBOT_API,
VORWERK_ROBOT_COORDINATOR,
2021-03-20 16:11:04 +01:00
VORWERK_ROBOTS,
)
_LOGGER = logging.getLogger(__name__)
SUPPORT_VORWERK = (
SUPPORT_BATTERY
| SUPPORT_PAUSE
| SUPPORT_RETURN_HOME
| SUPPORT_STOP
| SUPPORT_START
| SUPPORT_CLEAN_SPOT
| SUPPORT_STATE
| SUPPORT_LOCATE
)
async def async_setup_entry(hass, entry, async_add_entities):
"""Set up Vorwerk vacuum with config entry."""
_LOGGER.debug("Adding vorwerk vacuums")
async_add_entities(
[
2021-04-25 20:30:12 +02:00
VorwerkConnectedVacuum(
robot[VORWERK_ROBOT_API], robot[VORWERK_ROBOT_COORDINATOR]
)
2021-03-20 16:11:04 +01:00
for robot in hass.data[VORWERK_DOMAIN][entry.entry_id][VORWERK_ROBOTS]
],
True,
)
platform = entity_platform.current_platform.get()
assert platform is not None
platform.async_register_entity_service(
"custom_cleaning",
{
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,
},
"vorwerk_custom_cleaning",
)
2021-04-25 20:30:12 +02:00
class VorwerkConnectedVacuum(CoordinatorEntity, StateVacuumEntity):
2021-03-20 16:11:04 +01:00
"""Representation of a Vorwerk Connected Vacuum."""
2021-04-25 20:30:12 +02:00
def __init__(
self, robot_state: VorwerkState, coordinator: DataUpdateCoordinator[Any]
) -> None:
2021-03-20 16:11:04 +01:00
"""Initialize the Vorwerk Connected Vacuum."""
2021-04-25 20:30:12 +02:00
super().__init__(coordinator)
self.robot: Robot = robot_state.robot
self._state: VorwerkState = robot_state
2021-03-20 16:11:04 +01:00
self._name = f"{self.robot.name}"
self._robot_serial = self.robot.serial
2021-04-28 17:14:09 +02:00
self._robot_boundaries: list[str] = []
2021-03-20 16:11:04 +01: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_VORWERK
@property
def battery_level(self):
"""Return the battery level of the vacuum cleaner."""
2021-04-25 20:30:12 +02:00
return self._state.battery_level
2021-03-20 16:11:04 +01:00
@property
def available(self):
"""Return if the robot is available."""
2021-04-25 20:30:12 +02:00
return self._state.available
2021-03-20 16:11:04 +01:00
@property
def icon(self):
"""Return specific icon."""
return "mdi:robot-vacuum-variant"
@property
def state(self):
"""Return the status of the vacuum cleaner."""
2021-04-25 20:30:12 +02:00
return self._state.state if self._state else None
2021-03-20 16:11:04 +01:00
@property
def unique_id(self):
"""Return a unique ID."""
return self._robot_serial
@property
def device_state_attributes(self):
"""Return the state attributes of the vacuum cleaner."""
data = {}
2021-04-25 20:30:12 +02:00
if self._state.status is not None:
data[ATTR_STATUS] = self._state.status
2021-03-20 16:11:04 +01:00
return data
@property
def device_info(self):
"""Device info for robot."""
2021-04-25 20:30:12 +02:00
return self._state.device_info
2021-03-20 16:11:04 +01:00
def start(self):
"""Start cleaning or resume cleaning."""
2021-04-25 20:30:12 +02:00
if not self._state:
return
2021-03-20 16:11:04 +01:00
try:
2021-05-26 17:15:49 +02:00
if self._state.state == STATE_IDLE or self._state.state == STATE_DOCKED:
2021-03-20 16:11:04 +01:00
self.robot.start_cleaning()
2021-04-25 20:30:12 +02:00
elif self._state.state == STATE_PAUSED:
2021-03-20 16:11:04 +01:00
self.robot.resume_cleaning()
except NeatoRobotException as ex:
_LOGGER.error(
"Vorwerk vacuum connection error for '%s': %s", self.entity_id, ex
)
def pause(self):
"""Pause the vacuum."""
try:
self.robot.pause_cleaning()
except NeatoRobotException as ex:
_LOGGER.error(
"Vorwerk vacuum connection error for '%s': %s", self.entity_id, ex
)
def return_to_base(self, **kwargs):
"""Set the vacuum cleaner to return to the dock."""
try:
2021-04-25 20:30:12 +02:00
if self._state.state == STATE_CLEANING:
2021-03-20 16:11:04 +01:00
self.robot.pause_cleaning()
self.robot.send_to_base()
except NeatoRobotException as ex:
_LOGGER.error(
"Vorwerk vacuum connection error for '%s': %s", self.entity_id, ex
)
def stop(self, **kwargs):
"""Stop the vacuum cleaner."""
try:
self.robot.stop_cleaning()
except NeatoRobotException as ex:
_LOGGER.error(
"Vorwerk vacuum connection error for '%s': %s", self.entity_id, ex
)
def locate(self, **kwargs):
"""Locate the robot by making it emit a sound."""
try:
self.robot.locate()
except NeatoRobotException as ex:
_LOGGER.error(
"Vorwerk vacuum connection error for '%s': %s", self.entity_id, ex
)
def clean_spot(self, **kwargs):
"""Run a spot cleaning starting from the base."""
try:
self.robot.start_spot_cleaning()
except NeatoRobotException as ex:
_LOGGER.error(
"Vorwerk vacuum connection error for '%s': %s", self.entity_id, ex
)
def vorwerk_custom_cleaning(self, mode, navigation, category, zone=None):
"""Zone cleaning service call."""
boundary_id = None
if zone is not None:
for boundary in self._robot_boundaries:
if zone in boundary["name"]:
boundary_id = boundary["id"]
if boundary_id is None:
_LOGGER.error(
"Zone '%s' was not found for the robot '%s'", zone, self.entity_id
)
return
try:
self.robot.start_cleaning(mode, navigation, category, boundary_id)
except NeatoRobotException as ex:
_LOGGER.error(
"Vorwerk vacuum connection error for '%s': %s", self.entity_id, ex
)