Working with ThingConnect Devices

From IoT
Jump to: navigation, search

Go Up to ThingConnect


To use a Bluetooth LE device in your application, you need to follow these procedures.

Connecting with the Devices

To connect with a Bluetooth LE device in your application, you need to:

  1. Drop a TBluetoothDeviceDiscoveryManager component.
  2. Drop the corresponding component for the Bluetooth LE device.
  3. In the Object Inspector, set the DiscoveryManager property of the Bluetooth LE component to the TBluetoothDeviceDiscoveryManager.
  4. Set the appropriate discovery mechanism in the DiscoveryMethod property of the TBluetoothDeviceDiscoveryManager.
  5. To connect to the actual device you need to call the method DiscoverDevices of the TBluetoothDeviceDiscoveryManager.

    Delphi:

      FDiscoveryManager.DiscoverDevices;
    

    C++:

      FDiscoveryManager->DiscoverDevices();
    
  6. After connecting to the device, the OnDeviceConnected event of the corresponding component is called.
  7. Add the following units to the Uses clause of the application:
    • Iot.Family.BluetoothLE.GattTypes
    • The custom Types unit (if the component defines custom data types).

Setting the Discovery Mechanism Method

To set the discovery mechanism method of the Bluetooth LE devices in your application, you can either:

  • In the Object Inspector, use the DiscoveryMethod property.
  • Set the discovery mechanism by code before calling the DiscoverDevices method:

Delphi:

{$IF Defined(WIN32) or Defined(WIN64)}
FDiscoveryManager.DiscoveryMethod := TDiscoveryMethod.Connect;
{$ELSE}
FDiscoveryManager.DiscoveryMethod := TDiscoveryMethod.ScanResponse;
{$EndIf}

C++:

#ifdef _Windows
FDiscoveryManager->DiscoveryMethod = TDiscoveryMethod::Connect;
#else
FDiscoveryManager->DiscoveryMethod = TDiscoveryMethod::ScanResponse;
#endif
  • Note: For 32-bit Windows and 64-bit Windows platforms applications, you need to set Connect as the discovery method type.
Warning: Some devices do not broadcast their name or services in the advertised data. You need to use the Connect discovery method instead, and set manually the name of the device you want to connect to.

Using the ScanResponseAllDevices Discovery Mechanism Method

If you use the ScanResponseAllDevices discovery mechanism method to connect to a given device, you need to retrieve the name of the DiscoveredDevice from the list.

  1. Implement the OnGenericHeartRateMonitor1DeviceListDiscovered event handler to retrieve the list of discovered devices. In this code sample, the discovered devices are added to a TlistBox.

    Delphi:

    procedure TForm1.GenericHeartRateMonitor1DeviceListDiscovered(const Sender: TObject; const ADiscoveredDeviceCount: Integer);
    var
      I: Integer;
    begin
      for I := 0 to ADiscoveredDeviceCount - 1 do
        ListBox1.Items.Add(GenericHeartRateMonitor1.DiscoveredDevice[I].DeviceName);
    end;
    

    C++:

    void __fastcall TForm1::GenericHeartRateMonitor1DeviceListDiscovered(TObject * const Sender, const int ADiscoveredDeviceCount)
    {
      for (int I = 0; I < ADiscoveredDeviceCount; I++) {
        ListBox1->Items->Add() = GenericHeartRateMonitor1->DiscoveredDevice[I]->DeviceName;
      }
    }
    
  2. Use the ConnectDevice method to connect to the selected DiscoveredDevice. This item is retrieved from the TListBox.

    Delphi:

    procedure TForm1.ListBox1ItemClick(const Sender: TCustomListBox; const Item: TListBoxItem);
    begin
      GenericHeartRateMonitor1.ConnectDevice(GenericHeartRateMonitor1.DiscoveredDevice[Item.Index]);
    end;
    

    C++:

    void __fastcall TForm1::ListBox1ItemClick(TCustomListBox * const Sender, TListBoxItem * const Item)
    {
      TBluetoothLEDevice *LDevice;
      LDevice = GenericHeartRateMonitor1->DiscoveredDevice[AItem->Index];
      GenericHeartRateMonitor1->ConnectDevice(LDevice);
    }
    

Reading a Property Data

To read the data value of a property you need to call the Refresh method and implement the event handler of the event.

For example, to read the data value of the BatteryLevel property add the following code:

Delphi:

