Showing posts with label ESP32. Show all posts
Showing posts with label ESP32. Show all posts

Wednesday, June 23, 2021

BLE Communication between Nano RP2040 Connect (Peripheral) and ESP32 (Central), in Arduino framework.

Exercise of BLE Communication between Nano RP2040 Connect (Peripheral) and ESP32 (Central), in Arduino framework.

nanoRP2040_BLE_Peripheral_20210623a.ino run on Arduino Nano RP2040 Connect, act as BLE Peripheral (server), wait to be connected.

/*
 * Arduino nano RP2040 Connect exercise:
 * as BLE Peripheral 
 * 
 * reference:
 * ArduinoBLE library-
 * https://www.arduino.cc/en/Reference/ArduinoBLE
 * 
 * In my implementation:
 * BLEByteCharacteristic written event checked by polling.
 * BLEStringCharacteristic/BLEIntCharacteristic using event haandler.
 * 
 */
 #include <ArduinoBLE.h>

/*  Visit Online GUID / UUID Generator
 *  (https://www.guidgenerator.com/)
 *  to generate your uuid
 */
const char* serviceUUID =    "20a07a95-8c12-484c-94fa-b828c4465a3c";
const char* byteCharUUID =   "d34dda3b-7b4a-4ce3-9666-a8338db4e604";
const char* stringCharUUID = "41281b9c-8dc4-4649-8cbe-c39fa01513e2";
const char* intCharUUID =    "c7d27dc6-f4d8-4523-b060-3e2e4c187808";

const char* myLocalName = "MyBLE";
 
BLEService myBLEService(serviceUUID);
BLEByteCharacteristic myBLEByteCharacteristic(byteCharUUID, 
                              BLERead|BLEWrite);
BLEStringCharacteristic myBLEStringCharacteristic(stringCharUUID, 
                              BLERead|BLEWrite|BLENotify, 24);  //max length = 10
BLEIntCharacteristic myBLEIntCharacteristic(intCharUUID,
                              BLERead|BLEWrite);


void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
  Serial.begin(115200);
  delay(100);
  digitalWrite(LED_BUILTIN, HIGH);

  //Started, connect Serial to begin
  while(!Serial);
  Serial.println("\n---Start ---");
  digitalWrite(LED_BUILTIN, LOW);

  Serial.println("Initialize BLE...");
  if(!BLE.begin()){
    Serial.println("Starting BLE failed!");
    while(1);
  }
  Serial.println("BLE initialized.");
  Serial.print("MAC: ");
  Serial.println(BLE.address());
  Serial.println("Service UUIID: \t\t\t" + String(serviceUUID));
  Serial.println("Byte Characteristic UUIID: \t" + String(byteCharUUID));
  Serial.println("String Characteristic UUIID: \t" + String(stringCharUUID));
  Serial.println("Int Characteristic UUIID: \t" + String(intCharUUID));
  
  Serial.println();

  BLE.setLocalName(myLocalName);
  BLE.setAdvertisedService(myBLEService);
  myBLEService.addCharacteristic(myBLEByteCharacteristic);
  myBLEService.addCharacteristic(myBLEStringCharacteristic);
  myBLEService.addCharacteristic(myBLEIntCharacteristic);
  BLE.addService(myBLEService);

  myBLEStringCharacteristic.setEventHandler(BLEWritten, myBLEString_Written_Hndl);
  myBLEIntCharacteristic.setEventHandler(BLEWritten, myBLEInt_Written_Hndl);

  BLE.advertise();

}

void loop() {
  BLEDevice central = BLE.central();

  if(central){
    digitalWrite(LED_BUILTIN, HIGH);
    Serial.print("Connected: ");
    Serial.println(central.address());

    while(central.connected()){

      if(myBLEByteCharacteristic.written()){
        byte valByte = myBLEByteCharacteristic.value();
        Serial.print("myBLEByteCharacteristic received: ");
        Serial.println(valByte, HEX);
      }
    }

    digitalWrite(LED_BUILTIN, LOW);
    Serial.println("Disconnected.");
  }
}

// Event Handler for myBLEStringCharacteristic Written
// Print received Sring, and write back in upper case.
void myBLEString_Written_Hndl(BLEDevice central, BLECharacteristic characteristic) {
  Serial.print("BLEStringCharacteristic event, written: ");

  Serial.println("myBLEStringCharacteristic received: len=" + 
                  String(myBLEStringCharacteristic.valueLength()));
  String valString = myBLEStringCharacteristic.value();
  Serial.println(valString);
  valString.toUpperCase();
  Serial.println(valString);
  myBLEStringCharacteristic.setValue(valString);
}

// Event Handler for myBLEIntCharacteristic Written
void myBLEInt_Written_Hndl(BLEDevice central, BLECharacteristic characteristic) {
  Serial.print("BLEIntCharacteristic event, written: ");
  
  int valInt = myBLEIntCharacteristic.value();
  Serial.println(valInt);
  
}


ESP32_BLE_Central_20210623a.ino run on ESP32 Dev. Board, act as Central (client), scan and connect to Peripheral, and send something.
/*
 * ESP32 BLE exercise, as Central (Client)
 * connect to nanoRP2040 BLE Peripheral
 * 
 */

 #include "BLEDevice.h"

const String targetName = "MyBLE";

// The remote service/characteristic we wish to connect to.
// UUID(s) have to match with Peripheral side.
const char* serviceUUID =    "20a07a95-8c12-484c-94fa-b828c4465a3c";
const char* byteCharUUID =   "d34dda3b-7b4a-4ce3-9666-a8338db4e604";
const char* stringCharUUID = "41281b9c-8dc4-4649-8cbe-c39fa01513e2";
const char* intCharUUID =    "c7d27dc6-f4d8-4523-b060-3e2e4c187808";

static BLEUUID BLEUUID_service(serviceUUID);
static BLEUUID BLEUUID_byteChar(byteCharUUID);
static BLEUUID BLEUUID_stringChar(stringCharUUID);
static BLEUUID BLEUUID_intChar(intCharUUID);

static BLERemoteCharacteristic* pRemoteChar_byte;
static BLERemoteCharacteristic* pRemoteChar_string;
static BLERemoteCharacteristic* pRemoteChar_int;

static boolean doConnect = false;
static boolean connected = false;
static boolean doScan = false;

static BLEAdvertisedDevice* myDevice;

int notifyDur;

static void notifyCallback(
  BLERemoteCharacteristic* pBLERemoteCharacteristic,
  uint8_t* pData,
  size_t length,
  bool isNotify) {
    Serial.println("pRemoteChar_string notify callback -");
    Serial.println(pBLERemoteCharacteristic->getUUID().toString().c_str());
    Serial.print(" of data length ");
    Serial.println(length);
    Serial.print("data: ");
    Serial.println((char*)pData);
}

class MyClientCallback : public BLEClientCallbacks {
  void onConnect(BLEClient* pclient) {
  }

  void onDisconnect(BLEClient* pclient) {
    connected = false;
    Serial.println("onDisconnect");
  }
};

