예제 #1
0
async def test_switching_adapters_based_on_stale(hass, enable_bluetooth):
    """Test switching adapters based on the previous advertisement being stale."""

    address = "44:44:33:11:23:41"
    start_time_monotonic = 50.0

    switchbot_device_poor_signal_hci0 = BLEDevice(address,
                                                  "wohand_poor_signal_hci0",
                                                  rssi=-100)
    switchbot_adv_poor_signal_hci0 = AdvertisementData(
        local_name="wohand_poor_signal_hci0", service_uuids=[])
    inject_advertisement_with_time_and_source(
        hass,
        switchbot_device_poor_signal_hci0,
        switchbot_adv_poor_signal_hci0,
        start_time_monotonic,
        "hci0",
    )

    assert (bluetooth.async_ble_device_from_address(hass, address) is
            switchbot_device_poor_signal_hci0)

    switchbot_device_poor_signal_hci1 = BLEDevice(address,
                                                  "wohand_poor_signal_hci1",
                                                  rssi=-99)
    switchbot_adv_poor_signal_hci1 = AdvertisementData(
        local_name="wohand_poor_signal_hci1", service_uuids=[])
    inject_advertisement_with_time_and_source(
        hass,
        switchbot_device_poor_signal_hci1,
        switchbot_adv_poor_signal_hci1,
        start_time_monotonic,
        "hci1",
    )

    # Should not switch adapters until the advertisement is stale
    assert (bluetooth.async_ble_device_from_address(hass, address) is
            switchbot_device_poor_signal_hci0)

    # Should switch to hci1 since the previous advertisement is stale
    # even though the signal is poor because the device is now
    # likely unreachable via hci0
    inject_advertisement_with_time_and_source(
        hass,
        switchbot_device_poor_signal_hci1,
        switchbot_adv_poor_signal_hci1,
        start_time_monotonic + STALE_ADVERTISEMENT_SECONDS + 1,
        "hci1",
    )

    assert (bluetooth.async_ble_device_from_address(hass, address) is
            switchbot_device_poor_signal_hci1)
예제 #2
0
파일: bluetooth.py 프로젝트: jbouwh/core
 def async_on_advertisement(self, adv: BluetoothLEAdvertisement) -> None:
     """Call the registered callback."""
     now = time.monotonic()
     address = ":".join(TWO_CHAR.findall("%012X" %
                                         adv.address))  # must be upper
     advertisement_data = AdvertisementData(  # type: ignore[no-untyped-call]
         local_name=None if adv.name == "" else adv.name,
         manufacturer_data=adv.manufacturer_data,
         service_data=adv.service_data,
         service_uuids=adv.service_uuids,
     )
     device = BLEDevice(  # type: ignore[no-untyped-call]
         address=address,
         name=adv.name,
         details={},
         rssi=adv.rssi,
     )
     self._discovered_devices[address] = device
     self._discovered_device_timestamps[address] = now
     self._new_info_callback(
         BluetoothServiceInfoBleak(
             name=advertisement_data.local_name or device.name
             or device.address,
             address=device.address,
             rssi=device.rssi,
             manufacturer_data=advertisement_data.manufacturer_data,
             service_data=advertisement_data.service_data,
             service_uuids=advertisement_data.service_uuids,
             source=self._source,
             device=device,
             advertisement=advertisement_data,
             connectable=False,
             time=now,
         ))
