First off — thank you for the great library.
Description
I'm encountering an issue on Windows where a modified 128-bit characteristic UUID is not reflected in Bleak after updating my peripheral firmware. The service UUID appears correctly, but the characteristic UUID remains stuck at its previous value.
This looks like a Windows GATT caching issue, but I want to confirm whether:
- This is expected OS behavior.
- Bleak provides a way to force fresh service discovery.
- The previously merged Windows caching fixes (e.g., feat/windows-caching-issue) should already handle this case.
Peripheral
Custom embedded device (Nordic nRF52 running Zephyr).
- Originally:
- Service UUID:
562326d3-a8e8-43c4-b783-daa2145291f1
- Characteristic UUID:
562326d4-a8e8-43c4-b783-daa2145291f1
I then changed the characteristic UUID.
- Updated:
- Service UUID:
562326d3-a8e8-43c4-b783-daa2145291f1
- Characteristic UUID:
5c64d0cf-3ea7-42c7-9e92-844e3b345402
This is verified using nRF Connect (via nRF USB dongle), which correctly shows the updated UUID; see image below.
Environment
- bleak 2.1.1
- Windows 11
- Python 3.14.3
Supporting Info
"""
Scan/Discovery
--------------
Example showing how to scan for BLE devices.
Updated on 2019-03-25 by hbldh <henrik.blidh@nedomkull.com>
"""
import argparse
import asyncio
import logging
from contextlib import asynccontextmanager
from bleak import BleakScanner, BleakClient
logger = logging.getLogger(__name__)
class Args(argparse.Namespace):
debug: bool
async def active_scan(duration_s: int):
devices = await BleakScanner.discover(
return_adv=True,
timeout=duration_s,
scanning_mode="active",
)
for device_data, advertisement_data in devices.values():
logger.info("=" * 40)
logger.info(device_data)
logger.info(advertisement_data)
class DeviceNotFoundError(Exception):
"""Raised when a BLE device cannot be found."""
pass
@asynccontextmanager
async def connect_to_device(device_name: str, timeout_s: int = 5):
device = await BleakScanner.find_device_by_name(
name=device_name,
timeout=timeout_s,
scanning_mode="active",
)
if device is None:
raise DeviceNotFoundError(f"Failed to find device with name '{device_name}'")
async with BleakClient(device) as client:
yield client
async def main(args: Args):
logger.debug("entering main")
# scan_time_s = 2
# async def scanner_worker():
# while True:
# ble_min_advertisement_period_s = 0.020
# await active_scan(duration_s=ble_min_advertisement_period_s)
# try:
# await asyncio.wait_for(scanner_worker(), timeout=scan_time_s)
# except asyncio.TimeoutError:
# logger.debug(f"Scan stopped after {scan_time_s} seconds")
async with connect_to_device("Silas ROM") as client:
logger.info(client.is_connected)
for service in client.services:
logger.info(f"service w/ desc='{service.description}', uuid='{service.uuid}'")
for char in service.characteristics:
logger.info(f" Characteristic: uuid='{char.uuid}', props={char.properties}")
# Find the Characteristic User Description (CUD) descriptor
for descriptor in char.descriptors:
logger.info(f" Descriptor: uuid='{descriptor.uuid}'")
# if descriptor.uuid == "2901": # Standard CUD UUID
# cud_value = await client.read_gatt_descriptor(descriptor.handle)
# logger.info(f" CUD: {cud_value.decode('utf-8')}")
await asyncio.sleep(10)
if __name__ == "__main__":
# parse cli args
parser = argparse.ArgumentParser()
parser.add_argument(
"-d",
"--debug",
action="store_true",
help="sets the logging level to debug",
)
args = parser.parse_args(namespace=Args())
# setup logging
log_level = logging.DEBUG if args.debug else logging.INFO
logging.basicConfig(
level=log_level,
format="%(asctime)-15s %(name)-8s %(levelname)s: %(message)s",
)
asyncio.run(main(args))
> python .\main.py
2026-02-21 22:15:18,074 __main__ INFO: True
2026-02-21 22:15:18,074 __main__ INFO: service w/ desc='Generic Attribute Profile', uuid='00001801-0000-1000-8000-00805f9b34fb'
2026-02-21 22:15:18,075 __main__ INFO: Characteristic: uuid='00002a05-0000-1000-8000-00805f9b34fb', props=['indicate']
2026-02-21 22:15:18,075 __main__ INFO: Descriptor: uuid='00002902-0000-1000-8000-00805f9b34fb'
2026-02-21 22:15:18,075 __main__ INFO: service w/ desc='Generic Access Profile', uuid='00001800-0000-1000-8000-00805f9b34fb'
2026-02-21 22:15:18,075 __main__ INFO: Characteristic: uuid='00002a00-0000-1000-8000-00805f9b34fb', props=['read']
2026-02-21 22:15:18,075 __main__ INFO: Characteristic: uuid='00002a01-0000-1000-8000-00805f9b34fb', props=['read']
2026-02-21 22:15:18,075 __main__ INFO: Characteristic: uuid='00002a04-0000-1000-8000-00805f9b34fb', props=['read']
2026-02-21 22:15:18,075 __main__ INFO: service w/ desc='Unknown', uuid='562326d3-a8e8-43c4-b783-daa2145291f1'
2026-02-21 22:15:18,075 __main__ INFO: Characteristic: uuid='562326d4-a8e8-43c4-b783-daa2145291f1', props=['read']
First off — thank you for the great library.
Description
I'm encountering an issue on Windows where a modified 128-bit characteristic UUID is not reflected in Bleak after updating my peripheral firmware. The service UUID appears correctly, but the characteristic UUID remains stuck at its previous value.
This looks like a Windows GATT caching issue, but I want to confirm whether:
Peripheral
Custom embedded device (Nordic nRF52 running Zephyr).
562326d3-a8e8-43c4-b783-daa2145291f1562326d4-a8e8-43c4-b783-daa2145291f1I then changed the characteristic UUID.
562326d3-a8e8-43c4-b783-daa2145291f15c64d0cf-3ea7-42c7-9e92-844e3b345402This is verified using nRF Connect (via nRF USB dongle), which correctly shows the updated UUID; see image below.
Environment
Supporting Info