Showing posts with label Bluetooth Classic. Show all posts
Showing posts with label Bluetooth Classic. Show all posts

Thursday, December 31, 2020

Bi-direction Bluetooth Classic comm. between ESP32 (Arduino framework)

Last post show my exercise of "ESP-32S as Bluetooth classic Server, bi-direction communication with Raspberry Pi/Python". Here is the ESP32 implementation for the Client side, to connect to the ESP32 server in last post.

NodeMCU ESP-32S act as a server (in last post):
It echo what received from bluetooth back to sender, and display on SPI ST7735 display.

ESP32-DevKitC-V4 as client (this post):
Connect to server, forward data from serial,  to Bluetooth. Display data from Bluetooth on I2C SSD1306 OLED display.

The code start from ESP32 example of SerialToSerialBTM. But I found that the code SerialBT.connect() always return "true", and prompt "Connected Succesfully!", no matter the device name and MAC address, even no server exist. 

To solve it, I implement my bluetooth callback function to double check if ESP_SPP_OPEN_EVT raised. I don't know is it a long time solution, anyway it work in this exercise.

SPPClient_ESP32_ssd1306_20201231b.ino
/*
 * SPP Client on ESP32
 * Display on  SSD1306
 */

#include "ssd1306.h"
#include "ssd1306_console.h"
#include "BluetoothSerial.h"

Ssd1306Console  console;

BluetoothSerial SerialBT;

String ServerMACadd = "3C:71:BF:0D:DD:6A";
uint8_t ServerMAC[6]  = {0x3C, 0x71, 0xBF, 0x0D, 0xDD, 0x6A};
String ServerName = "ESP32_SPP";
char *pin = "1234"; //<- standard pin would be provided by default
bool connected;
bool isSppOpened = false;

/*
.arduino15/packages/esp32/hardware/esp32/1.0.4/libraries/
BluetoothSerial/src/BluetoothSerial.cpp

 */

void btCallback(esp_spp_cb_event_t event, esp_spp_cb_param_t *param){
  
  switch (event)
    {
    case ESP_SPP_INIT_EVT:
        Serial.println("ESP_SPP_INIT_EVT");
        break;

    case ESP_SPP_SRV_OPEN_EVT://Server connection open
        Serial.println("ESP_SPP_SRV_OPEN_EVT");
        break;

    case ESP_SPP_CLOSE_EVT://Client connection closed
        Serial.println("ESP_SPP_CLOSE_EVT");
        isSppOpened = false;
        break;

    case ESP_SPP_CONG_EVT://connection congestion status changed
        Serial.println("ESP_SPP_CONG_EVT");
        break;

    case ESP_SPP_WRITE_EVT://write operation completed
        Serial.println("ESP_SPP_WRITE_EVT");
        break;

    case ESP_SPP_DATA_IND_EVT://connection received data
        Serial.println("ESP_SPP_DATA_IND_EVT");
        break;

    case ESP_SPP_DISCOVERY_COMP_EVT://discovery complete
        Serial.println("ESP_SPP_DISCOVERY_COMP_EVT");
        break;

    case ESP_SPP_OPEN_EVT://Client connection open
        Serial.println("ESP_SPP_OPEN_EVT");
        isSppOpened = true;
        break;

    case ESP_SPP_START_EVT://server started
        Serial.println("ESP_SPP_START_EVT");
        break;

    case ESP_SPP_CL_INIT_EVT://client initiated a connection
        Serial.println("ESP_SPP_CL_INIT_EVT");
        break;

    default:
        Serial.println("unknown event!");
        break;
    }
}

static void startupScreen()
{
    ssd1306_setFixedFont(ssd1306xled_font6x8);
    ssd1306_clearScreen();
    ssd1306_printFixed(0, 0, "arduiino-er.blogspot.com", STYLE_BOLD);
    ssd1306_printFixed(0, 24, "ESP32 SPP Client", STYLE_NORMAL);
}

