mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 07:07:28 +00:00
2022.12.8 (#84369)
This commit is contained in:
commit
2205006d31
@ -369,6 +369,7 @@ class BluetoothManager:
|
|||||||
all_history = self._all_history
|
all_history = self._all_history
|
||||||
connectable = service_info.connectable
|
connectable = service_info.connectable
|
||||||
connectable_history = self._connectable_history
|
connectable_history = self._connectable_history
|
||||||
|
old_connectable_service_info = connectable and connectable_history.get(address)
|
||||||
|
|
||||||
source = service_info.source
|
source = service_info.source
|
||||||
debug = _LOGGER.isEnabledFor(logging.DEBUG)
|
debug = _LOGGER.isEnabledFor(logging.DEBUG)
|
||||||
@ -399,7 +400,6 @@ class BluetoothManager:
|
|||||||
# but not in the connectable history or the connectable source is the same
|
# but not in the connectable history or the connectable source is the same
|
||||||
# as the new source, we need to add it to the connectable history
|
# as the new source, we need to add it to the connectable history
|
||||||
if connectable:
|
if connectable:
|
||||||
old_connectable_service_info = connectable_history.get(address)
|
|
||||||
if old_connectable_service_info and (
|
if old_connectable_service_info and (
|
||||||
# If its the same as the preferred source, we are done
|
# If its the same as the preferred source, we are done
|
||||||
# as we know we prefer the old advertisement
|
# as we know we prefer the old advertisement
|
||||||
@ -442,17 +442,24 @@ class BluetoothManager:
|
|||||||
tracker.async_collect(service_info)
|
tracker.async_collect(service_info)
|
||||||
|
|
||||||
# If the advertisement data is the same as the last time we saw it, we
|
# If the advertisement data is the same as the last time we saw it, we
|
||||||
# don't need to do anything else.
|
# don't need to do anything else unless its connectable and we are missing
|
||||||
if old_service_info and not (
|
# connectable history for the device so we can make it available again
|
||||||
|
# after unavailable callbacks.
|
||||||
|
if (
|
||||||
|
# Ensure its not a connectable device missing from connectable history
|
||||||
|
not (connectable and not old_connectable_service_info)
|
||||||
|
# Than check if advertisement data is the same
|
||||||
|
and old_service_info
|
||||||
|
and not (
|
||||||
service_info.manufacturer_data != old_service_info.manufacturer_data
|
service_info.manufacturer_data != old_service_info.manufacturer_data
|
||||||
or service_info.service_data != old_service_info.service_data
|
or service_info.service_data != old_service_info.service_data
|
||||||
or service_info.service_uuids != old_service_info.service_uuids
|
or service_info.service_uuids != old_service_info.service_uuids
|
||||||
or service_info.name != old_service_info.name
|
or service_info.name != old_service_info.name
|
||||||
|
)
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
|
|
||||||
is_connectable_by_any_source = address in self._connectable_history
|
if not connectable and old_connectable_service_info:
|
||||||
if not connectable and is_connectable_by_any_source:
|
|
||||||
# Since we have a connectable path and our BleakClient will
|
# Since we have a connectable path and our BleakClient will
|
||||||
# route any connection attempts to the connectable path, we
|
# route any connection attempts to the connectable path, we
|
||||||
# mark the service_info as connectable so that the callbacks
|
# mark the service_info as connectable so that the callbacks
|
||||||
@ -481,7 +488,7 @@ class BluetoothManager:
|
|||||||
matched_domains,
|
matched_domains,
|
||||||
)
|
)
|
||||||
|
|
||||||
if is_connectable_by_any_source:
|
if connectable or old_connectable_service_info:
|
||||||
# Bleak callbacks must get a connectable device
|
# Bleak callbacks must get a connectable device
|
||||||
for callback_filters in self._bleak_callbacks:
|
for callback_filters in self._bleak_callbacks:
|
||||||
_dispatch_bleak_callback(*callback_filters, device, advertisement_data)
|
_dispatch_bleak_callback(*callback_filters, device, advertisement_data)
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
"bleak-retry-connector==2.10.2",
|
"bleak-retry-connector==2.10.2",
|
||||||
"bluetooth-adapters==0.12.0",
|
"bluetooth-adapters==0.12.0",
|
||||||
"bluetooth-auto-recovery==1.0.3",
|
"bluetooth-auto-recovery==1.0.3",
|
||||||
"bluetooth-data-tools==0.3.0",
|
"bluetooth-data-tools==0.3.1",
|
||||||
"dbus-fast==1.75.0"
|
"dbus-fast==1.75.0"
|
||||||
],
|
],
|
||||||
"codeowners": ["@bdraco"],
|
"codeowners": ["@bdraco"],
|
||||||
|
@ -226,14 +226,16 @@ class CloudRegisterView(HomeAssistantView):
|
|||||||
|
|
||||||
client_metadata = None
|
client_metadata = None
|
||||||
|
|
||||||
if location_info := await async_detect_location_info(
|
if (
|
||||||
|
location_info := await async_detect_location_info(
|
||||||
async_get_clientsession(hass)
|
async_get_clientsession(hass)
|
||||||
):
|
)
|
||||||
client_metadata = {
|
) and location_info.country_code is not None:
|
||||||
"NC_COUNTRY_CODE": location_info.country_code,
|
client_metadata = {"NC_COUNTRY_CODE": location_info.country_code}
|
||||||
"NC_REGION_CODE": location_info.region_code,
|
if location_info.region_code is not None:
|
||||||
"NC_ZIP_CODE": location_info.zip_code,
|
client_metadata["NC_REGION_CODE"] = location_info.region_code
|
||||||
}
|
if location_info.zip_code is not None:
|
||||||
|
client_metadata["NC_ZIP_CODE"] = location_info.zip_code
|
||||||
|
|
||||||
async with async_timeout.timeout(REQUEST_TIMEOUT):
|
async with async_timeout.timeout(REQUEST_TIMEOUT):
|
||||||
await cloud.auth.async_register(
|
await cloud.auth.async_register(
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"name": "LED BLE",
|
"name": "LED BLE",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/led_ble/",
|
"documentation": "https://www.home-assistant.io/integrations/led_ble/",
|
||||||
"requirements": ["bluetooth-data-tools==0.3.0", "led-ble==1.0.0"],
|
"requirements": ["bluetooth-data-tools==0.3.1", "led-ble==1.0.0"],
|
||||||
"dependencies": ["bluetooth"],
|
"dependencies": ["bluetooth"],
|
||||||
"codeowners": ["@bdraco"],
|
"codeowners": ["@bdraco"],
|
||||||
"bluetooth": [
|
"bluetooth": [
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"name": "Local Calendar",
|
"name": "Local Calendar",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/local_calendar",
|
"documentation": "https://www.home-assistant.io/integrations/local_calendar",
|
||||||
"requirements": ["ical==4.2.3"],
|
"requirements": ["ical==4.2.4"],
|
||||||
"codeowners": ["@allenporter"],
|
"codeowners": ["@allenporter"],
|
||||||
"iot_class": "local_polling",
|
"iot_class": "local_polling",
|
||||||
"loggers": ["ical"]
|
"loggers": ["ical"]
|
||||||
|
@ -17,6 +17,8 @@ from homeassistant.const import TEMP_CELSIUS
|
|||||||
|
|
||||||
from ..entity import OverkizEntity
|
from ..entity import OverkizEntity
|
||||||
|
|
||||||
|
PRESET_COMFORT1 = "comfort-1"
|
||||||
|
PRESET_COMFORT2 = "comfort-2"
|
||||||
PRESET_FROST_PROTECTION = "frost_protection"
|
PRESET_FROST_PROTECTION = "frost_protection"
|
||||||
|
|
||||||
OVERKIZ_TO_HVAC_MODES: dict[str, HVACMode] = {
|
OVERKIZ_TO_HVAC_MODES: dict[str, HVACMode] = {
|
||||||
@ -31,6 +33,8 @@ OVERKIZ_TO_PRESET_MODES: dict[str, str] = {
|
|||||||
OverkizCommandParam.FROSTPROTECTION: PRESET_FROST_PROTECTION,
|
OverkizCommandParam.FROSTPROTECTION: PRESET_FROST_PROTECTION,
|
||||||
OverkizCommandParam.ECO: PRESET_ECO,
|
OverkizCommandParam.ECO: PRESET_ECO,
|
||||||
OverkizCommandParam.COMFORT: PRESET_COMFORT,
|
OverkizCommandParam.COMFORT: PRESET_COMFORT,
|
||||||
|
OverkizCommandParam.COMFORT_1: PRESET_COMFORT1,
|
||||||
|
OverkizCommandParam.COMFORT_2: PRESET_COMFORT2,
|
||||||
}
|
}
|
||||||
|
|
||||||
PRESET_MODES_TO_OVERKIZ = {v: k for k, v in OVERKIZ_TO_PRESET_MODES.items()}
|
PRESET_MODES_TO_OVERKIZ = {v: k for k, v in OVERKIZ_TO_PRESET_MODES.items()}
|
||||||
|
@ -394,7 +394,7 @@ class PrometheusMetrics:
|
|||||||
metric.labels(**self._labels(state)).set(value)
|
metric.labels(**self._labels(state)).set(value)
|
||||||
|
|
||||||
def _handle_climate_temp(self, state, attr, metric_name, metric_description):
|
def _handle_climate_temp(self, state, attr, metric_name, metric_description):
|
||||||
if temp := state.attributes.get(attr):
|
if (temp := state.attributes.get(attr)) is not None:
|
||||||
if self._climate_units == TEMP_FAHRENHEIT:
|
if self._climate_units == TEMP_FAHRENHEIT:
|
||||||
temp = TemperatureConverter.convert(temp, TEMP_FAHRENHEIT, TEMP_CELSIUS)
|
temp = TemperatureConverter.convert(temp, TEMP_FAHRENHEIT, TEMP_CELSIUS)
|
||||||
metric = self._metric(
|
metric = self._metric(
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"domain": "tibber",
|
"domain": "tibber",
|
||||||
"name": "Tibber",
|
"name": "Tibber",
|
||||||
"documentation": "https://www.home-assistant.io/integrations/tibber",
|
"documentation": "https://www.home-assistant.io/integrations/tibber",
|
||||||
"requirements": ["pyTibber==0.26.5"],
|
"requirements": ["pyTibber==0.26.6"],
|
||||||
"codeowners": ["@danielhiversen"],
|
"codeowners": ["@danielhiversen"],
|
||||||
"quality_scale": "silver",
|
"quality_scale": "silver",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
|
@ -8,7 +8,7 @@ from .backports.enum import StrEnum
|
|||||||
APPLICATION_NAME: Final = "HomeAssistant"
|
APPLICATION_NAME: Final = "HomeAssistant"
|
||||||
MAJOR_VERSION: Final = 2022
|
MAJOR_VERSION: Final = 2022
|
||||||
MINOR_VERSION: Final = 12
|
MINOR_VERSION: Final = 12
|
||||||
PATCH_VERSION: Final = "7"
|
PATCH_VERSION: Final = "8"
|
||||||
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
__short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}"
|
||||||
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
|
__version__: Final = f"{__short_version__}.{PATCH_VERSION}"
|
||||||
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 9, 0)
|
REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 9, 0)
|
||||||
|
@ -14,7 +14,7 @@ bleak-retry-connector==2.10.2
|
|||||||
bleak==0.19.2
|
bleak==0.19.2
|
||||||
bluetooth-adapters==0.12.0
|
bluetooth-adapters==0.12.0
|
||||||
bluetooth-auto-recovery==1.0.3
|
bluetooth-auto-recovery==1.0.3
|
||||||
bluetooth-data-tools==0.3.0
|
bluetooth-data-tools==0.3.1
|
||||||
certifi>=2021.5.30
|
certifi>=2021.5.30
|
||||||
ciso8601==2.2.0
|
ciso8601==2.2.0
|
||||||
cryptography==38.0.3
|
cryptography==38.0.3
|
||||||
|
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "homeassistant"
|
name = "homeassistant"
|
||||||
version = "2022.12.7"
|
version = "2022.12.8"
|
||||||
license = {text = "Apache-2.0"}
|
license = {text = "Apache-2.0"}
|
||||||
description = "Open-source home automation platform running on Python 3."
|
description = "Open-source home automation platform running on Python 3."
|
||||||
readme = "README.rst"
|
readme = "README.rst"
|
||||||
|
@ -454,7 +454,7 @@ bluetooth-auto-recovery==1.0.3
|
|||||||
|
|
||||||
# homeassistant.components.bluetooth
|
# homeassistant.components.bluetooth
|
||||||
# homeassistant.components.led_ble
|
# homeassistant.components.led_ble
|
||||||
bluetooth-data-tools==0.3.0
|
bluetooth-data-tools==0.3.1
|
||||||
|
|
||||||
# homeassistant.components.bond
|
# homeassistant.components.bond
|
||||||
bond-async==0.1.22
|
bond-async==0.1.22
|
||||||
@ -926,7 +926,7 @@ ibm-watson==5.2.2
|
|||||||
ibmiotf==0.3.4
|
ibmiotf==0.3.4
|
||||||
|
|
||||||
# homeassistant.components.local_calendar
|
# homeassistant.components.local_calendar
|
||||||
ical==4.2.3
|
ical==4.2.4
|
||||||
|
|
||||||
# homeassistant.components.ping
|
# homeassistant.components.ping
|
||||||
icmplib==3.0
|
icmplib==3.0
|
||||||
@ -1432,7 +1432,7 @@ pyRFXtrx==0.30.0
|
|||||||
pySwitchmate==0.5.1
|
pySwitchmate==0.5.1
|
||||||
|
|
||||||
# homeassistant.components.tibber
|
# homeassistant.components.tibber
|
||||||
pyTibber==0.26.5
|
pyTibber==0.26.6
|
||||||
|
|
||||||
# homeassistant.components.dlink
|
# homeassistant.components.dlink
|
||||||
pyW215==0.7.0
|
pyW215==0.7.0
|
||||||
|
@ -368,7 +368,7 @@ bluetooth-auto-recovery==1.0.3
|
|||||||
|
|
||||||
# homeassistant.components.bluetooth
|
# homeassistant.components.bluetooth
|
||||||
# homeassistant.components.led_ble
|
# homeassistant.components.led_ble
|
||||||
bluetooth-data-tools==0.3.0
|
bluetooth-data-tools==0.3.1
|
||||||
|
|
||||||
# homeassistant.components.bond
|
# homeassistant.components.bond
|
||||||
bond-async==0.1.22
|
bond-async==0.1.22
|
||||||
@ -691,7 +691,7 @@ iaqualink==0.5.0
|
|||||||
ibeacon_ble==1.0.1
|
ibeacon_ble==1.0.1
|
||||||
|
|
||||||
# homeassistant.components.local_calendar
|
# homeassistant.components.local_calendar
|
||||||
ical==4.2.3
|
ical==4.2.4
|
||||||
|
|
||||||
# homeassistant.components.ping
|
# homeassistant.components.ping
|
||||||
icmplib==3.0
|
icmplib==3.0
|
||||||
@ -1032,7 +1032,7 @@ pyMetno==0.9.0
|
|||||||
pyRFXtrx==0.30.0
|
pyRFXtrx==0.30.0
|
||||||
|
|
||||||
# homeassistant.components.tibber
|
# homeassistant.components.tibber
|
||||||
pyTibber==0.26.5
|
pyTibber==0.26.6
|
||||||
|
|
||||||
# homeassistant.components.nextbus
|
# homeassistant.components.nextbus
|
||||||
py_nextbusnext==0.1.5
|
py_nextbusnext==0.1.5
|
||||||
|
@ -1,27 +1,46 @@
|
|||||||
"""Tests for the Bluetooth integration manager."""
|
"""Tests for the Bluetooth integration manager."""
|
||||||
|
|
||||||
|
from datetime import timedelta
|
||||||
import time
|
import time
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from bleak.backends.scanner import BLEDevice
|
from bleak.backends.scanner import AdvertisementData, BLEDevice
|
||||||
from bluetooth_adapters import AdvertisementHistory
|
from bluetooth_adapters import AdvertisementHistory
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from homeassistant.components import bluetooth
|
from homeassistant.components import bluetooth
|
||||||
from homeassistant.components.bluetooth import BaseHaScanner
|
from homeassistant.components.bluetooth import (
|
||||||
|
BaseHaRemoteScanner,
|
||||||
|
BaseHaScanner,
|
||||||
|
BluetoothChange,
|
||||||
|
BluetoothScanningMode,
|
||||||
|
BluetoothServiceInfo,
|
||||||
|
BluetoothServiceInfoBleak,
|
||||||
|
HaBluetoothConnector,
|
||||||
|
async_ble_device_from_address,
|
||||||
|
async_get_advertisement_callback,
|
||||||
|
async_scanner_count,
|
||||||
|
async_track_unavailable,
|
||||||
|
)
|
||||||
|
from homeassistant.components.bluetooth.const import UNAVAILABLE_TRACK_SECONDS
|
||||||
from homeassistant.components.bluetooth.manager import (
|
from homeassistant.components.bluetooth.manager import (
|
||||||
FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS,
|
FALLBACK_MAXIMUM_STALE_ADVERTISEMENT_SECONDS,
|
||||||
)
|
)
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
from homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
from . import (
|
from . import (
|
||||||
|
MockBleakClient,
|
||||||
|
_get_manager,
|
||||||
generate_advertisement_data,
|
generate_advertisement_data,
|
||||||
inject_advertisement_with_source,
|
inject_advertisement_with_source,
|
||||||
inject_advertisement_with_time_and_source,
|
inject_advertisement_with_time_and_source,
|
||||||
inject_advertisement_with_time_and_source_connectable,
|
inject_advertisement_with_time_and_source_connectable,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from tests.common import async_fire_time_changed
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def register_hci0_scanner(hass: HomeAssistant) -> None:
|
def register_hci0_scanner(hass: HomeAssistant) -> None:
|
||||||
@ -514,3 +533,172 @@ async def test_switching_adapters_when_one_stop_scanning(
|
|||||||
)
|
)
|
||||||
|
|
||||||
cancel_hci2()
|
cancel_hci2()
|
||||||
|
|
||||||
|
|
||||||
|
async def test_goes_unavailable_connectable_only_and_recovers(
|
||||||
|
hass, mock_bluetooth_adapters
|
||||||
|
):
|
||||||
|
"""Test all connectable scanners go unavailable, and than recover when there is a non-connectable scanner."""
|
||||||
|
assert await async_setup_component(hass, bluetooth.DOMAIN, {})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert async_scanner_count(hass, connectable=True) == 0
|
||||||
|
assert async_scanner_count(hass, connectable=False) == 0
|
||||||
|
switchbot_device_connectable = BLEDevice(
|
||||||
|
"44:44:33:11:23:45",
|
||||||
|
"wohand",
|
||||||
|
{},
|
||||||
|
rssi=-100,
|
||||||
|
)
|
||||||
|
switchbot_device_non_connectable = BLEDevice(
|
||||||
|
"44:44:33:11:23:45",
|
||||||
|
"wohand",
|
||||||
|
{},
|
||||||
|
rssi=-100,
|
||||||
|
)
|
||||||
|
switchbot_device_adv = generate_advertisement_data(
|
||||||
|
local_name="wohand",
|
||||||
|
service_uuids=["050a021a-0000-1000-8000-00805f9b34fb"],
|
||||||
|
service_data={"050a021a-0000-1000-8000-00805f9b34fb": b"\n\xff"},
|
||||||
|
manufacturer_data={1: b"\x01"},
|
||||||
|
rssi=-100,
|
||||||
|
)
|
||||||
|
callbacks = []
|
||||||
|
|
||||||
|
def _fake_subscriber(
|
||||||
|
service_info: BluetoothServiceInfo,
|
||||||
|
change: BluetoothChange,
|
||||||
|
) -> None:
|
||||||
|
"""Fake subscriber for the BleakScanner."""
|
||||||
|
callbacks.append((service_info, change))
|
||||||
|
|
||||||
|
cancel = bluetooth.async_register_callback(
|
||||||
|
hass,
|
||||||
|
_fake_subscriber,
|
||||||
|
{"address": "44:44:33:11:23:45", "connectable": True},
|
||||||
|
BluetoothScanningMode.ACTIVE,
|
||||||
|
)
|
||||||
|
|
||||||
|
class FakeScanner(BaseHaRemoteScanner):
|
||||||
|
def inject_advertisement(
|
||||||
|
self, device: BLEDevice, advertisement_data: AdvertisementData
|
||||||
|
) -> None:
|
||||||
|
"""Inject an advertisement."""
|
||||||
|
self._async_on_advertisement(
|
||||||
|
device.address,
|
||||||
|
advertisement_data.rssi,
|
||||||
|
device.name,
|
||||||
|
advertisement_data.service_uuids,
|
||||||
|
advertisement_data.service_data,
|
||||||
|
advertisement_data.manufacturer_data,
|
||||||
|
advertisement_data.tx_power,
|
||||||
|
{"scanner_specific_data": "test"},
|
||||||
|
)
|
||||||
|
|
||||||
|
new_info_callback = async_get_advertisement_callback(hass)
|
||||||
|
connector = (
|
||||||
|
HaBluetoothConnector(MockBleakClient, "mock_bleak_client", lambda: False),
|
||||||
|
)
|
||||||
|
connectable_scanner = FakeScanner(
|
||||||
|
hass,
|
||||||
|
"connectable",
|
||||||
|
"connectable",
|
||||||
|
new_info_callback,
|
||||||
|
connector,
|
||||||
|
True,
|
||||||
|
)
|
||||||
|
unsetup_connectable_scanner = connectable_scanner.async_setup()
|
||||||
|
cancel_connectable_scanner = _get_manager().async_register_scanner(
|
||||||
|
connectable_scanner, True
|
||||||
|
)
|
||||||
|
connectable_scanner.inject_advertisement(
|
||||||
|
switchbot_device_connectable, switchbot_device_adv
|
||||||
|
)
|
||||||
|
assert async_ble_device_from_address(hass, "44:44:33:11:23:45") is not None
|
||||||
|
assert async_scanner_count(hass, connectable=True) == 1
|
||||||
|
assert len(callbacks) == 1
|
||||||
|
|
||||||
|
assert (
|
||||||
|
"44:44:33:11:23:45"
|
||||||
|
in connectable_scanner.discovered_devices_and_advertisement_data
|
||||||
|
)
|
||||||
|
|
||||||
|
not_connectable_scanner = FakeScanner(
|
||||||
|
hass,
|
||||||
|
"not_connectable",
|
||||||
|
"not_connectable",
|
||||||
|
new_info_callback,
|
||||||
|
connector,
|
||||||
|
False,
|
||||||
|
)
|
||||||
|
unsetup_not_connectable_scanner = not_connectable_scanner.async_setup()
|
||||||
|
cancel_not_connectable_scanner = _get_manager().async_register_scanner(
|
||||||
|
not_connectable_scanner, False
|
||||||
|
)
|
||||||
|
not_connectable_scanner.inject_advertisement(
|
||||||
|
switchbot_device_non_connectable, switchbot_device_adv
|
||||||
|
)
|
||||||
|
assert async_scanner_count(hass, connectable=True) == 1
|
||||||
|
assert async_scanner_count(hass, connectable=False) == 2
|
||||||
|
|
||||||
|
assert (
|
||||||
|
"44:44:33:11:23:45"
|
||||||
|
in not_connectable_scanner.discovered_devices_and_advertisement_data
|
||||||
|
)
|
||||||
|
|
||||||
|
unavailable_callbacks: list[BluetoothServiceInfoBleak] = []
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def _unavailable_callback(service_info: BluetoothServiceInfoBleak) -> None:
|
||||||
|
"""Wrong device unavailable callback."""
|
||||||
|
nonlocal unavailable_callbacks
|
||||||
|
unavailable_callbacks.append(service_info.address)
|
||||||
|
|
||||||
|
cancel_unavailable = async_track_unavailable(
|
||||||
|
hass,
|
||||||
|
_unavailable_callback,
|
||||||
|
switchbot_device_connectable.address,
|
||||||
|
connectable=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert async_scanner_count(hass, connectable=True) == 1
|
||||||
|
cancel_connectable_scanner()
|
||||||
|
unsetup_connectable_scanner()
|
||||||
|
assert async_scanner_count(hass, connectable=True) == 0
|
||||||
|
assert async_scanner_count(hass, connectable=False) == 1
|
||||||
|
|
||||||
|
async_fire_time_changed(
|
||||||
|
hass, dt_util.utcnow() + timedelta(seconds=UNAVAILABLE_TRACK_SECONDS)
|
||||||
|
)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert "44:44:33:11:23:45" in unavailable_callbacks
|
||||||
|
cancel_unavailable()
|
||||||
|
|
||||||
|
connectable_scanner_2 = FakeScanner(
|
||||||
|
hass,
|
||||||
|
"connectable",
|
||||||
|
"connectable",
|
||||||
|
new_info_callback,
|
||||||
|
connector,
|
||||||
|
True,
|
||||||
|
)
|
||||||
|
unsetup_connectable_scanner_2 = connectable_scanner_2.async_setup()
|
||||||
|
cancel_connectable_scanner_2 = _get_manager().async_register_scanner(
|
||||||
|
connectable_scanner, True
|
||||||
|
)
|
||||||
|
connectable_scanner_2.inject_advertisement(
|
||||||
|
switchbot_device_connectable, switchbot_device_adv
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
"44:44:33:11:23:45"
|
||||||
|
in connectable_scanner_2.discovered_devices_and_advertisement_data
|
||||||
|
)
|
||||||
|
|
||||||
|
# We should get another callback to make the device available again
|
||||||
|
assert len(callbacks) == 2
|
||||||
|
|
||||||
|
cancel()
|
||||||
|
cancel_connectable_scanner_2()
|
||||||
|
unsetup_connectable_scanner_2()
|
||||||
|
cancel_not_connectable_scanner()
|
||||||
|
unsetup_not_connectable_scanner()
|
||||||
|
@ -293,6 +293,12 @@ async def test_climate(client, climate_entities):
|
|||||||
'friendly_name="Ecobee"} 24.0' in body
|
'friendly_name="Ecobee"} 24.0' in body
|
||||||
)
|
)
|
||||||
|
|
||||||
|
assert (
|
||||||
|
'climate_target_temperature_celsius{domain="climate",'
|
||||||
|
'entity="climate.fritzdect",'
|
||||||
|
'friendly_name="Fritz!DECT"} 0.0' in body
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("namespace", [""])
|
@pytest.mark.parametrize("namespace", [""])
|
||||||
async def test_humidifier(client, humidifier_entities):
|
async def test_humidifier(client, humidifier_entities):
|
||||||
@ -1001,6 +1007,23 @@ async def climate_fixture(hass, registry):
|
|||||||
data["climate_2"] = climate_2
|
data["climate_2"] = climate_2
|
||||||
data["climate_2_attributes"] = climate_2_attributes
|
data["climate_2_attributes"] = climate_2_attributes
|
||||||
|
|
||||||
|
climate_3 = registry.async_get_or_create(
|
||||||
|
domain=climate.DOMAIN,
|
||||||
|
platform="test",
|
||||||
|
unique_id="climate_3",
|
||||||
|
unit_of_measurement=TEMP_CELSIUS,
|
||||||
|
suggested_object_id="fritzdect",
|
||||||
|
original_name="Fritz!DECT",
|
||||||
|
)
|
||||||
|
climate_3_attributes = {
|
||||||
|
ATTR_TEMPERATURE: 0,
|
||||||
|
ATTR_CURRENT_TEMPERATURE: 22,
|
||||||
|
ATTR_HVAC_ACTION: climate.HVACAction.OFF,
|
||||||
|
}
|
||||||
|
set_state_with_entry(hass, climate_3, climate.HVACAction.OFF, climate_3_attributes)
|
||||||
|
data["climate_3"] = climate_3
|
||||||
|
data["climate_3_attributes"] = climate_3_attributes
|
||||||
|
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user