Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """The roomba component."""
2 
3 import asyncio
4 import contextlib
5 from functools import partial
6 import logging
7 from typing import Any
8 
9 from roombapy import Roomba, RoombaConnectionError, RoombaFactory
10 
11 from homeassistant import exceptions
12 from homeassistant.config_entries import ConfigEntry
13 from homeassistant.const import (
14  CONF_DELAY,
15  CONF_HOST,
16  CONF_NAME,
17  CONF_PASSWORD,
18  EVENT_HOMEASSISTANT_STOP,
19 )
20 from homeassistant.core import HomeAssistant
21 
22 from .const import CONF_BLID, CONF_CONTINUOUS, DOMAIN, PLATFORMS, ROOMBA_SESSION
23 from .models import RoombaData
24 
25 _LOGGER = logging.getLogger(__name__)
26 
27 
28 async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
29  """Set the config entry up."""
30  # Set up roomba platforms with config entry
31 
32  if not config_entry.options:
33  hass.config_entries.async_update_entry(
34  config_entry,
35  options={
36  CONF_CONTINUOUS: config_entry.data[CONF_CONTINUOUS],
37  CONF_DELAY: config_entry.data[CONF_DELAY],
38  },
39  )
40 
41  roomba = await hass.async_add_executor_job(
42  partial(
43  RoombaFactory.create_roomba,
44  address=config_entry.data[CONF_HOST],
45  blid=config_entry.data[CONF_BLID],
46  password=config_entry.data[CONF_PASSWORD],
47  continuous=config_entry.options[CONF_CONTINUOUS],
48  delay=config_entry.options[CONF_DELAY],
49  )
50  )
51 
52  try:
53  if not await async_connect_or_timeout(hass, roomba):
54  return False
55  except CannotConnect as err:
56  raise exceptions.ConfigEntryNotReady from err
57 
58  async def _async_disconnect_roomba(event):
59  await async_disconnect_or_timeout(hass, roomba)
60 
61  config_entry.async_on_unload(
62  hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, _async_disconnect_roomba)
63  )
64 
65  domain_data = RoombaData(roomba, config_entry.data[CONF_BLID])
66  hass.data.setdefault(DOMAIN, {})[config_entry.entry_id] = domain_data
67 
68  await hass.config_entries.async_forward_entry_setups(config_entry, PLATFORMS)
69 
70  if not config_entry.update_listeners:
71  config_entry.add_update_listener(async_update_options)
72 
73  return True
74 
75 
77  hass: HomeAssistant, roomba: Roomba
78 ) -> dict[str, Any]:
79  """Connect to vacuum."""
80  try:
81  name = None
82  async with asyncio.timeout(10):
83  _LOGGER.debug("Initialize connection to vacuum")
84  await hass.async_add_executor_job(roomba.connect)
85  while not roomba.roomba_connected or name is None:
86  # Waiting for connection and check data is ready
87  name = roomba_reported_state(roomba).get("name", None)
88  if name:
89  break
90  await asyncio.sleep(1)
91  except RoombaConnectionError as err:
92  _LOGGER.debug("Error to connect to vacuum: %s", err)
93  raise CannotConnect from err
94  except TimeoutError as err:
95  # api looping if user or password incorrect and roomba exist
96  await async_disconnect_or_timeout(hass, roomba)
97  _LOGGER.debug("Timeout expired: %s", err)
98  raise CannotConnect from err
99 
100  return {ROOMBA_SESSION: roomba, CONF_NAME: name}
101 
102 
103 async def async_disconnect_or_timeout(hass: HomeAssistant, roomba: Roomba) -> None:
104  """Disconnect to vacuum."""
105  _LOGGER.debug("Disconnect vacuum")
106  with contextlib.suppress(TimeoutError):
107  async with asyncio.timeout(3):
108  await hass.async_add_executor_job(roomba.disconnect)
109 
110 
111 async def async_update_options(hass: HomeAssistant, config_entry: ConfigEntry) -> None:
112  """Update options."""
113  await hass.config_entries.async_reload(config_entry.entry_id)
114 
115 
116 async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool:
117  """Unload a config entry."""
118  unload_ok = await hass.config_entries.async_unload_platforms(
119  config_entry, PLATFORMS
120  )
121  if unload_ok:
122  domain_data: RoombaData = hass.data[DOMAIN][config_entry.entry_id]
123  await async_disconnect_or_timeout(hass, roomba=domain_data.roomba)
124  hass.data[DOMAIN].pop(config_entry.entry_id)
125 
126  return unload_ok
127 
128 
129 def roomba_reported_state(roomba: Roomba) -> dict[str, Any]:
130  """Roomba report."""
131  return roomba.master_state.get("state", {}).get("reported", {})
132 
133 
135  """Error to indicate we cannot connect."""
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
None async_update_options(HomeAssistant hass, ConfigEntry config_entry)
Definition: __init__.py:111
dict[str, Any] roomba_reported_state(Roomba roomba)
Definition: __init__.py:129
dict[str, Any] async_connect_or_timeout(HomeAssistant hass, Roomba roomba)
Definition: __init__.py:78
None async_disconnect_or_timeout(HomeAssistant hass, Roomba roomba)
Definition: __init__.py:103
bool async_unload_entry(HomeAssistant hass, ConfigEntry config_entry)
Definition: __init__.py:116
bool async_setup_entry(HomeAssistant hass, ConfigEntry config_entry)
Definition: __init__.py:28