void setup()
{
    Serial.begin(115200);
    Serial.println("\n------ begin ----------------\n");
    
    ssd1306_128x64_i2c_init();
    ssd1306_clearScreen();
    startupScreen();
    delay(500);

    Serial.println("- to connect -");
    ssd1306_printFixed(0, 32, "...to connect", STYLE_NORMAL);
    
    SerialBT.begin("ESP32_Client", true);
    SerialBT.register_callback(btCallback);
    //connected = SerialBT.connect(ServerName);
    connected = SerialBT.connect(ServerMAC);

    /*
     * In my trial, 
     * SerialBT.connect() always return  true, even no server exist.
     * To solve it, I implemented bluetooth event callback function,
     * double varify if ESP_SPP_OPEN_EVT raised.
     */
    
    if(connected) {
      Serial.println("SerialBT.connect() == true");
    } else {
      Serial.println("Failed to connect! Reset to re-try");
      Serial.println("SerialBT.connect() == false");
      ssd1306_printFixed(0, 32, 
          "Failed to connect! Reset to re-try", STYLE_NORMAL);
      while(true){
      }
    }

    //may be there are some delay to call callback function,
    //delay before check
    delay(500);
    if(isSppOpened == false){
      Serial.println("isSppOpened == false");
      Serial.println("Reset to re-try");
      ssd1306_printFixed(0, 32, 
          "SPP_OPEN not raised! Reset to re-try", STYLE_NORMAL);
      while(true){
      }
    }
    
    Serial.println("isSppOpened == true");
    Serial.println("CONNECTED");

    ssd1306_clearScreen();
    ssd1306_setFixedFont(ssd1306xled_font6x8);
    console.println("CONNECTED:");
}

void loop()
{
    if(!isSppOpened){
      Serial.println("isSppOpened == false : DISCONNECTED");
      Serial.println("Reset to re-connect");
      console.println("DISCONNECTED");
      console.println("Reset to re-connect");
      while(true){
      }
    }
    if (Serial.available()) {
      SerialBT.write(Serial.read());
    }
    if (SerialBT.available()) {
      char c = SerialBT.read();
      //Serial.write(c);
      console.print(c);
    }
    delay(20);
}

For the setup of SPI ST7735 IPS used on server side, refer to the post "ESP32 display with 0.96" 80x160 SPI ST7735 IPS Display, using TFT_eSPI lib".

For the setup of I2C SSD1306 OLED used on client side, refer to the post "I2C SSD1306 OLED@ESP32 (ESP32-DevKitC-V4), using SSD1306 lib".

Tuesday, December 29, 2020

ESP-32S as Bluetooth classic Server, bi-direction communication with Raspberry Pi/Python


NodeMCU ESP-32S (in Arduino framework) act as a Bluetooth classical (SPP) server:
It echo what received back to sender, and display on SPI ST7735 display.
Also implement callback function to detect esp_spp_cb_event_t.

Python code run on Raspberry Pi, act as GUI Bluetooth classic client, using tkinter/pybluez. Python code refer to: Hello Raspberry Pi - Raspberry Pi/Python as Bluetooth classic client, bi-direction communication with ESP32

Arduino code on ESP32, SPPServer_ESP32.ino.

// ref: Examples > BluetoothSerial > SerialToSerialBT
//with SPI ST735 80x160 IPS Display

#include "BluetoothSerial.h"
#include "esp_bt_device.h"
#include <TFT_eSPI.h> // TFT library
#include <SPI.h>

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

BluetoothSerial SerialBT;

TFT_eSPI tft = TFT_eSPI();

const String deviceName = "ESP32_SPP";

String getMAC(){
  const uint8_t* point = esp_bt_dev_get_address();

  String s = "";

  for (int i = 0; i < 6; i++) {
    char str[3];
    sprintf(str, "%02X", (int)point[i]);
    s = s + str;
    if (i < 5){
      s = s+ ":";
    }
  }
  return s;
}

/*
.arduino15/packages/esp32/hardware/esp32/1.0.4/libraries/
BluetoothSerial/src/BluetoothSerial.cpp

 */

