반응형

ADUCON application

 

https://play.google.com/store/apps/details?id=com.tistory.postpop.hmi 

 

ADUCON - Google Play 앱

무선(WiFi/Bluetooth/BLE)을 통한 Arduino 원격 제어 앱

play.google.com

 

Basic code for remote control

- Set BLE library for the Bluetooth component of ESP32

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

 

- Library function to Inform if the bluetooth component of ESP32 has BLE connection or not

class MyServerCallbacks: public BLEServerCallbacks {
  void onConnect(BLEServer* pServer) {
    deviceConnected = true;
    Serial.println(F("connected"));
  };
  void onDisconnect(BLEServer* pServer) {
    deviceConnected = false;
    pServer->startAdvertising(); // restart advertising
    Serial.println(F("start advertising"));
  }
};

 

- Library function to receive data through ESP32's BLE connection

class MyCallbacks: public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic *pCharacteristic) {
    rxValue = pCharacteristic->getValue();
//    if (rxValue.length() > 0) { // output the received data to Serial Monitor
//      for (int i = 0; i < rxValue.length(); i++) {
//        Serial.print(i); Serial.print(": "); Serial.println(rxValue[i], HEX);
//      }
//    }
    rx_received = true;
  }
};

 

- BLE name and UUID settings

#define btName "ESP32ble"
#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"

 

- setup() function

void setup() {
  Serial.begin(115200);
  BLEDevice::init(btName);  //("ESP32");// Create the BLE Device
  pServer = BLEDevice::createServer();  // Create the BLE Server
  pServer->setCallbacks(new MyServerCallbacks());
  BLEService *pService = pServer->createService(SERVICE_UUID);  // Create the BLE Service
  pTxCharacteristic = pService->createCharacteristic (  // Create a BLE Characteristic
                      CHARACTERISTIC_UUID_TX,
                      BLECharacteristic::PROPERTY_NOTIFY
                    );
  pTxCharacteristic->addDescriptor(new BLE2902());
  BLECharacteristic * pRxCharacteristic = pService->createCharacteristic (
                                          CHARACTERISTIC_UUID_RX,
                                          BLECharacteristic::PROPERTY_WRITE
                                        );
  pRxCharacteristic->setCallbacks(new MyCallbacks());
  pService->start();  // Start the service
  pServer->getAdvertising()->start();  // Start advertising
  Serial.println(F("Waiting a client connection to notify..."));
}

 

- loop() function

bool gotData = false;

void loop() {
  if (rx_received == true) { // when incomming data from BLE
    for (int i = 0; i < rxValue.length(); i++) Serial.print(rxValue[i]); // Output data of BLE to the serial monitor.
    Serial.println(); 
    gotData = true; // the flag for response
    rx_received = false;
  } else {
    if (gotData) {  // if response
      char temp [21];
      String setVal = "";
      setVal += char(0xF4);      // protocol header of text for ADUCON with bluetooth
      setVal += "Hello World ";
      setVal += random(100,200); // the message for sending
      setVal += char(0xF1);      // protocol footer of text for ADUCON with bluetooth
      setVal += '\0';            // end character for sending, pTxCharacteristic->setValue(temp);
      Serial.println(setVal);    // Output the message to the serial monitor.
      if (setVal.length() <= 21) { // convert String to array of Char
        for (int i = 0; i < setVal.length(); i++) temp[i] = setVal[i];
      }
      pTxCharacteristic->setValue(temp); 
      pTxCharacteristic->notify();
      gotData = false;
    }
  }
}

 

ESP32_BLE_BASIC.zip

ESP32_BLE_BASIC.zip
0.00MB

 

- Output of Serial Monitor after upload scketch "ESP32_BLE_BASIC.ino"

 

connecting to BLE of ESP32 on the ADUCON app

- Bluetooth 4.0 Search and Connection in the App

Click the Bluetooth icon in the app and select Bluetooth 4.0 in Select Ver.

Click the Bluetooth button and select the BLE of ESP32.

Select ESP32ble
connected to ESP32ble
received data "%%F8connect"
response from ESP32

 

※ If a Bluetooth device is registered using the same device for Bluetooth Classic connection, the registered device must be removed to connect by BLE from the app.

If the device has registered, it will interfere with the BLE connection and the device will not respond to BLE connection requests from the app.

Code for remote control with BLE of ADUCON applications

- SerialBT_read() function

1. Protocol header definition

ADUCON app's protocol header settings

Define the headers for BLE in the Arduino sketch according to the protocol header settings in the ADUCON app.

#define pinHD 0xF0
#define pwmHD 0xF3
#define strHD 0xF4
#define footHD 0xF1
#define echoHD 0xE1
#define connectHD 0xF8
#define connectHDstr F("%%F8")
#define optionHD 0xF9

uint8_t pin[] = {pinHD, 0, 0}; //F0, pin state, F1
uint8_t pwm[] = {pwmHD, 0, 0, 0, 0}; //F3, slide number, 16bit value, F1

 

2. Code to check the connection attempt of ADUCON app

bool appConnection = false;

void BLE_read() {
  if (appConnection) { // If app connection is confirmed
    // Execute code after app connection is confirmed
  } else CheckF8("");  // check "%%F8connect"
}

 

3. Handling of values according to connection header "connectHDstr(%%F8)"

%%F8 + connect: Transmit the necessary app settings and current Arduino state values through the iniSet() and send_State() functions.

%%F8 + disconnect: Disconnect and change value of appConnection to false.

%%F8 + NA: Change setting values for BT05.

void CheckF8(String temp) {
  if (temp == "") {
    String hd = connectHDstr; // %%F8
    if (rxValue[0] == hd[0] && rxValue[1] == hd[1] && rxValue[2] == hd[2] && rxValue[3] == hd[3]) {
      for (int i = hd.length(); i < rxValue.length(); i++) {
        if (rxValue[i] != '\n') temp += rxValue[i];
        else break;
      }
      if (temp == F("connect")) { delay(100); needAppCheck = false; appConnection = true; iniSet(); send_State(); }
    } else { btDisconnect(); needAppCheck = false; } // disconnect & advertise
  } else {
    if (temp == F("disconnect")) appConnection = false; 
    else if (temp.startsWith(F("NA"))) { sendMessage(F("This funtion is not available.")); } 
    else Serial.println(temp);
  }
}

 

- If "%%F8connect" is not confirmed within disconnectTime after receiving the first data through BLE, the connection is terminated and re-advertise the name of BLE.

void orderDisconnect() { 
  if (needAppCheck) { 
    if (!appConnection) {
      if (millis() - disconnectTime > 3000) {
        needAppCheck = false;
        btDisconnect();
        Serial.println(F("enter app check disconnect"));
      }
    } 
  } 
}

 

- Command the app to click the disconnec button and terminate the connected BLE to ESP32

