get rid of sucks stuff to isolate custom component with its changes

This commit is contained in:
bittles
2022-12-14 01:51:22 -05:00
parent c3841c63ba
commit 9daaaf9040
19 changed files with 147 additions and 2906 deletions
+114
View File
@@ -0,0 +1,114 @@
"""Support for Ecovacs Deebot vacuums."""
import logging
import random
import string
from .sucksbumper import EcoVacsAPI, VacBot
import voluptuous as vol
from homeassistant.const import (
CONF_PASSWORD,
CONF_USERNAME,
CONF_VERIFY_SSL,
EVENT_HOMEASSISTANT_STOP,
Platform,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers import discovery
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.typing import ConfigType
_LOGGER = logging.getLogger(__name__)
DOMAIN = "ecovacs"
CONF_COUNTRY = "country"
CONF_CONTINENT = "continent"
CONF_BUMPER = "bumper"
CONF_BUMPER_SERVER = "bumper_server"
server_address = None
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.Optional(CONF_BUMPER, default=False): cv.boolean,
vol.Optional(CONF_BUMPER_SERVER): cv.string,
vol.Optional(CONF_VERIFY_SSL, default=True): cv.boolean,
}
)
},
extra=vol.ALLOW_EXTRA,
)
ECOVACS_DEVICES = "ecovacs_devices"
# Generate a random device ID on each bootup
ECOVACS_API_DEVICEID = "".join(
random.choice(string.ascii_uppercase + string.digits) for _ in range(8)
)
def setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the Ecovacs component."""
_LOGGER.debug("Creating new Ecovacs component")
hass.data[ECOVACS_DEVICES] = []
if CONF_BUMPER == True:
server_address = (config[DOMAIN].get(CONF_BUMPER_SERVER), 5223)
else:
server_address = None
ecovacs_api = EcoVacsAPI(
ECOVACS_API_DEVICEID,
config[DOMAIN].get(CONF_USERNAME),
EcoVacsAPI.md5(config[DOMAIN].get(CONF_PASSWORD)),
config[DOMAIN].get(CONF_COUNTRY),
config[DOMAIN].get(CONF_CONTINENT),
config[DOMAIN].get(CONF_VERIFY_SSL),
)
devices = ecovacs_api.devices()
_LOGGER.debug("Ecobot devices: %s", devices)
for device in devices:
_LOGGER.info(
"Discovered Ecovacs device on account: %s with nickname %s",
device.get("did"),
device.get("nick"),
)
vacbot = VacBot(
ecovacs_api.uid,
ecovacs_api.REALM,
ecovacs_api.resource,
ecovacs_api.user_access_token,
device,
config[DOMAIN].get(CONF_CONTINENT).lower(),
server_address,
config[DOMAIN].get(CONF_VERIFY_SSL),
monitor=True,
)
hass.data[ECOVACS_DEVICES].append(vacbot)
def stop(event: object) -> None:
"""Shut down open connections to Ecovacs XMPP server."""
for device in hass.data[ECOVACS_DEVICES]:
_LOGGER.info(
"Shutting down connection to Ecovacs device %s",
device.vacuum.get("did"),
)
device.disconnect()
# Listen for HA stop to disconnect.
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, stop)
if hass.data[ECOVACS_DEVICES]:
_LOGGER.debug("Starting vacuum components")
discovery.load_platform(hass, Platform.VACUUM, DOMAIN, {}, config)
return True
+10
View File
@@ -0,0 +1,10 @@
{
"domain": "ecovacs",
"name": "Ecovacs Bumper",
"version": "1.0.2",
"documentation": "https://www.home-assistant.io/integrations/ecovacs",
"requirements": ["sleekxmppfs>=1.3.4", "click>=6", "requests>=2.18", "pycryptodome>=3.4", "pycountry-convert>=0.5", "paho-mqtt>=1.4", "stringcase>=1.2"],
"codeowners": ["@OverloadUT", "@mib1185"],
"iot_class": "cloud_push",
"loggers": ["sleekxmppfs", "sucksbumper"]
}
+102
View File
@@ -0,0 +1,102 @@
# Describes the format for available vacuum services
turn_on:
name: Turn on
description: Start a new cleaning task.
target:
entity:
domain: vacuum
turn_off:
name: Turn off
description: Stop the current cleaning task and return to home.
target:
entity:
domain: vacuum
stop:
name: Stop
description: Stop the current cleaning task.
target:
entity:
domain: vacuum
locate:
name: Locate
description: Locate the vacuum cleaner robot.
target:
entity:
domain: vacuum
start_pause:
name: Start/Pause
description: Start, pause, or resume the cleaning task.
target:
entity:
domain: vacuum
start:
name: Start
description: Start or resume the cleaning task.
target:
entity:
domain: vacuum
pause:
name: Pause
description: Pause the cleaning task.
target:
entity:
domain: vacuum
return_to_base:
name: Return to base
description: Tell the vacuum cleaner to return to its dock.
target:
entity:
domain: vacuum
clean_spot:
name: Clean spot
description: Tell the vacuum cleaner to do a spot clean-up.
target:
entity:
domain: vacuum
send_command:
name: Send command
description: Send a raw command to the vacuum cleaner.
target:
entity:
domain: vacuum
fields:
command:
name: Command
description: Command to execute.
required: true
example: "set_dnd_timer"
selector:
text:
params:
name: Parameters
description: Parameters for the command.
example: '{ "key": "value" }'
selector:
object:
set_fan_speed:
name: Set fan speed
description: Set the fan speed of the vacuum cleaner.
target:
entity:
domain: vacuum
fields:
fan_speed:
name: Fan speed
description:
Platform dependent vacuum cleaner fan speed, with speed steps, like
'medium' or by percentage, between 0 and 100.
required: true
example: "low"
selector:
text:
File diff suppressed because it is too large Load Diff
+185
View File
@@ -0,0 +1,185 @@
"""Support for Ecovacs Ecovacs Vacuums."""
from __future__ import annotations
import logging
from typing import Any
from . import sucksbumper
from homeassistant.components.vacuum import VacuumEntity, VacuumEntityFeature
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.icon import icon_for_battery_level
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import ECOVACS_DEVICES
_LOGGER = logging.getLogger(__name__)
ATTR_ERROR = "error"
ATTR_COMPONENT_PREFIX = "component_"
def setup_platform(
hass: HomeAssistant,
config: ConfigType,
add_entities: AddEntitiesCallback,
discovery_info: DiscoveryInfoType | None = None,
) -> None:
"""Set up the Ecovacs vacuums."""
vacuums = []
for device in hass.data[ECOVACS_DEVICES]:
vacuums.append(EcovacsVacuum(device))
_LOGGER.debug("Adding Ecovacs Vacuums to Home Assistant: %s", vacuums)
add_entities(vacuums, True)
class EcovacsVacuum(VacuumEntity):
"""Ecovacs Vacuums such as Deebot."""
_attr_fan_speed_list = [sucksbumper.FAN_SPEED_NORMAL, sucksbumper.FAN_SPEED_HIGH]
_attr_should_poll = False
_attr_supported_features = (
VacuumEntityFeature.BATTERY
| VacuumEntityFeature.RETURN_HOME
| VacuumEntityFeature.CLEAN_SPOT
| VacuumEntityFeature.STOP
| VacuumEntityFeature.TURN_OFF
| VacuumEntityFeature.TURN_ON
| VacuumEntityFeature.LOCATE
| VacuumEntityFeature.STATUS
| VacuumEntityFeature.SEND_COMMAND
| VacuumEntityFeature.FAN_SPEED
)
def __init__(self, device: sucksbumper.VacBot) -> None:
"""Initialize the Ecovacs Vacuum."""
self.device = device
self.device.connect_and_wait_until_ready()
if self.device.vacuum.get("nick") is not None:
self._attr_name = str(self.device.vacuum["nick"])
else:
# In case there is no nickname defined, use the device id
self._attr_name = str(format(self.device.vacuum["did"]))
self._error = None
_LOGGER.debug("Vacuum initialized: %s", self.name)
async def async_added_to_hass(self) -> None:
"""Set up the event listeners now that hass is ready."""
self.device.statusEvents.subscribe(lambda _: self.schedule_update_ha_state())
self.device.batteryEvents.subscribe(lambda _: self.schedule_update_ha_state())
self.device.lifespanEvents.subscribe(lambda _: self.schedule_update_ha_state())
self.device.errorEvents.subscribe(self.on_error)
def on_error(self, error):
"""Handle an error event from the robot.
This will not change the entity's state. If the error caused the state
to change, that will come through as a separate on_status event
"""
if error == "no_error":
self._error = None
else:
self._error = error
self.hass.bus.fire(
"ecovacs_error", {"entity_id": self.entity_id, "error": error}
)
self.schedule_update_ha_state()
@property
def unique_id(self) -> str:
"""Return an unique ID."""
return self.device.vacuum.get("did")
@property
def is_on(self) -> bool:
"""Return true if vacuum is currently cleaning."""
return self.device.is_cleaning
@property
def is_charging(self) -> bool:
"""Return true if vacuum is currently charging."""
return self.device.is_charging
@property
def status(self) -> str | None:
"""Return the status of the vacuum cleaner."""
return self.device.vacuum_status
def return_to_base(self, **kwargs: Any) -> None:
"""Set the vacuum cleaner to return to the dock."""
self.device.run(sucksbumper.Charge())
@property
def battery_icon(self) -> str:
"""Return the battery icon for the vacuum cleaner."""
return icon_for_battery_level(
battery_level=self.battery_level, charging=self.is_charging
)
@property
def battery_level(self) -> int | None:
"""Return the battery level of the vacuum cleaner."""
if self.device.battery_status is not None:
return self.device.battery_status * 100
return super().battery_level
@property
def fan_speed(self) -> str | None:
"""Return the fan speed of the vacuum cleaner."""
return self.device.fan_speed
def turn_on(self, **kwargs: Any) -> None:
"""Turn the vacuum on and start cleaning."""
self.device.run(sucksbumper.Clean())
def turn_off(self, **kwargs: Any) -> None:
"""Turn the vacuum off stopping the cleaning and returning home."""
self.return_to_base()
def stop(self, **kwargs: Any) -> None:
"""Stop the vacuum cleaner."""
self.device.run(sucksbumper.Stop())
def clean_spot(self, **kwargs: Any) -> None:
"""Perform a spot clean-up."""
self.device.run(sucksbumper.Spot())
def locate(self, **kwargs: Any) -> None:
"""Locate the vacuum cleaner."""
self.device.run(sucksbumper.PlaySound())
def set_fan_speed(self, fan_speed: str, **kwargs: Any) -> None:
"""Set fan speed."""
if self.is_on:
self.device.run(sucksbumper.Clean(mode=self.device.clean_status, speed=fan_speed))
def send_command(
self,
command: str,
params: dict[str, Any] | list[Any] | None = None,
**kwargs: Any,
) -> None:
"""Send a command to a vacuum cleaner."""
self.device.run(sucksbumper.VacBotCommand(command, params))
@property
def extra_state_attributes(self) -> dict[str, Any]:
"""Return the device-specific state attributes of this vacuum."""
data: dict[str, Any] = {}
data[ATTR_ERROR] = self._error
for key, val in self.device.components.items():
attr_name = ATTR_COMPONENT_PREFIX + key
data[attr_name] = int(val * 100)
return data