void btCallback(esp_spp_cb_event_t event, esp_spp_cb_param_t *param){

  //tft.fillScreen(TFT_BLACK);
  //tft.setCursor(0, 0, 2);
  //tft.setTextSize(1);
  
  switch (event)
    {
    case ESP_SPP_INIT_EVT:
        Serial.println("ESP_SPP_INIT_EVT");
        //tft.println("ESP_SPP_INIT_EVT");
        break;

    case ESP_SPP_SRV_OPEN_EVT://Server connection open
        Serial.println("ESP_SPP_SRV_OPEN_EVT");
        //tft.println("ESP_SPP_SRV_OPEN_EVT");

        tft.fillScreen(TFT_BLACK);
        tft.setCursor(0, 0, 1);
        tft.setTextSize(1);
        break;

    case ESP_SPP_CLOSE_EVT://Client connection closed
        Serial.println("ESP_SPP_CLOSE_EVT");
        //tft.println("ESP_SPP_CLOSE_EVT");

        startUpScr();
        break;

    case ESP_SPP_CONG_EVT://connection congestion status changed
        Serial.println("ESP_SPP_CONG_EVT");
        //tft.println("ESP_SPP_CONG_EVT");
        break;

    case ESP_SPP_WRITE_EVT://write operation completed
        Serial.println("ESP_SPP_WRITE_EVT");
        //tft.println("ESP_SPP_WRITE_EVT");
        break;

    case ESP_SPP_DATA_IND_EVT://connection received data
        Serial.println("ESP_SPP_DATA_IND_EVT");
        //tft.println("ESP_SPP_DATA_IND_EVT");
        break;

    case ESP_SPP_DISCOVERY_COMP_EVT://discovery complete
        Serial.println("ESP_SPP_DISCOVERY_COMP_EVT");
        //tft.println("ESP_SPP_DISCOVERY_COMP_EVT");
        break;

    case ESP_SPP_OPEN_EVT://Client connection open
        Serial.println("ESP_SPP_OPEN_EVT");
        //tft.println("ESP_SPP_OPEN_EVT");
        break;

    case ESP_SPP_START_EVT://server started
        Serial.println("ESP_SPP_START_EVT");
        //tft.println("ESP_SPP_START_EVT");
        break;

    case ESP_SPP_CL_INIT_EVT://client initiated a connection
        Serial.println("ESP_SPP_CL_INIT_EVT");
        //tft.println("ESP_SPP_CL_INIT_EVT");
        break;

    default:
        Serial.println("unknown event!");
        //tft.println("unknown event!");
        break;
    }
}

void startUpScr(){
  tft.fillScreen(TFT_BLACK);
  tft.setCursor(0, 0, 2);
  tft.setTextSize(1);
  tft.println("arduino-er.blogspot.com");
  tft.println(deviceName);
  tft.setTextFont(1);
  tft.setTextSize(2);
  tft.println(getMAC());
}

void setup() {
  Serial.begin(115200);
  Serial.println("\n---Start---");
  SerialBT.begin(deviceName); //Bluetooth device name
  
  Serial.println("The device started, now you can pair it with bluetooth!");
  Serial.println("Device Name: " + deviceName);
  Serial.print("BT MAC: ");
  Serial.print(getMAC());
  Serial.println();
  SerialBT.register_callback(btCallback);

  tft.init();
  tft.setRotation(3);
  startUpScr();

}

void loop() {
  if (Serial.available()) {
    SerialBT.write(Serial.read());
  }
  if (SerialBT.available()) {
    char c = SerialBT.read();
    SerialBT.write(c);
    String s = String(c);
    if(tft.getCursorY() >= 80){
      tft.setCursor(0, 0);
      tft.fillScreen(TFT_BLACK);
    }
    tft.print(s);
  }
  delay(20);
}

To install TFT_eSPI library in Arduino IDE, and prepare custom setup file, refer ESP32 display with 0.96" 80x160 SPI ST7735 IPS Display, using TFT_eSPI lib.

Next:

Friday, December 25, 2020

ESP32 receive Bluetooth Classic command from Raspberry Pi/Python, to control Servos.

In my previous posts, I show simple examples of ESP32 Bluetooth Classic serial exampleServo Motor Control and I2C SSD1306 OLED. In this exercise, group three altogether run on ESP32-DevKitC-V4, receive single character command from Raspberry Pi/Python via Bluetooth Classic, control Servo Motors, and display position on 0.96" 128x64 I2C SSD1306 OLED.

Connection:

BTServoServer_20201226.ino

// BTServoServer

#include "BluetoothSerial.h"
#include "esp_bt_device.h"
#include "ssd1306.h"
#include <ESP32Servo.h>

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

BluetoothSerial SerialBT;
Servo myservoX;  // create servo objects to control a servo
Servo myservoY;
int servoPinX = 18;
int servoPinY = 19;

#define CMD_ORG 'O'
#define CMD_XDEC 'A'
#define CMD_XDEC10 'B'
#define CMD_XINC 'C'
#define CMD_XINC10 'D'
#define CMD_YDEC 'E'
#define CMD_YDEC10 'F'
#define CMD_YINC 'G'
#define CMD_YINC10 'H'

int x = 0;
int y = 0;

void printDeviceAddress() {
 
  const uint8_t* point = esp_bt_dev_get_address();
 
  for (int i = 0; i < 6; i++) {
 
    char str[3];
 
    sprintf(str, "%02X", (int)point[i]);
    Serial.print(str);
 
    if (i < 5){
      Serial.print(":");
    }
 
  }
}

