Giter Site home page Giter Site logo

dotnet-bluetooth-le / dotnet-bluetooth-le Goto Github PK

View Code? Open in Web Editor NEW
784.0 56.0 306.0 10.01 MB

Bluetooth LE plugin for Xamarin/MAUI, supporting Android, iOS, Mac, Windows

License: Apache License 2.0

C# 98.55% PowerShell 1.40% Shell 0.05%
xamarin xamarin-ios xamarin-android xamarin-forms ble bluetooth mvvmcross-plugin maui iot

dotnet-bluetooth-le's Introduction

Bluetooth LE plugin for Xamarin & MAUI

Build status: Build status

Xamarin, MAUI and MvvMCross plugin for accessing the bluetooth functionality. The plugin is loosely based on the BLE implementation of Monkey Robotics.

Important Note: With the term "vanilla" we mean the non-MvvmCross version, i.e. the pure Xamarin or MAUI plugin. You can use it without MvvmCross, if you download the vanilla package.

Support & Limitations

Release Notes

Platform Version Limitations
Xamarin.Android 4.3
Xamarin.iOS 7.0
Xamarin.Mac 10.9 (Mavericks) >= 2.1.0
Xamarin.UWP 1709 - 10.0.16299 >= 2.2.0
MAUI (Android, iOS, Mac, WinUI) >= 3.0.0

Nuget Packages

package stable beta downloads
Plugin.BLE NuGet NuGet Beta Downloads
MvvmCross.Plugin.BLE NuGet MvvMCross NuGet MvvMCross Beta Downloads

Installation

Vanilla

// stable
Install-Package Plugin.BLE
// or pre-release
Install-Package Plugin.BLE -Pre

MvvmCross

Install-Package MvvmCross.Plugin.BLE
// or
Install-Package MvvmCross.Plugin.BLE -Pre

Permissions

Android

Add these permissions to AndroidManifest.xml. For Marshmallow and above, please follow Requesting Runtime Permissions in Android Marshmallow and don't forget to prompt the user for the location permission.

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />

Android 12 and above may require one or more of the following additional runtime permissions, depending on which features of the library you are using (see the android Bluetooth permissions documentation)

<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />

Add this line to your manifest if you want to declare that your app is available to BLE-capable devices only:

<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

iOS

On iOS you must add the following keys to your Info.plist

<key>UIBackgroundModes</key>
<array>
    <!--for connecting to devices (client)-->
    <string>bluetooth-central</string>
    <!--for server configurations if needed-->
    <string>bluetooth-peripheral</string>
</array>

<!--Description of the Bluetooth request message (required on iOS 10, deprecated)-->
<key>NSBluetoothPeripheralUsageDescription</key>
<string>YOUR CUSTOM MESSAGE</string>

<!--Description of the Bluetooth request message (required on iOS 13)-->
<key>NSBluetoothAlwaysUsageDescription</key>
<string>YOUR CUSTOM MESSAGE</string>

MacOS

On MacOS (version 11 and above) you must add the following keys to your Info.plist:

<!--Description of the Bluetooth request message-->
<key>NSBluetoothAlwaysUsageDescription</key>
<string>YOUR CUSTOM MESSAGE</string>

UWP

Add this line to the Package Manifest (.appxmanifest):

<DeviceCapability Name="bluetooth" />

Sample app

We provide a sample Xamarin.Forms app, that is a basic bluetooth LE scanner. With this app, it's possible to

  • check the BLE status
  • discover devices
  • connect/disconnect
  • discover the services
  • discover the characteristics
  • see characteristic details
  • read/write and register for notifications of a characteristic

Have a look at the code and use it as starting point to learn about the plugin and play around with it.

Usage

Vanilla

var ble = CrossBluetoothLE.Current;
var adapter = CrossBluetoothLE.Current.Adapter;

MvvmCross

The MvvmCross plugin registers IBluetoothLE and IAdapter as lazy initialized singletons. You can resolve/inject them as any other MvvmCross service. You don't have to resolve/inject both. It depends on your use case.

var ble = Mvx.Resolve<IBluetoothLE>();
var adapter = Mvx.Resolve<IAdapter>();

or

MyViewModel(IBluetoothLE ble, IAdapter adapter)
{
    this.ble = ble;
    this.adapter = adapter;
}

Please make sure you have this code in your LinkerPleaseLink.cs file

public void Include(MvvmCross.Plugins.BLE.Plugin plugin)
{
    plugin.Load();
}

IBluetoothLE

Get the bluetooth status

var state = ble.State;

You can also listen for State changes. So you can react if the user turns on/off bluetooth on your smartphone.

ble.StateChanged += (s, e) =>
{
    Debug.WriteLine($"The bluetooth state changed to {e.NewState}");
};

IAdapter

Scan for devices

adapter.DeviceDiscovered += (s,a) => deviceList.Add(a.Device);
await adapter.StartScanningForDevicesAsync();

Scan Filtering

var scanFilterOptions = new ScanFilterOptions();
scanFilterOptions.ServiceUuids = new [] {guid1, guid2, etc}; // cross platform filter
scanFilterOptions.ManufacturerDataFilters = new [] { new ManufacturerDataFilter(1), new ManufacturerDataFilter(2) }; // android only filter
scanFilterOptions.DeviceAddresses = new [] {"80:6F:B0:43:8D:3B","80:6F:B0:25:C3:15",etc}; // android only filter
await adapter.StartScanningForDevicesAsync(scanFilterOptions);
ScanTimeout