예제 #3
0
async def test_switching_adapters_based_on_rssi(hass, enable_bluetooth):
    """Test switching adapters based on rssi."""

    address = "44:44:33:11:23:45"

    switchbot_device_poor_signal = BLEDevice(address,
                                             "wohand_poor_signal",
                                             rssi=-100)
    switchbot_adv_poor_signal = AdvertisementData(
        local_name="wohand_poor_signal", service_uuids=[])
    inject_advertisement_with_source(hass, switchbot_device_poor_signal,
                                     switchbot_adv_poor_signal, "hci0")

    assert (bluetooth.async_ble_device_from_address(hass, address) is
            switchbot_device_poor_signal)

    switchbot_device_good_signal = BLEDevice(address,
                                             "wohand_good_signal",
                                             rssi=-60)
    switchbot_adv_good_signal = AdvertisementData(
        local_name="wohand_good_signal", service_uuids=[])
    inject_advertisement_with_source(hass, switchbot_device_good_signal,
                                     switchbot_adv_good_signal, "hci1")

    assert (bluetooth.async_ble_device_from_address(hass, address) is
            switchbot_device_good_signal)

    inject_advertisement_with_source(hass, switchbot_device_good_signal,
                                     switchbot_adv_poor_signal, "hci0")
    assert (bluetooth.async_ble_device_from_address(hass, address) is
            switchbot_device_good_signal)

    # We should not switch adapters unless the signal hits the threshold
    switchbot_device_similar_signal = BLEDevice(address,
                                                "wohand_similar_signal",
                                                rssi=-62)
    switchbot_adv_similar_signal = AdvertisementData(
        local_name="wohand_similar_signal", service_uuids=[])

    inject_advertisement_with_source(hass, switchbot_device_similar_signal,
                                     switchbot_adv_similar_signal, "hci0")
    assert (bluetooth.async_ble_device_from_address(hass, address) is
            switchbot_device_good_signal)
예제 #4
0
    def _received_handler(
        self,
        sender: BluetoothLEAdvertisementWatcher,
        event_args: BluetoothLEAdvertisementReceivedEventArgs,
    ):
        if sender == self.watcher:
            logger.debug("Received {0}.".format(
                _format_event_args(event_args)))
            if (event_args.AdvertisementType ==
                    BluetoothLEAdvertisementType.ScanResponse):
                if event_args.BluetoothAddress not in self._scan_responses:
                    self._scan_responses[
                        event_args.BluetoothAddress] = event_args
            else:
                if event_args.BluetoothAddress not in self._devices:
                    self._devices[event_args.BluetoothAddress] = event_args

        if self._callback is None:
            return

        # Get a "BLEDevice" from parse_event args
        device = self.parse_eventargs(event_args)

        # Decode service data
        service_data = {}
        # 0x16 is service data with 16-bit UUID
        for section in event_args.Advertisement.GetSectionsByType(0x16):
            with BleakDataReader(section.Data) as reader:
                data = reader.read()
                service_data[
                    f"0000{data[1]:02x}{data[0]:02x}-0000-1000-8000-00805f9b34fb"] = data[
                        2:]
        # 0x20 is service data with 32-bit UUID
        for section in event_args.Advertisement.GetSectionsByType(0x20):
            with BleakDataReader(section.Data) as reader:
                data = reader.read()
                service_data[
                    f"{data[3]:02x}{data[2]:02x}{data[1]:02x}{data[0]:02x}-0000-1000-8000-00805f9b34fb"] = data[
                        4:]
        # 0x21 is service data with 128-bit UUID
        for section in event_args.Advertisement.GetSectionsByType(0x21):
            with BleakDataReader(section.Data) as reader:
                data = reader.read()
                service_data[str(UUID(bytes=data[15::-1]))] = data[16:]

        # Use the BLEDevice to populate all the fields for the advertisement data to return
        advertisement_data = AdvertisementData(
            local_name=event_args.Advertisement.LocalName,
            manufacturer_data=device.metadata["manufacturer_data"],
            service_data=service_data,
            service_uuids=device.metadata["uuids"],
            platform_data=(sender, event_args),
        )

        self._callback(device, advertisement_data)
