BLE Pairing not possible with Nuki 2.0

Thanks again Felix.
Now I get answer from Nuki. The key point was the way to read pData value (using your “debug_dump_binary())” is ok.
I can now go further to the next steps, thks to you.
I’ll keep you in touch.

It worked fine for me on my LolinD32…do you have the code for next steps? Check lock status and open/close?

Hi,

I have started writing an arduino library for use with an ESP32 to connect/configure a Nuki smart lock 2.0 via BLE.
I intend to make this open source on GIT once it is working, for others to use and improve…

I have started with the BLE API (which looks really well documented btw) but I allready get stuck at the first part connecting.

I wrote my own code but as it is not working I was looking for a fix and came across the code in this post:

It seems I get a timeout on the first step; connect BLE to Nuki (pClient->connect(myNukiAddr);).
This happens after 30 seconds, which I suspect is initiated by the Nuki as I see the same happening in NRFconnect.

It looks a bit like the ESP32 tries to establish a connection but the Nuki does not respond…? And the ESP BLE connect needs to finish before you can start registering on chars and sending the messages…

Any help is appreciated.

This is the code I used (as allready present in this topic, only changed the BLE address)

/**
 * A BLE client example that is rich in capabilities.
 * There is a lot new capabilities implemented.
 * author unknown
 * updated by chegewara
 */

#include "BLEDevice.h"
#include "esp_log.h"
#include "Arduino.h"
//#include "BLEScan.h"

// The remote service we wish to connect to.
static BLEUUID serviceUUID("a92ee100-5501-11e4-916c-0800200c9a66");//Pairing service

// The characteristic of the remote service we are interested in.
static BLEUUID    charUUID("a92ee101-5501-11e4-916c-0800200c9a66");//Characteristic of pairing service
//std::vector<uint8_t> response(200);
static boolean connected = false;
static BLERemoteCharacteristic* pRemoteCharacteristic;
uint8_t arrayFV[] = {0x01,0x00,0x03,0x00,0x27,0xA7}; //"0x0100030027A7";//first value to send as an array of byte to initiate Nuki Pairing

void debug_dump_binary(const void* buffer, size_t size)
{

  for(size_t i = 0; i < size; ++i)
  {
if(i > 0 && (i % 8) == 0)
{
  Serial.println("");
}
Serial.printf("%0x ", ((const uint8_t*) buffer)[i]);
  }
}

static void notifyCallback(
  BLERemoteCharacteristic* pBLERemoteCharacteristic,
  uint8_t* pData,
  size_t length,
  bool isNotify) {
Serial.print("******************** Notify callback for characteristic ");
Serial.println(pBLERemoteCharacteristic->getUUID().toString().c_str());
Serial.print(" of data length ");
Serial.println(length);
Serial.print("data: ");
//fw: don't print this directly. the value is binary, not a 0-terminated string
//Serial.println((char*)pData);
debug_dump_binary(pData, length);
 //   for(int i= 0;i<length;i++) response.push_back(*pData++);
} // end notifyCallback

class MyClientCallback : public BLEClientCallbacks {
  void onConnect(BLEClient* pclient) {
  }

  void onDisconnect(BLEClient* pclient) {
connected = false;  
Serial.println("onDisconnect");
  }
};

bool connectToServer() {
Serial.print("Forming a connection to ");
std::string myNukiAddr="54:d2:72:4F:98:48";

BLEClient*  pClient  = BLEDevice::createClient();
Serial.println(" - Created client");

pClient->setClientCallbacks(new MyClientCallback());

// Connect to the remove BLE Server.
Serial.print(" Essai de connexion à Nuki");
  
pClient->connect(myNukiAddr);  // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)
Serial.println(" - Connected to server");
delay(100);
// Obtain a reference to the service we are after in the remote BLE server.
BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
if (pRemoteService == nullptr) {
  Serial.print("Failed to find our service UUID: ");
  Serial.println(serviceUUID.toString().c_str());
  pClient->disconnect();
  return false;
}
Serial.println(" - Found our service");

// Obtain a reference to the characteristic in the service of the remote BLE server.
pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
if (pRemoteCharacteristic == nullptr) {
  Serial.print("Failed to find our characteristic UUID: ");
  Serial.println(charUUID.toString().c_str());
  pClient->disconnect();
  return false;
}
Serial.println(" - Found our characteristic");
Serial.print("CanRead : ");
Serial.println(pRemoteCharacteristic->canRead()); 
Serial.print("CanWrite : ");
Serial.println(pRemoteCharacteristic->canWrite()); 
Serial.print("CanNotify : ");
Serial.println(pRemoteCharacteristic->canNotify()); 
Serial.print("CanIndicate : ");
Serial.println(pRemoteCharacteristic->canIndicate()); 
   
connected = true;
Serial.print("connected : ");
Serial.println(connected);
return connected;
}