Set adapter.ScanTimeout to specify the maximum duration of the scan.

ScanMode

Set adapter.ScanMode to specify scan mode. It must be set before calling StartScanningForDevicesAsync(). Changing it while scanning, will not affect the current scan.

Connect to device

ConnectToDeviceAsync returns a Task that finishes if the device has been connected successful. Otherwise a DeviceConnectionException gets thrown.

try
{
    await _adapter.ConnectToDeviceAsync(device);
}
catch(DeviceConnectionException e)
{
    // ... could not connect to device
}

Connect to known Device

ConnectToKnownDeviceAsync can connect to a device with a given GUID. This means that if the device GUID is known, no scan is necessary to connect to a device. This can be very useful for a fast background reconnect. Always use a cancellation token with this method.

  • On iOS it will attempt to connect indefinitely, even if out of range, so the only way to cancel it is with the token.
  • On Android this will throw a GATT ERROR in a couple of seconds if the device is out of range.
try
{
    await _adapter.ConnectToKnownDeviceAsync(guid, cancellationToken);
}
catch(DeviceConnectionException e)
{
    // ... could not connect to device
}

Get services

var services = await connectedDevice.GetServicesAsync();

or get a specific service:

var service = await connectedDevice.GetServiceAsync(Guid.Parse("ffe0ecd2-3d16-4f8d-90de-e89e7fc396a5"));

Get characteristics

var characteristics = await service.GetCharacteristicsAsync();

or get a specific characteristic:

var characteristic = await service.GetCharacteristicAsync(Guid.Parse("d8de624e-140f-4a22-8594-e2216b84a5f2"));

Read characteristic

var bytes = await characteristic.ReadAsync();

Write characteristic

await characteristic.WriteAsync(bytes);

Characteristic notifications

characteristic.ValueUpdated += (o, args) =>
{
    var bytes = args.Characteristic.Value;
};

await characteristic.StartUpdatesAsync();

Get descriptors

var descriptors = await characteristic.GetDescriptorsAsync();

Read descriptor

var bytes = await descriptor.ReadAsync();

Write descriptor

await descriptor.WriteAsync(bytes);

Get System Devices

Returns all BLE devices connected or bonded (only Android) to the system. In order to use the device in the app you have to first call ConnectAsync.

var systemDevices = adapter.GetSystemConnectedOrPairedDevices();

foreach(var device in systemDevices)
{
    await _adapter.ConnectToDeviceAsync(device);
}

Caution! Important remarks / API limitations

The BLE API implementation (especially on Android) has the following limitations:

  • Characteristic/Descriptor Write: make sure you call characteristic.WriteAsync(...) from the main thread, failing to do so will most probably result in a GattWriteError.
  • Sequential calls: Always wait for the previous BLE command to finish before invoking the next. The Android API needs its calls to be serial, otherwise calls that do not wait for the previous ones will fail with some type of GattError. A more explicit example: if you call this in your view lifecycle (onAppearing etc) all these methods return void and 100% don't guarantee that any await bleCommand() called here will be truly awaited by other lifecycle methods.
  • Scan with services filter: On specifically Android 4.3 the scan services filter does not work (due to the underlying android implementation). For android 4.3 you will have to use a workaround and scan without a filter and then manually filter by using the advertisement data (which contains the published service GUIDs).

Best practice

API

  • Surround Async API calls in try-catch blocks. Most BLE calls can/will throw an exception in certain cases, this is especially true for Android. We will try to update the xml doc to reflect this.
    try
    {
        await _adapter.ConnectToDeviceAsync(device);
    }
    catch(DeviceConnectionException ex)
    {
        //specific
    }
    catch(Exception ex)
    {
        //generic
    }
  • Avoid caching of Characteristic or Service instances between connection sessions. This includes saving a reference to them in your class between connection sessions etc. After a device has been disconnected all Service & Characteristic instances become invalid. Always use GetServiceAsync and GetCharacteristicAsync to get a valid instance.

General BLE iOS, Android

  • Scanning: Avoid performing BLE device operations like Connect, Read, Write etc while scanning for devices. Scanning is battery-intensive.
    • Try to stop scanning before performing device operations (connect/read/write/etc).
    • Try to stop scanning as soon as you find the desired device.
    • Never scan on a loop, and set a time limit on your scan.

How to build the nuget package

  1. Build

    Open a console, change to the folder "dotnet-bluetooth-le/.build" and run cake.

  2. pack the nuget

    nuget pack ../Source/Plugin.BLE/Plugin.BLE.csproj

    nuget pack ../Source/MvvmCross.Plugins.BLE/MvvmCross.Plugins.BLE.csproj

Extended topics

Useful Links

How to contribute

We usually do our development work on a branch with the name of the milestone. So please base your pull requests on the currently open development branch.

Licence

Apache 2.0

dotnet-bluetooth-le's People

Contributors

adamdiament avatar adolgov avatar askbojesen avatar bed007 avatar chrimaka avatar dragon160 avatar felixfxu avatar fozzzgate avatar frankfolsche avatar genriquez avatar gtg529s avatar hoidi avatar hughesjs avatar ianbuk avatar jamesmontemagno avatar janusw avatar lothrop avatar m-anthoine avatar marcalx avatar midoragh avatar mkuckert avatar mspoehr avatar nithinsebastian avatar onekam avatar parth7676 avatar smstuebe avatar thorinos avatar tobi-tobi avatar travis012 avatar xabre avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dotnet-bluetooth-le's Issues