예제 #5
0
파일: scanner.py 프로젝트: bsiever/bleak
    def _received_handler(
        self,
        sender: BluetoothLEAdvertisementWatcher,
        event_args: BluetoothLEAdvertisementReceivedEventArgs,
    ):
        """Callback for AdvertisementWatcher.Received"""
        # TODO: Cannot check for if sender == self.watcher in winrt?
        logger.debug("Received {0}.".format(_format_event_args(event_args)))
        if event_args.advertisement_type == BluetoothLEAdvertisementType.SCAN_RESPONSE:
            if event_args.bluetooth_address not in self._scan_responses:
                self._scan_responses[event_args.bluetooth_address] = event_args
        else:
            if event_args.bluetooth_address not in self._devices:
                self._devices[event_args.bluetooth_address] = event_args

        if self._callback is None:
            return

        # Get a "BLEDevice" from parse_event args
        device = self._parse_event_args(event_args)

        # Decode service data
        service_data = {}
        # 0x16 is service data with 16-bit UUID
        for section in event_args.advertisement.get_sections_by_type(0x16):
            data = bytearray(
                CryptographicBuffer.copy_to_byte_array(section.data))
            service_data[
                f"0000{data[1]:02x}{data[0]:02x}-0000-1000-8000-00805f9b34fb"] = data[
                    2:]
        # 0x20 is service data with 32-bit UUID
        for section in event_args.advertisement.get_sections_by_type(0x20):
            data = bytearray(
                CryptographicBuffer.copy_to_byte_array(section.data))
            service_data[
                f"{data[3]:02x}{data[2]:02x}{data[1]:02x}{data[0]:02x}-0000-1000-8000-00805f9b34fb"] = data[
                    4:]
        # 0x21 is service data with 128-bit UUID
        for section in event_args.advertisement.get_sections_by_type(0x21):
            data = bytearray(
                CryptographicBuffer.copy_to_byte_array(section.data))
            service_data[str(UUID(bytes=bytes(data[15::-1])))] = data[16:]

        # Use the BLEDevice to populate all the fields for the advertisement data to return
        advertisement_data = AdvertisementData(
            local_name=event_args.advertisement.local_name,
            manufacturer_data=device.metadata["manufacturer_data"],
            service_data=service_data,
            service_uuids=device.metadata["uuids"],
            platform_data=(sender, event_args),
        )

        self._callback(device, advertisement_data)
예제 #6
0
async def test_advertisements_do_not_switch_adapters_for_no_reason(
        hass, enable_bluetooth):
    """Test we only switch adapters when needed."""

    address = "44:44:33:11:23:12"

    switchbot_device_signal_100 = BLEDevice(address,
                                            "wohand_signal_100",
                                            rssi=-100)
    switchbot_adv_signal_100 = AdvertisementData(
        local_name="wohand_signal_100", service_uuids=[])
    inject_advertisement_with_source(hass, switchbot_device_signal_100,
                                     switchbot_adv_signal_100, "hci0")

    assert (bluetooth.async_ble_device_from_address(hass, address) is
            switchbot_device_signal_100)

    switchbot_device_signal_99 = BLEDevice(address,
                                           "wohand_signal_99",
                                           rssi=-99)
    switchbot_adv_signal_99 = AdvertisementData(local_name="wohand_signal_99",
                                                service_uuids=[])
    inject_advertisement_with_source(hass, switchbot_device_signal_99,
                                     switchbot_adv_signal_99, "hci0")

    assert (bluetooth.async_ble_device_from_address(hass, address) is
            switchbot_device_signal_99)

    switchbot_device_signal_98 = BLEDevice(address,
                                           "wohand_good_signal",
                                           rssi=-98)
    switchbot_adv_signal_98 = AdvertisementData(
        local_name="wohand_good_signal", service_uuids=[])
    inject_advertisement_with_source(hass, switchbot_device_signal_98,
                                     switchbot_adv_signal_98, "hci1")

    # should not switch to hci1
    assert (bluetooth.async_ble_device_from_address(hass, address) is
            switchbot_device_signal_99)
예제 #7
0
        def callback(p: CBPeripheral, a: Dict[str, Any], r: int) -> None:
            # update identifiers for scanned device
            self._identifiers.setdefault(p.identifier(), {}).update(a)

            if not self._callback:
                return

            # Process service data
            service_data_dict_raw = a.get("kCBAdvDataServiceData", {})
            service_data = {
                cb_uuid_to_str(k): bytes(v) for k, v in service_data_dict_raw.items()
            }

            # Process manufacturer data into a more friendly format
            manufacturer_binary_data = a.get("kCBAdvDataManufacturerData")
            manufacturer_data = {}
            if manufacturer_binary_data:
                manufacturer_id = int.from_bytes(
                    manufacturer_binary_data[0:2], byteorder="little"
                )
                manufacturer_value = bytes(manufacturer_binary_data[2:])
                manufacturer_data[manufacturer_id] = manufacturer_value

            service_uuids = [
                cb_uuid_to_str(u) for u in a.get("kCBAdvDataServiceUUIDs", [])
            ]

            advertisement_data = AdvertisementData(
                local_name=p.name(),
                manufacturer_data=manufacturer_data,
                service_data=service_data,
                service_uuids=service_uuids,
                platform_data=(p, a, r),
            )

            device = BLEDevice(
                p.identifier().UUIDString(),
                p.name(),
                p,
                r,
                uuids=service_uuids,
                manufacturer_data=manufacturer_data,
                service_data=service_data,
                delegate=self._manager.central_manager.delegate(),
            )

            self._callback(device, advertisement_data)
