Central Argon to Peripheral Argon BLE mesh communication

I originally got argon to 2 xenon mesh network communication. Since Particle is going away from using the mesh network and xenons, I’m now trying to take a crack out of argon to argon communication using the BLE mesh library from this link: https://support.particle.io/hc/en-us/articles/360044755894-Create-a-local-publish-subscribe-group-using-BLE-on-Gen3-devices .

I’m trying to do this without connecting to cloud. My application is creating biometric motion sensors using accelerometers. My code is below.

Peripheral:

/*
 * Project peripheral_test
 * Description: Particle Argon BLE peripheral test
 * Author: Cameron Pinnock
 * Date: 7/14/2020
 */

#include "Particle.h"
#include <limits.h>
#include "BLE_Group.h"
#include <Adafruit_BNO055.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

// This strips the path from the filename
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)

BLE_Group *group;

//SYSTEM_THREAD(ENABLED);

//SYSTEM_MODE(SEMI_AUTOMATIC);

const unsigned long UPDATE_INTERVAL = 10;
unsigned long lastUpdate = 0;

//Message variables
char beatMsg[128];
char ackMsg[128];

Adafruit_BNO055 bno;     //Adafruit_BNO055(0x28 );

char accVal_beta[128];

int accel_valy;

void setup()
{
    Serial.begin(115200);
    
    while (!bno.begin())
    {
      Serial.println("BNO sensor not available");
    }
    
    group = new BLE_Group_Peripheral(1); // The parameter is the groupID

}

void loop()
{
    unsigned long currentMillis = millis();
    
    if (currentMillis - lastUpdate >= UPDATE_INTERVAL)
    {
        lastUpdate = millis();
    
        sensors_event_t event;
        bno.getEvent(&event);
        accel_valy=event.orientation.y;
        //accel_valy=event.orientation.y;
        //accel_valz=event.orientation.z;
        snprintf(accVal_beta, 128, "%d", accel_valy);
        Serial.println(accel_valy);
        //Particle.publish("Beta_Accelerameter", String(accVal_beta), PRIVATE);
        group->publish("accVal_beta001", accVal_beta);
        
    }
}

Central:

/*
 * Project peripheral_test
 * Description: Particle Argon BLE central test
 * Author: Cameron Pinnock
 * Date: 7/14/2020
 */

#include "Particle.h"
#include <limits.h>
#include "BLE_Group.h"
#include <Adafruit_BNO055.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

// This strips the path from the filename
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)

BLE_Group *group;

SYSTEM_THREAD(ENABLED);

SYSTEM_MODE(SEMI_AUTOMATIC);

const unsigned long UPDATE_INTERVAL = 10;
unsigned long lastUpdate = 0;

//Message variables
char beatMsg[128];
char ackMsg[128];


Adafruit_BNO055 bno;     //Adafruit_BNO055(0x28 );

int accelVal_alpha;

int val;

char biometricPacket[128];

void biometricData(const char *event, const char *data){

    unsigned long currentMillis = millis();
    
    if (currentMillis - lastUpdate >= UPDATE_INTERVAL)
    {
        int accelVal_beta = atoi(data);

        sensors_event_t event2;
        bno.getEvent(&event2);
        accelVal_alpha = event2.orientation.y;
        
        snprintf(biometricPacket, 128, "%d %d ", accelVal_beta, accelVal_alpha);

        Serial.println(biometricPacket);
    }
}

void setup()
{
    
    Serial.begin(115200);
    
    while (!bno.begin())
    {
      Serial.println("BNO sensor not available");
    }
    
    //group = new BLE_Group_Central(1); // The parameter is the groupID
    
    //group->subscribe("accVal_beta001", biometricData);

}

void loop()
{
    unsigned long currentMillis = millis();
    
    if (currentMillis - lastUpdate >= UPDATE_INTERVAL)
    {
        //int accelVal_beta = atoi(data);

        sensors_event_t event2;
        bno.getEvent(&event2);
        accelVal_alpha = event2.orientation.y;
        
        Serial.println(accelVal_alpha);
        
        //snprintf(biometricPacket, 128, "%d %d ", accelVal_beta, accelVal_alpha);

        //Serial.println(biometricPacket);
    }
}

