Skip to content

Commit

Permalink
Fixed README image to work with pub.dartlang.org
Browse files Browse the repository at this point in the history
  • Loading branch information
pauldemarco committed Sep 4, 2017
1 parent 197caba commit 9bc4c0f
Showing 12 changed files with 378 additions and 100 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
## 0.1.1

* Fixed image for pub.dartlang.org

## 0.1.0

* Characteristic notifications/indications.
* Merged in Guid library, removed from pubspec.yaml.

## 0.0.1 - September 1st, 2017

* Initial Release.
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<br>
<p align="center">
<img alt="FlutterBlue" src="site/flutterblue.png" />
<img alt="FlutterBlue" src="https://github.com/pauldemarco/flutter_blue/blob/master/site/flutterblue.png?raw=true" />
</p>
<br><br>

@@ -70,6 +70,15 @@ for(BluetoothDescriptor d in descriptors) {
// Writes to a descriptor
await device.writeDescriptor(d, [0x12, 0x34])
```

### Set notifications
```dart
await device.setNotifyValue(characteristic, true);
device.onValueChanged(characteristic).listen((value) {
// do something with new value
});
```

## Reference
### FlutterBlue API
| | Android | iOS | Description |
@@ -90,7 +99,8 @@ await device.writeDescriptor(d, [0x12, 0x34])
| readDescriptor | :white_check_mark: | :white_large_square: | Retrieves the value of a specified descriptor. |
| writeCharacteristic | :white_check_mark: | :white_large_square: | Writes the value of a characteristic. |
| writeDescriptor | :white_check_mark: | :white_large_square: | Writes the value of a descriptor. |
| setNotifyValue | :white_large_square: | :white_large_square: | Sets notifications or indications for the value of a specified characteristic. |
| setNotifyValue | :white_check_mark: | :white_large_square: | Sets notifications or indications for the value of a specified characteristic. |
| onValueChanged | :white_check_mark: | :white_large_square: | Notifies when the Bluetooth Characteristic's value has changed. |
| canSendWriteWithoutResponse | :white_large_square: | :white_large_square: | Indicates whether the Bluetooth Device can send a write without response. |
| state | :white_large_square: | :white_large_square: | Gets the current state of the Bluetooth Device. |
| onStateChanged | :white_large_square: | :white_large_square: | Stream of state changes for the Bluetooth Device. |
Original file line number Diff line number Diff line change
@@ -47,13 +47,15 @@
public class FlutterBluePlugin implements MethodCallHandler {
private static final String TAG = "FlutterBluePlugin";
private static final String NAMESPACE = "plugins.pauldemarco.com/flutter_blue";
static final private UUID CCCD_ID = UUID.fromString("000002902-0000-1000-8000-00805f9b34fb");
private final Registrar registrar;
private final MethodChannel channel;
private final EventChannel stateChannel;
private final EventChannel scanResultChannel;
private final EventChannel servicesDiscoveredChannel;
private final EventChannel characteristicReadChannel;
private final EventChannel descriptorReadChannel;
private final EventChannel characteristicNotifiedChannel;
private final BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private final Map<String, Result> mConnectionRequests = new HashMap<>();
@@ -74,6 +76,7 @@ public static void registerWith(Registrar registrar) {
this.servicesDiscoveredChannel = new EventChannel(registrar.messenger(), NAMESPACE+"/servicesDiscovered");
this.characteristicReadChannel = new EventChannel(registrar.messenger(), NAMESPACE+"/characteristicRead");
this.descriptorReadChannel = new EventChannel(registrar.messenger(), NAMESPACE+"/descriptorRead");
this.characteristicNotifiedChannel = new EventChannel(registrar.messenger(), NAMESPACE+"/characteristicNotified");
this.mBluetoothManager = (BluetoothManager) r.activity().getSystemService(Context.BLUETOOTH_SERVICE);
this.mBluetoothAdapter = mBluetoothManager.getAdapter();
channel.setMethodCallHandler(this);
@@ -82,6 +85,7 @@ public static void registerWith(Registrar registrar) {
servicesDiscoveredChannel.setStreamHandler(servicesDiscoveredHandler);
characteristicReadChannel.setStreamHandler(characteristicReadHandler);
descriptorReadChannel.setStreamHandler(descriptorReadHandler);
characteristicNotifiedChannel.setStreamHandler(characteristicNotifiedHandler);
}

@Override
@@ -248,7 +252,7 @@ public void onMethodCall(MethodCall call, Result result) {
Protos.DiscoverServicesResult.Builder p = Protos.DiscoverServicesResult.newBuilder();
p.setRemoteId(deviceId);
for(BluetoothGattService s : gattServer.getServices()){
p.addServices(ProtoMaker.from(gattServer.getDevice(), s));
p.addServices(ProtoMaker.from(gattServer.getDevice(), s, gattServer));
}
result.success(p.build().toByteArray());
break;
@@ -393,6 +397,71 @@ public void onMethodCall(MethodCall call, Result result) {
break;
}

case "setNotification":
{
byte[] data = call.arguments();
Protos.SetNotificationRequest request;
try {
request = Protos.SetNotificationRequest.newBuilder().mergeFrom(data).build();
} catch (InvalidProtocolBufferException e) {
result.error("RuntimeException", e.getMessage(), e);
break;
}

BluetoothGatt gattServer;
BluetoothGattCharacteristic characteristic;
BluetoothGattDescriptor cccDescriptor;
try {
gattServer = locateGatt(request.getRemoteId());
characteristic = locateCharacteristic(gattServer, request.getServiceUuid(), request.getSecondaryServiceUuid(), request.getCharacteristicUuid());
cccDescriptor = characteristic.getDescriptor(CCCD_ID);
if(cccDescriptor == null) {
throw new Exception("could not locate CCCD descriptor for characteristic: " +characteristic.getUuid().toString());
}
} catch(Exception e) {
result.error("set_notification_error", e.getMessage(), null);
return;
}

byte[] value = null;

if(request.getEnable()) {
boolean canNotify = (characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) > 0;
boolean canIndicate = (characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_INDICATE) > 0;
if(!canIndicate && !canNotify) {
result.error("set_notification_error", "the characteristic cannot notify or indicate", null);
return;
}
if(canIndicate) {
value = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE;
}
if(canNotify) {
value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE;
}
} else {
value = BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE;
}


if(!cccDescriptor.setValue(value)) {
result.error("set_notification_error", "error when setting the descriptor value to: " + value, null);
return;
}

if(!gattServer.writeDescriptor(cccDescriptor)) {
result.error("set_notification_error", "error when writing the descriptor", null);
return;
}

if(!gattServer.setCharacteristicNotification(characteristic, request.getEnable())){
result.error("set_notification_error", "could not set characteristic notifications to :" + request.getEnable(), null);
return;
}

result.success(ProtoMaker.from(characteristic, gattServer).toByteArray());
break;
}

default:
{
result.notImplemented();
@@ -630,6 +699,19 @@ public void onCancel(Object o) {
}
};

private EventSink characteristicNotifiedSink;
private final StreamHandler characteristicNotifiedHandler = new StreamHandler() {
@Override
public void onListen(Object o, EventChannel.EventSink eventSink) {
characteristicNotifiedSink = eventSink;
}

@Override
public void onCancel(Object o) {
characteristicNotifiedSink = null;
}
};

private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
@@ -660,7 +742,7 @@ public void onServicesDiscovered(BluetoothGatt gatt, int status) {
Protos.DiscoverServicesResult.Builder p = Protos.DiscoverServicesResult.newBuilder();
p.setRemoteId(gatt.getDevice().getAddress());
for(BluetoothGattService s : gatt.getServices()) {
p.addServices(ProtoMaker.from(gatt.getDevice(), s));
p.addServices(ProtoMaker.from(gatt.getDevice(), s, gatt));
}
servicesDiscoveredSink.success(p.build().toByteArray());
}
@@ -670,27 +752,9 @@ public void onServicesDiscovered(BluetoothGatt gatt, int status) {
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
Log.d(TAG, "onCharacteristicRead: ");
if(characteristicReadSink != null) {
// Rebuild the ReadAttributeRequest and send back along with response
Protos.ReadCharacteristicRequest.Builder q = Protos.ReadCharacteristicRequest.newBuilder();
q.setRemoteId(gatt.getDevice().getAddress());
q.setCharacteristicUuid(characteristic.getUuid().toString());
if(characteristic.getService().getType() == BluetoothGattService.SERVICE_TYPE_PRIMARY) {
q.setServiceUuid(characteristic.getService().getUuid().toString());
} else {
// Reverse search to find service
for(BluetoothGattService s : gatt.getServices()) {
for(BluetoothGattService ss : s.getIncludedServices()) {
if(ss.getUuid().equals(characteristic.getService().getUuid())){
q.setServiceUuid(s.getUuid().toString());
q.setSecondaryServiceUuid(ss.getUuid().toString());
break;
}
}
}
}
Protos.ReadCharacteristicResponse.Builder p = Protos.ReadCharacteristicResponse.newBuilder();
p.setRequest(q);
p.setValue(ByteString.copyFrom(characteristic.getValue()));
p.setRemoteId(gatt.getDevice().getAddress());
p.setCharacteristic(ProtoMaker.from(characteristic, gatt));
characteristicReadSink.success(p.build().toByteArray());
}
}
@@ -710,7 +774,14 @@ public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristi

@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
Log.d(TAG, "onCharacteristicChanged: ");
Log.d(TAG, "onCharacteristicChanged: " + characteristic.getValue());
if(characteristicNotifiedSink != null) {
// Rebuild the ReadAttributeRequest and send back along with response
Protos.OnNotificationResponse.Builder q = Protos.OnNotificationResponse.newBuilder();
q.setRemoteId(gatt.getDevice().getAddress());
q.setCharacteristic(ProtoMaker.from(characteristic, gatt));
characteristicNotifiedSink.success(q.build().toByteArray());
}
}

@Override
25 changes: 17 additions & 8 deletions android/src/main/java/com/pauldemarco/flutterblue/ProtoMaker.java
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@
package com.pauldemarco.flutterblue;

import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
@@ -21,32 +22,40 @@ public class ProtoMaker {

private static final UUID CCCD_UUID = UUID.fromString("000002902-0000-1000-8000-00805f9b34fb");

static Protos.BluetoothService from(BluetoothDevice device, BluetoothGattService service) {
static Protos.BluetoothService from(BluetoothDevice device, BluetoothGattService service, BluetoothGatt gatt) {
Protos.BluetoothService.Builder p = Protos.BluetoothService.newBuilder();
p.setRemoteId(device.getAddress());
p.setUuid(service.getUuid().toString());
p.setIsPrimary(service.getType() == BluetoothGattService.SERVICE_TYPE_PRIMARY);
for(BluetoothGattCharacteristic c : service.getCharacteristics()) {
p.addCharacteristics(from(c));
p.addCharacteristics(from(c, gatt));
}
for(BluetoothGattService s : service.getIncludedServices()) {
p.addIncludedServices(from(device, s));
p.addIncludedServices(from(device, s, gatt));
}
return p.build();
}

static Protos.BluetoothCharacteristic from(BluetoothGattCharacteristic characteristic) {
static Protos.BluetoothCharacteristic from(BluetoothGattCharacteristic characteristic, BluetoothGatt gatt) {
Protos.BluetoothCharacteristic.Builder p = Protos.BluetoothCharacteristic.newBuilder();
p.setUuid(characteristic.getUuid().toString());
p.setServiceUuid(characteristic.getService().getUuid().toString());
p.setProperties(from(characteristic.getProperties()));
if(characteristic.getValue() != null)
p.setValue(ByteString.copyFrom(characteristic.getValue()));
for(BluetoothGattDescriptor d : characteristic.getDescriptors()) {
p.addDescriptors(from(d));
if(d.getUuid() == CCCD_UUID) {
if(d.getValue() != null && d.getValue().length > 0 && (d.getValue()[0] == 1 || d.getValue()[0] == 2)){
p.setIsNotifying(true);
}
if(characteristic.getService().getType() == BluetoothGattService.SERVICE_TYPE_PRIMARY) {
p.setServiceUuid(characteristic.getService().getUuid().toString());
} else {
// Reverse search to find service
for(BluetoothGattService s : gatt.getServices()) {
for(BluetoothGattService ss : s.getIncludedServices()) {
if(ss.getUuid().equals(characteristic.getService().getUuid())){
p.setServiceUuid(s.getUuid().toString());
p.setSecondaryServiceUuid(ss.getUuid().toString());
break;
}
}
}
}
Loading

0 comments on commit 9bc4c0f

Please sign in to comment.