NordicSemiconductor / Android-nRF-Mesh-Library

The Bluetooth Mesh Provisioner and Configurator library.
https://www.nordicsemi.com/
BSD 3-Clause "New" or "Revised" License
406 stars 174 forks source link

Minimal example #570

Closed connyhald closed 11 months ago

connyhald commented 11 months ago

Is there a minimal example on how to use the mesh library?

I know the code for the example application but this is a rather complex app with many abstractions and indirections that are hard to follow. What I'm looking for is the minimal code to

Does anyone know something like this?

roshanrajaratnam commented 11 months ago

Hi @connyhald, the most minimalistic example is what the readme provides as of now. Here's the link pointing to it. https://github.com/NordicSemiconductor/Android-nRF-Mesh-Library#sample

connyhald commented 11 months ago

@roshanrajaratnam Thanks for you reply. I was hoping for something in between :smile:

Like what needs to be done after successful provisioning (using startProvisioning()) and sending a GenericOnOffSet message. Currently I'm trying to send ConfigCompositionDataGet but don't get any response. In fact it looks like I don't get any response at all no matter what I send.

roshanrajaratnam commented 11 months ago

To setup a basic network you need to do the following

  1. Provision a node
  2. Send ConfigCompositionDataGet
  3. Add an app key by sending ConfigAddAppKey
  4. Finally bind the application key that was added to a model that you want to send messages to.

Have you tried with the sample app if everything works? Are you using your own firmware?

connyhald commented 11 months ago

To setup a basic network you need to do the following

Thanks for confirming. This is what I'm trying to do.

Provision a node

Works, onProvisioningCompleted() gets called.

Send ConfigCompositionDataGet

That does not seem to work. I'm trying with createMeshPdu(meshNode.unicastAddress, ConfigCompositionDataGet()) it looks like the data is send but I'm seeing no reaction inside the log of the node and I'm not getting any response.

Have you tried with the sample app if everything works? Are you using your own firmware?

Yes, using nRF Mesh everything works fine. I've also spent many hours reading the code of the example app but fail to find any significant differences to my own code.

Do you have any other pointers for debugging this further?

roshanrajaratnam commented 11 months ago

Have you set up the mesh status call backs? You should get a callback every time a message is sent or received.

https://github.com/NordicSemiconductor/Android-nRF-Mesh-Library/blob/365c676595168fc07a1c739dbc9683c0532c2263/mesh/src/main/java/no/nordicsemi/android/mesh/MeshMngrApi.java#L36

connyhald commented 11 months ago

The MeshStatusCallbacks are registered and onMeshMessageProcessed is indeed being executed, but none of the other callbacks are ever called. This makes sense considering after provisioning no notifications are ever received in the notification callback (works fine during provisioning though).

The notification callback is setup as follows in the initialize() function of my BleManager:

setNotificationCallback(meshProxyDataOutCharacteristic).with { _, data ->
    meshManagerApi.handleNotifications(100, data.value!!)
}

with the notifications being enabled by executing

enableNotifications(meshProxyDataOutCharacteristic).suspend()

meshProxyDataOutCharacteristic is set in isRequiredServiceSupported by executing the following code:

gatt.getService(BleMeshUuids.meshProxyService)?.let {
    meshProxyDataOutCharacteristic = it.getCharacteristic(BleMeshUuids.meshProxyDataOutCharacteristic)
    meshProxyDataInCharacteristic = it.getCharacteristic(BleMeshUuids.meshProxyDataInCharacteristic)
}

Logcat shows the following entries, the second of which being emitted by the log function of my BleManager:

BluetoothGatt   D  setCharacteristicNotification() - uuid: 00002ade-0000-1000-8000-00805f9b34fb enable: true
System.out      I  [NORDIC_LOG] 4: Data written to descr. 00002902-0000-1000-8000-00805f9b34fb

Though it seems there is no error, the callback lambda registered after setNotificationCallback is never called. There is identical code for the provisioning data in/out characteristics which works the same way except with different UUIDs and for those the callback is called, which is why provisioning actually works while communication fails. Is there an error in how this code is set up? It seems like the mesh messages should be received just fine if the same code works for the provisioning messages.

roshanrajaratnam commented 11 months ago

Btw do you disconnect and reconnect again once the provisioning is completed? This is required due to the services and characteristics change and this requires a new service discovery on Android atleast.

connyhald commented 11 months ago

Interesting. No I'm currently not doing a reconnect because the changed services/characteristics are propagated even without a reconnect.

The following Android BluetoothGatt methods are called after provisioning has completed.

onServiceChanged()
discoverServices()
onSearchComplete()

That leads to BleManager::initialized() and BleManager::onDeviceReady() being called again where I'm subscribing to the changed characteristic and continue with sending ConfigCompositionDataGet() using MeshManagerAPI.

I can give it a try using a reconnect maybe it helps...

roshanrajaratnam commented 11 months ago

That explains it, you will have to reconnect once provisioning and the new service discovery will discover the new services and characteristics of the provisioned node.

connyhald commented 11 months ago

I've changed the code to include a disconnect/reconnect yesterday but unfortunately the behavior is unchanged. I've double and tripple checked that the disconnect actually happens and I can see it happening on the phone and the peripheral side.

The log on my peripheral now looks identically whether I use nRF Mesh or my own app. Up to that point indicated by the line below.

W BT_HCI: hcif disc complete: hdl 0x0, rsn 0x13  // <-- This is the disconnect
BT_GATT: GATT_GetConnIdIfConnected status=1 // <-- This is the reconnect
I BT_GATT: GATTS_HandleValueIndication
I BLE_MESH: net_idx 0x000 iv_index 0x00000000 flags 0x00
I BT_GATT: GATTS_HandleValueNotification
I BT_GATT: GATTS_SendRsp: conn_id: 3  trans_id: 1  Status: 0x0000

-------------------------------------------- The following only happens with nRF Mesh

I (23422) BLE_MESH: Add filter addr 0x0001
I (23422) BLE_MESH: recv, app_idx 0xfffe src 0x0001 dst 0x000b
I (23422) BLE_MESH: recv, len 3: 8008ff
W (23432) BLE_MESH: Composition page 255 not available
I (23432) BLE_MESH: send, app_idx 0xfffe src 0x000b dst 0x0001
I (23442) BLE_MESH: send, len 32: 0200e502000000000a0003000000020000000010000001000010000001000010
[...]

To be honest I'm running out of ideas. But maybe you could help me with the following questions:

connyhald commented 11 months ago

I've finally managed to get through. The last missing peace was settings up the correct addresses by using something like

val elementCount = meshNode.provisioningCapabilities.numberOfElements.toInt()
val provisioner = network.selectedProvisioner
val unicast = network.nextAvailableUnicastAddress(elementCount, provisioner)
network.assignUnicastAddress(unicast)

// ...

startProvisioning(meshNode)

@roshanrajaratnam Thanks for you help!

roshanrajaratnam commented 11 months ago

Seems like you solved it yourself! Good luck and feel free to close the issue ☺️