Fix PCL profile

for mvx its 259? for xamarin plugin its 259, too.
we should use 259 instead of 78

Cannot communicate after connection lost and reconnection

Hello,
I used your plugin to build an application.
All is working without problem, but I found a little problem and I can't understand if it is a plugin bug or a problem in my application:

If I write something in a characteristic and then I start notification to another characteristic all works well.
But if connection is lost (if I remove battery from my device) and then I reconnect (my device say that I correctly connected), than I can't write anything (my device don't recieve nothing) and I cannot start nofication.

Steps to reproduce

  1. Connect to a device
  2. Write a value in a characteristic
  3. Start notification to another characteristic
  4. Disconnect device
  5. Re connect to device
  6. Write a value in a characteristic
  7. Start notification to another caracteristic

Expected behavior

Values should be written without problems and notification should starts.

Actual behavior

No values are written and it is not possible to start a notification.

Crashlog

[...]
GattCallback state: Disconnected
Disconnected by lost connection
DisconnectedPeripheral by lost signal: _DEVICE_NAME_
07-08 17:21:24.535 D/BluetoothGatt(15023): onClientConnectionState() - status=0 clientIf=3 device=_DEVICE_ADDRESS_
07-08 17:21:24.535 D/BluetoothDevice(15023): mAddress: _DEVICE_ADDRESS_
07-08 17:21:24.535 I/mono-stdout(15023): GattCallback state: Disconnected
07-08 17:21:24.536 D/BluetoothDevice(15023): mAddress: _DEVICE_ADDRESS_
07-08 17:21:24.536 D/BluetoothDevice(15023): mAddress: _DEVICE_ADDRESS_
07-08 17:21:24.536 I/mono-stdout(15023): Disconnected by lost connection
07-08 17:21:24.537 D/BluetoothDevice(15023): mAddress: _DEVICE_ADDRESS_
07-08 17:21:24.538 D/BluetoothGatt(15023): close()
07-08 17:21:24.538 D/BluetoothGatt(15023): unregisterApp() - mClientIf=3
07-08 17:21:24.540 I/mono-stdout(15023): DisconnectedPeripheral by lost signal: _DEVICE_NAME_
[...]
GattCallback state: Connected
Connected
07-08 17:21:30.861 I/mono-stdout(15023): GattCallback state: Connected
07-08 17:21:30.861 I/mono-stdout(15023): Connected
07-08 17:21:30.862 D/BluetoothDevice(15023): mAddress: _DEVICE_ADDRESS_
07-08 17:21:30.862 D/BluetoothDevice(15023): mAddress: _DEVICE_ADDRESS_
07-08 17:21:30.863 D/BluetoothDevice(15023): getName: name = _DEVICE_NAME_
07-08 17:21:30.864 D/BluetoothDevice(15023): mAddress: _DEVICE_ADDRESS_
07-08 17:21:30.864 D/BluetoothDevice(15023): mAddress: _DEVICE_ADDRESS_
ConnectToDeviceAync Connected: 00000000-0000-0000-0000-_DEVICE_ADDRESS_ _DEVICE_NAME_
07-08 17:21:30.865 I/mono-stdout(15023): ConnectToDeviceAync Connected: 00000000-0000-0000-0000-_DEVICE_ADDRESS_ _DEVICE_NAME_
[...]
Characteristic.WriteAsync
07-08 17:21:34.068 I/mono-stdout(15023): Characteristic.WriteAsync
Write _FIRST_CHARACTERISTIC_
07-08 17:21:34.101 I/mono-stdout(15023): Write _FIRST_CHARACTERISTIC_
07-08 17:21:34.102 D/BluetoothGatt(15023): writeCharacteristic() - uuid: _FIRST_CHARACTERISTIC_
Characteristic.StartUpdates
07-08 17:21:34.105 I/mono-stdout(15023): Characteristic.StartUpdates
07-08 17:21:34.106 D/BluetoothGatt(15023): setCharacteristicNotification() - uuid: _SECOND_CHARACTERISTIC_ enable: true
07-08 17:21:34.203 D/Surface (15023): Surface::setBuffersDimensions(this=0xf45dad00,w=736,h=1280)
07-08 17:21:34.207 D/Surface (15023): Surface::setBuffersDimensions(this=0xf45dad00,w=736,h=1280)
07-08 17:21:34.211 D/Surface (15023): Surface::setBuffersDimensions(this=0xf45dad00,w=736,h=1280)
Descriptor set value: NOTIFY
07-08 17:21:34.215 I/mono-stdout(15023): Descriptor set value: NOTIFY
Characteristic.StartUpdates, successful: False
[...]

Configuration

Version: 1.0.0 - beta 5

Platform: Android

Device: Lenovo Tab 2 a8-50f (Android 5.1 - Api 22) and LGE LG-X150 (Android 5.0 - Api 21)

Thanks for your attention,
Enryb

Xamarin Plugin

I would also like to create a pure Xamarin plugin with no dependencies on MvvmCross.

