-
-
-
Hi.
I've created Android app that serves Location and Navigation service, Device info, and Time service (standard GATT profiles). LNS has 3 characteristics.
Currently in Bangle JS2 client app I can subscribe to one service, one characteristic.function connection_setup() { NRF.requestDevice({filters:[{namePrefix:"Pixel 4a"}]}).then(function(d) { device = d; console.log("Found device: "+d.name); E.showMessage("Found device"+d.name); return device.gatt.connect(); }).then(function(ga) { gatt = ga; E.showMessage("Connected"); console.log("Connected"); lastReceivedTime = new Date(); return gatt.getPrimaryService("1819"); //How to get another services here? }).then(function(s) { service = s; return service.getCharacteristic("2a67"); //How to get other characteristics here? }).then(function(c) { characteristic = c; characteristic.on('characteristicvaluechanged', (event)=>updateSpeed(event)); return characteristic.startNotifications(); }).then(function() { console.log("Notifications subsribed"); E.showMessage("Notifications subsribed"); }).catch(function(e) { E.showMessage(e.toString(), "ERROR"); console.log(e); }); }
How to subscribe for LNS multiple characteristics, and to Time service, and also query Device info? Each .then() has only one return, I am not getting how to fork or chain it.
-
-
Hi Gordon,
I've loaded the cutting edge build 2v14.64.
Now it shows the devices but fails to device.gatt.connect();
It shows:var device; var gatt; NRF.requestDevice({filters:[{services:["1805"]}]}).then(function(d) { device = d; console.log("Found device: "+d.name); return device.gatt.connect(); }).then(function(ga) { gatt = ga; console.log("Connected"); }).catch(function(e) { console.log(e); });
WARNING: Unknown phy "undefined" Found device: Pixel 4a ERR 0x7 (INVALID_PARAM)
-
-
'A' does make sense.
I just thought 'C' would be more flexible. So 'C' can be 'A', can be 'B', or even something in between. Like:function myRespondASAPHandler(event){ NRF.confirmIndication(event); //do something ... } function myRespondAfterDoneHandler(event){ //do something NRF.confirmIndication(event); } ... characteristic.on('characteristicvaluechanged', (event)=>myRespondAfterDoneHandler(event));
Response "After Done" will serve scenarios where processing of a message may take time. So it will prevent flooding the Client by too frequent indications. Otherwise some additional synchronization logic should be done, like skipping next coming indications if a current one is still in processing.
-
Great! Just one thing. I read different opinions how the confirmation should work:
A - automatically, as soon as an indication received
B - automatically, after an indication handler finished
C - manually, inside an indication handler where App can do some checks.I thought C should be universally cover all cases. But, of course, it will require to manually place the confirmation call. Which is not a big deal.
On the diagram from KBA_BT_0104: Acknowledged vs Unacknowledged GATT operations
the response goes from App level, not from stack. I understand the NRF wrapper lib is not a BLE stack, but it is not an App either. -
Hi Gordon,
yes, when I choose to send indications, with confirm=true, it then doesn't work. It looks like Espruino does not respond with confirmation. And in BLE the initiator of an indication cannot send another indication if it has not received the confirmation.
I read what I could find in Google, some say that confirmation should be send by Client app, some say that it is a part of ATT stack and should be sent automatically.
I've found this func from Nordic API https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.s132.api.v5.0.0%2Fgroup___b_l_e___g_a_t_t_c___f_u_n_c_t_i_o_n_s.html&cp=2_3_1_1_0_2_2_2_7&anchor=ga173e2d16c9bbd24dcf2c724ded6708a5
uint32_t sd_ble_gattc_hv_confirm ( uint16_t conn_handle, uint16_t handle )
Is it what is needed?In my case I control the both sides. But I want to make the sides maximally standard. For example my Bangle "Speed display" should work not only with mine Android GATT Location and Navigation service but with any other GATT Location and Navigation service that other GNSS devices can provide.
And there in the GATT specs https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=271997 is stated3.4 LN Control Point
If the LN Control Point is supported, profiles utilizing this service are required to ensure
that the Client configures the LN Control Point characteristic for indications (i.e., via the
Client Characteristic Configuration descriptor) at the first connection.The Server should use indications in other transactions as well, where Client writes values to the server, for example - "The response shall be indicated when the route has been selected using the Response Code Op Code, the Request Op Code along with “Success” or other appropriate Response Value."
I've found a good article with clarification of how the confirmations work.
https://community.silabs.com/s/article/kba-bt-0104-acknowledged-vs-unacknowledged-gatt-operations?language=en_USSo, it looks like the App should issue the confirmation. I assume it should be done from a notification/indication handler function.
If I am correct, we need just to introduce a new function in NRF, something like confirmIndication(event). -
Well. Actually it does not work. Additionally to setting PROPERTY_INDICATE to the characteristc, the actual notification call BluetoothDevice.notifyCharacteristicChanged had hardcoded confirm=false parameter.
After I've set it to True, the BJS2 NRF receives the indication just first time after the connection and subscription established. Then it does not receive indications.
chracteristic in Bangle shows:>characteristic =BluetoothRemoteGATTCharacteristic: { uuid: "0x2a2b", handle_value: 42, handle_decl: 41, properties: { broadcast: false, read: true, writeWithoutResponse: false, write: false, notify: false, indicate: true, authenticatedSignedWrites: false }, "#oncharacteristicvaluechanged": function (event) { ... }, handle_cccd: 43, value: DataView: { buffer: new Uint8Array([230, 7, 7, 12, 18, 43, 16, 2, 1, 0]).buffer, byteOffset: 0, byteLength: 10 } }
Do I have to send indication acknowledgements from the Bangle code, like from the event handler that is my updateTime(event) func? If so how to do it?
-
-
The BluetoothRemoteGATTCharacteristic.startNotifications() works fine when in Android program I configure characteristic to send notifications (PROPERTY_NOTIFY).
Bangle does not receive anything when I set to send indications (PROPERTY_INDICATE)
Android code:// Current Time characteristic BluetoothGattCharacteristic currentTime = new BluetoothGattCharacteristic(CURRENT_TIME, //Read-only characteristic, supports notifications BluetoothGattCharacteristic.PROPERTY_READ // | BluetoothGattCharacteristic.PROPERTY_NOTIFY, | BluetoothGattCharacteristic.PROPERTY_INDICATE, BluetoothGattCharacteristic.PERMISSION_READ);
Bangle code:
var in_connection_setup = false; function connection_setup() { if(in_connection_setup) return; in_connection_setup = true; E.showMessage("Scanning for CSC sensor..."); NRF.requestDevice({filters:[{services:["1805"]}]}).then(function(d) { device = d; console.log("Found device: "+d.name); E.showMessage("Found device"+d.name); return device.gatt.connect(); }).then(function(ga) { gatt = ga; E.showMessage("Connected"); console.log("Connected"); return gatt.getPrimaryService("1805"); }).then(function(s) { service = s; return service.getCharacteristic("2a2b"); }).then(function(c) { characteristic = c; characteristic.on('characteristicvaluechanged', (event)=>updateTime(event)); return characteristic.startNotifications(); }).then(function() { console.log("Notifications subsribed"); E.showMessage("Notifications subsribed"); //g.reset().clearRect(Bangle.appRect).flip(); }).catch(function(e) { E.showMessage(e.toString(), "ERROR"); console.log(e); }); in_connection_setup = false; }
Am I doing something wrong?
Is there a way to receive indications? -
Hmm, all cards I have have "standard" barcodes. :)
Another way of optimization - to get a checksum(like md5) from a bitmap and put it in local cash. Android will send list of card names with checksums, Bangle app will check checksums in local cash, if not found it will request to download it from Android. -
Do you really need to send barcodes from Android to Bangle each time a user wants to show a barcode in a store?
Well, it seems like the best user experience as it allows you to keep managing your loyalty cards on your phone instead of having to duplicate the cards you care about.
Sending bitmaps via BLE each time may be not a best way to do it.
Barcodes are basically 1 row of pixels expanded vertically. I would send 1 row bitmap and then expand it in Bangle JS. 176/8 will be just 12 bytes. -
I am not sure about GB. I've made test "Current Time" GATT server, and it works.
Regarding roles. In the standard L&N GATT it is specified:
https://www.bluetooth.org/DocMan/handlers/DownloadDoc.ashx?doc_id=271996
BLUETOOTH PROFILE SPECIFICATION Page 8 of 32Location and Navigation Profile
2 Configuration
2.1 Roles
The profile defines two roles: LN Sensor and Collector. The LN Sensor is the device
that reports speed, distance, location, elevation, and/or navigation data to a Collector.
The Collector is the device that receives the data from a LN Sensor while connected to
a LN Sensor.
The LN Sensor shall be a GATT Server.
The Collector shall be a GATT Client
...- The LN Sensor shall use the GAP Peripheral role
So, it looks like I've architected my apps correctly :)
- The LN Sensor shall use the GAP Peripheral role
-
-
-
I am lost. :).
So what would you suggest for my use case? - I want to see a speedometer when I am windsurfing. Smartphone has much better GPS chip and antenna, as well as other capabilities like L5, AGPS, and even DGNSS and RTK. Instead of using internal Bangle GNSS I am going to use the smartphone's one. And Bangle will just display what I need - speed, time, may be map with location and track, may be some supplementary info like accuracy and number of sats.
So I need to pass that data to the watch. I could make a custom service, but the standard Location and Navigation already includes all I need (except may be timezone). And it can be compatible with other GNSS pocket receivers. I guess they play a peripheral role in GAP. So my smartphone should mimic same. -
then for getting updated values one would need to scan repeatedly from phone => more phone battery usage
I thought after the connection between Central and Peripheral is established they agree on a receiving/transmission schedule and turn radio on just in time synchronously, during that periods GATT server may send characteristics updates. So no scan is required.
With my POC GATT Current Time service I can even stop advertising at Android, and updates are still coming to my Bangle.
It looks like in BLE Central/Peripheral is independent from Server/Client. It is possible to make Client to play Peripheral role and advertise. Then Server should scan. But it looks quite weird to me, I am used to a world where Servers listen and Clients initiate connection. :)
-
Scanning for advertising packets however takes more power
ok, but it happens once (in my case), when I start the app, it scans, connects to Android, then I assume, it just listens for updates. Does it still draws more power?
Another caveat having a peripheral/server on watch - it will be second peripheral, so no debugging is possible because only one device of each kind is currently supported. Or I am wrong again?
-
Hi guys,
yeah, BLE is weird (from my perspective) :) - Peripheral usually acts as a server and is advertising, Central acts as a client, scans and connects... Will in this case the Peripheral waist power for constant advertising? Other words will a Peripheral use more power for communication than a Central?
What I want to make is a lightweight program in BJS2 that gets data from "Location and Navigation" GATT service that runs on smartphone (Android). Then it just displays it on screen.
Assuming that advertisement will eat power I've decided to place the Server on smartphone, and Client on watch. Is it right decision?If the Client' name is not part of the GAP, then how I could whitelist clients, so only my watch can connect? By MAC only? I do not think it will be convenient for user to get the watch's MAC somehow and type it into Android. I envisioned it something like a standard BT pairing. Server will show a name of a client that tries to pair an user will allow or not. What is a best practice?
Can NRF be used to tap watch MAC into Android? -
I think an ethanol sensor should be added via BLE.
https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6407881/ -
The service on Android is standard Current Time Service 1805. It does not have that characteristic. I am just started playing around with this BLE technology, I am complete novice in.
The Android GATTService API has BluetoothDevice class (https://developer.android.com/reference/android/bluetooth/BluetoothDevice) that is instantiated upon BJS2 connects. The class has method getName(). I assumed that the name should be populated automatically as a part of connection/bonding protocol. I can see MAC. I expected there will be something like "Bangle 9713" in .getName() that should be somehow passed by NRF device.gatt.connect();.
Is it not a case? Or my understanding is not correct?
Hmm... well, yes, why not.... I'll try.