diff --git a/.github/ISSUE_TEMPLATE/stale.yml b/.github/ISSUE_TEMPLATE/stale.yml new file mode 100644 index 0000000..2dc5b67 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/stale.yml @@ -0,0 +1,19 @@ +# Number of days of inactivity before an issue becomes stale +daysUntilStale: 60 +# Number of days of inactivity before a stale issue is closed +daysUntilClose: 7 +# Issues with these labels will never be considered stale +exemptLabels: + - pinned + - security + - enhancement + - bug +# Label to use when marking an issue as stale +staleLabel: wontfix +# Comment to post when marking an issue as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +# Comment to post when closing a stale issue. Set to `false` to disable +closeComment: false diff --git a/.travis.yml b/.travis.yml index 64561da..e945e8a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ env: - BD=arduino:avr:mega:cpu=atmega2560 - BD=esp8266:esp8266:nodemcuv2:CpuFrequency=80,FlashSize=4M3M - BD=esp8266:esp8266:d1_mini:CpuFrequency=80,FlashSize=4M3M - - BD=espressif:esp32:esp32doit-devkit-v1:FlashFreq=80 + - BD=espressif:esp32:esp32:PartitionScheme=min_spiffs,FlashFreq=80 before_install: - "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_1.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :1 -ac -screen 0 1280x1024x16" - sleep 3 @@ -22,7 +22,7 @@ install: - cp -R /usr/local/share/arduino/OpenMQTTGateway/lib/. /usr/local/share/arduino/libraries - mkdir -p /usr/local/share/arduino/hardware/espressif - cd /usr/local/share/arduino/hardware/espressif - - wget https://github.com/espressif/arduino-esp32/archive/a153f6ad280e5932be9c80341556348ff505d586.zip -O /tmp/esp32.zip + - wget https://github.com/espressif/arduino-esp32/archive/89859f7f4c07ce3e5d487a4b689dbda78f5d5c3a.zip -O /tmp/esp32.zip - unzip /tmp/esp32.zip -d /usr/local/share/arduino/hardware/espressif - mv arduino-esp32* esp32 - cd esp32/tools/ diff --git a/OpenMQTTGateway.ino b/OpenMQTTGateway.ino index c2aa8bd..f6bc4bf 100644 --- a/OpenMQTTGateway.ino +++ b/OpenMQTTGateway.ino @@ -106,9 +106,12 @@ #ifdef ZgatewayRFM69 #include "config_RFM69.h" #endif - +#ifdef ZsensorGPIOInput + #include "config_GPIOInput.h" +#endif // array to store previous received RFs, IRs codes and their timestamps #if defined(ESP8266) || defined(ESP32) +#define MQTT_MAX_PACKET_SIZE 1024 #define array_size 12 unsigned long ReceivedSignal[array_size][2] ={{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0},{0,0}}; #else @@ -237,11 +240,12 @@ void callback(char* topic, byte* payload, unsigned int length) { void setup() { + //Launch serial for debugging purposes + Serial.begin(SERIAL_BAUD); + #if defined(ESP8266) || defined(ESP32) - //Launch serial for debugging purposes - #if defined(ZgatewaySRFB) || defined(ESP32) - Serial.begin(SERIAL_BAUD); // in the case of sonoff RF Bridge the link to the RF emitter/receiver is made by serial and need TX/RX - #else + #ifdef ESP8266 + Serial.end(); Serial.begin(SERIAL_BAUD, SERIAL_8N1, SERIAL_TX_ONLY); #endif #if defined(ESP8266) && !defined(ESPWifiManualSetup) @@ -249,13 +253,13 @@ void setup() #else // ESP32 case we don't use Wifi manager yet setup_wifi(); #endif - + trc(F("OpenMQTTGateway mac: ")); trc(WiFi.macAddress()); - + trc(F("OpenMQTTGateway ip: ")); - trc(WiFi.localIP()); - + trc(WiFi.localIP().toString()); + // Port defaults to 8266 ArduinoOTA.setPort(ota_port); @@ -373,6 +377,13 @@ void setup() #ifdef ZsensorHCSR501 setupHCSR501(); #endif + #ifdef ZsensorGPIOInput + setupGPIOInput(); + #endif + + trc(F("MQTT_MAX_PACKET_SIZE")); + trc(MQTT_MAX_PACKET_SIZE); + trc(F("Setup OpenMQTTGateway end")); } @@ -519,8 +530,14 @@ void setup_wifimanager(){ #else // Arduino case void setup_ethernet() { - Ethernet.begin(mac, ip); //Comment and uncomment the following line if you want to use advanced network config - //Ethernet.begin(mac, ip, Dns, gateway, subnet); + if (gateway[0] != 0 || Dns[0]!=0) + { + trc(F("Advanced ethernet config")); + Ethernet.begin(mac, ip, Dns, gateway, subnet); + }else{ + trc(F("Simple ethernet config")); + Ethernet.begin(mac, ip); + } trc(F("OpenMQTTGateway ip: ")); Serial.println(Ethernet.localIP()); trc(F("Ethernet ok")); @@ -609,6 +626,9 @@ void loop() #ifdef ZsensorHCSR501 MeasureHCSR501(); #endif + #ifdef ZsensorGPIOInput + MeasureGPIOInput(); + #endif #ifdef ZsensorADC MeasureADC(); //Addon to measure the analog value of analog pin #endif @@ -746,6 +766,9 @@ void stateMeasures(){ #ifdef ZsensorHCSR501 modules = modules + ZsensorHCSR501; #endif + #ifdef ZsensorGPIOInput + modules = modules + ZsensorGPIOInput; + #endif SYSdata["modules"] = modules; trc(modules); char JSONmessageBuffer[100]; diff --git a/README.md b/README.md index 5cf447b..540036a 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ [![Build Status](https://travis-ci.org/1technophile/OpenMQTTGateway.svg?branch=master)](https://travis-ci.org/1technophile/OpenMQTTGateway) -[![Download count](https://img.shields.io/github/downloads/1technophile/OpenMQTTGateway/latest/total.svg)](https://github.com/1technophile/OpenMQTTGateway/releases) +[![Download count](https://img.shields.io/github/downloads/1technophile/OpenMQTTGateway/total.svg)](https://github.com/1technophile/OpenMQTTGateway/releases) [![Community forum](https://img.shields.io/badge/community-forum-brightgreen.svg)](https://community.openmqttgateway.com) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/943c9b639b68441dae8e29ee39977ab2)](https://www.codacy.com/app/1technophile/OpenMQTTGateway?utm_source=github.com&utm_medium=referral&utm_content=1technophile/OpenMQTTGateway&utm_campaign=badger) [![Percentage of issues still open](http://isitmaintained.com/badge/open/1technophile/openmqttgateway.svg)](http://isitmaintained.com/project/1technophile/openmqttgateway "Percentage of issues still open") @@ -20,3 +20,7 @@ Download OpenMQTTGateway from [here](https://github.com/1technophile/OpenMQTTGat A list of supported 433mhz devices is available [here](https://community.home-assistant.io/t/433tomqttto433-gateway-device-list/7819): https://community.home-assistant.io/t/433tomqttto433-gateway-device-list/7819 + +If you want to buy a coffee or other beverage so as to give me some support, here is a way to do it : + +Buy Me A Coffee diff --git a/User_config.h b/User_config.h index a50e53c..4aa666b 100644 --- a/User_config.h +++ b/User_config.h @@ -29,7 +29,7 @@ along with this program. If not, see . */ /*-------------------VERSION----------------------*/ -#define OMG_VERSION "0.8beta" +#define OMG_VERSION "0.8" /*-------------DEFINE YOUR MQTT PARAMETERS BELOW----------------*/ //MQTT Parameters definition @@ -68,9 +68,8 @@ char mqtt_port[6] = "1883"; #endif const byte ip[] = { 192, 168, 1, 99 }; //ip adress -// Advanced network config (optional) if you want to use these parameters uncomment line 158, 172 and comment line 171 of OpenMQTTGateway.ino -const byte gateway[] = { 192, 168, 1, 1 }; //ip adress -const byte Dns[] = { 192, 168, 1, 1 }; //ip adress +const byte gateway[] = { 0, 0, 0, 0 }; //ip adress, if first value is different from 0 advanced config network will be used and you should fill gateway & dns +const byte Dns[] = { 0, 0, 0, 0 }; //ip adress, if first value is different from 0 advanced config network will be used and you should fill gateway & dns const byte subnet[] = { 255, 255, 255, 0 }; //ip adress /*-------------DEFINE YOUR OTA PARAMETERS BELOW----------------*/ @@ -133,4 +132,3 @@ const byte subnet[] = { 255, 255, 255, 0 }; //ip adress /*-------------------ACTIVATE TRACES----------------------*/ #define TRACE 1 // 0= trace off 1 = trace on - diff --git a/ZgatewayBT.ino b/ZgatewayBT.ino index de1df9f..1dc953f 100644 --- a/ZgatewayBT.ino +++ b/ZgatewayBT.ino @@ -82,6 +82,8 @@ Thanks to wolass https://github.com/wolass for suggesting me HM 10 and dinosd ht client.publish((char *)(mactopic + "/tx").c_str(),cTXPower); } if (advertisedDevice.haveServiceData()){ + char mac[mac_adress.length()+1]; + mac_adress.toCharArray(mac,mac_adress.length()+1); trc(F("Get service data ")); std::string serviceData = advertisedDevice.getServiceData(); int serviceDataLength = serviceData.length(); @@ -94,19 +96,22 @@ Thanks to wolass https://github.com/wolass for suggesting me HM 10 and dinosd ht } returnedString = returnedString + String(a,HEX); } - trc(returnedString); - + + char service_data[returnedString.length()+1]; + returnedString.toCharArray(service_data,returnedString.length()+1); + service_data[returnedString.length()] = '\0'; + trc(F("service_data")); + trc(service_data); + String mactopic(mac); + mactopic = subjectBTtoMQTT + mactopic + subjectBTtoMQTTservicedata; + client.publish((char *)mactopic.c_str(),service_data); + trc(F("Get service data UUID")); BLEUUID serviceDataUUID = advertisedDevice.getServiceDataUUID(); trc(serviceDataUUID.toString().c_str()); if (strstr(serviceDataUUID.toString().c_str(),"fe95") != NULL){ trc("Processing BLE device data"); - char service_data[returnedString.length()+1]; - returnedString.toCharArray(service_data,returnedString.length()+1); - service_data[returnedString.length()] = '\0'; - char mac[mac_adress.length()+1]; - mac_adress.toCharArray(mac,mac_adress.length()+1); if (strstr(service_data,"209800") != NULL) { trc("mi flora data reading"); boolean result = process_data(-22,service_data,mac); @@ -157,7 +162,7 @@ Thanks to wolass https://github.com/wolass for suggesting me HM 10 and dinosd ht #else boolean BTtoMQTT(){ unsigned long now = millis(); - if (now > (timeBLE + TimeBtw_Read)) {//retriving value of temperature and humidity of the box from DHT every xUL + if (now > (timeBLE + TimeBtw_Read)) { timeBLE = now; BLEDevice::init(""); BLEScan* pBLEScan = BLEDevice::getScan(); //create new scan @@ -238,13 +243,20 @@ boolean BTtoMQTT() { if((strlen(d[0].extract)) == 12) // if a mac adress is detected we publish it { strupp(d[0].extract); - String mactopic(d[0].extract); - trc(mactopic); - mactopic = subjectBTtoMQTT + mactopic + subjectBTtoMQTTrssi; + String mactopic; + trc(d[0].extract); + trc(d[0].extract); + mactopic = subjectBTtoMQTT + String(d[0].extract) + subjectBTtoMQTTrssi; int rssi = (int)strtol(d[2].extract, NULL, 16) - 256; char val[12]; sprintf(val, "%d", rssi); client.publish((char *)mactopic.c_str(),val); + trc(F("service_data")); + String Service_data(d[5].extract); + Service_data = Service_data.substring(14); + trc(Service_data); + mactopic = subjectBTtoMQTT + String(d[0].extract) + subjectBTtoMQTTservicedata; + client.publish((char *)mactopic.c_str(),(char *)(Service_data).c_str()); if (strcmp(d[4].extract, "fe95") == 0) if (strstr(d[5].extract,"209800") != NULL) { trc("mi flora data reading"); @@ -325,8 +337,6 @@ boolean BTtoMQTT() { #endif boolean process_data(int offset, char * rest_data, char * mac_adress){ - trc(F("rest_data")); - trc(rest_data); int data_length = 0; switch (rest_data[51 + offset]) { case '1' : @@ -353,10 +363,16 @@ boolean process_data(int offset, char * rest_data, char * mac_adress){ char val[12]; String mactopic(mac_adress); mactopic = subjectBTtoMQTT + mactopic; + + // second value + char val2[12]; + String mactopic2(mac_adress); + mactopic2 = subjectBTtoMQTT + mactopic2; + bool hasTopic2 = false; // Mi flora provides tem(perature), (earth) moi(sture), fer(tility) and lux (illuminance) - // Mi Jia provides tem(perature) and hum(idity) + // Mi Jia provides tem(perature), batt(erry) and hum(idity) // following the value of digit 47 we determine the type of data we get from the sensor switch (rest_data[47 + offset]) { case '9' : @@ -381,11 +397,40 @@ boolean process_data(int offset, char * rest_data, char * mac_adress){ mactopic = mactopic + subjectBTtoMQTTmoi; dtostrf(value,0,0,val); break; + + case 'a' : // batteryLevel + mactopic = mactopic + subjectBTtoMQTTbatt; + dtostrf(value,0,0,val); + break; + + case 'd' : // temp+hum + char tempAr[8]; + // humidity + memcpy(tempAr, data, 4); + tempAr[4] = '\0'; + value = strtol(tempAr, NULL, 16); + if (value > 65000) value = value - 65535; + dtostrf(value/10,3,1,val); // hum has to be divided by 10 + trc(val); + // temperature + memcpy(tempAr, &data[4], 4); + tempAr[4] = '\0'; + value = strtol(tempAr, NULL, 16); + if (value > 65000) value = value - 65535; + dtostrf(value/10,3,1,val2); // hum has to be divided by 10 + trc(val2); + mactopic = mactopic + subjectBTtoMQTThum; + mactopic2 = mactopic2 + subjectBTtoMQTTtem; + hasTopic2 = true; + break; default: trc("can't read values"); return false; } - client.publish((char *)mactopic.c_str(),val);; + client.publish((char *)mactopic.c_str(),val); + if (hasTopic2){ + client.publish((char *)mactopic2.c_str(),val2); + } trc(val); return true; } diff --git a/ZgatewayIR.ino b/ZgatewayIR.ino index 7a9c11e..6fd063a 100644 --- a/ZgatewayIR.ino +++ b/ZgatewayIR.ino @@ -31,7 +31,11 @@ #include #include // Needed if you want to send IR commands. #include // Needed if you want to receive IR commands. - IRrecv irrecv(IR_RECEIVER_PIN); + #ifdef DumpMode // in dump mode we increase the size of the buffer to catch big codes + IRrecv irrecv(IR_RECEIVER_PIN, 1024, 15U, true); + #else + IRrecv irrecv(IR_RECEIVER_PIN); + #endif IRsend irsend(IR_EMITTER_PIN); #else #include @@ -39,6 +43,35 @@ IRsend irsend; //connect IR emitter pin to D9 on arduino, you need to comment #define IR_USE_TIMER2 and uncomment #define IR_USE_TIMER1 on library IRremote.h so as to free pin D3 for RF RECEIVER PIN #endif +// IR protocol bits definition for Arduino (for ESP9266 they are defined in IRRemoteESP8266.h) +#ifndef NEC_BITS + #define NEC_BITS 32U +#endif +#ifndef SAMSUNG_BITS + #define SAMSUNG_BITS 32U +#endif +#ifndef SHARP_BITS + #define SHARP_ADDRESS_BITS 5U + #define SHARP_COMMAND_BITS 8U + #define SHARP_BITS (SHARP_ADDRESS_BITS + SHARP_COMMAND_BITS + 2) // 15U +#endif +#ifndef RC5_BITS + #define RC5_RAW_BITS 14U + #define RC5_BITS RC5_RAW_BITS - 2U +#endif +#ifndef DISH_BITS + #define DISH_BITS 16U +#endif +#ifndef SONY_12_BITS + #define SONY_12_BITS 12U +#endif +#ifndef LG_BITS + #define LG_BITS 28U +#endif +#ifndef WHYNTER_BITS + #define WHYNTER_BITS 32U +#endif + void setupIR() { diff --git a/ZsensorGPIOInput.ino b/ZsensorGPIOInput.ino new file mode 100644 index 0000000..563fb2a --- /dev/null +++ b/ZsensorGPIOInput.ino @@ -0,0 +1,79 @@ +/* + OpenMQTTGateway Addon - ESP8266 or Arduino program for home automation + Act as a wifi or ethernet gateway between your 433mhz/infrared IR signal and a MQTT broker + Send and receiving command by MQTT + + GPIO Input derived from HC SR-501 reading Addon and https://www.arduino.cc/en/Tutorial/Debounce + + This reads a high (open) or low (closed) through a circuit (switch, float sensor, etc.) connected to ground. + + Copyright: (c)Florian ROBERT + + Contributors: + - 1technophile + - QuagmireMan + + This file is part of OpenMQTTGateway. + + OpenMQTTGateway is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + OpenMQTTGateway is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#ifdef ZsensorGPIOInput + +unsigned long lastDebounceTime = 0; +int InputState = 3; // Set to 3 so that it reads on startup +int lastInputState = 3; + + +void setupGPIOInput() { + pinMode(GPIOInput_PIN, INPUT_PULLUP); // declare GPIOInput pin as input_pullup to prevent floating. Pin will be high when not connected to ground +} + +void MeasureGPIOInput(){ + int reading = digitalRead(GPIOInput_PIN); + + // check to see if you just pressed the button + // (i.e. the input went from LOW to HIGH), and you've waited long enough + // since the last press to ignore any noise: + + // If the switch changed, due to noise or pressing: + if (reading != lastInputState) { + // reset the debouncing timer + lastDebounceTime = millis(); + + } + + if ((millis() - lastDebounceTime) > GPIOInputDebounceDelay) { + // whatever the reading is at, it's been there for longer than the debounce + // delay, so take it as the actual current state: + #if defined(ESP8266) || defined(ESP32) + yield(); + #endif + // if the Input state has changed: + if (reading != InputState) { + InputState = reading; + + if (InputState == HIGH) { + trc(F("GPIO HIGH")); + client.publish(subjectGPIOInputtoMQTT,"HIGH"); + } + if (InputState == LOW) { + trc(F("GPIO LOW")); + client.publish(subjectGPIOInputtoMQTT,"LOW"); + } + } + } + + // save the reading. Next time through the loop, it'll be the lastInputState: + lastInputState = reading; + +} +#endif diff --git a/config_BT.h b/config_BT.h index af96549..32aff79 100644 --- a/config_BT.h +++ b/config_BT.h @@ -32,6 +32,8 @@ #define subjectBTtoMQTTmoi "/moi" #define subjectBTtoMQTTfer "/fer" #define subjectBTtoMQTTlux "/lux" +#define subjectBTtoMQTTbatt "/batt" +#define subjectBTtoMQTTservicedata "/servicedata" #define TimeBtw_Read 55555 //define the time between 2 scans #define Scan_duration 10 //define the time for a scan #define HM-10 diff --git a/config_GPIOInput.h b/config_GPIOInput.h new file mode 100644 index 0000000..145aba4 --- /dev/null +++ b/config_GPIOInput.h @@ -0,0 +1,38 @@ +/* + OpenMQTTGateway - ESP8266 or Arduino program for home automation + + Act as a wifi or ethernet gateway between your 433mhz/infrared IR signal and a MQTT broker + Send and receiving command by MQTT + + This files enables to set your parameter for the GPIOInput sensor + + Copyright: (c)Florian ROBERT + + This file is part of OpenMQTTGateway. + + OpenMQTTGateway is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenMQTTGateway is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/*----------------------------USER PARAMETERS-----------------------------*/ +/*-------------DEFINE YOUR MQTT PARAMETERS BELOW----------------*/ +#define subjectGPIOInputtoMQTT Base_Topic Gateway_Name "/GPIOInputtoMQTT" +#define GPIOInputDebounceDelay 60 //debounce time, increase if there are issues + +/*-------------------PIN DEFINITIONS----------------------*/ +#if defined(ESP8266) || defined(ESP32) + #define GPIOInput_PIN 5 //D5 +#else + #define GPIOInput_PIN 7 +#endif + diff --git a/config_IR.h b/config_IR.h index 7aff8b9..2b838e8 100644 --- a/config_IR.h +++ b/config_IR.h @@ -39,6 +39,7 @@ #define repeatIRwMQTT false // do we repeat a received signal by using mqtt #define RawDirectForward false // direct repeat of IR signal with raw data #define RawFrequency 38 // raw frequency sending +//#define DumpMode true // uncomment so as to see big dumps of IR codes #define pubIRunknownPrtcl false // key to avoid mqtt publication of unknown IR protocol (set to true if you want to publish unknown protocol) #define PanasonicAddress 0x4004 // Panasonic address (Pre data) @@ -95,7 +96,7 @@ /*-------------------PIN DEFINITIONS----------------------*/ #ifdef ESP8266 #define IR_RECEIVER_PIN 2 - #define IR_EMITTER_PIN 16 + #define IR_EMITTER_PIN 16 // replace by 0 if you use IR LOLIN controller shield #elif ESP32 #define IR_RECEIVER_PIN 27 #define IR_EMITTER_PIN 14 @@ -103,4 +104,3 @@ #define IR_RECEIVER_PIN 0 // 0 = D2 on arduino #define IR_EMITTER_PIN 9 #endif - diff --git a/config_RF.h b/config_RF.h index 7e49cd8..6c4a2d3 100644 --- a/config_RF.h +++ b/config_RF.h @@ -74,9 +74,8 @@ RF supported protocols #define RF_RECEIVER_PIN 13 // D13 on DOIT ESP32 #define RF_EMITTER_PIN 12 // D12 on DOIT ESP32 #else - //IMPORTANT NOTE: On arduino UNO connect IR emitter pin to D9 , comment #define IR_USE_TIMER2 and uncomment #define IR_USE_TIMER1 on library IRremote/IRremoteInt.h so as to free pin D3 for RF RECEIVER PIN + //IMPORTANT NOTE: On arduino UNO connect IR emitter pin to D9 , comment #define IR_USE_TIMER2 and uncomment #define IR_USE_TIMER1 on library IRremote/boarddefs.h so as to free pin D3 for RF RECEIVER PIN //RF PIN definition #define RF_RECEIVER_PIN 1 //1 = D3 on arduino #define RF_EMITTER_PIN 4 //4 = D4 on arduino #endif - diff --git a/img/arduino-esp32-sketchbook.png b/img/arduino-esp32-sketchbook.png new file mode 100644 index 0000000..c7f982f Binary files /dev/null and b/img/arduino-esp32-sketchbook.png differ diff --git a/lib/ESP32_BLE_Arduino/README.md b/lib/ESP32_BLE_Arduino/README.md index d7bcf50..e80fbe0 100644 --- a/lib/ESP32_BLE_Arduino/README.md +++ b/lib/ESP32_BLE_Arduino/README.md @@ -1,5 +1,5 @@ # ESP32 BLE for Arduino -The Arduino IDE provides an excellent library package managed where versions of libraries can be downloaded and installed. This Github project provides the repository for the ESP32 BLE support for Arduino. +The Arduino IDE provides an excellent library package manager where versions of libraries can be downloaded and installed. This Github project provides the repository for the ESP32 BLE support for Arduino. The actual source of the project which is being maintained can be found here: diff --git a/lib/ESP32_BLE_Arduino/examples/BLE_iBeacon/BLE_iBeacon.ino b/lib/ESP32_BLE_Arduino/examples/BLE_iBeacon/BLE_iBeacon.ino new file mode 100644 index 0000000..5f6ed00 --- /dev/null +++ b/lib/ESP32_BLE_Arduino/examples/BLE_iBeacon/BLE_iBeacon.ino @@ -0,0 +1,104 @@ +/* + Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp + Ported to Arduino ESP32 by pcbreflux +*/ + + +/* + Create a BLE server that will send periodic iBeacon frames. + The design of creating the BLE server is: + 1. Create a BLE Server + 2. Create advertising data + 3. Start advertising. + 4. wait + 5. Stop advertising. + 6. deep sleep + +*/ +#include "sys/time.h" + +#include "BLEDevice.h" +#include "BLEServer.h" +#include "BLEUtils.h" +#include "BLEBeacon.h" +#include "esp_sleep.h" + +#define GPIO_DEEP_SLEEP_DURATION 10 // sleep x seconds and then wake up +RTC_DATA_ATTR static time_t last; // remember last boot in RTC Memory +RTC_DATA_ATTR static uint32_t bootcount; // remember number of boots in RTC Memory + +#ifdef __cplusplus +extern "C" { +#endif + +uint8_t temprature_sens_read(); +//uint8_t g_phyFuns; + +#ifdef __cplusplus +} +#endif + +// See the following for generating UUIDs: +// https://www.uuidgenerator.net/ +BLEAdvertising *pAdvertising; +struct timeval now; + +#define BEACON_UUID "8ec76ea3-6668-48da-9866-75be8bc86f4d" // UUID 1 128-Bit (may use linux tool uuidgen or random numbers via https://www.uuidgenerator.net/) + +void setBeacon() { + + BLEBeacon oBeacon = BLEBeacon(); + oBeacon.setManufacturerId(0x4C00); // fake Apple 0x004C LSB (ENDIAN_CHANGE_U16!) + oBeacon.setProximityUUID(BLEUUID(BEACON_UUID)); + oBeacon.setMajor((bootcount & 0xFFFF0000) >> 16); + oBeacon.setMinor(bootcount&0xFFFF); + BLEAdvertisementData oAdvertisementData = BLEAdvertisementData(); + BLEAdvertisementData oScanResponseData = BLEAdvertisementData(); + + oAdvertisementData.setFlags(0x04); // BR_EDR_NOT_SUPPORTED 0x04 + + std::string strServiceData = ""; + + strServiceData += (char)26; // Len + strServiceData += (char)0xFF; // Type + strServiceData += oBeacon.getData(); + oAdvertisementData.addData(strServiceData); + + pAdvertising->setAdvertisementData(oAdvertisementData); + pAdvertising->setScanResponseData(oScanResponseData); + +} + +void setup() { + + + Serial.begin(115200); + gettimeofday(&now, NULL); + + Serial.printf("start ESP32 %d\n",bootcount++); + + Serial.printf("deep sleep (%lds since last reset, %lds since last boot)\n",now.tv_sec,now.tv_sec-last); + + last = now.tv_sec; + + // Create the BLE Device + BLEDevice::init(""); + + // Create the BLE Server + BLEServer *pServer = BLEDevice::createServer(); + + pAdvertising = pServer->getAdvertising(); + + setBeacon(); + // Start advertising + pAdvertising->start(); + Serial.println("Advertizing started..."); + delay(100); + pAdvertising->stop(); + Serial.printf("enter deep sleep\n"); + esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION); + Serial.printf("in deep sleep\n"); +} + +void loop() { +} diff --git a/lib/ESP32_BLE_Arduino/examples/BLE_notify/BLE_notify.ino b/lib/ESP32_BLE_Arduino/examples/BLE_notify/BLE_notify.ino index 8d329c2..5e915be 100644 --- a/lib/ESP32_BLE_Arduino/examples/BLE_notify/BLE_notify.ino +++ b/lib/ESP32_BLE_Arduino/examples/BLE_notify/BLE_notify.ino @@ -23,8 +23,10 @@ #include #include -BLECharacteristic *pCharacteristic; +BLEServer* pServer = NULL; +BLECharacteristic* pCharacteristic = NULL; bool deviceConnected = false; +bool oldDeviceConnected = false; uint8_t value = 0; // See the following for generating UUIDs: @@ -53,7 +55,7 @@ void setup() { BLEDevice::init("MyESP32"); // Create the BLE Server - BLEServer *pServer = BLEDevice::createServer(); + pServer = BLEDevice::createServer(); pServer->setCallbacks(new MyServerCallbacks()); // Create the BLE Service @@ -81,13 +83,23 @@ void setup() { } void loop() { - - if (deviceConnected) { - Serial.printf("*** NOTIFY: %d ***\n", value); - pCharacteristic->setValue(&value, 1); - pCharacteristic->notify(); - //pCharacteristic->indicate(); - value++; - } - delay(2000); + // notify changed value + if (deviceConnected) { + pCharacteristic->setValue(&value, 1); + pCharacteristic->notify(); + value++; + delay(10); // bluetooth stack will go into congestion, if too many packets are sent + } + // 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; + } } \ No newline at end of file diff --git a/lib/ESP32_BLE_Arduino/examples/BLE_uart/BLE_uart.ino b/lib/ESP32_BLE_Arduino/examples/BLE_uart/BLE_uart.ino index a348a66..35b570b 100644 --- a/lib/ESP32_BLE_Arduino/examples/BLE_uart/BLE_uart.ino +++ b/lib/ESP32_BLE_Arduino/examples/BLE_uart/BLE_uart.ino @@ -24,8 +24,10 @@ #include #include -BLECharacteristic *pCharacteristic; +BLEServer *pServer = NULL; +BLECharacteristic * pTxCharacteristic; bool deviceConnected = false; +bool oldDeviceConnected = false; uint8_t txValue = 0; // See the following for generating UUIDs: @@ -70,26 +72,26 @@ void setup() { BLEDevice::init("UART Service"); // Create the BLE Server - BLEServer *pServer = BLEDevice::createServer(); + 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_TX, - BLECharacteristic::PROPERTY_NOTIFY - ); + pTxCharacteristic = pService->createCharacteristic( + CHARACTERISTIC_UUID_TX, + BLECharacteristic::PROPERTY_NOTIFY + ); - pCharacteristic->addDescriptor(new BLE2902()); + pTxCharacteristic->addDescriptor(new BLE2902()); - BLECharacteristic *pCharacteristic = pService->createCharacteristic( - CHARACTERISTIC_UUID_RX, - BLECharacteristic::PROPERTY_WRITE - ); + BLECharacteristic * pRxCharacteristic = pService->createCharacteristic( + CHARACTERISTIC_UUID_RX, + BLECharacteristic::PROPERTY_WRITE + ); - pCharacteristic->setCallbacks(new MyCallbacks()); + pRxCharacteristic->setCallbacks(new MyCallbacks()); // Start the service pService->start(); @@ -101,11 +103,23 @@ void setup() { void loop() { - if (deviceConnected) { - Serial.printf("*** Sent Value: %d ***\n", txValue); - pCharacteristic->setValue(&txValue, 1); - pCharacteristic->notify(); - txValue++; - } - delay(1000); + if (deviceConnected) { + pTxCharacteristic->setValue(&txValue, 1); + pTxCharacteristic->notify(); + txValue++; + delay(10); // bluetooth stack will go into congestion, if too many packets are sent + } + + // 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; + } } diff --git a/lib/ESP32_BLE_Arduino/library.properties b/lib/ESP32_BLE_Arduino/library.properties index fabbf2e..23e642e 100644 --- a/lib/ESP32_BLE_Arduino/library.properties +++ b/lib/ESP32_BLE_Arduino/library.properties @@ -1,5 +1,5 @@ name=ESP32 BLE Arduino -version=0.4.9 +version=0.4.16 author=Neil Kolban maintainer=Neil Kolban sentence=BLE functions for ESP32 diff --git a/lib/ESP32_BLE_Arduino/src/BLEAdvertisedDevice.cpp b/lib/ESP32_BLE_Arduino/src/BLEAdvertisedDevice.cpp index 351c5e1..67603df 100644 --- a/lib/ESP32_BLE_Arduino/src/BLEAdvertisedDevice.cpp +++ b/lib/ESP32_BLE_Arduino/src/BLEAdvertisedDevice.cpp @@ -234,6 +234,7 @@ void BLEAdvertisedDevice::parseAdvertisement(uint8_t* payload) { uint8_t ad_type; uint8_t sizeConsumed = 0; bool finished = false; + setPayload(payload); while(!finished) { length = *payload; // Retrieve the length of the record. @@ -506,7 +507,13 @@ std::string BLEAdvertisedDevice::toString() { return ss.str(); } // toString +uint8_t* BLEAdvertisedDevice::getPayload() { + return m_payload; +} +void BLEAdvertisedDevice::setPayload(uint8_t* payload) { + m_payload = payload; +} #endif /* CONFIG_BT_ENABLED */ diff --git a/lib/ESP32_BLE_Arduino/src/BLEAdvertisedDevice.h b/lib/ESP32_BLE_Arduino/src/BLEAdvertisedDevice.h index 41bc4c6..a3b1e6e 100644 --- a/lib/ESP32_BLE_Arduino/src/BLEAdvertisedDevice.h +++ b/lib/ESP32_BLE_Arduino/src/BLEAdvertisedDevice.h @@ -39,9 +39,10 @@ public: BLEUUID getServiceDataUUID(); BLEUUID getServiceUUID(); int8_t getTXPower(); + uint8_t* getPayload(); - bool isAdvertisingService(BLEUUID uuid); + bool isAdvertisingService(BLEUUID uuid); bool haveAppearance(); bool haveManufacturerData(); bool haveName(); @@ -69,6 +70,7 @@ private: void setServiceUUID(const char* serviceUUID); void setServiceUUID(BLEUUID serviceUUID); void setTXPower(int8_t txPower); + void setPayload(uint8_t* payload); bool m_haveAppearance; @@ -92,6 +94,7 @@ private: int8_t m_txPower; std::string m_serviceData; BLEUUID m_serviceDataUUID; + uint8_t* m_payload; }; /** diff --git a/lib/ESP32_BLE_Arduino/src/BLEAdvertising.cpp b/lib/ESP32_BLE_Arduino/src/BLEAdvertising.cpp index 9e01ab7..4b3cb8d 100644 --- a/lib/ESP32_BLE_Arduino/src/BLEAdvertising.cpp +++ b/lib/ESP32_BLE_Arduino/src/BLEAdvertising.cpp @@ -91,6 +91,16 @@ void BLEAdvertising::setAppearance(uint16_t appearance) { m_advData.appearance = appearance; } // setAppearance +void BLEAdvertising::setMinInterval(uint16_t mininterval) { + m_advData.min_interval = mininterval; + m_advParams.adv_int_min = mininterval; +} // setMinInterval + +void BLEAdvertising::setMaxInterval(uint16_t maxinterval) { + m_advData.max_interval = maxinterval; + m_advParams.adv_int_max = maxinterval; +} // setMaxInterval + /** * @brief Set the filtering for the scan filter. diff --git a/lib/ESP32_BLE_Arduino/src/BLEAdvertising.h b/lib/ESP32_BLE_Arduino/src/BLEAdvertising.h index 003ad1a..e316529 100644 --- a/lib/ESP32_BLE_Arduino/src/BLEAdvertising.h +++ b/lib/ESP32_BLE_Arduino/src/BLEAdvertising.h @@ -29,13 +29,12 @@ public: void setPartialServices(BLEUUID uuid); void setServiceData(BLEUUID uuid, std::string data); void setShortName(std::string name); + void addData(std::string data); // Add data to the payload. + std::string getPayload(); // Retrieve the current advert payload. private: friend class BLEAdvertising; std::string m_payload; // The payload of the advertisement. - - void addData(std::string data); // Add data to the payload. - std::string getPayload(); // Retrieve the current advert payload. }; // BLEAdvertisementData @@ -52,6 +51,8 @@ public: void start(); void stop(); void setAppearance(uint16_t appearance); + void setMaxInterval(uint16_t maxinterval); + void setMinInterval(uint16_t mininterval); void setAdvertisementData(BLEAdvertisementData& advertisementData); void setScanFilter(bool scanRequertWhitelistOnly, bool connectWhitelistOnly); void setScanResponseData(BLEAdvertisementData& advertisementData); diff --git a/lib/ESP32_BLE_Arduino/src/BLECharacteristic.cpp b/lib/ESP32_BLE_Arduino/src/BLECharacteristic.cpp index 5e5aa2a..931c753 100644 --- a/lib/ESP32_BLE_Arduino/src/BLECharacteristic.cpp +++ b/lib/ESP32_BLE_Arduino/src/BLECharacteristic.cpp @@ -683,6 +683,43 @@ void BLECharacteristic::setValue(std::string value) { setValue((uint8_t*)(value.data()), value.length()); } // setValue +void BLECharacteristic::setValue(uint16_t& data16) { + uint8_t temp[2]; + temp[0]=data16; + temp[1]=data16>>8; + setValue(temp, 2); +} // setValue + +void BLECharacteristic::setValue(uint32_t& data32) { + uint8_t temp[4]; + temp[0]=data32; + temp[1]=data32>>8; + temp[2]=data32>>16; + temp[3]=data32>>24; + setValue(temp, 4); +} // setValue + +void BLECharacteristic::setValue(int& data32) { + uint8_t temp[4]; + temp[0]=data32; + temp[1]=data32>>8; + temp[2]=data32>>16; + temp[3]=data32>>24; + setValue(temp, 4); +} // setValue + +void BLECharacteristic::setValue(float& data32) { + uint8_t temp[4]; + *((float *)temp) = data32; + setValue(temp, 4); +} // setValue + +void BLECharacteristic::setValue(double& data64) { + uint8_t temp[8]; + *((double *)temp) = data64; + setValue(temp, 8); +} // setValue + /** * @brief Set the Write No Response property value. diff --git a/lib/ESP32_BLE_Arduino/src/BLECharacteristic.h b/lib/ESP32_BLE_Arduino/src/BLECharacteristic.h index 10dc787..b3f8d2e 100644 --- a/lib/ESP32_BLE_Arduino/src/BLECharacteristic.h +++ b/lib/ESP32_BLE_Arduino/src/BLECharacteristic.h @@ -75,6 +75,11 @@ public: void setReadProperty(bool value); void setValue(uint8_t* data, size_t size); void setValue(std::string value); + void setValue(uint16_t& data16); + void setValue(uint32_t& data32); + void setValue(int& data32); + void setValue(float& data32); + void setValue(double& data64); void setWriteProperty(bool value); void setWriteNoResponseProperty(bool value); std::string toString(); diff --git a/lib/ESP32_BLE_Arduino/src/BLEClient.cpp b/lib/ESP32_BLE_Arduino/src/BLEClient.cpp index 55af054..141cf0f 100644 --- a/lib/ESP32_BLE_Arduino/src/BLEClient.cpp +++ b/lib/ESP32_BLE_Arduino/src/BLEClient.cpp @@ -77,6 +77,7 @@ void BLEClient::clearServices() { delete myPair.second; } m_servicesMap.clear(); + m_haveServices = false; ESP_LOGD(LOG_TAG, "<< clearServices"); } // clearServices @@ -110,6 +111,7 @@ bool BLEClient::connect(BLEAddress address) { errRc = ::esp_ble_gattc_open( getGattcIf(), *getPeerAddress().getNative(), // address + BLE_ADDR_TYPE_PUBLIC, // Note: This was added on 2018-04-03 when the latest ESP-IDF was detected to have changed the signature. 1 // direct connection ); if (errRc != ESP_OK) { @@ -165,6 +167,8 @@ void BLEClient::gattClientEventHandler( m_pClientCallbacks->onDisconnect(this); } m_isConnected = false; + m_semaphoreRssiCmplEvt.give(); + m_semaphoreSearchCmplEvt.give(1); break; } // ESP_GATTC_DISCONNECT_EVT @@ -212,7 +216,7 @@ void BLEClient::gattClientEventHandler( // - uint16_t conn_id // case ESP_GATTC_SEARCH_CMPL_EVT: { - m_semaphoreSearchCmplEvt.give(); + m_semaphoreSearchCmplEvt.give(0); break; } // ESP_GATTC_SEARCH_CMPL_EVT @@ -365,8 +369,8 @@ std::map* BLEClient::getServices() { ESP_LOGE(LOG_TAG, "esp_ble_gattc_search_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); return &m_servicesMap; } - m_semaphoreSearchCmplEvt.wait("getServices"); - m_haveServices = true; // Remember that we now have services. + // If sucessfull, remember that we now have services. + m_haveServices = (m_semaphoreSearchCmplEvt.wait("getServices") == 0); ESP_LOGD(LOG_TAG, "<< getServices"); return &m_servicesMap; } // getServices diff --git a/lib/ESP32_BLE_Arduino/src/BLEDescriptor.cpp b/lib/ESP32_BLE_Arduino/src/BLEDescriptor.cpp index 1a72ef3..58ff78b 100644 --- a/lib/ESP32_BLE_Arduino/src/BLEDescriptor.cpp +++ b/lib/ESP32_BLE_Arduino/src/BLEDescriptor.cpp @@ -155,7 +155,7 @@ void BLEDescriptor::handleGATTServerEvent( (uint32_t)m_pCharacteristic->getService()->getLastCreatedCharacteristic()); */ if (m_pCharacteristic != nullptr && - m_bleUUID.equals(BLEUUID(param->add_char_descr.char_uuid)) && + m_bleUUID.equals(BLEUUID(param->add_char_descr.descr_uuid)) && m_pCharacteristic->getService()->getHandle() == param->add_char_descr.service_handle && m_pCharacteristic == m_pCharacteristic->getService()->getLastCreatedCharacteristic()) { setHandle(param->add_char_descr.attr_handle); diff --git a/lib/ESP32_BLE_Arduino/src/BLEDevice.cpp b/lib/ESP32_BLE_Arduino/src/BLEDevice.cpp index b333ed7..a7db454 100644 --- a/lib/ESP32_BLE_Arduino/src/BLEDevice.cpp +++ b/lib/ESP32_BLE_Arduino/src/BLEDevice.cpp @@ -30,6 +30,7 @@ #include "GeneralUtils.h" #ifdef ARDUINO_ARCH_ESP32 #include "esp32-hal-log.h" +#include "esp32-hal-bt.h" #endif static const char* LOG_TAG = "BLEDevice"; @@ -99,9 +100,11 @@ uint16_t BLEDevice::m_localMTU = 23; switch(event) { case ESP_GATTS_CONNECT_EVT: { BLEDevice::m_localMTU = 23; +#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig if(BLEDevice::m_securityLevel){ esp_ble_set_encryption(param->connect.remote_bda, BLEDevice::m_securityLevel); } +#endif // CONFIG_BLE_SMP_ENABLE break; } // ESP_GATTS_CONNECT_EVT @@ -148,9 +151,11 @@ uint16_t BLEDevice::m_localMTU = 23; ESP_LOGE(LOG_TAG, "esp_ble_gattc_send_mtu_req: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); } } +#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig if(BLEDevice::m_securityLevel){ esp_ble_set_encryption(param->connect.remote_bda, BLEDevice::m_securityLevel); } +#endif // CONFIG_BLE_SMP_ENABLE break; } // ESP_GATTC_CONNECT_EVT @@ -190,16 +195,20 @@ uint16_t BLEDevice::m_localMTU = 23; break; case ESP_GAP_BLE_NC_REQ_EVT: ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_NC_REQ_EVT"); +#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig if(BLEDevice::m_securityCallbacks!=nullptr){ esp_ble_confirm_reply(param->ble_security.ble_req.bd_addr, BLEDevice::m_securityCallbacks->onConfirmPIN(param->ble_security.key_notif.passkey)); } +#endif // CONFIG_BLE_SMP_ENABLE break; case ESP_GAP_BLE_PASSKEY_REQ_EVT: /* passkey request event */ ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PASSKEY_REQ_EVT: "); // esp_log_buffer_hex(LOG_TAG, m_remote_bda, sizeof(m_remote_bda)); +#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig if(BLEDevice::m_securityCallbacks!=nullptr){ esp_ble_passkey_reply(param->ble_security.ble_req.bd_addr, true, BLEDevice::m_securityCallbacks->onPassKeyRequest()); } +#endif // CONFIG_BLE_SMP_ENABLE break; /* * TODO should we add white/black list comparison? @@ -208,12 +217,14 @@ uint16_t BLEDevice::m_localMTU = 23; /* send the positive(true) security response to the peer device to accept the security request. If not accept the security request, should sent the security response with negative(false) accept value*/ ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_SEC_REQ_EVT"); +#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig if(BLEDevice::m_securityCallbacks!=nullptr){ esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, BLEDevice::m_securityCallbacks->onSecurityRequest()); } else{ esp_ble_gap_security_rsp(param->ble_security.ble_req.bd_addr, true); } +#endif // CONFIG_BLE_SMP_ENABLE break; /* * @@ -221,19 +232,27 @@ uint16_t BLEDevice::m_localMTU = 23; case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: ///the app will receive this evt when the IO has Output capability and the peer device IO has Input capability. ///show the passkey number to the user to input it in the peer deivce. ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_PASSKEY_NOTIF_EVT"); +#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig if(BLEDevice::m_securityCallbacks!=nullptr){ ESP_LOGI(LOG_TAG, "passKey = %d", param->ble_security.key_notif.passkey); BLEDevice::m_securityCallbacks->onPassKeyNotify(param->ble_security.key_notif.passkey); } +#endif // CONFIG_BLE_SMP_ENABLE break; case ESP_GAP_BLE_KEY_EVT: //shows the ble key type info share with peer device to the user. + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_KEY_EVT"); +#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig ESP_LOGI(LOG_TAG, "key type = %s", BLESecurity::esp_key_type_to_str(param->ble_security.ble_key.key_type)); +#endif // CONFIG_BLE_SMP_ENABLE break; case ESP_GAP_BLE_AUTH_CMPL_EVT: + ESP_LOGI(LOG_TAG, "ESP_GAP_BLE_AUTH_CMPL_EVT"); +#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig if(BLEDevice::m_securityCallbacks!=nullptr){ BLEDevice::m_securityCallbacks->onAuthenticationComplete(param->ble_security.auth_cmpl); } +#endif // CONFIG_BLE_SMP_ENABLE break; default: { break; @@ -313,14 +332,21 @@ uint16_t BLEDevice::m_localMTU = 23; if(!initialized){ initialized = true; // Set the initialization flag to ensure we are only initialized once. - esp_err_t errRc = ::nvs_flash_init(); + esp_err_t errRc = ESP_OK; +#ifdef ARDUINO_ARCH_ESP32 + if (!btStart()) { + errRc = ESP_FAIL; + return; + } +#else + errRc = ::nvs_flash_init(); if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "nvs_flash_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); return; } - esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); - errRc = esp_bt_controller_init(&bt_cfg); + esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT(); + errRc = esp_bt_controller_init(&bt_cfg); if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "esp_bt_controller_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); return; @@ -340,18 +366,24 @@ uint16_t BLEDevice::m_localMTU = 23; ESP_LOGE(LOG_TAG, "esp_bt_controller_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); return; } +#endif #endif - errRc = esp_bluedroid_init(); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_bluedroid_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; + esp_bluedroid_status_t bt_state = esp_bluedroid_get_status(); + if (bt_state == ESP_BLUEDROID_STATUS_UNINITIALIZED){ + errRc = esp_bluedroid_init(); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_bluedroid_init: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } } - errRc = esp_bluedroid_enable(); - if (errRc != ESP_OK) { - ESP_LOGE(LOG_TAG, "esp_bluedroid_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); - return; + if (bt_state != ESP_BLUEDROID_STATUS_ENABLED){ + errRc = esp_bluedroid_enable(); + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_bluedroid_enable: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } } errRc = esp_ble_gap_register_callback(BLEDevice::gapEventHandler); @@ -382,12 +414,14 @@ uint16_t BLEDevice::m_localMTU = 23; return; }; +#ifdef CONFIG_BLE_SMP_ENABLE // Check that BLE SMP (security) is configured in make menuconfig esp_ble_io_cap_t iocap = ESP_IO_CAP_NONE; errRc = ::esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE, &iocap, sizeof(uint8_t)); if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "esp_ble_gap_set_security_param: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); return; }; +#endif // CONFIG_BLE_SMP_ENABLE } vTaskDelay(200/portTICK_PERIOD_MS); // Delay for 200 msecs as a workaround to an apparent Arduino environment issue. } // init @@ -507,4 +541,8 @@ esp_err_t BLEDevice::setMTU(uint16_t mtu) { uint16_t BLEDevice::getMTU() { return m_localMTU; } + +bool BLEDevice::getInitialized() { + return initialized; +} #endif // CONFIG_BT_ENABLED diff --git a/lib/ESP32_BLE_Arduino/src/BLEDevice.h b/lib/ESP32_BLE_Arduino/src/BLEDevice.h index 7f33143..7a1b833 100644 --- a/lib/ESP32_BLE_Arduino/src/BLEDevice.h +++ b/lib/ESP32_BLE_Arduino/src/BLEDevice.h @@ -42,6 +42,7 @@ public: static void setSecurityCallbacks(BLESecurityCallbacks* pCallbacks); static esp_err_t setMTU(uint16_t mtu); static uint16_t getMTU(); + static bool getInitialized(); // Returns the state of the device, is it initialized or not? private: static BLEServer *m_pServer; diff --git a/lib/ESP32_BLE_Arduino/src/BLEScan.cpp b/lib/ESP32_BLE_Arduino/src/BLEScan.cpp index e450664..3046b7c 100644 --- a/lib/ESP32_BLE_Arduino/src/BLEScan.cpp +++ b/lib/ESP32_BLE_Arduino/src/BLEScan.cpp @@ -74,6 +74,9 @@ void BLEScan::handleGAPEvent( // asked to stop. case ESP_GAP_SEARCH_INQ_CMPL_EVT: { m_stopped = true; + if (m_scanCompleteCB != nullptr) { + m_scanCompleteCB(m_scanResults); + } m_semaphoreScanEnd.give(); break; } // ESP_GAP_SEARCH_INQ_CMPL_EVT @@ -186,12 +189,14 @@ void BLEScan::setWindow(uint16_t windowMSecs) { /** * @brief Start scanning. * @param [in] duration The duration in seconds for which to scan. - * @return N/A. + * @param [in] scanCompleteCB A function to be called when scanning has completed. + * @return True if scan started or false if there was an error. */ -BLEScanResults BLEScan::start(uint32_t duration) { +bool BLEScan::start(uint32_t duration, void (*scanCompleteCB)(BLEScanResults)) { ESP_LOGD(LOG_TAG, ">> start(duration=%d)", duration); m_semaphoreScanEnd.take(std::string("start")); + m_scanCompleteCB = scanCompleteCB; // Save the callback to be invoked when the scan completes. m_scanResults.m_vectorAdvertisedDevices.clear(); @@ -200,7 +205,7 @@ BLEScanResults BLEScan::start(uint32_t duration) { if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "esp_ble_gap_set_scan_params: err: %d, text: %s", errRc, GeneralUtils::errorToString(errRc)); m_semaphoreScanEnd.give(); - return m_scanResults; + return false; } errRc = ::esp_ble_gap_start_scanning(duration); @@ -208,14 +213,25 @@ BLEScanResults BLEScan::start(uint32_t duration) { if (errRc != ESP_OK) { ESP_LOGE(LOG_TAG, "esp_ble_gap_start_scanning: err: %d, text: %s", errRc, GeneralUtils::errorToString(errRc)); m_semaphoreScanEnd.give(); - return m_scanResults; + return false; } m_stopped = false; - m_semaphoreScanEnd.wait("start"); // Wait for the semaphore to release. - ESP_LOGD(LOG_TAG, "<< start()"); + return true; +} // start + + +/** + * @brief Start scanning and block until scanning has been completed. + * @param [in] duration The duration in seconds for which to scan. + * @return The BLEScanResults. + */ +BLEScanResults BLEScan::start(uint32_t duration) { + if(start(duration, nullptr)) { + m_semaphoreScanEnd.wait("start"); // Wait for the semaphore to release. + } return m_scanResults; } // start diff --git a/lib/ESP32_BLE_Arduino/src/BLEScan.h b/lib/ESP32_BLE_Arduino/src/BLEScan.h index c905c43..76c7c7c 100644 --- a/lib/ESP32_BLE_Arduino/src/BLEScan.h +++ b/lib/ESP32_BLE_Arduino/src/BLEScan.h @@ -53,6 +53,7 @@ public: bool wantDuplicates = false); void setInterval(uint16_t intervalMSecs); void setWindow(uint16_t windowMSecs); + bool start(uint32_t duration, void (*scanCompleteCB)(BLEScanResults)); BLEScanResults start(uint32_t duration); void stop(); @@ -71,6 +72,7 @@ private: FreeRTOS::Semaphore m_semaphoreScanEnd = FreeRTOS::Semaphore("ScanEnd"); BLEScanResults m_scanResults; bool m_wantDuplicates; + void (*m_scanCompleteCB)(BLEScanResults scanResults); }; // BLEScan #endif /* CONFIG_BT_ENABLED */ diff --git a/lib/ESP32_BLE_Arduino/src/BLEServer.cpp b/lib/ESP32_BLE_Arduino/src/BLEServer.cpp index 9d26eb5..d5c9de6 100644 --- a/lib/ESP32_BLE_Arduino/src/BLEServer.cpp +++ b/lib/ESP32_BLE_Arduino/src/BLEServer.cpp @@ -18,7 +18,6 @@ #include "BLEUtils.h" #include #include -#include #include #ifdef ARDUINO_ARCH_ESP32 #include "esp32-hal-log.h" @@ -70,21 +69,23 @@ BLEService* BLEServer::createService(const char* uuid) { * of a new service. Every service must have a unique UUID. * @param [in] uuid The UUID of the new service. * @param [in] numHandles The maximum number of handles associated with this service. + * @param [in] inst_id With multiple services with the same UUID we need to provide inst_id value different for each service. * @return A reference to the new service object. */ -BLEService* BLEServer::createService(BLEUUID uuid, uint32_t numHandles) { +BLEService* BLEServer::createService(BLEUUID uuid, uint32_t numHandles, uint8_t inst_id) { ESP_LOGD(LOG_TAG, ">> createService - %s", uuid.toString().c_str()); m_semaphoreCreateEvt.take("createService"); // Check that a service with the supplied UUID does not already exist. if (m_serviceMap.getByUUID(uuid) != nullptr) { - ESP_LOGE(LOG_TAG, "<< Attempt to create a new service with uuid %s but a service with that UUID already exists.", + ESP_LOGW(LOG_TAG, "<< Attempt to create a new service with uuid %s but a service with that UUID already exists.", uuid.toString().c_str()); - m_semaphoreCreateEvt.give(); - return nullptr; + //m_semaphoreCreateEvt.give(); + //return nullptr; } BLEService* pService = new BLEService(uuid, numHandles); + pService->m_id = inst_id; m_serviceMap.setByUUID(uuid, pService); // Save a reference to this service being on this server. pService->executeCreate(this); // Perform the API calls to actually create the service. @@ -322,6 +323,14 @@ void BLEServer::setCallbacks(BLEServerCallbacks* pCallbacks) { m_pServerCallbacks = pCallbacks; } // setCallbacks +/* + * Remove service + */ +void BLEServer::removeService(BLEService *service) { + service->stop(); + service->executeDelete(); + m_serviceMap.removeService(service); +} /** * @brief Start advertising. diff --git a/lib/ESP32_BLE_Arduino/src/BLEServer.h b/lib/ESP32_BLE_Arduino/src/BLEServer.h index bc0ef05..95c55d5 100644 --- a/lib/ESP32_BLE_Arduino/src/BLEServer.h +++ b/lib/ESP32_BLE_Arduino/src/BLEServer.h @@ -40,10 +40,14 @@ public: void setByUUID(const char* uuid, BLEService* service); void setByUUID(BLEUUID uuid, BLEService* service); std::string toString(); + BLEService* getFirst(); + BLEService* getNext(); + void removeService(BLEService *service); private: - std::map m_uuidMap; std::map m_handleMap; + std::map m_uuidMap; + std::map::iterator m_iterator; }; @@ -54,10 +58,11 @@ class BLEServer { public: uint32_t getConnectedCount(); BLEService* createService(const char* uuid); - BLEService* createService(BLEUUID uuid, uint32_t numHandles=15); + BLEService* createService(BLEUUID uuid, uint32_t numHandles=15, uint8_t inst_id=0); BLEAdvertising* getAdvertising(); void setCallbacks(BLEServerCallbacks* pCallbacks); void startAdvertising(); + void removeService(BLEService *service); private: diff --git a/lib/ESP32_BLE_Arduino/src/BLEService.cpp b/lib/ESP32_BLE_Arduino/src/BLEService.cpp index 32bcc57..340ea56 100644 --- a/lib/ESP32_BLE_Arduino/src/BLEService.cpp +++ b/lib/ESP32_BLE_Arduino/src/BLEService.cpp @@ -72,7 +72,8 @@ void BLEService::executeCreate(BLEServer *pServer) { m_semaphoreCreateEvt.take("executeCreate"); // Take the mutex and release at event ESP_GATTS_CREATE_EVT esp_gatt_srvc_id_t srvc_id; - srvc_id.id.inst_id = 0; + srvc_id.is_primary = true; + srvc_id.id.inst_id = m_id; srvc_id.id.uuid = *m_uuid.getNative(); esp_err_t errRc = ::esp_ble_gatts_create_service( getServer()->getGattsIf(), @@ -90,6 +91,28 @@ void BLEService::executeCreate(BLEServer *pServer) { } // executeCreate +/** + * @brief Delete the service. + * Delete the service. + * @return N/A. + */ + +void BLEService::executeDelete() { + ESP_LOGD(LOG_TAG, ">> executeDelete()"); + m_semaphoreDeleteEvt.take("executeDelete"); // Take the mutex and release at event ESP_GATTS_DELETE_EVT + + esp_err_t errRc = ::esp_ble_gatts_delete_service( getHandle() ); + + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "esp_ble_gatts_delete_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + + m_semaphoreDeleteEvt.wait("executeDelete"); + ESP_LOGD(LOG_TAG, "<< executeDelete"); +} // executeDelete + + /** * @brief Dump details of this BLE GATT service. * @return N/A. @@ -152,6 +175,34 @@ void BLEService::start() { } // start +/** + * @brief Stop the service. + * @return Stop the service. + */ +void BLEService::stop() { +// We ask the BLE runtime to start the service and then create each of the characteristics. +// We start the service through its local handle which was returned in the ESP_GATTS_CREATE_EVT event +// obtained as a result of calling esp_ble_gatts_create_service(). +// + ESP_LOGD(LOG_TAG, ">> stop(): Stopping service (esp_ble_gatts_stop_service): %s", toString().c_str()); + if (m_handle == NULL_HANDLE) { + ESP_LOGE(LOG_TAG, "<< !!! We attempted to stop a service but don't know its handle!"); + return; + } + + m_semaphoreStopEvt.take("stop"); + esp_err_t errRc = ::esp_ble_gatts_stop_service(m_handle); + + if (errRc != ESP_OK) { + ESP_LOGE(LOG_TAG, "<< esp_ble_gatts_stop_service: rc=%d %s", errRc, GeneralUtils::errorToString(errRc)); + return; + } + m_semaphoreStopEvt.wait("stop"); + + ESP_LOGD(LOG_TAG, "<< stop()"); +} // start + + /** * @brief Set the handle associated with this service. * @param [in] handle The handle associated with the service. @@ -192,7 +243,7 @@ void BLEService::addCharacteristic(BLECharacteristic* pCharacteristic) { // Check that we don't add the same characteristic twice. if (m_characteristicMap.getByUUID(pCharacteristic->getUUID()) != nullptr) { - ESP_LOGE(LOG_TAG, "<< Attempt to add a characteristic but we already have one with this UUID"); + ESP_LOGW(LOG_TAG, "<< Adding a new characteristic with the same UUID as a previous one"); //return; } @@ -277,6 +328,19 @@ void BLEService::handleGATTServerEvent( break; } // ESP_GATTS_START_EVT + // ESP_GATTS_STOP_EVT + // + // stop: + // esp_gatt_status_t status + // uint16_t service_handle + // + case ESP_GATTS_STOP_EVT: { + if (param->stop.service_handle == getHandle()) { + m_semaphoreStopEvt.give(); + } + break; + } // ESP_GATTS_STOP_EVT + // ESP_GATTS_CREATE_EVT // Called when a new service is registered as having been created. @@ -291,13 +355,28 @@ void BLEService::handleGATTServerEvent( // * - bool is_primary // case ESP_GATTS_CREATE_EVT: { - if (getUUID().equals(BLEUUID(param->create.service_id.id.uuid))) { + if (getUUID().equals(BLEUUID(param->create.service_id.id.uuid)) && m_id == param->create.service_id.id.inst_id) { setHandle(param->create.service_handle); m_semaphoreCreateEvt.give(); } break; } // ESP_GATTS_CREATE_EVT + + // ESP_GATTS_DELETE_EVT + // Called when a service is deleted. + // + // delete: + // * esp_gatt_status_t status + // * uint16_t service_handle + // + case ESP_GATTS_DELETE_EVT: { + if (param->del.service_handle == getHandle()) { + m_semaphoreDeleteEvt.give(); + } + break; + } // ESP_GATTS_DELETE_EVT + default: { break; } // Default diff --git a/lib/ESP32_BLE_Arduino/src/BLEService.h b/lib/ESP32_BLE_Arduino/src/BLEService.h index 2b78e62..93b4b2c 100644 --- a/lib/ESP32_BLE_Arduino/src/BLEService.h +++ b/lib/ESP32_BLE_Arduino/src/BLEService.h @@ -57,13 +57,16 @@ public: BLECharacteristic* createCharacteristic(BLEUUID uuid, uint32_t properties); void dump(); void executeCreate(BLEServer* pServer); + void executeDelete(); BLECharacteristic* getCharacteristic(const char* uuid); BLECharacteristic* getCharacteristic(BLEUUID uuid); BLEUUID getUUID(); BLEServer* getServer(); void start(); + void stop(); std::string toString(); uint16_t getHandle(); + uint8_t m_id = 0; private: BLEService(const char* uuid, uint32_t numHandles); @@ -81,7 +84,9 @@ private: BLEUUID m_uuid; FreeRTOS::Semaphore m_semaphoreCreateEvt = FreeRTOS::Semaphore("CreateEvt"); + FreeRTOS::Semaphore m_semaphoreDeleteEvt = FreeRTOS::Semaphore("DeleteEvt"); FreeRTOS::Semaphore m_semaphoreStartEvt = FreeRTOS::Semaphore("StartEvt"); + FreeRTOS::Semaphore m_semaphoreStopEvt = FreeRTOS::Semaphore("StopEvt"); uint32_t m_numHandles; diff --git a/lib/ESP32_BLE_Arduino/src/BLEServiceMap.cpp b/lib/ESP32_BLE_Arduino/src/BLEServiceMap.cpp index 8fdbd5a..dd828fa 100644 --- a/lib/ESP32_BLE_Arduino/src/BLEServiceMap.cpp +++ b/lib/ESP32_BLE_Arduino/src/BLEServiceMap.cpp @@ -27,8 +27,8 @@ BLEService* BLEServiceMap::getByUUID(const char* uuid) { */ BLEService* BLEServiceMap::getByUUID(BLEUUID uuid) { for (auto &myPair : m_uuidMap) { - if (myPair.second->getUUID().equals(uuid)) { - return myPair.second; + if (myPair.first->getUUID().equals(uuid)) { + return myPair.first; } } //return m_uuidMap.at(uuid.toString()); @@ -54,7 +54,7 @@ BLEService* BLEServiceMap::getByHandle(uint16_t handle) { */ void BLEServiceMap::setByUUID(BLEUUID uuid, BLEService *service) { - m_uuidMap.insert(std::pair(uuid.toString(), service)); + m_uuidMap.insert(std::pair(service, uuid.toString())); } // setByUUID @@ -89,7 +89,44 @@ void BLEServiceMap::handleGATTServerEvent( esp_ble_gatts_cb_param_t *param) { // Invoke the handler for every Service we have. for (auto &myPair : m_uuidMap) { - myPair.second->handleGATTServerEvent(event, gatts_if, param); + myPair.first->handleGATTServerEvent(event, gatts_if, param); } } + +/** + * @brief Get the first service in the map. + * @return The first service in the map. + */ +BLEService* BLEServiceMap::getFirst() { + m_iterator = m_uuidMap.begin(); + if (m_iterator == m_uuidMap.end()) { + return nullptr; + } + BLEService* pRet = m_iterator->first; + m_iterator++; + return pRet; +} // getFirst + +/** + * @brief Get the next service in the map. + * @return The next service in the map. + */ +BLEService* BLEServiceMap::getNext() { + if (m_iterator == m_uuidMap.end()) { + return nullptr; + } + BLEService* pRet = m_iterator->first; + m_iterator++; + return pRet; +} // getNext + +/** + * @brief Removes service from maps. + * @return N/A. + */ +void BLEServiceMap::removeService(BLEService *service){ + m_handleMap.erase(service->getHandle()); + m_uuidMap.erase(service); +} // removeService + #endif /* CONFIG_BT_ENABLED */ diff --git a/lib/ESP32_BLE_Arduino/src/BLEUtils.cpp b/lib/ESP32_BLE_Arduino/src/BLEUtils.cpp index ff4ebfa..a33ee27 100644 --- a/lib/ESP32_BLE_Arduino/src/BLEUtils.cpp +++ b/lib/ESP32_BLE_Arduino/src/BLEUtils.cpp @@ -1654,7 +1654,7 @@ void BLEUtils::dumpGattServerEvent( evtParam->add_char_descr.attr_handle, evtParam->add_char_descr.service_handle, evtParam->add_char_descr.service_handle, - BLEUUID(evtParam->add_char_descr.char_uuid).toString().c_str()); + BLEUUID(evtParam->add_char_descr.descr_uuid).toString().c_str()); break; } // ESP_GATTS_ADD_CHAR_DESCR_EVT diff --git a/lib/WiFiManager/README.md b/lib/WiFiManager/README.md index a329f2b..3782339 100644 --- a/lib/WiFiManager/README.md +++ b/lib/WiFiManager/README.md @@ -1,3 +1,5 @@ +## Current development going on here :arrow_right: [Development Branch](https://github.com/tzapu/WiFiManager/tree/development) + # WiFiManager ESP8266 WiFi Connection manager with fallback web configuration portal @@ -43,16 +45,19 @@ First attempt at a library. Lots more changes and fixes to do. Contributions are ![ESP8266 WiFi Captive Portal Homepage](http://i.imgur.com/YPvW9eql.png) ![ESP8266 WiFi Captive Portal Configuration](http://i.imgur.com/oicWJ4gl.png) ## Wishlist -- ~~remove dependency on EEPROM library~~ -- ~~move HTML Strings to PROGMEM~~ -- ~~cleanup and streamline code~~ (although this is ongoing) -- if timeout is set, extend it when a page is fetched in AP mode -- ~~add ability to configure more parameters than ssid/password~~ -- ~~maybe allow setting ip of ESP after reboot~~ -- ~~add to Arduino Library Manager~~ -- ~~add to PlatformIO~~ -- add multiple sets of network credentials -- ~~allow users to customize CSS~~ +- [x] remove dependency on EEPROM library +- [x] move HTML Strings to PROGMEM +- [x] cleanup and streamline code (although this is ongoing) +- [x] if timeout is set, extend it when a page is fetched in AP mode +- [x] add ability to configure more parameters than ssid/password +- [x] maybe allow setting ip of ESP after reboot +- [x] add to Arduino Library Manager +- [x] add to PlatformIO +- [ ] add multiple sets of network credentials +- [x] allow users to customize CSS +- [ ] ESP32 support or instructions +- [ ] rewrite documentation for simplicity, based on scenarios/goals +- [ ] rely on the SDK's built in auto connect more than forcing a connect ## Quick Start diff --git a/lib/WiFiManager/WiFiManager.cpp b/lib/WiFiManager/WiFiManager.cpp index 3fbbb42..2e7884d 100644 --- a/lib/WiFiManager/WiFiManager.cpp +++ b/lib/WiFiManager/WiFiManager.cpp @@ -5,7 +5,7 @@ inspired by: http://www.esp8266.com/viewtopic.php?f=29&t=2520 https://github.com/chriscook8/esp-arduino-apboot - https://github.com/esp8266/Arduino/tree/esp8266/hardware/esp8266com/esp8266/libraries/DNSServer/examples/CaptivePortalAdvanced + https://github.com/esp8266/Arduino/tree/master/libraries/DNSServer/examples/CaptivePortalAdvanced Built by AlexT https://github.com/tzapu Licensed under MIT license **************************************************************/ @@ -34,7 +34,7 @@ void WiFiManagerParameter::init(const char *id, const char *placeholder, const c _placeholder = placeholder; _length = length; _value = new char[length + 1]; - for (int i = 0; i < length; i++) { + for (int i = 0; i < length + 1; i++) { _value[i] = 0; } if (defaultValue != NULL) { @@ -44,6 +44,12 @@ void WiFiManagerParameter::init(const char *id, const char *placeholder, const c _customHTML = custom; } +WiFiManagerParameter::~WiFiManagerParameter() { + if (_value != NULL) { + delete[] _value; + } +} + const char* WiFiManagerParameter::getValue() { return _value; } @@ -60,14 +66,42 @@ const char* WiFiManagerParameter::getCustomHTML() { return _customHTML; } + WiFiManager::WiFiManager() { + _max_params = WIFI_MANAGER_MAX_PARAMS; + _params = (WiFiManagerParameter**)malloc(_max_params * sizeof(WiFiManagerParameter*)); } -void WiFiManager::addParameter(WiFiManagerParameter *p) { +WiFiManager::~WiFiManager() +{ + if (_params != NULL) + { + DEBUG_WM(F("freeing allocated params!")); + free(_params); + } +} + +bool WiFiManager::addParameter(WiFiManagerParameter *p) { + if(_paramsCount + 1 > _max_params) + { + // rezise the params array + _max_params += WIFI_MANAGER_MAX_PARAMS; + DEBUG_WM(F("Increasing _max_params to:")); + DEBUG_WM(_max_params); + WiFiManagerParameter** new_params = (WiFiManagerParameter**)realloc(_params, _max_params * sizeof(WiFiManagerParameter*)); + if (new_params != NULL) { + _params = new_params; + } else { + DEBUG_WM(F("ERROR: failed to realloc params, size not increased!")); + return false; + } + } + _params[_paramsCount] = p; _paramsCount++; - DEBUG_WM("Adding parameter"); + DEBUG_WM(F("Adding parameter")); DEBUG_WM(p->getID()); + return true; } void WiFiManager::setupConfigPortal() { @@ -109,14 +143,14 @@ void WiFiManager::setupConfigPortal() { dnsServer->start(DNS_PORT, "*", WiFi.softAPIP()); /* Setup web pages: root, wifi config pages, SO captive portal detectors and not found. */ - server->on("/", std::bind(&WiFiManager::handleRoot, this)); - server->on("/wifi", std::bind(&WiFiManager::handleWifi, this, true)); - server->on("/0wifi", std::bind(&WiFiManager::handleWifi, this, false)); - server->on("/wifisave", std::bind(&WiFiManager::handleWifiSave, this)); - server->on("/i", std::bind(&WiFiManager::handleInfo, this)); - server->on("/r", std::bind(&WiFiManager::handleReset, this)); + server->on(String(F("/")), std::bind(&WiFiManager::handleRoot, this)); + server->on(String(F("/wifi")), std::bind(&WiFiManager::handleWifi, this, true)); + server->on(String(F("/0wifi")), std::bind(&WiFiManager::handleWifi, this, false)); + server->on(String(F("/wifisave")), std::bind(&WiFiManager::handleWifiSave, this)); + server->on(String(F("/i")), std::bind(&WiFiManager::handleInfo, this)); + server->on(String(F("/r")), std::bind(&WiFiManager::handleReset, this)); //server->on("/generate_204", std::bind(&WiFiManager::handle204, this)); //Android/Chrome OS captive portal check. - server->on("/fwlink", std::bind(&WiFiManager::handleRoot, this)); //Microsoft captive portal. Maybe not needed. Might be handled by notFound handler. + server->on(String(F("/fwlink")), std::bind(&WiFiManager::handleRoot, this)); //Microsoft captive portal. Maybe not needed. Might be handled by notFound handler. server->onNotFound (std::bind(&WiFiManager::handleNotFound, this)); server->begin(); // Web server start DEBUG_WM(F("HTTP server started")); @@ -149,10 +183,34 @@ boolean WiFiManager::autoConnect(char const *apName, char const *apPassword) { return startConfigPortal(apName, apPassword); } +boolean WiFiManager::configPortalHasTimeout(){ + if(_configPortalTimeout == 0 || wifi_softap_get_station_num() > 0){ + _configPortalStart = millis(); // kludge, bump configportal start time to skew timeouts + return false; + } + return (millis() > _configPortalStart + _configPortalTimeout); +} + +boolean WiFiManager::startConfigPortal() { + String ssid = "ESP" + String(ESP.getChipId()); + return startConfigPortal(ssid.c_str(), NULL); +} + boolean WiFiManager::startConfigPortal(char const *apName, char const *apPassword) { - //setup AP - WiFi.mode(WIFI_AP_STA); - DEBUG_WM("SET AP STA"); + + if(!WiFi.isConnected()){ + WiFi.persistent(false); + // disconnect sta, start ap + WiFi.disconnect(); // this alone is not enough to stop the autoconnecter + WiFi.mode(WIFI_AP); + WiFi.persistent(true); + } + else { + //setup AP + WiFi.mode(WIFI_AP_STA); + DEBUG_WM(F("SET AP STA")); + } + _apName = apName; _apPassword = apPassword; @@ -165,7 +223,11 @@ boolean WiFiManager::startConfigPortal(char const *apName, char const *apPasswo connect = false; setupConfigPortal(); - while (_configPortalTimeout == 0 || millis() < _configPortalStart + _configPortalTimeout) { + while(1){ + + // check if timeout + if(configPortalHasTimeout()) break; + //DNS dnsServer->processNextRequest(); //HTTP @@ -222,7 +284,7 @@ int WiFiManager::connectWifi(String ssid, String pass) { } //fix for auto connect racing issue if (WiFi.status() == WL_CONNECTED) { - DEBUG_WM("Already connected. Bailing out."); + DEBUG_WM(F("Already connected. Bailing out.")); return WL_CONNECTED; } //check if we have ssid and pass and force those, if not, try with last saved values @@ -230,7 +292,7 @@ int WiFiManager::connectWifi(String ssid, String pass) { WiFi.begin(ssid.c_str(), pass.c_str()); } else { if (WiFi.SSID()) { - DEBUG_WM("Using last saved values, should be faster"); + DEBUG_WM(F("Using last saved values, should be faster")); //trying to fix connection in progress hanging ETS_UART_INTR_DISABLE(); wifi_station_disconnect(); @@ -238,7 +300,7 @@ int WiFiManager::connectWifi(String ssid, String pass) { WiFi.begin(); } else { - DEBUG_WM("No saved credentials"); + DEBUG_WM(F("No saved credentials")); } } @@ -246,11 +308,13 @@ int WiFiManager::connectWifi(String ssid, String pass) { DEBUG_WM ("Connection result: "); DEBUG_WM ( connRes ); //not connected, WPS enabled, no pass - first attempt + #ifdef NO_EXTRA_4K_HEAP if (_tryWPS && connRes != WL_CONNECTED && pass == "") { startWPS(); //should be connected at the end of WPS connRes = waitForConnectResult(); } + #endif return connRes; } @@ -278,9 +342,9 @@ uint8_t WiFiManager::waitForConnectResult() { } void WiFiManager::startWPS() { - DEBUG_WM("START WPS"); + DEBUG_WM(F("START WPS")); WiFi.beginWPSConfig(); - DEBUG_WM("END WPS"); + DEBUG_WM(F("END WPS")); } /* String WiFiManager::getSSID() { @@ -362,13 +426,14 @@ void WiFiManager::handleRoot() { page += FPSTR(HTTP_STYLE); page += _customHeadElement; page += FPSTR(HTTP_HEAD_END); - page += "