bool connectToServer() {
    Serial.print("Forming a connection to ");
    Serial.println(myDevice->getAddress().toString().c_str());
    
    BLEClient*  pClient  = BLEDevice::createClient();
    Serial.println(" - Created client");

    pClient->setClientCallbacks(new MyClientCallback());

    // Connect to the remove BLE Server.
    pClient->connect(myDevice);
    Serial.println(" - Connected to server");

    // Obtain a reference to the service we are after in the remote BLE server.
    BLERemoteService* pRemoteService = pClient->getService(BLEUUID_service);
    if (pRemoteService == nullptr) {
      Serial.print("Failed to find our service UUID: ");
      Serial.println(BLEUUID_service.toString().c_str());
      pClient->disconnect();
      return false;
    }
    Serial.println(" - Found our service");


    // Obtain a reference to the characteristic in the service of the remote BLE server.
    pRemoteChar_byte = pRemoteService->getCharacteristic(BLEUUID_byteChar);
    pRemoteChar_string = pRemoteService->getCharacteristic(BLEUUID_stringChar);
    pRemoteChar_int = pRemoteService->getCharacteristic(BLEUUID_intChar);

    //assume all characteristics found, skip checking
    /*
    if (pRemoteChar_string == nullptr) {
      Serial.print("Failed to find our characteristic UUID: ");
      Serial.println(BLEUUID_stringChar.toString().c_str());
      pClient->disconnect();
      return false;
    }
    */
    Serial.println(" - Found our characteristic");

    // Read the value of the characteristic.
    if(pRemoteChar_string->canRead()) {
      std::string value = pRemoteChar_string->readValue();
      Serial.print("The characteristic value was: ");
      Serial.println(value.c_str());
    }

    if(pRemoteChar_string->canNotify()){
      Serial.println("pRemoteChar_string CAN Notify");
      pRemoteChar_string->registerForNotify(notifyCallback);
    }else{
      Serial.println("pRemoteChar_string CANNOT Notify");
    }

    connected = true;
    return true;
}

/**
 * Scan for BLE servers and find the first one matched advertises service
 */
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
 /**
   * Called for each advertising BLE server.
   */
  void onResult(BLEAdvertisedDevice advertisedDevice) {
    //Serial.print("BLE Advertised Device found: ");
    //Serial.println(advertisedDevice.toString().c_str());
    String devName = advertisedDevice.getName().c_str();
    //Serial.println(devName);

    if(devName == targetName){
      Serial.println("Target found-");
      // We have found a device,
      // let us now see if it contains the service we are looking for.
      Serial.println(advertisedDevice.getServiceUUID().toString().c_str());
      
      if (advertisedDevice.haveServiceUUID() && 
            advertisedDevice.isAdvertisingService(BLEUUID_service)) {
        Serial.println("BLEUUID_service match -");
        BLEDevice::getScan()->stop();
        myDevice = new BLEAdvertisedDevice(advertisedDevice);
        doConnect = true;
        doScan = true;
      } // Found our server
    }
  } // onResult
}; // MyAdvertisedDeviceCallbacks



void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("\n--- ESP32 Start ---");

  BLEDevice::init("");

  // Retrieve a Scanner and set the callback we want to use to be informed when we
  // have detected a new device.  Specify that we want active scanning and start the
  // scan to run for 5 seconds.
  BLEScan* pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setInterval(1349);
  pBLEScan->setWindow(449);
  pBLEScan->setActiveScan(true);
  pBLEScan->start(5, false);
}

// This is the Arduino main loop function.
void loop() {

  // If the flag "doConnect" is true then we have scanned for and found the desired
  // BLE Server with which we wish to connect.  Now we connect to it.  Once we are 
  // connected we set the connected flag to be true.
  if (doConnect == true) {
    if (connectToServer()) {
      Serial.println("We are now connected to the BLE Server.");
    } else {
      Serial.println("We have failed to connect to the server; there is nothin more we will do.");
    }
    doConnect = false;
  }

  // If we are connected to a peer BLE Server, update the characteristic each time we are reached
  // with the current time since boot.
  if (connected) {
    notifyDur = millis();
    String newValue = "time since boot: " + String(notifyDur/1000);
    
    // Set the characteristic's value to be the array of bytes that is actually a string.
    pRemoteChar_string->writeValue(newValue.c_str(), newValue.length());
    pRemoteChar_int->writeValue(notifyDur, true);
  }else if(doScan){
    BLEDevice::getScan()->start(0);
  }
  
  delay(1000); // Delay a second between loops.
} // End of loop




~ More exercise of Arduino Nano RP2040 Connect.

Wednesday, May 19, 2021

ESP32/Arduino BLE UART Client connect to Raspberry Pi Pico/CircuitPython + ESP32/nina-fw

It's a BLE UART Client exercise run on ESP2-DevKitC using arduino-esp32 framework. Connect to cpyPico_ESP32_BLE.py in Raspberry Pi Pico/CircuitPython + ESP32/adafruit nina-fw (act as WiFi/BLE Co-Processor).


It search BLE device with specified service UUID, and characteristics for TX and RX. Then sending something every 5 seconds. In the Pico/CircuitPython +ESP32/nina-fw server side, receive and echo back every bytes. This client then print the received byte on Terminal.

ESP32_BLE_client.ino
/*
Modify from Arduino Examples for ESP32 Dev Module:
>  ESP32 BLE Arduino > BLE_client
 */

#include "BLEDevice.h"
//#include "BLEScan.h"

#define SERVICE_UUID           "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" // RX Characteristic
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" // TX Characteristic
static BLEUUID serviceUUID(SERVICE_UUID);
static BLEUUID charUUID_RX(CHARACTERISTIC_UUID_RX);   
static BLEUUID charUUID_TX(CHARACTERISTIC_UUID_TX);  

static boolean doConnect = false;
static boolean connected = false;
static boolean doScan = false;
static BLERemoteCharacteristic* pTXCharacteristic;
static BLERemoteCharacteristic* pRXCharacteristic;
static BLEAdvertisedDevice* myDevice;

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

class MyClientCallback : public BLEClientCallbacks {
  void onConnect(BLEClient* pclient) {
  }

  void onDisconnect(BLEClient* pclient) {
    connected = false;
    Serial.println("onDisconnect");
  }
};

bool connectToServer() {
    Serial.print("Forming a connection to ");
    Serial.println(myDevice->getAddress().toString().c_str());
    
    BLEClient*  pClient  = BLEDevice::createClient();
    Serial.println(" - Created client");

    pClient->setClientCallbacks(new MyClientCallback());

    // Connect to the remove BLE Server.
    pClient->connect(myDevice);  
    // if you pass BLEAdvertisedDevice instead of address, 
    // it will be recognized type of peer device address (public or private)
    Serial.println(" - Connected to server");

    // Obtain a reference to the service we are after in the remote BLE server.
    BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
    if (pRemoteService == nullptr) {
      Serial.print("Failed to find our service UUID: ");
      Serial.println(serviceUUID.toString().c_str());
      pClient->disconnect();
      return false;
    }
    Serial.println(" - Found our service");

    // =================================================================================
    // Obtain a reference to the characteristic in the service of the remote BLE server.
    // charUUID_TX
    pTXCharacteristic = pRemoteService->getCharacteristic(charUUID_TX);
    if (pTXCharacteristic == nullptr) {
      Serial.print("Failed to find our characteristic UUID: ");
      Serial.println(charUUID_TX.toString().c_str());
      pClient->disconnect();
      return false;
    }
    Serial.println(" - Found charUUID_TX characteristic");

    // Read the value of the characteristic.
    if(pTXCharacteristic->canRead()) {
      std::string value = pTXCharacteristic->readValue();
      Serial.print("The characteristic value was: ");
      Serial.println(value.c_str());
    }

    if(pTXCharacteristic->canNotify())
      pTXCharacteristic->registerForNotify(notifyCallback);

    // =================================================================================
    // Obtain a reference to the characteristic in the service of the remote BLE server.
    // charUUID_RX
    pRXCharacteristic = pRemoteService->getCharacteristic(charUUID_RX);
    if (pRXCharacteristic == nullptr) {
      Serial.print("Failed to find our characteristic UUID: ");
      Serial.println(charUUID_RX.toString().c_str());
      pClient->disconnect();
      return false;
    }
    Serial.println(" - Found charUUID_RX characteristic");

    String helloValue = "Hello Remote Server";
    pRXCharacteristic->writeValue(helloValue.c_str(), helloValue.length());

    

    // =================================================================================
    connected = true;
    return true;
}
/**
 * Scan for BLE servers and find the first one that 
 * advertises the service we are looking for.
 */
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
 /**
   * Called for each advertising BLE server.
   */
  void onResult(BLEAdvertisedDevice advertisedDevice) {
    Serial.print("BLE Advertised Device found: ");
    Serial.println(advertisedDevice.toString().c_str());

    // We have found a device, 
    // let us now see if it contains the service we are looking for.
    if (advertisedDevice.haveServiceUUID() && 
    	advertisedDevice.isAdvertisingService(serviceUUID)) {

      BLEDevice::getScan()->stop();
      myDevice = new BLEAdvertisedDevice(advertisedDevice);
      doConnect = true;
      doScan = true;

    } // Found our server
  } // onResult
}; // MyAdvertisedDeviceCallbacks