On the Central device, what happens if you un-comment out the two last lines in setup()? (group=new BLE_Group_Central(1);group->subscribe(“accVal_beta001”,biometricData);

I uncommented it and still only got the accelerometer data from the void loop(). I then thought maybe the I should call the function biometricData in the void loop() instead. When I do that I don’t get any data out. I think my syntax could be wrong. Here are my modified peripheral and central codes.

Peripheral code:

/*
 * Project peripheral_test
 * Description: Particle Argon BLE peripheral test
 * Author: Cameron Pinnock
 * Date: 7/14/2020
 */

#include "Particle.h"
#include <limits.h>
#include "BLE_Group.h"
#include <Adafruit_BNO055.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

// This strips the path from the filename
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)

BLE_Group *group;

SYSTEM_THREAD(ENABLED);

SYSTEM_MODE(SEMI_AUTOMATIC);

const unsigned long UPDATE_INTERVAL = 10;
unsigned long lastUpdate = 0;

//Message variables
char beatMsg[128];
char ackMsg[128];

Adafruit_BNO055 bno;     //Adafruit_BNO055(0x28 );

char accVal_beta[128];

int accel_valy;

void setup()
{
    Serial.begin(115200);
    
    while (!bno.begin())
    {
      Serial.println("BNO sensor not available");
    }
    
    group = new BLE_Group_Peripheral(1); // The parameter is the groupID

}

void loop()
{
    unsigned long currentMillis = millis();
    
    if (currentMillis - lastUpdate >= UPDATE_INTERVAL)
    {
        lastUpdate = millis();
    
        sensors_event_t event;
        bno.getEvent(&event);
        accel_valy=event.orientation.y;
        //accel_valy=event.orientation.y;
        //accel_valz=event.orientation.z;
        snprintf(accVal_beta, 128, "%d", accel_valy);
        Serial.println(accel_valy);
        //Particle.publish("Beta_Accelerameter", String(accVal_beta), PRIVATE);
        group->publish("accVal_beta001", accVal_beta);
        
    }
}

Central code:

/*
 * Project peripheral_test
 * Description: Particle Argon BLE central test
 * Author: Cameron Pinnock
 * Date: 7/14/2020
 */

#include "Particle.h"
#include <limits.h>
#include "BLE_Group.h"
#include <Adafruit_BNO055.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

// This strips the path from the filename
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)

BLE_Group *group;

SYSTEM_THREAD(ENABLED);

SYSTEM_MODE(SEMI_AUTOMATIC);

const unsigned long UPDATE_INTERVAL = 10;
unsigned long lastUpdate = 0;

//Message variables
char beatMsg[128];
char ackMsg[128];


Adafruit_BNO055 bno;     //Adafruit_BNO055(0x28 );

int accelVal_alpha;

int val;

char biometricPacket[128];

void biometricData(const char *event, const char *data){

    unsigned long currentMillis = millis();
    
    if (currentMillis - lastUpdate >= UPDATE_INTERVAL)
    {
        int accelVal_beta = atoi(data);

        sensors_event_t event2;
        bno.getEvent(&event2);
        accelVal_alpha = event2.orientation.y;
        
        snprintf(biometricPacket, 128, "%d %d ", accelVal_beta, accelVal_alpha);

        Serial.println(biometricPacket);
    }
}

void setup()
{
    
    Serial.begin(115200);
    
    while (!bno.begin())
    {
      Serial.println("BNO sensor not available");
    }
    
    group = new BLE_Group_Central(1); // The parameter is the groupID
    
    group->subscribe("accVal_beta001", biometricData);

}

void loop()
{
    biometricData;
}

You don’t need to call biometricData in the loop().

But the central does need to scan to be able to find peripherals and make the connection. For example, put inside loop():

if (group->devices_connected() < BLE_GROUP_MAX_PERIPHERALS)
{
  group->scan();
}

Added the line of code to the void loop. Now the argon starts with a white led then it starts blinking red. I still don’t see any data being printed.

Central Code:

/*
 * Project peripheral_test
 * Description: Particle Argon BLE central test
 * Author: Cameron Pinnock
 * Date: 7/14/2020
 */

#include "Particle.h"
#include <limits.h>
#include "BLE_Group.h"
#include <Adafruit_BNO055.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

// This strips the path from the filename
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)

BLE_Group *group;

SYSTEM_THREAD(ENABLED);

SYSTEM_MODE(SEMI_AUTOMATIC);

const unsigned long UPDATE_INTERVAL = 10;
unsigned long lastUpdate = 0;

//Message variables
char beatMsg[128];
char ackMsg[128];


Adafruit_BNO055 bno;     //Adafruit_BNO055(0x28 );

int accelVal_alpha;

int val;

char biometricPacket[128];

void biometricData(const char *event, const char *data){

    unsigned long currentMillis = millis();
    
    if (currentMillis - lastUpdate >= UPDATE_INTERVAL)
    {
        int accelVal_beta = atoi(data);

        sensors_event_t event2;
        bno.getEvent(&event2);
        accelVal_alpha = event2.orientation.y;
        
        snprintf(biometricPacket, 128, "%d %d ", accelVal_beta, accelVal_alpha);

        Serial.println(biometricPacket);
    }
}

void setup()
{
    
    Serial.begin(115200);
    
    while (!bno.begin())
    {
      Serial.println("BNO sensor not available");
    }
    
    group = new BLE_Group_Central(1); // The parameter is the groupID
    
    group->subscribe("accVal_beta001", biometricData);

}

void loop()
{
    if (group->devices_connected() < BLE_GROUP_MAX_PERIPHERALS)
    {
      group->scan();
    }
}

When posting code, can you please use the Preformatted Text feature ( image ) to wrap the code block in some better readable form?

Sorry about that this is my first time posting on here. I’m still getting red leds on both the central and peripheral argons. Also, no data is printing from the central argon.

Central Code

/*
 * Project peripheral_test
 * Description: Particle Argon BLE central test
 * Author: Cameron Pinnock
 * Date: 7/14/2020
 */

#include "Particle.h"
#include <limits.h>
#include "BLE_Group.h"
#include <Adafruit_BNO055.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

// This strips the path from the filename
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)

BLE_Group *group;

SYSTEM_THREAD(ENABLED);

SYSTEM_MODE(SEMI_AUTOMATIC);

const unsigned long UPDATE_INTERVAL = 10;
unsigned long lastUpdate = 0;

//Message variables
char beatMsg[128];
char ackMsg[128];


Adafruit_BNO055 bno;     //Adafruit_BNO055(0x28 );

int accelVal_alpha;

int val;

char biometricPacket[128];

void biometricData(const char *event, const char *data){

    unsigned long currentMillis = millis();
    
    if (currentMillis - lastUpdate >= UPDATE_INTERVAL)
    {
        int accelVal_beta = atoi(data);

        sensors_event_t event2;
        bno.getEvent(&event2);
        accelVal_alpha = event2.orientation.y;
        
        snprintf(biometricPacket, 128, "%d %d ", accelVal_beta, accelVal_alpha);

        Serial.println(biometricPacket);
    }
}

void setup()
{
    
    Serial.begin(115200);
    
    while (!bno.begin())
    {
      Serial.println("BNO sensor not available");
    }
    
    group = new BLE_Group_Central(1); // The parameter is the groupID
    
    group->subscribe("accVal_beta001", biometricData);

}

void loop()
{
    if (group->devices_connected() < BLE_GROUP_MAX_PERIPHERALS)
    {
      group->scan();
    }
}

Peripheral Code:

/*
 * Project peripheral_test
 * Description: Particle Argon BLE peripheral test
 * Author: Cameron Pinnock
 * Date: 7/14/2020
 */

#include "Particle.h"
#include <limits.h>
#include "BLE_Group.h"
#include <Adafruit_BNO055.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

// This strips the path from the filename
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)

BLE_Group *group;

SYSTEM_THREAD(ENABLED);

SYSTEM_MODE(SEMI_AUTOMATIC);

const unsigned long UPDATE_INTERVAL = 10;
unsigned long lastUpdate = 0;

//Message variables
char beatMsg[128];
char ackMsg[128];

Adafruit_BNO055 bno;     //Adafruit_BNO055(0x28 );

char accVal_beta[128];

int accel_valy;

void setup()
{
    Serial.begin(115200);
    
    while (!bno.begin())
    {
      Serial.println("BNO sensor not available");
    }
    
    group = new BLE_Group_Peripheral(1); // The parameter is the groupID

}

void loop()
{
    unsigned long currentMillis = millis();
    
    if (currentMillis - lastUpdate >= UPDATE_INTERVAL)
    {
        lastUpdate = millis();
    
        sensors_event_t event;
        bno.getEvent(&event);
        accel_valy=event.orientation.y;
        //accel_valy=event.orientation.y;
        //accel_valz=event.orientation.z;
        snprintf(accVal_beta, 128, "%d", accel_valy);
        Serial.println(accel_valy);
        //Particle.publish("Beta_Accelerameter", String(accVal_beta), PRIVATE);
        group->publish("accVal_beta001", accVal_beta);
        
    }
}

I still can’t see any data on the central end. I think we’re in the right direction but think missing something. The both are blinking red so they are communicating but nothing is getting through and I don’t think red anything good but at least we’re getting some interaction.

Flashing red could be an error code. Please see the documentation here:
https://docs.particle.io/tutorials/device-os/led/argon/#red-flash-sos

On the Central device, can you make the scan() so that it doesn’t happen on every loop() iteration, but maybe every 30 seconds or so? For example:

unsigned long lastScan = 0;
void loop()
{
    if (group->devices_connected() < BLE_GROUP_MAX_PERIPHERALS && millis() - lastScan > 30000)
    {
      lastScan = millis();
      group->scan();
 
   }
}

Do I have to connected to the cloud? I’m trying to do this without being connected to the cloud. I added that line of code and I’m still getting blinking red lights and no data printing. How does the rest of my code look for both central and peripheral. Please let me know.

The sad thing is I never had these issues with the original mesh network which was working for us very well. I keep getting issues with the BLE mesh. I killed 2 argons doing a particle update, finally got one to work. Then I flashed a --tinker in dfu mode. Still getting these issues. Could you just send me a simple data passing code for central and peripheral argons where the central argon is just Serial printing millis() values from the peripheral argon? If I get that I could figure out how to get my application to work.

Oh! I see that you are in SEMI_AUTOMATIC mode. The radios are not turned on automatically in that mode.

So in setup(), you’ll want to:

BLE.on();

If that doesn’t fix the issue, I would recommend that you start from one of the examples in the BLE_Group library. For example: https://github.com/particle-iot/ble-group-library/blob/main/examples/heartbeat/heartbeat.ino

1 Like

That didn’t work. Are the your example heartbeat codes with my added sections. No red blinking led but I don’t under the data I’m getting and I’m seeing the data I want.

Peripheral Code:

/*
 * Project ble-group-heart-beat-example
 * Description: Create local BLE communication among multiple devices and monitor long term connectivity
 * Author: Mariano Goluboff
 * Date: January 24th, 2020
 *
 * Instructions:
 * - Deploy firmware to several Gen3 devices (Argon or Boron)
 * - Use the Particle Console to run SetCentral on one device and SetPeripheral on the others
 *   all with the same numerical input (e.g. 5)
 * - Reboot all devices
 */

#include <string>
#include "Particle.h"
#include <limits.h>
#include "BLE_Group.h"
#include <Adafruit_BNO055.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

SYSTEM_THREAD(ENABLED);

SYSTEM_MODE(SEMI_AUTOMATIC);

SerialLogHandler logHandler;

BLE_Group *group;

int eeprom_address = 0;
struct bleConfig {
  uint8_t is_central;
  uint16_t group_number;
};

bool dev_configured;

unsigned long heartbeat_time, scan_time;

// Set the device flash configuration to peripheral.
// It is applied at the next reboot.
int setAsPeripheral(String extra)
{
  bleConfig myConfig = { 0, (uint16_t)std::atoi(extra)};
  EEPROM.put(eeprom_address, myConfig);
  return 0;
}

// Set the device flash configuration to central.
// It is applied at the next reboot
int setAsCentral(String extra)
{
  bleConfig myConfig = { 1, (uint16_t)std::atoi(extra)};
  EEPROM.put(eeprom_address, myConfig);
  return 0;
}

void kickFunc(const char *event, const char *data)
{
  //Particle.publish("kick-received", data, PRIVATE);
}

/*
 * Callback functions to monitor connection/disconnection from the
 * local BLE Group.
 */
void onConnect(const BlePeerDevice& peer, void* context)
{
  Particle.publish("Connected", peer.address().toString(), PRIVATE);
}
void onDisconnect(const BlePeerDevice& peer, void* context)
{
  Particle.publish("Disconnected", peer.address().toString(), PRIVATE);
}

const unsigned long UPDATE_INTERVAL = 100;
unsigned long lastUpdate = 0;

Adafruit_BNO055 bno;     //Adafruit_BNO055(0x28 );

char accVal_beta[128];

int accel_valy;

// setup() runs once, when the device is first turned on.
void setup() {

  BLE.on();

  Serial.begin(115200);
  
  Wire.begin();
  
  while (!bno.begin())
  {
    Serial.println("BNO sensor not available");
  }
  
  Particle.function("SetPeripheral", setAsPeripheral);
  //Particle.function("SetCentral", setAsCentral);
  bleConfig myConfig;
  EEPROM.get(eeprom_address, myConfig);
  if (myConfig.is_central == 0xFF)
  {
    dev_configured = false;
  }
  else if (myConfig.is_central == 1)
  {
    group = new BLE_Group_Central(myConfig.group_number);
    dev_configured = true;
  }
  else if (myConfig.is_central == 0)
  {
    group = new BLE_Group_Peripheral(myConfig.group_number);
    dev_configured = true;
  }
  if (dev_configured)
  {
    group->subscribe("kick", kickFunc);
    group->onConnect(onConnect, NULL);
    group->onDisconnect(onDisconnect, NULL);
  }
  scan_time = 0;
  heartbeat_time = 0;
  // Speed up transmission (this works for Particle devices talking to Particle devices
  // but can break communications to iPhones as they have higher latencies)
  BLE.setPPCP(12, 12, 0, 200);
  // Increase transmit power to max
  BLE.setTxPower(8);
}

// loop() runs over and over again, as quickly as it can execute.
void loop() {

  //unsigned long currentMillis = millis();
  
  if (dev_configured && millis() - heartbeat_time >= UPDATE_INTERVAL)
  {
      sensors_event_t event;
      bno.getEvent(&event);
      accel_valy=event.orientation.y;
      //accel_valy=event.orientation.y;
      //accel_valz=event.orientation.z;
      snprintf(accVal_beta, sizeof(accVal_beta), "%d", accel_valy);
      Serial.println(accVal_beta);
      //Particle.publish("Beta_Accelerameter", String(accVal_beta), PRIVATE);
      group->publish("accVal_beta001", accVal_beta);
      heartbeat_time = millis();
      
  }
  
  if(dev_configured && (millis() - heartbeat_time) > 60000 )
  {
    group->publish("kick", System.deviceID());
    heartbeat_time = millis();
    Serial.println(heartbeat_time);
  }
  
}


