Developing the Internet of Things: Zephyr Heart Rate Monitor
Appmethod continues to expand support for the ever-increasing Internet of Things ecosystem. Appmethod users can build mobile and desktop apps that connect, read, and integrate data from Bluetooth LE and Wifi enabled devices. This week we're showcasing the HxM heart rate monitor mobile health wearable from Zephyr.
Appmethod Tethering with Bluetooth LE
This tutorial explores the Zephyr HxM Heart Rate Monitor demo project that ships with Appmethod. By breaking down this demo you will learn how to analyze a GATT profile and read in information broadcasted from a Bluetooth LE device.
Appmethod features the TBluetoohLE component that provides complete support for Bluetooth LE. You can use this component within your apps to discover, capture, and process data from connected Bluetooth Smart Devices via their GATT profiles.
Exploring the Heart Rate Monitor Demo Project
The latest build for the Heart Rate Monitor project can be found on Sourceforge. They come in both C++ and Object Pascal languages.
Open the Project
Open up the project and look for the BluetoothLE1 component in the Form Designer. Ensure that the Design View is selected at the Master level. Select the BluetoothLE1 component and open the Events tab within the Object Inspector window.
Respond to Events
Double clicking on an event from within the Object Inspector will open up and jump to the associated source code definition. Appmethod will automatically create the empty event handler for you. That way the programmer can focus on implementing application logic rather than having to code up the same event handler signatures over and over again.
The application uses a TButton and an OnClick event defined by the btnScanClick method that in turn calls DoScan.
Button Click Event
//--------------------------------------------------------------------------- void __fastcall TfrmHeartMonitor::btnScanClick(TObject *Sender) { DoScan(); } //--------------------------------------------------------------------------- void __fastcall TfrmHeartMonitor::DoScan(void) { ClearData(); lblDevice->Text = ""; lblBodyLocation->Text = ""; lblContactStatus->Text = ""; std::auto_ptr AList(new GUID(HRSERVICE)); BluetoothLE1->DiscoverDevices(2500, AList.get(), 1); }
The DiscoverDevices method of the BluetoothLE component will attempt to discover all available Bluetooth devices. The timeout is set for 2500 milliseconds. This timeout may be increased in situations with heavy Bluetooth traffic.
The Heartrate Monitor application uses three events of the TBluetoothLE component:
- BluetoothLE1CharacteristicRead
- BluetoothLE1DescriptorRead
- BluetoothLE1EndDiscoverDevices
Bluetooth Caracteristic Read Event
//--------------------------------------------------------------------------- void __fastcall TfrmHeartMonitor::BluetoothLE1CharacteristicRead(TObject * const Sender, TBluetoothGattCharacteristic * const ACharacteristic, TBluetoothGattStatus AGattStatus) { if(AGattStatus != TBluetoothGattStatus::Success) { Memo1->Lines->Add("Error reading Characteristic " + ACharacteristic->UUIDName + ": " + IntToStr(static_cast(AGattStatus))); } else { String LSValue = BytesToString(ACharacteristic->Value); Memo1->Lines->Add(ACharacteristic->UUIDName + " Value: " + LSValue); ManageCharacteristicData(ACharacteristic); //IT PROCESSES THE DATA AND UPDATES DE BPM DISPLAY } }
A device broadcasting BluethoothLE data is read by the application through the OnCharacteristicRead event that is defined by the BluetoothLE1CharacteristicRead method.
First we use the passed in AGattStatus flag to ensure that the connected device was successfully read. If so, then the ACharacteristic object is read from and converted to a long string for use with the TMemo component. This will effectively trace out the raw sensor data to the application UI. Lastly, the utility function ManageCharacterisitcData is called to process the current sensor data for display by the application logic.
If AGattStatus is not successful the error code is traced out to the TMemo.
Bluetooth Descriptor Read Event
//--------------------------------------------------------------------------- void __fastcall TfrmHeartMonitor::BluetoothLE1DescriptorRead(TObject * const Sender, TBluetoothGattDescriptor * const ADescriptor, TBluetoothGattStatus AGattStatus) { if(AGattStatus != TBluetoothGattStatus::Success) { Memo1->Lines->Add("Error reading Characteristoc " + ADescriptor->UUIDName + ": " + StrToInt(static_cast(AGattStatus))); } else { String LSValue = BytesToString(ADescriptor->GetValue()); Memo1->Lines->Add(ADescriptor->UUIDName + " Value: " + LSValue); } }
A device broadcasting BluethoothLE descriptor data is read by the application through the OnDescriptorRead event that is defined by the BluetoothLE1DescriptorRead method.
This method traces out the descriptor event to the TMemo.
Bluetooth End Discover Devices Event
//--------------------------------------------------------------------------- void __fastcall TfrmHeartMonitor::BluetoothLE1EndDiscoverDevices(TObject * const Sender, TBluetoothLEDeviceList * const ADeviceList) { Memo1->Lines->Add(IntToStr(ADeviceList->Count) + " devices discovered:"); for (int i = 0; i < ADeviceList->Count; i++) { Memo1->Lines->Add(ADeviceList->Items[i]->DeviceName); } if(BluetoothLE1->DiscoveredDevices->Count > 0) { FBLEDevice = BluetoothLE1->DiscoveredDevices->First(); lblDevice->Text = HRDeviceName; if(BluetoothLE1->GetServices(FBLEDevice)->Count == 0) { Memo1->Lines->Add("No services found!"); lblBPM->Font->Size = 26; lblBPM->Text = "No services found!"; } else { GetServiceAndCharacteristics(); } } else { lblDevice->Text = "Device not found"; } }
Lastly we analyze the BluetoothLE discovery phase. It is handled by the OnEndDiscoverDevices event and is implemented by the BluetoothLE1EndDiscoverDevices method.
ADeviceList contains an array of all discovered BluetoothLE devices. The method begins by looping over each found device and traces out the device name to the TMemo.
Once a device has been found, the next step is to determine if that device has any consumable services. If a service is found then the GetServiceAndCharacteristics is called to begin processing device data with application logic.
Test The Application
When the application is run the Zephyer Heart Rate Monitor device information is displayed by a TMemo component.


Comments
-
Please login first in order for you to submit comments