MarkDH102
Posts: 360
Joined: Fri Feb 13, 2015 3:18 pm

How can I make a Pi0W into a bluetooth server using python?

Tue Oct 15, 2019 6:26 pm

I have an ESP32 on which I am running the Arduino example Bluetooth sniffer code (in C via Arduino IDE). I presume this is the "client". The ESP32 is BLE.
I want to run python code on my Pi0W (Stretch) to turn it into a simple Bluetooth server (I hope that I have the terminology correct).
I'm just tinkering to see if the ESP32 can see the Pi0W and if I can make my own GATT message structures.
Can anyone point me at some suitable python code that will do what I want (or give me a starting push) please?
Cheers.
I already run code (based on someone else's hard work) on a Pi0W that talks to my WiiFit board (which I just about understand) and wonder if I can modify that in some way?

PhatFil
Posts: 1439
Joined: Thu Apr 13, 2017 3:55 pm
Location: Oxford UK

Re: How can I make a Pi0W into a bluetooth server using python?

Tue Oct 15, 2019 6:37 pm

the ble model isnt the traditional client server arrangement.

http://www.raspberry-pi-geek.com/Archiv ... (offset)/1

Is a pretty good walk through and intro to the subject, and get you on the way to creating a ble device that advertises its presence and type ..

edit personally i would use the esp to create the low power ble device to advertise and offer data and use the pi to host a system to query record and perhaps analyse the data for presentation..

MarkDH102
Posts: 360
Joined: Fri Feb 13, 2015 3:18 pm

Re: How can I make a Pi0W into a bluetooth server using python?

Tue Oct 15, 2019 6:42 pm

Many thanks. I will take a look in the morning when I'm more awake...

User avatar
Douglas6
Posts: 4783
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: How can I make a Pi0W into a bluetooth server using python?

Tue Oct 15, 2019 6:55 pm

Here's some Python code I adapted from the BlueZ sample code that implements a GATT server: https://github.com/Douglas6/cputemp

MarkDH102
Posts: 360
Joined: Fri Feb 13, 2015 3:18 pm

Re: How can I make a Pi0W into a bluetooth server using python?

Wed Oct 16, 2019 6:14 am

Hi Douglas6

Thanks for the link. I've downloaded and will be playing shortly. I like a well documented GitHub repository. Many thanks.

MarkDH102
Posts: 360
Joined: Fri Feb 13, 2015 3:18 pm

Re: How can I make a Pi0W into a bluetooth server using python?

Thu Oct 17, 2019 6:23 am

Hi Douglas6

It does exactly what I want. Thanks. It works as advertised on the app you suggested for the Android phone and I see it as a device on my ESP32.
Now I've got to work out why I can't see the services on my ESP32, but that's my problem now...

Regards Mark

User avatar
Douglas6
Posts: 4783
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: How can I make a Pi0W into a bluetooth server using python?

Fri Oct 18, 2019 12:58 am

MarkDH102 wrote:
Thu Oct 17, 2019 6:23 am
Now I've got to work out why I can't see the services on my ESP32, but that's my problem now...
Note that some devices include their services in the advertising data. CPUtemp does not. So you will need to connect to get a list of services.

MarkDH102
Posts: 360
Joined: Fri Feb 13, 2015 3:18 pm

Re: How can I make a Pi0W into a bluetooth server using python?

Sat Oct 19, 2019 6:24 am

HI Douglas6

I have got it working now and will post the 'C' code that works on an ESP32 when I have tidied it up so that other people may make use of it.
Thanks for the advice about connecting. That is the conclusion that I had arrived at.
I can't profess to fully understand what is going on in the Python code on the Pi as 'C' is my speciality, but I'm going to try to modify it to include some of the 'standard' GATT messages. I will try with 180A (2A24, 2A26 etc) first to put in some manufacturer info.
Also, one thing puzzles me. My Pi 'device' does not report a name via Bluetooth. It's network name is 'oddjob' which I would have thought would filter down to the Bluetooth stack somehow?

Best regards Mark

User avatar
Douglas6
Posts: 4783
Joined: Sat Mar 16, 2013 5:34 am
Location: Chicago, IL

Re: How can I make a Pi0W into a bluetooth server using python?

Sat Oct 19, 2019 1:43 pm

For classic Bluetooth, yes the 'Bluetooth name' defaults to the machine name. For BLE, my Pi is identified by the local name I assigned to the advertising data, 'Thermometer'. At least, that is how nRF Connect identifies it.

MarkDH102
Posts: 360
Joined: Fri Feb 13, 2015 3:18 pm

Re: How can I make a Pi0W into a bluetooth server using python?

Mon Oct 21, 2019 7:29 am

'C' code (Arduino) for my ESP32 (A Heltec Kit32 with OLED) - as promised. A bit rough and ready but it works with the Pi code that Douglas6 posted.

Code: Select all

/*
 * Program to operate ESP32 in client mode and get served information from a Raspberry Pi
 * Program by: Mark Hollingworth
 * The code for the Raspberry Pi can be found here : 
 * https://www.raspberrypi.org/forums/viewtopic.php?f=62&t=254431
 * Dated: 18-10-2019
 * NOTE: The MY_RASPBERRY_PI_ADDRESS is specific to my Raspberry Pi and will need to be changed in the onResult() function
 * NOTE: There is a bug in the BLE characteristic library found here in a Win10 installation of the Arduino code :
 * C:\Users\YOURNAME\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.2\libraries\BLE\src\BLEremotecharacteristic.cpp
 * Search the following (at line 33 in my file) and add ": m_rawData(nullptr)"
 * BLERemoteCharacteristic::BLERemoteCharacteristic(
 *   uint16_t             handle,
 *   BLEUUID              uuid,
 *   esp_gatt_char_prop_t charProp,
 *   BLERemoteService*    pRemoteService) : m_rawData(nullptr) {
 */
#define MAX_DEVICES 5

#include <BLEDevice.h> 

//Service UUID of Pi temperature
static BLEUUID  serviceUUID("00000001-710e-4a5b-8d75-3e5b444bc3cf"); 
//Characteristic  UUID of Pi temperature R
static BLEUUID    char2UUID("00000002-710e-4a5b-8d75-3e5b444bc3cf");
//Characteristic  UUID of Pi temperature unit R/W 'C' or 'F'
static BLEUUID    char3UUID("00000003-710e-4a5b-8d75-3e5b444bc3cf");
 
static  BLERemoteCharacteristic*  _pRemoteCharacteristic;
        BLEScan*                  _pBLEScan;
static  BLEAddress*               _pServer_BLE_Address[MAX_DEVICES];
        String                    _strScanned_BLE_Address;
        boolean                   _blnPaired;
        int                       _intDeviceCount;
        int                       _intPairedDeviceIndex;

static void notifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic,uint8_t* pData,size_t length,bool isNotify) 
{
  Serial.print("Notify callback for characteristic : ");
  #ifdef DEBUG_SERIAL
  Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str());
  Serial.print(" of data length ");
  Serial.println(length);
  Serial.print("data: ");
  #endif
  Serial.println((char*)pData);
}