void setup() {
  Serial.begin(115200);
  Serial.println("Starting Arduino BLE Client application...");
  BLEDevice::init("");

  // Retrieve a Scanner and set the callback we want to use to be informed when we
  // have detected a new device.  Specify that we want active scanning and start the
  // scan to run for 5 seconds.
  BLEScan* pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setInterval(1349);
  pBLEScan->setWindow(449);
  pBLEScan->setActiveScan(true);
  pBLEScan->start(5, false);
} // End of setup.


// This is the Arduino main loop function.
void loop() {

  // If the flag "doConnect" is true then we have scanned for and found the desired
  // BLE Server with which we wish to connect.  Now we connect to it.  Once we are 
  // connected we set the connected flag to be true.
  if (doConnect == true) {
    if (connectToServer()) {
      Serial.println("We are now connected to the BLE Server.");
    } else {
      Serial.println("We have failed to connect to the server; there is nothin more we will do.");
    }
    doConnect = false;
  }

  // If we are connected to a peer BLE Server, 
  // update the characteristic each time we are reached
  // with the current time since boot.
  if (connected) {
    //String newValue = "Time since boot: " + String(millis()/1000 + "\n");
    //Serial.println("Setting new characteristic value to \"" + newValue + "\"");

    String newValue = " " + String(millis()/1000);
    // Set the characteristic's value to be the array of bytes that is actually a string.
    pRXCharacteristic->writeValue(newValue.c_str(), newValue.length());
  }else if(doScan){
    BLEDevice::getScan()->start(0);  
    // this is just example to start scan after disconnect, 
    // most likely there is better way to do it in arduino
  }
  
  delay(5000); // Delay a second between loops.
} // End of loop


Thursday, April 29, 2021

ESP32-C3/Arduino (ESP32-C3-DevKitM-1) read Network Time from pool.ntp.org

It's a example from arduino-esp32, ESP32 >Time > SimpleTime, to read Network Time from pool.ntp.org.

Tested on ESP32-C3 (ESP32-C3-DevKitM-1).


Currently, to program ESP32-C3 using Arduino, Install arduino-esp32 2.0.0-alpha1 on Arduino IDE.


Wednesday, April 28, 2021

ESP32-S2/Arduino (ESP32-S2-Saola-1) web server control onboard RGB LED (NeoPixel)

With arduino-esp32 2.0.0-alpha1 installed, we can program ESP32-S2 using Arduino IDE.

This exercise run on ESP32-S2-Saola-1 (ESP32-S2), act as access point, setup web server, and turn ON/OFF onboard RGB LED (NeoPixel) according to user click.

Scroll down to have another exercise changing onboard LED color with HTML ColorPicker.

The onboard RGB LED of ESP32-S2-Saola-1 is connected to GPIO18.

Adafruit NeoPixel library is needed, can be install in Arduino IDE's Library Manager.



ESP32_WebRGB.ino

/*
 A simple web server that lets you blink the onboard RGB LED via the web.

 Run on ESP32-S2-Saola-1 (ESP32-S2),
 ast as access point, setup web server,
 and turn ON/OFF onboard RGB LED (NexPixel) accordingly.

 The onboard RGB LED of ESP32-S2-Saola-1 is connected to GPIO18.

 http://yourAddress/H turns the LED on
 http://yourAddress/L turns it off

reference examples in Arduino:
Examples > WiFi > WiFiAccessPoint
Examples > WiFi > SimpleWiFiServer
Examples > Adafruit NeoPixel > simple
 
 */
#include <Adafruit_NeoPixel.h>
#include <WiFi.h>
#include <Esp.h>

//Onboard RGB LED (NeoPixel)
#define PIXELPIN  18
#define NUMPIXELS 1

const char* ssid     = "esp32s2";
const char* password = "password";

const char* html="<html>"
      "<head>"
      "<meta charset=\"utf-8\">"
      "<title>ESP32-S2 Web control NeoPixel</title>"
      "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, maximum-scale=1\">"
      "</head>"
      "<body>"
      "Click <a href=\"/H\">here</a> to turn the RGB LED (NeoPixel) ON.<br>"
      "Click <a href=\"/L\">here</a> to turn the RGB LED (NeoPixel) OFF.<br>"
      "</body>"
      "</html>";

Adafruit_NeoPixel pixel(NUMPIXELS, PIXELPIN, NEO_GRB + NEO_KHZ800);
WiFiServer server(80);

void setup()
{
    Serial.begin(115200);
    pixel.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
    pixel.clear(); // Set pixel colors to 'off'
    pixel.show();

    delay(1);
    Serial.printf("\n\n---Start---\n");
    Serial.print("Chip Model: ");
    Serial.print(ESP.getChipModel());
    Serial.print("\nChip Revision: ");
    Serial.print(ESP.getChipRevision());
    Serial.println();
  
    Serial.println();
    Serial.println("Configuring access point...");

    WiFi.softAP(ssid, password);

    IPAddress myIP = WiFi.softAPIP();
    Serial.print("AP IP address: ");
    Serial.println(myIP);
    server.begin();
    
    Serial.println("Server started");

}

int value = 0;

void loop(){
 WiFiClient client = server.available();   // listen for incoming clients

  if (client) {                             // if you get a client,
    Serial.println("New Client.");          // print a message out the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected()) {            // loop while the client's connected
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        if (c == '\n') {                    // if the byte is a newline character

          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            client.print(html);
            // break out of the while loop:
            break;
          } else {    // if you got a newline, then clear currentLine:
            currentLine = "";
          }
        } else if (c != '\r') {  // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }

        // Check to see if the client request was "GET /H" or "GET /L":
        if (currentLine.endsWith("GET /H")) {
          Serial.println("\n--- ON ---");
          pixel.setPixelColor(0, pixel.Color(100, 100, 0));
        }
        if (currentLine.endsWith("GET /L")) {
          Serial.println("\n--- OFF ---");
          pixel.setPixelColor(0, pixel.Color(0, 0, 0));
        }

        pixel.show();
      }
    }
    // close the connection:
    client.stop();
    Serial.println("Client Disconnected.");
  }
}




ESP32-S2/Arduino (ESP32-S2-Saola-1) web control onboard NeoPixel, with HTML ColorPicker

This another exercise run on ESP32-S2-Saola-1 (ESP32-S2), act as station, connect to mobile hotspot, setup web server. User can open the web page using browsers on mobile, change LED color using HTML ColorPicker.



ESPAsyncWebServer and the AsyncTCP libraries are need.

ESP32_WebRGB_ColorPicker.ino
#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <Adafruit_NeoPixel.h>

//Onboard RGB LED (NeoPixel)
#define PIXELPIN  18
#define NUMPIXELS 1
Adafruit_NeoPixel pixel(NUMPIXELS, PIXELPIN, NEO_GRB + NEO_KHZ800);