"; + page += String(F("

")); page += _apName; - page += "

"; - page += F("

WiFiManager

"); + page += String(F("")); + page += String(F("

WiFiManager

")); page += FPSTR(HTTP_PORTAL_OPTIONS); page += FPSTR(HTTP_END); + server->sendHeader("Content-Length", String(page.length())); server->send(200, "text/html", page); } @@ -459,7 +524,7 @@ void WiFiManager::handleWifi(boolean scan) { } page += FPSTR(HTTP_FORM_START); - char parLength[2]; + char parLength[5]; // add the extra parameters to the form for (int i = 0; i < _paramsCount; i++) { if (_params[i] == NULL) { @@ -471,7 +536,7 @@ void WiFiManager::handleWifi(boolean scan) { pitem.replace("{i}", _params[i]->getID()); pitem.replace("{n}", _params[i]->getID()); pitem.replace("{p}", _params[i]->getPlaceholder()); - snprintf(parLength, 2, "%d", _params[i]->getValueLength()); + snprintf(parLength, 5, "%d", _params[i]->getValueLength()); pitem.replace("{l}", parLength); pitem.replace("{v}", _params[i]->getValue()); pitem.replace("{c}", _params[i]->getCustomHTML()); @@ -522,6 +587,7 @@ void WiFiManager::handleWifi(boolean scan) { page += FPSTR(HTTP_END); + server->sendHeader("Content-Length", String(page.length())); server->send(200, "text/html", page); @@ -544,7 +610,7 @@ void WiFiManager::handleWifiSave() { //read parameter String value = server->arg(_params[i]->getID()).c_str(); //store it in array - value.toCharArray(_params[i]->_value, _params[i]->_length); + value.toCharArray(_params[i]->_value, _params[i]->_length + 1); DEBUG_WM(F("Parameter")); DEBUG_WM(_params[i]->getID()); DEBUG_WM(value); @@ -579,6 +645,7 @@ void WiFiManager::handleWifiSave() { page += FPSTR(HTTP_SAVED); page += FPSTR(HTTP_END); + server->sendHeader("Content-Length", String(page.length())); server->send(200, "text/html", page); DEBUG_WM(F("Sent wifi save page")); @@ -621,6 +688,7 @@ void WiFiManager::handleInfo() { page += F(""); page += FPSTR(HTTP_END); + server->sendHeader("Content-Length", String(page.length())); server->send(200, "text/html", page); DEBUG_WM(F("Sent info page")); @@ -638,6 +706,8 @@ void WiFiManager::handleReset() { page += FPSTR(HTTP_HEAD_END); page += F("Module will reset in a few seconds."); page += FPSTR(HTTP_END); + + server->sendHeader("Content-Length", String(page.length())); server->send(200, "text/html", page); DEBUG_WM(F("Sent reset page")); @@ -646,17 +716,6 @@ void WiFiManager::handleReset() { delay(2000); } - - -//removed as mentioned here https://github.com/tzapu/WiFiManager/issues/114 -/*void WiFiManager::handle204() { - DEBUG_WM(F("204 No Response")); - server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); - server->sendHeader("Pragma", "no-cache"); - server->sendHeader("Expires", "-1"); - server->send ( 204, "text/plain", ""); -}*/ - void WiFiManager::handleNotFound() { if (captivePortal()) { // If captive portal redirect instead of displaying the error page. return; @@ -676,6 +735,7 @@ void WiFiManager::handleNotFound() { server->sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); server->sendHeader("Pragma", "no-cache"); server->sendHeader("Expires", "-1"); + server->sendHeader("Content-Length", String(message.length())); server->send ( 404, "text/plain", message ); } @@ -737,7 +797,7 @@ int WiFiManager::getRSSIasQuality(int RSSI) { /** Is this an IP? */ boolean WiFiManager::isIp(String str) { - for (int i = 0; i < str.length(); i++) { + for (size_t i = 0; i < str.length(); i++) { int c = str.charAt(i); if (c != '.' && (c < '0' || c > '9')) { return false; diff --git a/lib/WiFiManager/WiFiManager.h b/lib/WiFiManager/WiFiManager.h index 827c985..3da163e 100644 --- a/lib/WiFiManager/WiFiManager.h +++ b/lib/WiFiManager/WiFiManager.h @@ -5,7 +5,7 @@ inspired by: http://www.esp8266.com/viewtopic.php?f=29&t=2520 https://github.com/chriscook8/esp-arduino-apboot - https://github.com/esp8266/Arduino/tree/esp8266/hardware/esp8266com/esp8266/libraries/DNSServer/examples/CaptivePortalAdvanced + https://github.com/esp8266/Arduino/tree/master/libraries/DNSServer/examples/CaptivePortalAdvanced Built by AlexT https://github.com/tzapu Licensed under MIT license **************************************************************/ @@ -29,19 +29,26 @@ const char HTTP_HEAD_END[] PROGMEM = "
{v} {r}%
"; const char HTTP_FORM_START[] PROGMEM = "