예제 #8
0
파일: __init__.py 프로젝트: jbouwh/core
def make_advertisement(address: str,
                       payload: bytes) -> BluetoothServiceInfoBleak:
    """Make a dummy advertisement."""
    return BluetoothServiceInfoBleak(
        name="Test Device",
        address=address,
        device=BLEDevice(address, None),
        rssi=-56,
        manufacturer_data={},
        service_data={
            "0000181c-0000-1000-8000-00805f9b34fb": payload,
        },
        service_uuids=["0000181c-0000-1000-8000-00805f9b34fb"],
        source="local",
        advertisement=AdvertisementData(local_name="Test Device"),
        time=0,
        connectable=False,
    )
예제 #9
0
    def _invoke_callback(self, path: str, message: Message) -> None:
        """Invokes the advertising data callback.

        Args:
            message: The D-Bus message that triggered the callback.
        """
        if self._callback is None:
            return

        props = self._devices[path]

        # Get all the information wanted to pack in the advertisement data
        _local_name = props.get("Name")
        _manufacturer_data = {
            k: bytes(v)
            for k, v in props.get("ManufacturerData", {}).items()
        }
        _service_data = {
            k: bytes(v)
            for k, v in props.get("ServiceData", {}).items()
        }
        _service_uuids = props.get("UUIDs", [])

        # Pack the advertisement data
        advertisement_data = AdvertisementData(
            local_name=_local_name,
            manufacturer_data=_manufacturer_data,
            service_data=_service_data,
            service_uuids=_service_uuids,
            platform_data=(props, message),
        )

        device = BLEDevice(
            props["Address"],
            props["Alias"],
            {
                "path": path,
                "props": props
            },
            props.get("RSSI", 0),
        )

        self._callback(device, advertisement_data)
예제 #10
0
파일: scanner.py 프로젝트: irremotus/govee
 def _callback(device: BLEDevice, adv: AdvertisementData):
     adv = process_advertisement(device, adv)
     if adv:
         for callback in self._callbacks:
             callback(adv.dict())
예제 #11
0
파일: __init__.py 프로젝트: jbouwh/core
        await hass.async_block_till_done()

    return entry


WOHAND_SERVICE_INFO = BluetoothServiceInfoBleak(
    name="WoHand",
    manufacturer_data={89: b"\xfd`0U\x92W"},
    service_data={"00000d00-0000-1000-8000-00805f9b34fb": b"H\x90\xd9"},
    service_uuids=["cba20d00-224d-11e6-9fb8-0002a5d5c51b"],
    address="aa:bb:cc:dd:ee:ff",
    rssi=-60,
    source="local",
    advertisement=AdvertisementData(
        local_name="WoHand",
        manufacturer_data={89: b"\xfd`0U\x92W"},
        service_data={"00000d00-0000-1000-8000-00805f9b34fb": b"H\x90\xd9"},
        service_uuids=["cba20d00-224d-11e6-9fb8-0002a5d5c51b"],
    ),
    device=BLEDevice("aa:bb:cc:dd:ee:ff", "WoHand"),
    time=0,
    connectable=True,
)