procedure TForm1.ReadPropertyClick(Sender: TObject);
begin
  ZephyrHeartRateMonitor.RefreshBatteryLevel;
end;

C++:

void __fastcall TForm1::ReadPropertyClick(TObject *Sender)
{
  ZephyrHeartRateMonitor1->RefreshBatteryLevel();
}

Event Handler

On the readable properties, the event handler is raised when the data is received after calling the Refresh method. This kind of events are called On<NameOfTheProperty>Update.

Following the above example, to implement the event handler of the OnBatteryLevelUpdate event use the following code snippet:

Delphi:

uses
Iot.Family.BluetoothLE.GattTypes, Iot.Device.ZephyrHeartRateMonitorTypes;

var BatteryLevelText : UnicodeString;

procedure TForm1.ZephyrHeartRateMonitorBatteryLevelUpdate(Sender: TObject; Value: Byte);
begin
  BatteryLevelText := IntToStr(Value) + '%';
end;

C++:

  • In the .h file, add the Uses clause:
#include <Iot.Family.BluetoothLE.GattTypes.hpp>
#include <Iot.Device.ZephyrHeartRateMonitorTypes.hpp>
  • In the .cpp file:
void __fastcall TForm1::ZephyrHeartRateMonitor1BatteryLevelUpdate (TObject *Sender, BYTE Value)
{
  UnicodeString BateryLevel = IntToStr(Value) + "%";
}

Subscribing to a Characteristic

To subscribe to a characteristic, you need to call the Subscribe method of the characteristic and implement the event handler of the event.

For example, to subscribe to the Heart Rate Measurement characteristic add the following code:

Delphi:

procedure TForm1.HRMSubscribeBtnClick(Sender: TObject);
begin
  ZephyrHeartRateMonitor.SubscribeHeartRateMeasurement;
end;

C++:

void __fastcall TForm1::HRMSubscribeBtnClick(TObject *Sender)
{
  FZephyrHeartRateMonitor->SubscribeHeartRateMeasurement();
}

Event Handler

To start receiving data updates from a subscribed characteristic, you need to implement the event handler of the event.

For example, to receive heart rate measurement updates, implement the event handler of the OnHeartRateMeasurementUpdate event as follow:

Delphi:

uses
Iot.Family.BluetoothLE.GattTypes, Iot.Device.ZephyrHeartRateMonitorTypes;

var HRMValueText : UnicodeString;

procedure TForm1.ZephyrHeartRateMonitorHeartRateMeasurementUpdate(Sender: TObject; const Value: TGattHeartRateMeasurement);
begin
  HRMValueText := 'HR: ' + IntToStr(Value.HeartRateMeasurement) + 'bpm RRInterval: ' + IntToStr(Value.RRInterval) + ' EnergyExp: ' + IntToStr(Value.EnergyExpended) +
  ' Contact: ' + IntToStr(Ord(Value.ContactStatus));
end;

C++:

  • In the .h file:
#include <Iot.Family.BluetoothLE.GattTypes.hpp>
#include <Iot.Device.ZephyrHeartRateMonitorTypes.hpp>
  • In the .cpp file:
void __fastcall TForm1::FZephyrHeartRateMonitorHeartRateMeasurementUpdate(TObject *Sender, const TGattHeartRateMeasurement &Value)
{
  TGattHeartRateMeasurement Ghrm = Value;
  UnicodeString HRMValueText = "HR: " + IntToStr(Ghrm.HeartRateMeasurement) + " bpm RRInterval : " + IntToStr(Ghrm.RRInterval) + " EnergyExp : " + IntToStr(Ghrm.EnergyExpended) +
  " Contact:" + IntToStr((int)Ghrm.ContactStatus);
}

Unsubscribing from a Characteristic

To unsubscribe from a characteristic, you need to call the Unsubscribe method of that characteristic.

For example, to unsubscribe from the Heart Rate Measurement characteristic add the following code:

Delphi:

procedure TForm1.HRMUnSubscribeBtnClick(Sender: TObject);
begin
  ZephyrHeartRateMonitor.UnsubscribeHeartRateMeasurement;
end;

C++:

void __fastcall TForm1::HRMUnSubscribeBtnClick(TObject *Sender)
{
  FZephyrHeartRateMonitor->UnsubscribeHeartRateMeasurement();
}

Writing to a Characteristic