My initial idea is to either use precompiler directives like #if #endif to isolate MvvmCross dependencies and create 3 new csprojects which link the same files as the existing ones but don't have any nuget / package dependencies.

What are your thoughts on this? :)

Improve CharacteristicPropertyType implementation

CharacteristicPropertyType is not truly platform independent. Something like AppleWriteWithoutResponse should not be included.

  • Check if it needs to be a flag. If yes, refactor all usages to HasFlag instead of ==.
  • Look up if there are more possible flag values
  • get rid of bad code like (CharacteristicPropertyType)(int)_nativeCharacteristic.Properties

Get BLE state

  • Check if the device has BLE
  • Get the state (On, Off, NotAvailable)
  • Event that notifies about state changes
  • add to sample app
  • document feature
  • unauthorized state Android

Add this to IBluetoothLE.

Xamarin.Mac support

Interesting project! Are there any plans to support the macOS platform?

I suspect that it should be quite similar to the iOS platform?

Startupdate not working on reconnect using the extension

Hey guys,
Great job on the API. I initially grabbed the original project and heavily modified to make it work on my side in March 2015. When I saw your code I decided to switch as I like your API much more (has support for API 21).

However I ran into an issue that took me a couple of hours to figure out. If the connection is lost, the code below will re-establish the connection with the device. However setCharacteristicNotification() will fail hence resulting StartUpdates() for the Charactrastics to not work.

Assume a IDevice ID is saved. In my case it is a preferred device set by users which is meant be auto-connected to.

Here is the sample code:

var device = await Adapter.DiscoverSpecificDeviceAsync (SOME_DEVICE_ID);
var connectedDevice = await Adapter.ConnectAsync (device);
var service = await connectedDevice.GetServiceAsync (SOME_GATT_SERVICE_ID);
_sampleCharacteristic = await service.GetCharacteristicAsync (SOME_GATT_CHAR_ID)
_sampleCharacteristic .StartUpdates();

_sampleCharacteristic .StartUpdates() returns false since the DiscoveredDevices list is not cleared hence Adapter.DiscoverSpecificDeviceAsync returns the stored IDevice and Gatt object. Java code behind returns false since mClienIf or mService are null.

Not sure if this is intentional or not. To fix this in my code, I listen to ConnectionLost event and clear out the DiscoveredDevices list.

Characteristic Notify with acknowledgment aka. Indicate

Currently we only support classical notifications (without ack). As pointed out by one of our collegues some devices require indicate instead of notify. Indicate is notify with ack.

For Android use:

descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE)

instead of

descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)

For iOS:
The CoreBluetooth APIs in iOS don't let you differentiate between notifications and indications; based on the peripheral's GATT structure, it will simply use whichever type of data push method is available (notify or indicate). If the GATT structure has both notify and indicate enabled--which is very uncommon and probably shouldn't be done--then iOS will use notify.

ToDo's:

  • Add indicate flag to CanUpdate in CharacteristicBase
  • Android: set descriptor value to Indicate

IDevice.ReadRssi() throws NullReferenceException

I am playing around with the plugin a bit and ran into this issue with calling ReadRssi() on an IDevice instance.

What I am doing is basically, scan for devices, select one of them and show details about it.

On that selected IDevice instance I do:

_device?.ReadRssi();

This throws the following exception:

05-04 10:43:20.080 E/mono-rt (20530): [ERROR] FATAL UNHANDLED EXCEPTION: System.NullReferenceException: Object reference not set to an instance of an object.
05-04 10:43:20.080 E/mono-rt (20530):   at MvvmCross.Plugins.BLE.Droid.Bluetooth.LE.Device.ReadRssi () [0x00000] in c:\Users\sead\Documents\GitHub\MvvmCross-BluetoothLE\Source\MvvmCross.Plugins.BLE.Droid\Bluetooth\LE\Device.cs:264 
05-04 10:43:20.080 E/mono-rt (20530):   at com.bksv.ems.sxuble.ViewModels.DeviceDetailsViewModel.StartData () [0x00031] in C:\Users\Tomasz\Documents\Visual Studio 2015\Projects\SXUBLE\SXUBLE\ViewModels\DeviceDetailsViewModel.cs:90 
05-04 10:43:20.080 E/mono-rt (20530):   at com.bksv.ems.sxuble.droid.Views.DeviceDetailsView.OnResume () [0x00008] in C:\Users\Tomasz\Documents\Visual Studio 2015\Projects\SXUBLE\SXUBLE.Droid\Views\DeviceDetailsView.cs:22 
05-04 10:43:20.080 E/mono-rt (20530):   at Android.App.Activity.n_OnResume (IntPtr jnienv, IntPtr native__this) [0x00009] in /Users/builder/data/lanes/2923/b4be22e9/source/monodroid/src/Mono.Android/platforms/android-23/src/generated/Android.App.Activity.cs:3920 
05-04 10:43:20.080 E/mono-rt (20530):   at (wrapper dynamic-method) System.Object:ec6c167c-6312-4270-86db-3b0ff9ed091e (intptr,intptr)

Looking at the line it throws at: https://github.com/xabre/xamarin-bluetooth-le/blob/master/Source/MvvmCross.Plugins.BLE.Droid/Bluetooth/LE/Device.cs#L264 it could seem like the _gattCallback is null for some reason.

getting stared with plugin

Hi