WOHAND_SERVICE_INFO_NOT_CONNECTABLE = BluetoothServiceInfoBleak(
    name="WoHand",
    manufacturer_data={89: b"\xfd`0U\x92W"},
    service_data={"00000d00-0000-1000-8000-00805f9b34fb": b"H\x90\xd9"},
    service_uuids=["cba20d00-224d-11e6-9fb8-0002a5d5c51b"],
    address="aa:bb:cc:dd:ee:ff",
    rssi=-60,
    source="local",
예제 #12
0
    def parse_msg(self, message):
        if message.member == "InterfacesAdded":
            msg_path = message.body[0]
            try:
                device_interface = message.body[1].get(defs.DEVICE_INTERFACE,
                                                       {})
            except Exception as e:
                raise e
            self._devices[msg_path] = ({
                **self._devices[msg_path],
                **device_interface
            } if msg_path in self._devices else device_interface)
        elif message.member == "PropertiesChanged":
            iface, changed, invalidated = message.body
            if iface != defs.DEVICE_INTERFACE:
                return

            msg_path = message.path
            # the PropertiesChanged signal only sends changed properties, so we
            # need to get remaining properties from cached_devices. However, we
            # don't want to add all cached_devices to the devices dict since
            # they may not actually be nearby or powered on.
            if msg_path not in self._devices and msg_path in self._cached_devices:
                self._devices[msg_path] = self._cached_devices[msg_path]
            self._devices[msg_path] = ({
                **self._devices[msg_path],
                **changed
            } if msg_path in self._devices else changed)

            if self._callback is None:
                return

            props = self._devices[msg_path]

            # Get all the information wanted to pack in the advertisement data
            _local_name = props.get("Name")
            _manufacturer_data = {
                k: bytes(v)
                for k, v in props.get("ManufacturerData", {}).items()
            }
            _service_data = {
                k: bytes(v)
                for k, v in props.get("ServiceData", {}).items()
            }
            _service_uuids = props.get("UUIDs", [])

            # Pack the advertisement data
            advertisement_data = AdvertisementData(
                local_name=_local_name,
                manufacturer_data=_manufacturer_data,
                service_data=_service_data,
                service_uuids=_service_uuids,
                platform_data=(props, message),
            )

            device = BLEDevice(props["Address"], props["Alias"], props,
                               props.get("RSSI", 0))

            self._callback(device, advertisement_data)

        elif (message.member == "InterfacesRemoved"
              and message.body[1][0] == defs.BATTERY_INTERFACE):
            logger.debug("{0}, {1} ({2}): {3}".format(message.member,
                                                      message.interface,
                                                      message.path,
                                                      message.body))
            return
        else:
            msg_path = message.path
            logger.debug("{0}, {1} ({2}): {3}".format(message.member,
                                                      message.interface,
                                                      message.path,
                                                      message.body))

        logger.debug("{0}, {1} ({2} dBm), Object Path: {3}".format(
            *_device_info(msg_path, self._devices.get(msg_path))))
예제 #13
0
 async def start(self):
     """Start scanning for devices."""
     for device in devices:
         self._callback(device, AdvertisementData())
예제 #14
0
async def test_tracking_battery_successful(hass, mock_bluetooth,
                                           mock_device_tracker_conf):
    """Test tracking the battery gets a value."""

    address = "DE:AD:BE:EF:13:37"
    name = "Mock device name"
    entity_id = f"{DOMAIN}.{slugify(name)}"

    with patch(
            "homeassistant.components.bluetooth.async_discovered_service_info"
    ) as mock_async_discovered_service_info, patch.object(
            device_tracker, "MIN_SEEN_NEW", 3):

        device = BluetoothServiceInfoBleak(
            name=name,
            address=address,
            rssi=-19,
            manufacturer_data={},
            service_data={},
            service_uuids=[],
            source="local",
            device=BLEDevice(address, None),
            advertisement=AdvertisementData(local_name="empty"),
            time=0,
            connectable=True,
        )
        # Return with name when seen first time
        mock_async_discovered_service_info.return_value = [device]

        config = {
            CONF_PLATFORM: "bluetooth_le_tracker",
            CONF_SCAN_INTERVAL: timedelta(minutes=1),
            CONF_TRACK_BATTERY: True,
            CONF_TRACK_BATTERY_INTERVAL: timedelta(minutes=2),
            CONF_TRACK_NEW: True,
        }
        result = await async_setup_component(hass, DOMAIN, {DOMAIN: config})
        assert result

        # Tick until device seen enough times for to be registered for tracking
        for _ in range(device_tracker.MIN_SEEN_NEW - 1):
            async_fire_time_changed(
                hass,
                dt_util.utcnow() + config[CONF_SCAN_INTERVAL] +
                timedelta(seconds=1),
            )
            await hass.async_block_till_done()

        with patch(
                "homeassistant.components.bluetooth_le_tracker.device_tracker.BleakClient",
                MockBleakClientBattery5,
        ):
            # Wait for the battery scan
            async_fire_time_changed(
                hass,
                dt_util.utcnow() + config[CONF_SCAN_INTERVAL] +
                timedelta(seconds=1) + timedelta(minutes=2),
            )
            await hass.async_block_till_done()

    state = hass.states.get(entity_id)
    assert state.name == name
    assert state.attributes["battery"] == 5
예제 #15
0
from bleak.backends.device import BLEDevice
from bleak.backends.scanner import AdvertisementData

from homeassistant.components.bluetooth import BluetoothServiceInfoBleak

NOT_SENSOR_PUSH_SERVICE_INFO = BluetoothServiceInfoBleak(
    name="Not it",
    address="00:00:00:00:00:00",
    device=BLEDevice("00:00:00:00:00:00", None),
    rssi=-63,
    manufacturer_data={3234: b"\x00\x01"},
    service_data={},
    service_uuids=[],
    source="local",
    advertisement=AdvertisementData(local_name="Not it"),
    time=0,
    connectable=False,
)

LYWSDCGQ_SERVICE_INFO = BluetoothServiceInfoBleak(
    name="LYWSDCGQ",
    address="58:2D:34:35:93:21",
    device=BLEDevice("00:00:00:00:00:00", None),
    rssi=-63,
    manufacturer_data={},
    service_data={
        "0000fe95-0000-1000-8000-00805f9b34fb":
        b"P \xaa\x01\xda!\x9354-X\r\x10\x04\xfe\x00H\x02"
    },
    service_uuids=["0000fe95-0000-1000-8000-00805f9b34fb"],
예제 #16
0
async def test_recovery_from_dbus_restart(hass, one_adapter):
    """Test we can recover when DBus gets restarted out from under us."""

    called_start = 0
    called_stop = 0
    _callback = None
    mock_discovered = []

    class MockBleakScanner:
        async def start(self, *args, **kwargs):
            """Mock Start."""
            nonlocal called_start
            called_start += 1

        async def stop(self, *args, **kwargs):
            """Mock Start."""
            nonlocal called_stop
            called_stop += 1

        @property
        def discovered_devices(self):
            """Mock discovered_devices."""
            nonlocal mock_discovered
            return mock_discovered

        def register_detection_callback(self, callback: AdvertisementDataCallback):
            """Mock Register Detection Callback."""
            nonlocal _callback
            _callback = callback

    scanner = MockBleakScanner()

    with patch(
        "homeassistant.components.bluetooth.scanner.OriginalBleakScanner",
        return_value=scanner,
    ):
        await async_setup_with_one_adapter(hass)

        assert called_start == 1

    start_time_monotonic = 1000
    scanner = _get_manager()
    mock_discovered = [MagicMock()]

    # Ensure we don't restart the scanner if we don't need to
    with patch(
        "homeassistant.components.bluetooth.scanner.MONOTONIC_TIME",
        return_value=start_time_monotonic + 10,
    ):
        async_fire_time_changed(hass, dt_util.utcnow() + SCANNER_WATCHDOG_INTERVAL)
        await hass.async_block_till_done()

    assert called_start == 1

    # Fire a callback to reset the timer
    with patch(
        "homeassistant.components.bluetooth.scanner.MONOTONIC_TIME",
        return_value=start_time_monotonic,
    ):
        _callback(
            BLEDevice("44:44:33:11:23:42", "any_name"),
            AdvertisementData(local_name="any_name"),
        )

    # Ensure we don't restart the scanner if we don't need to
    with patch(
        "homeassistant.components.bluetooth.scanner.MONOTONIC_TIME",
        return_value=start_time_monotonic + 20,
    ):
        async_fire_time_changed(hass, dt_util.utcnow() + SCANNER_WATCHDOG_INTERVAL)
        await hass.async_block_till_done()

    assert called_start == 1

    # We hit the timer, so we restart the scanner
    with patch(
        "homeassistant.components.bluetooth.scanner.MONOTONIC_TIME",
        return_value=start_time_monotonic + SCANNER_WATCHDOG_TIMEOUT,
    ):
        async_fire_time_changed(hass, dt_util.utcnow() + SCANNER_WATCHDOG_INTERVAL)
        await hass.async_block_till_done()

    assert called_start == 2
예제 #17
0
from homeassistant.components.bluetooth import BluetoothServiceInfoBleak

YALE_ACCESS_LOCK_DISCOVERY_INFO = BluetoothServiceInfoBleak(
    name="M1012LU",
    address="AA:BB:CC:DD:EE:FF",
    rssi=-60,
    manufacturer_data={
        465: b"\x00\x00\xd1\xf0b;\xd8\x1dE\xd6\xba\xeeL\xdd]\xf5\xb2\xe9",
        76:
        b"\x061\x00Z\x8f\x93\xb2\xec\x85\x06\x00i\x00\x02\x02Q\xed\x1d\xf0",
    },
    service_uuids=[],
    service_data={},
    source="local",
    device=BLEDevice(address="AA:BB:CC:DD:EE:FF", name="M1012LU"),
    advertisement=AdvertisementData(),
    time=0,
    connectable=True,
)

LOCK_DISCOVERY_INFO_UUID_ADDRESS = BluetoothServiceInfoBleak(
    name="M1012LU",
    address="61DE521B-F0BF-9F44-64D4-75BBE1738105",
    rssi=-60,
    manufacturer_data={
        465: b"\x00\x00\xd1\xf0b;\xd8\x1dE\xd6\xba\xeeL\xdd]\xf5\xb2\xe9",
        76:
        b"\x061\x00Z\x8f\x93\xb2\xec\x85\x06\x00i\x00\x02\x02Q\xed\x1d\xf0",
    },
    service_uuids=[],
    service_data={},
예제 #18
0
async def test_preserve_new_tracked_device_name(hass, mock_bluetooth,
                                                mock_device_tracker_conf):
    """Test preserving tracked device name across new seens."""

    address = "DE:AD:BE:EF:13:37"
    name = "Mock device name"
    entity_id = f"{DOMAIN}.{slugify(name)}"

    with patch(
            "homeassistant.components.bluetooth.async_discovered_service_info"
    ) as mock_async_discovered_service_info, patch.object(
            device_tracker, "MIN_SEEN_NEW", 3):

        device = BluetoothServiceInfoBleak(
            name=name,
            address=address,
            rssi=-19,
            manufacturer_data={},
            service_data={},
            service_uuids=[],
            source="local",
            device=BLEDevice(address, None),
            advertisement=AdvertisementData(local_name="empty"),
            time=0,
            connectable=False,
        )
        # Return with name when seen first time
        mock_async_discovered_service_info.return_value = [device]

        config = {
            CONF_PLATFORM: "bluetooth_le_tracker",
            CONF_SCAN_INTERVAL: timedelta(minutes=1),
            CONF_TRACK_NEW: True,
        }
        result = await async_setup_component(hass, DOMAIN, {DOMAIN: config})
        assert result

        # Seen once here; return without name when seen subsequent times
        device = BluetoothServiceInfoBleak(
            name=None,
            address=address,
            rssi=-19,
            manufacturer_data={},
            service_data={},
            service_uuids=[],
            source="local",
            device=BLEDevice(address, None),
            advertisement=AdvertisementData(local_name="empty"),
            time=0,
            connectable=False,
        )
        # Return with name when seen first time
        mock_async_discovered_service_info.return_value = [device]

        # Tick until device seen enough times for to be registered for tracking
        for _ in range(device_tracker.MIN_SEEN_NEW - 1):
            async_fire_time_changed(
                hass,
                dt_util.utcnow() + config[CONF_SCAN_INTERVAL] +
                timedelta(seconds=1),
            )
            await hass.async_block_till_done()

    state = hass.states.get(entity_id)
    assert state
    assert state.name == name