Arduino Nano 33 BLE Sense laptop communication using BLE dongle

Hello,

I am working on a project to stream sensor data from the Arduino Nano 33 BLE Sense to a laptop (MacOS) via bluetooth.

In order to get around the BLE-laptop compatibility issues, I have bought a Bluetooth 4.0 USB dongle (Hideez). However, I am still unable to detect the Arduino board via the usual Mac connection process. I can detect and connect to the board using the BlueSee app; however, the Arduino board does not seem to register the connection.

I am attempting to read the sensor data from the Arduino by reading off the serial port on Python, but again this has not been successful.

Any help with this would be greatly appreciated.

What is that process? Do you try to connect from an app or the OS? With BLE the OS UI is usually not involved with connecting.

What does that mean? When you connect with a smartphone to the Arduino Nano 33 BLE you obviously did something right. Otherwise, it would not work. There are callbacks you can use to do something when a central connects. Can you post your code?

Can you be a bit more specific? Usually when people use the word stream, they mean lots of data. That is not what BLE was designed for.

With BLE you should be able to create a peripheral with a service and characteristic, set this all up working with a generic BLE app running on a smartphone (iOS or Android). And if this all works you can try to get a central working on any other platform without the need to modify anything on the peripheral device.

What is that process? Do you try to connect from an app or the OS? With BLE the OS UI is usually not involved with connecting.

I was unable to connect using the OS, but connected within the BlueSee Mac app. I'm just using getting started example code to send the temperature and humidity sensor readings via BLE:

#include <ArduinoBLE.h>
#include <Arduino_HTS221.h>

const int UPDATE_FREQUENCY = 2000; // Update frequency in ms
const float CALIBRATION_FACTOR = -4.0; // Temperature calibration factor (celcius)

int previousTemperature = 0;
unsigned int previousHumidity = 0;
long previousMillis = 0;  // last time readings were checked, in ms

BLEService environmentService("181A");  // Standard Environmental Sensing service

BLEIntCharacteristic tempCharacteristic("2A6E",  // Standard 16-bit Temperature characteristic
  BLERead | BLENotify); // Remote clients can read and get updates

BLEUnsignedIntCharacteristic humidCharacteristic("2A6F", // Unsigned 16-bit Humidity characteristic
  BLERead | BLENotify);

void setup() {
  Serial.begin(9600);    // Initialize serial communication
  while (!Serial);

  if (!HTS.begin()) {  // Initialize HTS22 sensor
    Serial.println("Failed to initialize humidity temperature sensor!");
    while (1);
  }

  pinMode(LED_BUILTIN, OUTPUT); // Initialize the built-in LED pin

  if (!BLE.begin()) {   // Initialize BLE
    Serial.println("starting BLE failed!");
    while (1);
  }

  BLE.setLocalName("Nano33BLESENSE");  // Set name for connection
  BLE.setAdvertisedService(environmentService); // Advertise environment service
  environmentService.addCharacteristic(tempCharacteristic); // Add temperature characteristic
  environmentService.addCharacteristic(humidCharacteristic); // Add humidity chararacteristic
  BLE.addService(environmentService); // Add environment service
  tempCharacteristic.setValue(0); // Set initial temperature value
  humidCharacteristic.setValue(0); // Set initial humidity value

  BLE.advertise();  // Start advertising
  Serial.print("Peripheral device MAC: ");
  Serial.println(BLE.address());
  Serial.println("Waiting for connections...");
}

void loop() {
  BLEDevice central = BLE.central();  // Wait for a BLE central to connect

  // If central is connected to peripheral
  if (central) {
    Serial.print("Connected to central MAC: ");
    Serial.println(central.address());    // Central's BT address:
    // Turn on the LED to indicate the connection:
    digitalWrite(LED_BUILTIN, HIGH);

    while (central.connected()) {
      long currentMillis = millis();
      // After UPDATE_FREQUENCY ms have passed, check temperature & humidity
      if (currentMillis - previousMillis >= UPDATE_FREQUENCY) {
        previousMillis = currentMillis;
        updateReadings();
      }
    }

    // When the central disconnects, turn off the LED
    digitalWrite(LED_BUILTIN, LOW);
    Serial.print("Disconnected from central MAC: ");
    Serial.println(central.address());
  }
}

int getTemperature(float calibration) {
  // Get calibrated temperature as signed 16-bit int for BLE characteristic
  return (int) (HTS.readTemperature() * 100) + (int) (calibration * 100);
}

unsigned int getHumidity() {
  // Get humidity as unsigned 16-bit int for BLE characteristic
  return (unsigned int) (HTS.readHumidity() * 100);
}

void updateReadings() {
  // Read the HTS22 temperature and humidity
  int temperature = getTemperature(CALIBRATION_FACTOR);
  unsigned int humidity = getHumidity();

  if (temperature != previousTemperature) {  // If reading has changed
    Serial.print("Temperature: ");
    Serial.println(temperature);
    tempCharacteristic.writeValue(temperature);  // Update characteristic
    previousTemperature = temperature;           // Save value
  }
  
  if (humidity != previousHumidity) {
    Serial.print("Humidity: ");
    Serial.println(humidity);
    humidCharacteristic.writeValue(humidity);
    previousHumidity = humidity;
  }
}

Once the Arduino connects to the laptop it should print out the MAC address, however, there is no print out once I have connected via the BlueSee app. Additionally, my Python script that uses Serial read off of the Bluetooth port does not record any data.

In this instance I would like to set up a live stream of sensor data from the Arduino board to my laptop using BLE.

I tested your sketch with a couple of generic BLE apps. It seems to work OK. Here is the print from the Serial Monitor:

Peripheral device MAC: xx:xx:xx:xx:xx:xx
Waiting for connections...
Connected to central MAC: yy:yy:yy:yy:yy:yy
Temperature: 1948
Humidity: 8160
Temperature: 2070
Humidity: 7956
Temperature: 2072
Humidity: 7943
Temperature: 2077
Humidity: 7923
Disconnected from central MAC: yy:yy:yy:yy:yy:yy

Here are a few things I noted:

  • int data type is 32-bit on ARM processors not 16-bit, I recommend using the following naming convention uint16_t, int16_t to ensure the datatype size is what you want.
  • BLE MAC address for smart phones change randomly, do not rely on them (just FYI)
  • millis() uses unsigned long (uint32_t), I recommend to use this data type because it will work correctly when millis() overflows
  • in case you want your sketch to work without serial you should add a delay before calling HTS.begin(), 10ms is enough, there is an issue when you call it straight after power-up

Have a look at an example I posted here:

https://forum.arduino.cc/t/bluetooth-communications/902610/2

It also shows how to use some handlers instead of testing the connection in loop() and using while(). This will allow you to run other stuff in loop().

You may want to update the characteristics even if they did not change. This will cause a regular notifications and help you when you develop your central device. In any case it is unlikely the temperature stays stable within the resolution of the values. You might as well not bother testing (temperature != previousTemperature).

That will not work. There is no serial Bluetooth port associated with this sketch. You will have to connect and read the characteristics you are interested in. This sketch uses GATT which is what BLE was designed for. You may have seen some sketches that use Bluetooth Classic and the Serial Port Profile.

Thank you for all your help Klaus and for checking the sketch works for you!