Hi Chris and Gerard,
Currently I haven't got the chance to test as I fried my ESP32 playing around with a potentiometer (and 12V unfortunately...). To answer your 3 questions Chris:
1. Yes, I had already checked that and made sure that that is the case
2. See below:
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include <BLESecurity.h>
BLEServer* pServer = NULL;
BLECharacteristic* pTxCharacteristic;
BLECharacteristic* pRxCharacteristic;
BLECharacteristic* pRxPot1Characteristic;
bool deviceConnected = false;
bool oldDeviceConnected = false;
static const int PWM_Pin1 = 13; //here we set the pins that will output a PWM signal
static const int PWM_Pin2 = 12;
static const int PWM_Pin3 = 25;
static const int PWM_Pin4 = 26;
const int potPin = 34;
int potValue = 0;
// setting PWM properties
const int freq = 5000; //a 5kHz frequency assures that LED's which are connected do not flicker. It also gives us a signal that many MOSFET's, for amplification, are capable of handling.
const int ledChannel_1 = 0; //channels 0 and 1 share same freq. as do 2,3 and 5. Internally the ESP32 microcontroller sets a led channel that is later assigned to pins.
const int ledChannel_2 = 1;
const int ledChannel_3 = 2;
const int ledChannel_4 = 3;
const int resolution = 8; // apparently the resolution of the PWM can be altered. 8 bits gives us 255 steps.
String PWM_state_1;
String PWM_state_2;
String PWM_state_3;
String PWM_state_4;
// See the following for generating UUIDs:
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
int OldPotmeter = 0;
int NewPotmeter = 1;
int dutyCycle = 0;
//The MyServerCallbacks handles the BLE connection status. It sets flags to true or false so it knows whether it is connected or disconnected.
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
BLEDevice::startAdvertising(); //the start advertising is used here to enable multiple connections. Normally after a connection the server stops advertising, hence it is repeated here.
Serial.println("Client connected");
};
void onDisconnect(BLEServer* pServer) {
delay(500);
deviceConnected = false;
Serial.println("Disconnected");
}
};
//The MyCallbacks handles RECEIVED data from the app.
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string rxValue = pCharacteristic->getValue();
String msg = "";
String sub1 = "";
String sub2 = "";
if (rxValue.length() > 0) {
for (int i = 0; i < rxValue.length(); i++) {
msg += rxValue[i];
}
}
// Do stuff based on the command received from the app. For now we print the slider nr and its corresponding value to the Serial Monitor screen.
sub1 = msg.substring(0, msg.indexOf("="));
sub2 = msg.substring((msg.indexOf("=") + 1), (msg.length() - 1));
Serial.println(sub1);
Serial.println(sub2);
if (sub1 == "Slider1") {
ledcWrite(ledChannel_1, sub2.toInt());
}
else if (sub1 == "Slider2") {
ledcWrite(ledChannel_2, sub2.toInt());
}
else if (sub1 == "Slider3") {
ledcWrite(ledChannel_3, sub2.toInt());
}
else if (sub1 == "Slider4") {
ledcWrite(ledChannel_4, sub2.toInt());
}
}
//With this code here the callback function also sends back text to the Client (app on phone) upon a change in value. However, when a slider is changed it pushes that value back as well.
//In conclusion, the callback function works for both received and sent messages.
};
class MySecurity : public BLESecurityCallbacks {
uint32_t onPassKeyRequest() {
ESP_LOGI(LOG_TAG, "PassKeyRequest");
return 123456;
}
void onPassKeyNotify(uint32_t pass_key) {
ESP_LOGI(LOG_TAG, "The passkey Notify number:%d", pass_key);
}
bool onConfirmPIN(uint32_t pass_key) {
ESP_LOGI(LOG_TAG, "The passkey YES/NO number:%d", pass_key);
vTaskDelay(5000);
return true;
}
bool onSecurityRequest() {
ESP_LOGI(LOG_TAG, "SecurityRequest");
return true;
}
void onAuthenticationComplete(esp_ble_auth_cmpl_t cmpl) {
ESP_LOGI(LOG_TAG, "Starting BLE work!");
}
};
void setup() {
Serial.begin(115200);
// Create the BLE Device
BLEDevice::init("ESP32");
BLEDevice::setPower(ESP_PWR_LVL_P7);
// Create the BLE Server
pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// Create the BLE Service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Enable encryption
BLEDevice::setEncryptionLevel(ESP_BLE_SEC_ENCRYPT);
/*
Required in authentication process to provide displaying and/or input passkey or yes/no butttons confirmation
*/
BLEDevice::setSecurityCallbacks(new MySecurity());
// Create two BLE Characteristics, one for transmitting (TX), other for receiving (RX). The transmitted data on one end is the received data on the other end and the RX UUID characteristics in the app are the TX UUID characteristics of the ESP32 and vice versa.
// DO NOT CHANGE THE ORDER/SEQUENCE OF CODE. First TX, then Descriptor, then RX, then Callback
pRxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
//BLECharacteristic::PROPERTY_READ |
//BLECharacteristic::PROPERTY_NOTIFY |
//BLECharacteristic::PROPERTY_INDICATE |
BLECharacteristic::PROPERTY_WRITE
);
pRxCharacteristic->setCallbacks(new MyCallbacks()); //is the MyCallbacks used to transmit and receive data AFTER pairing has been established???
pTxCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
//BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_NOTIFY
//BLECharacteristic::PROPERTY_INDICATE |
//BLECharacteristic::PROPERTY_WRITE
);
pTxCharacteristic->addDescriptor(new BLE2902());
// Start the service
pService->start();
// Start advertising
pServer->getAdvertising()->start();
Serial.println("Waiting a client connection to notify...");
esp_ble_auth_req_t auth_req = ESP_LE_AUTH_REQ_SC_MITM_BOND; //bonding with peer device after authentication
esp_ble_io_cap_t iocap = ESP_IO_CAP_OUT; //set the IO capability to No output YES input. Otherwise use ESP_IO_CAP_NONE;
uint8_t key_size = 16; //the key size should be 7~16 bytes
uint8_t init_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
uint8_t rsp_key = ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK;
//set static passkey
uint32_t passkey = 123456;
uint8_t auth_option = ESP_BLE_ONLY_ACCEPT_SPECIFIED_AUTH_DISABLE;
// uint8_t oob_support = ESP_BLE_OOB_DISABLE;
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_STATIC_PASSKEY, &passkey, sizeof(uint32_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, &auth_req, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_MAX_KEY_SIZE, &key_size, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_ONLY_ACCEPT_SPECIFIED_SEC_AUTH, &auth_option, sizeof(uint8_t));
// esp_ble_gap_set_security_param(ESP_BLE_SM_OOB_SUPPORT, &oob_support, sizeof(uint8_t));
/* If your BLE device act as a Slave, the init_key means you hope which types of key of the master should distribut to you,
and the response key means which key you can distribut to the Master;
If your BLE device act as a master, the response key means you hope which types of key of the slave should distribut to you,
and the init key means which key you can distribut to the slave. */
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, &init_key, sizeof(uint8_t));
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, &rsp_key, sizeof(uint8_t));
Serial.println("Characteristic defined! Now you can read it in your phone!");
//Configure pins to which PWM signal is written
ledcSetup(ledChannel_1, freq, resolution);
ledcSetup(ledChannel_2, freq, resolution);
ledcSetup(ledChannel_3, freq, resolution);
ledcSetup(ledChannel_4, freq, resolution);
ledcAttachPin(PWM_Pin1, ledChannel_1);
ledcAttachPin(PWM_Pin2, ledChannel_2);
ledcAttachPin(PWM_Pin3, ledChannel_3);
ledcAttachPin(PWM_Pin4, ledChannel_4);
/*//ledcWrite(ledChannel_1, 255); //the PWM signal is fully on at start-up, i.e. initial app load.
//ledcWrite(ledChannel_2, 255);
PWM_state_1 = "255"; //the value set here is passed to app at first load, i.e. upon first connection or app re-start (also a first connection)
PWM_state_2 = "255";
PWM_state_3 = "255";
PWM_state_4 = "255";
*/
}
void loop() {
// notify changed value
if (deviceConnected) {
if (NewPotmeter == OldPotmeter) { //for now alter between "equal" and "unequal" as a notification for test purposes.
pTxCharacteristic->setValue("Equal");
pTxCharacteristic->notify();
NewPotmeter = 25;
delay(500);
}
else {
pTxCharacteristic->setValue("Unequal");
pTxCharacteristic->notify();
NewPotmeter = OldPotmeter;
delay(500);
}
}
// disconnecting
if (!deviceConnected && oldDeviceConnected) {
delay(500); // give the bluetooth stack the chance to get things ready
pServer->startAdvertising(); // restart advertising
Serial.println("start advertising again");
oldDeviceConnected = deviceConnected;
}
// connecting
if (deviceConnected && !oldDeviceConnected) {
// do stuff here on connecting
oldDeviceConnected = deviceConnected;
}
/*
potValue = analogRead(potPin);
Serial.println(potValue);
Serial.println(potValue);
dutyCycle = map(potValue, 0, 4095, 20, 255);
ledcWrite(ledChannel_1, dutyCycle);
delay(500);
*/
}
3. Correct, it's running on Android 8.1.0
@Gerard, thanks heaps for the suggestion. I haven't got the chance to test that but I will soon. Once complete I will write my feedback here. I sure am hoping that solves the problem because this has been causing me lots of headaches :-(