Central Code:

 /*
  * Project ble-group-heart-beat-example
  * Description: Create local BLE communication among multiple devices and monitor long term connectivity
  * Author: Mariano Goluboff
  * Date: January 24th, 2020
  *
  * Instructions:
  * - Deploy firmware to several Gen3 devices (Argon or Boron)
  * - Use the Particle Console to run SetCentral on one device and SetPeripheral on the others
  *   all with the same numerical input (e.g. 5)
  * - Reboot all devices
  */
 #include <string>
 #include "Particle.h"
 #include <limits.h>
 #include "BLE_Group.h"
 #include <Adafruit_BNO055.h>
 #include <Adafruit_Sensor.h>
 #include <Wire.h>
 #if defined(ARDUINO) && ARDUINO >= 100
 #include "Arduino.h"
 #else
 #include "WProgram.h"
 #endif

 SYSTEM_THREAD(ENABLED);
 
 SYSTEM_MODE(SEMI_AUTOMATIC);

 SerialLogHandler logHandler;

 BLE_Group *group;

 int eeprom_address = 0;
 struct bleConfig {
   uint8_t is_central;
   uint16_t group_number;
 };

 bool dev_configured;

 unsigned long heartbeat_time, scan_time;

 // Set the device flash configuration to peripheral.
 // It is applied at the next reboot.
 int setAsPeripheral(String extra)
 {
   bleConfig myConfig = { 0, (uint16_t)std::atoi(extra)};
   EEPROM.put(eeprom_address, myConfig);
   return 0;
 }

 // Set the device flash configuration to central.
 // It is applied at the next reboot
 int setAsCentral(String extra)
 {
   bleConfig myConfig = { 1, (uint16_t)std::atoi(extra)};
   EEPROM.put(eeprom_address, myConfig);
   return 0;
 }

 void kickFunc(const char *event, const char *data)
 {
   //Particle.publish("kick-received", data, PRIVATE);
 }

 /*
  * Callback functions to monitor connection/disconnection from the
  * local BLE Group.
  */
 void onConnect(const BlePeerDevice& peer, void* context)
 {
   Particle.publish("Connected", peer.address().toString(), PRIVATE);
 }
 void onDisconnect(const BlePeerDevice& peer, void* context)
 {
   Particle.publish("Disconnected", peer.address().toString(), PRIVATE);
 }
 
 const unsigned long UPDATE_INTERVAL = 100;
 unsigned long lastUpdate = 0;

 Adafruit_BNO055 bno;     //Adafruit_BNO055(0x28 );
 
 int accelVal_alpha;

 int val;

 char biometricPacket[128];

void biometricData(const char *event, const char *data){

    unsigned long currentMillis = millis();
    
    if (currentMillis - lastUpdate >= UPDATE_INTERVAL)
    {
        int accelVal_beta = std::atoi(data);

        sensors_event_t event2;
        bno.getEvent(&event2);
        accelVal_alpha = event2.orientation.y;

        snprintf(biometricPacket, sizeof(biometricPacket), "%d %d", accelVal_beta, accelVal_alpha);

        Serial.println(accelVal_alpha);
        
        lastUpdate = millis();
        
    }
}

 // setup() runs once, when the device is first turned on.
 void setup() {
 
   BLE.on();
 
   Serial.begin(115200);
   
   Wire.begin();
   
   while (!bno.begin())
   {
     Serial.println("BNO sensor not available");
   }
   
   //Particle.function("SetPeripheral", setAsPeripheral);
   Particle.function("SetCentral", setAsCentral);
   bleConfig myConfig;
   EEPROM.get(eeprom_address, myConfig);
   if (myConfig.is_central == 0xFF)
   {
     dev_configured = false;
   }
   else if (myConfig.is_central == 1)
   {
     group = new BLE_Group_Central(myConfig.group_number);
     dev_configured = true;
   }
   else if (myConfig.is_central == 0)
   {
     group = new BLE_Group_Peripheral(myConfig.group_number);
     dev_configured = true;
   }
   if (dev_configured)
   {
     group->subscribe("kick", kickFunc);
     group->subscribe("accVal_beta001", biometricData);
     group->onConnect(onConnect, NULL);
     group->onDisconnect(onDisconnect, NULL);
   }
   scan_time = 0;
   heartbeat_time = 0;
   // Speed up transmission (this works for Particle devices talking to Particle devices
   // but can break communications to iPhones as they have higher latencies)
   BLE.setPPCP(12, 12, 0, 200);
   // Increase transmit power to max
   BLE.setTxPower(8);
 }

 // loop() runs over and over again, as quickly as it can execute.
 void loop() {
   if (dev_configured && group->isCentral())
   {
     // Scan for more devices to build the group if we're the Central device
     // and we haven't hit the maximum number of devices yet.
     if (group->devices_connected() < BLE_GROUP_MAX_PERIPHERALS && (millis() - scan_time) > 30000)
     {
       group->scan();
       scan_time = millis();
     }
   }
   if(dev_configured && (millis() - heartbeat_time) > 60000 )
   {
     group->publish("kick", System.deviceID());
     heartbeat_time = millis();
     //Serial.println(heartbeat_time);
   }
 }

