Building Bluetooth Apps with BTComObj in Lazarus — Step‑by‑Step

  • Main form with: device address input, Connect/Disconnect buttons, status label, a memo to show received messages, an edit box for outgoing messages, and a Send button.
  • Use BTComObj component to handle the Bluetooth link asynchronously (events).
  1. Create the UI
  • New Project → Application.
  • Place these components on the form:
    • TEdit named edtAddress (for MAC like 00:11:22:33:44:55 or COM port name)
    • TButton named btnConnect (Caption: Connect)
    • TButton named btnDisconnect (Caption: Disconnect)
    • TLabel named lblStatus (Caption: Disconnected)
    • TMemo named memLog (ReadOnly := True)
    • TEdit named edtOut
    • TButton named btnSend (Caption: Send)
  • Optionally: a TComboBox to list discovered devices if you implement scanning.
  1. Add the BTComObj component
  • From the Component Palette (after package installation) place the BTComObj component on the form (name it btSerial or BTCom).
  • If the component is not visible, add the appropriate unit to the uses clause and create it at runtime:
    
    uses ..., BTComObj; // exact unit name may vary 
  • Example runtime creation (in FormCreate):
    
    btSerial := TBTCom.Create(Self); btSerial.OnConnect := BTConnect; btSerial.OnDisconnect := BTDisconnect; btSerial.OnDataReceived := BTDataReceived; // adjust per actual event names 
  1. Connect/Disconnect logic
  • btnConnect.OnClick:
    
    procedure TForm1.btnConnectClick(Sender: TObject); begin lblStatus.Caption := 'Connecting...'; btSerial.DeviceAddress := Trim(edtAddress.Text); // if the component expects RFCOMM channel: // btSerial.Channel := 1;  try btSerial.Connect; except on E: Exception do begin   lblStatus.Caption := 'Connect error';   memLog.Lines.Add('Connect error: ' + E.Message); end; end; end; 
  • btnDisconnect.OnClick:
    
    procedure TForm1.btnDisconnectClick(Sender: TObject); begin btSerial.Disconnect; end; 
  1. Handle connection events “`pascal procedure TForm1.BTConnect(Sender: TObject); begin lblStatus.Caption := ‘Connected’; memLog.Lines.Add(‘Connected to ’ + btSerial.DeviceAddress); end;

procedure TForm1.BTDisconnect(Sender: TObject); begin lblStatus.Caption := ‘Disconnected’; memLog.Lines.Add(‘Disconnected’); end;


5) Sending data - btnSend.OnClick: ```pascal procedure TForm1.btnSendClick(Sender: TObject); var   s: string; begin   s := edtOut.Text;   if s = '' then Exit;   // Append newline if desired by device   btSerial.Write(s + #13#10);   memLog.Lines.Add('Sent: ' + s);   edtOut.Clear; end; 
  1. Receiving data
  • Event handler (the exact signature depends on BTComObj):
    
    procedure TForm1.BTDataReceived(Sender: TObject; const AData: string); begin // Called in main thread or synchronised callback depending on component memLog.Lines.Add('Recv: ' + AData); end; 
  • If the component delivers raw bytes, convert to string first:
    
    var buf: array of byte; s: string; begin // convert buf to string depending on encoding, e.g. ANSI/UTF-8 s := TEncoding.UTF8.GetString(buf); memLog.Lines.Add('Recv: ' + s); end; 
  1. Threading and Synchronization
  • Many BT components raise events in background threads. If you update UI controls from those events, ensure you synchronise to the main thread (use TThread.Synchronize or TThread.Queue). Example:
    
    procedure TForm1.BTDataReceived(Sender: TObject; const AData: string); begin TThread.Queue(nil, procedure begin   memLog.Lines.Add('Recv: ' + AData); end); end; 

Advanced Features & Tips

  • Device Discovery: Add a discovery routine to list nearby devices and their addresses/channels. On Linux, BlueZ may require running discovery via system tools (hcitool/ bluetoothctl) or using DBus APIs; BTComObj may wrap discovery for you.
  • Auto-reconnect: Implement logic to attempt reconnects with exponential backoff if the connection drops.
  • Flow control & buffering: Some devices send bursts; buffer incoming data and parse complete messages (e.g., newline-terminated).
  • Binary data: If communicating with binary protocols, treat data as bytes. Use checksums/length prefixes to delineate messages.
  • BLE vs Classic: BTComObj primarily targets classic RFCOMM/SPP. For Bluetooth Low Energy (BLE) you’ll need libraries that support GATT (CoreBluetooth on macOS/iOS, BlueZ D-Bus LE APIs on Linux, Windows BluetoothLE APIs).
  • Permissions: On Linux, add your user to the bluetooth group or create udev rules for RFCOMM devices. On Windows, ensure pairing is done and COM port is assigned if using virtual COM.
  • Logging: Enable detailed logs during development; many connection issues are due to pairing, wrong channel, or interference.

Debugging Checklist

  • Is the device powered and in discoverable mode? HC‑05 often needs AT mode to change settings; normal mode to connect.
  • Is the correct MAC address or COM port used?
  • Are drivers and BlueZ (Linux) up-to-date?
  • Has the device been paired? On Windows, pairing may create a COM port.
  • Is your app handling threading correctly (UI updates from background threads)?
  • Try a serial terminal (PuTTY, cutecom) to verify the Bluetooth-to-serial link works outside your app.
  • Check permissions: do you need root or extra capabilities on Linux?
  • Use packet/log captures (BlueZ debug logging, Windows Event Viewer, or component logging) to diagnose low-level failures.

Packaging and Distribution

  • When deploying, ensure the target machines have the necessary Bluetooth stack and drivers.
  • On Windows, if your app depends on virtual COM ports from pairing, document pairing steps for users.
  • Provide installers or scripts to register any required runtime packages or third-party DLLs if BTComObj uses them.
  • Test on each target OS/version — Bluetooth behavior diverges between platforms.

Example: Parsing a Line-Based Protocol (Robust receive)

If your device sends newline-terminated messages, use a receive buffer and emit lines only when complete:

var   RecvBuffer: string = ''; procedure TForm1.BTDataReceived(Sender: TObject; const AData: string); begin   TThread.Queue(nil,     procedure     var       i: Integer;       lines: TArray<string>;     begin       RecvBuffer := RecvBuffer + AData;       lines := RecvBuffer.Split([sLineBreak]);       for i := 0 to High(lines)-1 do         memLog.Lines.Add('Line: ' + lines[i]);       RecvBuffer := lines[High(lines)]; // remainder     end); end; 

Common Pitfalls

  • Expecting BLE to behave like SPP — they are different. SPP is serial-style; BLE is characteristic-based.
  • Updating UI directly from non-main threads — causes crashes or weird behavior.
  • Hardcoding RFCOMM channel numbers — some devices use different channels; discovery returns available channels.
  • Not handling partial messages — TCP/serial-like streams can split messages.

Further Reading & Resources

  • BTComObj documentation and source (check repository or package readme).
  • BlueZ (Linux) developer documentation for RFCOMM and D-Bus APIs.
  • Microsoft Bluetooth API documentation for classic and LE differences.
  • Lazarus and FPC threading guidelines (TThread.Queue / Synchronize).

Building Bluetooth apps with BTComObj in Lazarus gives you a pragmatic path to integrating classic Bluetooth serial devices into Pascal desktop applications. Start with a small test app (like the chat example above), verify connectivity with a terminal, then add parsing, reconnection, and UI polish.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *