inovait / neatle Goto Github PK
View Code? Open in Web Editor NEWA Neat BluetoothLE library for Android
License: MIT License
A Neat BluetoothLE library for Android
License: MIT License
Really would just need to expose the underlying BluetoothGatt
instance so users can in turn call requestMtu
method:
https://developer.android.com/reference/android/bluetooth/BluetoothGatt.html#requestMtu(int)
The example includes the following note:
Note: An active subscription will keep a ConnectionMonitor with setKeepAlive(false) (the default setting) alive.
Can you make it possible to get an access to this ConnectionMonitor?
Hey, at first thx for your work!
second: can you add an example in wiki with WRITE-OPERATION?
I'm an newbie android developer, and I'm trying to write some bytes(like 0x11) to my BLE device, I can't get further without examples.
Add support to automatically deploy artifacts built on TravisCI to Bintray and GitHub releases.
So far i could find out is the type when invoking SubscribeCommand.start() always Type.SUBSCRIBE_NOTIFICATION. It looks this feature to make this decision is not implemented?
Hi,
I'm using neatle to connect one or more BLE cycling sensors in an Android app. These are long lasting connections and I'm setting the keepAlive flag in a ConnectionMonitor.
Occasionally, after some time I'm getting the following exception during the connection :
java.lang.IllegalStateException at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:697) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:902) at java.lang.reflect.Method.invoke(Method.java:372) at java.lang.reflect.Method.invoke(Native Method) at android.app.ActivityThread.main(ActivityThread.java:5254) at android.os.Looper.loop(Looper.java:135) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Handler.handleCallback(Handler.java:739) at si.inova.neatle.Device$6.run(Device.java:480) at si.inova.neatle.operation.CharacteristicSubscriptionImpl$1.onConnectionStateChanged(CharacteristicSubscriptionImpl.java:56) at si.inova.neatle.operation.CharacteristicSubscriptionImpl.access$000(CharacteristicSubscriptionImpl.java:39) at si.inova.neatle.operation.CharacteristicSubscriptionImpl.subscribeOnDevice(CharacteristicSubscriptionImpl.java:130) at si.inova.neatle.operation.OperationImpl.execute(OperationImpl.java:97) at si.inova.neatle.Device.execute(Device.java:220) at si.inova.neatle.Device.connect(Device.java:388)
I'm doing the following to connect a device (here for a csc sensor) :
final BluetoothDevice device = Neatle.getDevice(macAddress));
final CharacteristicSubscription cscSubscription = Neatle.createSubscription(context, device, Bluetooth.CSC_SERVICE, Bluetooth.CSC_MEASUREMENT_CHARACTERISTIC);
cscSubscription.setOnCharacteristicsChangedListener(sensorDataHandler.getBLEListener());
cscSubscription.start();
final ConnectionMonitor monitor = Neatle.createConnectionMonitor(context, btDevice);
monitor.setOnConnectionStateListener(new ConnectionStateListener() {
@Override
public void onConnectionStateChanged(Connection connection, int newState) {
switch (newState){
case BluetoothAdapter.STATE_DISCONNECTED:
log("sensor "+ sensorName + " disconnected");
break;
case BluetoothAdapter.STATE_CONNECTING:
log("sensor "+ sensorName + " connecting");
break;
case BluetoothAdapter.STATE_CONNECTED:
log("sensor "+ sensorName + " connected");
break;
case BluetoothAdapter.STATE_DISCONNECTING:
log("sensor "+ sensorName + " disconnecting");
break;
}
}
});
monitor.setKeepAlive(true);
monitor.start();`
What am I doing wrong here ? Can you help me ?
Thank you
Robert
i'm using Neatle operation to write characteristic, if I put InputSource to StringInputSource("100") like code below, i was excepting to get chaged major to 100 but i get 257 error
code for operation
final Operation operation = Neatle.createOperationBuilder(this)
.write(SERVICE_UUID_USERDATA,CHARACTERISTIC_UUID_MAJOR, new StringInputSource("100"))
.onFinished(new SimpleOperationObserver() {
@Override
public void onOperationFinished(Operation op, OperationResults results) {
Log.i(TAG, "onOperationFinished: op: " + op.toString());
Log.i(TAG, "onOperationFinished: result: " + results.toString());
Log.i(TAG, "onOperationFinished: ");
if(results.wasSuccessful()){
Log.i(TAG, "onOperationFinished: success");
Log.i(TAG, "onOperationFinished: result: " + results);
}else {
Log.i(TAG, "onOperationFinished: fail");
}
}
})
.build(Neatle.getDevice(mSelectedBeacon.getMac()));
operation.execute();
log for error
Connection attempt failed. Notifying all pending operations
OperationImpl: onConnectionStateChange, state:133, newState: 0
04-26 19:58:38.652 3955-3955I/Neatle: Command failed. Aborting operation. Error: 257
04-26 19:58:38.654 3955-3955/EditBeaconActivity: onOperationFinished: op: Operation[retryCount: 0, attempts: 0, commands:[WriteCommand[async:false -"characteristicUUID"] on [serviceUUID]]]
04-26 19:58:38.655 3955-3955/EditBeaconActivity: onOperationFinished: result: si.inova.neatle.operation.OperationResults@2216ffb
is there someting i missed?
I try to connect to a Micro:Bit and send a firmware/.hex-file with neatle (Micro:Bit Firmware Update Service).
It seems to fail in connecting to the device, but device.bondState
gives 12 and device.name
also returns the name of my device. Did I made something wrong, is there another way to do this with neatle, or is it just impossible to initiate a dfu firmware update without the nordic library?
The Kotlin Code:
val decodedBytes = Base64.decode(base64EncodedString, Base64.DEFAULT)
val inputSource = ByteArrayInputSource(decodedBytes)
var preferences = PreferenceManager.getDefaultSharedPreferences(this)
var macAddress = preferences.getString("Device", "")
if (macAddress!!.equals("", ignoreCase = true)) {
Toast.makeText(applicationContext, "No Device Selected", Toast.LENGTH_LONG).show()
} else {
val device = Neatle.getDevice(macAddress)
var state = device.bondState;
if((state) != 12) {
// ToDo pre set pin for bonding atempt to 000000 device.setPin("000000".toByteArray())
device.createBond()
}
Toast.makeText(applicationContext, "Send file to " + device.name, Toast.LENGTH_LONG).show()
var dfuServiceUUID = UUID.fromString("E95D93B0-251D-470A-A062-FA1922DFA9A8")
val dfuCharacteristicsUUID = UUID.fromString("E95D93B1-251D-470A-A062-FA1922DFA9A8")
val operation = Neatle.createOperationBuilder(this)
.write(dfuServiceUUID, dfuCharacteristicsUUID, inputSource)
.onFinished(object : SimpleOperationObserver() {
override fun onOperationFinished(op: Operation, results: OperationResults) {
if (results.wasSuccessful()) {
Toast.makeText(applicationContext, "SUCCESS", Toast.LENGTH_LONG).show()
} else {
Toast.makeText(applicationContext, "FAILED", Toast.LENGTH_LONG).show()
}
}
})
.build(device)
operation.execute()
}
The Log output:
I/Neatle: Resuming with Callback[Operation[retryCount: 0, attempts: 0, commands:[WriteCommand[async:false - e95d93b1-251d-470a-a062-fa1922dfa9a8] on [e95d93b0-251d-470a-a062-fa1922dfa9a8]]]]
I/Neatle: Write on e95d93b1-251d-470a-a062-fa1922dfa9a8 failed with status 133
I/Neatle: Command failed. Aborting operation. Error: 133
I/Neatle: Disconnecting on idle
Disconnecting
I/Neatle: Connection attempt failed. Notifying all pending operations
So far so good with NeatLE but once I've connected to a device I would like to update the signal strength in real time. Is this possible?
Once I tried to transport some bigger data (small JSON payload, e.g. wifi credentials) I found out, that the data isn't transported completely via a write operation. After a small investigation of your code, I've found out that the MAX_CHUNK_SIZE
in your ByteArrayInputSource
class is hardcoded set to 20
causing the problem. I would be great, that you provide an option to make it configurable in the client code in the newer versions.
Add support for RxJava2 - as a separate module and a separate library, that wraps around the NeatLE core.
Thanks for this library.
I'm attempting to perform a read and then I want to perform a write based on the result of the read - I thought I could use the OperationBuilder
for this but its not clear on how to use it in such a style.
Does the OperationBuilder
support this style of use? And if so, how?
Thanks!
First of all, I'd like to thank you for your contribution, it has been very easy to integrate and works very well so far.
I have a problem though. I'm pairing with a Heart Rate Monitor and this is the code I was using to extract the heart rate value from the BluetoothGattCharacteristic
from the Android framework class:
int flag = characteristic.getProperties();
int format = (flag & 0x01) != 0 ?
BluetoothGattCharacteristic.FORMAT_UINT16 :
BluetoothGattCharacteristic.FORMAT_UINT8;
int heartRate = characteristic.getIntValue(format, 1);
However, when I receive a CommandChange
on a subscription now, I don't have access to either the properties of the characteristic, or the characteristic itself, so I cannot extract the heart rate.
How should I proceed here? If it is not even possible with the current state of the library and its code needs to be modified, I can implement the necessary modifications if you provide some guidance.
This warning is given when building an app using proguard:
Warning:si.inova.neatle.operation.OperationBuilder: can't find referenced class si.inova.neatle.operation.SubscribeCommand$Type
Adding -dontwarn to your app's proguard-rules file is the temporary solution:
-dontwarn si.inova.neatle.operation.SubscribeCommand$Type
Hi,
Neatle 0.9.7
Android API Level 26
Nexus P
I'm having an issue with using the library when sending a series of 20 byte payloads to a BLE device.
After a time (could be after 4-5 times, could be after the 4,000th time - it's not deterministic), the transfer stops and this is produced:
W/BluetoothGatt: Unhandled exception in callback
java.lang.NullPointerException: Attempt to invoke virtual method 'void si.inova.neatle.operation.Command.onCharacteristicChanged(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic)' on a null object reference
at si.inova.neatle.operation.OperationImpl$GattCallback.onCharacteristicChanged(OperationImpl.java:327)
at si.inova.neatle.Device$GattCallback.onCharacteristicChanged(Device.java:635)
at android.bluetooth.BluetoothGatt$1$8.run(BluetoothGatt.java:443)
at android.bluetooth.BluetoothGatt.runOrQueueCallback(BluetoothGatt.java:725)
at android.bluetooth.BluetoothGatt.-wrap0(Unknown Source:0)
at android.bluetooth.BluetoothGatt$1.onNotify(BluetoothGatt.java:437)
at android.bluetooth.IBluetoothGattCallback$Stub.onTransact(IBluetoothGattCallback.java:184)
at android.os.Binder.execTransact(Binder.java:697)
The setup is like this:
I have a byte array of say 110KB that requires special formatting (basically a special header put on the first 4 bytes of the 20 byte array, with the 16 remaining bytes being the payload). I'm chunking up the byte array into 16 byte chunks, appending the header and sending it off. Using (in Kotlin):
So sending lots of this command:
fun writePayload(byteArray: ByteArray) {
Neatle.createOperationBuilder(context)
.write(serviceUUID, writeCharacteristicUUID, byteArray)
.build(device)
.execute()
}
Before that, I create a subscription, listening for a particular reply
Neatle.createSubscription(context, device, serviceUUID, readCharacteristicUUID)
.setOnCharacteristicChangedListener {
if(it.wasSuccessful() && it.value[2] == replyToTheSentCommand) {
onSuccess()
}
}
}
I send the first writePayload
command, then within the subscription, when it receives the change (i.e., the BLE device saying I've seen the first packet, here's my reply) I send the next writePayload
, which obviously triggers the subscription to fire again and the process continues until the end (all the chunks have been sent).
Does this help explain the background. I'm really puzzled as to why the error just seems to happen all the time, at different points during different runs.
Interestingly enough, if I put a watch on the OperationImpl#onCharacteristicChanged
method, it seems to work better (but still not 100%). This seems to suggest a timing issue? Perhaps the list of commands are being consumed and discarded to fast by Neatle, before the subscription has time to process the result?
-=david=-
Hello,
I've been using the library without a problem in devices with Android OS 5.x and 6.x to connect to a custom IoT device. But If I use the library to connect, using a device with 7.x OS, it fails. The IoT device is found during scan, but unable to connect.
If I use a third party app (ie, Nordisk's nRF Connect app) to test the connection, I have no problems.
Do you know of any known issues in Nougat?
Thanks!
Hi,
Could you please migrate this library from jCenter to Maven as jCenter is deprecated?
I am getting this error from Android version 10. Please check this.
More details :
Brand: Xiaomi Model: Mi A2 Orientation: Portrait RAM free: 795.8 MB Disk free: 7.28 GB
Version: 10 Orientation: Portrait Rooted: No
Fatal Exception: java.lang.ArrayIndexOutOfBoundsException: length=62; index=-95
at si.inova.neatle.scan.ScanRecord.createFromBytes(ScanRecord.java:98)
at si.inova.neatle.scan.ScanEvent.<init>(ScanEvent.java:43)
at si.inova.neatle.scan.LolipopLEScanner$ScanCallbackHandler.onLeScan(LolipopLEScanner.java:98)
at android.bluetooth.BluetoothAdapter$3.onScanResult(BluetoothAdapter.java:3020)
at android.bluetooth.le.BluetoothLeScanner$BleScanCallbackWrapper$1.run(BluetoothLeScanner.java:498)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7403)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:935)
There should be an option to scan for all BTLE devices and receive a list of available devices.
Android 12 does not require GPS to be turned on when scanning for devices using the BLUETOOTH_CONNECT/BLUETOOTH_SCAN permissions.
It seems that it will not scan unless I turn it on, even tho there's no errors logged.
We should add a sample application that demonstrates the usage of NeatLE.
The typedef annotation of SubscribeCommand is not found, and is not present in the packaged aar.
Every once in a while, an exception is thrown when trying to connect to a device.
We need to unify status codes that get return in status listeners (OperationObserver, CommandResult...), and use those status codes in all public calls.
Something like:
@IntDef({CommandStatus.SERVICE_NOT_FOUND, CommandStatus.CHARACTERISTIC_NOT_FOUND, CommandStatus.DESCRIPTOR_NOT_FOUND})
public @interface CommandStatus {
int SERVICE_NOT_FOUND = 0;
int CHARACTERISTIC_NOT_FOUND = 1;
int DESCRIPTOR_NOT_FOUND = 2;
}
NeatLE 0.9.4
Android 7.1
I'm getting the following exception :
java.lang.IllegalStateException:
at si.inova.neatle.Device.connect (Device.java:388)
at si.inova.neatle.Device.resume (Device.java:283)
at si.inova.neatle.Device.access$1000 (Device.java:54)
at si.inova.neatle.Device$4.run (Device.java:365)
at android.os.Handler.handleCallback (Handler.java:751)
at android.os.Handler.dispatchMessage (Handler.java:95)
at android.os.Looper.loop (Looper.java:179)
at android.app.ActivityThread.main (ActivityThread.java:6152)
at java.lang.reflect.Method.invoke (Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:776)
I'm seeing this is thrown when there is already a gatt instance. Is this exception really necessary here or wouldn't it be enough to nullify the gatt instance as the app is crashing at this point and I cannot catch the exception.
I will update to the latest 0.9.7 but the code regarding that exception did not change.
Thank you
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.