void btDisconnect() {
  sendDisconnect();
  delay(10);
  pServer->disconnect(pServer->getConnId());
}

 

4. Handling of values according to option header "optionHDstr(%%F9)"

void CheckF9(String temp) {
  Serial.println(temp);
  if (temp.startsWith(F("RAD"))) { } // if it starts with "RAD"
  else if (temp.startsWith(F("CKB"))) { } // if it starts with "CKB"
  else if (temp.startsWith(F("CHD"))) { } // if it starts with "CHD"
  else if (temp.startsWith(F("LSD"))) { } // if it starts with "LSD"
  else if (temp.startsWith(F("STR"))) { } // if it starts with "STR"
  else { // if not
    if (temp.length() < 10) Serial.println(F("alarm")); // set the time if the length of the value is less than 10
    else Serial.println(F("date/time")); // current date/time if larger
  }
}

 

5. Handling of values according to button header "pinHD(0xF0)"

// 0xF0 + 1byte Num + 0xF1
if (rxValue[2] == footHD) {     // if the third byte is 0xF1
  pin_control(rxValue[1]);      // execute the code with the value of second byte
}

 

6. Handling of values according to SeekBar(slide bar) header "pwmHD(0xF3)"

// 0xF3 + 1byte Num(slide number) + 2byte Num(PWM) + 0xF1
uint8_t cn = 0;
while (rxValue[cn] == pwmHD) {      // 0xF3, Process 3 PWM values of COLOR PICKER
  if (rxValue[cn+4] == footHD) {    // if the fifth byte is 0xF1
    uint16_t value = rxValue[cn+3]; // Swap third and fourth bytes
    value = value << 8 | rxValue[cn+2];
    pwm_control(rxValue[cn+1], value); // execute the code with values
  }
  cn = cn+5; // index of next 0xF3
}

 

Protocol function to send data from Arduino to app

1. Change the state of the button.

void sendPinState(uint8_t pin_val){
  pin[1] = pin_val;
  pin[2] = footHD;
  pTxCharacteristic->setValue((uint8_t*)&pin, 3);
  pTxCharacteristic->notify();
}

 

2. Transmits an echo for the received value of the button.

void sendPinEcho(uint8_t pin_val){
  pin[1] = pin_val;
  pin[2] = echoHD;
  pTxCharacteristic->setValue((uint8_t*)&pin, 3);
  pTxCharacteristic->notify();
}

 

3. Change the slide state of the app.

void sendPwmSlide(uint8_t slide, uint16_t pwm_val) {
  pwm[1] = slide;
  pwm[2] = pwm_val;
  pwm[3] = pwm_val >> 8;
  pwm[4] = footHD;
  pTxCharacteristic->setValue((uint8_t*)&pwm, 5);
  pTxCharacteristic->notify();
}

 

4. Transmits the echo for the received value of the PWM.

void sendPwmEcho(uint8_t slide, uint16_t pwm_val) {
  pwm[1] = slide;
  pwm[2] = pwm_val;
  pwm[3] = pwm_val >> 8;
  pwm[4] = echoHD;
  pTxCharacteristic->setValue((uint8_t*)&pwm, 5);
  pTxCharacteristic->notify();
}

 

- A code example that reflects the status of the current button and PWM values of Arduino to the app when connected to the ADUCON app

void send_iniState() { // CURRENT STATE
  sendPinState(10); 
  sendPinState(21); 
  sendPinState(30); 
  sendPinState(41); 
  sendPinState(50); 
  sendPinState(61); 
  sendPinState(71); 
  sendPinState(80); 
  sendPinState(91); 
  sendPinState(101); 
  sendPinState(110); 
  sendPinState(121); 
  sendPinState(130); 
  sendPinState(141); 
  sendPinState(150); 
  sendPwmSlide(1, 110); 
  sendPwmSlide(2, 120); 
  sendPwmSlide(3, 210); 
  sendPwmSlide(4, 0); 
  sendPwmSlide(5, 0); 
  sendPwmSlide(6, 0);
}

Screen reflecting initial state and labels when connecting Arduino

 

5. Send text with over the limitation of transmit data length of BLE.

void sendText(String str) {
  char temp [21]; // 18
  uint16_t len = str.length();
  uint8_t repeat = 1;
  uint8_t endLen = 0;
  if (len > 18) {
     repeat = (len/18)+1;
     endLen = (len%18);
  } else endLen = len;
  for (int r = 0; r < repeat; r++) {
    temp[0] = strHD;
    uint8_t ed = 0;
    if (repeat-r > 1) ed = 18;
    else ed = endLen;
    for (int i = 1; i < ed+1; i++) {
      temp[i] = str[(r*18)+i-1];
    }
    if (repeat-r > 1) temp[ed+1] = echoHD;
    else temp[ed+1] = footHD;
    temp[ed+2] = '\0';
    pTxCharacteristic->setValue(temp); 
    pTxCharacteristic->notify();
  }
}

 

6. Set to send the date/time of the Android system When connecting, or request the transmission of the date/time if necessary.

void requstDateTime(){ // order disconnect to App 
  uint8_t setVal[3];
  setVal[0] = connectHD;
  setVal[1] = 0x01;
  setVal[2] = 0x00;
  pTxCharacteristic->setValue((uint8_t*)&setVal,3); 
  pTxCharacteristic->notify(); 
}

 

7. Use when you want to acquire control authority by using the set password for ESP32

It can be changed to any name through definition of the passName and passNameLen for processing the password in the sketch and the app send datas starting with passName as password value. This is to enhance security.

#define passName F("PAS:")
#define pnLength 4

void requestPass(bool val){ // order disconnect to App 
  uint8_t setVal[3+pnLength];
  String temp = passName;
  setVal[0] = connectHD;
  setVal[1] = 0x02;
  if (val) {
    setVal[2] = pnLength;
    for (int i = 0; i<pnLength;i++) setVal[i+3] = temp[i];
    pTxCharacteristic->setValue((uint8_t*)&setVal,3+pnLength); 
  } else {
    setVal[2] = val;
    pTxCharacteristic->setValue((uint8_t*)&setVal,3); 
  }
  pTxCharacteristic->notify();
}

 

8. Response for correct or not through password confirmation

void responsePass(bool val){ 
  uint8_t setVal[3];
  setVal[0] = connectHD;
  setVal[1] = 0x03;
  setVal[2] = val;
  pTxCharacteristic->setValue((uint8_t*)&setVal,3); 
  pTxCharacteristic->notify();
}

 

9. Outputs the message in the form of a pop-up.