What does this mean?

Serial Data from Peripheral Argon:

Serial Data from Central Argon:

That’s the debug information from adding SerialLogHandler

See the Logging documentation here:
https://docs.particle.io/reference/device-os/firmware/argon/#logging

Ok cool. How do I get the central argon to read what the peripheral argon is doing? I let’s provide a simple case: I want the central argon to print the millis() from the peripheral argon.

Please instruct me how to do so.

Also do I still have to register the argons with the phone app and connect them with the cloud first? I assumed with this library you do not have to since you don’t have to connect to the cloud. Let me know as well.

I think I’m getting the hang of this. I kind of pieced together the BLE tutorial which jumps around a lot and is brutal to understand do to that. I got the peripheral to compile but I can’t get the central to compile. Then went to your library and noticed you have 2 types of scan commands. scan() and scan(ScanEvent handler, void* context). Which do I use?

Screen Shot 2020-07-29 at 3.58.51 PM

For using the library, you just need to use the scan(). It will take care of making the connection between the Central and Peripheral devices. The other one is in case you want to have a custom callback to be fired each time a scan result is returned.

Just a comment: I am switching to UDP multicast. I set up a format for my messages which include a message name as well as a uniq ID. All the Argons on the local network pick up the messages (sometimes twice, thus the unique message identifier). If the receiving Argon isn’t interested in the message (not “subscribed”), it ignores it, but rebroadcasts it just to make sure everyone gets a crack. Each device maintains a “most recent message” list to avoid duplicate processing.

Also, this can be paired with Particle publish, as I have had instances where those messages aren’t picked up by all subscribers. The UDP also doesn’t suffer from 1 message per second speed limits.

I was planning on building this into my framework library (which also includes asynchronous Publish processing that prevents delay in your program as well as preventing overloading Particle’s 1 message per second speed limit), but if there is interest I can make it a separate library - perhaps combined with async publishing.

I will also have a Python library to monitor, process, and generate the UDP messages, as my Escape Room uses Python programs to direct and monitor the rooms.

2 Likes

Thank you for your help. I am still having trouble with BLEGroup library. I also discovered a typo in the “scanResult” function on the BLE tutorial doc website in the central code, it was saying “scanResults” which is incorrect so I deleted all the “s” in the code. Just my luck the central code compiled in my terminal. Now I just recently created a hybrid of the the BLE tutorial central code and part the BLE_Central.cpp library custom callback scan function. I then set the D7 led to light up when the devices are connected. To my luck it all compiled and they are connected, now my central argon can read the accelerometer data from peripheral argon. But it is only 1 argon is there a way to do multiple and know which argon is send what data.

Here is my code for you or anyone else to look at. This is a basic code where a central argon is reading the millis() clock on a connected peripheral argon.

Peripheral Code:

/*
* Project argon_proto_ble_peripheral
* Description: Particle Argon BLE peripheral test
* Author: Cameron Pinnock
* Date: 7/31/2020
*/

#include "Particle.h"
#include <limits.h>
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

// This strips the path from the filename
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)

SYSTEM_MODE(SEMI_AUTOMATIC);

SYSTEM_THREAD(ENABLED);

//SerialLogHandler logHandler(LOG_LEVEL_TRACE);

const unsigned long UPDATE_INTERVAL = 20;
unsigned long lastUpdate = 0;

#define BLELED D7 //BLE connected LED Indicator Pin

//Create new Service ID at https://www.uuidgenerator.net

BleUuid testService("c3d24e7e-6140-4f08-918b-a530e8599139");

//Create new Characteristic Service ID at https://www.uuidgenerator.net

BleCharacteristic testCharacteristic("testData", BleCharacteristicProperty::NOTIFY, BleUuid("57dd7c71-bf55-4fda-9cc5-5a22ccc472b8"), testService);

void setup()
{
    //(void)logHandler; // Does nothing, just to eliminate the unused variable warning

    Serial.begin(115200);
    
    BLE.on();
    
    BLE.addCharacteristic(testCharacteristic);
    
    BleAdvertisingData advData;
    
    advData.appendServiceUUID(testService);
    
    BLE.advertise(&advData);
    
    pinMode(BLELED, OUTPUT);

}

void loop()
{

    const unsigned long currentMillis = millis();
    
    if (currentMillis - lastUpdate >= UPDATE_INTERVAL)
    {
        lastUpdate = millis();
        
        const unsigned long test_data = millis();
        
        Serial.println(test_data);
        
        if (BLE.connected())
        {
        
            digitalWrite(BLELED,HIGH);
            
            uint8_t buf[2];
            
            buf[0] = 0x04;
            
            uint32_t value = test_data;
            
            memcpy(&buf[1], &value, 4);
            
            testCharacteristic.setValue(buf, sizeof(buf));
        
        }
        
    }
}

Central Code:

#include "Particle.h"
#include <limits.h>
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

// This strips the path from the filename
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)

SYSTEM_MODE(SEMI_AUTOMATIC);

SYSTEM_THREAD(ENABLED);

//SerialLogHandler logHandler(LOG_LEVEL_TRACE);

const unsigned long UPDATE_INTERVAL = 20;
unsigned long lastUpdate = 0;

#define BLELED D7 //BLE connected LED Indicator Pin

const size_t SCAN_RESULT_MAX = 1;

BleUuid testService("c3d24e7e-6140-4f08-918b-a530e8599139"); //The Service UUID for the peripheral device

BleCharacteristic testCharacteristic;

BleScanResult scanResult[SCAN_RESULT_MAX];
BlePeerDevice peer;

uint32_t last_test_data = 0;

void onDataReceived(const uint8_t* data, size_t len, const BlePeerDevice& peer, void* context);

void setup()
{
    //(void)logHandler; // Does nothing, just to eliminate the unused variable warning
    
    Serial.begin(115200);
    
    BLE.on();
    
    testCharacteristic.onDataReceived(onDataReceived, NULL);
    
    pinMode(BLELED, OUTPUT);
}

unsigned long lastScan = 0;

void loop()
{
    if (BLE.connected()) {
        // We're currently connected to a sensor
        digitalWrite(BLELED,HIGH);
    }
    else {
        // We are not connected to a sensor, scan for one
        int count = BLE.scan(scanResult, SCAN_RESULT_MAX);

        for (int ii = 0; ii < count; ii++) {
            uint8_t buf[BLE_MAX_ADV_DATA_LEN];
            size_t len;
            BleUuid foundService;
            // We're looking for devices that have a heart rate service (0x180D)
            len = scanResult[ii].advertisingData.serviceUUID(&foundService, 1);
            if (len > 0 && foundService == testService) {
                //Log.info("%d", scanResult[ii].rssi);
                //Serial.println(scanResult[ii].rssi);
                len = scanResult[ii].advertisingData.customData(buf, BLE_MAX_ADV_DATA_LEN);
                peer = BLE.connect(scanResult[ii].address);
                if (peer.connected()) {
                    //Log.info("successfully connected!");
                    // Get the test_data
                    peer.getCharacteristicByUUID(testCharacteristic, BleUuid("57dd7c71-bf55-4fda-9cc5-5a22ccc472b8")); //Characteristic UUID for peripheral device
                }
                else {
                    //Log.info("connection failed");
                }
            }
        }
    }
}

void onDataReceived(const uint8_t* data, size_t len, const BlePeerDevice& peer, void* context) {

    const unsigned long currentMillis = millis();
    
    if (currentMillis - lastUpdate >= UPDATE_INTERVAL)
    {
    
        lastUpdate = millis();
        
        uint8_t flags = data[0];

        uint32_t test_data;
        
        if (flags & 0x01) {
            // test_data is 32 bits
            memcpy(&test_data, &data[1], sizeof(uint32_t));
        }
        else {
            // test_data is 8 bits (normal case)
            test_data = data[1];
        }
        if (test_data != last_test_data) {
            last_test_data = test_data;
        }
        
        Serial.println(test_data);
        
        //Log.info("Peripheral Argon clock = %u", test_data);
        
    }
}