I am trying to make use of the MvvmCross.Plugins.BLE plugin in a Xamarin forms project. I am having trouble getting stared. Especially in regard to the injecting of the IAdapter service in my project. Would appreciate help getting stared. Perhaps even a sample project would be greatly appreciated.

Thanking you in advance

Allow to specify write type

It might be useful to let the user decide if he wants to use write with response or without response if the device supports both. Write with response should be default.
We have to look up if the APIs support it.

Todo:

  • Implement
  • Add to sample app
  • documentation

Get the connected device(s) from IAdapter.ConnectToDeviceAsync

ConnectToDeviceAsync among other async methods do not return anything other than a Task. This is really confusing when dealing with async methods as you would, especially on ConnectToDeviceAsync, expect it to return the connected device or devices. Currently you have to hook up an event and wait for them to appear there, which is not really super nice.

Let me explain with some code. Say you have device sensor you want to connect to and discover some services and characteristics and maybe do some reading and writing to said characteristics.

Currently you would have to do something like:

bleAdapter.DeviceConnected += BleAdapterOnDeviceConnected;

await bleAdapter.ConnectToDeviceAsync(sensor);

Then in the method BleAdapterOnDeviceConnected you would get notified about connected devices, so you go await from the scope where you called await on ConnectToDeviceAsync and straight after you can't really know whether you have connected to a device yet or not, since you need to wait for the event to trigger.

Usually when I work with other libraries that have async stuff incorporated I would work something like this:

IDevice device = await bleAdapter.ConnectToDeviceAsync(sensor);
// do stuff with device

Maybe even if we need to disconnect from the device automatically make a IDisposable implementation:

using(var device = await bleAdapter.ConnectToDeviceAsync(sensor))
{
    // do stuff with connected device
}

// device is disconnected here

Would be really awesome if this library could support something like this.

Queries on 'Writing a value to a characteristic' in Plugin.BLE nuget package

Hi,

I have a few queries related to 'Writing a value to a characteristic’ using Plugin.BLE nuget package.
The write operation can be of two types: write with response and write without response.

According to Apple's documentation of Core Bluetooth framework, there are two types of characteristic write: CBCharacteristicWriteType - CBCharacteristicWriteWithResponse and CBCharacteristicWriteWithoutResponse. "The peripheral responds to write requests that are specified as CBCharacteristicWriteWithResponse by calling the peripheral:didWriteValueForCharacteristic:error: method of its delegate object."

According to Android BluetoothGatt documentation, we can set the write type for a characteristic. “Setting the write type of a characteristic determines how the writeCharacteristic(BluetoothGattCharacteristic) function write this characteristic.”. It can be one of: WRITE_TYPE_DEFAULT, WRITE_TYPE_NO_RESPONSE or WRITE_TYPE_SIGNED.

In Plugin.BLE nuget package, we could find there are a few characteristic property types defined related to write: AppleWriteWithoutResponse, WriteWithoutResponse, AuthenticatedSignedWrites.
And we have a method "WriteAsync(data)" to write a value to a characteristic, which returns a bool. If the return value is ‘true’, data is written successfully. If it is ‘false’, the data is not written to the characteristic.

  1. Is there any way to specify whether this is a writeWithResponse or writeWithoutResponse? How to perform write with response using Plugin.BLE nugget package?
  2. What is the difference between WriteWithoutResponse and AppleWriteWithoutResponse?

Can you please help me getting answers for the above mentioned questions?

Thanks in advance :)

Regards,
Leela

iOS deviceon connect -> name not updated

Ios names become stale and need to be read from Advertisment data.

  • this is currently done on device discovery
  • this is not done for the device passed as a connected event argument!

Sample App

Was thinking of also including a SampleApp (like a BLE explorer) maybe using Xamarin Forms for both platforms.

  • Move Sample from UWP branch to 1.0
  • Device List Page
  • Service List Page
  • Characteristic List Page
  • Characteristic detail Page

Testing Support Library

In our projects we are always writing mocks for IDevice, IAdapter, ...
We should provide a extra package where we offer some useful mocks.

Started Service Background Scanning

Currently my started service and run and discover device when the application is "foreground". Which means it's not minimized. The output is fine

[0:] BLE Bluetooth is On
[0:] BLE IS SCANNING
06-30 15:38:24.396 D/Mono    (27664): Assembly Ref addref Plugin.BLE[0x7f9a6ab500] -> System.Core[0x7f7aae1180]: 4
Adapter >= 21: Starting a scan for devices.
06-30 15:38:24.404 I/mono-stdout(27664): Adapter >= 21: Starting a scan for devices.
06-30 15:38:24.417 D/BluetoothAdapter(27664): STATE_ON
06-30 15:38:24.429 D/BluetoothLeScanner(27664): onClientRegistered() - status=0 clientIf=6
06-30 15:38:24.454 D/Mono    (27664): [0x7f758a0440] hill climbing, change max number of threads 6
06-30 15:38:24.729 D/Mono    (27664): DllImport searching in: '__Internal' ('(null)').
06-30 15:38:24.730 D/Mono    (27664): Searching for 'java_interop_jnienv_is_assignable_from'.
06-30 15:38:24.730 D/Mono    (27664): Probing 'java_interop_jnienv_is_assignable_from'.
06-30 15:38:24.730 D/Mono    (27664): Found as 'java_interop_jnienv_is_assignable_from'.
06-30 15:38:24.735 D/Mono    (27664): DllImport searching in: '__Internal' ('(null)').
06-30 15:38:24.735 D/Mono    (27664): Searching for 'java_interop_jnienv_get_byte_array_region'.
06-30 15:38:24.735 D/Mono    (27664): Probing 'java_interop_jnienv_get_byte_array_region'.
06-30 15:38:24.735 D/Mono    (27664): Found as 'java_interop_jnienv_get_byte_array_region'.
06-30 15:38:24.766 D/Mono    (27664): Assembly Ref addref Plugin.BLE.Abstractions[0x7f9a6ab400] -> System.Runtime.Extensions[0x7f7b642980]: 3
Adv rec [Type CompleteLocalName; Data 49-44-31-30-37-20-48-52]
Adv rec [Type Appearance; Data 41-03]
Adv rec [Type Flags; Data 06]
Adv rec [Type UuidsComplete16Bit; Data 0A-F0]
Adv rec [Type ManufacturerSpecificData; Data 11-00-02-00-EA-7A-9B-5B-50-4E-0B]
[0:] Trying to reconnect
[0:] Guid Found
[0:] Scanning
Adapter: Stopping the scan for devices.
Adapter >= 21: Stopping the scan for devices.

But once I minimize the application. It doesn't "receive" or discover anything.

[0:] BLE Bluetooth is On
Thread started: <Thread Pool> #8
[0:] BLE IS SCANNING
Adapter >= 21: Starting a scan for devices.
06-30 15:38:49.147 D/Mono    (27664): [0x7f7863f440] worker starting
06-30 15:38:49.150 I/mono-stdout(27664): Adapter >= 21: Starting a scan for devices.
06-30 15:38:49.154 D/BluetoothAdapter(27664): STATE_ON
06-30 15:38:49.158 D/BluetoothLeScanner(27664): onClientRegistered() - status=0 clientIf=7
Adapter: Scan timeout has elapsed.
06-30 15:39:09.205 I/mono-stdout(27664): Adapter: Scan timeout has elapsed.
Adapter: Stopping the scan for devices.
Adapter >= 21: Stopping the scan for devices.
06-30 15:39:09.209 I/mono-stdout(27664): Adapter: Stopping the scan for devices.
06-30 15:39:09.210 I/mono-stdout(27664): Adapter >= 21: Stopping the scan for devices.
06-30 15:39:09.219 D/BluetoothAdapter(27664): STATE_ON
[0:] BLE Bluetooth is On

So my concern is, how to get the scanning to receive the device in the background(as in minimized/when the application is not in focus).

Vanilla Android ListView Adapters

I'm trying to use the non-mvvm plugin for a pure android application that has a ListView to store the Devices result. So I do not know what is the right way to do it. Do I need to create a listview adapter to store the device? The sample app has Device, device, Devices and so on. So it's confusing for a beginner like me who would like to just have a simple click button to discover device.

My code so far to display result is

public IDevice Device { get; } //In my MainActivity class

//on my OnCreate(Bundle bundle)
button.Click += ScanForDevices;
_bluetoothLe.Adapter.DeviceDiscovered += _bluetoothLe_DeviceDiscovred;
//