bool connectToserver (BLEAddress pAddress)
{
    BLEClient*  pClient  = BLEDevice::createClient();
    Serial.println("Created client");
    // Connect to the BLE Server.
    pClient->connect(pAddress);
    Serial.println("Connected to Pi");
    // Obtain a reference to the service we are after in the remote BLE server.
    BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
    if (pRemoteService != nullptr)
    {
      Serial.println("Found our TEMPERATURE service");

      // Obtain a reference to the temperature unit characteristic in the service of the remote BLE server.
      _pRemoteCharacteristic = pRemoteService->getCharacteristic(char3UUID);
      if (_pRemoteCharacteristic != nullptr)
      {
        Serial.print("Found characteristic TEMPERATURE UNIT :");
        if (_pRemoteCharacteristic->canRead())
        {
          Serial.print(" read (");
          Serial.print(_pRemoteCharacteristic->readValue().c_str());
          Serial.print(")");
        }
        if (_pRemoteCharacteristic->canWrite())
        {
          Serial.print(" write");
          // So change it from the default F to C
          _pRemoteCharacteristic->writeValue('C', false);
          Serial.print(" (change it to 'C') ");
        }
        if (_pRemoteCharacteristic->canNotify())
        {
          Serial.print(" notify");
          _pRemoteCharacteristic->registerForNotify(notifyCallback);
        }
        Serial.println("");
      }

      // Obtain a reference to the temperature characteristic in the service of the remote BLE server.
      _pRemoteCharacteristic = pRemoteService->getCharacteristic(char2UUID);
      if (_pRemoteCharacteristic != nullptr)
      {
        Serial.print("Found characteristic TEMPERATURE :");
        if (_pRemoteCharacteristic->canRead())
        {
          Serial.print(" read (");
          Serial.print(_pRemoteCharacteristic->readValue().c_str());
          Serial.print(")");
        }
        if (_pRemoteCharacteristic->canWrite())
        {
          Serial.print(" write");
        }
        if (_pRemoteCharacteristic->canNotify())
        {
          Serial.print(" notify");
          _pRemoteCharacteristic->registerForNotify(notifyCallback);
        }
        Serial.println("");
      }
            
      return true;
    }

    return false;
}


class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks 
{
    void onResult(BLEAdvertisedDevice advertisedDevice) 
    {
      // NOTE change this for YOUR Raspberry Pi
      const String MY_RASPBERRY_PI_ADDRESS = "b8:27:eb:cf:ca:ad";
      
      if (_blnPaired == false)
      {
        Serial.printf("Scan Result: %s \n", advertisedDevice.toString().c_str());
        _pServer_BLE_Address[_intDeviceCount] = new BLEAddress(advertisedDevice.getAddress());
        _strScanned_BLE_Address = _pServer_BLE_Address[_intDeviceCount]->toString().c_str();
    		if (_strScanned_BLE_Address == MY_RASPBERRY_PI_ADDRESS)
    		{
    		  _intPairedDeviceIndex = _intDeviceCount;
    		}
    		_intDeviceCount++;
    		if (_intDeviceCount == MAX_DEVICES)
    		{
    		  _intDeviceCount--;
    		  Serial.println("Maximum number of devices found");
    		}
      }
    }
};


void setup() 
{
  _blnPaired = false;
  _intDeviceCount = 0;
  _intPairedDeviceIndex = -1;

  Serial.begin(115200); 
  Serial.println("ESP32 BLE Server program (for Raspberry Pi)");

  BLEDevice::init("");
  _pBLEScan = BLEDevice::getScan();
  _pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  _pBLEScan->setActiveScan(true); 
}


void loop() 
{
  BLEScanResults  foundDevices;
  
  foundDevices = _pBLEScan->start(5);
  
  while (foundDevices.getCount() >= 1)
  {
    if (_intPairedDeviceIndex != -1 && _blnPaired == false)
    {
      Serial.println("Found DEVICE...connecting to Server as Client");
      if (connectToserver(*_pServer_BLE_Address[_intPairedDeviceIndex]))
      {
        _blnPaired = true;
        break;
      }
      else
      {
        Serial.println("Pairing failed");
        break;
      }
    }
  } 
}

Return to “Off topic discussion”