To write to a characteristic, you need to set the corresponding property of the component. To do so, use the Create method of that characteristic, pass the needed values and then set the values to it. Moreover, you can implement an event handler to obtain the status information of the writing operation.

For example, to update the light color of the IoT light bulb you need to set the ControlCharacter property of the component. To write to this property add the following code:

Delphi:

uses
System.UIConsts;

procedure TForm1.SetColorClick(Sender: TObject);
var
  LColor: TAlphaColor;
  LIntensity: Integer;
begin
  LIntensity := 80;
  LColor := claOrange; //System.UITypes.TAlphaColor
  YeelightBlue1.ControlCharacter := TControlCharacter.Create(LColor, LIntensity);
end;

C++:

void __fastcall TForm1::SetColorClick(TObject *Sender)
{
  int LIntensity = 80;
  TAlphaColor LColor =   TAlphaColor(claGreen); //System.UITypes.TAlphaColor
  YeelightBlue1->ControlCharacter = TControlCharacter(LColor, LIntensity);
}

Event Handler

On the writable properties, you can implement an event to obtain information about the status of the writing operation. This kind of events, which are named On<NameOfTheProperty>WriteStatus, return the status at the end of the writing operation. These are the possible statuses.

To implement the write status event handler use the following code snippet:

Delphi:

procedure TForm1.YeelightBlue1ControlCharacterWriteStatus(Sender: TObject; const Status: TBluetoothGattStatus);
begin
  case Status of
    TBluetoothGattStatus.Success: ShowMessage('The operation finished successfully');
    TBluetoothGattStatus.ReadNotPermitted: ShowMessage('The read operation is not permitted');
    TBluetoothGattStatus.WriteNotPermitted: ShowMessage('The write operation is not permitted');
    TBluetoothGattStatus.InsufficientAutentication: ShowMessage('Your authentication data is valid but it does not authorize you to perform the operation. You do not have the
    required permissions');
    TBluetoothGattStatus.RequestNotSupported: ShowMessage('The operation is not supported');
    TBluetoothGattStatus.InvalidOffset: ShowMessage('The offset specified in your operation is not valid');
    TBluetoothGattStatus.InvalidAttributeLength: ShowMessage('The length of the specified value is not valid for the target attribute');
    TBluetoothGattStatus.InsufficientEncryption: ShowMessage('The encryption used for the operation is not strong enough');
    TBluetoothGattStatus.Failure: ShowMessage('An unspecified error prevented the operation from succeeding.');
  end;
end;

C++:

void __fastcall TForm1::YeelightBlue1ControlCharacterWriteStatus(TObject *Sender, const TBluetoothGattStatus Status);
{
  switch (status) {
    case TBluetoothGattStatus::Success:
      ShowMessage('The operation finished successfully');
      break;
    case TBluetoothGattStatus::ReadNotPermittedReadNotPermitted 
      ShowMessage('The read operation is not permitted');
     break;
    case TBluetoothGattStatus::WriteNotPermitted:
      ShowMessage('The write operation is not permitted');
      break;
    case TBluetoothGattStatus::InsufficientAutentication
      ShowMessage('The read operation is not permitted');
     break;
    case TBluetoothGattStatus::RequestNotSupported:
      ShowMessage('Your authentication data is valid but it does not authorize you to perform the operation. You do not have the required permissions');
      break;
    case TBluetoothGattStatus::InvalidOffset
      ShowMessage('The operation is not supported');
     break; 
    case TBluetoothGattStatus::InsufficientAutentication
      ShowMessage('The offset specified in your operation is not valid');
     break;
    case TBluetoothGattStatus::InvalidAttributeLength:
      ShowMessage('The length of the specified value is not valid for the target attribute');
      break;
    case TBluetoothGattStatus::InsufficientEncryption
      ShowMessage('The encryption used for the operation is not strong enough');
     break;   
    case TBluetoothGattStatus::Failure
      ShowMessage('An unspecified error prevented the operation from succeeding');
     break;
  } 
}

Error Handling

While connecting to the device, different errors may raise that you need to handle:

Error Component Description
OnGeneralDiscoveryError TBluetoothDeviceDiscoveryManager

The manager can not find any nearby device from that type.

The procedure also has an additional parameter, Handled. If you want to handle the exception yourself, set Handled to True.

TGeneralDiscoveryErrorEvent = procedure(const Sender: TObject; const AException: Exception; var Handled: Boolean) of object;
OnDeviceConnectionError Bluetooth LE component The component can not find the device.

See Also