I've created a test application with Bluetooth Low Energy (BLE) to perform pooling on the BLE device every 500ms, sending request and receiving response. The BLE device has a "Characteristic" with "Read, Write and Notify Descriptors". After signing in to BLE, an Subscribe is executed on that "Characteristic" via CurrentBLEDevice.SetCharacteristicNotification. The value of "Characteristic" is read in the CurrentBLEDevice.OnCharacteristicRead event (where OnCharacteristicRead = DidCharacteristicRead). Everything works fine until the CurrentBLEDevice.OnCharacteristicRead event stops responding for no reason. (Delphi 10.2.1, Android 5.0).
I have not been able to simulate the error yet and would like to know if there is any test I can do to simulate or fix error.
procedure DidCharacteristicRead(const Sender: TObject;
const ACharacteristic: TBluetoothGattCharacteristic;
AGattStatus: TBluetoothGattStatus);
var FCharactValueGet: TBytes;
begin
if AGattStatus <> TBluetoothGattStatus.Success then Exit;
FCharactValueGet:= [];
FCharactValueGet := ACharacteristic.Value;
end;
Related
Is it possible to detect when a button has been pressed on a BLE HID device using react-native-ble-plx?
I want to use these BLE remotes to have a cheap and robust way of controlling a React Native app with external devices (avoiding making a new project using ESP32 or it's variants would be preferred). When connected through the Android OS it works as simple volume up and volume down buttons - which triggers camera shutter, as intended. However, when connected to a BLE app (tested with LightBlue and with a React native app) that functionality is gone.
I have a few of these remotes and need to detect when a button was pressed and which remote was pressed on. Because they are BLE and not Bluetooth classic more than one can be connected at the same time.
Detection of volume up and volume down actions works by using react-native-keyevent but only when the remotes are connected to the OS and there is no way to get which remote triggered the action.
By using this piece of code to try to monitor all characteristics only errors are returned:
await bleManager.connect(discoveredDevice);
let discoveredServices = (await (await discoveredDevice.discoverAllServicesAndCharacteristics()).services());
for (let iService = 0; iService < discoveredServices.length; iService++) {
let characteristics = await discoveredServices[iService].characteristics();
for (let iCharacteristic = 0; iCharacteristic < characteristics.length; iCharacteristic++) {
characteristics[iCharacteristic].monitor((error: BleError | null, characteristic: Characteristic | null): void => {
if (error) {
console.error(error.message);
return;
} else {
console.log(characteristic?.value);
}
});
}
}
The following error occurs for all monitor() calls - with different UUIDs:
ERROR Characteristic 0000ae42-0000-1000-8000-00805f9b34fb notify change failed for device ? and service 0000ae40-0000-1000-8000-00805f9b34fb
A screenshot containing the services and characteristics of the device captured within LightBlue can be found here
This question might be duplicate of this question
Thanks to the help of many Stackoverflow contributors, I have successfully completed my Windows VCL project to, ping a number of IP Addresses, add them to an SQLtable, sort them by ping time and automatically set the IpV4 DNS settings to the fastest 2 addresses. This works perfectly under Windows.
I am now trying to create a similar application running under Android. I am using idIcmpclient to ping the addreses and pick up the IdICMPClient1.ReplyStatus.MsRoundTripTime. The code compiles and installs on my Android test device(s). However when run under Android, I receive a Socket #1 error. The testing code is below.
procedure TForm1.Button1Click(Sender: TObject);
var
ipAddr: string;
begin
ipAddr := '188.132.234.170';
IdIcmpClient1.ReceiveTimeout := 200;
IdIcmpClient1.Host := ipAddr;
IdIcmpClient1.ping();
if IdIcmpClient1.ReplyStatus.ReplyStatusType = rsEcho then
begin
Memo1.Lines.Add(IntToStr(IdIcmpClient1.ReplyStatus.MsRoundTripTime));
Memo1.Lines.Add(IdIcmpClient1.ReplyStatus.Msg)
end
else if IdIcmpClient1.ReplyStatus.ReplyStatusType = rsTimeout then
begin
// have a timeout, link is down
end
else
begin
// do something else
end;
end;
I have looked to see if there are peculiarities with IdIcmpclient and other OS's and have found out that it does not work with iOS , something to do with Raw Sockets.
I am assuming that maybe the same case applies to Android, which leaves me with a bit of a problem and possibly an untimely end to my new Android project.
If IdIcmpClient.Ping does not work under Android, is there an alternative method to Ping addresses and get the return times.
Any help much appreciated
My BLE server permanently measures a sensor value and sends a notification with 20 byte user data after each measurement. The goal is to generate as much throughput as possible.
On the client side, the value sent by the server is received and processed.
rxBleConnection.setupNotification(setDescriptorEnableNotification(characteristic))
.flatMap(notificationObservable -> notificationObservable)
.observeOn(Schedulers.newThread())
.buffer(1)
.subscribe(bytes -> {
onNotificationReceived(bytes, buffer);
} , throwable -> {
// Handle an error here.
onNotificationSetupFailure(throwable);
}
);
If I set the Connection intervall to 11.25ms, I receive all values. However, if I set the connection interval to 30ms, I receive a few values and then the connection is closed.
In the Android Log i see the followed message:
BleGattException status=8 (0x8),
bleGattOperationType=BleGattOperation{description='CONNECTION_STATE'
Why is the connection interrupted and what is the trigger?
With the help of a BLE Sniffer this is not recognizable. The set connection parameters are accepted and the transfer begins. Suddenly the transmission ends and the error message appears.
Update:
BLE Sniffer screenshot has been added:
30ms, this is connection interval you set in server or android?
Btw, on android you can set speed mode
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
mBluetoothGatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH);
}
Error 8 means the connection timed out. There is nothing wrong on the Android side. The problem is with the communication between the two Bluetooth controllers. If you have a sniffer then you should be able to see who is the one that fails to send packets.
Here is an Image from BLE Sniffer.
BLE Sniffer
I have the similar problem. On Android 7.0 there were two ways to keep connection:
1) If devices are bonded and there is a charachteristic reading callback with constant thread of packets. If there are no packets by some time, then connection fails.
2) If devides are not bonded, but I do TXCharacheristic.read every few seconds. If don't do that some time, then connection fails.
But now in Android 7.1.2 this way doesn't work.
May be the first way will work for you.
On your Android device you should make bonding, on your kit you should handle this bonding.
On Nexus 6P and Samsung S7 it doesn't work anymore, but I didn't try it on the other devices.
I suppose, you have min connection interval 7.5 on your BLE kit, but now it is deprecated on Android.
Try to set min connection interval to 11.25 on your BLE kit and set connection priority
gatt.requestConnectionPriority(CONNECTION_PRIORITY_HIGH);
where CONNECTION_PRIORITY_HIGH = 1
in onConnectionStateChange.
It had worked for me when I had changed min connection interval in my nordic from 7.5 to 11.25.
I have with my delphi code found the device I want to connect to and display services available. When I do the DiscoverServices for the device I found the method returns false meaning it didn't started. I suspect that this is because the device is not connected.
Following the example in https://developer.android.com/guide/topics/connectivity/bluetooth-le.html#read I do the whole discover part but I have found no equal thing in delphi that does
device.connectGatt(this, false, mGattCallback)
How do I go about to connect the device to my android phone in Delphi?
Am currently doing like the following
FBLEDevice := FBluetoothManagerLE.LastDiscoveredDevices.First;
FBLEDevice.OnServicesDiscovered := GetServicesAndCharacteristics;
if FBLEDevice.DiscoverServices = False then
Memo1.Lines.Add('DiscServ could not start')
else
Memo1.Lines.Add('Discover Services started');
SOLUTION:
You apparently don't need to connect in some special way as I though, the problem that my method won't start was because there are currently no services to discover on the module I am using.
I want to connect with Android to a bluetooth printer with Delphi, using the technique described in the Bluetooth Paired Devices Browser example by David I.
My printer is the Panda BIXOLON SPP-R200II:
I get the Error:
"java.io.IOException: read failed, socket might closed or timeout, read ret: -1"
by sock.connect;
Here is my Code:
procedure TForm1.ListView1ItemClick(const Sender: TObject;
const AItem: TListViewItem);
begin
ShowMessage('You selected: '+Aitem.Text);
// depending on the bluetooth device selected - do something with it
targetMACAddress:=Aitem.Detail;
if trim(targetMACAddress)='' then exit;
Adapter:=TJBluetoothAdapter.JavaClass.getDefaultAdapter;
remoteDevice:=Adapter.getRemoteDevice(stringtojstring(targetMACAddress));
sock:=remoteDevice.createRfcommSocketToServiceRecord(UID);
try
sock.connect;
except
on E : Exception do
ShowMessage(E.Message);
end;
if not sock.isConnected then
begin
ShowMessage('Failed to connect to Try again...');
exit;
end;
listview1.Visible:=false; // hide the chooser
label1.Visible:=false; // hide the chooser
reload.Visible:=false; // hide the chooser
end;
All communication made with the Bluetooth device must be carried out through Threads.
I transcribed a project in Android Studio for Delphi, using threads, and everything worked.
Do not use Timer, use the TThread object.