void setup() {
  Serial.begin(115200);
  Serial.println("\n---Start---");
  SerialBT.begin("ESP32test"); //Bluetooth device name
  
  Serial.println("The device started, now you can pair it with bluetooth!");
  Serial.println("Device Name: ESP32test");
  Serial.print("BT MAC: ");
  printDeviceAddress();
  Serial.println();

  ssd1306_setFixedFont(ssd1306xled_font6x8);
  ssd1306_128x64_i2c_init();
  ssd1306_clearScreen();
  ssd1306_printFixed(0,  8, "BTServoServer", STYLE_BOLD);
  ssd1306_printFixed(0,  40, "arduino-er.blogspot.com", STYLE_BOLD);

  // Allow allocation of all timers
  ESP32PWM::allocateTimer(0);
  ESP32PWM::allocateTimer(1);
  ESP32PWM::allocateTimer(2);
  ESP32PWM::allocateTimer(3);
  myservoX.setPeriodHertz(50);    // standard 50 hz servo
  myservoX.attach(servoPinX, 500, 2500); // attaches the servo on pin 18 to the servo object
  myservoY.setPeriodHertz(50);    // standard 50 hz servo
  myservoY.attach(servoPinY, 500, 2500);

  myservoX.write(90);
  myservoY.write(90);
}

void loop() {
  if (SerialBT.available()) {
    char cmd = SerialBT.read();
    switch(cmd) {
      case CMD_ORG:
            x = 0;
            y = 0; 
            break;
      case CMD_XDEC:
            x--;
            break;
      case CMD_XDEC10:
            x = x-10;
            break;
      case CMD_XINC:
            x++;
            break;
      case CMD_XINC10:
            x = x+10;
            break;
      case CMD_YDEC:
            y--;
            break;
      case CMD_YDEC10:
            y = y-10;
            break;
      case CMD_YINC:
            y++;
            break;
      case CMD_YINC10:
            y = y+10;
            break;
      default:
            Serial.println("unknown command!");
            break;
    }

    if(x < -90)
      x = -90;
    if(x > 90)
      x = 90;
    if(y < -90)
      y = -90;
    if(y > 90)
      y = 90;

    String s = String(x, DEC) + " : " + String(y, DEC) + "    ";
    const char* c;
    c = s.c_str();
    Serial.println(s);
    ssd1306_printFixed(0, 25, c, STYLE_NORMAL);

    myservoX.write(x + 90);
    myservoY.write(y + 90);
    delay(200);             // wait for the servo to get there
  }
  delay(20);
}


Python code in Raspberry Pi side, refer to my another blog's post: Hello Raspberry Pi - Raspberry Pi/Python remote control ESP32/Servos via Bluetooth Classic

Next:

Saturday, December 19, 2020

ESP32 Bluetooth serial example

It's a simple example of ESP32 Bluetooth serial communication, run on ESP32-DevKitC V4.

The video show how it run, to communicate with Python/Raspberry Pi. The Python code is in my another blog: HelloRaspberryPi - Python (on Raspberry Pi) Bluetooth communicate with ESP32 SerialToSerialBT, using pybluez.

To make the ESP32 examples appear in examples list, you have to choose board of ESP32 first. It's ESP32 Wrover Module in may case.

The example available in Arduino IDE MENU > File > Examples > Bluetooth Serial (under Examples for Wrover Module) > SerialToSerialBT.


I make a little bit modification to display its Bluetooth MAC address.
// ref: Examples > BluetoothSerial > SerialToSerialBT

#include "BluetoothSerial.h"
#include "esp_bt_device.h"

#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

BluetoothSerial SerialBT;

void printDeviceAddress() {
 
  const uint8_t* point = esp_bt_dev_get_address();
 
  for (int i = 0; i < 6; i++) {
 
    char str[3];
 
    sprintf(str, "%02X", (int)point[i]);
    Serial.print(str);
 
    if (i < 5){
      Serial.print(":");
    }
 
  }
}

void setup() {
  Serial.begin(115200);
  Serial.println("\n---Start---");
  SerialBT.begin("ESP32test"); //Bluetooth device name
  
  Serial.println("The device started, now you can pair it with bluetooth!");
  Serial.println("Device Name: ESP32test");
  Serial.print("BT MAC: ");
  printDeviceAddress();
  Serial.println();
}

void loop() {
  if (Serial.available()) {
    SerialBT.write(Serial.read());
  }
  if (SerialBT.available()) {
    Serial.write(SerialBT.read());
  }
  delay(20);
}

The function printDeviceAddress() is copy from dfrobot ESP32 Arduino: Getting the Bluetooth Device Address.

Next: