user158306
Member since Jun 2024 • Last active Oct 2024Most recent activity
-
Hi Gordon!
Thank you for your patience and support with my project. Good news, we have success!!! I'll post the final code below for anyone that is having a similar issue with the BlueFruit Feather. What seemed to make it finally work were two things - 1) The direct setting of the CCCD handle to 35. 2) Moving the TX up so that it registers the notification before sending the value to the Arduino board.
In the code below I've also added the buffer conversion, and a disconnect once it receives the correct value so that you can push the Puck to start the process again.
Again, thank you so much for your patience and support!
// Blink green for 100ms function blinkGreen() { LED2.write(true); setTimeout(function () { LED2.write(false); }, 100); } // Variables var feather = "ff:8d:05:ae:17:64 random"; let gattServer; // UART Service UUID const UART_SERVICE_UUID = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"; // UART RX Characteristic UUID (for sending data to the Arduino) const UART_RX_CHARACTERISTIC_UUID = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"; // UART TX Characteristic UUID (for receiving data from the Arduino) const UART_TX_CHARACTERISTIC_UUID = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"; // Function to connect and send data function connectAndSend() { console.log("Trying to connect to Arduino Board."); NRF.requestDevice({ filters: [{ id: feather }], active: true }) .then(function(device) { console.log("Connecting to device..."); return device.gatt.connect(); }) .then(function(gatt) { console.log("Connected to GATT server"); gattServer = gatt; return gatt.getPrimaryService(UART_SERVICE_UUID); }) .then(function(service) { console.log("Setting up TX Service..."); return service.getCharacteristic(UART_TX_CHARACTERISTIC_UUID); }).then(function(txcharacteristic) { console.log("Setting up listener for incoming data..."); txcharacteristic.on('characteristicvaluechanged', function(event) { console.log("Received: "+JSON.stringify(event.target.value.buffer)); // Convert the event target value to a Uint8Array let receivedData = new Uint8Array(event.target.value.buffer); // Convert the array of ASCII codes to a string let decodedValue = String.fromCharCode.apply(null, receivedData); // Log the received value console.log("RX: " + decodedValue); if (decodedValue.trim() === "1") { disconnect(); } else { console.log("Received unexpected value: " + decodedValue); } }); txcharacteristic.handle_cccd = 35; return txcharacteristic.startNotifications(); }) .then(function() { return gattServer.getPrimaryService(UART_SERVICE_UUID); }) .then(function(service) { console.log("Got UART service"); //console.log(service); console.log(" "); return service.getCharacteristic(UART_RX_CHARACTERISTIC_UUID); }) .then(function(rxcharacteristic) { console.log("Got RX characteristic, sending '1'..."); //console.log(rxcharacteristic); console.log(" "); return rxcharacteristic.writeValue("1"); }) .catch(function(error) { console.log("Error: " + error); }); } // Function to disconnect function disconnect() { if (gattServer && gattServer.connected) { gattServer.disconnect(); console.log("Disconnected"); } } // Button press to initiate connection and sending setWatch(connectAndSend, BTN, {edge:"rising", repeat:true, debounce:50});
-
Hi Gordon - thanks so much for all of your support!
This is what the Puck returns after connection:
> Connecting Connected > Service 0x1800 1=>7 Characteristic 0x2a00 3 (CCCD 2) {broadcast:false,read:true,writeWithoutResponse:false,write:true,notify:false,indicate:false,authenticatedSignedWrites:false} Characteristic 0x2a01 5 (CCCD 4) {broadcast:false,read:true,writeWithoutResponse:false,write:false,notify:false,indicate:false,authenticatedSignedWrites:false} Characteristic 0x2a04 7 (CCCD 6) {broadcast:false,read:true,writeWithoutResponse:false,write:false,notify:false,indicate:false,authenticatedSignedWrites:false} Service 0x1801 8=>11 Characteristic 0x2a05 10 (CCCD 9) {broadcast:false,read:false,writeWithoutResponse:false,write:false,notify:false,indicate:true,authenticatedSignedWrites:false} Service 0x0000[vendor] 12=>19 Characteristic 0x0000[vendor] 14 (CCCD 13) {broadcast:false,read:false,writeWithoutResponse:true,write:false,notify:false,indicate:false,authenticatedSignedWrites:false} Characteristic 0x0000[vendor] 16 (CCCD 15) {broadcast:false,read:false,writeWithoutResponse:false,write:true,notify:true,indicate:false,authenticatedSignedWrites:false} Characteristic 0x0000[vendor] 19 (CCCD 18) {broadcast:false,read:true,writeWithoutResponse:false,write:false,notify:false,indicate:false,authenticatedSignedWrites:false} Service 0x180a 20=>30 Characteristic 0x2a29 22 (CCCD 21) {broadcast:false,read:true,writeWithoutResponse:false,write:false,notify:false,indicate:false,authenticatedSignedWrites:false} Characteristic 0x2a24 24 (CCCD 23) {broadcast:false,read:true,writeWithoutResponse:false,write:false,notify:false,indicate:false,authenticatedSignedWrites:false} Characteristic 0x2a28 26 (CCCD 25) {broadcast:false,read:true,writeWithoutResponse:false,write:false,notify:false,indicate:false,authenticatedSignedWrites:false} Characteristic 0x2a26 28 (CCCD 27) {broadcast:false,read:true,writeWithoutResponse:false,write:false,notify:false,indicate:false,authenticatedSignedWrites:false} Characteristic 0x2a27 30 (CCCD 29) {broadcast:false,read:true,writeWithoutResponse:false,write:false,notify:false,indicate:false,authenticatedSignedWrites:false} Service 6e400001-b5a3-f393-e0a9-e50e24dcca9e 31=>65535 Characteristic 6e400003-b5a3-f393-e0a9-e50e24dcca9e 33 (CCCD 32) {broadcast:false,read:false,writeWithoutResponse:false,write:false,notify:true,indicate:false,authenticatedSignedWrites:false} Characteristic 6e400002-b5a3-f393-e0a9-e50e24dcca9e 37 (CCCD 36) {broadcast:false,read:false,writeWithoutResponse:true,write:true,notify:false,indicate:false,authenticatedSignedWrites:false}
I've attached all of the pictures from nRF Connect.
-
I'll try to add as much code and images as possible to see what might help figure this out.
Here is my bare bones Arduino Code. It should receive the value from the Puck and then if it matches, send a value back.
[#include](https://forum.espruino.com/search/?q=%23include) <Arduino.h> [#include](https://forum.espruino.com/search/?q=%23include) <SPI.h> [#include](https://forum.espruino.com/search/?q=%23include) "Adafruit_BLE.h" [#include](https://forum.espruino.com/search/?q=%23include) "Adafruit_BluefruitLE_SPI.h" [#include](https://forum.espruino.com/search/?q=%23include) "Adafruit_BluefruitLE_UART.h" [#include](https://forum.espruino.com/search/?q=%23include) "BluefruitConfig.h" [#if](https://forum.espruino.com/search/?q=%23if) SOFTWARE_SERIAL_AVAILABLE [#include](https://forum.espruino.com/search/?q=%23include) <SoftwareSerial.h> [#endif](https://forum.espruino.com/search/?q=%23endif) [#define](https://forum.espruino.com/search/?q=%23define) FACTORYRESET_ENABLE 1 [#define](https://forum.espruino.com/search/?q=%23define) MINIMUM_FIRMWARE_VERSION "0.6.6" [#define](https://forum.espruino.com/search/?q=%23define) MODE_LED_BEHAVIOUR "MODE" [#define](https://forum.espruino.com/search/?q=%23define) LED_BUILTIN 13 Adafruit_BluefruitLE_SPI ble(BLUEFRUIT_SPI_CS, BLUEFRUIT_SPI_IRQ, BLUEFRUIT_SPI_RST); void error(const __FlashStringHelper* err) { Serial.println(err); while (1); } int incomingByte = 0; String readString; void setup() { pinMode(LED_BUILTIN, OUTPUT); Serial.begin(9600); Serial.println(); Serial.println("Setting beacon configuration details: "); Serial.println("---------------------------------------"); if (!ble.begin(VERBOSE_MODE)) { error(F("Couldn't find Bluefruit, make sure it's in CoMmanD mode & check wiring?")); } if (FACTORYRESET_ENABLE) { Serial.println(F("Performing a factory reset: ")); if (!ble.factoryReset()) { error(F("Couldn't factory reset")); } } ble.echo(false); Serial.println("Requesting Bluefruit info:"); ble.info(); Serial.println(); ble.verbose(false); Serial.println(F("Setting device name to 'Splitz Start Beacon'")); if (!ble.sendCommandCheckOK(F("AT+GAPDEVNAME=Splitz Start Beacon"))) { error(F("Could not set device name?")); } Serial.println(F("Switching to DATA mode!")); ble.setMode(BLUEFRUIT_MODE_DATA); while (!ble.isConnected()) { delay(500); } if (ble.isConnected()) { Serial.println(F("BLE device is connected.")); } } void loop() { if (ble.available()) { char input[64]; int len = ble.readBytesUntil('\n', input, sizeof(input)-1); input[len] = 0; Serial.print(F("Received: ")); Serial.println(input); if (strcmp(input, "hi") == 0) { Serial.println(F("Sending reply: hello")); ble.println("hello"); // Write to the characteristic ble.sendCommandCheckOK(("AT+GATTCHAR=1,hello")); } } }
The first image is the Serial response.
This is the code I have for the Puck.
// Blink green for 100ms function blinkGreen() { LED2.write(true); setTimeout(function () { LED2.write(false); }, 100); } // Variables var feather = "ff:8d:05:ae:17:64 random"; let gattServer; // UART Service UUID const UART_SERVICE_UUID = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"; // UART RX Characteristic UUID (for sending data to the Arduino) const UART_RX_CHARACTERISTIC_UUID = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"; // UART TX Characteristic UUID (for receiving data from the Arduino) const UART_TX_CHARACTERISTIC_UUID = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"; // Function to connect and send data function connectAndSend() { console.log("Trying to connect to Arduino Board."); NRF.requestDevice({ filters: [{ id: feather }], active: true }) .then(function(device) { console.log("Connecting to device..."); return device.gatt.connect(); }) .then(function(gatt) { console.log("Connected to GATT server"); gattServer = gatt; return gatt.getPrimaryService(UART_SERVICE_UUID); }) .then(function(service) { console.log("Got UART service"); return service.getCharacteristic(UART_RX_CHARACTERISTIC_UUID); }) .then(function(characteristic) { console.log("Got RX characteristic, sending 'hi'..."); return characteristic.writeValue("hi"); }) .then(function() { console.log("Message sent successfully"); blinkGreen(); return gattServer.getPrimaryService(UART_SERVICE_UUID); }) .then(function(service) { console.log("Setting up TX Service..."); return service.getCharacteristic(UART_TX_CHARACTERISTIC_UUID); }).then(function(characteristic) { console.log("Setting up listener for incoming data"); characteristic.on('characteristicvaluechanged', function(event) { console.log("RX: "+JSON.stringify(event.target.value.buffer)); }); return characteristic.startNotifications(); }) .catch(function(error) { console.log("Error: " + error); }); } // Function to disconnect function disconnect() { if (gattServer && gattServer.connected) { gattServer.disconnect(); console.log("Disconnected"); } } // Button press to initiate connection and sending setWatch(connectAndSend, BTN, {edge:"rising", repeat:true, debounce:50});
The 2nd image is the output I receive. Even if I move the TX handle to before the RX , I still get a CCCD error.
I also just added log to the Primary, RX, and TX return so that we can see what is being returned.
Trying to connect to Arduino Board. Connecting to device... Connected to GATT server Got UART service BluetoothRemoteGATTService: { "device": BluetoothDevice: { "id": "ff:8d:05:ae:17:64 random", "rssi": -61, "data": new Uint8Array([2, 1, 6, 2, 10, 0, 17, 6, 158, 202, 220, 36, 14, 229, 169, 224, 147, 243, 163, 181, 1, 0, 64, 110]).buffer, "services": [ "6e400001-b5a3-f393-e0a9-e50e24dcca9e" ], "gatt": BluetoothRemoteGATTServer: { "device": ... , "connected": true, "handle": 1 } }, "uuid": "6e400001-b5a3-f393-e0a9-e50e24dcca9e", "isPrimary": true, "start_handle": 31, "end_handle": 65535 } Got RX characteristic, sending 'hi'... BluetoothRemoteGATTCharacteristic: { "service": BluetoothRemoteGATTService: { "device": BluetoothDevice: { "id": "ff:8d:05:ae:17:64 random", "rssi": -61, "data": new Uint8Array([2, 1, 6, 2, 10, 0, 17, 6, 158, 202, 220, 36, 14, 229, 169, 224, 147, 243, 163, 181, 1, 0, 64, 110]).buffer, "services": [ "6e400001-b5a3-f393-e0a9-e50e24dcca9e" ], "gatt": BluetoothRemoteGATTServer: { "device": ... , "connected": true, "handle": 1 } }, "uuid": "6e400001-b5a3-f393-e0a9-e50e24dcca9e", "isPrimary": true, "start_handle": 31, "end_handle": 65535 }, "uuid": "6e400002-b5a3-f393-e0a9-e50e24dcca9e", "handle_value": 37, "handle_decl": 36, "properties": { "broadcast": false, "read": false, "writeWithoutResponse": true, "write": true, "notify": false, "indicate": false, "authenticatedSignedWrites": false } } Setting up TX Service... BluetoothRemoteGATTCharacteristic: { "service": BluetoothRemoteGATTService: { "device": BluetoothDevice: { "id": "ff:8d:05:ae:17:64 random", "rssi": -61, "data": new Uint8Array([2, 1, 6, 2, 10, 0, 17, 6, 158, 202, 220, 36, 14, 229, 169, 224, 147, 243, 163, 181, 1, 0, 64, 110]).buffer, "services": [ "6e400001-b5a3-f393-e0a9-e50e24dcca9e" ], "gatt": BluetoothRemoteGATTServer: { "device": ... , "connected": true, "handle": 1 } }, "uuid": "6e400001-b5a3-f393-e0a9-e50e24dcca9e", "isPrimary": true, "start_handle": 31, "end_handle": 65535 }, "uuid": "6e400003-b5a3-f393-e0a9-e50e24dcca9e", "handle_value": 33, "handle_decl": 32, "properties": { "broadcast": false, "read": false, "writeWithoutResponse": false, "write": false, "notify": true, "indicate": false, "authenticatedSignedWrites": false } } Setting up listener for incoming data Error: CCCD Handle not found
-
Hi Gordon, thank you again for spending time helping me with this.
I would like to be able to communicate back and forth between the Arduino and the Puck.
Is there something that I can share from the Bluefruit that would help?
When I use:
return require("ble_uart").connect(device);
I am receiving the error "Uncaught Error: Unhandled promise rejection: CCCD Handle not found"
But if I use
return require("ble_simple_uart").write(device, "1");
The puck will write "1" to the feather.
-
Hi Gordon - Thank you for the reply.
When I try this, I am getting a "Uncaught Error: Unhandled promise rejection: CCCD Handle not found" error from the Puck.
The Puck does connect to the Arduino board. Then it seems to lock/hold a connection to the board (which is because of not having the disconnect), but the Arduino board doesn't register the Puck writing (arduino receiving) the value to the board, so the return promise is never handled. Does that make sense?
Under the Arduino Serial output should be the lines
"if statement worked"
"Sending Start: 1"
if the arduino board received the value. -
Thanks for this info Gordon - and apologies for the delay in getting this updated. I think I'm really stuck on the eval aspect of how to receive data to the Puck.js. I'm sure I'm just missing something trivial in the library that once I see it, it will be so obvious. I tried to reduce the code to just a basic - send a simple vale "1" to the Arduino board, and once the board receives a value of "1" return back to the Puck a value of "1" to confirm the data.
Puck Code:
// Variables var feather = "ff:8d:05:ae:17:64 random"; var uart; function sendMessage() { console.log("Trying to Connect"); NRF.requestDevice({ filters: [{ id: feather }], active:true }).then(function(device) { //return require("ble_simple_uart").write(device, "1"); return require("ble_uart").connect(device); }).then(function(uart) { uart.write("1"); }).then(function() { console.log("Message sent successfully."); uart.on('data', function(d) { console.log("Got:"+JSON.stringify(d)); }); }); } // Send a message when the button is pressed setWatch(function() { sendMessage(); }, BTN, { edge: "rising", debounce: 50, repeat: true });
Arduino Code:
[#include](https://forum.espruino.com/search/?q=%23include) <Arduino.h> [#include](https://forum.espruino.com/search/?q=%23include) <SPI.h> [#include](https://forum.espruino.com/search/?q=%23include) "Adafruit_BLE.h" [#include](https://forum.espruino.com/search/?q=%23include) "Adafruit_BluefruitLE_SPI.h" [#include](https://forum.espruino.com/search/?q=%23include) "Adafruit_BluefruitLE_UART.h" [#include](https://forum.espruino.com/search/?q=%23include) "BluefruitConfig.h" [#if](https://forum.espruino.com/search/?q=%23if) SOFTWARE_SERIAL_AVAILABLE [#include](https://forum.espruino.com/search/?q=%23include) <SoftwareSerial.h> [#endif](https://forum.espruino.com/search/?q=%23endif) [#define](https://forum.espruino.com/search/?q=%23define) FACTORYRESET_ENABLE 1 [#define](https://forum.espruino.com/search/?q=%23define) MINIMUM_FIRMWARE_VERSION "0.6.6" [#define](https://forum.espruino.com/search/?q=%23define) MODE_LED_BEHAVIOUR "MODE" [#define](https://forum.espruino.com/search/?q=%23define) LED_BUILTIN 13 Adafruit_BluefruitLE_SPI ble(BLUEFRUIT_SPI_CS, BLUEFRUIT_SPI_IRQ, BLUEFRUIT_SPI_RST); void error(const __FlashStringHelper* err) { Serial.println(err); while (1); } int incomingByte = 0; String readString; void startRaceSequence() { Serial.println(F("if statement worked")); Serial.print("Sending Start: 1"); ble.println("1"); } void setup() { pinMode(LED_BUILTIN, OUTPUT); Serial1.begin(9600); Serial.begin(115200); ble.echo(false); Serial.println("Requesting Bluefruit info:"); ble.info(); Serial.println(); ble.verbose(false); Serial.println(F("Setting device name to 'Splitz Start Beacon'")); if (!ble.sendCommandCheckOK(F("AT+GAPDEVNAME=Splitz Start Beacon"))) { error(F("Could not set device name?")); } Serial.println(F("Switching to DATA mode!")); ble.setMode(BLUEFRUIT_MODE_DATA); while (!ble.isConnected()) { delay(500); } if (ble.isConnected()) { Serial.println(F("BLE device is connected.")); } } void loop() { while (ble.available()) { Serial.println("Waiting for message."); char c = ble.read(); readString += c; delay(2); } if (readString.length() > 0) { Serial.println(readString); if (readString == "1") { // Send back a response message after receiving "1" ble.write("Received '1', race sequence triggered"); startRaceSequence(); } } readString = ""; }
I am able to send the value to the Arduino board, and can trigger a function on the Arduino board based on the value sent by the Puck (but usually only when I use the ble uart simple). But am not able to get a value back. I usually receive a CCCD error.
Any direction would be greatly appreciated!
-
One of the things I am stuck on with the ble_uart module, is what does the puck code look like if I already have an established connection. When I look at the source of the module, and most of the examples, they show requestDevice as the default. But when I try to use the standard ble_uart, I am getting errors that I am already connected or if I do something like :
// Function to send a message function sendMessage() { console.log("Trying to Connect"); NRF.requestDevice({ filters: [{ id: feather }], active:true }).then(function(device) { print(device); uart.write(device, "true"); }).then(function() { console.log('Done!'); }); }
I get a "Uncaught Error: Unhandled promise rejection: Error: Function "write" not found!"
Here is all of the testing code:
var feather = "ff:8d:05:ae:17:64 random"; var uart = require("ble_uart"); NRF.setAdvertising({},{ name: "Splitz Puck", showName: true, discoverable: true, connectable: true, scannable : true, }); // Blink green for 100ms function blinkGreen() { LED2.write(true); setTimeout(function () { LED2.write(false); }, 100); } // Function to send a message function sendMessage() { console.log("Trying to Connect"); NRF.requestDevice({ filters: [{ id: feather }], active:true }).then(function(device) { print(device); uart.write(device, "true"); }).then(function() { console.log('Done!'); }); } /*function sendMessage(text, tx) { return new Promise(function sender(resolve, reject) { if (text.length) { tx.writeValue(text.substr(0,20)).then(function() { sender(resolve, reject); }).catch(reject); text = text.substr(20); } else resolve(); }); }*/ // Send a message when the button is pressed setWatch(function() { blinkGreen(); sendMessage(); }, BTN, { edge: "rising", debounce: 50, repeat: true });
-
Thank you so much for all of your support on this! I've been making further progress in other areas and trying to get the arduino board and the puck to talk to each other. What I can't seem to figure out - after looking at the tutorials and digging through the forums is how to receive a ble_art update from the arduino board. I have seen the "eval" function and I've seen the examples with the web and python implementations - but how do those get adapted for the puck? sorry, I have a feeling this is a very basic question, but I can't seem to find the right direction.
Hi Gordon,
For sure, happy to try it. Let me know what you need.