private void _bluetoothLe_DeviceDiscovred(object sender, DeviceEventArgs e)
        {
            var msg = string.Format(@"Device found: {0}
                     {1} - {2}", Device.Name, e.Device.Name, e.Device.Id, e.Device.Rssi);
            DisplayInformation(msg);
        }
                private void ScanForDevices(object sender, EventArgs e)
        {
            if (!_bluetoothLe.Adapter.IsScanning)
                _bluetoothLe.Adapter.StartScanningForDevicesAsync();
        }

Currently, even this simple showing device isn't working for me. It's working if I use the other plugin/way from this link "https://elbruno.com/2015/09/08/vs2015-listing-bluetooth-le-devices-in-android-with-xamarin/"

Appreciate any help or advice given in advance.

Connect to known device without discovering it before.

Hi,
First of all, it is a very cool project. Thank you very much for the good work.

I tried the library for some days and I wonder if there is a way to connect to a known device (by its GUID) directly, without performing a long discovery before?

Also, I noticed that if I disconnect from a device, than I can connect again to that device but cannot exchange any data. I have to perform a discovery before to make it work again.
Do I make something wrong?

Thank you for your answers.
Cheers.

Create package install test projects

Create 2 solutions that contain

  • Empty App (Core, iOS, Android)
  • Empty MvvmCross App (Core, iOS, Android)
  • Add references to Adapter (similar to linker please include) "compiler please check"

Script that

  • installs the nuget packages from local source
  • updates the packages to the latest version
  • builds the apps

to ensure that packages are installable and cause no build error.

Namespace name 'Touch' does not exist in the namespace 'MvvmCross.Plugins.BLE

I have just installed version 0.9.1 into a Xamarin.Forms PCL project, targetting ios & android. However, when I run an ios build, I get the following error.

Error: CS0234 The type or namespace name 'Touch' does not exist in the namespace 'MvvmCross.Plugins.BLE' (are you missing an assembly reference?) My_App.iOS C:\Users\George\Desktop\My_App_Xamarin_Forms\iOS\Bootstrap\BlePluginBootstrap.cs

I have a few other issues I am running into with my project, so it could be related to those, but It struck me as an odd thing to get, is this a know issue or a common problem - any idea what might be causing it?

Possible issues with reliable Write on android

Our GattCallback has OnReliableWriteCompleted that should get called after reliable write was successful. But it's doing nothing. Shouldn't we use this in our WriteNative().

We only use [onCharacteristicWrite](https://developer.android.com/reference/android/bluetooth/BluetoothGattCallback.html#onCharacteristicWrite%28android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int%29)

The documentation of it says:

If this callback is invoked while a reliable write transaction is in progress, the value of the characteristic represents the value reported by the remote device. An application should compare this value to the desired value to be written. If the values don't match, the application must abort the reliable write transaction.

I think we aren't doing it. We do not use BeginReliableWrite, AbortReliableWrite, ExecuteReliableWrite. http://stackoverflow.com/a/31011052/1489968

Hi,

To help us fix your issue, please provide the information in the below template. If something causes a crash, provide a much information as you can gather.
Just imagine: we do not know what you are doing!

Note: There is often little we can do without a minimal reproducible sample of the issue, so please provide that in a standalone git repository and link it here.

Steps to reproduce

Expected behavior

Tell us what should happen

Actual behavior

Tell us what happens instead

Crashlog

If something causes an exception paste full stack trace + Exception here

Configuration

Version: 0.9.3

Platform: iOS/Android/ ...

Device: HTC Sensation/ ...

Clear cached services after disconnect.

Pulled the bug out from issue #47 so we can handle feature request and bug separately

from @domo4all:

Also, I noticed that if I disconnect from a device, than I can connect again to that device but cannot exchange any data. I have to perform a discovery before to make it work again.
Do I make something wrong?

from @xabre:
I think I know what the problem is. We do not clear the list of KnownServices on disconnect, and when reusing the instance of the IDevice it uses the list of cached services from the previous connection.

Yes, there is no call to discover services after the second connection
[BluetoothGatt] discoverServices() - device: 20:91:48:BB:C8:9A
We will publish a fix for this problem. Maybe later today -beta4. Thank you for pointing it out.

error with nuget

I tried to install the nuget package via the package manager but when I am trying to do so I get the following error

Install failed. Rolling back...
Package 'Plugin.BLE.1.0.0-beta4' does not exist in project 'BluetoothToggleWidget'
Package 'Plugin.BLE.1.0.0-beta4' does not exist in folder 'C:\Users\sebastienj\Documents\WORK\MyStuff\XamarinBLETest\Xamarin\AndroidChat\packages'
Install-Package : Failed to add reference to 'Plugin.BLE.Abstractions'.
At line:1 char:1

  • Install-Package Plugin.BLE -Pre
  • - CategoryInfo          : NotSpecified: (:) [Install-Package], Exception
    - FullyQualifiedErrorId : NuGetCmdletUnhandledException,NuGet.PackageManagement.PowerShellCmdlets.InstallPackageCommand
    
    

Can you please fix it?

Characteristic.WriteAsync never returns on iOS

Steps to reproduce

  1. Connect to device
  2. Discover services
  3. Discover characteristic
  4. Write to characteristic async

My code does the following:

_bleAdapter.ConnectToDevice(device);

In the DeviceConnected event I do the following:

private async void BleAdapterOnDeviceConnected(object sender, DeviceConnectionEventArgs args)
{
    var device = args.Device;

    var deviceViewModel = Devices.FirstOrDefault(d => d.Id == device.ID);
    deviceViewModel.Connected = true;
    deviceViewModel.DeviceName = device.Name;

    Mvx.TaggedTrace("HomeViewModel::DeviceConnected", $"Connected to {deviceViewModel.DeviceName} - UUID {deviceViewModel.Uuid}");

    try
    {
        var service =
            await device.GetServiceAsync(new Guid("13333333333333333333333333333337")).ConfigureAwait(false);
        if (service != null)
        {
            Mvx.TaggedTrace("HomeViewModel::DeviceConnected", "Found WiFi configuration service");

            var characteristic =
                await
                    service.GetCharacteristicAsync(new Guid("13333333333333333333333333330001"))
                        .ConfigureAwait(false);

            if (characteristic != null && characteristic.CanWrite)
            {
                Mvx.TaggedTrace("HomeViewModel::DeviceConnected", "Found SSID configuration characteristic");

                var ssidBytes = Encoding.UTF8.GetBytes(HotspotViewModel.Ssid);
                var writeOk = await characteristic.WriteAsync(ssidBytes).ConfigureAwait(false);
                if (writeOk)
                {
                    Mvx.TaggedTrace("HomeViewModel::DeviceConnected", "Wrote SSID successful!");
                    deviceViewModel.Ssid = HotspotViewModel.Ssid;
                }
            }
        }

        _bleAdapter.DisconnectDevice(device);
        Mvx.TaggedTrace("HomeViewModel",
            $"Disconnecting device  {deviceViewModel.DeviceName} - UUID {deviceViewModel.Uuid}");
    }
    catch (Exception e)
    {
        Mvx.TaggedTrace("HomeViewModel::DeviceConnected", $"Got exception: {e}");
    }
}

The code never reaches the if (writeOk) and does not throw any exceptions either. The bytes are written to the device. So must be something wrong with the TaskCompletionSource. Maybe something is garbage collected, such as the eventhandler that you hook up.

This same construction works fine on Android.

Expected behavior

WriteAsync should eventually return

Actual behavior

WriteAsync never returns

Configuration

Version: MvvmCross.Plugin.BLE 0.9.2

Platform: iOS

Device: iPhone 4s, iPhone 6+

Make everything async

Refactor everything to be an async operation and get rid of non async stuff. This means basically moving the extension methods to the classes.

Acting as a peripheral

Hello,
I was wondering if you planned to manage Peripheral mode, so that a smartphone or tablet can send advertisements, can be connected from another BLE devices, etc.

Cheers.

Android - ConnectedDevice list not up to date

Sometimes an inconssistency appears between the internal list of connected devices and the truly connected devices.

Use BluetoothManager:
public IList GetConnectedDevices ([GeneratedEnum] ProfileType profile);

to try to detect inconsistencies.

Scenario:
ConnectedDevice list is empty. The real BLE device is still connected.

Windows Support

Are there any plans to expand the scope of this project to include the Windows platforms (8.1, phone 8.1 and/or Universal Windows)?

Support for LongRead

For reading characteristics that are longer that the usual 20 bytes BLE offers a read option called (LongRead). It would be cool if your addin provides support for that.

attclient_read_long command: Starts a procedure where the client first sends normal read request to the server, and if the server returns an attribute value with a length equal to the BLE MTU (22 bytes), then the client continues to send "read long" requests until rest of the attribute is read. This only applies if you are reading attributes that are longer than 22 bytes. It is often simpler to construct your GATT server such that there are no long attributes, for simplicity. Note that the BLE protocol still requires that data is packetized into max. 22-byte chunks, so using "read long" does not save transmission time

(https://bluegiga.zendesk.com/entries/25053373--REFERENCE-BLE-master-slave-GATT-client-server-and-data-RX-TX-basics)

I think there are two ways to support LongRead:

a) Always take LongRead since it only applies if the attribute is longer than usual
b) Check the size of the characteristics and than apply Read or LongRead

Retrieving Services after Selecting Device(Android)

Unable to display Services from the selected Device (on my first page ListView).

var services = await connectedDevice.GetServicesAsync();

This line here is the example given on Readme. How do I create the _connectedDevice object which can refer back to what I have selected on my previous Activity? It gives off a NullException error when trying to debug it. Which is crashing at GetServicesAsync.

Here are my codes on my ServiceList.cs. If needed, please check attached file for the ServiceListAdapter (It's abit long if I put them all inside this issue)
ServiceListAdapter.txt

    private ListView servicelistview;
    private IDevice _connectedDevice;
    public IList<IService> _services;
    private TextView tv1;
    private IService item;
    private ServiceListAdapter sla;

    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
        //var selectedItemId = Intent.Extras.GetString("DeviceSelected");
        SetContentView(Resource.Layout.servicelist);

        tv1 = FindViewById<TextView>(Resource.Id.textView1);

       // tv1.Text = selectedItemId;

        servicelistview = FindViewById<ListView>(Resource.Id.listView1);

        getServices();
    }

    private async void getServices()
    {
        if (_services == null)
        {
            tv1.Text = "Services is null";
            _services = await _connectedDevice.GetServicesAsync();
            showServices();
        }

        else
        {
            tv1.Text = "Show Services";
            showServices();
        }

    }

    private void showServices()
    {
        //_services.Add(item);
        sla = new ServiceListAdapter(this, _services);
        servicelistview.Adapter = sla;

        sla.NotifyDataSetChanged();
    }

Error XA2006 Referencing back to Plugin.BLE

Hi again,

I've come across this error. On the Plugin.BLE beta3, I can release the solution and build an APK. But if I updated my package to beta4 and try to release the solution. This will pop up. Any clue? I do need to use the beta4 for now. Can't stick to beta3 for too long.

Severity Code Description Project File Line Suppression State
Error The "LinkAssemblies" task failed unexpectedly.
Xamarin.Android.XamarinAndroidException: error XA2006: Reference to metadata item '!!0[] System.Array::Empty()' (defined in 'Plugin.BLE, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null') from 'Plugin.BLE, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' could not be resolved. ---> Mono.Cecil.ResolutionException: Failed to resolve !!0[] System.Array::Empty()
at Mono.Linker.Steps.MarkStep.MarkMethod(MethodReference reference)
at Mono.Linker.Steps.MarkStep.MarkInstruction(Instruction instruction)
at Mono.Linker.Steps.MarkStep.MarkMethodBody(MethodBody body)
at Mono.Linker.Steps.MarkStep.ProcessMethod(MethodDefinition method)
at Mono.Linker.Steps.MarkStep.ProcessQueue()
at Mono.Linker.Steps.MarkStep.Process()
at Mono.Linker.Steps.MarkStep.Process(LinkContext context)
at Mono.Linker.Pipeline.Process(LinkContext context)
at MonoDroid.Tuner.Linker.Process(LinkerOptions options, LinkContext& context)
at Xamarin.Android.Tasks.LinkAssemblies.Execute()
--- End of inner exception stack trace ---
at Xamarin.Android.Diagnostic.Error(Int32 code, Exception innerException, String message, Object[] args)
at Xamarin.Android.Tasks.LinkAssemblies.Execute()
at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute()
at Microsoft.Build.BackEnd.TaskBuilder.d__26.MoveNext() App2

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.