AsyncWebServer server(80);

// ssid/password match your WiFi Network
const char* ssid = "ssid";
const char* password = "password";

const char* Param_COLOR ="color";

// HTML
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html><head>
  <title>ESP32-S2 exercise</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  </head><body>
  <p>Select Color</p>
  <form action="/get">
    <input name="color" type="color">
    <input type="submit" value="Update RGB">
  </form><br>

</body></html>)rawliteral";

void notFound(AsyncWebServerRequest *request) {
  request->send(404, "text/plain", "Not found");
}

void setup() {
  Serial.begin(115200);
  Serial.println("---Start---");
  Serial.println("Chip Model: ");
  Serial.println(ESP.getChipModel());
  Serial.println("\nChip Revision: ");
  Serial.println(ESP.getChipRevision());
  Serial.println();
  
  pixel.begin();    // INITIALIZE NeoPixel
  pixel.clear();    // Set pixel colors to 'off'
  pixel.show();

  //Act as STA, connect to WiFi network
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  if (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("WiFi Failed!");
    return;
  }
  Serial.println();
  Serial.print("Visit IP Address: ");
  Serial.println(WiFi.localIP());

  // Send HTML
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html);
  });

  // Send a GET request to <ESP_IP>/get?color=#rrggbb
  server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) {
    String color_value;

    //check if parameter "color" found
    if (request->hasParam(Param_COLOR)) {
      Serial.println("param_COLOR received");
      color_value = request->getParam(Param_COLOR)->value();
      Serial.println(color_value);

      //Convert intMessage in #rrggbb form to r,g,b
      color_value.remove(0, 1);
      int intColor = hstol(color_value);
      int r = (intColor & 0xff0000)>>16;
      int g = (intColor & 0x00ff00)>>8;
      int b = (intColor & 0x0000ff);
      Serial.println(r);
      Serial.println(g);
      Serial.println(b);

      //set NeoPixel color
      pixel.setPixelColor(0, pixel.Color(r, g, b));
      pixel.show();
    }
    
    else {
      Serial.println("No color found");
    }
    
    
    //re-send html
    request->send_P(200, "text/html", index_html);
    
  });
  server.onNotFound(notFound);
  server.begin();
}

//hex-string to long
long hstol(String recv){
  char c[recv.length() + 1];
  recv.toCharArray(c, recv.length() + 1);
  return strtol(c, NULL, 16); 
}

void loop() {
  
}


Wednesday, March 3, 2021

Install Arduino IDE 2.0 beta on Linux Mint 20.1, include ESP32/ESP8266 support.

Arduino IDE 2.0 (beta) is now available (refer to announcement in Arduino blog). It,s my first try to install Arduino IDE 2.0 beta (2.0.0-beta3) on Linux Mint 20.1, tested with VirtualBox 6.1/Windows 10.

Download Arduino IDE 2.0 beta

Visit https://www.arduino.cc/en/software, scroll download to download Arduino IDE 2.0 beta for Linux 64 bits (X86-64).

Run arduino-ide

Extract the downloaded file to a any folder you want. Run arduino-ide in Terminal
$ ./arduino-ide

Install board

In a fresh new installed Arduino IDE 2.0, no board is installed, you will be report with error:

Compilation error: Error: 2 UNKNOWN: platform not installed

Click Boards Manager on left, search to install Arduino AVR Boards by Arduino.

Add permission to user, to access USB

In a new Linux, you (as a regular user) have no permission to access USB port, and report with error:

avrdude: ser_open(): can't open device "/dev/ttyACM0": Permission denied

Open Terminal, enter the command to add permission:
$ sudo usermod -a -G dialout <username>
$ sudo chmod a+rw <port>

Done.



Install board support for ESP32/ESP8266


Menu > File> Preferences
Enter the url in the "Additional Board Manager URLs":

Then you can add board of ESP32/ESP8266 in Boards Manager.

Setup Python

By default Linux Mint 20.1 pre-install Python3, but no Python2. Currently, esptool for ESPs call python. You can create a symlinks /usr/bin/python to python3 by installing python-is-python3.

$ sudo apt install python-is-python3

Optionally, you can prevent Python 2 from being installed as a dependency of something in the future:

$ sudo apt-mark hold python2 python2-minimal python2.7 python2.7-minimal libpython2-stdlib libpython2.7-minimal libpython2.7-stdlib

And you have to install pyserial with pip:

$ sudo apt install python3-pip
$ pip3 install pyserial

Add permission to your user (if not do in above steps):

Additionally, if you cannot download your code to board caused by:
avrdude: ser_open(): can't open device "/dev/xxx": Permission denied

$ sudo usermod -a -G dialout <username>
$ sudo chmod a+rw <port>











Monday, January 25, 2021

ESP32 drive NeoPixel using Adafruit_NeoPixel library

ESP32 (ESP32-DevKitC V4) code in Arduino Framework to drive a 8X NeoPixel Ring using Adafruit_NeoPixel library simple example.

In Arduino IDE library manager, install Adafruit_NeoPixel library.


Open Example > Adafruit_NeoPixel > simple


Edit PIN on the Arduino is connected to the NeoPixels, and number of NeoPixels are attached.


 Connect NexPixel to ESP32 accordingly, verify and upload your code to run:



Note that if you assign PIN to a wrong pin, such as input only. Error message will be output to Serial:




~ more examples of ESP32-DevKitC V4

Sunday, January 24, 2021

BLE Notification example: ESP32 BLE server read analog input and notify connected device

Code run on ESP32-DevKitC V4 (Arduino framework), to act as BLE server. Once connected, it read Analog Input and notify connected device.

It's modified from last post of ESP32 BLE_notify example.

The client side is programmed using Python run on Raspberry Pi, handle the notification and plot the value graphically.


BLE_notify_AIN.ino
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

#define PinAnalogIn 36

BLEServer* pServer = NULL;
BLECharacteristic* pCharacteristic = NULL;
bool deviceConnected = false;
bool oldDeviceConnected = false;
uint32_t value = 0;

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

bool rqsNotify;
unsigned long prvMillis;
#define INTERVAL_READ 1000
int valNotify;
#define MAX_VALNOTIFY 255

int ain = 0;

class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;

      rqsNotify = false;
      prvMillis = millis();
      Serial.println("Device connected");
    };

    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
      rqsNotify = false;
      Serial.println("Device disconnected");
    }
};

void prcRead(){
  if(deviceConnected){
    unsigned long curMillis = millis();
    if((curMillis-prvMillis) >= INTERVAL_READ){
      int valAIO = analogRead(PinAnalogIn);
      valNotify = map(valAIO, 0, 4096, 0, 255);
      Serial.println(valNotify);
      
      rqsNotify = true;
      prvMillis = curMillis;
    }
  }
  
}


void setup() {
  Serial.begin(115200);

  // Create the BLE Device
  BLEDevice::init("ESP32");

  // Create the BLE Server
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // Create the BLE Service
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // Create a BLE Characteristic
  pCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID,
                      BLECharacteristic::PROPERTY_READ   |
                      BLECharacteristic::PROPERTY_WRITE  |
                      BLECharacteristic::PROPERTY_NOTIFY |
                      BLECharacteristic::PROPERTY_INDICATE
                    );

  // Create a BLE Descriptor
  pCharacteristic->addDescriptor(new BLE2902());

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

  // Start advertising
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(false);
  pAdvertising->setMinPreferred(0x0);  // set value to 0x00 to not advertise this parameter
  BLEDevice::startAdvertising();
  Serial.println("Waiting a client connection to notify...");

  
}

