mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Update PySwitchbot to improve connection reliability (#75692)
This commit is contained in:
parent
c9ae409d9a
commit
d890598da7
@ -1,9 +1,6 @@
|
|||||||
"""Support for Switchbot devices."""
|
"""Support for Switchbot devices."""
|
||||||
|
|
||||||
from collections.abc import Mapping
|
|
||||||
import logging
|
import logging
|
||||||
from types import MappingProxyType
|
|
||||||
from typing import Any
|
|
||||||
|
|
||||||
import switchbot
|
import switchbot
|
||||||
|
|
||||||
@ -24,11 +21,8 @@ from .const import (
|
|||||||
ATTR_BOT,
|
ATTR_BOT,
|
||||||
ATTR_CURTAIN,
|
ATTR_CURTAIN,
|
||||||
ATTR_HYGROMETER,
|
ATTR_HYGROMETER,
|
||||||
COMMON_OPTIONS,
|
|
||||||
CONF_RETRY_COUNT,
|
CONF_RETRY_COUNT,
|
||||||
CONF_RETRY_TIMEOUT,
|
|
||||||
DEFAULT_RETRY_COUNT,
|
DEFAULT_RETRY_COUNT,
|
||||||
DEFAULT_RETRY_TIMEOUT,
|
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
)
|
)
|
||||||
from .coordinator import SwitchbotDataUpdateCoordinator
|
from .coordinator import SwitchbotDataUpdateCoordinator
|
||||||
@ -49,8 +43,6 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
"""Set up Switchbot from a config entry."""
|
"""Set up Switchbot from a config entry."""
|
||||||
hass.data.setdefault(DOMAIN, {})
|
hass.data.setdefault(DOMAIN, {})
|
||||||
domain_data = hass.data[DOMAIN]
|
|
||||||
|
|
||||||
if CONF_ADDRESS not in entry.data and CONF_MAC in entry.data:
|
if CONF_ADDRESS not in entry.data and CONF_MAC in entry.data:
|
||||||
# Bleak uses addresses not mac addresses which are are actually
|
# Bleak uses addresses not mac addresses which are are actually
|
||||||
# UUIDs on some platforms (MacOS).
|
# UUIDs on some platforms (MacOS).
|
||||||
@ -65,10 +57,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
if not entry.options:
|
if not entry.options:
|
||||||
hass.config_entries.async_update_entry(
|
hass.config_entries.async_update_entry(
|
||||||
entry,
|
entry,
|
||||||
options={
|
options={CONF_RETRY_COUNT: DEFAULT_RETRY_COUNT},
|
||||||
CONF_RETRY_COUNT: DEFAULT_RETRY_COUNT,
|
|
||||||
CONF_RETRY_TIMEOUT: DEFAULT_RETRY_TIMEOUT,
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
|
|
||||||
sensor_type: str = entry.data[CONF_SENSOR_TYPE]
|
sensor_type: str = entry.data[CONF_SENSOR_TYPE]
|
||||||
@ -78,13 +67,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
raise ConfigEntryNotReady(
|
raise ConfigEntryNotReady(
|
||||||
f"Could not find Switchbot {sensor_type} with address {address}"
|
f"Could not find Switchbot {sensor_type} with address {address}"
|
||||||
)
|
)
|
||||||
|
|
||||||
if COMMON_OPTIONS not in domain_data:
|
|
||||||
domain_data[COMMON_OPTIONS] = entry.options
|
|
||||||
|
|
||||||
common_options: Mapping[str, int] = domain_data[COMMON_OPTIONS]
|
|
||||||
switchbot.DEFAULT_RETRY_TIMEOUT = common_options[CONF_RETRY_TIMEOUT]
|
|
||||||
|
|
||||||
cls = CLASS_BY_DEVICE.get(sensor_type, switchbot.SwitchbotDevice)
|
cls = CLASS_BY_DEVICE.get(sensor_type, switchbot.SwitchbotDevice)
|
||||||
device = cls(
|
device = cls(
|
||||||
device=ble_device,
|
device=ble_device,
|
||||||
@ -92,7 +74,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
retry_count=entry.options[CONF_RETRY_COUNT],
|
retry_count=entry.options[CONF_RETRY_COUNT],
|
||||||
)
|
)
|
||||||
coordinator = hass.data[DOMAIN][entry.entry_id] = SwitchbotDataUpdateCoordinator(
|
coordinator = hass.data[DOMAIN][entry.entry_id] = SwitchbotDataUpdateCoordinator(
|
||||||
hass, _LOGGER, ble_device, device, common_options
|
hass, _LOGGER, ble_device, device
|
||||||
)
|
)
|
||||||
entry.async_on_unload(coordinator.async_start())
|
entry.async_on_unload(coordinator.async_start())
|
||||||
if not await coordinator.async_wait_ready():
|
if not await coordinator.async_wait_ready():
|
||||||
@ -106,6 +88,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
async def _async_update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
||||||
|
"""Handle options update."""
|
||||||
|
await hass.config_entries.async_reload(entry.entry_id)
|
||||||
|
|
||||||
|
|
||||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
||||||
"""Unload a config entry."""
|
"""Unload a config entry."""
|
||||||
sensor_type = entry.data[CONF_SENSOR_TYPE]
|
sensor_type = entry.data[CONF_SENSOR_TYPE]
|
||||||
@ -119,11 +106,3 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
hass.data.pop(DOMAIN)
|
hass.data.pop(DOMAIN)
|
||||||
|
|
||||||
return unload_ok
|
return unload_ok
|
||||||
|
|
||||||
|
|
||||||
async def _async_update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
|
||||||
"""Handle options update."""
|
|
||||||
# Update entity options stored in hass.
|
|
||||||
common_options: MappingProxyType[str, Any] = hass.data[DOMAIN][COMMON_OPTIONS]
|
|
||||||
if entry.options != common_options:
|
|
||||||
await hass.config_entries.async_reload(entry.entry_id)
|
|
||||||
|
@ -17,14 +17,7 @@ from homeassistant.core import callback
|
|||||||
from homeassistant.data_entry_flow import FlowResult
|
from homeassistant.data_entry_flow import FlowResult
|
||||||
from homeassistant.helpers.service_info.bluetooth import BluetoothServiceInfo
|
from homeassistant.helpers.service_info.bluetooth import BluetoothServiceInfo
|
||||||
|
|
||||||
from .const import (
|
from .const import CONF_RETRY_COUNT, DEFAULT_RETRY_COUNT, DOMAIN, SUPPORTED_MODEL_TYPES
|
||||||
CONF_RETRY_COUNT,
|
|
||||||
CONF_RETRY_TIMEOUT,
|
|
||||||
DEFAULT_RETRY_COUNT,
|
|
||||||
DEFAULT_RETRY_TIMEOUT,
|
|
||||||
DOMAIN,
|
|
||||||
SUPPORTED_MODEL_TYPES,
|
|
||||||
)
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -140,11 +133,6 @@ class SwitchbotOptionsFlowHandler(OptionsFlow):
|
|||||||
"""Manage Switchbot options."""
|
"""Manage Switchbot options."""
|
||||||
if user_input is not None:
|
if user_input is not None:
|
||||||
# Update common entity options for all other entities.
|
# Update common entity options for all other entities.
|
||||||
for entry in self.hass.config_entries.async_entries(DOMAIN):
|
|
||||||
if entry.unique_id != self.config_entry.unique_id:
|
|
||||||
self.hass.config_entries.async_update_entry(
|
|
||||||
entry, options=user_input
|
|
||||||
)
|
|
||||||
return self.async_create_entry(title="", data=user_input)
|
return self.async_create_entry(title="", data=user_input)
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
@ -153,13 +141,7 @@ class SwitchbotOptionsFlowHandler(OptionsFlow):
|
|||||||
default=self.config_entry.options.get(
|
default=self.config_entry.options.get(
|
||||||
CONF_RETRY_COUNT, DEFAULT_RETRY_COUNT
|
CONF_RETRY_COUNT, DEFAULT_RETRY_COUNT
|
||||||
),
|
),
|
||||||
): int,
|
): int
|
||||||
vol.Optional(
|
|
||||||
CONF_RETRY_TIMEOUT,
|
|
||||||
default=self.config_entry.options.get(
|
|
||||||
CONF_RETRY_TIMEOUT, DEFAULT_RETRY_TIMEOUT
|
|
||||||
),
|
|
||||||
): int,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.async_show_form(step_id="init", data_schema=vol.Schema(options))
|
return self.async_show_form(step_id="init", data_schema=vol.Schema(options))
|
||||||
|
@ -15,15 +15,11 @@ SUPPORTED_MODEL_TYPES = {
|
|||||||
|
|
||||||
# Config Defaults
|
# Config Defaults
|
||||||
DEFAULT_RETRY_COUNT = 3
|
DEFAULT_RETRY_COUNT = 3
|
||||||
DEFAULT_RETRY_TIMEOUT = 5
|
|
||||||
|
|
||||||
# Config Options
|
# Config Options
|
||||||
CONF_RETRY_COUNT = "retry_count"
|
CONF_RETRY_COUNT = "retry_count"
|
||||||
CONF_SCAN_TIMEOUT = "scan_timeout"
|
|
||||||
|
|
||||||
# Deprecated config Entry Options to be removed in 2023.4
|
# Deprecated config Entry Options to be removed in 2023.4
|
||||||
CONF_TIME_BETWEEN_UPDATE_COMMAND = "update_time"
|
CONF_TIME_BETWEEN_UPDATE_COMMAND = "update_time"
|
||||||
CONF_RETRY_TIMEOUT = "retry_timeout"
|
CONF_RETRY_TIMEOUT = "retry_timeout"
|
||||||
|
CONF_SCAN_TIMEOUT = "scan_timeout"
|
||||||
# Data
|
|
||||||
COMMON_OPTIONS = "common_options"
|
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from collections.abc import Mapping
|
|
||||||
import logging
|
import logging
|
||||||
from typing import Any, cast
|
from typing import Any, cast
|
||||||
|
|
||||||
@ -16,8 +15,6 @@ from homeassistant.components.bluetooth.passive_update_coordinator import (
|
|||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
|
|
||||||
from .const import CONF_RETRY_COUNT
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -38,21 +35,14 @@ class SwitchbotDataUpdateCoordinator(PassiveBluetoothDataUpdateCoordinator):
|
|||||||
logger: logging.Logger,
|
logger: logging.Logger,
|
||||||
ble_device: BLEDevice,
|
ble_device: BLEDevice,
|
||||||
device: switchbot.SwitchbotDevice,
|
device: switchbot.SwitchbotDevice,
|
||||||
common_options: Mapping[str, int],
|
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize global switchbot data updater."""
|
"""Initialize global switchbot data updater."""
|
||||||
super().__init__(hass, logger, ble_device.address)
|
super().__init__(hass, logger, ble_device.address)
|
||||||
self.ble_device = ble_device
|
self.ble_device = ble_device
|
||||||
self.device = device
|
self.device = device
|
||||||
self.common_options = common_options
|
|
||||||
self.data: dict[str, Any] = {}
|
self.data: dict[str, Any] = {}
|
||||||
self._ready_event = asyncio.Event()
|
self._ready_event = asyncio.Event()
|
||||||
|
|
||||||
@property
|
|
||||||
def retry_count(self) -> int:
|
|
||||||
"""Return retry count."""
|
|
||||||
return self.common_options[CONF_RETRY_COUNT]
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _async_handle_bluetooth_event(
|
def _async_handle_bluetooth_event(
|
||||||
self,
|
self,
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
"domain": "switchbot",
|
"domain": "switchbot",
|
||||||
"name": "SwitchBot",
|
"name": "SwitchBot",
|
||||||
"documentation": "https://www.home-assistant.io/integrations/switchbot",
|
"documentation": "https://www.home-assistant.io/integrations/switchbot",
|
||||||
"requirements": ["PySwitchbot==0.15.0"],
|
"requirements": ["PySwitchbot==0.15.1"],
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"dependencies": ["bluetooth"],
|
"dependencies": ["bluetooth"],
|
||||||
"codeowners": ["@danielhiversen", "@RenierM26", "@murtas"],
|
"codeowners": ["@danielhiversen", "@RenierM26", "@murtas"],
|
||||||
|
@ -24,8 +24,7 @@
|
|||||||
"step": {
|
"step": {
|
||||||
"init": {
|
"init": {
|
||||||
"data": {
|
"data": {
|
||||||
"retry_count": "Retry count",
|
"retry_count": "Retry count"
|
||||||
"retry_timeout": "Timeout between retries"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,7 @@
|
|||||||
"step": {
|
"step": {
|
||||||
"init": {
|
"init": {
|
||||||
"data": {
|
"data": {
|
||||||
"retry_count": "Retry count",
|
"retry_count": "Retry count"
|
||||||
"retry_timeout": "Timeout between retries"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ PyRMVtransport==0.3.3
|
|||||||
PySocks==1.7.1
|
PySocks==1.7.1
|
||||||
|
|
||||||
# homeassistant.components.switchbot
|
# homeassistant.components.switchbot
|
||||||
PySwitchbot==0.15.0
|
PySwitchbot==0.15.1
|
||||||
|
|
||||||
# homeassistant.components.transport_nsw
|
# homeassistant.components.transport_nsw
|
||||||
PyTransportNSW==0.1.1
|
PyTransportNSW==0.1.1
|
||||||
|
@ -33,7 +33,7 @@ PyRMVtransport==0.3.3
|
|||||||
PySocks==1.7.1
|
PySocks==1.7.1
|
||||||
|
|
||||||
# homeassistant.components.switchbot
|
# homeassistant.components.switchbot
|
||||||
PySwitchbot==0.15.0
|
PySwitchbot==0.15.1
|
||||||
|
|
||||||
# homeassistant.components.transport_nsw
|
# homeassistant.components.transport_nsw
|
||||||
PyTransportNSW==0.1.1
|
PyTransportNSW==0.1.1
|
||||||
|
@ -2,10 +2,7 @@
|
|||||||
|
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from homeassistant.components.switchbot.const import (
|
from homeassistant.components.switchbot.const import CONF_RETRY_COUNT
|
||||||
CONF_RETRY_COUNT,
|
|
||||||
CONF_RETRY_TIMEOUT,
|
|
||||||
)
|
|
||||||
from homeassistant.config_entries import SOURCE_BLUETOOTH, SOURCE_USER
|
from homeassistant.config_entries import SOURCE_BLUETOOTH, SOURCE_USER
|
||||||
from homeassistant.const import CONF_ADDRESS, CONF_NAME, CONF_PASSWORD, CONF_SENSOR_TYPE
|
from homeassistant.const import CONF_ADDRESS, CONF_NAME, CONF_PASSWORD, CONF_SENSOR_TYPE
|
||||||
from homeassistant.data_entry_flow import FlowResultType
|
from homeassistant.data_entry_flow import FlowResultType
|
||||||
@ -276,7 +273,6 @@ async def test_options_flow(hass):
|
|||||||
},
|
},
|
||||||
options={
|
options={
|
||||||
CONF_RETRY_COUNT: 10,
|
CONF_RETRY_COUNT: 10,
|
||||||
CONF_RETRY_TIMEOUT: 10,
|
|
||||||
},
|
},
|
||||||
unique_id="aabbccddeeff",
|
unique_id="aabbccddeeff",
|
||||||
)
|
)
|
||||||
@ -294,14 +290,12 @@ async def test_options_flow(hass):
|
|||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
user_input={
|
user_input={
|
||||||
CONF_RETRY_COUNT: 3,
|
CONF_RETRY_COUNT: 3,
|
||||||
CONF_RETRY_TIMEOUT: 5,
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert result["type"] == FlowResultType.CREATE_ENTRY
|
assert result["type"] == FlowResultType.CREATE_ENTRY
|
||||||
assert result["data"][CONF_RETRY_COUNT] == 3
|
assert result["data"][CONF_RETRY_COUNT] == 3
|
||||||
assert result["data"][CONF_RETRY_TIMEOUT] == 5
|
|
||||||
|
|
||||||
assert len(mock_setup_entry.mock_calls) == 2
|
assert len(mock_setup_entry.mock_calls) == 2
|
||||||
|
|
||||||
@ -319,16 +313,13 @@ async def test_options_flow(hass):
|
|||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
user_input={
|
user_input={
|
||||||
CONF_RETRY_COUNT: 6,
|
CONF_RETRY_COUNT: 6,
|
||||||
CONF_RETRY_TIMEOUT: 6,
|
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert result["type"] == FlowResultType.CREATE_ENTRY
|
assert result["type"] == FlowResultType.CREATE_ENTRY
|
||||||
assert result["data"][CONF_RETRY_COUNT] == 6
|
assert result["data"][CONF_RETRY_COUNT] == 6
|
||||||
assert result["data"][CONF_RETRY_TIMEOUT] == 6
|
|
||||||
|
|
||||||
assert len(mock_setup_entry.mock_calls) == 1
|
assert len(mock_setup_entry.mock_calls) == 1
|
||||||
|
|
||||||
assert entry.options[CONF_RETRY_COUNT] == 6
|
assert entry.options[CONF_RETRY_COUNT] == 6
|
||||||
assert entry.options[CONF_RETRY_TIMEOUT] == 6
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user