Update HA, add vacuum, grid cards, fixes
这个提交包含在:
119
custom_components/deebot/__init__.py
普通文件
119
custom_components/deebot/__init__.py
普通文件
@@ -0,0 +1,119 @@
|
||||
"""Support for Deebot Vaccums."""
|
||||
import asyncio
|
||||
import logging
|
||||
import async_timeout
|
||||
import time
|
||||
import random
|
||||
import string
|
||||
import base64
|
||||
import voluptuous as vol
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from datetime import timedelta
|
||||
from deebotozmo import *
|
||||
from homeassistant.util import Throttle
|
||||
from homeassistant.helpers import discovery
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, EVENT_HOMEASSISTANT_STOP
|
||||
|
||||
REQUIREMENTS = ['deebotozmo==1.7.8']
|
||||
|
||||
CONF_COUNTRY = "country"
|
||||
CONF_CONTINENT = "continent"
|
||||
CONF_DEVICEID = "deviceid"
|
||||
CONF_LIVEMAPPATH = "livemappath"
|
||||
CONF_LIVEMAP = "live_map"
|
||||
CONF_SHOWCOLORROOMS = "show_color_rooms"
|
||||
DEEBOT_DEVICES = "deebot_devices"
|
||||
|
||||
# Generate a random device ID on each bootup
|
||||
DEEBOT_API_DEVICEID = "".join(
|
||||
random.choice(string.ascii_uppercase + string.digits) for _ in range(8)
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
HUB = None
|
||||
DOMAIN = 'deebot'
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
DOMAIN: vol.Schema({
|
||||
vol.Required(CONF_USERNAME): cv.string,
|
||||
vol.Required(CONF_PASSWORD): cv.string,
|
||||
vol.Required(CONF_COUNTRY): vol.All(vol.Lower, cv.string),
|
||||
vol.Required(CONF_CONTINENT): vol.All(vol.Lower, cv.string),
|
||||
vol.Required(CONF_DEVICEID): vol.All(cv.ensure_list, [cv.string]),
|
||||
vol.Optional(CONF_LIVEMAP, default=True): cv.boolean,
|
||||
vol.Optional(CONF_SHOWCOLORROOMS, default=False): cv.boolean,
|
||||
vol.Optional(CONF_LIVEMAPPATH, default='www/'): cv.string
|
||||
}),
|
||||
}, extra=vol.ALLOW_EXTRA)
|
||||
|
||||
def setup(hass, config):
|
||||
"""Set up the Deebot."""
|
||||
global HUB
|
||||
|
||||
HUB = DeebotHub(config[DOMAIN])
|
||||
|
||||
for component in ('sensor', 'binary_sensor', 'vacuum'):
|
||||
discovery.load_platform(hass, component, DOMAIN, {}, config)
|
||||
|
||||
return True
|
||||
|
||||
class DeebotHub(Entity):
|
||||
"""Deebot Hub"""
|
||||
|
||||
def __init__(self, domain_config):
|
||||
"""Initialize the Deebot Vacuum."""
|
||||
|
||||
self.config = domain_config
|
||||
self._lock = threading.Lock()
|
||||
|
||||
self.ecovacs_api = EcoVacsAPI(
|
||||
DEEBOT_API_DEVICEID,
|
||||
domain_config.get(CONF_USERNAME),
|
||||
EcoVacsAPI.md5(domain_config.get(CONF_PASSWORD)),
|
||||
domain_config.get(CONF_COUNTRY),
|
||||
domain_config.get(CONF_CONTINENT)
|
||||
)
|
||||
|
||||
devices = self.ecovacs_api.devices()
|
||||
liveMapEnabled = domain_config.get(CONF_LIVEMAP)
|
||||
liveMapRooms = domain_config.get(CONF_SHOWCOLORROOMS)
|
||||
country = domain_config.get(CONF_COUNTRY).lower()
|
||||
continent = domain_config.get(CONF_CONTINENT).lower()
|
||||
self.vacbots = []
|
||||
|
||||
# CREATE VACBOT FOR EACH DEVICE
|
||||
for device in devices:
|
||||
if device['name'] in domain_config.get(CONF_DEVICEID):
|
||||
vacbot = VacBot(
|
||||
self.ecovacs_api.uid,
|
||||
self.ecovacs_api.resource,
|
||||
self.ecovacs_api.user_access_token,
|
||||
device,
|
||||
country,
|
||||
continent,
|
||||
liveMapEnabled,
|
||||
liveMapRooms
|
||||
)
|
||||
|
||||
_LOGGER.debug("New vacbot found: " + device['name'])
|
||||
|
||||
self.vacbots.append(vacbot)
|
||||
|
||||
_LOGGER.debug("Hub initialized")
|
||||
|
||||
@Throttle(timedelta(seconds=10))
|
||||
def update(self):
|
||||
""" Update all statuses. """
|
||||
try:
|
||||
for vacbot in self.vacbots:
|
||||
vacbot.request_all_statuses()
|
||||
except Exception as ex:
|
||||
_LOGGER.error('Update failed: %s', ex)
|
||||
raise
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
""" Return the name of the hub."""
|
||||
return "Deebot Hub"
|
||||
二进制文件未显示。
二进制文件未显示。
二进制文件未显示。
二进制文件未显示。
@@ -0,0 +1,48 @@
|
||||
"""Support for Deebot Sensor."""
|
||||
from typing import Optional
|
||||
|
||||
from deebotozmo import *
|
||||
from homeassistant.components.binary_sensor import BinarySensorEntity
|
||||
|
||||
from . import HUB as hub
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
"""Set up the Deebot binary sensor platform."""
|
||||
hub.update()
|
||||
|
||||
for vacbot in hub.vacbots:
|
||||
add_devices([DeebotMopAttachedBinarySensor(vacbot, "mop_attached")], True)
|
||||
|
||||
|
||||
class DeebotMopAttachedBinarySensor(BinarySensorEntity):
|
||||
"""Deebot mop attached binary sensor"""
|
||||
|
||||
def __init__(self, vacbot: VacBot, device_id: str):
|
||||
"""Initialize the Sensor."""
|
||||
self._vacbot = vacbot
|
||||
self._id = device_id
|
||||
|
||||
if self._vacbot.vacuum.get("nick", None) is not None:
|
||||
self._vacbot_name = "{}".format(self._vacbot.vacuum["nick"])
|
||||
else:
|
||||
# In case there is no nickname defined, use the device id
|
||||
self._vacbot_name = "{}".format(self._vacbot.vacuum["did"])
|
||||
|
||||
self._name = self._vacbot_name + "_" + device_id
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the device."""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
return self._vacbot.mop_attached
|
||||
|
||||
@property
|
||||
def icon(self) -> Optional[str]:
|
||||
"""Return the icon to use in the frontend, if any."""
|
||||
return "mdi:water" if self.is_on else "mdi:water-off"
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"domain": "deebot",
|
||||
"name": "Deebot for Hassio",
|
||||
"documentation": "https://github.com/And3rsL/Deebot-for-hassio",
|
||||
"requirements": [
|
||||
"deebotozmo==1.7.8"
|
||||
],
|
||||
"dependencies": [],
|
||||
"codeowners": ["@And3rsL"],
|
||||
"homeassistant": "0.110.0"
|
||||
}
|
||||
179
custom_components/deebot/sensor.py
普通文件
179
custom_components/deebot/sensor.py
普通文件
@@ -0,0 +1,179 @@
|
||||
"""Support for Deebot Sensor."""
|
||||
from typing import Optional
|
||||
|
||||
from deebotozmo import *
|
||||
from homeassistant.const import (STATE_UNKNOWN)
|
||||
from homeassistant.helpers.entity import Entity
|
||||
|
||||
from . import HUB as hub
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
from homeassistant.components.vacuum import (
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_ERROR,
|
||||
STATE_IDLE,
|
||||
STATE_PAUSED,
|
||||
STATE_RETURNING,
|
||||
)
|
||||
|
||||
STATE_CODE_TO_STATE = {
|
||||
'STATE_IDLE': STATE_IDLE,
|
||||
'STATE_CLEANING': STATE_CLEANING,
|
||||
'STATE_RETURNING': STATE_RETURNING,
|
||||
'STATE_DOCKED': STATE_DOCKED,
|
||||
'STATE_ERROR': STATE_ERROR,
|
||||
'STATE_PAUSED': STATE_PAUSED,
|
||||
}
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
"""Set up the Deebot sensor."""
|
||||
hub.update()
|
||||
|
||||
for vacbot in hub.vacbots:
|
||||
# General
|
||||
add_devices([DeebotLastCleanImageSensor(vacbot, "last_clean_image")], True)
|
||||
add_devices([DeebotWaterLevelSensor(vacbot, "water_level")], True)
|
||||
|
||||
# Components
|
||||
add_devices([DeebotComponentSensor(vacbot, COMPONENT_MAIN_BRUSH)], True)
|
||||
add_devices([DeebotComponentSensor(vacbot, COMPONENT_SIDE_BRUSH)], True)
|
||||
add_devices([DeebotComponentSensor(vacbot, COMPONENT_FILTER)], True)
|
||||
|
||||
# Stats
|
||||
add_devices([DeebotStatsSensor(vacbot, "stats_area")], True)
|
||||
add_devices([DeebotStatsSensor(vacbot, "stats_time")], True)
|
||||
add_devices([DeebotStatsSensor(vacbot, "stats_type")], True)
|
||||
|
||||
|
||||
class DeebotBaseSensor(Entity):
|
||||
"""Deebot base sensor"""
|
||||
|
||||
def __init__(self, vacbot, device_id):
|
||||
"""Initialize the Sensor."""
|
||||
|
||||
self._state = STATE_UNKNOWN
|
||||
self._vacbot = vacbot
|
||||
self._id = device_id
|
||||
|
||||
if self._vacbot.vacuum.get("nick", None) is not None:
|
||||
self._vacbot_name = "{}".format(self._vacbot.vacuum["nick"])
|
||||
else:
|
||||
# In case there is no nickname defined, use the device id
|
||||
self._vacbot_name = "{}".format(self._vacbot.vacuum["did"])
|
||||
|
||||
self._name = self._vacbot_name + "_" + device_id
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Return the name of the device."""
|
||||
return self._name
|
||||
|
||||
|
||||
class DeebotLastCleanImageSensor(DeebotBaseSensor):
|
||||
"""Deebot Sensor"""
|
||||
|
||||
def __init__(self, vacbot, device_id):
|
||||
"""Initialize the Sensor."""
|
||||
super(DeebotLastCleanImageSensor, self).__init__(vacbot, device_id)
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state of the vacuum cleaner."""
|
||||
if self._vacbot.last_clean_image is not None:
|
||||
return self._vacbot.last_clean_image
|
||||
|
||||
@property
|
||||
def icon(self) -> Optional[str]:
|
||||
"""Return the icon to use in the frontend, if any."""
|
||||
return "mdi:image-search"
|
||||
|
||||
|
||||
class DeebotWaterLevelSensor(DeebotBaseSensor):
|
||||
"""Deebot Sensor"""
|
||||
|
||||
def __init__(self, vacbot, device_id):
|
||||
"""Initialize the Sensor."""
|
||||
super(DeebotWaterLevelSensor, self).__init__(vacbot, device_id)
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state of the vacuum cleaner."""
|
||||
|
||||
if self._vacbot.water_level is not None:
|
||||
return self._vacbot.water_level
|
||||
|
||||
@property
|
||||
def icon(self) -> Optional[str]:
|
||||
"""Return the icon to use in the frontend, if any."""
|
||||
return "mdi:water"
|
||||
|
||||
|
||||
class DeebotComponentSensor(DeebotBaseSensor):
|
||||
"""Deebot Sensor"""
|
||||
|
||||
def __init__(self, vacbot, device_id):
|
||||
"""Initialize the Sensor."""
|
||||
super(DeebotComponentSensor, self).__init__(vacbot, device_id)
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self):
|
||||
"""Return the unit of measurement."""
|
||||
return '%'
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state of the vacuum cleaner."""
|
||||
|
||||
for key, val in self._vacbot.components.items():
|
||||
if key == self._id:
|
||||
return int(val)
|
||||
|
||||
@property
|
||||
def icon(self) -> Optional[str]:
|
||||
"""Return the icon to use in the frontend, if any."""
|
||||
if self._id == COMPONENT_MAIN_BRUSH or self._id == COMPONENT_SIDE_BRUSH:
|
||||
return "mdi:broom"
|
||||
elif self._id == COMPONENT_FILTER:
|
||||
return "mdi:air-filter"
|
||||
|
||||
|
||||
class DeebotStatsSensor(DeebotBaseSensor):
|
||||
"""Deebot Sensor"""
|
||||
|
||||
def __init__(self, vacbot, device_id):
|
||||
"""Initialize the Sensor."""
|
||||
super(DeebotStatsSensor, self).__init__(vacbot, device_id)
|
||||
|
||||
@property
|
||||
def unit_of_measurement(self):
|
||||
"""Return the unit of measurement."""
|
||||
if self._id == 'stats_area':
|
||||
return "mq"
|
||||
elif self._id == 'stats_time':
|
||||
return "min"
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state of the vacuum cleaner."""
|
||||
|
||||
if self._id == 'stats_area' and self._vacbot.stats_area is not None:
|
||||
return int(self._vacbot.stats_area)
|
||||
elif self._id == 'stats_time' and self._vacbot.stats_time is not None:
|
||||
return int(self._vacbot.stats_time/60)
|
||||
elif self._id == 'stats_type':
|
||||
return self._vacbot.stats_type
|
||||
else:
|
||||
return STATE_UNKNOWN
|
||||
|
||||
@property
|
||||
def icon(self) -> Optional[str]:
|
||||
"""Return the icon to use in the frontend, if any."""
|
||||
if self._id == 'stats_area':
|
||||
return "mdi:floor-plan"
|
||||
elif self._id == 'stats_time':
|
||||
return "mdi:timer-outline"
|
||||
elif self._id == 'stats_type':
|
||||
return "mdi:cog"
|
||||
247
custom_components/deebot/vacuum.py
普通文件
247
custom_components/deebot/vacuum.py
普通文件
@@ -0,0 +1,247 @@
|
||||
"""Support for Deebot Vaccums."""
|
||||
import base64
|
||||
from typing import Optional, Dict, Any, Union, List
|
||||
|
||||
from deebotozmo import *
|
||||
from homeassistant.util import slugify
|
||||
|
||||
from . import HUB as hub
|
||||
|
||||
CONF_COUNTRY = "country"
|
||||
CONF_CONTINENT = "continent"
|
||||
CONF_DEVICEID = "deviceid"
|
||||
CONF_LIVEMAPPATH = "livemappath"
|
||||
CONF_LIVEMAP = "live_map"
|
||||
CONF_SHOWCOLORROOMS = "show_color_rooms"
|
||||
DEEBOT_DEVICES = "deebot_devices"
|
||||
|
||||
from homeassistant.components.vacuum import (
|
||||
PLATFORM_SCHEMA,
|
||||
STATE_CLEANING,
|
||||
STATE_DOCKED,
|
||||
STATE_ERROR,
|
||||
STATE_IDLE,
|
||||
STATE_PAUSED,
|
||||
STATE_RETURNING,
|
||||
SUPPORT_BATTERY,
|
||||
SUPPORT_FAN_SPEED,
|
||||
SUPPORT_LOCATE,
|
||||
SUPPORT_PAUSE,
|
||||
SUPPORT_RETURN_HOME,
|
||||
SUPPORT_SEND_COMMAND,
|
||||
SUPPORT_START,
|
||||
SUPPORT_STATE,
|
||||
VacuumEntity,
|
||||
)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
SUPPORT_DEEBOT = (
|
||||
SUPPORT_BATTERY
|
||||
| SUPPORT_FAN_SPEED
|
||||
| SUPPORT_LOCATE
|
||||
| SUPPORT_PAUSE
|
||||
| SUPPORT_RETURN_HOME
|
||||
| SUPPORT_SEND_COMMAND
|
||||
| SUPPORT_START
|
||||
| SUPPORT_STATE
|
||||
)
|
||||
|
||||
STATE_CODE_TO_STATE = {
|
||||
'STATE_IDLE': STATE_IDLE,
|
||||
'STATE_CLEANING': STATE_CLEANING,
|
||||
'STATE_RETURNING': STATE_RETURNING,
|
||||
'STATE_DOCKED': STATE_DOCKED,
|
||||
'STATE_ERROR': STATE_ERROR,
|
||||
'STATE_PAUSED': STATE_PAUSED,
|
||||
}
|
||||
|
||||
ATTR_COMPONENT_PREFIX = "component_"
|
||||
|
||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
"""Set up the Deebot vacuums."""
|
||||
if DEEBOT_DEVICES not in hass.data:
|
||||
hass.data[DEEBOT_DEVICES] = []
|
||||
|
||||
for vacbot in hub.vacbots:
|
||||
vacuum = DeebotVacuum(hass, vacbot)
|
||||
add_devices([vacuum])
|
||||
|
||||
class DeebotVacuum(VacuumEntity):
|
||||
"""Deebot Vacuums"""
|
||||
|
||||
def __init__(self, hass, vacbot):
|
||||
"""Initialize the Deebot Vacuum."""
|
||||
self._hass = hass
|
||||
|
||||
self.device = vacbot
|
||||
|
||||
if self.device.vacuum.get("nick", None) is not None:
|
||||
self._name = "{}".format(self.device.vacuum["nick"])
|
||||
else:
|
||||
# In case there is no nickname defined, use the device id
|
||||
self._name = "{}".format(self.device.vacuum["did"])
|
||||
|
||||
self._fan_speed = None
|
||||
self._live_map = None
|
||||
self._live_map_path = hub.config.get(CONF_LIVEMAPPATH) + self._name + '_liveMap.png'
|
||||
|
||||
self.device.refresh_statuses()
|
||||
|
||||
_LOGGER.debug("Vacuum initialized: %s", self.name)
|
||||
|
||||
def on_fan_change(self, fan_speed):
|
||||
self._fan_speed = fan_speed
|
||||
|
||||
@property
|
||||
def should_poll(self) -> bool:
|
||||
"""Return True if entity has to be polled for state."""
|
||||
return True
|
||||
|
||||
@property
|
||||
def unique_id(self) -> str:
|
||||
"""Return an unique ID."""
|
||||
return self.device.vacuum.get("did", None)
|
||||
|
||||
@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_DEEBOT
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
"""Return the state of the vacuum cleaner."""
|
||||
if self.device.vacuum_status is not None and self.device.is_available == True:
|
||||
return STATE_CODE_TO_STATE[self.device.vacuum_status]
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
"""Return True if entity is available."""
|
||||
return self.device.is_available
|
||||
|
||||
async def async_return_to_base(self, **kwargs):
|
||||
"""Set the vacuum cleaner to return to the dock."""
|
||||
await self.hass.async_add_executor_job(self.device.Charge)
|
||||
|
||||
@property
|
||||
def battery_level(self):
|
||||
"""Return the battery level of the vacuum cleaner."""
|
||||
if self.device.battery_status is not None:
|
||||
return self.device.battery_status
|
||||
|
||||
return super().battery_level
|
||||
|
||||
@property
|
||||
def fan_speed(self):
|
||||
"""Return the fan speed of the vacuum cleaner."""
|
||||
return self.device.fan_speed
|
||||
|
||||
async def async_set_fan_speed(self, fan_speed, **kwargs):
|
||||
await self.hass.async_add_executor_job(self.device.SetFanSpeed, fan_speed)
|
||||
|
||||
@property
|
||||
def fan_speed_list(self):
|
||||
"""Get the list of available fan speed steps of the vacuum cleaner."""
|
||||
return [FAN_SPEED_QUIET, FAN_SPEED_NORMAL, FAN_SPEED_MAX, FAN_SPEED_MAXPLUS]
|
||||
|
||||
async def async_pause(self):
|
||||
"""Pause the vacuum cleaner."""
|
||||
await self.hass.async_add_executor_job(self.device.CleanPause)
|
||||
|
||||
async def async_start(self):
|
||||
"""Start the vacuum cleaner."""
|
||||
await self.hass.async_add_executor_job(self.device.CleanResume)
|
||||
|
||||
async def async_locate(self, **kwargs):
|
||||
"""Locate the vacuum cleaner."""
|
||||
await self.hass.async_add_executor_job(self.device.PlaySound)
|
||||
|
||||
async def async_send_command(self, command, params=None, **kwargs):
|
||||
"""Send a command to a vacuum cleaner."""
|
||||
_LOGGER.debug("async_send_command %s (%s), %s", command, params, kwargs)
|
||||
|
||||
if command == 'spot_area':
|
||||
await self.hass.async_add_executor_job(self.device.SpotArea, params['rooms'], params['cleanings'])
|
||||
return
|
||||
|
||||
if command == 'custom_area':
|
||||
await self.hass.async_add_executor_job(self.device.CustomArea, params['coordinates'], params['cleanings'])
|
||||
return
|
||||
|
||||
if command == 'set_water':
|
||||
await self.hass.async_add_executor_job(self.device.SetWaterLevel, params['amount'])
|
||||
return
|
||||
|
||||
if command == 'relocate':
|
||||
await self.hass.async_add_executor_job(self.device.Relocate)
|
||||
return
|
||||
|
||||
if command == 'auto_clean':
|
||||
self.hass.async_add_executor_job(self.device.Clean, params['type'])
|
||||
return
|
||||
|
||||
if command == 'refresh_components':
|
||||
await self.hass.async_add_executor_job(self.device.refresh_components)
|
||||
return
|
||||
|
||||
if command == 'refresh_statuses':
|
||||
await self.hass.async_add_executor_job(self.device.refresh_statuses)
|
||||
return
|
||||
|
||||
if command == 'refresh_live_map':
|
||||
await self.hass.async_add_executor_job(self.device.refresh_liveMap)
|
||||
return
|
||||
|
||||
if command == 'save_live_map':
|
||||
if(self._live_map != self.device.live_map):
|
||||
self._live_map = self.device.live_map
|
||||
with open(params['path'], "wb") as fh:
|
||||
fh.write(base64.decodebytes(self.device.live_map))
|
||||
|
||||
await self.hass.async_add_executor_job(self.device.exc_command, command, params)
|
||||
|
||||
async def async_update(self):
|
||||
"""Fetch state from the device."""
|
||||
await self.hass.async_add_executor_job(self.device.request_all_statuses)
|
||||
|
||||
try:
|
||||
if(self._live_map != self.device.live_map):
|
||||
self._live_map = self.device.live_map
|
||||
with open(self._live_map_path, "wb") as fh:
|
||||
fh.write(base64.decodebytes(self.device.live_map))
|
||||
except KeyError:
|
||||
_LOGGER.warning("Can't access local folder: %s", self._live_map_path)
|
||||
|
||||
@property
|
||||
def device_state_attributes(self) -> Optional[Dict[str, Any]]:
|
||||
"""Return device specific state attributes.
|
||||
|
||||
Implemented by platform classes. Convention for attribute names
|
||||
is lowercase snake_case.
|
||||
"""
|
||||
|
||||
data: Dict[str, Union[int, List[int]]] = {}
|
||||
|
||||
# Needed for custom vacuum-card (https://github.com/denysdovhan/vacuum-card)
|
||||
# Should find a better way without breaking everyone rooms script
|
||||
data['status'] = STATE_CODE_TO_STATE[self.device.vacuum_status]
|
||||
|
||||
if self.device.getSavedRooms() is not None:
|
||||
for r in self.device.getSavedRooms():
|
||||
# convert room name to snake_case to meet the convention
|
||||
room_name = "room_" + slugify(r["subtype"])
|
||||
room_values = data.get(room_name)
|
||||
if room_values is None:
|
||||
data[room_name] = r["id"]
|
||||
elif isinstance(room_values, list):
|
||||
room_values.append(r["id"])
|
||||
else:
|
||||
# Convert from int to list
|
||||
data[room_name] = [room_values, r["id"]]
|
||||
|
||||
return data
|
||||
在新工单中引用
屏蔽一个用户