-
-
Notifications
You must be signed in to change notification settings - Fork 37k
Expand file tree
/
Copy path__init__.py
More file actions
132 lines (104 loc) · 4.2 KB
/
__init__.py
File metadata and controls
132 lines (104 loc) · 4.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
"""The Gardena Bluetooth integration."""
from __future__ import annotations
import asyncio
import logging
from bleak.backends.device import BLEDevice
from gardena_bluetooth.client import CachedConnection, Client
from gardena_bluetooth.const import AquaContour, DeviceConfiguration, DeviceInformation
from gardena_bluetooth.exceptions import (
CharacteristicNoAccess,
CharacteristicNotFound,
CommunicationFailure,
)
from gardena_bluetooth.parse import CharacteristicTime
from homeassistant.components import bluetooth
from homeassistant.const import CONF_ADDRESS, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.util import dt as dt_util
from .const import DOMAIN
from .coordinator import (
DeviceUnavailable,
GardenaBluetoothConfigEntry,
GardenaBluetoothCoordinator,
)
from .util import async_get_product_type
PLATFORMS: list[Platform] = [
Platform.BINARY_SENSOR,
Platform.BUTTON,
Platform.NUMBER,
Platform.SELECT,
Platform.SENSOR,
Platform.SWITCH,
Platform.VALVE,
]
LOGGER = logging.getLogger(__name__)
TIMEOUT = 20.0
DISCONNECT_DELAY = 5
def get_connection(hass: HomeAssistant, address: str) -> CachedConnection:
"""Set up a cached client that keeps connection after last use."""
def _device_lookup() -> BLEDevice:
device = bluetooth.async_ble_device_from_address(
hass, address, connectable=True
)
if not device:
raise DeviceUnavailable("Unable to find device")
return device
return CachedConnection(DISCONNECT_DELAY, _device_lookup)
async def _update_timestamp(client: Client, characteristics: CharacteristicTime):
try:
await client.update_timestamp(characteristics, dt_util.now())
except CharacteristicNotFound:
pass
except CharacteristicNoAccess:
LOGGER.debug("No access to update internal time")
async def async_setup_entry(
hass: HomeAssistant, entry: GardenaBluetoothConfigEntry
) -> bool:
"""Set up Gardena Bluetooth from a config entry."""
address = entry.data[CONF_ADDRESS]
try:
async with asyncio.timeout(TIMEOUT):
product_type = await async_get_product_type(hass, address)
except TimeoutError as exception:
raise ConfigEntryNotReady("Unable to find product type") from exception
client = Client(get_connection(hass, address), product_type)
try:
chars = await client.get_all_characteristics()
sw_version = await client.read_char(DeviceInformation.firmware_version, None)
manufacturer = await client.read_char(DeviceInformation.manufacturer_name, None)
model = await client.read_char(DeviceInformation.model_number, None)
name = entry.title
name = await client.read_char(DeviceConfiguration.custom_device_name, name)
name = await client.read_char(AquaContour.custom_device_name, name)
await _update_timestamp(client, DeviceConfiguration.unix_timestamp)
await _update_timestamp(client, AquaContour.unix_timestamp)
except (TimeoutError, CommunicationFailure, DeviceUnavailable) as exception:
await client.disconnect()
raise ConfigEntryNotReady(
f"Unable to connect to device {address} due to {exception}"
) from exception
device = DeviceInfo(
identifiers={(DOMAIN, address)},
connections={(dr.CONNECTION_BLUETOOTH, address)},
name=name,
sw_version=sw_version,
manufacturer=manufacturer,
model=model,
)
coordinator = GardenaBluetoothCoordinator(
hass, entry, LOGGER, client, set(chars.keys()), device, address
)
entry.runtime_data = coordinator
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
await coordinator.async_refresh()
return True
async def async_unload_entry(
hass: HomeAssistant, entry: GardenaBluetoothConfigEntry
) -> bool:
"""Unload a config entry."""
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
await entry.runtime_data.async_shutdown()
return unload_ok