mirror of https://github.com/home-assistant/core
Switchbot bump Dependency 0.14.0 (#74001)
* Bump requirement. * Switchbot depenacy update, full async. * Update tests, remove redundant config entry check. * Update requirements_test_all.txt * Update requirements_all.txt * Remove asyncio lock. Not required anymore with bleak. * Update requirements_all.txt * Update requirements_test_all.txt * pyswitchbot no longer uses bluepy
This commit is contained in:
parent
b185de0ac0
commit
10ea88e0ea
|
@ -1,17 +1,14 @@
|
|||
"""Support for Switchbot devices."""
|
||||
from asyncio import Lock
|
||||
|
||||
import switchbot # pylint: disable=import-error
|
||||
import switchbot
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_SENSOR_TYPE, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryNotReady
|
||||
|
||||
from .const import (
|
||||
ATTR_BOT,
|
||||
ATTR_CURTAIN,
|
||||
BTLE_LOCK,
|
||||
COMMON_OPTIONS,
|
||||
CONF_RETRY_COUNT,
|
||||
CONF_RETRY_TIMEOUT,
|
||||
|
@ -50,12 +47,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
# Uses BTLE advertisement data, all Switchbot devices in range is stored here.
|
||||
if DATA_COORDINATOR not in hass.data[DOMAIN]:
|
||||
|
||||
# Check if asyncio.lock is stored in hass data.
|
||||
# BTLE has issues with multiple connections,
|
||||
# so we use a lock to ensure that only one API request is reaching it at a time:
|
||||
if BTLE_LOCK not in hass.data[DOMAIN]:
|
||||
hass.data[DOMAIN][BTLE_LOCK] = Lock()
|
||||
|
||||
if COMMON_OPTIONS not in hass.data[DOMAIN]:
|
||||
hass.data[DOMAIN][COMMON_OPTIONS] = {**entry.options}
|
||||
|
||||
|
@ -72,7 +63,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
api=switchbot,
|
||||
retry_count=hass.data[DOMAIN][COMMON_OPTIONS][CONF_RETRY_COUNT],
|
||||
scan_timeout=hass.data[DOMAIN][COMMON_OPTIONS][CONF_SCAN_TIMEOUT],
|
||||
api_lock=hass.data[DOMAIN][BTLE_LOCK],
|
||||
)
|
||||
|
||||
hass.data[DOMAIN][DATA_COORDINATOR] = coordinator
|
||||
|
@ -82,9 +72,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||
|
||||
await coordinator.async_config_entry_first_refresh()
|
||||
|
||||
if not coordinator.last_update_success:
|
||||
raise ConfigEntryNotReady
|
||||
|
||||
entry.async_on_unload(entry.add_update_listener(_async_update_listener))
|
||||
|
||||
hass.data[DOMAIN][entry.entry_id] = {DATA_COORDINATOR: coordinator}
|
||||
|
|
|
@ -8,6 +8,7 @@ from homeassistant.components.binary_sensor import (
|
|||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_MAC, CONF_NAME
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import PlatformNotReady
|
||||
from homeassistant.helpers.entity import EntityCategory
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
|
@ -33,8 +34,8 @@ async def async_setup_entry(
|
|||
DATA_COORDINATOR
|
||||
]
|
||||
|
||||
if not coordinator.data[entry.unique_id].get("data"):
|
||||
return
|
||||
if not coordinator.data.get(entry.unique_id):
|
||||
raise PlatformNotReady
|
||||
|
||||
async_add_entities(
|
||||
[
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
"""Config flow for Switchbot."""
|
||||
from __future__ import annotations
|
||||
|
||||
from asyncio import Lock
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from switchbot import GetSwitchbotDevices # pylint: disable=import-error
|
||||
from switchbot import GetSwitchbotDevices
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry, ConfigFlow, OptionsFlow
|
||||
|
@ -14,7 +13,6 @@ from homeassistant.core import callback
|
|||
from homeassistant.data_entry_flow import FlowResult
|
||||
|
||||
from .const import (
|
||||
BTLE_LOCK,
|
||||
CONF_RETRY_COUNT,
|
||||
CONF_RETRY_TIMEOUT,
|
||||
CONF_SCAN_TIMEOUT,
|
||||
|
@ -30,10 +28,10 @@ from .const import (
|
|||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _btle_connect() -> dict:
|
||||
async def _btle_connect() -> dict:
|
||||
"""Scan for BTLE advertisement data."""
|
||||
|
||||
switchbot_devices = GetSwitchbotDevices().discover()
|
||||
switchbot_devices = await GetSwitchbotDevices().discover()
|
||||
|
||||
if not switchbot_devices:
|
||||
raise NotConnectedError("Failed to discover switchbot")
|
||||
|
@ -52,14 +50,9 @@ class SwitchbotConfigFlow(ConfigFlow, domain=DOMAIN):
|
|||
# store asyncio.lock in hass data if not present.
|
||||
if DOMAIN not in self.hass.data:
|
||||
self.hass.data.setdefault(DOMAIN, {})
|
||||
if BTLE_LOCK not in self.hass.data[DOMAIN]:
|
||||
self.hass.data[DOMAIN][BTLE_LOCK] = Lock()
|
||||
|
||||
connect_lock = self.hass.data[DOMAIN][BTLE_LOCK]
|
||||
|
||||
# Discover switchbots nearby.
|
||||
async with connect_lock:
|
||||
_btle_adv_data = await self.hass.async_add_executor_job(_btle_connect)
|
||||
_btle_adv_data = await _btle_connect()
|
||||
|
||||
return _btle_adv_data
|
||||
|
||||
|
|
|
@ -22,5 +22,4 @@ CONF_SCAN_TIMEOUT = "scan_timeout"
|
|||
|
||||
# Data
|
||||
DATA_COORDINATOR = "coordinator"
|
||||
BTLE_LOCK = "btle_lock"
|
||||
COMMON_OPTIONS = "common_options"
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
"""Provides the switchbot DataUpdateCoordinator."""
|
||||
from __future__ import annotations
|
||||
|
||||
from asyncio import Lock
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
import switchbot # pylint: disable=import-error
|
||||
import switchbot
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
||||
|
@ -26,7 +25,6 @@ class SwitchbotDataUpdateCoordinator(DataUpdateCoordinator):
|
|||
api: switchbot,
|
||||
retry_count: int,
|
||||
scan_timeout: int,
|
||||
api_lock: Lock,
|
||||
) -> None:
|
||||
"""Initialize global switchbot data updater."""
|
||||
self.switchbot_api = api
|
||||
|
@ -39,20 +37,12 @@ class SwitchbotDataUpdateCoordinator(DataUpdateCoordinator):
|
|||
hass, _LOGGER, name=DOMAIN, update_interval=self.update_interval
|
||||
)
|
||||
|
||||
self.api_lock = api_lock
|
||||
|
||||
def _update_data(self) -> dict | None:
|
||||
"""Fetch device states from switchbot api."""
|
||||
|
||||
return self.switchbot_data.discover(
|
||||
retry=self.retry_count, scan_timeout=self.scan_timeout
|
||||
)
|
||||
|
||||
async def _async_update_data(self) -> dict | None:
|
||||
"""Fetch data from switchbot."""
|
||||
|
||||
async with self.api_lock:
|
||||
switchbot_data = await self.hass.async_add_executor_job(self._update_data)
|
||||
switchbot_data = await self.switchbot_data.discover(
|
||||
retry=self.retry_count, scan_timeout=self.scan_timeout
|
||||
)
|
||||
|
||||
if not switchbot_data:
|
||||
raise UpdateFailed("Unable to fetch switchbot services data")
|
||||
|
|
|
@ -4,7 +4,7 @@ from __future__ import annotations
|
|||
import logging
|
||||
from typing import Any
|
||||
|
||||
from switchbot import SwitchbotCurtain # pylint: disable=import-error
|
||||
from switchbot import SwitchbotCurtain
|
||||
|
||||
from homeassistant.components.cover import (
|
||||
ATTR_CURRENT_POSITION,
|
||||
|
@ -16,6 +16,7 @@ from homeassistant.components.cover import (
|
|||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_MAC, CONF_NAME, CONF_PASSWORD
|
||||
from homeassistant.core import HomeAssistant, callback
|
||||
from homeassistant.exceptions import PlatformNotReady
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.helpers.restore_state import RestoreEntity
|
||||
|
||||
|
@ -36,6 +37,9 @@ async def async_setup_entry(
|
|||
DATA_COORDINATOR
|
||||
]
|
||||
|
||||
if not coordinator.data.get(entry.unique_id):
|
||||
raise PlatformNotReady
|
||||
|
||||
async_add_entities(
|
||||
[
|
||||
SwitchBotCurtainEntity(
|
||||
|
@ -94,44 +98,30 @@ class SwitchBotCurtainEntity(SwitchbotEntity, CoverEntity, RestoreEntity):
|
|||
"""Open the curtain."""
|
||||
|
||||
_LOGGER.debug("Switchbot to open curtain %s", self._mac)
|
||||
|
||||
async with self.coordinator.api_lock:
|
||||
self._last_run_success = bool(
|
||||
await self.hass.async_add_executor_job(self._device.open)
|
||||
)
|
||||
self._last_run_success = bool(await self._device.open())
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_close_cover(self, **kwargs: Any) -> None:
|
||||
"""Close the curtain."""
|
||||
|
||||
_LOGGER.debug("Switchbot to close the curtain %s", self._mac)
|
||||
|
||||
async with self.coordinator.api_lock:
|
||||
self._last_run_success = bool(
|
||||
await self.hass.async_add_executor_job(self._device.close)
|
||||
)
|
||||
self._last_run_success = bool(await self._device.close())
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_stop_cover(self, **kwargs: Any) -> None:
|
||||
"""Stop the moving of this device."""
|
||||
|
||||
_LOGGER.debug("Switchbot to stop %s", self._mac)
|
||||
|
||||
async with self.coordinator.api_lock:
|
||||
self._last_run_success = bool(
|
||||
await self.hass.async_add_executor_job(self._device.stop)
|
||||
)
|
||||
self._last_run_success = bool(await self._device.stop())
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_set_cover_position(self, **kwargs: Any) -> None:
|
||||
"""Move the cover shutter to a specific position."""
|
||||
position = kwargs.get(ATTR_POSITION)
|
||||
|
||||
_LOGGER.debug("Switchbot to move at %d %s", position, self._mac)
|
||||
|
||||
async with self.coordinator.api_lock:
|
||||
self._last_run_success = bool(
|
||||
await self.hass.async_add_executor_job(
|
||||
self._device.set_position, position
|
||||
)
|
||||
)
|
||||
self._last_run_success = bool(await self._device.set_position(position))
|
||||
self.async_write_ha_state()
|
||||
|
||||
@callback
|
||||
def _handle_coordinator_update(self) -> None:
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"domain": "switchbot",
|
||||
"name": "SwitchBot",
|
||||
"documentation": "https://www.home-assistant.io/integrations/switchbot",
|
||||
"requirements": ["PySwitchbot==0.13.3"],
|
||||
"requirements": ["PySwitchbot==0.14.0"],
|
||||
"config_flow": true,
|
||||
"codeowners": ["@danielhiversen", "@RenierM26"],
|
||||
"iot_class": "local_polling",
|
||||
|
|
|
@ -14,6 +14,7 @@ from homeassistant.const import (
|
|||
SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
|
||||
)
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import PlatformNotReady
|
||||
from homeassistant.helpers.entity import EntityCategory
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
|
@ -53,8 +54,8 @@ async def async_setup_entry(
|
|||
DATA_COORDINATOR
|
||||
]
|
||||
|
||||
if not coordinator.data[entry.unique_id].get("data"):
|
||||
return
|
||||
if not coordinator.data.get(entry.unique_id):
|
||||
raise PlatformNotReady
|
||||
|
||||
async_add_entities(
|
||||
[
|
||||
|
|
|
@ -4,12 +4,13 @@ from __future__ import annotations
|
|||
import logging
|
||||
from typing import Any
|
||||
|
||||
from switchbot import Switchbot # pylint: disable=import-error
|
||||
from switchbot import Switchbot
|
||||
|
||||
from homeassistant.components.switch import SwitchDeviceClass, SwitchEntity
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_MAC, CONF_NAME, CONF_PASSWORD, STATE_ON
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import PlatformNotReady
|
||||
from homeassistant.helpers import entity_platform
|
||||
from homeassistant.helpers.restore_state import RestoreEntity
|
||||
|
||||
|
@ -32,6 +33,9 @@ async def async_setup_entry(
|
|||
DATA_COORDINATOR
|
||||
]
|
||||
|
||||
if not coordinator.data.get(entry.unique_id):
|
||||
raise PlatformNotReady
|
||||
|
||||
async_add_entities(
|
||||
[
|
||||
SwitchBotBotEntity(
|
||||
|
@ -80,25 +84,19 @@ class SwitchBotBotEntity(SwitchbotEntity, SwitchEntity, RestoreEntity):
|
|||
"""Turn device on."""
|
||||
_LOGGER.info("Turn Switchbot bot on %s", self._mac)
|
||||
|
||||
async with self.coordinator.api_lock:
|
||||
self._last_run_success = bool(
|
||||
await self.hass.async_add_executor_job(self._device.turn_on)
|
||||
)
|
||||
if self._last_run_success:
|
||||
self._attr_is_on = True
|
||||
self.async_write_ha_state()
|
||||
self._last_run_success = bool(await self._device.turn_on())
|
||||
if self._last_run_success:
|
||||
self._attr_is_on = True
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn device off."""
|
||||
_LOGGER.info("Turn Switchbot bot off %s", self._mac)
|
||||
|
||||
async with self.coordinator.api_lock:
|
||||
self._last_run_success = bool(
|
||||
await self.hass.async_add_executor_job(self._device.turn_off)
|
||||
)
|
||||
if self._last_run_success:
|
||||
self._attr_is_on = False
|
||||
self.async_write_ha_state()
|
||||
self._last_run_success = bool(await self._device.turn_off())
|
||||
if self._last_run_success:
|
||||
self._attr_is_on = False
|
||||
self.async_write_ha_state()
|
||||
|
||||
@property
|
||||
def assumed_state(self) -> bool:
|
||||
|
|
|
@ -34,7 +34,7 @@ PyRMVtransport==0.3.3
|
|||
PySocks==1.7.1
|
||||
|
||||
# homeassistant.components.switchbot
|
||||
# PySwitchbot==0.13.3
|
||||
PySwitchbot==0.14.0
|
||||
|
||||
# homeassistant.components.transport_nsw
|
||||
PyTransportNSW==0.1.1
|
||||
|
|
|
@ -30,7 +30,7 @@ PyRMVtransport==0.3.3
|
|||
PySocks==1.7.1
|
||||
|
||||
# homeassistant.components.switchbot
|
||||
# PySwitchbot==0.13.3
|
||||
PySwitchbot==0.14.0
|
||||
|
||||
# homeassistant.components.transport_nsw
|
||||
PyTransportNSW==0.1.1
|
||||
|
|
|
@ -30,7 +30,6 @@ COMMENT_REQUIREMENTS = (
|
|||
"opencv-python-headless",
|
||||
"pybluez",
|
||||
"pycups",
|
||||
"PySwitchbot",
|
||||
"pySwitchmate",
|
||||
"python-eq3bt",
|
||||
"python-gammu",
|
||||
|
|
|
@ -45,6 +45,19 @@ class MocGetSwitchbotDevices:
|
|||
"model": "m",
|
||||
"rawAdvData": "000d6d00",
|
||||
},
|
||||
"c0ceb0d426be": {
|
||||
"mac_address": "c0:ce:b0:d4:26:be",
|
||||
"isEncrypted": False,
|
||||
"data": {
|
||||
"temp": {"c": 21.6, "f": 70.88},
|
||||
"fahrenheit": False,
|
||||
"humidity": 73,
|
||||
"battery": 100,
|
||||
"rssi": -58,
|
||||
},
|
||||
"model": "T",
|
||||
"modelName": "WoSensorTH",
|
||||
},
|
||||
}
|
||||
self._curtain_all_services_data = {
|
||||
"mac_address": "e7:89:43:90:90:90",
|
||||
|
@ -72,11 +85,11 @@ class MocGetSwitchbotDevices:
|
|||
"modelName": "WoOther",
|
||||
}
|
||||
|
||||
def discover(self, retry=0, scan_timeout=0):
|
||||
async def discover(self, retry=0, scan_timeout=0):
|
||||
"""Mock discover."""
|
||||
return self._all_services_data
|
||||
|
||||
def get_device_data(self, mac=None):
|
||||
async def get_device_data(self, mac=None):
|
||||
"""Return data for specific device."""
|
||||
if mac == "e7:89:43:99:99:99":
|
||||
return self._all_services_data
|
||||
|
|
Loading…
Reference in New Issue