"; -const char HTTP_FORM_PARAM[] PROGMEM = "
"; +const char HTTP_FORM_PARAM[] PROGMEM = "
"; const char HTTP_FORM_END[] PROGMEM = "
"; const char HTTP_SCAN_LINK[] PROGMEM = "
"; const char HTTP_SAVED[] PROGMEM = "
Credentials Saved
Trying to connect ESP to network.
If it fails reconnect to AP to try again
"; const char HTTP_END[] PROGMEM = ""; +#ifndef WIFI_MANAGER_MAX_PARAMS #define WIFI_MANAGER_MAX_PARAMS 10 +#endif class WiFiManagerParameter { public: + /** + Create custom parameters that can be added to the WiFiManager setup web page + @id is used for HTTP queries and must not contain spaces nor other special characters + */ WiFiManagerParameter(const char *custom); WiFiManagerParameter(const char *id, const char *placeholder, const char *defaultValue, int length); WiFiManagerParameter(const char *id, const char *placeholder, const char *defaultValue, int length, const char *custom); + ~WiFiManagerParameter(); const char *getID(); const char *getValue(); @@ -65,11 +72,13 @@ class WiFiManager { public: WiFiManager(); + ~WiFiManager(); boolean autoConnect(); boolean autoConnect(char const *apName, char const *apPassword = NULL); //if you want to always start the config portal, without trying to connect first + boolean startConfigPortal(); boolean startConfigPortal(char const *apName, char const *apPassword = NULL); // get the AP name of the config portal, so it can be used in the callback @@ -78,12 +87,12 @@ class WiFiManager void resetSettings(); //sets timeout before webserver loop ends and exits even if there has been no setup. - //usefully for devices that failed to connect at some point and got stuck in a webserver loop + //useful for devices that failed to connect at some point and got stuck in a webserver loop //in seconds setConfigPortalTimeout is a new name for setTimeout void setConfigPortalTimeout(unsigned long seconds); void setTimeout(unsigned long seconds); - //sets timeout for which to attempt connecting, usefull if you get a lot of failed connects + //sets timeout for which to attempt connecting, useful if you get a lot of failed connects void setConnectTimeout(unsigned long seconds); @@ -98,9 +107,9 @@ class WiFiManager void setAPCallback( void (*func)(WiFiManager*) ); //called when settings have been changed and connection was successful void setSaveConfigCallback( void (*func)(void) ); - //adds a custom parameter - void addParameter(WiFiManagerParameter *p); - //if this is set, it will exit after config, even if connection is unsucessful. + //adds a custom parameter, returns false on failure + bool addParameter(WiFiManagerParameter *p); + //if this is set, it will exit after config, even if connection is unsuccessful. void setBreakAfterConfig(boolean shouldBreak); //if this is set, try WPS setup when starting (this will delay config portal for up to 2 mins) //TODO @@ -159,6 +168,7 @@ class WiFiManager void handleNotFound(); void handle204(); boolean captivePortal(); + boolean configPortalHasTimeout(); // DNS server const byte DNS_PORT = 53; @@ -174,7 +184,8 @@ class WiFiManager void (*_apcallback)(WiFiManager*) = NULL; void (*_savecallback)(void) = NULL; - WiFiManagerParameter* _params[WIFI_MANAGER_MAX_PARAMS]; + int _max_params; + WiFiManagerParameter** _params; template void DEBUG_WM(Generic text); diff --git a/lib/WiFiManager/examples/AutoConnect/AutoConnect.ino b/lib/WiFiManager/examples/AutoConnect/AutoConnect.ino index 37ff392..0c44909 100644 --- a/lib/WiFiManager/examples/AutoConnect/AutoConnect.ino +++ b/lib/WiFiManager/examples/AutoConnect/AutoConnect.ino @@ -17,7 +17,7 @@ void setup() { //wifiManager.resetSettings(); //set custom ip for portal - //wifiManager.setAPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0)); + //wifiManager.setAPStaticIPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0)); //fetches ssid and pass from eeprom and tries to connect //if it does not connect it starts an access point with the specified name diff --git a/lib/WiFiManager/examples/AutoConnectWithFSParameters/AutoConnectWithFSParameters.ino b/lib/WiFiManager/examples/AutoConnectWithFSParameters/AutoConnectWithFSParameters.ino index 1d58e5c..7e6c373 100644 --- a/lib/WiFiManager/examples/AutoConnectWithFSParameters/AutoConnectWithFSParameters.ino +++ b/lib/WiFiManager/examples/AutoConnectWithFSParameters/AutoConnectWithFSParameters.ino @@ -61,6 +61,7 @@ void setup() { } else { Serial.println("failed to load json config"); } + configFile.close(); } } } else { diff --git a/lib/WiFiManager/examples/OnDemandConfigPortal/OnDemandConfigPortal.ino b/lib/WiFiManager/examples/OnDemandConfigPortal/OnDemandConfigPortal.ino index edf4f46..2f2d0cc 100644 --- a/lib/WiFiManager/examples/OnDemandConfigPortal/OnDemandConfigPortal.ino +++ b/lib/WiFiManager/examples/OnDemandConfigPortal/OnDemandConfigPortal.ino @@ -5,7 +5,7 @@ #include #include //https://github.com/tzapu/WiFiManager -// select wich pin will trigger the configuraton portal when set to LOW +// select which pin will trigger the configuration portal when set to LOW // ESP-01 users please note: the only pins available (0 and 2), are shared // with the bootloader, so always set them HIGH at power-up #define TRIGGER_PIN 0 diff --git a/lib/WiFiManager/extras/WiFiManager.template.html b/lib/WiFiManager/extras/WiFiManager.template.html index 0cf8604..e15593b 100644 --- a/lib/WiFiManager/extras/WiFiManager.template.html +++ b/lib/WiFiManager/extras/WiFiManager.template.html @@ -1,38 +1,80 @@ -{v} - + + + + + + {v} + + + + + + + + + + +
+ - -
- - - + -
{v} {r}%
-
PMisa 100%
- -
PMisa 8%
- - - -
- - -


-
-
-

-
-
- + + + + +



+ + +
{v} {r}%
+
PMisa 100%
+ +
PMisa 8%
+ + +
{v} {r}%
+ + +


+ + +
+ + +
+ + +
+ + +
Credentials Saved
Trying to connect ESP to network.
If it fails reconnect to AP to try again
+ + + + + +
- \ No newline at end of file + + + diff --git a/lib/WiFiManager/extras/parse.js b/lib/WiFiManager/extras/parse.js new file mode 100644 index 0000000..97a3e38 --- /dev/null +++ b/lib/WiFiManager/extras/parse.js @@ -0,0 +1,60 @@ +'use strict'; + +const fs = require('fs'); + +console.log('starting'); + +const inFile = 'WiFiManager.template.html'; +const outFile = 'template.h'; + +const defineRegEx = //gm; +console.log('parsing', inFile); + +fs.readFile(inFile, 'utf8', function (err,data) { + if (err) { + return console.log(err); + } + //console.log(data); + + let defines = data.match(defineRegEx); + + //console.log(defines); + var stream = fs.createWriteStream(outFile); + stream.once('open', function(fd) { + for (const i in defines) { + + const start = defines[i]; + const end = start.replace('