I developed two applications that implements both GATT roles: server and client.
In my case, the GATT server is also the GAP peripheral and the GATT client is the GAP central.
I can connect/disconnect the client to/from the server, but I found some problems when I tried to stop advertising in the moment when the client is connected to the server. In this case, the connection is broken.
I can't understand. If two devices are connected, the server shoud not need to transmit advertising packets to keep alive the connection... That's strange.
I am using the SDK version 23
After receiving STATE_CONNECTED in your GattServerCallback, before stopping advertise, run mGattServer.connect(device, false); to tell the fool Android that "Hey, I want to keep this connection alive!"!
According to the BLE specification following is allowed: A device which is in connection state can have both master and slave roles simultaneously. Master and slave devices may have multiple connections. The only restriction is the following: Two BLE devices cannot be both master and slave for each other at the same time since
two BLE devices can have only one connection at a time.
Although BLE specification states these rules, it is the BLE chip in your device that limits the number of connections and number of other BLE events that are happening simultaneously. If you see unexpected behaviors on BLE, I would suggest to try the same thing with different devices that have different BLE chips.
After a connection is established, it is lower layers' task to keep the connection alive. You don't need to do anything using the API. If the device is in connection, the connection may not be stable in case it advertises at the same time depending on the capability of the chip.
Related
I am trying to make an app, that when it sees a specific bluetooth device to connect to it and send a command and before loose that connection to send another command.
The device is standard bluetooth serial device.
Is there a way to check when i am going to loose the connection?
No unfortunately Bluetooth doesn't work this way. You are usually notified that the remote device disconnected and you can even get the disconnection reason (e.g. BT_HCI_REMOTE_USER_TERMINATED_CONNECTION), but by then it is already too late and the link between your device and the remote device is already lost. Generally speaking, the way a disconnection works is that there are empty Bluetooth packets sent back and forth between the two devices (similar to an ACK) to indicate that the link is alive. If that packet does not arrive after a certain timeout, the BLE stack throws an event to the application notifying it that the connection has been lost (i.e. a disconnection event).
If you are using Bluetooth Low Energy, and if you are in control of both devices (your one and the remote one), then you could implement additional communication on the advertising channels. This is not as efficient as performing the communication through a connection, but you can advertise this additional command upon disconnection, and the remote device would scan for this new command upon disconnection as well.
I hope this helps.
I am new to Bluetooth, but have been working for a month or so on a Android Client that connects to a BLE peripheral to write data to a characteristic.
My BLE peripheral is a nrf52832 (Nordic) device and I have loaded the BLE_SM (security manager) example project so that I can use bonding/pairing for secure communications.
My Android code pairs/bonds successfully to the peripheral, but from what I can see the peripheral now stops advertising. I'm not sure if this is normal or it's because I received a gap.onDisconnection event of type REMOTE_USER_TERMINATED_CONNECTION.
Irrespective I am bonded so you would think I could now not need to scan anymore for the device and could just call device.connectGatt(), but it is not working and my callback gets a GATT STATE_DISCONNECTED event.
I read in another post that had pasted the following from Nordic (Tutorial):
It is not possible to connect to a peripheral which is not
advertising, even though one knows its address from before. This is
because the peripheral will only turn on the receiver for a set amount
of time after transmitting an advertisement. This time is used to
listen for connection requests and scan requests.
If this is in fact true, it seems I would be unable to stop the peripheral continually advertising, which is not helpful if I am trying to reduce the peripheral's power consumption.
The citation is 100% true. Connection setup has nothing to do with if the device is bonded or not (assuming you don't use directed advertising). If the peripheral is neither connected nor advertising, the radio is completely off and therefore a central can't connect.
If you want to minimize power consumption, make sure you don't advertise when you don't need to. Depending on your use case, can you have anything triggering advertising? For example a button or a sensor event?
If you need to advertise all the time, you can try use a longer advertising interval to save battery, but this will increase discovery and connection setup time.
What is the main difference between the WiFi aware and WiFi P2P technologies?
Using WiFi P2P you can establish a connection between two or more nearby devices without the need of common network. But the android docs spec also that
Wi-Fi Aware capabilities enable devices running Android 8.0 (API level
26) and higher to discover and connect directly to each other without
any other type of connectivity between them.
What is the difference between them?
Based on the Android docs, with Wi-Fi Aware, you can send data (lightweight only! max of 255 bytes) between the devices during service discovery phase and when needed, you may open a connection between the devices to send larger data. With Wi-Fi peer-to-peer, you have to perform some kind of authentication first and then open a socket before you can send data between the devices.
Here are the portions of the Wi-Fi aware overview where I got these information:
The Wi-Fi Aware APIs let apps perform the following operations:
Discover other devices: [...] After the subscriber discovers a publisher, the subscriber can either send a short message or establish a network connection with the discovered device.
Create a network connection: After two devices have discovered each other [...] they can create a bi-directional Wi-Fi Aware network connection without an access point.
Note: Messages are generally used for lightweight messaging, as they might not be delivered (or be delivered out-of-order or more than once) and are limited to about 255 bytes in length.
Additionally, with Wi-Fi Aware, developers have a choice between the methods createNetworkSpecifierOpen() and createNetworkSpecifierPassphrase() of the DiscoverySession class to open unencrypted or encrypted connections, respectively, between the devices.
With Wi-Fi peer to peer, developers have no other choices other than the WifiP2PManager.connect() method. Calling it will trigger a dialog box (Push Button Configuration) on the device being connected to and that dialog box will only appear when two devices connects to each other for the first time.
By the way... modifying the WpsInfo of a WifiP2pConfig is useless; it will always use the Push Button Configuration option. I tested it on the devices I have (Asus ZC520TL-Nougat, Asus ZE551ML-Marshmallow, Huawei Y5-Marshmallow, and Huawei T1-KitKat). The PBC dialog appeared even if the wifip2pconfig.wps.setup is not equal to WpsInfo.PBC. Feel free correct me if this isn't true for all devices because it might just be an OEM thing.
For more information visit Wi-Fi peer-to-peer overview.
WiFi Aware is significantly faster at establishing a connection.
The discovery stage is much more flexible: you can add your own information (255 bytes) to your service announcements and exchange short messages (255 bytes) with other peers without needing to establish a connection.
However, all the connections in WiFi Aware are one-to-one. A device can only have a very limited number of simultaneous connections (two, in the case of the Pixel 2).
For comparison, WiFi P2P works more similarly to an automatic Hotspot: the devices negotiate among themselves which of them will create a WiFi network, and afterwards other devices can join in. If you manage to get the WiFi SSID/password, it is possible to join the network manually.
My understanding is that WiFi P2P has worse performance in terms of battery (at least in the case of the central node).
From https://www.wi-fi.org/knowledge-center/faq/what-is-the-relationship-between-wi-fi-aware-and-wi-fi-direct:
Wi-Fi Aware is a similar peer-to-peer connectivity technology to Wi-Fi Direct. However, while Wi-Fi Direct requires a centralized coordinator, called a Group Owner, Wi-Fi Aware creates decentralized, dynamic peer-to-peer connections. Many applications, such as Miracast and direct printer connections, work well with Wi-Fi Direct. Wi-Fi Aware is positioned to provide peer-to-peer connectivity in highly mobile environments, where devices join or leave in a less deterministic manner. Whether it's professionals at a crowded conference to find each other or strangers on a subway momentarily joining a multi-player game, Wi-Fi Aware connections seamlessly adapt to changing environment and usage conditions.
There isn't much documentation in regards to setting up a pin with a Bluetooth Low Energy peripheral device. In my Gatt service I have set the BluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED_MITM and receive a GATT_INSUFFICIENT_PERMISSION message in my log upon attempting to write to the Bluetooth Write Characteristic I have set up. I was wondering what the process is for enabling encryption for the peripheral.
Thanks
Bluetooth LE requires to devices to be bonded (paired) before they can successfully encrypt transmissions used to read/write a given characteristic. Android does not handle this process for you, so you will need to initiate pairing between the two devices before any GATT transactions are attempted.
With the current Android Things previews, development of the Settings app (which generally handles much of the device pairing process) is heavily in flux. As such, traditional workflows for pairing a device are likely not to work at the moment until these changes are complete.
You could try initiating a pairing request from your Android Things device via createBond(), listening to the ACTION_PAIRING_REQUEST broadcast, and applying the necessary PIN code with setPin(). Some combination of those may work for you in the short term until a more official solution is available.
I'm developing an application that tries to connect my smartphone to a BLE device with Gatt (it can be either a smartphone or a BLE device) and read just a piece of data. This data will dynamically change and I want to keep this data as the value of a characteristic of a service. My main purpose is to read this data from the client side. Since I am connecting with Gatt, I think the only way is to store that data as the value of characteristic.
How can I add a service and a characteristic to the BLE device from the app which I created for the BLE device? I did a research and found some useful information from here. But this helps you create a service for a device you have connected to. Please help me or give me an idea. Thank you very much
Seems to me that what you are trying to do is to connect to a device and add a service on that remote device. That is not have it works and you will not be able to create an app that does this.
In BLE, both sides have a Gatt server. The addService API call in BluetoothGattService is only for adding services to your local Gatt server, not the remote server.
This is how it needs to work:
Your phone is called the central (or master), the device you are connecting to are the peripheral (or slave).
Both sides can define their local Gatt server (typically before they connect). The local Gatt server is mandatory for both sides.
If you can write the firmware running on the peripheral you can certainly create the services and characteristics you need to make your application work (again this is usually as the devices is starting, not after a connection has been made)
Your phone will connect to the peripheral and can read from or write to the Gatt server running on the remote device using the Android Gatt client. The structure however remains unchanged.
To be able to answer more detailed a lot more information on the setup is necessary.
Android (prior to 5.0) doesn't support acting as a peripheral mode you can write applications in order to act as central(master) or Observer mode.
Since Android 5.0, you can use android.bluetooth.le API along with BluetoothGattServer to adopt peripheral role on your Android 5.0+ devices.