I want my UART Bluetooth client program to read the value of a characteristic from its Bluetooth server, and if the value is A then turn a green LED on and a red LED off, and if the value is Z to turn the green LED off and the red LED on.
Every time I try to read the value and make a comparison I get an invalid conversion error. The code for the client program, and the error message I get, are given below. At the bottom I also included the code for my server program in case it helps.
Most of my code comes from the UART Server and Client examples for the ESP32C3. I commented out a lot of extra stuff. I apologize if it's still hard to read. I'm a newb when it comes to Bluetooth!
Here's my setup:
I have 2 ESP32C3s. The first is running "Server_for_ESP32C3." It has a green button hooked up to pin 8, and a red button hooked up to pin 20. It also has 3 LEDs: green, red & white (hooked to pins 3,5 & 7 respectively).
The server is working just fine.
The second ESP32C3 is where I'm having the compile error. It should be running "Client_for_UART_ESP32C3." (For the record, it has a button connected to pin 8, a green LED on pin 3, and a red LED on pin 5, but I don't think these connections are part of the problem.)
Client_for_UART_ESP32C3.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"
const uint8_t sendButton = 8;
int sendButtonState = 0;
int hasSentA = 0;
uint8_t greenLED = 3;
uint8_t redLED = 5;
uint8_t greenLEDState = 0;
uint8_t redLEDState = 0;
//uint8_t serverCommand;
//uint8_t str[1];
//char blahBlah;
// The remote service we wish to connect to.
static BLEUUID serviceUUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E");
// The characteristic of the remote service we are interested in.
static BLEUUID charUUID("6E400003-B5A3-F393-E0A9-E50E24DCCA9E");
// The RX Characteristic of the remote service.
static BLEUUID rxUUID("6E400002-B5A3-F393-E0A9-E50E24DCCA9E");
static boolean doConnect = false;
static boolean connected = false;
static boolean doScan = false;
static BLERemoteCharacteristic *pRemoteCharacteristic;
static BLERemoteCharacteristic *pRemoteRxCharacteristic;
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.write(pData, length);
//Serial.println();
}
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 remote 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");
pClient->setMTU(517); //set client to request maximum MTU from server (default is 23 otherwise)
// 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");
pRemoteRxCharacteristic = pRemoteService->getCharacteristic(rxUUID);
if (pRemoteRxCharacteristic == nullptr){
Serial.println("Failed to get Rx Characteristic");
return false;
} else{
//Serial.println("Got Rx Characteristic");
}
// Read the value of the characteristic.
/*-------------Here pRemoteCharacteristic->readValue() works fine. ----------------------*/
/*-------------pRemoteCharacteristic->canRead() returns false for some reason, but when I comment out that part of the code, the readValue() command doesn't give an error. */
//if (pRemoteCharacteristic->canRead()) {
String value = pRemoteCharacteristic->readValue();
Serial.print("The characteristic value was: ");
Serial.println(value.c_str());
//memcpy(blahBlah,pRemoteCharacteristic->readValue(),sizeof(blahBlah));
//}
if (pRemoteCharacteristic->canNotify()) {
pRemoteCharacteristic->registerForNotify(notifyCallback);
Serial.println("Registered for Callbacks.");
}
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(9600);
pinMode(sendButton, INPUT);
pinMode(greenLED, OUTPUT);
pinMode(redLED, OUTPUT);
digitalWrite(greenLED, LOW);
digitalWrite(redLED, LOW);
Serial.println("Initializing Server Connection");
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.");
//digitalWrite(greenLED, HIGH);
} else {
//Serial.println("We have failed to connect to the server; there is nothing 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());
/*============This is where I'm having trouble. I want the program to read the value of the remote characteristic,
If that value is A, turn the green LED on and the red LED off.
If that value is Z, turn the green LED off and the red LED on.
*/
String txValue = pRemoteCharacteristic->readValue();
if(txValue == 'A')
{
digitalWrite(greenLED, HIGH);
digitalWrite(redLED, LOW);
}
else if (txValue == 'Z'){
digitalWrite(greenLED,LOW);
digitalWrite(redLED,HIGH);
}
} 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
}
/*
if (connected) {
sendButtonState = digitalRead(sendButton);
if (sendButtonState == HIGH){
digitalWrite(greenLED, HIGH);
digitalWrite(redLED, HIGH);
if(hasSentA == 0){
pRemoteRxCharacteristic->writeValue('A',sizeof('A'));
}
}
}
*/
//Serial.println(Client->connected());
//Serial.println
delay(1000); // Delay a second between loops.
} // End of loop
C:\Users\BFreese_Laptop\Documents\Arduino\Client_for_UART_ESP32C3_ForPosting\Client_for_UART_ESP32C3_ForPosting.ino: In function 'void loop()':
C:\Users\BFreese_Laptop\Documents\Arduino\Client_for_UART_ESP32C3_ForPosting\Client_for_UART_ESP32C3_ForPosting.ino:197:19: error: invalid conversion from 'char' to 'const char*' [-fpermissive]
197 | if(txValue == 'A')
| ^~~
| |
| char
In file included from C:\Users\BFreese_Laptop\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.1.3\cores\esp32/Arduino.h:195,
from C:\Users\BFreese_Laptop\AppData\Local\arduino\sketches\C5E3DF050B18498A1EA29D6A94375477\sketch\Client_for_UART_ESP32C3_ForPosting.ino.cpp:1:
C:\Users\BFreese_Laptop\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.1.3\cores\esp32/WString.h:214:31: note: initializing argument 1 of 'bool String::operator==(const char*) const'
214 | bool operator==(const char *cstr) const {
| ~~~~~~~~~~~~^~~~
C:\Users\BFreese_Laptop\Documents\Arduino\Client_for_UART_ESP32C3_ForPosting\Client_for_UART_ESP32C3_ForPosting.ino:202:25: error: invalid conversion from 'char' to 'const char*' [-fpermissive]
202 | else if (txValue == 'Z'){
| ^~~
| |
| char
C:\Users\BFreese_Laptop\AppData\Local\Arduino15\packages\esp32\hardware\esp32\3.1.3\cores\esp32/WString.h:214:31: note: initializing argument 1 of 'bool String::operator==(const char*) const'
214 | bool operator==(const char *cstr) const {
| ~~~~~~~~~~~~^~~~
exit status 1
Compilation error: invalid conversion from 'char' to 'const char*' [-fpermissive]
Server_for_ESP32C3.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
Create a BLE server that, once we receive a connection, will send periodic notifications.
The service advertises itself as: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E
Has a characteristic of: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E - used for receiving data with "WRITE"
Has a characteristic of: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E - used to send data with "NOTIFY"
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.
In this example rxValue is the data received (only accessible inside that function).
And txValue is the data to be sent.
*/
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
BLEServer *pServer = NULL;
BLECharacteristic * pTxCharacteristic;
bool deviceConnected = false;
bool oldDeviceConnected = false;
uint8_t txValue = 0;
//int txValue = 0;
int incomingByte = 0;
// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
// Pin numbers for Green and Red buttons
/* Originally these started with "const int" but I have a vague memory of that not working with bluetooth for some reason. So I'm going with what I remember working here. */
uint8_t greenButtonPin = 8;
uint8_t redButtonPin = 20;
// Pin numbers for Green and Red LEDs
uint8_t greenLED = 3;
uint8_t redLED = 5;
uint8_t whiteLED = 7;
/* Variables to use when pressing button turns LED on, pressing again turns LED off. */
uint8_t greenLEDState = LOW;
uint8_t greenButtonState = 0;
uint8_t greenButtonStateLAST = LOW;
/* Variables to use for red button and red LED. */
uint8_t redLEDState = LOW;
uint8_t redButtonState = 0;
uint8_t redButtonStateLAST = LOW;
uint8_t zToBeSent = 'Z';
uint8_t aToBeSent = 'A';
uint8_t whiteLEDState = LOW;
unsigned long lastGreenDebounceTime = 0; //The last time the output pin was toggled
unsigned long lastRedDebounceTime = 0; //The last time the output pin was toggled
unsigned long debounceDelay = 10; // The debounce time; increase if output flickers
String readValue;
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
//Serial.println("Client has connected");
//digitalWrite(greenLED, HIGH);
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
//Serial.println("Client has disconnected");
//digitalWrite(greenLED, LOW);
}
};
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
String rxValue = pCharacteristic->getValue();
if (rxValue.length() > 0) {
/*
Serial.println("*********");
Serial.print("Received Value: ");
for (int i = 0; i < rxValue.length(); i++)
Serial.print(rxValue[i]);
Serial.println();
Serial.println("*********");
*/
//readValue = rxValue;
if(rxValue[0] == 'A'){
digitalWrite(greenLED, HIGH);
}
else{
digitalWrite(greenLED, LOW);
}
}
}
};
void setup() {
Serial.begin(115200);
Serial.println("Server Service Initiated");
// Create the BLE Device
BLEDevice::init("Bluetooth Server ESP32C3");
// 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
pTxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_NOTIFY
);
pTxCharacteristic->addDescriptor(new BLE2902());
BLECharacteristic * pRxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
BLECharacteristic::PROPERTY_WRITE
);
pRxCharacteristic->setCallbacks(new MyCallbacks());
// Start the service
pService->start();
// Start advertising
/*
pServer->getAdvertising()->start();
Serial.println("Waiting on a client connection to notify...");
*/
// Code below added to get the service advertising
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();
// Set up the green and red button input pins
pinMode(greenButtonPin, INPUT);
pinMode(redButtonPin, INPUT);
// Set up the green and red LEDs output pins
pinMode(greenLED, OUTPUT);
pinMode(redLED,OUTPUT);
pinMode(whiteLED,OUTPUT);
// Establishes initial state of LEDs
digitalWrite(greenLED, LOW);
digitalWrite(redLED, LOW);
digitalWrite(whiteLED, LOW);
}
void loop() {
// 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;
}
// Read the state of each switch into the corresponding local variable.
int greenButtonReading = digitalRead(greenButtonPin);
int redButtonReading = digitalRead(redButtonPin);
// If the GREEN switch changed, start the GREEN debounce timer
if (greenButtonReading != greenButtonStateLAST){
lastGreenDebounceTime = millis();
}
// If the RED switch changed, start the RED debounce timer
if (redButtonReading != redButtonStateLAST){
lastRedDebounceTime = millis();
}
if ((millis() - lastGreenDebounceTime) > debounceDelay){
if(greenButtonReading != greenButtonState){
greenButtonState = greenButtonReading;
if(greenButtonState == HIGH){
greenLEDState = !greenLEDState;
}
}
}
// If the Red Button was pressed, the red LED shouldbe turned on or off.
if ((millis() - lastRedDebounceTime) > debounceDelay){
if(redButtonReading != redButtonState){
redButtonState = redButtonReading;
if(redButtonState == HIGH){
redLEDState = !redLEDState;
}
}
}
if(redLEDState){
//If the red LED is ON, broadcast character Z to client.
pTxCharacteristic->setValue(&zToBeSent, 1);
pTxCharacteristic->notify();
delay(1000);
}
else{
//If the red LED is OFF, broadcast character A to client.
pTxCharacteristic->setValue(&aToBeSent, 1);
pTxCharacteristic->notify();
delay(1000);
}
if(deviceConnected){
digitalWrite(whiteLED, HIGH);
}
else{
digitalWrite(whiteLED, LOW);
}
digitalWrite(greenLED, greenLEDState);
digitalWrite(redLED, redLEDState);
greenButtonStateLAST = greenButtonReading;
redButtonStateLAST = redButtonReading;
}