void send_message(String str, uint8_t head, uint8_t fn) {
  char temp [21]; // 18
  uint16_t len = str.length();
  uint8_t repeat = 1;
  uint8_t endLen = 0;
  if (len > 17) {
     repeat = (len/17)+1;
     endLen = (len%17);
  } else endLen = len;
  for (int r = 0; r < repeat; r++) {
    temp[0] = head;
    temp[1] = fn;
    uint8_t ed = 0;
    if (repeat-r > 1) ed = 17;
    else ed = endLen;
    for (int i = 2; i < ed+2; i++) {
      temp[i] = str[(r*17)+i-2];
    }
    if (repeat-r > 1) temp[ed+2] = echoHD;
    else temp[ed+2] = footHD;
    temp[ed+3] = '\0';
    pTxCharacteristic->setValue(temp); 
    pTxCharacteristic->notify();
  }
}

void sendMessage(String str) {
  send_message(str, connectHD, 0x04);
}

 

10. Instruct the app to click the Disconnect Button.

void sendDisconnect(){ // order disconnect to App 
  uint8_t setVal[3];
  setVal[0] = connectHD;
  setVal[1] = 0x05;
  setVal[2] = 0x00;
  pTxCharacteristic->setValue((uint8_t*)&setVal,3); 
  pTxCharacteristic->notify();
}

Disconnect Button for Bluetooth

 

11. Set the function to continuously transmit the changed value of the SeekBar (slide bar) according to the specified interval.

true: Active Slide Mode

false: Passive Slide Mode (transmits only values when the slide bar is touched up)

void setActiveSlide(bool val){ 
  uint8_t setVal[4];
  setVal[0] = optionHD;
  setVal[1] = 0x01;
  setVal[2] = val;
  setVal[3] = 0x00;
  pTxCharacteristic->setValue((uint8_t*)&setVal, 4);
  pTxCharacteristic->notify();
}

 

12. Set transmission interval of ACTIVE SLIDE MODE. (Unit: Millisecond)

void setSlideInterval(uint16_t val){ 
  uint8_t setVal[4];
  setVal[0] = optionHD;
  setVal[1] = 0x02;
  setVal[2] = val;
  setVal[3] = val >> 8;
  pTxCharacteristic->setValue((uint8_t*)&setVal, 4);
  pTxCharacteristic->notify();
}

 

13. Set the operation function when clicking the label displaying the current connection status.

0: No function.

1: Show only connection information when it clicked.

3: Show connection information and password when it clicked so that the connection and password can be set.

// 0: not use, 1: show only name, 2: show name & pass // defalult: 2
void setSSIDLabelMode(uint8_t val) { 
  uint8_t setVal[4];
  setVal[0] = optionHD;
  setVal[1] = 0x03;
  setVal[2] = val;
  setVal[3] = 0x00;
  pTxCharacteristic->setValue((uint8_t*)&setVal, 4);
  pTxCharacteristic->notify();
}

* BLE is no need to pair with Mobile Phone. 

* If pairing is attempted, an error message is displayed.

 

14. Display additional push buttons in the main menu area. (it is possible to control only at Arduino)

void showDialogMenu(bool val){ 
  uint8_t setVal[4];
  setVal[0] = optionHD;
  setVal[1] = 0x04;
  setVal[2] = val;
  setVal[3] = 0x00;
  pTxCharacteristic->setValue((uint8_t*)&setVal, 4);
  pTxCharacteristic->notify();
}

 

15. Change the main screen to Color Picker / Pwm Nob screen from Arduino. (generally set in the options of the app)

uint8_t: list below

0: Display buttons and SeekBar (slide bar) on the main screen

1: Display Color_Picker on the main screen.

2: Display Color_Picker and Group 2 on the main screen.

3: Display PWM Nob on the main screen.

4: Display PWM Nob and Group 2 on the main screen.

String: name of the group

bool: Sets whether to display the SeekBar (slide bar) when the main screen buttons are displayed.

* true: SeekBar (slide bar) is also displayed when button is displayed or Pwm Nob is displayed

* false: SeekBar (slide bar) is not displayed when button is displayed and SeekBar (slide bar) is displayed only when Pwm Nob is displayed

//0: not use 1:color picke 2:color picker+add group 3: pwm nob 4: pwm nob+add group, group1 & group2 Label
void setColorNob(uint8_t val, String group1, String group2, bool pwmDPMain) { 
  String str = String(val); str += ','; 
  str += group1; str += ','; 
  str += group2; str += ',';
  str += pwmDPMain;
  send_message(str, optionHD, 0x05);
}

 

16. Set the main screen display of the app.

Set to 0 or 1 in order depending on whether buttons 1 to 15, SeekBar (slide bar) 1 to 6, text input, and floating buttons are displayed.

0: hidden 1: visible

///////////////////////// SET MAIN DISPLAY
//F("111111111111111"  // button 1 ~ 15, 0:hide 1:display
//  "111111"           // slider 1 ~ 6
//  "11")              // Text Input/Floating Button
void setDisplay(String str){ 
  send_message(str, optionHD, 0x06);
}

 

17. Set labels for buttons and SeekBar.

Label buttons 1 to 15 and SeekBar (slide bar) 1 to 6 in order using ',' as a separator.

//F("BT1,BT2,BT3,BT4,BT5,BT6,BT7,BT8,BT9,BT10,BT11,BT12,BT13,BT14,BT15," // button 1 ~ 15
//  "PW1,PW2,PW3,PW4,PW5,PW6")) // slider 1 ~ 6
void setButtonLabel(String str){ 
  send_message(str, optionHD, 0x07);
}

 

18. Set the button's toggle/push properties.

Set the button properties to 0 or 1 in order of buttons 1 to 15.

0: Push 1: Toggle

//F("111111111111111") // button 1 ~ 15, 0:push 1:toggle 
void setButtonToggle(String str){ 
  send_message(str, optionHD, 0x08);
}

 

19. Set the maximum/minimum values of the SeekBar (slide bar).

SeekBar (slide bar) Specifies the maximum/minimum values from 1 to 6 in order using ',' as a separator.

//F("0,255,0,255,0,255,0,255,0,255,0,255")
void setMinMax(String str){ 
  send_message(str, optionHD, 0x09);
}

 

20. Set the title of the Arduino sketch.

//title: Test Mode
//text: Arduino<br/>- WiFi Controler<br/><br/>Manual<br/><a href='https://postpop.tistory.com/8'>https://postpop.tistory.com/8</a>
void setAppTitleMessage(String title, String text){
  String str = title; str += ','; 
  str += text; 
  send_message(str, optionHD, 0x0A);
}

 

21. Dialog Message: radio button

// option = "A,B,C" -> index = 1(A) ~ 3(C)
void dialogRadio(uint8_t id, String title, String option, uint8_t selection){ 
  String str = F("RAD:"); 
  str += String(id); str += ':';
  str += title; str += ':';
  str += option; str += ':';
  str += String(selection);
  send_message(str, optionHD, 0x0B);
} // Return -> RAD:0:1(index) , RAD:id:option index

 

22. Dialog Message: Checkbox

// option = "A,B,C"
void dialogCheckbox(uint8_t id, String title, String option){ 
  String str = F("CKB:"); 
  str += String(id); str += ':';
  str += title; str += ':';
  str += option; 
  send_message(str, optionHD, 0x0B);
} // Return -> CKB:0:1,3(index) , CKB:id:option index

 

23. Dialog Message: Select button

// option = "A,B"
void dialogChoose(uint8_t id, String message, String option){ 
  String str = F("CHD:"); 
  str += String(id); str += ':'; 
  str += message; str += ':'; 
  str += option; 
  send_message(str, optionHD, 0x0B);
} // Return -> CHD:0:B , CHD:id:option str

 

24. Dialog Message: List Window

// option = "A,B,C,D,E,F,G,H"
void dialogList(uint8_t id, String title, String option){ 
  String str = F("LSD:"); 
  str += String(id); str += ':';
  str += title; str += ':'; 
  str += option; 
  send_message(str, optionHD, 0x0B);
} // Return -> LSD:0:F , LSD:id:option str

 

25. Dialog Message: Input text

void dialogInput(uint8_t id, String title){ 
  String str = F("STR:"); 
  str += String(id); str += ':'; 
  str += title; 
  send_message(str, optionHD, 0x0B);
} // Return -> STR:0:str , STR:id:str

 

ESP32_HMI_BLE_CONTROL.zip

ESP32_HMI_BLE_CONTROL.zip
0.00MB

 

https://youtu.be/P1vCF_uNCVU

 

Main sketch

더보기
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

BLEServer *pServer = NULL;
BLECharacteristic * pTxCharacteristic;
bool deviceConnected = false;
bool rx_received = false;      // flag to excute the function when receiving data from BLE
std::string rxValue; // Set global variables to save the received data from BLE

unsigned long int disconnectTime = 0;
bool needAppCheck = false;
bool appConnection = false;

#include "protocol.h"

class MyServerCallbacks: public BLEServerCallbacks {
  void onConnect(BLEServer* pServer) {
    deviceConnected = true;
    disconnectTime = millis(); needAppCheck = true; 
    Serial.println(F("connected"));
  };
  void onDisconnect(BLEServer* pServer) {
    deviceConnected = false;
    delay(500);
    pServer->startAdvertising(); // restart advertising
    Serial.println(F("start advertising"));
  }
};

class MyCallbacks: public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic *pCharacteristic) {
    rxValue = pCharacteristic->getValue();
//    if (rxValue.length() > 0) {
//      for (int i = 0; i < rxValue.length(); i++) {
//        Serial.print(i); Serial.print(": "); Serial.println(rxValue[i], HEX);
//      }
//    }
    rx_received = true;
  }
};

#define btName "ESP32ble"
#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"

void setup() {
  Serial.begin(115200);
  BLEDevice::init(btName);  //("ESP32");// Create the BLE Device
  pServer = BLEDevice::createServer();  // Create the BLE Server
  pServer->setCallbacks(new MyServerCallbacks());
  BLEService *pService = pServer->createService(SERVICE_UUID);  // Create the BLE Service
  pTxCharacteristic = pService->createCharacteristic (     // Create a BLE Characteristic
                      CHARACTERISTIC_UUID_TX,
                      BLECharacteristic::PROPERTY_NOTIFY
                    );
  pTxCharacteristic->addDescriptor(new BLE2902());
  BLECharacteristic * pRxCharacteristic = pService->createCharacteristic (
                                          CHARACTERISTIC_UUID_RX,
                                          BLECharacteristic::PROPERTY_WRITE
                                        );
  pRxCharacteristic->setCallbacks(new MyCallbacks());
  pService->start();                   // Start the service
  pServer->getAdvertising()->start();  // Start advertising
  Serial.println(F("Waiting a client connection to notify..."));
}

void pin_control(uint8_t value) {
  if (value != 0) {
    switch (value) {
      case 11: Serial.println(F("button 1 : on"));
               sendPinEcho(value);
               sendText(F("1: ON")); 
                  break;
      case 10: Serial.println(F("button 1 : off"));
               sendText(F("1: OFF")); 
               sendPinEcho(value);
                  break;
      case 21: Serial.println(F("button 2 : on"));
                  break;
      case 20: Serial.println(F("button 2 : off"));
                  break;
      case 31: Serial.println(F("button 3 : on"));
                  break;
      case 30: Serial.println(F("button 3 : off"));
                  break;
      case 41: Serial.println(F("button 4 : on"));
                  break;
      case 40: Serial.println(F("button 4 : off"));
                  break;
      case 51: Serial.println(F("button 5 : on"));
                  break;
      case 50: Serial.println(F("button 5 : off"));
                  break;
      case 61: Serial.println(F("button 6 : on"));
                  break;
      case 60: Serial.println(F("button 6 : off"));
                  break;
      case 71: Serial.println(F("button 7 : on"));
                  break;
      case 70: Serial.println(F("button 7 : off"));
                  break;
      case 81: Serial.println(F("button 8 : on"));
                  break;
      case 80: Serial.println(F("button 8 : off"));
                  break;
      case 91: Serial.println(F("button 9 : on"));
                  break;
      case 90: Serial.println(F("button 9 : off"));
                  break;  
      case 101: Serial.println(F("button 10 : on"));
                  break;
      case 100: Serial.println(F("button 10 : off"));
                  break;  
      case 111: Serial.println(F("button 11 : on"));
                  break;
      case 110: Serial.println(F("button 11 : off"));
                  break;  
      case 121: Serial.println(F("button 12 : on"));
                  break;
      case 120: Serial.println(F("button 12 : off"));
                  break;                  
      case 131: Serial.println(F("button 13 : on"));
                  break;  
      case 130: Serial.println(F("button 13 : off"));
                  break;  
      case 141: Serial.println(F("button 14 : on"));
                  break;  
      case 140: Serial.println(F("button 14 : off"));
                  break;  
      case 151: Serial.println(F("button 15 : on"));
                  break;  
      case 150: Serial.println(F("button 15 : off"));
                  break;         
      case 161: Serial.println(F("button 16 : click"));
                  break; 
      case 171: Serial.println(F("button 17 : click"));
                  break;
      case 181: Serial.println(F("button 18 : click"));
                  break;  
      case 191: Serial.println(F("button 19 : click"));
                  break;  
      case 201: Serial.println(F("button 20 : click"));
                  break;                 
    }
  }
}

void pwm_control(uint8_t num, uint16_t value) {
  if (num == 1) {  // SeekBar (slide bar) 1
    sendPwmEcho(num, value); 
    Serial.print(F("pwm1: ")); Serial.println(value);
  } else if (num == 2) { // SeekBar (slide bar) 2
    sendPwmEcho(num, value);
    Serial.print(F("pwm2: ")); Serial.println(value);
  } else if (num == 3) {  // SeekBar (slide bar) 3
    sendPwmEcho(num, value);
    Serial.print(F("pwm3: ")); Serial.println(value);
  } else if (num == 4) {  // SeekBar (slide bar) 4
    Serial.print(F("pwm4: ")); Serial.println(value);
  } else if (num == 5) {  // SeekBar (slide bar) 5
    Serial.print(F("pwm5: ")); Serial.println(value);
  } else if (num == 6) {  // SeekBar (slide bar) 6
    Serial.print(F("pwm6: ")); Serial.println(value);
  }
}

bool gotEnd = false;
String message = "";

void BLE_read() {
  if (rx_received == true) {  
    if (appConnection) {
      String temp = ""; 
      if (rxValue[0] == pwmHD) {
        uint8_t cn = 0;
        while (rxValue[cn] == pwmHD) {   // 0xF3
          if (rxValue[cn+4] == footHD) { // verification of Received value
            uint16_t value = rxValue[cn+3];
            value = value << 8 | rxValue[cn+2];
            pwm_control(rxValue[cn+1], value); // execute the code with values
          }
          cn = cn+5;
        }
      } else if (rxValue[0] == pinHD) { // 0xF0
        if (rxValue[2] == footHD) {     // verification of Received value
          pin_control(rxValue[1]);      // execute the code with values
        }
      } else {
        String hd = connectHDstr; 
        if (rxValue[0] == hd[0] && rxValue[1] == hd[1] && rxValue[2] == hd[2]) {
          for (int i = hd.length(); i < rxValue.length(); i++) {
            if (rxValue[i] != '\n') message += rxValue[i];
            else { gotEnd = true; break; }
          }
          if (gotEnd) {
            if (rxValue[3] == hd[3]) CheckF8(message);
            else CheckF9(message);
            gotEnd = false; message = "";
          }
        } else {
          for (int i = 0; i < rxValue.length(); i++) Serial.print(rxValue[i]);
        }
      }
    } else CheckF8("");
    rx_received = false;
  }
}

void loop() {
  BLE_read();
  orderDisconnect();
  if(Serial.available()) { // if there is data in the serial buffer
    String temp = Serial.readStringUntil('\n'); // option of serial monitor: NEW LINE
    Serial.println(temp);
    if(temp == "on"){    // input serial monitor: "on"
      sendPinState(11);  // button state of the app: on
      sendText("ON");
      sendPwmEcho(1, 150);
    } else if(temp == "off"){  // input serial monitor: "off"
      sendPwmEcho(1, 250);     // PWM echo: off
      sendPinState(10); 
      sendText("OFF");
    } else if(temp == "1"){   
      
    } 
  }
}

 

Protocol sketch

더보기
//////////////////////////////////////////////////////////// COMMON
///////////////////////////////////////// ESSENTIAL 
#define pinHD 0xF0
#define pwmHD 0xF3
#define strHD 0xF4
#define footHD 0xF1
#define echoHD 0xE1
#define connectHD 0xF8
#define connectHDstr F("%%F8")
#define optionHD 0xF9

uint8_t pin[] = {pinHD, 0, 0}; //F0, pin state, F1

void sendPinState(uint8_t pin_val){
  pin[1] = pin_val;
  pin[2] = footHD;
  pTxCharacteristic->setValue((uint8_t*)&pin, 3);
  pTxCharacteristic->notify();
}

void sendPinEcho(uint8_t pin_val){
  pin[1] = pin_val;
  pin[2] = echoHD;
  pTxCharacteristic->setValue((uint8_t*)&pin, 3);
  pTxCharacteristic->notify();
}

uint8_t pwm[] = {pwmHD, 0, 0, 0, 0}; //F3, slide number, 16bit value, F1

void sendPwmSlide(uint8_t slide, uint16_t pwm_val) {
  pwm[1] = slide;
  pwm[2] = pwm_val;
  pwm[3] = pwm_val >> 8;
  pwm[4] = footHD;
  pTxCharacteristic->setValue((uint8_t*)&pwm, 5);
  pTxCharacteristic->notify();
}

void sendPwmEcho(uint8_t slide, uint16_t pwm_val) {
  pwm[1] = slide;
  pwm[2] = pwm_val;
  pwm[3] = pwm_val >> 8;
  pwm[4] = echoHD;
  pTxCharacteristic->setValue((uint8_t*)&pwm, 5);
  pTxCharacteristic->notify();
}

void sendText(String str) {
  char temp [21]; // 18
  uint16_t len = str.length();
  uint8_t repeat = 1;
  uint8_t endLen = 0;
  if (len > 18) {
     repeat = (len/18)+1;
     endLen = (len%18);
  } else endLen = len;
  for (int r = 0; r < repeat; r++) {
    temp[0] = strHD;
    uint8_t ed = 0;
    if (repeat-r > 1) ed = 18;
    else ed = endLen;
    for (int i = 1; i < ed+1; i++) {
      temp[i] = str[(r*18)+i-1];
    }
    if (repeat-r > 1) temp[ed+1] = echoHD;
    else temp[ed+1] = footHD;
    temp[ed+2] = '\0';
    pTxCharacteristic->setValue(temp); 
    pTxCharacteristic->notify();
  }
}

///////////////////////////////////////// CONNECTION 
void requstDateTime(){ // order disconnect to App 
  uint8_t setVal[3];
  setVal[0] = connectHD;
  setVal[1] = 0x01;
  setVal[2] = 0x00;
  pTxCharacteristic->setValue((uint8_t*)&setVal,3); 
  pTxCharacteristic->notify(); 
}

//#define passName F("PAS:")
//#define pnLength 4
//
//void requestPass(bool val){ // order disconnect to App 
//  uint8_t setVal[3+pnLength];
//  String temp = passName;
//  setVal[0] = connectHD;
//  setVal[1] = 0x02;
//  if (val) {
//    setVal[2] = pnLength;
//    for (int i = 0; i<pnLength;i++) setVal[i+3] = temp[i];
//    pTxCharacteristic->setValue((uint8_t*)&setVal,3+pnLength); 
//  } else {
//    setVal[2] = val;
//    pTxCharacteristic->setValue((uint8_t*)&setVal,3); 
//  }
//  pTxCharacteristic->notify();
//}
//
//void responsePass(bool val){ 
//  uint8_t setVal[3];
//  setVal[0] = connectHD;
//  setVal[1] = 0x03;
//  setVal[2] = val;
//  pTxCharacteristic->setValue((uint8_t*)&setVal,3); 
//  pTxCharacteristic->notify();
//}

