Delphi 10.3 BTLE心率服务发现异常:需配对及设备发现事件未触发咨询
Let's break down your core misunderstandings first, then walk through practical fixes for your code:
1. Misconception: BLE Never Requires Pairing
You’re correct that most standard BLE services (like Heart Rate) are designed for open access, but Windows (and Delphi’s BLE implementation) may still trigger implicit pairing/bonding when accessing services with underlying security requirements. Even if your device doesn’t show a manual pairing prompt, the OS might initiate a background pairing process when you attempt to discover services—this is what’s throwing your exception. You don’t need pre-pair manually, but you do need to let the OS handle automatic pairing requests.
2. Misconception: OnEndDiscoverDevices Only Triggers When Cancelled
The OnEndDiscoverDevices event should fire both when the scan interval expires naturally AND when you call CancelDiscovery. The reason it only fires on cancel is your timCancel timer cuts the scan short before the 18-second interval finishes. If you let the scan run to completion without cancelling, the event will trigger automatically.
Also, BTLE.DiscoverDevices() handles the timeout internally—you don’t need a manual timer to cancel it. Your current timer overrides the natural scan completion flow.
3. Misconception: You Can Discover Services Without Connecting First
In your tvDevicesClick handler, you’re calling aDev.DiscoverServices() directly without establishing a connection to the device first. For BLE, you must connect to the device before you can discover its services. The DiscoverServices method tries to connect implicitly, but if that connection triggers an unhandled pairing request, it throws an exception.
Code Fixes to Resolve These Issues
Fix 1: Let Scans Complete Naturally (Fix OnEndDiscoverDevices)
Remove the timCancel timer logic from Button1Click—let DiscoverDevices handle the timeout on its own:
procedure TForm1.Button1Click(Sender: TObject); begin tvDevices.Items.Clear; // Let DiscoverDevices manage the 18-second timeout internally if BTLE.DiscoverDevices(18000, [HRSERVICE]) then memLog.Lines.Add('Scan started successfully'); end;
You can delete the timCancelTimer procedure and remove the timer from your form entirely, or add a dedicated "Stop Scan" button if you need manual cancellation.
Fix 2: Connect Before Discovering Services
Modify your tvDevicesClick handler to first connect to the selected device, then discover services once connected. Add an OnConnected event to your TBluetoothLE component:
// Add this event to your BTLE component via the form designer procedure TForm1.BTLEConnected(const Sender: TObject; const ADevice: TBluetoothLEDevice); begin memLog.Lines.Add('Connected to ' + ADevice.DeviceName); // Discover services only after successful connection ADevice.DiscoverServices; end; procedure TForm1.tvDevicesClick(Sender: TObject); var SelectedDeviceName: string; aDev : TBluetoothLEDevice; begin if tvDevices.Selected = nil then Exit; SelectedDeviceName := tvDevices.Selected.Text; for aDev in btle.CurrentManager.AllDiscoveredDevices do begin if (aDev.DeviceName = SelectedDeviceName) or (aDev.Identifier = SelectedDeviceName) then begin memLog.Lines.Add('Attempting to connect to ' + SelectedDeviceName); // Initiate connection to the device aDev.Connect; Break; end; end; end;
Fix 3: Handle Pairing Requests (If Needed)
If the OS prompts for pairing, auto-accept requests for your device by adding an OnPairingRequest event to TBluetoothLE:
// Add this event to your BTLE component via the form designer procedure TForm1.BTLEPairingRequest(const Sender: TObject; const ADevice: TBluetoothLEDevice; var PairingAccepted: Boolean); begin // Auto-accept pairing for your heart rate device PairingAccepted := True; memLog.Lines.Add('Accepting pairing request for ' + ADevice.DeviceName); end;
Quick Bug Fix
Your bytesToStr function has an off-by-one error—change:
for i := 0 to Length(aval) do
to:
for i := 0 to Length(aval) - 1 do
This prevents accessing an index beyond the array’s bounds.
内容的提问来源于stack exchange,提问作者mrabat




