Skip to content

Commit

Permalink
introduces testing device for e2e tests
Browse files Browse the repository at this point in the history
  • Loading branch information
chrvadala committed Feb 12, 2024
1 parent 6c68398 commit 5b11553
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 16 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ node_modules
.env
coverage
*.log
.pio
30 changes: 30 additions & 0 deletions ble-test-device/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Node BLE Testing device
This code allows you to flash an ESP32 device and create a BLE device that can be used for e2e testing.

Read [Testing](https://github.com/chrvadala/node-ble/blob/main/docs/documentation-testing.md) to see how to use it in a test.

## How to flash a test device

### 1. PlatformIO Setup
Install PlatformIO Core by following the instructions on the [official PlatformIO website](https://platformio.org/install/cli).
````bash
curl -fsSL -o get-platformio.py https://raw.githubusercontent.com/platformio/platformio-core-installer/master/get-platformio.py
python3 get-platformio.py
````

### 2. Build firmware and flash device
````bash
cd ble-test-device/
pio run -t upload
````

### 3. Watch logs (Optional)
````bash
pio device monitor
````
---

_References_
- https://en.wikipedia.org/wiki/ESP32
- https://github.com/arduino-libraries/ArduinoBLE

16 changes: 16 additions & 0 deletions ble-test-device/platformio.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html

[env:esp32dev]
platform = espressif32
framework = arduino
board = esp32dev
monitor_speed = 115200
lib_deps = arduino-libraries/ArduinoBLE@^1.3.6
142 changes: 142 additions & 0 deletions ble-test-device/src/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
#include <Arduino.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

#define DEVICE_NAME "EchoBLE"
#define SERVICE_UUID "12345678-1234-5678-1234-56789abcdef0"
#define CHARACTERISTIC_UUID1 "12345678-1234-5678-1234-56789abcdef1"
#define CHARACTERISTIC_UUID2 "12345678-1234-5678-1234-56789abcdef2"

BLEService *pService;
BLECharacteristic *pCharacteristic1;
BLECharacteristic *pCharacteristic2;
BLEServer *pServer;
bool deviceConnected = false;

/**
* @brief Callbacks for BLE server events.
*/
class MyServerCallbacks : public BLEServerCallbacks
{
void onConnect(BLEServer *pServer)
{
Serial.println("Client connected");
deviceConnected = true;
}

void onDisconnect(BLEServer *pServer)
{
Serial.println("Client disconnected");
// Restart advertising after disconnection
pServer->getAdvertising()->start();
deviceConnected = false;
}
};

/**
* @brief Callbacks for characteristic1 events.
*/
class MyCallbacks1 : public BLECharacteristicCallbacks
{
std::string storedValue; // Variable to store the value of characteristic1

void onWrite(BLECharacteristic *pCharacteristic)
{
std::string value = pCharacteristic->getValue();
Serial.print("Characteristic1 value written: ");
printValue(value);
storedValue = value;
}

void onRead(BLECharacteristic *pCharacteristic)
{
Serial.print("Characteristic1 value read: ");
std::string res = "ECHO>" + storedValue;
printValue(res);
pCharacteristic->setValue(res);
}

void printValue(const std::string& value)
{
for (int i = 0; i < value.length(); i++)
{
Serial.print(value[i]);
}
Serial.println();
}
};

void setupBLE()
{
BLEDevice::init(DEVICE_NAME); // Initialize BLEDevice with the device name

// Print device UUID
Serial.print("Device UUID: ");
Serial.println(BLEDevice::getAddress().toString().c_str());

pServer = BLEDevice::createServer(); // Create BLE server
pServer->setCallbacks(new MyServerCallbacks()); // Set server callbacks

pService = pServer->createService(SERVICE_UUID); // Initialize pService

pCharacteristic1 = pService->createCharacteristic(
CHARACTERISTIC_UUID1,
BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE
);
pCharacteristic1->setCallbacks(new MyCallbacks1());

pCharacteristic2 = pService->createCharacteristic(
CHARACTERISTIC_UUID2,
BLECharacteristic::PROPERTY_NOTIFY
);
pCharacteristic2->addDescriptor(new BLE2902());

pService->start(); // Start the service

BLEAdvertising *pAdvertising = pServer->getAdvertising(); // Get advertising from server
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->start(); // Start advertising from server
pAdvertising->setScanResponse(true);
pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
pAdvertising->setMinPreferred(0x12);
pServer->startAdvertising(); // Start advertising from server
}

void setup()
{
Serial.begin(115200);
Serial.println("Boot");
setupBLE();
Serial.println("Ready");
}

void loop()
{
if (deviceConnected)
{
static unsigned long lastNotifyTime = 0;
if (millis() - lastNotifyTime > 3000)
{
lastNotifyTime = millis();

// Check if notifications are enabled
BLE2902* p2902Descriptor = (BLE2902*)pCharacteristic2->getDescriptorByUUID(BLEUUID((uint16_t)0x2902));
if (p2902Descriptor->getNotifications() || p2902Descriptor->getIndications())
{
// Notifications or indications are enabled
Serial.println("Notifications or indications are enabled");

std::string notificationData = "Notification data " + std::to_string(millis());
pCharacteristic2->setValue(notificationData.c_str());
pCharacteristic2->notify();
}
else
{
// Notifications and indications are disabled
Serial.println("Notifications and indications are disabled");
}
}
}
}
12 changes: 3 additions & 9 deletions docs/documentation-testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,11 @@ npm test
## Run end to end (e2e) tests

The end to end test will try to connect to a real bluetooth device and read some characteristics. To do that, you need two different devices.
Prior to that, you need to create a test device. [A guide is available
here](https://github.com/chrvadala/node-ble/blob/main/ble-test-device).

#### Device 1
```shell script
wget https://git.kernel.org/pub/scm/bluetooth/bluez.git/plain/test/example-advertisement
wget https://git.kernel.org/pub/scm/bluetooth/bluez.git/plain/test/example-gatt-server
python example-advertisement
python example-gatt-server
hcitool dev #this command shows bluetooth address
```
After you have prepared the device, you have to connect it via bluetooth and read its MAC Address, then launch...

#### Device 2
```shell script
TEST_DEVICE=00:00:00:00:00:00 npm run test:e2e
```
18 changes: 11 additions & 7 deletions test-e2e/e2e.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ const { createBluetooth } = require('..')
const TEST_SERVICE = '12345678-1234-5678-1234-56789abcdef0' // FOR READ/WRITE TESTING
const TEST_CHARACTERISTIC = '12345678-1234-5678-1234-56789abcdef1' // FOR READ/WRITE TESTING

const TEST_NOTIFY_SERVICE = '0000180d-0000-1000-8000-00805f9b34fb' // FOR NOTIFY TESTING
const TEST_NOTIFY_CHARACTERISTIC = '00002a37-0000-1000-8000-00805f9b34fb' // FOR NOTIFY TESTING
const TEST_NOTIFY_SERVICE = '12345678-1234-5678-1234-56789abcdef0' // FOR NOTIFY TESTING
const TEST_NOTIFY_CHARACTERISTIC = '12345678-1234-5678-1234-56789abcdef2' // FOR NOTIFY TESTING

const TEST_DEVICE = getTestDevice()

Expand Down Expand Up @@ -83,11 +83,13 @@ describe('gatt e2e', () => {
})

test('read/write value', async () => {
const string = Buffer.from(`hello_world_${new Date().toISOString()}`)
const now = new Date().toISOString()
const string = Buffer.from(`hello_world_${now}`)
const expected = Buffer.from(`ECHO>hello_world_${now}`)

await characteristic.writeValue(string)
const value = await characteristic.readValue()
expect(value).toEqual(string)
expect(value).toEqual(expected)
console.log({ value: value.toString() })
})

Expand All @@ -106,14 +108,16 @@ describe('gatt e2e', () => {
})
await notifiableCharacteristic.startNotifications()

const res = new Promise(resolve => {
const res = await new Promise(resolve => {
notifiableCharacteristic.on('valuechanged', buffer => {
console.log({ notifiedBuffer: buffer })
console.log({ notifiedBuffer: buffer, string: buffer.toString() })
resolve(buffer)
})
})

await expect(res).resolves.toBeInstanceOf(Buffer)
console.log({notifiedString: res.toString()})
expect(res).toBeInstanceOf(Buffer)
expect(res.toString().startsWith("Notification data")).toBeTruthy()

await notifiableCharacteristic.stopNotifications()
})
Expand Down

0 comments on commit 5b11553

Please sign in to comment.