void send_message(String str, uint8_t head, uint8_t fn) {
  char temp [21]; // 18
  uint16_t len = str.length();
  uint8_t repeat = 1;
  uint8_t endLen = 0;
  if (len > 17) {
     repeat = (len/17)+1;
     endLen = (len%17);
  } else endLen = len;
  for (int r = 0; r < repeat; r++) {
    temp[0] = head;
    temp[1] = fn;
    uint8_t ed = 0;
    if (repeat-r > 1) ed = 17;
    else ed = endLen;
    for (int i = 2; i < ed+2; i++) {
      temp[i] = str[(r*17)+i-2];
    }
    if (repeat-r > 1) temp[ed+2] = echoHD;
    else temp[ed+2] = footHD;
    temp[ed+3] = '\0';
    pTxCharacteristic->setValue(temp); 
    pTxCharacteristic->notify();
  }
}

void sendMessage(String str) {
  send_message(str, connectHD, 0x04);
}

void sendDisconnect(){ // order disconnect to App 
  uint8_t setVal[3];
  setVal[0] = connectHD;
  setVal[1] = 0x05;
  setVal[2] = 0x00;
  pTxCharacteristic->setValue((uint8_t*)&setVal,3); 
  pTxCharacteristic->notify();
}

///////////////////////////////////////// OPTION
///////////////////////// SET FUNCION
void setActiveSlide(bool val){ 
  uint8_t setVal[4];
  setVal[0] = optionHD;
  setVal[1] = 0x01;
  setVal[2] = val;
  setVal[3] = 0x00;
  pTxCharacteristic->setValue((uint8_t*)&setVal, 4);
  pTxCharacteristic->notify();
}

// SEND SLIDE GET VALUE INTERVAL
void setSlideInterval(uint16_t val){ 
  uint8_t setVal[4];
  setVal[0] = optionHD;
  setVal[1] = 0x02;
  setVal[2] = val;
  setVal[3] = val >> 8;
  pTxCharacteristic->setValue((uint8_t*)&setVal, 4);
  pTxCharacteristic->notify();
}

// 0: not use, 1: show only name, 2: show name & pass // defalult: 2
void setSSIDLabelMode(uint8_t val) { 
  uint8_t setVal[4];
  setVal[0] = optionHD;
  setVal[1] = 0x03;
  setVal[2] = val;
  setVal[3] = 0x00;
  pTxCharacteristic->setValue((uint8_t*)&setVal, 4);
  pTxCharacteristic->notify();
}

void showDialogMenu(bool val){ 
  uint8_t setVal[4];
  setVal[0] = optionHD;
  setVal[1] = 0x04;
  setVal[2] = val;
  setVal[3] = 0x00;
  pTxCharacteristic->setValue((uint8_t*)&setVal, 4);
  pTxCharacteristic->notify();
}

//0: not use 1:color picke 2:color picker+add group 3: pwm nob 4: pwm nob+add group, group1 & group2 Label
void setColorNob(uint8_t val, String group1, String group2, bool pwmDPMain) { 
  String str = String(val); str += ','; 
  str += group1; str += ','; 
  str += group2; str += ',';
  str += pwmDPMain;
  send_message(str, optionHD, 0x05);
}

///////////////////////// SET MAIN DISPLAY
//F("111111111111111"  // button 1 ~ 15, 0:hide 1:display
//  "111111"           // slider 1 ~ 6
//  "11")              // Text Input/Floating Button
void setDisplay(String str){ 
  send_message(str, optionHD, 0x06);
}

//F("BT1,BT2,BT3,BT4,BT5,BT6,BT7,BT8,BT9,BT10,BT11,BT12,BT13,BT14,BT15," // button 1 ~ 15
//  "PW1,PW2,PW3,PW4,PW5,PW6")) // slider 1 ~ 6
void setButtonLabel(String str){ 
  send_message(str, optionHD, 0x07);
}

//F("111111111111111") // button 1 ~ 15, 0:push 1:toggle 
void setButtonToggle(String str){ 
  send_message(str, optionHD, 0x08); 
}

//F("0,255,0,255,0,255,0,255,0,255,0,255")
void setMinMax(String str){ 
  send_message(str, optionHD, 0x09);
}

void setAppTitleMessage(String title, String text){
  String str = title; str += ','; 
  str += text; 
  send_message(str, optionHD, 0x0A);
}

///////////////////////// PERFORM DIALOG
// option = "A,B,C" -> index = 1(A) ~ 3(C)
void dialogRadio(uint8_t id, String title, String option, uint8_t selection){ 
  String str = F("RAD:"); 
  str += String(id); str += ':';
  str += title; str += ':';
  str += option; str += ':';
  str += String(selection);
  send_message(str, optionHD, 0x0B);
} // Return -> RAD:0:1(index) , RAD:id:option index

// option = "A,B,C"
void dialogCheckbox(uint8_t id, String title, String option){ 
  String str = F("CKB:"); 
  str += String(id); str += ':';
  str += title; str += ':';
  str += option; 
  send_message(str, optionHD, 0x0B);
} // Return -> CKB:0:1,3(index) , CKB:id:option index

// option = "A,B"
void dialogChoose(uint8_t id, String message, String option){ 
  String str = F("CHD:"); 
  str += String(id); str += ':'; 
  str += message; str += ':'; 
  str += option; 
  send_message(str, optionHD, 0x0B);
} // Return -> CHD:0:B , CHD:id:option str

// option = "A,B,C,D,E,F,G,H"
void dialogList(uint8_t id, String title, String option){ 
  String str = F("LSD:"); 
  str += String(id); str += ':';
  str += title; str += ':'; 
  str += option; 
  send_message(str, optionHD, 0x0B);
} // Return -> LSD:0:F , LSD:id:option str 

void dialogInput(uint8_t id, String title){ 
  String str = F("STR:"); 
  str += String(id); str += ':'; 
  str += title; 
  send_message(str, optionHD, 0x0B);
} // Return -> STR:0:str , STR:id:str

//////////////////////////////////////////////////////////// INDIVIDUAL
void iniSet() {
  setActiveSlide(true); setSlideInterval(100);
  setSSIDLabelMode(0);
}

// SEND LOCAL STATE AT PRESENT TO APP
void send_State() { // 현재 상태값
  sendPinState(10);
  sendPinState(21);
  sendPinState(30);
  sendPinState(41);
  sendPinState(50);
  sendPinState(61);
  sendPinState(71);
  sendPinState(80);
  sendPinState(91);
  sendPinState(101);
  sendPinState(110);
  sendPinState(121);
  sendPinState(130);
  sendPinState(141);
  sendPinState(150);
  sendPwmSlide(1, 110);
  sendPwmSlide(2, 120);
  sendPwmSlide(3, 210);
  sendPwmSlide(4, 0);
  sendPwmSlide(5, 0);
  sendPwmSlide(6, 0);
}

void btDisconnect() {
  sendDisconnect();
  delay(10);
  pServer->disconnect(pServer->getConnId());
}

void orderDisconnect() { 
  if (needAppCheck) { 
    if (!appConnection) {
      if (millis() - disconnectTime > 3000) {
        needAppCheck = false;
        btDisconnect();
        Serial.println(F("enter app check disconnect"));
      }
    } 
  } 
}