void setup() {
//esp_log_level_set("*", ESP_LOG_DEBUG);
  Serial.begin(115200);
  Serial.println("Starting Arduino BLE Client application...");
  BLEDevice::init("");

if (connectToServer()) {
  Serial.println("We are now connected to the BLE Server.");
} else {
  Serial.println("We have failed to connect to the server; there is nothin more we will do.");
} 
   //register for indication   
   //fw: don't need this. this is done by registerForNotify()
//const uint8_t indicationOn[] = {0x2,0x0};
//pRemoteCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)indicationOn,2,true);
pRemoteCharacteristic->registerForNotify(notifyCallback, false); //false = indication, true = notification
delay(100);
   //write Value
if(pRemoteCharacteristic->canWrite()) {
  //fw: and here's your problem. you were sending the first byte only (writeValue(arrayFV, 1)
  pRemoteCharacteristic->writeValue(arrayFV, sizeof(arrayFV), true);
        delay(50);           
  }
 std::string value = pRemoteCharacteristic->readValue();
  Serial.print("The characteristic value was: ");
  Serial.println(value.c_str());
} // End of setup


// This is the Arduino main loop function.
void loop() {
  //fw: I don't think you should loop here. loop() is looping anyways
  Serial.println("debut loop...");
  if (connected) {
Serial.println("Still connected, loop");
   // Read the value of the characteristic.
 std::string value = pRemoteCharacteristic->readValue();
  Serial.print("The characteristic value was: ");
  Serial.println(value.c_str());

  delay(1000); // Delay between loops.
}
else { 
 Serial.println("not connected");
}

} // End of loop

This is the output where you see I get a onDisconnect:

Starting Arduino BLE Client application...
Forming a connection to  - Created client
 Essai de connexion à Nuki[D][BLEClient.cpp:96] connect(): >> connect(54:d2:72:4f:98:48)
[D][BLEDevice.cpp:593] addPeerDevice(): add conn_id: 0, GATT role: client
[D][BLEDevice.cpp:148] gattClientEventHandler(): gattClientEventHandler [esp_gatt_if: 4] ... Unknown
[D][BLEClient.cpp:158] gattClientEventHandler(): gattClientEventHandler [esp_gatt_if: 4] ... Unknown
[D][BLEDevice.cpp:148] gattClientEventHandler(): gattClientEventHandler [esp_gatt_if: 4] ... Unknown
[D][BLEClient.cpp:158] gattClientEventHandler(): gattClientEventHandler [esp_gatt_if: 4] ... Unknown
onDisconnect
 - Connected to server
[I][BLEDevice.cpp:604] removePeerDevice(): remove: 0, GATT role client
[D][BLEDevice.cpp:148] gattClientEventHandler(): gattClientEventHandler [esp_gatt_if: 4] ... Unknown
[D][BLEDevice.cpp:148] gattClientEventHandler(): gattClientEventHandler [esp_gatt_if: 4] ... Unknown

omg, I found it. bit ashamed to say but I made a typo in the BLE address :disappointed:
note to self: look for the most obvious solution/cause when having an issue

1 Like

I wrote a Nuki Fob based on the NRF51822. I my code I do not register for indications and it’s still able to pair and perform lock/unlock actions on a V1 Nuki. Apparently, I still receive indications despite not writing to the CCCD. Now users report they can’t pair with their V2 Nuki. Can you confirm that enabling indications is necessary for the V2 Nuki, but not the V1?

@i-connect any news about your lib and the project to release it on Git?
I would be really interested.

Sorry have some other prio’s to work on at the moment. But I do intend to continue with it , will probably be working on it 2nd half of this year.

1 Like

EDIT: Never mind, I think I found it on: https://github.com/I-Connect/NukiBleEsp32
Thanks a lot!

Hi Jeroen,

I‘d like to build an receiver for the Nuki Fob so I can trigger the Opener via HTTP as it is not reachable with the FOB from the outside. If you could provide any code that already has the basic bluetooth and Nuki stuff it would be super helpful and save me a lot of time. Just getting the latest non-working code would already help. :slight_smile:

Thanks,
Panda

thanky you for your work. After some problems with uploading the .bin file, i got it.
But my ibeacon has Pin25 and Pin26 for led and button instead of Pin11 and Pin30. It works with my nuki. The only thing i got stuck now is to use your source code, change the Pin there and create a .bin. Have some Problems with SDK and the Makefile.

@jeroen and the others thanky you for your work.
I started some month ago with Key-Pad/RFID/Fingerprint and connection to Nuki. At the moment i use Arduino Nano with Wiegand Protocol, some Relais and a Nuki Fob to open Nuki KT. As next step i want to combine Wiegand Protocol and Nuki open-close function in one ESP32. Did someone try the same or has some hints ?

Thank you,
uvs1313de

haven’t worked with wiegand yet but if you have it working on a Nano it should be no issue running it on an esp32 and combining it with the NukiBleEsp32 lib

thank you for your reply. I will have a look at this. I build my sketch in Arduino IDE, so i will add NukiBleEsp32 to this (maybe have to convert a bit)

Hi all, does Nuki 3.0 also support the BLE pairing with an esp32?

yes it does, see:
https://github.com/I-Connect/NukiBleEsp32