Use DataUpdateCoordinator
This commit is contained in:
parent
bba9a3c1eb
commit
d10af9824a
59
__init__.py
59
__init__.py
@ -12,11 +12,16 @@ from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
|
|||||||
from homeassistant.exceptions import ConfigEntryNotReady
|
from homeassistant.exceptions import ConfigEntryNotReady
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.typing import ConfigType, HomeAssistantType
|
from homeassistant.helpers.typing import ConfigType, HomeAssistantType
|
||||||
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||||
from homeassistant.util import Throttle
|
from homeassistant.util import Throttle
|
||||||
|
|
||||||
|
from .api import VorwerkState
|
||||||
from .const import (
|
from .const import (
|
||||||
|
MIN_TIME_BETWEEN_UPDATES,
|
||||||
VORWERK_DOMAIN,
|
VORWERK_DOMAIN,
|
||||||
VORWERK_PLATFORMS,
|
VORWERK_PLATFORMS,
|
||||||
|
VORWERK_ROBOT_API,
|
||||||
|
VORWERK_ROBOT_COORDINATOR,
|
||||||
VORWERK_ROBOT_ENDPOINT,
|
VORWERK_ROBOT_ENDPOINT,
|
||||||
VORWERK_ROBOT_NAME,
|
VORWERK_ROBOT_NAME,
|
||||||
VORWERK_ROBOT_SECRET,
|
VORWERK_ROBOT_SECRET,
|
||||||
@ -65,7 +70,45 @@ async def async_setup(hass: HomeAssistantType, config: ConfigType) -> bool:
|
|||||||
|
|
||||||
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool:
|
async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool:
|
||||||
"""Set up config entry."""
|
"""Set up config entry."""
|
||||||
|
robots = await _async_create_robots(hass, entry.data[VORWERK_ROBOTS])
|
||||||
|
|
||||||
|
robot_states = [ VorwerkState(robot) for robot in robots ]
|
||||||
|
|
||||||
|
hass.data[VORWERK_DOMAIN][entry.entry_id] = {
|
||||||
|
VORWERK_ROBOTS: [
|
||||||
|
{
|
||||||
|
VORWERK_ROBOT_API: r,
|
||||||
|
VORWERK_ROBOT_COORDINATOR: _create_coordinator(hass, r),
|
||||||
|
}
|
||||||
|
for r in robot_states
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
for component in VORWERK_PLATFORMS:
|
||||||
|
hass.async_create_task(
|
||||||
|
hass.config_entries.async_forward_entry_setup(entry, component)
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def _create_coordinator(
|
||||||
|
hass: HomeAssistantType, robot_state: VorwerkState
|
||||||
|
) -> DataUpdateCoordinator:
|
||||||
|
async def async_update_data():
|
||||||
|
"""Fetch data from API endpoint."""
|
||||||
|
await hass.async_add_executor_job(robot_state.update)
|
||||||
|
|
||||||
|
return DataUpdateCoordinator(
|
||||||
|
hass,
|
||||||
|
_LOGGER,
|
||||||
|
name=robot_state.robot.name,
|
||||||
|
update_method=async_update_data,
|
||||||
|
update_interval=MIN_TIME_BETWEEN_UPDATES,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def _async_create_robots(hass, robot_confs):
|
||||||
@Throttle(timedelta(minutes=1))
|
@Throttle(timedelta(minutes=1))
|
||||||
def create_robot(config):
|
def create_robot(config):
|
||||||
return Robot(
|
return Robot(
|
||||||
@ -77,27 +120,19 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool
|
|||||||
endpoint=config[VORWERK_ROBOT_ENDPOINT],
|
endpoint=config[VORWERK_ROBOT_ENDPOINT],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
robots = []
|
||||||
try:
|
try:
|
||||||
robots = await asyncio.gather(
|
robots = await asyncio.gather(
|
||||||
*(
|
*(
|
||||||
hass.async_add_executor_job(create_robot, robot_conf)
|
hass.async_add_executor_job(create_robot, robot_conf)
|
||||||
for robot_conf in entry.data[VORWERK_ROBOTS]
|
for robot_conf in robot_confs
|
||||||
),
|
),
|
||||||
return_exceptions=False,
|
return_exceptions=False,
|
||||||
)
|
)
|
||||||
hass.data[VORWERK_DOMAIN][entry.entry_id] = {VORWERK_ROBOTS: robots}
|
|
||||||
except NeatoException as ex:
|
except NeatoException as ex:
|
||||||
_LOGGER.warning(
|
_LOGGER.error("Failed to connect to robots: %s", ex)
|
||||||
"Failed to connect to robot %s: %s", entry.data[VORWERK_ROBOT_NAME], ex
|
|
||||||
)
|
|
||||||
raise ConfigEntryNotReady from ex
|
raise ConfigEntryNotReady from ex
|
||||||
|
return robots
|
||||||
for component in VORWERK_PLATFORMS:
|
|
||||||
hass.async_create_task(
|
|
||||||
hass.config_entries.async_forward_entry_setup(entry, component)
|
|
||||||
)
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool:
|
async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry) -> bool:
|
||||||
|
214
api.py
Normal file
214
api.py
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
"""Auth sessions for pybotvac."""
|
||||||
|
from functools import wraps
|
||||||
|
import logging
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
import pybotvac
|
||||||
|
from pybotvac.exceptions import NeatoRobotException
|
||||||
|
|
||||||
|
from homeassistant.components.vacuum import (
|
||||||
|
STATE_CLEANING,
|
||||||
|
STATE_DOCKED,
|
||||||
|
STATE_ERROR,
|
||||||
|
STATE_IDLE,
|
||||||
|
STATE_PAUSED,
|
||||||
|
STATE_RETURNING,
|
||||||
|
)
|
||||||
|
|
||||||
|
from .const import (
|
||||||
|
ACTION,
|
||||||
|
ALERTS,
|
||||||
|
ERRORS,
|
||||||
|
MODE,
|
||||||
|
ROBOT_ACTION_DOCKING,
|
||||||
|
ROBOT_STATE_BUSY,
|
||||||
|
ROBOT_STATE_ERROR,
|
||||||
|
ROBOT_STATE_IDLE,
|
||||||
|
ROBOT_STATE_PAUSE,
|
||||||
|
VORWERK_DOMAIN,
|
||||||
|
)
|
||||||
|
|
||||||
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class VorwerkSession(pybotvac.PasswordlessSession):
|
||||||
|
"""PasswordlessSession pybotvac session for Vorwerk cloud."""
|
||||||
|
|
||||||
|
# The client_id is the same for all users.
|
||||||
|
CLIENT_ID = "KY4YbVAvtgB7lp8vIbWQ7zLk3hssZlhR"
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
"""Initialize Vorwerk cloud session."""
|
||||||
|
super().__init__(client_id=VorwerkSession.CLIENT_ID, vendor=pybotvac.Vorwerk())
|
||||||
|
|
||||||
|
@property
|
||||||
|
def token(self):
|
||||||
|
"""Return the token dict. Contains id_token, access_token and refresh_token."""
|
||||||
|
return self._token
|
||||||
|
|
||||||
|
|
||||||
|
def when_available(f):
|
||||||
|
"""Prevent calling the method and return None when not available."""
|
||||||
|
|
||||||
|
@wraps(f)
|
||||||
|
def wrapper(self, *args, **kw):
|
||||||
|
if self.available:
|
||||||
|
return f(self, *args, **kw)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
class VorwerkState:
|
||||||
|
"""Class to convert robot_state dict to more useful object."""
|
||||||
|
|
||||||
|
def __init__(self, robot: pybotvac.Robot) -> None:
|
||||||
|
"""Initialize new vorwerk vacuum state."""
|
||||||
|
self.robot = robot
|
||||||
|
self.robot_state = {}
|
||||||
|
self.robot_info = {}
|
||||||
|
|
||||||
|
def available(self) -> bool:
|
||||||
|
"""Return true when robot state is available."""
|
||||||
|
return bool(self.robot_state)
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
"""Update robot state and robot info."""
|
||||||
|
_LOGGER.debug("Running Vorwerk Vacuums update for '%s'", self.robot.name)
|
||||||
|
self._update_robot_info()
|
||||||
|
self._update_state()
|
||||||
|
|
||||||
|
def _update_state(self):
|
||||||
|
try:
|
||||||
|
if self.robot_info is None:
|
||||||
|
self.robot_info = self.robot.get_general_info().json().get("data")
|
||||||
|
except NeatoRobotException:
|
||||||
|
_LOGGER.warning("Couldn't fetch robot information of %s", self.robot.name)
|
||||||
|
|
||||||
|
def _update_robot_info(self):
|
||||||
|
try:
|
||||||
|
self.robot_state = self.robot.state
|
||||||
|
except NeatoRobotException as ex:
|
||||||
|
if self.available: # print only once when available
|
||||||
|
_LOGGER.error(
|
||||||
|
"Vorwerk vacuum connection error for '%s': %s", self.robot.name, ex
|
||||||
|
)
|
||||||
|
self.robot_state = {}
|
||||||
|
return
|
||||||
|
|
||||||
|
self._available = True
|
||||||
|
|
||||||
|
@property
|
||||||
|
@when_available
|
||||||
|
def docked(self) -> Optional[bool]:
|
||||||
|
"""Vacuum is docked."""
|
||||||
|
return (
|
||||||
|
self.robot_state["state"] == ROBOT_STATE_IDLE
|
||||||
|
and self.robot_state["details"]["isDocked"]
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
@when_available
|
||||||
|
def charging(self) -> Optional[bool]:
|
||||||
|
"""Vacuum is charging."""
|
||||||
|
return (
|
||||||
|
self.robot_state.get("state") == ROBOT_STATE_IDLE
|
||||||
|
and self.robot_state["details"]["isCharging"]
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
@when_available
|
||||||
|
def state(self) -> Optional[str]:
|
||||||
|
"""Return Home Assistant vacuum state."""
|
||||||
|
robot_state = self.robot_state.get("state")
|
||||||
|
if self.charging or self.docked:
|
||||||
|
return STATE_DOCKED
|
||||||
|
elif robot_state == ROBOT_STATE_IDLE:
|
||||||
|
return STATE_IDLE
|
||||||
|
elif robot_state == ROBOT_STATE_BUSY:
|
||||||
|
if robot_state["action"] != ROBOT_ACTION_DOCKING:
|
||||||
|
return STATE_RETURNING
|
||||||
|
else:
|
||||||
|
return STATE_CLEANING
|
||||||
|
elif robot_state == ROBOT_STATE_PAUSE:
|
||||||
|
return STATE_PAUSED
|
||||||
|
elif robot_state == ROBOT_STATE_ERROR:
|
||||||
|
return STATE_ERROR
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
@when_available
|
||||||
|
def alert(self) -> Optional[str]:
|
||||||
|
"""Return vacuum alert message."""
|
||||||
|
if "alert" in self.robot_state:
|
||||||
|
return ALERTS.get(self.robot_state["alert"], self.robot_state["alert"])
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
@when_available
|
||||||
|
def status(self) -> Optional[str]:
|
||||||
|
"""Return vacuum status message."""
|
||||||
|
status = None
|
||||||
|
|
||||||
|
if self.state == STATE_ERROR:
|
||||||
|
status = self._error_status()
|
||||||
|
elif self.alert:
|
||||||
|
status = self.alert
|
||||||
|
elif self.state == STATE_DOCKED:
|
||||||
|
if self.charging:
|
||||||
|
status = "Charging"
|
||||||
|
if self.docked:
|
||||||
|
status = "Docked"
|
||||||
|
elif self.state == STATE_IDLE:
|
||||||
|
status = "Stopped"
|
||||||
|
elif self.state == STATE_CLEANING:
|
||||||
|
status = self._cleaning_status()
|
||||||
|
elif self.state == STATE_PAUSED:
|
||||||
|
status = "Paused"
|
||||||
|
|
||||||
|
return status
|
||||||
|
|
||||||
|
def _error_status(self):
|
||||||
|
"""Return error status."""
|
||||||
|
robot_state = self.robot_state.get("state")
|
||||||
|
return ERRORS.get(robot_state["error"], robot_state["error"])
|
||||||
|
|
||||||
|
def _cleaning_status(self):
|
||||||
|
"""Return cleaning status."""
|
||||||
|
robot_state = self.robot_state.get("state")
|
||||||
|
status_items = [
|
||||||
|
MODE.get(robot_state["cleaning"]["mode"]),
|
||||||
|
ACTION.get(robot_state["action"]),
|
||||||
|
]
|
||||||
|
if (
|
||||||
|
"boundary" in robot_state["cleaning"]
|
||||||
|
and "name" in robot_state["cleaning"]["boundary"]
|
||||||
|
):
|
||||||
|
status_items.append(robot_state["cleaning"]["boundary"]["name"])
|
||||||
|
return " ".join(s for s in status_items if s)
|
||||||
|
|
||||||
|
@property
|
||||||
|
@when_available
|
||||||
|
def battery_level(self):
|
||||||
|
"""Return the battery level of the vacuum cleaner."""
|
||||||
|
return self.robot_state["details"]["charge"]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_info(self):
|
||||||
|
"""Device info for robot."""
|
||||||
|
info = {
|
||||||
|
"identifiers": {(VORWERK_DOMAIN, self.robot.serial)},
|
||||||
|
"name": self.robot.name,
|
||||||
|
}
|
||||||
|
if self.robot_info:
|
||||||
|
info["manufacturer"] = self.robot_info["battery"]["vendor"]
|
||||||
|
info["model"] = self.robot_info["model"]
|
||||||
|
info["sw_version"] = self.robot_info["firmware"]
|
||||||
|
return info
|
||||||
|
|
||||||
|
@property
|
||||||
|
@when_available
|
||||||
|
def scheduleEnabled(self) -> Optional[bool]:
|
||||||
|
"""Return True when schedule is enabled."""
|
||||||
|
return bool(self.robot_state["details"]["isScheduleEnabled"])
|
@ -1,18 +0,0 @@
|
|||||||
"""Auth sessions for pybotvac."""
|
|
||||||
import pybotvac
|
|
||||||
|
|
||||||
|
|
||||||
class VorwerkSession(pybotvac.PasswordlessSession):
|
|
||||||
"""PasswordlessSession pybotvac session for Vorwerk cloud."""
|
|
||||||
|
|
||||||
# The client_id is the same for all users.
|
|
||||||
CLIENT_ID = "KY4YbVAvtgB7lp8vIbWQ7zLk3hssZlhR"
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
"""Initialize Vorwerk cloud session."""
|
|
||||||
super().__init__(client_id=VorwerkSession.CLIENT_ID, vendor=pybotvac.Vorwerk())
|
|
||||||
|
|
||||||
@property
|
|
||||||
def token(self):
|
|
||||||
"""Return the token dict. Contains id_token, access_token and refresh_token."""
|
|
||||||
return self._token
|
|
@ -9,7 +9,7 @@ import voluptuous as vol
|
|||||||
from homeassistant import config_entries
|
from homeassistant import config_entries
|
||||||
from homeassistant.const import CONF_CODE, CONF_EMAIL, CONF_TOKEN
|
from homeassistant.const import CONF_CODE, CONF_EMAIL, CONF_TOKEN
|
||||||
|
|
||||||
from . import authsession
|
from . import api
|
||||||
|
|
||||||
# pylint: disable=unused-import
|
# pylint: disable=unused-import
|
||||||
from .const import (
|
from .const import (
|
||||||
@ -36,7 +36,7 @@ class VorwerkConfigFlow(config_entries.ConfigFlow, domain=VORWERK_DOMAIN):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""Initialize the config flow."""
|
"""Initialize the config flow."""
|
||||||
self._email: Optional[str] = None
|
self._email: Optional[str] = None
|
||||||
self._session = authsession.VorwerkSession()
|
self._session = api.VorwerkSession()
|
||||||
|
|
||||||
async def async_step_user(self, user_input=None):
|
async def async_step_user(self, user_input=None):
|
||||||
"""Step when user initializes a integration."""
|
"""Step when user initializes a integration."""
|
||||||
@ -67,7 +67,9 @@ class VorwerkConfigFlow(config_entries.ConfigFlow, domain=VORWERK_DOMAIN):
|
|||||||
code = user_input.get(CONF_CODE) if user_input else None
|
code = user_input.get(CONF_CODE) if user_input else None
|
||||||
if code:
|
if code:
|
||||||
try:
|
try:
|
||||||
robots = await self.async_get_robots(self._email, code)
|
robots = await self.hass.async_add_executor_job(
|
||||||
|
self._get_robots, self._email, code
|
||||||
|
)
|
||||||
return self.async_create_entry(
|
return self.async_create_entry(
|
||||||
title=self._email,
|
title=self._email,
|
||||||
data={
|
data={
|
||||||
@ -79,7 +81,10 @@ class VorwerkConfigFlow(config_entries.ConfigFlow, domain=VORWERK_DOMAIN):
|
|||||||
except (HTTPError, NeatoException):
|
except (HTTPError, NeatoException):
|
||||||
errors["base"] = "invalid_auth"
|
errors["base"] = "invalid_auth"
|
||||||
|
|
||||||
self._session.send_email_otp(self._email)
|
await self.hass.async_add_executor_job(
|
||||||
|
self._session.send_email_otp, self._email
|
||||||
|
)
|
||||||
|
|
||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
step_id="code",
|
step_id="code",
|
||||||
data_schema=vol.Schema(
|
data_schema=vol.Schema(
|
||||||
@ -105,7 +110,7 @@ class VorwerkConfigFlow(config_entries.ConfigFlow, domain=VORWERK_DOMAIN):
|
|||||||
data=data,
|
data=data,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def async_get_robots(self, email: str, code: str):
|
def _get_robots(self, email: str, code: str):
|
||||||
"""Fetch the robot list from vorwerk."""
|
"""Fetch the robot list from vorwerk."""
|
||||||
self._session.fetch_token_passwordless(email, code)
|
self._session.fetch_token_passwordless(email, code)
|
||||||
return [
|
return [
|
||||||
|
21
const.py
21
const.py
@ -1,8 +1,11 @@
|
|||||||
"""Constants for Vorwerk integration."""
|
"""Constants for Vorwerk integration."""
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
VORWERK_DOMAIN = "vorwerk"
|
VORWERK_DOMAIN = "vorwerk"
|
||||||
|
|
||||||
VORWERK_ROBOTS = "robots"
|
VORWERK_ROBOTS = "robots"
|
||||||
|
VORWERK_ROBOT_API = "robot_api"
|
||||||
|
VORWERK_ROBOT_COORDINATOR = "robot_coordinator"
|
||||||
|
|
||||||
VORWERK_ROBOT_NAME = "name"
|
VORWERK_ROBOT_NAME = "name"
|
||||||
VORWERK_ROBOT_SERIAL = "serial"
|
VORWERK_ROBOT_SERIAL = "serial"
|
||||||
@ -12,7 +15,7 @@ VORWERK_ROBOT_ENDPOINT = "endpoint"
|
|||||||
|
|
||||||
VORWERK_PLATFORMS = ["vacuum", "switch", "sensor"]
|
VORWERK_PLATFORMS = ["vacuum", "switch", "sensor"]
|
||||||
|
|
||||||
SCAN_INTERVAL_MINUTES = 1
|
MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=1)
|
||||||
|
|
||||||
MODE = {1: "Eco", 2: "Turbo"}
|
MODE = {1: "Eco", 2: "Turbo"}
|
||||||
|
|
||||||
@ -162,3 +165,19 @@ ATTR_CLEAN_SUSP_TIME = "clean_suspension_time"
|
|||||||
ATTR_CLEAN_PAUSE_TIME = "clean_pause_time"
|
ATTR_CLEAN_PAUSE_TIME = "clean_pause_time"
|
||||||
ATTR_CLEAN_ERROR_TIME = "clean_error_time"
|
ATTR_CLEAN_ERROR_TIME = "clean_error_time"
|
||||||
ATTR_LAUNCHED_FROM = "launched_from"
|
ATTR_LAUNCHED_FROM = "launched_from"
|
||||||
|
|
||||||
|
ATTR_NAVIGATION = "navigation"
|
||||||
|
ATTR_CATEGORY = "category"
|
||||||
|
ATTR_ZONE = "zone"
|
||||||
|
|
||||||
|
|
||||||
|
ROBOT_STATE_INVALID = 0
|
||||||
|
ROBOT_STATE_IDLE = 1
|
||||||
|
ROBOT_STATE_BUSY = 2
|
||||||
|
ROBOT_STATE_PAUSE = 3
|
||||||
|
ROBOT_STATE_ERROR = 4
|
||||||
|
|
||||||
|
ROBOT_ACTION_HOUSE_CLEANING = 1
|
||||||
|
ROBOT_ACTION_SPOT_CLEANING = 2
|
||||||
|
ROBOT_ACTION_MANUAL_CLEANING = 3
|
||||||
|
ROBOT_ACTION_DOCKING = 4
|
||||||
|
@ -11,5 +11,6 @@
|
|||||||
],
|
],
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"http"
|
"http"
|
||||||
]
|
],
|
||||||
|
"iot_class": "cloud_polling"
|
||||||
}
|
}
|
52
sensor.py
52
sensor.py
@ -1,18 +1,26 @@
|
|||||||
"""Support for Vorwerk sensors."""
|
"""Support for Vorwerk sensors."""
|
||||||
from datetime import timedelta
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from pybotvac.exceptions import NeatoRobotException
|
from pybotvac.robot import Robot
|
||||||
|
|
||||||
from homeassistant.components.sensor import DEVICE_CLASS_BATTERY
|
from homeassistant.components.sensor import DEVICE_CLASS_BATTERY
|
||||||
from homeassistant.const import PERCENTAGE
|
from homeassistant.const import PERCENTAGE
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
|
from homeassistant.helpers.update_coordinator import (
|
||||||
|
CoordinatorEntity,
|
||||||
|
DataUpdateCoordinator,
|
||||||
|
)
|
||||||
|
|
||||||
from .const import SCAN_INTERVAL_MINUTES, VORWERK_DOMAIN, VORWERK_ROBOTS
|
from .api import VorwerkState
|
||||||
|
from .const import (
|
||||||
|
VORWERK_DOMAIN,
|
||||||
|
VORWERK_ROBOT_API,
|
||||||
|
VORWERK_ROBOT_COORDINATOR,
|
||||||
|
VORWERK_ROBOTS,
|
||||||
|
)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
SCAN_INTERVAL = timedelta(minutes=SCAN_INTERVAL_MINUTES)
|
|
||||||
|
|
||||||
BATTERY = "Battery"
|
BATTERY = "Battery"
|
||||||
|
|
||||||
@ -22,39 +30,25 @@ async def async_setup_entry(hass, entry, async_add_entities):
|
|||||||
_LOGGER.debug("Adding sensors for vorwerk robots")
|
_LOGGER.debug("Adding sensors for vorwerk robots")
|
||||||
async_add_entities(
|
async_add_entities(
|
||||||
[
|
[
|
||||||
VorwerkSensor(robot)
|
VorwerkSensor(robot[VORWERK_ROBOT_API], robot[VORWERK_ROBOT_COORDINATOR])
|
||||||
for robot in hass.data[VORWERK_DOMAIN][entry.entry_id][VORWERK_ROBOTS]
|
for robot in hass.data[VORWERK_DOMAIN][entry.entry_id][VORWERK_ROBOTS]
|
||||||
],
|
],
|
||||||
True,
|
True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class VorwerkSensor(Entity):
|
class VorwerkSensor(CoordinatorEntity, Entity):
|
||||||
"""Vorwerk sensor."""
|
"""Vorwerk sensor."""
|
||||||
|
|
||||||
def __init__(self, robot):
|
def __init__(
|
||||||
|
self, robot_state: VorwerkState, coordinator: DataUpdateCoordinator
|
||||||
|
) -> None:
|
||||||
"""Initialize Vorwerk sensor."""
|
"""Initialize Vorwerk sensor."""
|
||||||
self.robot = robot
|
super().__init__(coordinator)
|
||||||
self._available = False
|
self.robot: Robot = robot_state.robot
|
||||||
|
self._state: VorwerkState = robot_state
|
||||||
self._robot_name = f"{self.robot.name} {BATTERY}"
|
self._robot_name = f"{self.robot.name} {BATTERY}"
|
||||||
self._robot_serial = self.robot.serial
|
self._robot_serial = self.robot.serial
|
||||||
self._state = None
|
|
||||||
|
|
||||||
def update(self):
|
|
||||||
"""Update Vorwerk Sensor."""
|
|
||||||
try:
|
|
||||||
self._state = self.robot.state
|
|
||||||
except NeatoRobotException as ex:
|
|
||||||
if self._available:
|
|
||||||
_LOGGER.error(
|
|
||||||
"Vorwerk sensor connection error for '%s': %s", self.entity_id, ex
|
|
||||||
)
|
|
||||||
self._state = None
|
|
||||||
self._available = False
|
|
||||||
return
|
|
||||||
|
|
||||||
self._available = True
|
|
||||||
_LOGGER.debug("self._state=%s", self._state)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
@ -74,12 +68,12 @@ class VorwerkSensor(Entity):
|
|||||||
@property
|
@property
|
||||||
def available(self):
|
def available(self):
|
||||||
"""Return availability."""
|
"""Return availability."""
|
||||||
return self._available
|
return self._state.available
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
"""Return the state."""
|
"""Return the state."""
|
||||||
return self._state["details"]["charge"]
|
return self._state.battery_level
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unit_of_measurement(self):
|
def unit_of_measurement(self):
|
||||||
@ -89,4 +83,4 @@ class VorwerkSensor(Entity):
|
|||||||
@property
|
@property
|
||||||
def device_info(self):
|
def device_info(self):
|
||||||
"""Device info for robot."""
|
"""Device info for robot."""
|
||||||
return {"identifiers": {(VORWERK_DOMAIN, self._robot_serial)}}
|
return self._state.device_info
|
||||||
|
101
switch.py
101
switch.py
@ -1,31 +1,36 @@
|
|||||||
"""Support for Vorwerk Connected Vacuums switches."""
|
"""Support for Vorwerk Connected Vacuums switches."""
|
||||||
from datetime import timedelta
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from pybotvac.exceptions import NeatoRobotException
|
from pybotvac.exceptions import NeatoRobotException
|
||||||
|
from pybotvac.robot import Robot
|
||||||
|
|
||||||
from homeassistant.const import STATE_OFF, STATE_ON
|
from homeassistant.const import STATE_OFF, STATE_ON
|
||||||
from homeassistant.helpers.entity import ToggleEntity
|
from homeassistant.helpers.entity import ToggleEntity
|
||||||
|
from homeassistant.helpers.update_coordinator import (
|
||||||
|
CoordinatorEntity,
|
||||||
|
DataUpdateCoordinator,
|
||||||
|
)
|
||||||
|
|
||||||
from .const import SCAN_INTERVAL_MINUTES, VORWERK_DOMAIN, VORWERK_ROBOTS
|
from .api import VorwerkState
|
||||||
|
from .const import (
|
||||||
|
VORWERK_DOMAIN,
|
||||||
|
VORWERK_ROBOT_API,
|
||||||
|
VORWERK_ROBOT_COORDINATOR,
|
||||||
|
VORWERK_ROBOTS,
|
||||||
|
)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
SCAN_INTERVAL = timedelta(minutes=SCAN_INTERVAL_MINUTES)
|
|
||||||
|
|
||||||
SWITCH_TYPE_SCHEDULE = "schedule"
|
|
||||||
|
|
||||||
SWITCH_TYPES = {SWITCH_TYPE_SCHEDULE: ["Schedule"]}
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass, entry, async_add_entities):
|
async def async_setup_entry(hass, entry, async_add_entities):
|
||||||
"""Set up Vorwerk switch with config entry."""
|
"""Set up Vorwerk switch with config entry."""
|
||||||
_LOGGER.debug("Adding switches for vorwerk (%s)", entry.title)
|
_LOGGER.debug("Adding switches for vorwerk (%s)", entry.title)
|
||||||
|
|
||||||
dev = [
|
dev = [
|
||||||
VorwerkConnectedSwitch(robot, switch_type)
|
VorwerkScheduleSwitch(
|
||||||
|
robot[VORWERK_ROBOT_API], robot[VORWERK_ROBOT_COORDINATOR]
|
||||||
|
)
|
||||||
for robot in hass.data[VORWERK_DOMAIN][entry.entry_id][VORWERK_ROBOTS]
|
for robot in hass.data[VORWERK_DOMAIN][entry.entry_id][VORWERK_ROBOTS]
|
||||||
for switch_type in SWITCH_TYPES
|
|
||||||
]
|
]
|
||||||
|
|
||||||
if not dev:
|
if not dev:
|
||||||
@ -34,46 +39,19 @@ async def async_setup_entry(hass, entry, async_add_entities):
|
|||||||
async_add_entities(dev, True)
|
async_add_entities(dev, True)
|
||||||
|
|
||||||
|
|
||||||
class VorwerkConnectedSwitch(ToggleEntity):
|
class VorwerkScheduleSwitch(CoordinatorEntity, ToggleEntity):
|
||||||
"""Vorwerk Connected Switches."""
|
"""Vorwerk Schedule Switches."""
|
||||||
|
|
||||||
def __init__(self, robot, switch_type):
|
def __init__(
|
||||||
"""Initialize the Vorwerk Connected switches."""
|
self, robot_state: VorwerkState, coordinator: DataUpdateCoordinator
|
||||||
self.type = switch_type
|
) -> None:
|
||||||
self.robot = robot
|
"""Initialize the Vorwerk Schedule switch."""
|
||||||
self._available = False
|
super().__init__(coordinator)
|
||||||
self._robot_name = f"{self.robot.name} {SWITCH_TYPES[self.type][0]}"
|
self.robot: Robot = robot_state.robot
|
||||||
self._state = None
|
self._robot_name = f"{self.robot.name} Schedule"
|
||||||
self._schedule_state = None
|
self._state: VorwerkState = robot_state
|
||||||
self._clean_state = None
|
|
||||||
self._robot_serial = self.robot.serial
|
self._robot_serial = self.robot.serial
|
||||||
|
|
||||||
def update(self):
|
|
||||||
"""Update the states of Vorwerk switches."""
|
|
||||||
_LOGGER.debug("Running Vorwerk switch update for '%s'", self.entity_id)
|
|
||||||
try:
|
|
||||||
self._state = self.robot.state
|
|
||||||
except NeatoRobotException as ex:
|
|
||||||
if self._available: # Print only once when available
|
|
||||||
_LOGGER.error(
|
|
||||||
"Vorwerk switch connection error for '%s': %s", self.entity_id, ex
|
|
||||||
)
|
|
||||||
self._state = None
|
|
||||||
self._available = False
|
|
||||||
return
|
|
||||||
|
|
||||||
self._available = True
|
|
||||||
_LOGGER.debug("self._state=%s", self._state)
|
|
||||||
if self.type == SWITCH_TYPE_SCHEDULE:
|
|
||||||
_LOGGER.debug("State: %s", self._state)
|
|
||||||
if self._state["details"]["isScheduleEnabled"]:
|
|
||||||
self._schedule_state = STATE_ON
|
|
||||||
else:
|
|
||||||
self._schedule_state = STATE_OFF
|
|
||||||
_LOGGER.debug(
|
|
||||||
"Schedule state for '%s': %s", self.entity_id, self._schedule_state
|
|
||||||
)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
"""Return the name of the switch."""
|
"""Return the name of the switch."""
|
||||||
@ -82,7 +60,7 @@ class VorwerkConnectedSwitch(ToggleEntity):
|
|||||||
@property
|
@property
|
||||||
def available(self):
|
def available(self):
|
||||||
"""Return True if entity is available."""
|
"""Return True if entity is available."""
|
||||||
return self._available
|
return self._state.available
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unique_id(self):
|
def unique_id(self):
|
||||||
@ -92,19 +70,21 @@ class VorwerkConnectedSwitch(ToggleEntity):
|
|||||||
@property
|
@property
|
||||||
def is_on(self):
|
def is_on(self):
|
||||||
"""Return true if switch is on."""
|
"""Return true if switch is on."""
|
||||||
if self.type == SWITCH_TYPE_SCHEDULE:
|
if self._state.available:
|
||||||
if self._schedule_state == STATE_ON:
|
if self._state.scheduleEnabled:
|
||||||
return True
|
return STATE_ON
|
||||||
return False
|
else:
|
||||||
|
return STATE_OFF
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_info(self):
|
def device_info(self):
|
||||||
"""Device info for robot."""
|
"""Device info for robot."""
|
||||||
return {"identifiers": {(VORWERK_DOMAIN, self._robot_serial)}}
|
return self._state.device_info
|
||||||
|
|
||||||
def turn_on(self, **kwargs):
|
async def async_turn_on(self, **kwargs):
|
||||||
"""Turn the switch on."""
|
"""Turn the switch on."""
|
||||||
if self.type == SWITCH_TYPE_SCHEDULE:
|
|
||||||
|
def turn_on():
|
||||||
try:
|
try:
|
||||||
self.robot.enable_schedule()
|
self.robot.enable_schedule()
|
||||||
except NeatoRobotException as ex:
|
except NeatoRobotException as ex:
|
||||||
@ -112,12 +92,19 @@ class VorwerkConnectedSwitch(ToggleEntity):
|
|||||||
"Vorwerk switch connection error '%s': %s", self.entity_id, ex
|
"Vorwerk switch connection error '%s': %s", self.entity_id, ex
|
||||||
)
|
)
|
||||||
|
|
||||||
def turn_off(self, **kwargs):
|
await self.hass.async_add_executor_job(turn_on)
|
||||||
|
await self.coordinator.async_request_refresh()
|
||||||
|
|
||||||
|
async def async_turn_off(self, **kwargs):
|
||||||
"""Turn the switch off."""
|
"""Turn the switch off."""
|
||||||
if self.type == SWITCH_TYPE_SCHEDULE:
|
|
||||||
|
def turn_off():
|
||||||
try:
|
try:
|
||||||
self.robot.disable_schedule()
|
self.robot.disable_schedule()
|
||||||
except NeatoRobotException as ex:
|
except NeatoRobotException as ex:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
"Vorwerk switch connection error '%s': %s", self.entity_id, ex
|
"Vorwerk switch connection error '%s': %s", self.entity_id, ex
|
||||||
)
|
)
|
||||||
|
|
||||||
|
await self.hass.async_add_executor_job(turn_off)
|
||||||
|
await self.coordinator.async_request_refresh()
|
||||||
|
149
vacuum.py
149
vacuum.py
@ -1,18 +1,16 @@
|
|||||||
"""Support for Neato Connected Vacuums."""
|
"""Support for Neato Connected Vacuums."""
|
||||||
from datetime import timedelta
|
|
||||||
import logging
|
import logging
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
from pybotvac.exceptions import NeatoRobotException
|
from pybotvac.exceptions import NeatoRobotException
|
||||||
|
from pybotvac.robot import Robot
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
from homeassistant.components.vacuum import (
|
from homeassistant.components.vacuum import (
|
||||||
ATTR_STATUS,
|
ATTR_STATUS,
|
||||||
STATE_CLEANING,
|
STATE_CLEANING,
|
||||||
STATE_DOCKED,
|
|
||||||
STATE_ERROR,
|
|
||||||
STATE_IDLE,
|
STATE_IDLE,
|
||||||
STATE_PAUSED,
|
STATE_PAUSED,
|
||||||
STATE_RETURNING,
|
|
||||||
SUPPORT_BATTERY,
|
SUPPORT_BATTERY,
|
||||||
SUPPORT_CLEAN_SPOT,
|
SUPPORT_CLEAN_SPOT,
|
||||||
SUPPORT_LOCATE,
|
SUPPORT_LOCATE,
|
||||||
@ -23,12 +21,17 @@ from homeassistant.components.vacuum import (
|
|||||||
SUPPORT_STOP,
|
SUPPORT_STOP,
|
||||||
StateVacuumEntity,
|
StateVacuumEntity,
|
||||||
)
|
)
|
||||||
|
|
||||||
from homeassistant.const import ATTR_MODE
|
from homeassistant.const import ATTR_MODE
|
||||||
from homeassistant.helpers import config_validation as cv, entity_platform
|
from homeassistant.helpers import config_validation as cv, entity_platform
|
||||||
|
from homeassistant.helpers.update_coordinator import (
|
||||||
|
CoordinatorEntity,
|
||||||
|
DataUpdateCoordinator,
|
||||||
|
)
|
||||||
|
|
||||||
|
from .api import VorwerkState
|
||||||
from .const import (
|
from .const import (
|
||||||
ACTION,
|
ATTR_CATEGORY,
|
||||||
ALERTS,
|
|
||||||
ATTR_CLEAN_AREA,
|
ATTR_CLEAN_AREA,
|
||||||
ATTR_CLEAN_BATTERY_END,
|
ATTR_CLEAN_BATTERY_END,
|
||||||
ATTR_CLEAN_BATTERY_START,
|
ATTR_CLEAN_BATTERY_START,
|
||||||
@ -39,16 +42,16 @@ from .const import (
|
|||||||
ATTR_CLEAN_SUSP_COUNT,
|
ATTR_CLEAN_SUSP_COUNT,
|
||||||
ATTR_CLEAN_SUSP_TIME,
|
ATTR_CLEAN_SUSP_TIME,
|
||||||
ATTR_LAUNCHED_FROM,
|
ATTR_LAUNCHED_FROM,
|
||||||
ERRORS,
|
ATTR_NAVIGATION,
|
||||||
MODE,
|
ATTR_ZONE,
|
||||||
SCAN_INTERVAL_MINUTES,
|
|
||||||
VORWERK_DOMAIN,
|
VORWERK_DOMAIN,
|
||||||
|
VORWERK_ROBOT_API,
|
||||||
|
VORWERK_ROBOT_COORDINATOR,
|
||||||
VORWERK_ROBOTS,
|
VORWERK_ROBOTS,
|
||||||
)
|
)
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
SCAN_INTERVAL = timedelta(minutes=SCAN_INTERVAL_MINUTES)
|
|
||||||
|
|
||||||
SUPPORT_VORWERK = (
|
SUPPORT_VORWERK = (
|
||||||
SUPPORT_BATTERY
|
SUPPORT_BATTERY
|
||||||
@ -62,18 +65,15 @@ SUPPORT_VORWERK = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
ATTR_NAVIGATION = "navigation"
|
|
||||||
ATTR_CATEGORY = "category"
|
|
||||||
ATTR_ZONE = "zone"
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass, entry, async_add_entities):
|
async def async_setup_entry(hass, entry, async_add_entities):
|
||||||
"""Set up Vorwerk vacuum with config entry."""
|
"""Set up Vorwerk vacuum with config entry."""
|
||||||
|
|
||||||
_LOGGER.debug("Adding vorwerk vacuums")
|
_LOGGER.debug("Adding vorwerk vacuums")
|
||||||
async_add_entities(
|
async_add_entities(
|
||||||
[
|
[
|
||||||
VorwerkConnectedVacuum(robot)
|
VorwerkConnectedVacuum(
|
||||||
|
robot[VORWERK_ROBOT_API], robot[VORWERK_ROBOT_COORDINATOR]
|
||||||
|
)
|
||||||
for robot in hass.data[VORWERK_DOMAIN][entry.entry_id][VORWERK_ROBOTS]
|
for robot in hass.data[VORWERK_DOMAIN][entry.entry_id][VORWERK_ROBOTS]
|
||||||
],
|
],
|
||||||
True,
|
True,
|
||||||
@ -94,19 +94,23 @@ async def async_setup_entry(hass, entry, async_add_entities):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class VorwerkConnectedVacuum(StateVacuumEntity):
|
class VorwerkConnectedVacuum(CoordinatorEntity, StateVacuumEntity):
|
||||||
"""Representation of a Vorwerk Connected Vacuum."""
|
"""Representation of a Vorwerk Connected Vacuum."""
|
||||||
|
|
||||||
def __init__(self, robot):
|
def __init__(
|
||||||
|
self, robot_state: VorwerkState, coordinator: DataUpdateCoordinator[Any]
|
||||||
|
) -> None:
|
||||||
"""Initialize the Vorwerk Connected Vacuum."""
|
"""Initialize the Vorwerk Connected Vacuum."""
|
||||||
self.robot = robot
|
super().__init__(coordinator)
|
||||||
self._available = False
|
self.robot: Robot = robot_state.robot
|
||||||
|
self._state: VorwerkState = robot_state
|
||||||
|
|
||||||
self._name = f"{self.robot.name}"
|
self._name = f"{self.robot.name}"
|
||||||
self._robot_has_map = False
|
|
||||||
self._robot_serial = self.robot.serial
|
self._robot_serial = self.robot.serial
|
||||||
self._status_state = None
|
|
||||||
|
# Variables form neato impl
|
||||||
|
# We keep it here for later implementations
|
||||||
self._clean_state = None
|
self._clean_state = None
|
||||||
self._state = None
|
|
||||||
self._clean_time_start = None
|
self._clean_time_start = None
|
||||||
self._clean_time_stop = None
|
self._clean_time_stop = None
|
||||||
self._clean_area = None
|
self._clean_area = None
|
||||||
@ -117,76 +121,7 @@ class VorwerkConnectedVacuum(StateVacuumEntity):
|
|||||||
self._clean_pause_time = None
|
self._clean_pause_time = None
|
||||||
self._clean_error_time = None
|
self._clean_error_time = None
|
||||||
self._launched_from = None
|
self._launched_from = None
|
||||||
self._battery_level = None
|
|
||||||
self._robot_boundaries = []
|
self._robot_boundaries = []
|
||||||
self._robot_stats = None
|
|
||||||
|
|
||||||
def update(self):
|
|
||||||
"""Update the states of Vorwerk Vacuums."""
|
|
||||||
_LOGGER.debug("Running Vorwerk Vacuums update for '%s'", self.entity_id)
|
|
||||||
try:
|
|
||||||
if self._robot_stats is None:
|
|
||||||
self._robot_stats = self.robot.get_general_info().json().get("data")
|
|
||||||
except NeatoRobotException:
|
|
||||||
_LOGGER.warning("Couldn't fetch robot information of %s", self.entity_id)
|
|
||||||
|
|
||||||
try:
|
|
||||||
self._state = self.robot.state
|
|
||||||
except NeatoRobotException as ex:
|
|
||||||
if self._available: # print only once when available
|
|
||||||
_LOGGER.error(
|
|
||||||
"Vorwerk vacuum connection error for '%s': %s", self.entity_id, ex
|
|
||||||
)
|
|
||||||
self._state = None
|
|
||||||
self._available = False
|
|
||||||
return
|
|
||||||
|
|
||||||
self._available = True
|
|
||||||
_LOGGER.debug("self._state=%s", self._state)
|
|
||||||
if "alert" in self._state:
|
|
||||||
robot_alert = ALERTS.get(self._state["alert"])
|
|
||||||
else:
|
|
||||||
robot_alert = None
|
|
||||||
if self._state["state"] == 1:
|
|
||||||
if self._state["details"]["isCharging"]:
|
|
||||||
self._clean_state = STATE_DOCKED
|
|
||||||
self._status_state = "Charging"
|
|
||||||
elif (
|
|
||||||
self._state["details"]["isDocked"]
|
|
||||||
and not self._state["details"]["isCharging"]
|
|
||||||
):
|
|
||||||
self._clean_state = STATE_DOCKED
|
|
||||||
self._status_state = "Docked"
|
|
||||||
else:
|
|
||||||
self._clean_state = STATE_IDLE
|
|
||||||
self._status_state = "Stopped"
|
|
||||||
|
|
||||||
if robot_alert is not None:
|
|
||||||
self._status_state = robot_alert
|
|
||||||
elif self._state["state"] == 2:
|
|
||||||
if robot_alert is None:
|
|
||||||
self._clean_state = STATE_CLEANING
|
|
||||||
self._status_state = (
|
|
||||||
f"{MODE.get(self._state['cleaning']['mode'])} "
|
|
||||||
f"{ACTION.get(self._state['action'])}"
|
|
||||||
)
|
|
||||||
if (
|
|
||||||
"boundary" in self._state["cleaning"]
|
|
||||||
and "name" in self._state["cleaning"]["boundary"]
|
|
||||||
):
|
|
||||||
self._status_state += (
|
|
||||||
f" {self._state['cleaning']['boundary']['name']}"
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
self._status_state = robot_alert
|
|
||||||
elif self._state["state"] == 3:
|
|
||||||
self._clean_state = STATE_PAUSED
|
|
||||||
self._status_state = "Paused"
|
|
||||||
elif self._state["state"] == 4:
|
|
||||||
self._clean_state = STATE_ERROR
|
|
||||||
self._status_state = ERRORS.get(self._state["error"])
|
|
||||||
|
|
||||||
self._battery_level = self._state["details"]["charge"]
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
@ -201,12 +136,12 @@ class VorwerkConnectedVacuum(StateVacuumEntity):
|
|||||||
@property
|
@property
|
||||||
def battery_level(self):
|
def battery_level(self):
|
||||||
"""Return the battery level of the vacuum cleaner."""
|
"""Return the battery level of the vacuum cleaner."""
|
||||||
return self._battery_level
|
return self._state.battery_level
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def available(self):
|
def available(self):
|
||||||
"""Return if the robot is available."""
|
"""Return if the robot is available."""
|
||||||
return self._available
|
return self._state.available
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def icon(self):
|
def icon(self):
|
||||||
@ -216,7 +151,7 @@ class VorwerkConnectedVacuum(StateVacuumEntity):
|
|||||||
@property
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
"""Return the status of the vacuum cleaner."""
|
"""Return the status of the vacuum cleaner."""
|
||||||
return self._clean_state
|
return self._state.state if self._state else None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unique_id(self):
|
def unique_id(self):
|
||||||
@ -228,8 +163,8 @@ class VorwerkConnectedVacuum(StateVacuumEntity):
|
|||||||
"""Return the state attributes of the vacuum cleaner."""
|
"""Return the state attributes of the vacuum cleaner."""
|
||||||
data = {}
|
data = {}
|
||||||
|
|
||||||
if self._status_state is not None:
|
if self._state.status is not None:
|
||||||
data[ATTR_STATUS] = self._status_state
|
data[ATTR_STATUS] = self._state.status
|
||||||
if self._clean_time_start is not None:
|
if self._clean_time_start is not None:
|
||||||
data[ATTR_CLEAN_START] = self._clean_time_start
|
data[ATTR_CLEAN_START] = self._clean_time_start
|
||||||
if self._clean_time_stop is not None:
|
if self._clean_time_stop is not None:
|
||||||
@ -256,22 +191,16 @@ class VorwerkConnectedVacuum(StateVacuumEntity):
|
|||||||
@property
|
@property
|
||||||
def device_info(self):
|
def device_info(self):
|
||||||
"""Device info for robot."""
|
"""Device info for robot."""
|
||||||
info = {
|
return self._state.device_info
|
||||||
"identifiers": {(VORWERK_DOMAIN, self._robot_serial)},
|
|
||||||
"name": self._name,
|
|
||||||
}
|
|
||||||
if self._robot_stats:
|
|
||||||
info["manufacturer"] = self._robot_stats["battery"]["vendor"]
|
|
||||||
info["model"] = self._robot_stats["model"]
|
|
||||||
info["sw_version"] = self._robot_stats["firmware"]
|
|
||||||
return info
|
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
"""Start cleaning or resume cleaning."""
|
"""Start cleaning or resume cleaning."""
|
||||||
|
if not self._state:
|
||||||
|
return
|
||||||
try:
|
try:
|
||||||
if self._state["state"] == 1:
|
if self._state.state == STATE_IDLE:
|
||||||
self.robot.start_cleaning()
|
self.robot.start_cleaning()
|
||||||
elif self._state["state"] == 3:
|
elif self._state.state == STATE_PAUSED:
|
||||||
self.robot.resume_cleaning()
|
self.robot.resume_cleaning()
|
||||||
except NeatoRobotException as ex:
|
except NeatoRobotException as ex:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
@ -290,9 +219,8 @@ class VorwerkConnectedVacuum(StateVacuumEntity):
|
|||||||
def return_to_base(self, **kwargs):
|
def return_to_base(self, **kwargs):
|
||||||
"""Set the vacuum cleaner to return to the dock."""
|
"""Set the vacuum cleaner to return to the dock."""
|
||||||
try:
|
try:
|
||||||
if self._clean_state == STATE_CLEANING:
|
if self._state.state == STATE_CLEANING:
|
||||||
self.robot.pause_cleaning()
|
self.robot.pause_cleaning()
|
||||||
self._clean_state = STATE_RETURNING
|
|
||||||
self.robot.send_to_base()
|
self.robot.send_to_base()
|
||||||
except NeatoRobotException as ex:
|
except NeatoRobotException as ex:
|
||||||
_LOGGER.error(
|
_LOGGER.error(
|
||||||
@ -339,7 +267,6 @@ class VorwerkConnectedVacuum(StateVacuumEntity):
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
self._clean_state = STATE_CLEANING
|
|
||||||
try:
|
try:
|
||||||
self.robot.start_cleaning(mode, navigation, category, boundary_id)
|
self.robot.start_cleaning(mode, navigation, category, boundary_id)
|
||||||
except NeatoRobotException as ex:
|
except NeatoRobotException as ex:
|
||||||
|
Loading…
Reference in New Issue
Block a user