void CheckF8(String temp) {
  if (temp == "") {
    String hd = connectHDstr; 
    if (rxValue[0] == hd[0] && rxValue[1] == hd[1] && rxValue[2] == hd[2] && rxValue[3] == hd[3]) {
      for (int i = hd.length(); i < rxValue.length(); i++) {
        if (rxValue[i] != '\n') temp += rxValue[i];
        else break;
      }
      if (temp == F("connect")) { delay(100); needAppCheck = false; appConnection = true; iniSet(); send_State(); }
    } else { btDisconnect(); needAppCheck = false; }
  } else {
    if (temp == F("disconnect")) appConnection = false; 
    else if (temp.startsWith(F("NA"))) { sendMessage(F("This funtion is not available.")); } 
    else Serial.println(temp);
  }
}

void CheckF9(String temp) {
  Serial.println(temp);
  if (temp.startsWith(F("RAD"))) {  }
  else if (temp.startsWith(F("CKB"))) {  }
  else if (temp.startsWith(F("CHD"))) {  }
  else if (temp.startsWith(F("LSD"))) {  }
  else if (temp.startsWith(F("STR"))) {  }
  else {  
    if (temp.length() < 10) Serial.println(F("alarm"));
    else Serial.println(F("date/time"));
  }
}

 

Example of using Protocol to set ADUCON app

- ADUCON app settings: label/toggle properties, use of the timer for checkHD(0xF5), Slide Mode settings, etc.

void iniSet() {
  setDisplay(F("111111111111111" // button 1 ~ 15, 0:hide 1:display
               "111111"          // slider 1 ~ 6
               "11"));           // Text Input/Floating Button
  setColorNob(0, F("GR1"), F("GR2"), false); // Set Color Picker and Pwm Nob
  setButtonLabel(F("BT1,BT2,BT3,BT4,BT5,BT6,BT7,BT8,BT9,BT10,BT11," // set labels
                   "BT12,BT13,BT14,BT15,PW1,PW2,PW3,PW4,PW5,PW6"));
  setButtonToggle(F("111111111111111")); // button 1 ~ 15, toggle setting, 0:push 1:toggle
  setMinMax(F("0,255,0,255,0,255,0,255,0,255,0,255")); // slider 1 ~ 6
  setAppTitleMessage(F("Test Mode"), // Change title for Arduino code on the app
  F("Arduino<br/>- WiFi Controler<br/><br/>Manual<br/>" //Message
    "<a href='https://postpop.tistory.com/8'>"
    "https://postpop.tistory.com/8</a>"));
  setActiveSlide(true); setSlideInterval(100); // Active Slide Mode
  setSSIDLabelMode(0);   // Set the function of the label displaying Wi-Fi connection
  showDialogMenu(true);  // show menu button
  delay(100); // it need to wait flushing sending buffer if the length of data is too long. 
}

 

- Example of code processing for each function of a button that changes according to the screen number (pageId).

void pin_control(uint8_t value) {
  if (value != 0) {
    switch (value) {
      case 11: if (pageId == 4) Serial.println(F("powor : on"));
               else Serial.println(F("button 1 : on"));
                  break;
      case 10: if (pageId == 4) Serial.println(F("powor : off"));
               else Serial.println(F("button 1 : off"));
                  break;
      case 21: if (pageId == 4) { 
                 Serial.println(F("motor1 : on")); 
                 sendPinState(30); 
               } else Serial.println(F("button 2 : on"));
                  break;
      case 20: if (pageId == 4) Serial.println(F("motor1 : off"));
               else Serial.println(F("button 2 : off"));
                  break;
      case 31: if (pageId == 4) { 
                 Serial.println(F("motor2 : on")); 
                 sendPinState(20); 
               } else Serial.println(F("button 3 : on"));
                  break;
      case 30: if (pageId == 4) Serial.println(F("motor2 : off"));
               else Serial.println(F("button 3 : off"));
                  break;
      case 201: Serial.println(F("button 20 : click"));
                dialogList(0, F("MENU"), F("select,Dial_Nob,Color_Picker,Key_Pad,Arrow_Pad,Main")); // dialog message
                  break;              
    }
  }
}

 

- Example of modifying the function "CheckF9()" that handles dialog messages.

void CheckF9(String temp) {
  Serial.println(temp);
  if (temp.startsWith(F("RAD"))) {  }
  else if (temp.startsWith(F("CKB"))) {  }
  else if (temp.startsWith(F("CHD"))) {  }
  else if (temp.startsWith(F("LSD"))) {  
    int ed = temp.indexOf(':');
    temp.remove(0, ed+1);
    ed = temp.indexOf(':');
    String ID = temp.substring(0, ed);
    uint8_t id = ID.toInt();
    temp.remove(0, ed+1);
    if (id == 0) {
      if (temp.startsWith(F("Dial"))) {
        setDisplay(F("11111111111111111111110")); // hide floating button
        setColorNob(4, F("GR1"), F("GR2"), false); pageId = 1; Serial.println("Dial");
      } else if (temp.startsWith(F("Color"))) {
        setDisplay(F("11111111111111111111110")); // hide floating button
        setColorNob(2, F("GR1"), F("GR2"), false); pageId = 2; Serial.println("color");
      } else if (temp.startsWith(F("Key"))) {
        if (pageId < 2) setColorNob(0, F("GR1"), F("GR2"), false);
        setDisplay(F("11111111111100011111110")); 
        setButtonToggle(F("000000000000111"));
        setButtonLabel(F("1,2,3,4,5,6,7,8,9,*,0,#"));
        pageId = 3;
      } else if (temp.startsWith(F("Arrow"))) {
        if (pageId < 2) setColorNob(0, F("GR1"), F("GR2"), false);
        setDisplay(F("11111101010101011111111")); 
        setButtonToggle(F("111111000000000"));
        setButtonLabel(F("Power,Motor1,Moror2,BT4,BT5,BT6,7,Up,9,Left,0,Right,0,Down"));
        pageId = 4;
      } else {
        if (pageId <= 2) { setColorNob(0, F("GR1"), F("GR2"), false); pageId = 0; }
        setDisplay(F("11111111111111111111111"));
        setButtonToggle(F("111111111111111"));
        setButtonLabel(F("BT1,BT2,BT3,BT4,BT5,BT6,BT7,BT8,BT9,BT10,BT11,BT12,BT13,BT14,BT15"));
        send_State();
        pageId = 0;
      }
    }
  }
  else if (temp.startsWith(F("STR"))) {  }
  else {  
    if (temp.length() < 6) Serial.println(F("alarm"));
    else Serial.println(F("date/time"));
  }
}

 

ESP32_HMI_BLE_CONTROL_MENU.zip

ESP32_HMI_BLE_CONTROL_MENU.zip
0.01MB

 

https://youtu.be/O4jbwZ5k8kM

 

 

Change name for the bluetooth of ESP32 on ADUCON App

 

- Define array variable to save the name for the bluetooth of ESP32.

#include "SPIFFS.h"  
char btName[11] = "ESP32blue";  // 10 char

 

- SPIFFS Setting

bool saveConfig() {   // Write NAME
  String value = btName;
  Serial.println(value);
  File configFile = SPIFFS.open(F("/config.txt"), "w");
  if (!configFile) {
    Serial.println(F("Failed to open config file for writing"));
    return false;
  } else {
    configFile.println(value); // save at config.txt including '\n'
    configFile.close();
    return true;
  }
}

bool loadConfig() { // Read NAME
  File configFile = SPIFFS.open(F("/config.txt"), "r");
  if (!configFile) {
    Serial.println(F("Failed to open config file"));
    return false;
  } else {
    String temp = configFile.readStringUntil('\r');
    for (int i = 0; i < temp.length(); i++) btName[i] = temp[i];
    btName[temp.length()] = '\0';
    configFile.close();
    Serial.println(btName);
    return true;
  }
}

void setup() {
    if (SPIFFS.exists(F("/config.txt"))) loadConfig(); // if there is "/config.txt", read
    else saveConfig();  // if there is not, save a new config.txt 
}

// SPIFFS initialization code at serial monitor
void loop() {
  if(Serial.available()) { // Serial monitor
    String temp = Serial.readStringUntil('\n');
    Serial.println(temp);
    if(temp == "1"){   
      esp_bt_controller_disable();
      Serial.println(F("format..."));
      SPIFFS.format();
      Serial.println(F("done. can start upload."));
      while(1); // stanby for uploading
    } 
  }
}

 

- Save parsing data for name and remove the data for password and send a message applyed in Arduino.

void changeBTname(String str) { 
  bool save = false; 
  String temp = str.substring(0, 1);
  bool delPass = temp.toInt(); // if true, there is data for password which is not used in this sketch 
  str.remove(0, 1);
  if (delPass) str.remove(0, 6); // remove pass
  if (str != btName) {
    if (temp != "") {
      for (int i = 0; i < str.length(); i++) btName[i] = str[i];
      btName[str.length()] = '\0';
      save = true; 
    }
  }
  if (save) {
    saveConfig();
    temp  = F("<p>NAME:  ");
    temp += btName;
    temp += F("</p>Value's Saved.");
    if (delPass) temp += F("<br/>Function of Set pass is not provided.<br/>");
    temp += F(" The module will reboot.<br/>try to reconnect.");
    sendMessage(temp);
    sendDisconnect(); delay(500); ESP.restart();
  } else {
    temp  = F("There's no change.");
    if (delPass) temp += F("<br/>Function of Set pass is not provided.");
    sendMessage(temp);
  }
}

 

ESP32_HMI_BLE_CONTROL_NAME.zip

ESP32_HMI_BLE_CONTROL_NAME.zip
0.01MB

SPIFFS_FORMAT_ESP32.zip

SPIFFS_FORMAT_ESP32.zip
0.00MB

 

https://youtu.be/vS7-YcWAJR4

 

 

App Login

Obtain control authority using the password for BLE of ESP32.

 

- Define array variable to save the name for the bluetooth of ESP32 and the set password for login.

char btName[11] = "ESP32ble";  // 10 char
char pass[7] = "123456";

 

- Password handling code: response message, input prohibition setting, etc.

bool waitPass = false;
uint8_t passAllow = 5;

#define passWaitTime 120000
#define banResetTime 600000

void banReset() {  // if wrong password is entered 5 times, banned inputting for banResetTime
  if (millis() - disconnectTime > banResetTime) passAllow = 5; 
}

void orderDisconnect() { 
  if (!appConnection) {
    if (millis() - disconnectTime > 3000) { // If "%%F8connect" is not confirmed within disconnectTime after receiving the first data through BLE
      needAppCheck = false;
      btDisconnect();
      Serial.println(F("enter app check disconnect"));
    }
  } else if (waitPass) { // if there's no input a pass within passWaitTime, terminate the connection
    if (millis() - disconnectTime > passWaitTime) {
      Serial.println("time over");
      needAppCheck = false; waitPass = false; appConnection = false; 
      sendMessage(F("It's disconnected by time expires.<br/>Try to reconnect."));
      sendDisconnect(); 
    }
  }
}

void CheckF8(String temp) {
  if (temp == "") {
    String hd = connectHDstr; 
    if (rxValue[0] == hd[0] && rxValue[1] == hd[1] && rxValue[2] == hd[2] && rxValue[3] == hd[3]) {
      for (int i = hd.length(); i < rxValue.length(); i++) {
        if (rxValue[i] != '\n') temp += rxValue[i];
        else break;
      }
      if (waitPass) { 
        if (temp.startsWith(passName)) {
          temp.remove(0, pnLength); bool ok = true;
          if (temp.length() == 6) {
            for (int i = 0; i < 6; i++) { if (temp[i] != pass[i]) { ok = false; break; } }
          }
          if (ok) { passOK = true; waitPass = false; needAppCheck = false; iniSet(); send_State(); }  
          else { passAllow--; disconnectTime = millis(); } // wrong password & timer set
          if (!passAllow) { // if wrong password is entered 5 times
            waitPass = false; appConnection = false; 
            sendMessage(F("You've got wrong password 5 times.<br/>Try to reconnect 10 Min later."));
            sendDisconnect(); 
          } else responsePass(ok);
        } else if (temp == F("connect")) { requestPass(usePass); disconnectTime = millis(); } // request pass & timer set
        else if (temp == F("disconnect")) { waitPass = false; needAppCheck = false; appConnection = false; } 
      } else {
        if (temp == F("connect") || temp == F("autoCon")) {
          needAppCheck = false; appConnection = true; 
          if (usePass) { 
            delay(100); requestPass(usePass); 
            waitPass = true; needAppCheck = true; disconnectTime = millis(); 
          } else { iniSet(); send_State(); }
        } 
      }
    } else { btDisconnect(); needAppCheck = false; }
  } else {
    if (temp.startsWith(F("autoCon"))) { needAppCheck = false; } 
    else if (temp == F("disconnect")) { appConnection = false; passOK = false; } 
    else if (temp.startsWith(F("NA"))) { temp.remove(0, 2); changeBTname(temp); }
    else Serial.println(temp);
  }
}

 

ESP32_HMI_BLE_CONTROL_PASS.zip

ESP32_HMI_BLE_CONTROL_PASS.zip
0.01MB

 

https://youtu.be/Q9fUifmNY6M

 

[Arduino/ADUCON] - ADUCON - Arduino wireless remote control application

 

 

 

 

+ Recent posts