void loop() {
    // notify changed value
    if (deviceConnected) {
        if(rqsNotify){
          rqsNotify = false;
          //pCharacteristic->setValue((uint8_t*)valNotify, 1);
          //pCharacteristic->notify();

          value = valNotify;

          pCharacteristic->setValue((uint8_t*)&value, 4);
          pCharacteristic->notify();
          //value++;
          
        }
    }
    // disconnecting
    if (!deviceConnected && oldDeviceConnected) {
        delay(500); // give the bluetooth stack the chance to get things ready
        pServer->startAdvertising(); // restart advertising
        Serial.println("start advertising");
        oldDeviceConnected = deviceConnected;
    }
    // connecting
    if (deviceConnected && !oldDeviceConnected) {
        // do stuff here on connecting
        oldDeviceConnected = deviceConnected;
    }

    prcRead();
}


Wednesday, January 20, 2021

ESP32 BLE_notify example, handle Notification with Python/Raspberry Pi.

ESP32 BLE_notify example create a BLE server that, once we receive a connection, will send periodic notifications.

In ESP32 side, load
Examples > ESP32 BLE Arduino > BLE_notify

Tested on ESP32-DevKitC V4 in my case.

I implemented a simple Python code run on Raspberry Pi, connect to ESP32 and handle notification.

BLE_notify.ino
/*
    Video: https://www.youtube.com/watch?v=oCMOYS71NIU
    Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
    Ported to Arduino ESP32 by Evandro Copercini
    updated by chegewara

   Create a BLE server that, once we receive a connection, will send periodic notifications.
   The service advertises itself as: 4fafc201-1fb5-459e-8fcc-c5c9c331914b
   And has a characteristic of: beb5483e-36e1-4688-b7f5-ea07361b26a8

   The design of creating the BLE server is:
   1. Create a BLE Server
   2. Create a BLE Service
   3. Create a BLE Characteristic on the Service
   4. Create a BLE Descriptor on the characteristic
   5. Start the service.
   6. Start advertising.

   A connect hander associated with the server starts a background task that performs notification
   every couple of seconds.
*/
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

BLEServer* pServer = NULL;
BLECharacteristic* pCharacteristic = NULL;
bool deviceConnected = false;
bool oldDeviceConnected = false;
uint32_t value = 0;

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"


class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
    };

    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
    }
};



void setup() {
  Serial.begin(115200);

  // Create the BLE Device
  BLEDevice::init("ESP32");

  // Create the BLE Server
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // Create the BLE Service
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // Create a BLE Characteristic
  pCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID,
                      BLECharacteristic::PROPERTY_READ   |
                      BLECharacteristic::PROPERTY_WRITE  |
                      BLECharacteristic::PROPERTY_NOTIFY |
                      BLECharacteristic::PROPERTY_INDICATE
                    );

  // https://www.bluetooth.com/specifications/gatt/viewer?attributeXmlFile=org.bluetooth.descriptor.gatt.client_characteristic_configuration.xml
  // Create a BLE Descriptor
  pCharacteristic->addDescriptor(new BLE2902());

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

  // Start advertising
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(false);
  pAdvertising->setMinPreferred(0x0);  // set value to 0x00 to not advertise this parameter
  BLEDevice::startAdvertising();
  Serial.println("Waiting a client connection to notify...");
}

void loop() {
    // notify changed value
    if (deviceConnected) {
        pCharacteristic->setValue((uint8_t*)&value, 4);
        pCharacteristic->notify();
        value++;
        delay(3); // bluetooth stack will go into congestion, if too many packets are sent, in 6 hours test i was able to go as low as 3ms
    }
    // disconnecting
    if (!deviceConnected && oldDeviceConnected) {
        delay(500); // give the bluetooth stack the chance to get things ready
        pServer->startAdvertising(); // restart advertising
        Serial.println("start advertising");
        oldDeviceConnected = deviceConnected;
    }
    // connecting
    if (deviceConnected && !oldDeviceConnected) {
        // do stuff here on connecting
        oldDeviceConnected = deviceConnected;
    }
}


Next:

Sunday, January 17, 2021

BLE_server example run on ESP32 (Arduino framework), accessed by Python on Raspberry Pi/ESP32 BLE_client

BLE_server:

In Arduino Ide, Examples > ESP32 BLE Arduino > BLE_server is a simple BLE server for ESP32. This video show it run on ESP32-DevKitC V4, read the Characteristic "Hello World says Neil" using Python on Raspberry Pi.

BLE_server.ino

/*
    Based on Neil Kolban example for IDF: 
    https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleServer.cpp
    Ported to Arduino ESP32 by Evandro Copercini
    updates by chegewara
*/

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

void setup() {
  Serial.begin(115200);
  Serial.println("Starting BLE work!");

  BLEDevice::init("Long name works now");
  BLEServer *pServer = BLEDevice::createServer();
  BLEService *pService = pServer->createService(SERVICE_UUID);
  BLECharacteristic *pCharacteristic = pService->createCharacteristic(
                                         CHARACTERISTIC_UUID,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_WRITE
                                       );

  pCharacteristic->setValue("Hello World says Neil");
  pService->start();
  // BLEAdvertising *pAdvertising = pServer->getAdvertising();  
  // this still is working for backward compatibility
  BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID);
  pAdvertising->setScanResponse(true);
  pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue
  pAdvertising->setMinPreferred(0x12);
  BLEDevice::startAdvertising();
  Serial.println("Characteristic defined! Now you can read it in your phone!");
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(2000);
}


BLE_client: 

You can also program Examples > ESP32 BLE Arduino > BLE_client on another ESP32 to access the BLE_server.

After powered up, BLE_client to read and change the characteristic value.



BLE_client.ino
/**
 * A BLE client example that is rich in capabilities.
 * There is a lot new capabilities implemented.
 * author unknown
 * updated by chegewara
 */

#include "BLEDevice.h"
//#include "BLEScan.h"

// The remote service we wish to connect to.
static BLEUUID serviceUUID("4fafc201-1fb5-459e-8fcc-c5c9c331914b");
// The characteristic of the remote service we are interested in.
static BLEUUID    charUUID("beb5483e-36e1-4688-b7f5-ea07361b26a8");

static boolean doConnect = false;
static boolean connected = false;
static boolean doScan = false;
static BLERemoteCharacteristic* pRemoteCharacteristic;
static BLEAdvertisedDevice* myDevice;

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

class MyClientCallback : public BLEClientCallbacks {
  void onConnect(BLEClient* pclient) {
  }

  void onDisconnect(BLEClient* pclient) {
    connected = false;
    Serial.println("onDisconnect");
  }
};

bool connectToServer() {
    Serial.print("Forming a connection to ");
    Serial.println(myDevice->getAddress().toString().c_str());
    
    BLEClient*  pClient  = BLEDevice::createClient();
    Serial.println(" - Created client");

    pClient->setClientCallbacks(new MyClientCallback());

    // Connect to the remove BLE Server.
    pClient->connect(myDevice);  
    // if you pass BLEAdvertisedDevice instead of address, 
    // it will be recognized type of peer device address (public or private)
    Serial.println(" - Connected to server");

    // Obtain a reference to the service we are after in the remote BLE server.
    BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
    if (pRemoteService == nullptr) {
      Serial.print("Failed to find our service UUID: ");
      Serial.println(serviceUUID.toString().c_str());
      pClient->disconnect();
      return false;
    }
    Serial.println(" - Found our service");


    // Obtain a reference to the characteristic in the service of the remote BLE server.
    pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
    if (pRemoteCharacteristic == nullptr) {
      Serial.print("Failed to find our characteristic UUID: ");
      Serial.println(charUUID.toString().c_str());
      pClient->disconnect();
      return false;
    }
    Serial.println(" - Found our characteristic");

    // Read the value of the characteristic.
    if(pRemoteCharacteristic->canRead()) {
      std::string value = pRemoteCharacteristic->readValue();
      Serial.print("The characteristic value was: ");
      Serial.println(value.c_str());
    }

    if(pRemoteCharacteristic->canNotify())
      pRemoteCharacteristic->registerForNotify(notifyCallback);

    connected = true;
    return true;
}
/**
 * Scan for BLE servers and find the first one that advertises 
 * the service we are looking for.
 */
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
 /**
   * Called for each advertising BLE server.
   */
  void onResult(BLEAdvertisedDevice advertisedDevice) {
    Serial.print("BLE Advertised Device found: ");
    Serial.println(advertisedDevice.toString().c_str());

    // We have found a device,
    // let us now see if it contains the service we are looking for.
    if (advertisedDevice.haveServiceUUID() && 
			advertisedDevice.isAdvertisingService(serviceUUID)) {

      BLEDevice::getScan()->stop();
      myDevice = new BLEAdvertisedDevice(advertisedDevice);
      doConnect = true;
      doScan = true;

    } // Found our server
  } // onResult
}; // MyAdvertisedDeviceCallbacks


void setup() {
  Serial.begin(115200);
  Serial.println("Starting Arduino BLE Client application...");
  BLEDevice::init("");

  // Retrieve a Scanner and set the callback we want to use to be informed when we
  // have detected a new device.  Specify that we want active scanning and start the
  // scan to run for 5 seconds.
  BLEScan* pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setInterval(1349);
  pBLEScan->setWindow(449);
  pBLEScan->setActiveScan(true);
  pBLEScan->start(5, false);
} // End of setup.


// This is the Arduino main loop function.
void loop() {

  // If the flag "doConnect" is true then we have scanned for and found the desired
  // BLE Server with which we wish to connect.  Now we connect to it.  Once we are 
  // connected we set the connected flag to be true.
  if (doConnect == true) {
    if (connectToServer()) {
      Serial.println("We are now connected to the BLE Server.");
    } else {
      Serial.println("We have failed to connect to the server; there is nothin more we will do.");
    }
    doConnect = false;
  }

  // If we are connected to a peer BLE Server,
  // update the characteristic each time we are reached
  // with the current time since boot.
  if (connected) {
    String newValue = "Time since boot: " + String(millis()/1000);
    Serial.println("Setting new characteristic value to \"" + newValue + "\"");
    
    // Set the characteristic's value to be the array of bytes that is actually a string.
    pRemoteCharacteristic->writeValue(newValue.c_str(), newValue.length());
  }else if(doScan){
    BLEDevice::getScan()->start(0);  
    // this is just eample to start scan after disconnect, 
    // most likely there is better way to do it in arduino
  }
  
  delay(1000); // Delay a second between loops.
} // End of loop

Tuesday, January 12, 2021

ESP32 (NodeMCU-32S) capture Analog input, display on SPI ILI9341 screen in waveform, base on Timer Interrupt.

The code run on NodeMCU-32S (ESP32 in Arduino framework) capture analog input in background base on timer interrupt, display on SPI ILI9341 screen graphically.


The timer interrupt is prepared in setup(), refer to Arduino IDE Examples > ESP32 > Timer > RepeatTimer.

bfr[][] is a 2x300 double buffer to store captured analog data. When one page (300 elements) is filled in interrupt service routine, it will switch to fill the another page and set bfr_filled flag to display the filled page in main loop(). Such that the main loop have to finish display within one page filled, 300 x sampling interval.

ESP32_AIN_TmrInt_20210112b.ino
#include "SPI.h"

#include "TFT_eSPI.h"
#define TFT_GREY 0x7BEF

TFT_eSPI myGLCD = TFT_eSPI();

#define FRAME_TOPX    10
#define FRAME_TOPY    5
#define FRAME_WIDTH   300
#define FRAME_HEIGHT  200
#define FRAME_BOTTOMY FRAME_TOPY + FRAME_HEIGHT

#define LAMP_PLOTTING_X FRAME_TOPX+290
#define LAMP_PLOTTING_Y FRAME_BOTTOMY+10
#define LAMP_PLOTTING_R 5

#define NO_OF_BFR_PAGE  2
#define NO_OF_BFR_ELE   300
unsigned int bfr[NO_OF_BFR_PAGE][NO_OF_BFR_ELE];
volatile int   bfr_page;
volatile int   bfr_idx;
volatile bool  bfr_filled;
volatile int   bfr_filled_page;
volatile bool  bfr_run = false;

volatile int   updateDot = -1;
volatile unsigned long prvSamplingTime;
#define PrgressDot_X  FRAME_TOPX
#define PrgressDot_Y  FRAME_BOTTOMY+4

#define PinAnalogIn 36

unsigned long previousTime = 0;

hw_timer_t * timer = NULL;
volatile SemaphoreHandle_t timerSemaphore;

void IRAM_ATTR onTimer(){
  toFillBfr();
  // Give a semaphore that we can check in the loop
  xSemaphoreGiveFromISR(timerSemaphore, NULL);
}

void setup() {
  
  Serial.begin(115200);
  myGLCD.init();
  myGLCD.setRotation(1);
  myGLCD.fillScreen(TFT_BLACK);
  delay(500);
  myGLCD.fillRect(FRAME_TOPX-1, FRAME_TOPY-1, 
                  FRAME_WIDTH+2, FRAME_HEIGHT+2, TFT_WHITE);
  myGLCD.fillRect(FRAME_TOPX, FRAME_TOPY, 
                  FRAME_WIDTH, FRAME_HEIGHT, TFT_GREY);

  myGLCD.setTextColor(TFT_WHITE,TFT_BLACK);
  myGLCD.drawString("Double Buffer", FRAME_TOPX, FRAME_BOTTOMY+20);

  // prepare bfr
  bfr_run = false;
  bfr_filled = false;
  bfr_page = 0;
  bfr_idx = 0;
  bfr_run = true;

  // --- Prepare Timer Intrrupt ---
  // Create semaphore to inform us when the timer has fired
  timerSemaphore = xSemaphoreCreateBinary();

  // Use 1st timer of 4 (counted from zero).
  // Set 80 divider for prescaler (see ESP32 Technical Reference Manual for more
  // info).
  timer = timerBegin(0, 80, true);

  // Attach onTimer function to our timer.
  timerAttachInterrupt(timer, &onTimer, true);

  // Set alarm to call onTimer function every second (value in microseconds).
  // Repeat the alarm (third parameter)
  timerAlarmWrite(timer, 10000, true);  //10ms
  //timerAlarmWrite(timer, 1000, true);   //1ms

  // Start an alarm
  timerAlarmEnable(timer);
  prvSamplingTime = micros();
  // --- End of Prepare Timer Intrrupt ---

  Serial.println("\n --- Start ---\n");
  Serial.println("CPU Frequency (Mhz): " + String(getCpuFrequencyMhz()));
}

void handle_screen(){
  if(bfr_filled){
    //unsigned long beforeScreen = micros();
    
    bfr_filled = false;
    myGLCD.fillCircle(LAMP_PLOTTING_X, LAMP_PLOTTING_Y, LAMP_PLOTTING_R, TFT_RED);
    
    myGLCD.fillRect(FRAME_TOPX, FRAME_TOPY, 
                  FRAME_WIDTH, FRAME_HEIGHT, TFT_GREY);
    int yPrv = bfr[bfr_filled_page][0];
    for(int i=1; i<NO_OF_BFR_ELE; i++){
      int yCur = bfr[bfr_filled_page][i];
      myGLCD.drawLine(FRAME_TOPX+i-1, FRAME_BOTTOMY-yPrv, 
                      FRAME_TOPX+i, FRAME_BOTTOMY-yCur, 
                      TFT_WHITE);
      yPrv = yCur;
        
    }

    myGLCD.fillCircle(LAMP_PLOTTING_X, LAMP_PLOTTING_Y, LAMP_PLOTTING_R, TFT_GREEN);
    myGLCD.drawLine(PrgressDot_X, PrgressDot_Y, PrgressDot_X+299, PrgressDot_Y, TFT_BLACK);

    //Serial.println("Fil duration: " + String(micros()-beforeScreen) + " (microsecond)");
  }

  //to draw alblue line under the graph for indicate the sample progress
  if(int x=updateDot){
    updateDot = -1;
    myGLCD.drawPixel(PrgressDot_X+x, PrgressDot_Y, TFT_BLUE);
  }
  
}

