private async Task _disconnect()
        {
            try
            {
                _characteristicHR.ValueUpdated -= CharacteristicHR_ValueUpdated;
                await _characteristicHR.StopUpdatesAsync();

                await _adapter.DisconnectDeviceAsync(_device);

                _connectionRetry            = 0;
                _device                     = null;
                _serviceHR                  = null;
                _serviceBattery             = null;
                _characteristicHR           = null;
                _characteristicBatteryLevel = null;
                _currentValue               = null;

                _log("_disconnect", "disconnected");
            }
            catch (Exception e)
            {
                _log("_disconnect", e.Message);
            }
        }
        private async void CharacteristicHR_ValueUpdated(object sender, Plugin.BLE.Abstractions.EventArgs.CharacteristicUpdatedEventArgs args)
        {
            // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.heart_rate_measurement.xml
            // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.characteristic.battery_level.xml

            try
            {
                int heartValue;
                var bytes = args.Characteristic.Value;

                byte flags = bytes[0];
                int  header;

                if ((flags & 0x1) == 0x1)
                {
                    // HB data is 16 bits (bytes[2]bytes[1] since it's LSB first)
                    header     = (bytes[2] >> 4);                    // First 4 bits
                    heartValue = bytes[1] | ((0xF & bytes[2]) << 8); // Next 12

                    if (heartValue == 0xFFF)
                    {
                        heartValue = -1;
                    }

                    if (_update_func != null)
                    {
                        await _update_func(header, heartValue);
                    }
                }
                else
                {
                    header     = 0;
                    heartValue = bytes[1];

                    if (_update_func != null)
                    {
                        await _update_func(header, heartValue);
                    }
                }

                if (_currentValue == null)
                {
                    _currentValue = new HeartRateData();
                }

                _currentValue.Value     = bytes[1];
                _currentValue.Timestamp = DateTime.Now;


                if (_characteristicBatteryLevel != null)
                {
                    if (_currentValue.TimestampBatteryLevel == null ||
                        (DateTime.Now - _currentValue.TimestampBatteryLevel).Value.Minutes > 1)
                    {
                        _currentValue.BatteryLevel = null;

                        var batteryLevelByte = await _characteristicBatteryLevel?.ReadAsync();

                        _currentValue.TimestampBatteryLevel = DateTime.Now;
                        _currentValue.BatteryLevel          = batteryLevelByte[0];
                    }
                }

                _log("CharacteristicHR_ValueUpdated", $"Device {_currentValue.Value}");
            }
            catch (Exception e)
            {
                _log("CharacteristicHR_ValueUpdated", e.Message);
            }
        }