Puck.js Connect to Adafruit Feather Board

Posted on
Page
of 2
/ 2
Next
  • Hi! I am new to Arduino and Puck and Bluetooth programming. This is probably a very simple thing - but I am really struggling to make this work.

    I have a Puck and an Adafruit Feather BLE board that I am jut trying to send signals between. I have the Arduino board setup and I know it is broadcasting. I have the Puck setup and I can run the findDevice() to search for devices (and it creates a list of available devices).

    I have the board renamed - say to "Splitz" - and my phone and Mac see the board as renamed as "Splitz" if I connect to it. But I can not for the life of me get the Puck to "see" the board.

    This is what I am using to scan for devices on a Puck button push.

    setWatch(function(e) {
        NRF.findDevices(function(devices) {
          print(devices);
      });
    }, BTN, { edge: "falling", repeat: true, debounce: 50 });
    

    The below is some of what returns. I know I just don't know what I am looking for in the returned data to parse out which one is the Feather board. The code says it is 0x00D6 hardware? I can see both devices on the Bluefruit App as well and can connect and UART to them both. I'd like to be able to send signals from the puck to the Board and vice versa.

    [
    BluetoothDevice: {
        "id": "d9:c7:44:31:02:87 random",
        "rssi": -79,
        "data": new Uint8Array([26, 255, 76, 0, 18, 2, 238, 1, 7, 17, 6, 125, 223, 234, 190, 158, 8, 80, 62, 43, 210, 193, 95, 101, 14, 224, 65]).buffer,
        "manufacturer": 76,
        "manufacturerData": new Uint8Array([18, 2, 238, 1, 7, 17, 6, 125, 223, 234, 190, 158, 8, 80, 62, 43, 210, 193, 95, 101, 14, 224, 65]).buffer
       },
      BluetoothDevice: {
        "id": "65:40:40:bb:4d:7f private-resolvable",
        "rssi": -66,
        "data": new Uint8Array([2, 1, 26, 13, 255, 76, 0, 22, 8, 0, 108, 189, 35, 11, 170, 240, 33]).buffer,
        "manufacturer": 76,
        "manufacturerData": new Uint8Array([22, 8, 0, 108, 189, 35, 11, 170, 240, 33]).buffer
       },
      BluetoothDevice: {
        "id": "6d:67:7b:97:ef:28 private-resolvable",
        "rssi": -48,
        "data": new Uint8Array([2, 1, 26, 13, 255, 76, 0, 22, 8, 0, 172, 3, 209, 26, 155, 13, 167]).buffer,
        "manufacturer": 76,
        "manufacturerData": new Uint8Array([22, 8, 0, 172, 3, 209, 26, 155, 13, 167]).buffer
       },
      BluetoothDevice: {
        "id": "cf:1b:24:db:c7:86 random",
        "rssi": -49,
        "data": new Uint8Array([7, 255, 76, 0, 18, 2, 0, 3]).buffer,
        "manufacturer": 76,
        "manufacturerData": new Uint8Array([18, 2, 0, 3]).buffer
       }
     ]
    

    Any help in the right direction would be amazing!!

  • The device name is often sent in scan response packet that Puck.js must actively ask for for every device. That is the active: true option which is not enabled by default. https://www.espruino.com/Reference#l_NRF­_findDevices

  • Do you know (maybe from the adafruit app, or the NRF connect app) what the device's MAC address is? That way you can at least try and track down which the correct device is - or you can even just specify it manually using the MAC address.

    In what you posted all I see is "manufacturer": 76, - these are all Apple devices, so not your Feather BLE.

    Could you feather still be connected by BLE to your phone/PC? If so it won't be advertising.

  • Thank you for the response - I've updated the puck.js code to include the "active:true" below, and I've included a full list of the devices that are seen by the puck.

    setWatch(function(e) {
    
      NRF.findDevices(function(devices) {
        print(devices);
      }, {timeout : 2000,
          active : true, 
          filters : [
            { manufacturerData:{0x00D6:{}}}
          ]
         });
    }, BTN, { edge: "falling", repeat: true, debounce: 50 });
    
    [
      BluetoothDevice: {
        "id": "2d:3b:c7:59:79:b0 private-nonresolvable",
        "rssi": -50,
        "data": new Uint8Array([2, 1, 26, 11, 255, 76, 0, 9, 6, 3, 191, 192, 168, 0, 10]).buffer,
        "manufacturer": 76,
        "manufacturerData": new Uint8Array([9, 6, 3, 191, 192, 168, 0, 10]).buffer
       },
      BluetoothDevice: {
        "id": "47:b8:c7:f3:29:b4 private-resolvable",
        "rssi": -69,
        "data": new Uint8Array([3, 3, 159, 254, 23, 22, 159, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]).buffer,
        "services": [
          "fe9f"
         ],
        "serviceData": {
          "fe9f": new ArrayBuffer(20)
         }
       },
      BluetoothDevice: {
        "id": "70:10:8f:e4:08:a5 private-resolvable",
        "rssi": -49,
        "data": new Uint8Array([2, 1, 26, 2, 10, 12, 10, 255, 76, 0, 16, 5, 78, 28, 90, 249, 167]).buffer,
        "manufacturer": 76,
        "manufacturerData": new Uint8Array([16, 5, 78, 28, 90, 249, 167]).buffer
       },
      BluetoothDevice: {
        "id": "7f:bb:91:1f:68:11 private-resolvable",
        "rssi": -50,
        "data": new Uint8Array([2, 1, 26, 2, 10, 12, 11, 255, 76, 0, 16, 6, 61, 30, 200, 213, 243, 249]).buffer,
        "manufacturer": 76,
        "manufacturerData": new Uint8Array([16, 6, 61, 30, 200, 213, 243, 249]).buffer
       },
      BluetoothDevice: {
        "id": "ff:8d:05:ae:17:64 random",
        "rssi": -45,
        "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"
         ]
       },
      BluetoothDevice: {
        "id": "68:6b:cd:8a:7a:e2 private-resolvable",
        "rssi": -76,
        "data": new Uint8Array([2, 1, 26, 2, 10, 7, 10, 255, 76, 0, 16, 5, 114, 28, 211, 224, 196]).buffer,
        "manufacturer": 76,
        "manufacturerData": new Uint8Array([16, 5, 114, 28, 211, 224, 196]).buffer
       },
      BluetoothDevice: {
        "id": "df:f6:01:75:33:e8 random",
        "rssi": -75,
        "data": new Uint8Array([7, 255, 76, 0, 18, 2, 0, 0]).buffer,
        "manufacturer": 76,
        "manufacturerData": new Uint8Array([18, 2, 0, 0]).buffer
       }
     ]
    
  • Ok, I think I am getting closer. I'm just really trying to navigate how the two different libraries (Arduino and Espruino) talk to each other.

    I have the following code on the puck.js. I can see and connect to the Arduino Adafruit Feather board with the puck on a button push.

    // Initialize the UART connection on Puck.js
    Serial1.setup(9600, { tx: D29, rx: D28 });
    
    // Function to send a message
    function sendMessage(message) {
      NRF.connect("ff:8d:05:ae:17:64 random").then(function(d)   {
        device = d;
        console.log("Device ",device);
        Serial1.print(message);
      });
    }
    
    // Send a message when the button is pressed
    setWatch(function() {
      sendMessage("Hello, Arduino!");
    }, BTN, { edge: "rising", debounce: 50, repeat: true });
    

    The code on the Arduino Feather is below. In the Serial output, when I click the puck button it shows the Device Connected in the output - but I can not for some reason get the UART message to be passed between the puck and the Arduino board. I'm sure it's something simple I'm missing - so sorry if this is an easy one.

    [#include](https://forum.espruino.com/se­arch/?q=%23include) <Arduino.h>
    [#include](https://forum.espruino.com/se­arch/?q=%23include) <SPI.h>
    [#include](https://forum.espruino.com/se­arch/?q=%23include) "Adafruit_BLE.h"
    [#include](https://forum.espruino.com/se­arch/?q=%23include) "Adafruit_BluefruitLE_SPI.h"
    [#include](https://forum.espruino.com/se­arch/?q=%23include) "Adafruit_BluefruitLE_UART.h"
    
    [#include](https://forum.espruino.com/se­arch/?q=%23include) "BluefruitConfig.h"
    
    [#if](https://forum.espruino.com/search/­?q=%23if) SOFTWARE_SERIAL_AVAILABLE
      [#include](https://forum.espruino.com/se­arch/?q=%23include) <SoftwareSerial.h>
    [#endif](https://forum.espruino.com/sear­ch/?q=%23endif)
    
        [#define](https://forum.espruino.com/sea­rch/?q=%23define) FACTORYRESET_ENABLE         1
        [#define](https://forum.espruino.com/sea­rch/?q=%23define) MINIMUM_FIRMWARE_VERSION    "0.6.6"
        [#define](https://forum.espruino.com/sea­rch/?q=%23define) MODE_LED_BEHAVIOUR          "MODE"
        [#define](https://forum.espruino.com/sea­rch/?q=%23define) LED_BUILTIN                 13
    /*======================================­===================================
    
    Adafruit_BluefruitLE_UART ble(bluefruitSS, BLUEFRUIT_UART_MODE_PIN,
                          BLUEFRUIT_UART_CTS_PIN, BLUEFRUIT_UART_RTS_PIN);
    
    // A small helper
    void error(const __FlashStringHelper*err) {
      Serial.println(err);
      while (1);
    }
    
    /***************************************­***********************************/
    /*!
        @brief  Sets up the HW an the BLE module (this function is called
                automatically on startup)
    */
    /***************************************­***********************************/
    
    void setup() {
      // Start the hardware serial communication at 9600 baud rate
      Serial.begin(9600); // Serial Monitor
      Serial1.begin(9600); // UART Communication (Replace Serial1 with appropriate Serial for your Feather)
    
      Serial.println(F("Adafruit Bluefruit Command Mode Example"));
        Serial.println(F("----------------------­-----------------"));
    
        /* Initialise the module */
        Serial.print(F("Initialising the Bluefruit LE module: "));
    
        if ( !ble.begin(VERBOSE_MODE) ){
          error(F("Couldn't find Bluefruit, make sure it's in CoMmanD mode & check wiring?"));
        }
        Serial.println( F("OK!") );
    
        if ( FACTORYRESET_ENABLE ){
          /* Perform a factory reset to make sure everything is in a known state */
          Serial.println(F("Performing a factory reset: "));
          if ( ! ble.factoryReset() ){
            error(F("Couldn't factory reset"));
          }
        }
    
        /* Disable command echo from Bluefruit */
        ble.echo(false);
    
        Serial.println("Requesting Bluefruit info:");
        /* Print Bluefruit information */
        ble.info();
    
        Serial.println(F("Please use Adafruit Bluefruit LE app to connect in UART mode"));
        Serial.println(F("Then Enter characters to send to Bluefruit"));
        Serial.println();
    
        ble.verbose(false);  // debug info is a little annoying after this point!
    
        /* Wait for connection */
        while (! ble.isConnected()) {
            delay(500);
        }
    
        while(ble.isConnected()){
          Serial.println(F("Device is connected."));
          delay(500);
        }
        pinMode(LED_BUILTIN, OUTPUT); // Optional: Use the built-in LED to indicate received data
    }
    
    void loop() {
      // Check if there is any data available on Serial1
      if (Serial.available()) {
        // Read the incoming byte
        String incomingMessage = "";
        while (Serial.available()) {
          char incomingByte = Serial.read();
          incomingMessage += incomingByte;
        }
        // Print the incoming message to the Serial Monitor
        Serial.println("Received: " + incomingMessage);
    
        // Optional: Blink LED to indicate message received
        digitalWrite(LED_BUILTIN, HIGH);
        delay(1000);
        digitalWrite(LED_BUILTIN, LOW);
      }
    }
    
  • Ahh - ok. Right, well, first off to detect the feather, using MAC address is great if it's just one-off. You can see it reports as:

      BluetoothDevice: {
        "id": "ff:8d:05:ae:17:64 random",
        "rssi": -45,
        "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"
         ]
       },
    

    So you can do:

    NRF.requestDevice({ filters: [{ services: ['6e400001-b5a3-f393-e0a9-e50e24dcca9e"'­] }] }).then(function(device) { ... });
    

    To return any device advertising the Nordic UART service.

    What you're doing with Serial1.* is you're using the physical UART on the Puck on pins D28/29 - that's nothing to do with Bluetooth. What you need is https://www.espruino.com/BLE+UART

    So your code would be more like:

    // Function to send a message
    function sendMessage(message) {
      NRF.connect("ff:8d:05:ae:17:64 random").then(function(d)   {
        device = d;
        console.log("Device ",device);
        require("ble_simple_uart").write(device,­ message, function() {
          print('Done!');
        });
      });
    }
    // Send a message when the button is pressed
    setWatch(function() {
      sendMessage("Hello, Arduino!");
    }, BTN, { edge: "rising", debounce: 50, repeat: true });
    
  • I should add I'm not 10o% sure whether that's the right code for the Feather either... I'd have expected the ble class to be providing functionality to read data, not Serial - but I could be wrong as I don't have any experience of BLE on the Feather

  • There are plenty of such Feather boards
    https://www.adafruit.com/search?q=ble+fe­ather&c=1010
    so it is not clear which one it is, the Arudino code includes Adafruit_BluefruitLE_UART.h and some of those boards have nrf51 module connected over serial to main CPU. Maybe it is this one ? https://www.adafruit.com/product/2995

    There are even modules just with the nrf51 to be connected over UART or SPI https://www.adafruit.com/search?q=ble+fr­iend (there is also #include "Adafruit_BluefruitLE_SPI.h"

    Also I see in the Arduino code that the FACTORYRESET_ENABLE is enabled so maybe the device name gets reset on every power on and maybe that's why it is not available in the scan?

  • Hi fanoush and Gordon,

    Thank you for your help in trying to connect the puck with the Feather. The board that I am using is: https://learn.adafruit.com/adafruit-feat­her-32u4-bluefruit-le/using-with-arduino­-ide

    I can get the puck and feather to "connect" to each other - when I push the button on the puck the Bluetooth LED on the Feather lights up - which means it is making a connection.

    Figuring out how to exchange/communicate UART data between them after they are connected seems to be tricky.

    When I include the code above I get the following error:

    Device  BluetoothRemoteGATTServer: {
      "device": BluetoothDevice: {
        "id": "ff:8d:05:ae:17:64 random",
        "gatt":  ...
       },
      "connected": true, "handle": 1 }
    Uncaught Error: Unhandled promise rejection: Error: Can't read property 'connect' of undefined
     at line 1 col 97 in .bootcde
    var d;return h.gatt.connect().then(function(a){d=a;re­turn a....
                       ^
    in function "write" called from line 16 col 6 in .bootcde
        });
         ^
    in function called from system
    
  • I've got the Puck to connect and return the promise using requestDevice. I just don't see the result on the Arduino board. I know they connect.

    // Blink green for 100ms
    function blinkGreen() {
      LED2.write(true);
      setTimeout(function () { LED2.write(false); }, 100);
    }
    
    // Function to send a message
    function sendMessage(message) {
      NRF.requestDevice({ filters: [{ id: 'ff:8d:05:ae:17:64 random' }], timeout: 2000, active:true }).then(function(device) {
        print(device);
        return require("ble_simple_uart").write(device,­ message);
        }).then(function() {
          print('Done!');
      });
    }
    
    // Send a message when the button is pressed
    setWatch(function() {
      sendMessage("Hello, Arduino!/n");
      blinkGreen();
    }, BTN, { edge: "rising", debounce: 50, repeat: true });
    

    This is my arduino code with the libraries included.

    [#include](https://forum.espruino.com/se­arch/?q=%23include) <Arduino.h>
    [#include](https://forum.espruino.com/se­arch/?q=%23include) <SPI.h>
    [#include](https://forum.espruino.com/se­arch/?q=%23include) "Adafruit_BLE.h"
    [#include](https://forum.espruino.com/se­arch/?q=%23include) "Adafruit_BluefruitLE_SPI.h"
    [#include](https://forum.espruino.com/se­arch/?q=%23include) "Adafruit_BluefruitLE_UART.h"
    
    [#include](https://forum.espruino.com/se­arch/?q=%23include) "BluefruitConfig.h"
    
    [#if](https://forum.espruino.com/search/­?q=%23if) SOFTWARE_SERIAL_AVAILABLE
      [#include](https://forum.espruino.com/se­arch/?q=%23include) <SoftwareSerial.h>
    [#endif](https://forum.espruino.com/sear­ch/?q=%23endif)
    
    /*======================================­===================================
        ----------------------------------------­-------------------------------*/
        [#define](https://forum.espruino.com/sea­rch/?q=%23define) FACTORYRESET_ENABLE         1
        [#define](https://forum.espruino.com/sea­rch/?q=%23define) MINIMUM_FIRMWARE_VERSION    "0.6.6"
        [#define](https://forum.espruino.com/sea­rch/?q=%23define) MODE_LED_BEHAVIOUR          "MODE"
        [#define](https://forum.espruino.com/sea­rch/?q=%23define) LED_BUILTIN                 13
    /*======================================­===================================*/
    
    Adafruit_BluefruitLE_SPI ble(BLUEFRUIT_SPI_CS, BLUEFRUIT_SPI_IRQ, BLUEFRUIT_SPI_RST);
    
    // A small helper
    void error(const __FlashStringHelper*err) {
      Serial.println(err);
      while (1);
    }
    
    /***************************************­***********************************/
    /*!
        @brief  Sets up the HW an the BLE module (this function is called
                automatically on startup)
    */
    /***************************************­***********************************/
    
    void setup() {
      // Start the hardware serial communication at 9600 baud rate
      Serial.begin(9600); // Serial Monitor
      Serial1.begin(9600); // UART Communication (Replace Serial1 with appropriate Serial for your Feather)
    
      Serial.println(F("Adafruit Bluefruit Command Mode Example"));
        Serial.println(F("----------------------­-----------------"));
    
        /* Initialise the module */
        Serial.print(F("Initialising the Bluefruit LE module: "));
    
        if ( !ble.begin(VERBOSE_MODE) ){
          error(F("Couldn't find Bluefruit, make sure it's in CoMmanD mode & check wiring?"));
        }
        Serial.println( F("OK!") );
    
        if ( FACTORYRESET_ENABLE ){
          /* Perform a factory reset to make sure everything is in a known state */
          Serial.println(F("Performing a factory reset: "));
          if ( ! ble.factoryReset() ){
            error(F("Couldn't factory reset"));
          }
        }
    
        /* Disable command echo from Bluefruit */
        ble.echo(false);
    
        Serial.println("Requesting Bluefruit info:");
        /* Print Bluefruit information */
        ble.info();
    
        Serial.println(F("Please use Adafruit Bluefruit LE app to connect in UART mode"));
        Serial.println(F("Then Enter characters to send to Bluefruit"));
        Serial.println();
    
        ble.verbose(false);  // debug info is a little annoying after this point!
    
        /* Wait for connection */
        while (! ble.isConnected()) {
            delay(500);
        }
    
        while(ble.isConnected()){
          Serial.println(F("Device is connected."));
          delay(5000);
        }
    
        pinMode(13, OUTPUT); // Optional: Use the built-in LED to indicate received data
    }
    
    void loop() {
      // Check if there is any data available on Serial1
      Serial.println("Serial is Available");
      if (Serial.available()) {
        Serial.println("Serial is Available");
        // Read the incoming byte
        String incomingMessage = "";
        while (Serial.available()) {
          char incomingByte = Serial.read();
          incomingMessage += incomingByte;
        }
        // Print the incoming message to the Serial Monitor
        Serial.println("Received: " + incomingMessage);
        
        // Optional: Blink LED to indicate message received
        digitalWrite(13, HIGH);
        delay(1000);
        digitalWrite(13, LOW);
      }
    }
    
  • Sorry, that's my fault for some bad example code. Glad you got it sorted with requestDevice.

    One thing I do notice is you do sendMessage("Hello, Arduino!/n"); which I assume is to send a newline, but the slash is the wrong way around so it'll just send /n and not a newline.

    So you could try sendMessage("Hello, Arduino!\n"); and see if that helps?

  • I just don't see the result on the Arduino board.

    you should perhaps work with the ble object to read/write data, something like

      while ( ble.available() )
      {
        Serial.print(ble.read());
      }
    

    inside the loop could get the data?

  • Thank you both for the support! I put in an update using fanoush's recommendation on the Feather.
    I removed the while loop so that it just continually loops. The serial response when clicking the Puck returns "I received: -1". The -1 means no data. So I'm not sure if that means the serial ports are not looking on the same space?

    void loop() {
        incomingByte = ble.read();
        // say what you got:
        Serial.print("I received: ");
        Serial.println(incomingByte, DEC);
    }
    
  • What about trying some bleuart example from adafruit?


    1 Attachment

    • Screenshot 2024-06-11 134406.jpg
  • You could also try connecting to the feather with the 'nRF Connect' Android/iOS app and writing to the characteristic directly - that way you can rule out Espruino as being the problem

  • Lots of progress - thank you both for your patience and guidance!!! In the process, I'm learning a lot about the environments (BLE, Aurduino, and Espruino).

    I have the Puck and the Feather talking to each other!!! I'm not sure EXACTLY what made it happen, but I'll go with it

    Here is what I have on the Puck that works.

    var feather = "ff:8d:05:ae:17:64 random";
    
    // 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);
        return require("ble_simple_uart").write(device,­ "true");
      }).then(function() {
        console.log('Done!');
      });
    }
    
    // Send a message when the button is pressed
    setWatch(function() {
      blinkGreen();
      sendMessage();
    }, BTN, { edge: "rising", debounce: 50, repeat: true });
    

    Here is what I have on the Feather. I am able to read the serial and then I have an if statement to check the value and if it matches then it triggers another function. This is just a simple example to test it, but it works.

    [#include](https://forum.espruino.com/se­arch/?q=%23include) <Arduino.h>
    [#include](https://forum.espruino.com/se­arch/?q=%23include) <SPI.h>
    [#include](https://forum.espruino.com/se­arch/?q=%23include) "Adafruit_BLE.h"
    [#include](https://forum.espruino.com/se­arch/?q=%23include) "Adafruit_BluefruitLE_SPI.h"
    [#include](https://forum.espruino.com/se­arch/?q=%23include) "Adafruit_BluefruitLE_UART.h"
    
    [#include](https://forum.espruino.com/se­arch/?q=%23include) "BluefruitConfig.h"
    
    [#if](https://forum.espruino.com/search/­?q=%23if) SOFTWARE_SERIAL_AVAILABLE
      [#include](https://forum.espruino.com/se­arch/?q=%23include) <SoftwareSerial.h>
    [#endif](https://forum.espruino.com/sear­ch/?q=%23endif)
    
    /*======================================­===================================
        ----------------------------------------­-------------------------------*/
        [#define](https://forum.espruino.com/sea­rch/?q=%23define) FACTORYRESET_ENABLE         1
        [#define](https://forum.espruino.com/sea­rch/?q=%23define) MINIMUM_FIRMWARE_VERSION    "0.6.6"
        [#define](https://forum.espruino.com/sea­rch/?q=%23define) MODE_LED_BEHAVIOUR          "MODE"
        [#define](https://forum.espruino.com/sea­rch/?q=%23define) LED_BUILTIN                 13
    /*======================================­===================================*/
    
    Adafruit_BluefruitLE_SPI ble(BLUEFRUIT_SPI_CS, BLUEFRUIT_SPI_IRQ, BLUEFRUIT_SPI_RST);
    
    // A small helper
    void error(const __FlashStringHelper*err) {
      Serial.println(err);
      while (1);
    }
    
    /***************************************­***********************************/
    /*!
        @brief  Sets up the HW an the BLE module (this function is called
                automatically on startup)
    */
    /***************************************­***********************************/
    
    int incomingByte = 0; // for incoming serial data
    String readString;
    
    void testFunction(){
      Serial.println(F("if statement worked"));
    }
    
    void setup() {
      // Start the hardware serial communication at 9600 baud rate
      Serial.begin(115200); // Serial Monitor
      Serial1.begin(115200); // UART Communication (Replace Serial1 with appropriate Serial for your Feather)
    
      /* Initialise the module */
      Serial.print(F("Initialising the Splitz Start Beacon"));
      Serial.println(F("----------------------­-----------------"));
    
      if ( !ble.begin(VERBOSE_MODE) ){
        error(F("Couldn't find Bluefruit, make sure it's in CoMmanD mode & check wiring?"));
      }
      Serial.println( F("OK!") );
    
      if ( FACTORYRESET_ENABLE ){
        /* Perform a factory reset to make sure everything is in a known state */
        Serial.println(F("Performing a factory reset: "));
        if ( ! ble.factoryReset() ){
          error(F("Couldn't factory reset"));
        }
      }
    
      /* Disable command echo from Bluefruit */
      ble.echo(false);
    
      Serial.println("Requesting Bluefruit info:");
      /* Print Bluefruit information */
      ble.info();
      Serial.println();
    
      ble.verbose(false);  // debug info is a little annoying after this point!
    
      /* Change the device name to make it easier to find */
      Serial.println(F("Setting device name to 'Splitz Start Beacon'"));
      if (!ble.sendCommandCheckOK(F("AT+GAPDEVNAM­E=Splitz Start Beacon"))) {
        error(F("Could not set device name?"));
      }
    
      // Set module to DATA mode
      Serial.println( F("Switching to DATA mode!") );
      ble.setMode(BLUEFRUIT_MODE_DATA);
    
      /* Wait for connection */
      while (! ble.isConnected()) {
          delay(500);
      }
    
      if(ble.isConnected()){
        Serial.println(F("Device is connected."));
      }
    
      pinMode(13, OUTPUT); // Optional: Use the built-in LED to indicate received data
    }
    
    void loop() {
      // Echo received data
      while ( ble.available() )
      {
        char c = ble.read();
        readString += c; //makes the String readString
        delay(3);  //slow looping to allow buffer to fill with next character
      } 
    
      if (readString.length() > 0) {
        Serial.println(readString);  //so you can see the captured String
        if (readString == "true"){
          testFunction();
        }
        readString = "";
      }
    }
    

    The only issue is that it disconnects after it sends the info. How would I be able to persist the connection?

    I tried the below. It connects to the board but doesn't write to the serial like "requestDevice " did.

      NRF.connect(feather).then(function(d){
        print(d);
        return require("ble_simple_uart").write(d, "true");
      }).then(function() {
        console.log('Done!');
      });
    
  • Glad you got it working! ble_simple_uart will always disconnect BLE - it's just there to have something super simple to use.

    If you look at https://www.espruino.com/BLE+UART#receiv­ing-evaluating there are some other examples though. Probably most useful is:

    NRF.requestDevice({ filters: [{ id: feather }] }).then(function(device) {
      return require("ble_uart").connect(device);
    }).then(function(uart) {
      uart.on('data', function(d) { print("Got:"+JSON.stringify(d)); });
      uart.write("testing!"); // .then(...)
      setTimeout(function() {
        uart.disconnect();
        console.log("Disconnected");
      }, 20000); // disconnect after 20s
    });
    
  • 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.

  • 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.

  • 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(fu­nction() {
            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 });
    
  • I feel like maybe you're getting code mixed up somewhere? On the BLE UART page it gives you some examples, but you're doing something a bit different: https://www.espruino.com/BLE+UART#receiv­ing-evaluating

    For example you're doing uart.write(device, "true"); but the code in the link above requires you to do require("ble_uart").connect(device) to get a promise that returns a uart instance, and then you do uart.write("true"); on that.

    So your code should look something like:

    function sendMessage() {
      console.log("Trying to Connect");
      NRF.requestDevice({ filters: [{ id: feather }], active:true }).then(function(device) {
      return require("ble_uart").connect(device);
    }).then(function(uart) {
      uart.write("true"); // .then(...)
      setTimeout(function() {
        uart.disconnect();
        console.log("Disconnected");
      }, 2000);
    });
    }
    

    If you want to stay connected you could hang onto the uart variable rather than only using it in sendMessage though

  • 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/se­arch/?q=%23include) <Arduino.h>
    [#include](https://forum.espruino.com/se­arch/?q=%23include) <SPI.h>
    [#include](https://forum.espruino.com/se­arch/?q=%23include) "Adafruit_BLE.h"
    [#include](https://forum.espruino.com/se­arch/?q=%23include) "Adafruit_BluefruitLE_SPI.h"
    [#include](https://forum.espruino.com/se­arch/?q=%23include) "Adafruit_BluefruitLE_UART.h"
    [#include](https://forum.espruino.com/se­arch/?q=%23include) "BluefruitConfig.h"
    
    [#if](https://forum.espruino.com/search/­?q=%23if) SOFTWARE_SERIAL_AVAILABLE
      [#include](https://forum.espruino.com/se­arch/?q=%23include) <SoftwareSerial.h>
    [#endif](https://forum.espruino.com/sear­ch/?q=%23endif)
    
    [#define](https://forum.espruino.com/sea­rch/?q=%23define) FACTORYRESET_ENABLE         1
    [#define](https://forum.espruino.com/sea­rch/?q=%23define) MINIMUM_FIRMWARE_VERSION    "0.6.6"
    [#define](https://forum.espruino.com/sea­rch/?q=%23define) MODE_LED_BEHAVIOUR          "MODE"
    [#define](https://forum.espruino.com/sea­rch/?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+GAPDEVNAM­E=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!

  • On the Puck, maybe try:

    function sendMessage() {
      console.log("Trying to Connect");
      NRF.requestDevice({ filters: [{ id: feather }], active:true }).then(function(device) {
      return require("ble_uart").connect(device);
    }).then(function(_uart) {
      uart = _uart;
      uart.on('data', function(d) {
        console.log("Got:"+JSON.stringify(d));
      });
      return uart.write("1");
    }).then(function() {
      console.log("Message sent successfully.");  
    });
    }
    

    There were a few issues on the Puck side:

    • you weren't returning the promise from uart.write so it'd have returned immediately
    • best to register to receive the data before it's sent, or maybe the data will come back before the .on has executed
    • You were never setting the value of the global uart variable - it would always have been undefined, so the uart.on code would always fail
  • 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.


    2 Attachments

    • Screenshot 2024-09-27 at 6.04.56.png
    • Screenshot 2024-09-27 at 6.04.36.png
  • Ahh, ok, thanks! So the CCCD Handle not found error is coming from Espruino via ble_uart.

    When a device provides a 'characteristic' that provides notifications when its value changes, it's supposed to have another characteristic linked to that one called a CCCD that allows you to switch those characteristics on or off.

    It would seem that the Bluefruit is providing the UART TX data characteristic, but somehow the CCCD that's supposed to be for it can't be found by Espruino.

    Without me having a Bluefruit here it might be a bit hard for me to track this down.

    However looking back, it seems that you didn't really want the two-way communication anyway? You just wanted to be able to send some data without disconnecting?

    In that case we can just modify the code from https://www.espruino.com/modules/ble_sim­ple_uart.js slightly and include it in your folder directly:

    var device;
    const feather = "e8:76:9a:13:1a:32 random"; // Change me!
    
    function ble_uart_write(gatt, text) {
      return gatt.getPrimaryService("6e400001-b5a3-f3­93-e0a9-e50e24dcca9e"
      ).then(function(s) {
        return s.getCharacteristic("6e400002-b5a3-f393-­e0a9-e50e24dcca9e");
      }).then(function(c) {
        function sender(resolve, reject) {
          if (text.length) {
            c.writeValue(text.substr(0,20)).then(fun­ction() {
              sender(resolve, reject);
            }).catch(reject);
            text = text.substr(20);
          } else  {
            resolve();
          }
        }
        return new Promise(sender);
      });
    }
    
    
    function sendMessage() {
      var promise = (device&&device.gatt.connected) ? Promise.resolve(device.gatt) :
         NRF.requestDevice({ filters: [{ id: feather }] }).then(function(d) {
          device = d;
          console.log("Trying to Connect");
          return device.gatt.connect();
         });
      promise.then(function(gatt) {
        console.log("Sending message");
        return ble_uart_write(gatt, "LED.toggle();\n"); // Change me!
      }).then(function() {
        console.log("Message sent successfully.");  
      });
    }
    

    Just tried this - not on a feather though, and it works well for me - and automatically reconnects if there's no connection

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

Puck.js Connect to Adafruit Feather Board

Posted by Avatar for user158306 @user158306

Actions