void loop() {

  if (xSemaphoreTake(timerSemaphore, 0) == pdTRUE){
    handle_screen();
  }
}

void toFillBfr(){
  //unsigned long beforeFill = micros();

  unsigned long int curSamplingTime = micros();
  
  if(bfr_run){
    bfr[bfr_page][bfr_idx] = map(analogRead(PinAnalogIn),0, 4096, 0, 200);

    updateDot = bfr_idx;
    bfr_idx++;
    
    if(bfr_idx >= NO_OF_BFR_ELE){
      bfr_filled_page = bfr_page;
      bfr_idx=0;
      if(bfr_page==0){
        bfr_page = 1;
      }else{
        bfr_page = 0;
      }
      bfr_filled = true;
    }
  }

  //Send sampling interval to Serial Monitor for evaluation only,
  //remove it before finalize.
  Serial.println(curSamplingTime - prvSamplingTime);
  prvSamplingTime = curSamplingTime;

  //Serial.println("Fil duration: " + String(micros()-beforeFill) + " (microsecond)");
}

To setup TFT_eSPI using SPI ILI9342 for ESP32, read the post "ESP32 + 2.4" 320X240 Display (SPI ILI9341), using TFT_eSPI, prepare user setup file".


Sunday, January 10, 2021

ESP32 get time from pool.ntp.org (timeserver) display on 320x240 SPI ILI9341 Screen

Exercise run on ESP32 (NodeMCU-32S), Combine the examples of ESP32_SimpleTime and TFT_DIGITAL_CLOCK, get time from ntpServer "pool.ntp.org", and display on 2.4" 320x240 SPI ILI9341 screen in digital clock form.


ESP32_ILI9341_ntp_Clock_Digital_2021-01-10a.ino
/*
 * ESP32_ILI9341_ntp_Clock_Digital
 * 
 * Combine the examples of
 * Examples > ESP32 > Time > ESP32_SimpleTime and
 * Examples > TFT_eSPI > 320 x 240 > TFT_DIGITAL_CLOCK
 * 
 * Get time from ntpServer "pool.ntp.org",
 * display on SPI ILI9341 screen in digital clock form.
 * 
 * You have to change ssid/password to match with your wifi network.
 * and change gmtOffset_sec to match your timezone.
 =========================================================================
 Make sure all the display driver and pin comnenctions are correct by
 editting the User_Setup.h file in the TFT_eSPI library folder.
 
 #########################################################################
 ###### DON'T FORGET TO UPDATE THE User_Setup.h FILE IN THE LIBRARY ######
 #########################################################################
For using SPI ILI9341 screen on ESP32,
refer Arduino-er: ESP32 + 2.4" 320X240 Display (SPI ILI9341), 
using TFT_eSPI, prepare user setup file.
http://arduino-er.blogspot.com/2021/01/esp32-24-320x240-display-spi-ili9341.html

A few colour codes:

code	color
0x0000	Black
0xFFFF	White
0xBDF7	Light Gray
0x7BEF	Dark Gray
0xF800	Red
0xFFE0	Yellow
0xFBE0	Orange
0x79E0	Brown
0x7E0	Green
0x7FF	Cyan
0x1F	Blue
0xF81F	Pink

 */

#include <TFT_eSPI.h> // Hardware-specific library
#include <SPI.h>
#include <WiFi.h>
#include "time.h"


const char* ssid       = "ssid";
const char* password   = "password";

const char* ntpServer = "pool.ntp.org";
//+8 hr@HongKong
//8 * 60 * 60 = 28800
const long  gmtOffset_sec = 28800; //-8hr@Hong Kong
const int   daylightOffset_sec = 3600;

#define TFT_GREY 0x5AEB

TFT_eSPI tft = TFT_eSPI();       // Invoke custom library

uint32_t targetTime = 0;                    // for next 1 second timeout


/* The original example get H, M, S from compile time
static uint8_t conv2d(const char* p); // Forward declaration needed for IDE 1.6.x

uint8_t hh = conv2d(__TIME__), mm = conv2d(__TIME__ + 3), 
        ss = conv2d(__TIME__ + 6); // Get H, M, S from compile time
*/

/*
 *  Get H,M, S after ntp server connected, 
 *  will load in printLocalTime()
 */
uint8_t hh,mm,ss;


byte omm = 99, oss = 99;
byte xcolon = 0, xsecs = 0;
unsigned int colour = 0;

void printLocalTime()
{
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    Serial.println("Failed to obtain time");
    return;
  }
  Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");

  /* to read elements from getLocalTime(&timeinfo)
   * ref:
   * http://www.cplusplus.com/reference/ctime/tm/
   */
  int time_yday = timeinfo.tm_yday; //days since January 1
  int time_wday = timeinfo.tm_wday; //days since Sunday
  int time_year = timeinfo.tm_year; // years since 1900
  int time_mon  = timeinfo.tm_mon;   //months since January
  int time_mday = timeinfo.tm_mday; //day of the month
  int time_hr   = timeinfo.tm_hour;
  int time_min  = timeinfo.tm_min;
  int time_sec  = timeinfo.tm_sec;
  Serial.println("tm_yday: " + String(time_yday));
  Serial.println("tm_wday: " + String(time_wday));
  Serial.println("tm_year: " + String(time_year));
  Serial.println("tm_mon:  " + String(time_mon));
  Serial.println("tm_mday: " + String(time_mday));
  Serial.println("tm_hr:   " + String(time_hr));
  Serial.println("tm_min:  " + String(time_min));
  Serial.println("tm_sec:  " + String(time_sec)); 
  hh = time_hr;
  mm = time_min;
  ss = time_sec;
}

void setup(void) {
  Serial.begin(115200);
  /*
   * Connect to WiFi, and get time from ntpServer
   * To simplify, only once when power-up.
   */
  //connect to WiFi
  Serial.printf("Connecting to %s ", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
  }
  Serial.println(" CONNECTED");
  
  //init and get the time
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  printLocalTime();

  //disconnect WiFi as it's no longer needed
  WiFi.disconnect(true);
  WiFi.mode(WIFI_OFF);
  
  /*
   * Prepare for TFT
   */
  tft.init();
  tft.setRotation(1);
  tft.fillScreen(TFT_BLACK);

  tft.setTextSize(1);
  tft.setTextColor(TFT_YELLOW, TFT_BLACK);

  targetTime = millis() + 1000;
}

void loop() {
  if (targetTime < millis()) {
    // Set next update for 1 second later
    targetTime = millis() + 1000;

    // Adjust the time values by adding 1 second
    ss++;              // Advance second
    if (ss == 60) {    // Check for roll-over
      ss = 0;          // Reset seconds to zero
      omm = mm;        // Save last minute time for display update
      mm++;            // Advance minute
      if (mm > 59) {   // Check for roll-over
        mm = 0;
        hh++;          // Advance hour
        if (hh > 23) { // Check for 24hr roll-over (could roll-over on 13)
          hh = 0;      // 0 for 24 hour clock, set to 1 for 12 hour clock
        }
      }
    }


    // Update digital time
    int xpos = 0;
    int ypos = 85; // Top left corner ot clock text, about half way down
    int ysecs = ypos + 24;

    if (omm != mm) { // Redraw hours and minutes time every minute
      omm = mm;
      // Draw hours and minutes
      if (hh < 10) xpos += tft.drawChar('0', xpos, ypos, 8); // Add hours leading zero for 24 hr clock
      xpos += tft.drawNumber(hh, xpos, ypos, 8);             // Draw hours
      xcolon = xpos; // Save colon coord for later to flash on/off later
      xpos += tft.drawChar(':', xpos, ypos - 8, 8);
      if (mm < 10) xpos += tft.drawChar('0', xpos, ypos, 8); // Add minutes leading zero
      xpos += tft.drawNumber(mm, xpos, ypos, 8);             // Draw minutes
      xsecs = xpos; // Sae seconds 'x' position for later display updates
    }
    if (oss != ss) { // Redraw seconds time every second
      oss = ss;
      xpos = xsecs;

      if (ss % 2) { // Flash the colons on/off
        tft.setTextColor(0x39C4, TFT_BLACK);        // Set colour to grey to dim colon
        tft.drawChar(':', xcolon, ypos - 8, 8);     // Hour:minute colon
        xpos += tft.drawChar(':', xsecs, ysecs, 6); // Seconds colon
        tft.setTextColor(TFT_YELLOW, TFT_BLACK);    // Set colour back to yellow
      }
      else {
        tft.drawChar(':', xcolon, ypos - 8, 8);     // Hour:minute colon
        xpos += tft.drawChar(':', xsecs, ysecs, 6); // Seconds colon
      }

      //Draw seconds
      if (ss < 10) xpos += tft.drawChar('0', xpos, ysecs, 6); // Add leading zero
      tft.drawNumber(ss, xpos, ysecs, 6);                     // Draw seconds
    }
  }
}

/*
// Function to extract numbers from compile time string
static uint8_t conv2d(const char* p) {
  uint8_t v = 0;
  if ('0' <= *p && *p <= '9')
    v = *p - '0';
  return 10 * v + *++p - '0';
}
*/


Thursday, January 7, 2021

ESP32 (Arduino) ADC (Analog to Digital Converter), analogRead() and plot on 2.4" 320X240 Display (SPI ILI9341).

Example run on NodeMCU-32S, analogRead() from GPIO36, and plot on 2.4" 320X240 Display (SPI ILI9341).

To setup of the display, refer last post "ESP32 + 2.4" 320X240 Display (SPI ILI9341), using TFT_eSPI, prepare user setup file".


ESP32_ILI9341_AIN_20210108a.ino
/*
 * ESP32 + SPI ILI9341
 * Read Analog In and
 * plot on 2.4" 320x240 SPI ILI9341 screen
 */

#include "SPI.h"
#include "TFT_eSPI.h"

#define TFT_GREY 0x7BEF

TFT_eSPI myGLCD = TFT_eSPI();

#define FRAME_TOPX    10
#define FRAME_TOPY    5
#define FRAME_WIDTH   300
#define FRAME_HEIGHT  200
#define FRAME_BOTTOMY FRAME_TOPY + FRAME_HEIGHT

#define PinAnalogIn 36
int idx = 0;
#define IDX_MAX     300

void setup(){
  Serial.begin(115200);
  myGLCD.init();
  myGLCD.setRotation(1);
  myGLCD.fillScreen(TFT_BLACK);
  delay(500);
  myGLCD.fillRect(FRAME_TOPX-1, FRAME_TOPY-1, 
                  FRAME_WIDTH+2, FRAME_HEIGHT+2, TFT_WHITE);
  myGLCD.fillRect(FRAME_TOPX, FRAME_TOPY, 
                  FRAME_WIDTH, FRAME_HEIGHT, TFT_GREY);

  myGLCD.setTextColor(TFT_WHITE,TFT_BLACK);
  myGLCD.drawString("ESP32 (Arduino framework) + SPI ILI9341", 
                  FRAME_TOPX, FRAME_BOTTOMY+10);
  myGLCD.drawString("ADC exercise", FRAME_TOPX, FRAME_BOTTOMY+20);

  Serial.println("\n --- Start ---\n");
}

void loop(){
  int val = analogRead(PinAnalogIn);
  int AnalogInVal = map(val, 0, 4096, 0, 200);

  Serial.print(val);
  Serial.print(" : ");
  Serial.println(AnalogInVal);
  
  myGLCD.drawLine(
      FRAME_TOPX+idx, FRAME_BOTTOMY, 
      FRAME_TOPX+idx, FRAME_BOTTOMY-AnalogInVal, 
      TFT_WHITE);
  
  //Serial.println(hall);
  delay(100);
  
  idx++;
  if(idx >= IDX_MAX){
    idx = 0;
    myGLCD.fillRect(FRAME_TOPX, FRAME_TOPY, 
                    FRAME_WIDTH, FRAME_HEIGHT, TFT_GREY);
  }

}

Next:

Tuesday, January 5, 2021

ESP32 + 2.4" 320X240 Display (SPI ILI9341), using TFT_eSPI, prepare user setup file.

Install TFT_eSPI library in Arduino IDE Library Manager.

Reading the TFT_eSPI GitHub page, if you update TFT_eSPI then it will over-write your setups if they are kept within the TFT_eSPI folder. It's suggested to create a new folder in your Arduino library folder called "TFT_eSPI_Setups". You then place your custom setup.h files in there. After an upgrade simply edit the User_Setup_Select.h file to point to your custom setup file.

Here is how to prepare my custom setup file for using SPI ILI9341 on ESP32 (NodeMCU-32S).

- Create a new folder in your Arduino library folder called "TFT_eSPI_Setups"

- Copy default User_Setup.h (checked it match with using SPI ILI9341) to "TFT_eSPI_Setups" folder, rename it if you want.


- Edit the User_Setup_Select.h file to point to the custom setup file.


- Edit the custom user setup file:

ILI9341_DRIVER is selected by default, keep it no change.


Comment and un-comment the pin assignment code as shown:

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:

Sunday, December 27, 2020

ESP32 display with 0.96" 80x160 SPI ST7735 IPS Display, using TFT_eSPI lib

Steps to install TFT_eSPI library in Arduino IDE, and prepare custom setup file. To make ESP32 (in Arduino framework) display on 0.96" 80x160 IPS Display with ST7735 SPI Driver.


ESP32 board used is NodeMCU ESP-32S with ESP32-WROOM-32 module:



0.96" 80x160 IPS Display with ST7735 SPI Driver:



Install TFT_eSPI:

In Arduino IDE, install TFT_eSPI library.

From the TFT_eSPI GitHub page, we know that if you load a new copy of TFT_eSPI then it will over-write your setups if they are kept within the TFT_eSPI folder. It's suggested to create a new folder in your Arduino library folder called "TFT_eSPI_Setups". You then place your custom setup.h files in there. After an upgrade simply edit the User_Setup_Select.h file to point to your custom setup file.


Copy the selected setup file to "TFT_eSPI_Setups" folder:


You custom setup file. No need to change in our case. Just connect ESP32 board to ST7735 display board match with the your custom setup file.


Edit the User_Setup_Select.h file to point to the custom setup file.


Then you can load examples of TFT_eSPI to see the result.

Next:


Updated@2021-01-06, after library updated.

You see, TFT_eSPI/User_Setup_Select.h changed back to original.


TFT_eSPI_Setups/Setup43_ST7735_ESP32_80x160.h still here.


You simply needed to edit the User_Setup_Select.h file to point to your custom setup file.