diff --git a/lib/libesp32/NimBLE-Arduino/CHANGELOG.md b/lib/libesp32/NimBLE-Arduino/CHANGELOG.md
index e763a3c6d..a76ef59a6 100644
--- a/lib/libesp32/NimBLE-Arduino/CHANGELOG.md
+++ b/lib/libesp32/NimBLE-Arduino/CHANGELOG.md
@@ -2,6 +2,70 @@
All notable changes to this project will be documented in this file.
+## [1.2.0] - 2021-02-08
+
+### Added
+- `NimBLECharacteristic::getDescriptorByHandle`: Return the BLE Descriptor for the given handle.
+
+- `NimBLEDescriptor::getStringValue`: Get the value of this descriptor as a string.
+
+- `NimBLEServer::getServiceByHandle`: Get a service by its handle.
+
+- `NimBLEService::getCharacteristicByHandle`: Get a pointer to the characteristic object with the specified handle.
+
+- `NimBLEService::getCharacteristics`: Get the vector containing pointers to each characteristic associated with this service.
+Overloads to get a vector containing pointers to all the characteristics in a service with the UUID. (supports multiple same UUID's in a service)
+ - `NimBLEService::getCharacteristics(const char *uuid)`
+ - `NimBLEService::getCharacteristics(const NimBLEUUID &uuid)`
+
+- `NimBLEAdvertisementData` New methods:
+ - `NimBLEAdvertisementData::addTxPower`: Adds transmission power to the advertisement.
+ - `NimBLEAdvertisementData::setPreferredParams`: Adds connection parameters to the advertisement.
+ - `NimBLEAdvertisementData::setURI`: Adds URI data to the advertisement.
+
+- `NimBLEAdvertising` New methods:
+ - `NimBLEAdvertising::setName`: Set the name advertised.
+ - `NimBLEAdvertising::setManufacturerData`: Adds manufacturer data to the advertisement.
+ - `NimBLEAdvertising::setURI`: Adds URI data to the advertisement.
+ - `NimBLEAdvertising::setServiceData`: Adds service data to the advertisement.
+ - `NimBLEAdvertising::addTxPower`: Adds transmission power to the advertisement.
+ - `NimBLEAdvertising::reset`: Stops the current advertising and resets the advertising data to the default values.
+
+- `NimBLEDevice::setScanFilterMode`: Set the controller duplicate filter mode for filtering scanned devices.
+
+- `NimBLEDevice::setScanDuplicateCacheSize`: Sets the number of advertisements filtered before the cache is reset.
+
+- `NimBLEScan::setMaxResults`: This allows for setting a maximum number of advertised devices stored in the results vector.
+
+- `NimBLEAdvertisedDevice` New data retrieval methods added:
+ - `haveAdvInterval/getAdvInterval`: checks if the interval is advertised / gets the advertisement interval value.
+
+ - `haveConnParams/getMinInterval/getMaxInterval`: checks if the parameters are advertised / get min value / get max value.
+
+ - `haveURI/getURI`: checks if a URI is advertised / gets the URI data.
+
+ - `haveTargetAddress/getTargetAddressCount/getTargetAddress(index)`: checks if a target address is present / gets a count of the addresses targeted / gets the address of the target at index.
+
+### Changed
+- `nimconfig.h` (Arduino) is now easier to use.
+
+- `NimBLEServer::getServiceByUUID` Now takes an extra parameter of instanceID to support multiple services with the same UUID.
+
+- `NimBLEService::getCharacteristic` Now takes an extra parameter of instanceID to support multiple characteristics with the same UUID.
+
+- `NimBLEAdvertising` Transmission power is no longer advertised by default and can be added to the advertisement by calling `NimBLEAdvertising::addTxPower`
+
+- `NimBLEAdvertising` Custom scan response data can now be used without custom advertisment.
+
+- `NimBLEScan` Now uses the controller duplicate filter.
+
+- `NimBLEAdvertisedDevice` Has been refactored to store the complete advertisement payload and no longer parses the data from each advertisement.
+Instead the data will be parsed on-demand when the user application asks for specific data.
+
+### Fixed
+- `NimBLEHIDDevice` Characteristics now use encryption, this resolves an issue with communicating with devices requiring encryption for HID devices.
+
+
## [1.1.0] - 2021-01-20
### Added
@@ -9,7 +73,7 @@ All notable changes to this project will be documented in this file.
- New examples for securing and authenticating client/server connections, by mblasee.
-- `NimBLEAdvertiseing::SetMinPreferred` and `NimBLEAdvertiseing::SetMinPreferred` re-added.
+- `NimBLEAdvertising::SetMinPreferred` and `NimBLEAdvertising::SetMinPreferred` re-added.
- Conditional checks added for command line config options in `nimconfig.h` to support custom configuration in platformio.
@@ -71,6 +135,7 @@ advertised them as 16/32bit but resolved them to 128bits. Both are now checked.
- (Arduino) Ensure controller mode is set to BLE Only.
+
## [1.0.2] - 2020-09-13
### Changed
@@ -84,6 +149,7 @@ Any changes to the controller max connection settings in `sdkconfig.h` will now
- (Arduino) Revert the previous change to fix the advertising start delay. Instead a replacement fix that routes all BLE controller commands from
a task running on core 0 (same as the controller) has been implemented. This improves response times and reliability for all BLE functions.
+
## [1.0.1] - 2020-09-02
### Added
diff --git a/lib/libesp32/NimBLE-Arduino/docs/Command_line_config.md b/lib/libesp32/NimBLE-Arduino/docs/Command_line_config.md
index 813156f76..c22565f4f 100644
--- a/lib/libesp32/NimBLE-Arduino/docs/Command_line_config.md
+++ b/lib/libesp32/NimBLE-Arduino/docs/Command_line_config.md
@@ -1,93 +1,117 @@
# Arduino command line and platformio config options
-`CONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED`
-
- If defined, NimBLE Client functions will not be included.
-- Reduces flash size by approx. 7kB.
-
+`CONFIG_BT_NIMBLE_MAX_CONNECTIONS`
-`CONFIG_BT_NIMBLE_ROLE_OBSERVER_DISABLED`
+Sets the number of simultaneous connections (esp controller max is 9)
+- Default value is 3
+
-If defined, NimBLE Scan functions will not be included.
-- Reduces flash size by approx. 26kB.
-
+`CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU`
-`CONFIG_BT_NIMBLE_ROLE_PERIPHERAL_DISABLED`
+Sets the default MTU size.
+- Default value is 255
+
-If defined NimBLE Server functions will not be included.
-- Reduces flash size by approx. 16kB.
-
+`CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME`
-`CONFIG_BT_NIMBLE_ROLE_BROADCASTER_DISABLED`
-
-If defined, NimBLE Advertising functions will not be included.
-- Reduces flash size by approx. 5kB.
-
+Set the default device name
+- Default value is "nimble"
+
`CONFIG_BT_NIMBLE_DEBUG`
If defined, enables debug log messages from the NimBLE host
- Uses approx. 32kB of flash memory.
-
+
`CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT`
If defined, NimBLE host return codes will be printed as text in debug log messages.
- Uses approx. 7kB of flash memory.
-
+
`CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT`
If defined, GAP event codes will be printed as text in debug log messages.
- Uses approx. 1kB of flash memory.
-
+
`CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT`
If defined, advertisment types will be printed as text while scanning in debug log messages.
- Uses approx. 250 bytes of flash memory.
-
+
+
+`CONFIG_BT_NIMBLE_SVC_GAP_APPEARANCE`
+
+Set the default appearance.
+- Default value is 0x00
+
+
+`CONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED`
+
+If defined, NimBLE Client functions will not be included.
+- Reduces flash size by approx. 7kB.
+
+
+`CONFIG_BT_NIMBLE_ROLE_OBSERVER_DISABLED`
+
+If defined, NimBLE Scan functions will not be included.
+- Reduces flash size by approx. 26kB.
+
+
+`CONFIG_BT_NIMBLE_ROLE_PERIPHERAL_DISABLED`
+
+If defined NimBLE Server functions will not be included.
+- Reduces flash size by approx. 16kB.
+
+
+`CONFIG_BT_NIMBLE_ROLE_BROADCASTER_DISABLED`
+
+If defined, NimBLE Advertising functions will not be included.
+- Reduces flash size by approx. 5kB.
+
+
+`CONFIG_BT_NIMBLE_MAX_BONDS`
+
+Sets the number of devices allowed to store/bond with
+- Default value is 3
+
+
+`CONFIG_BT_NIMBLE_MAX_CCCDS`
+
+Sets the maximum number of CCCD subscriptions to store
+- Default value is 8
+
+
+`CONFIG_BT_NIMBLE_RPA_TIMEOUT`
+
+Sets the random address refresh time in seconds.
+- Default value is 900
+
+
+`CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT`
+
+Set the number of msys blocks For prepare write & prepare responses. This may need to be increased if
+you are sending large blocks of data with a low MTU. E.g: 512 bytes with 23 MTU will fail.
+- Default value is 12
+
+
+`CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL`
+
+Sets the NimBLE stack to use external PSRAM will be loaded
+- Must be defined with a value of 1; Default is CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL 1
+
`CONFIG_BT_NIMBLE_PINNED_TO_CORE`
Sets the core the NimBLE host stack will run on
- Options: 0 or 1
-
+
`CONFIG_BT_NIMBLE_TASK_STACK_SIZE`
-Set the task stack size for the NimBLE core.
+Set the task stack size for the NimBLE core.
- Default is 4096
-
-
-
-`CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL`
-
-Sets the NimBLE stack to use external PSRAM will be loaded
-- Must be defined with a value of 1; Default is CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL 1
-
-
-`CONFIG_BT_NIMBLE_MAX_CONNECTIONS`
-
-Sets the number of simultaneous connections (esp controller max is 9)
-- Default value is 3
-
-
-`CONFIG_BT_NIMBLE_MAX_BONDS`
-
-Sets the number of devices allowed to store/bond with
-- Default value is 3
-
-
-`CONFIG_BT_NIMBLE_MAX_CCCDS`
-
-Sets the maximum number of CCCD subscriptions to store
-- Default value is 8
-
-
-`CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME`
-
-Set the default device name
-- Default value is "nimble"
-
+
diff --git a/lib/libesp32/NimBLE-Arduino/docs/Migration_guide.md b/lib/libesp32/NimBLE-Arduino/docs/Migration_guide.md
index 69671824a..59854e5fd 100644
--- a/lib/libesp32/NimBLE-Arduino/docs/Migration_guide.md
+++ b/lib/libesp32/NimBLE-Arduino/docs/Migration_guide.md
@@ -69,6 +69,8 @@ For example `BLEServer::createService(SERVICE_UUID)` will work just as it did be
### Characteristics
+The constructor for `(Nim)BLECharacteristic` is now private, so if you currently subclass it to add logic you should switch to use `NimBLEService::createCharacteristic` instead. Any custom processing logic previously in a `BLECharacteristic` subclass should be moved to a `NimBLECharacteristicCallbacks` subclass instead, and passed into `NimBLECharacteristic::setCallbacks`.
+
`BLEService::createCharacteristic` (`NimBLEService::createCharacteristic`) is used the same way as originally except the properties parameter has changed.
When creating a characteristic the properties are now set with `NIMBLE_PROPERTY::XXXX` instead of `BLECharacteristic::XXXX`.
@@ -218,10 +220,11 @@ If you wish to advertise these parameters you can still do so manually via `BLEA
Calling `NimBLEAdvertising::setAdvertisementData` will entirely replace any data set with `NimBLEAdvertising::addServiceUUID`, or
-`NimBLEAdvertising::setAppearance`. You should set all the data you wish to advertise within the `NimBLEAdvertisementData` instead.
+`NimBLEAdvertising::setAppearance` or similar methods. You should set all the data you wish to advertise within the `NimBLEAdvertisementData` instead.
-Calling `NimBLEAdvertising::setScanResponseData` without also calling `NimBLEAdvertising::setAdvertisementData` will have no effect.
-When using custom scan response data you must also use custom advertisement data.
+~~Calling `NimBLEAdvertising::setScanResponseData` without also calling `NimBLEAdvertising::setAdvertisementData` will have no effect.
+When using custom scan response data you must also use custom advertisement data.~~
+No longer true as of release 1.2.0 and above, custom scan response is now supported without custom advertisement data.
> BLEAdvertising::start (NimBLEAdvertising::start)
diff --git a/lib/libesp32/NimBLE-Arduino/docs/Usage_tips.md b/lib/libesp32/NimBLE-Arduino/docs/Usage_tips.md
new file mode 100644
index 000000000..b8edde2de
--- /dev/null
+++ b/lib/libesp32/NimBLE-Arduino/docs/Usage_tips.md
@@ -0,0 +1,41 @@
+# Usage Tips
+
+## Put BLE functions in a task running on the NimBLE stack core
+
+When commands are sent to the stack from a differnt core they can experience delays in execution.
+This library detects this and invokes the esp32 IPC to reroute these commands through the correct core but this also increases overhead.
+Therefore it is highly recommended to create tasks for BLE to run on the same core, the macro `CONFIG_BT_NIMBLE_PINNED_TO_CORE` can be used to set the core.
+
+
+## Do not delete client instances unless necessary or unused
+
+When a client instance has been created and has connected to a peer device and it has retrieved service/characteristic information it will store that data for the life of the client instance.
+If you are periodically connecting to the same devices and you have deleted the client instance or the services when connecting again it will cause a retrieval of that information from the peer again.
+This results in significant energy drain on the battery of the devices, fragments heap, and reduces connection performance.
+
+Client instances in this library use approximately 20% of the original bluedroid library, deleteing them will provide much less gain than it did before.
+
+It is recommended to retain the client instance in cases where the time between connecting to the same device is less than 5 minutes.
+
+
+## Only retrieve the services and characteriscs needed
+
+As a client the use of `NimBLEClient::getServices` or `NimBLERemoteService::getCharacteristics` and using `true` for the parameter should be limited to devices that are not known.
+Instead `NimBLEClient::getService(NimBLEUUID)` or `NimBLERemoteService::getCharacteristic(NimBLEUUID)` should be used to access certain attributes that are useful to the application.
+This reduces energy consumed, heap allocated, connection time and improves overall efficiency.
+
+
+## Check return values
+
+Many user issues can be avoided by checking if a function returned successfully, by either testing for true/false such as when calling `NimBLEClient::connect`,
+or nullptr such as when calling `NimBLEClient::getService`. The latter being a must, as calling a method on a nullptr will surely result in a crash.
+Most of the functions in this library return something that should be checked before proceeding.
+
+
+## There will be bugs - please report them
+
+No code is bug free and unit testing will not find them all on it's own. If you encounter a bug, please report it along with any logs and decoded backtrace if applicable.
+Best efforts will be made to correct any errors ASAP.
+
+Bug reports can be made at https://github.com/h2zero/NimBLE-Arduino/issues or https://github.com/h2zero/esp-nimble-cpp/issues.
+Questions and suggestions will be happily accepted there as well.
diff --git a/lib/libesp32/NimBLE-Arduino/examples/NimBLE_Scan_Continuous/NimBLE_Scan_Continuous.ino b/lib/libesp32/NimBLE-Arduino/examples/NimBLE_Scan_Continuous/NimBLE_Scan_Continuous.ino
new file mode 100644
index 000000000..b8d24d264
--- /dev/null
+++ b/lib/libesp32/NimBLE-Arduino/examples/NimBLE_Scan_Continuous/NimBLE_Scan_Continuous.ino
@@ -0,0 +1,71 @@
+/** Example of continuous scanning for BLE advertisements.
+ * This example will scan forever while consuming as few resources as possible
+ * and report all advertisments on the serial monitor.
+ *
+ * Created: on January 31 2021
+ * Author: H2zero
+ *
+ */
+
+#include "NimBLEDevice.h"
+
+NimBLEScan* pBLEScan;
+
+class MyAdvertisedDeviceCallbacks: public NimBLEAdvertisedDeviceCallbacks {
+ void onResult(NimBLEAdvertisedDevice* advertisedDevice) {
+ Serial.printf("Advertised Device: %s \n", advertisedDevice->toString().c_str());
+ }
+};
+
+void setup() {
+ Serial.begin(115200);
+ Serial.println("Scanning...");
+
+/** *Optional* Sets the filtering mode used by the scanner in the BLE controller.
+ *
+ * Can be one of:
+ * CONFIG_BTDM_SCAN_DUPL_TYPE_DEVICE (0) (default)
+ * Filter by device address only, advertisements from the same address will be reported only once.
+ *
+ * CONFIG_BTDM_SCAN_DUPL_TYPE_DATA (1)
+ * Filter by data only, advertisements with the same data will only be reported once,
+ * even from different addresses.
+ *
+ * CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE (2)
+ * Filter by address and data, advertisements from the same address will be reported only once,
+ * except if the data in the advertisement has changed, then it will be reported again.
+ *
+ * Can only be used BEFORE calling NimBLEDevice::init.
+*/
+ NimBLEDevice::setScanFilterMode(CONFIG_BTDM_SCAN_DUPL_TYPE_DEVICE);
+
+/** *Optional* Sets the scan filter cache size in the BLE controller.
+ * When the number of duplicate advertisements seen by the controller
+ * reaches this value it will clear the cache and start reporting previously
+ * seen devices. The larger this number, the longer time between repeated
+ * device reports. Range 10 - 1000. (default 20)
+ *
+ * Can only be used BEFORE calling NimBLEDevice::init.
+ */
+ NimBLEDevice::setScanDuplicateCacheSize(200);
+
+ NimBLEDevice::init("");
+
+ pBLEScan = NimBLEDevice::getScan(); //create new scan
+ // Set the callback for when devices are discovered, no duplicates.
+ pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks(), false);
+ pBLEScan->setActiveScan(true); // Set active scanning, this will get more data from the advertiser.
+ pBLEScan->setInterval(97); // How often the scan occurs / switches channels; in milliseconds,
+ pBLEScan->setWindow(37); // How long to scan during the interval; in milliseconds.
+ pBLEScan->setMaxResults(0); // do not store the scan results, use callback only.
+}
+
+void loop() {
+ // If an error occurs that stops the scan, it will be restarted here.
+ if(pBLEScan->isScanning() == false) {
+ // Start scan with: duration = 0 seconds(forever), no scan end callback, not a continuation of a previous scan.
+ pBLEScan->start(0, nullptr, false);
+ }
+
+ delay(2000);
+}
\ No newline at end of file
diff --git a/lib/libesp32/NimBLE-Arduino/examples/NimBLE_Service_Data_Advertiser/NimBLE_Service_Data_Advertiser.ino b/lib/libesp32/NimBLE-Arduino/examples/NimBLE_Service_Data_Advertiser/NimBLE_Service_Data_Advertiser.ino
new file mode 100644
index 000000000..dd588fd22
--- /dev/null
+++ b/lib/libesp32/NimBLE-Arduino/examples/NimBLE_Service_Data_Advertiser/NimBLE_Service_Data_Advertiser.ino
@@ -0,0 +1,33 @@
+/** NimBLE_Service_Data_Advertiser Demo:
+ *
+ * Simple demo of advertising service data that changes every 5 seconds
+ *
+ * Created: on February 7 2021
+ * Author: H2zero
+ *
+*/
+
+#include
+
+#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
+
+static NimBLEUUID dataUuid(SERVICE_UUID);
+static NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
+static uint32_t count = 0;
+
+void setup() {
+ Serial.begin(115200);
+ Serial.println("Starting BLE work!");
+
+ NimBLEDevice::init("svc data");
+}
+
+void loop() {
+ pAdvertising->stop();
+ pAdvertising->setServiceData(dataUuid, std::string((char*)&count, sizeof(count)));
+ pAdvertising->start();
+
+ Serial.printf("Advertising count = %d\n", count);
+ count++;
+ delay(5000);
+}
diff --git a/lib/libesp32/NimBLE-Arduino/library.json b/lib/libesp32/NimBLE-Arduino/library.json
index a64024df6..a56985a06 100644
--- a/lib/libesp32/NimBLE-Arduino/library.json
+++ b/lib/libesp32/NimBLE-Arduino/library.json
@@ -2,7 +2,7 @@
"name": "NimBLE-Arduino",
"keywords": "esp32, bluetooth",
"description": "Bluetooth low energy (BLE) library for arduino-esp32 based on NimBLE",
- "version": "1.1.0",
+ "version": "1.2.0",
"frameworks": "arduino",
"platforms": "espressif32"
}
diff --git a/lib/libesp32/NimBLE-Arduino/library.properties b/lib/libesp32/NimBLE-Arduino/library.properties
index 7f2508333..4435958d1 100644
--- a/lib/libesp32/NimBLE-Arduino/library.properties
+++ b/lib/libesp32/NimBLE-Arduino/library.properties
@@ -1,5 +1,5 @@
name=NimBLE-Arduino
-version=1.1.0
+version=1.2.0
author=h2zero
maintainer=h2zero
sentence=Bluetooth low energy (BLE) library for arduino-esp32 based on NimBLE.
diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertisedDevice.cpp b/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertisedDevice.cpp
index 992b1f377..c697fe752 100644
--- a/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertisedDevice.cpp
+++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertisedDevice.cpp
@@ -28,25 +28,14 @@ static const char* LOG_TAG = "NimBLEAdvertisedDevice";
/**
* @brief Constructor
*/
-NimBLEAdvertisedDevice::NimBLEAdvertisedDevice() {
+NimBLEAdvertisedDevice::NimBLEAdvertisedDevice() :
+ m_payload(62,0)
+{
m_advType = 0;
- m_appearance = 0;
- m_manufacturerData = "";
- m_name = "";
m_rssi = -9999;
- m_txPower = 0;
- m_payloadLength = 0;
- m_payload = nullptr;
-
- m_haveAppearance = false;
- m_haveManufacturerData = false;
- m_haveName = false;
- m_haveRSSI = false;
- m_haveServiceData = false;
- m_haveServiceUUID = false;
- m_haveTXPower = false;
- m_callbackSent = false;
-
+ m_callbackSent = false;
+ m_timestamp = 0;
+ m_advLength = 0;
} // NimBLEAdvertisedDevice
@@ -82,25 +71,126 @@ uint8_t NimBLEAdvertisedDevice::getAdvType() {
* @return The appearance of the advertised device.
*/
uint16_t NimBLEAdvertisedDevice::getAppearance() {
- return m_appearance;
+ uint8_t data_loc = 0;
+
+ if(findAdvField(BLE_HS_ADV_TYPE_APPEARANCE, 0, &data_loc) > 0) {
+ ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
+ if(field->length == BLE_HS_ADV_APPEARANCE_LEN + 1) {
+ return *field->value | *(field->value + 1) << 8;
+ }
+ }
+
+ return 0;
} // getAppearance
+/**
+ * @brief Get the advertisement interval.
+ * @return The advertisement interval in 0.625ms units.
+ */
+uint16_t NimBLEAdvertisedDevice::getAdvInterval() {
+ uint8_t data_loc = 0;
+
+ if(findAdvField(BLE_HS_ADV_TYPE_ADV_ITVL, 0, &data_loc) > 0) {
+ ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
+ if(field->length == BLE_HS_ADV_ADV_ITVL_LEN + 1) {
+ return *field->value | *(field->value + 1) << 8;
+ }
+ }
+
+ return 0;
+} // getAdvInterval
+
+
+/**
+ * @brief Get the preferred min connection interval.
+ * @return The preferred min connection interval in 1.25ms units.
+ */
+uint16_t NimBLEAdvertisedDevice::getMinInterval() {
+ uint8_t data_loc = 0;
+
+ if(findAdvField(BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE, 0, &data_loc) > 0) {
+ ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
+ if(field->length == BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN + 1) {
+ return *field->value | *(field->value + 1) << 8;
+ }
+ }
+
+ return 0;
+} // getMinInterval
+
+
+/**
+ * @brief Get the preferred max connection interval.
+ * @return The preferred max connection interval in 1.25ms units.
+ */
+uint16_t NimBLEAdvertisedDevice::getMaxInterval() {
+ uint8_t data_loc = 0;
+
+ if(findAdvField(BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE, 0, &data_loc) > 0) {
+ ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
+ if(field->length == BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN + 1) {
+ return *(field->value + 2) | *(field->value + 3) << 8;
+ }
+ }
+
+ return 0;
+} // getMaxInterval
+
+
/**
* @brief Get the manufacturer data.
* @return The manufacturer data of the advertised device.
*/
std::string NimBLEAdvertisedDevice::getManufacturerData() {
- return m_manufacturerData;
+ uint8_t data_loc = 0;
+
+ if(findAdvField(BLE_HS_ADV_TYPE_MFG_DATA, 0, &data_loc) > 0) {
+ ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
+ if(field->length > 1) {
+ return std::string((char*)field->value, field->length - 1);
+ }
+ }
+
+ return "";
} // getManufacturerData
+/**
+ * @brief Get the URI from the advertisement.
+ * @return The URI data.
+ */
+std::string NimBLEAdvertisedDevice::getURI() {
+ uint8_t data_loc = 0;
+
+ if(findAdvField(BLE_HS_ADV_TYPE_URI, 0, &data_loc) > 0) {
+ ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
+ if(field->length > 1) {
+ return std::string((char*)field->value, field->length - 1);
+ }
+ }
+
+ return "";
+} // getURI
+
+
/**
* @brief Get the advertised name.
* @return The name of the advertised device.
*/
std::string NimBLEAdvertisedDevice::getName() {
- return m_name;
+ uint8_t data_loc = 0;
+
+ if(findAdvField(BLE_HS_ADV_TYPE_COMP_NAME, 0, &data_loc) > 0 ||
+ findAdvField(BLE_HS_ADV_TYPE_INCOMP_NAME, 0, &data_loc) > 0)
+ {
+ ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
+ if(field->length > 1) {
+ return std::string((char*)field->value, field->length - 1);
+ }
+ }
+
+ return "";
} // getName
@@ -122,17 +212,70 @@ NimBLEScan* NimBLEAdvertisedDevice::getScan() {
} // getScan
+/**
+ * @brief Get the number of target addresses.
+ * @return The number of addresses.
+ */
+size_t NimBLEAdvertisedDevice::getTargetAddressCount() {
+ uint8_t count = 0;
+
+ count = findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR);
+ count += findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR);
+
+ return count;
+}
+
+
+/**
+ * @brief Get the target address at the index.
+ * @param [in] index The index of the target address.
+ * @return The target address.
+ */
+NimBLEAddress NimBLEAdvertisedDevice::getTargetAddress(uint8_t index) {
+ ble_hs_adv_field *field = nullptr;
+ uint8_t count = 0;
+ uint8_t data_loc = 0xFF;
+
+ index++;
+ count = findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR, index, &data_loc);
+
+ if (count < index) {
+ index -= count;
+ count = findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR, index, &data_loc);
+ }
+
+ if(count > 0 && data_loc != 0xFF) {
+ field = (ble_hs_adv_field *)&m_payload[data_loc];
+ if(field->length < index * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN) {
+ index -= count - field->length / BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN;
+ }
+ if(field->length > index * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN) {
+ return NimBLEAddress(field->value + (index - 1) * BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN);
+ }
+ }
+
+ return NimBLEAddress("");
+}
+
+
/**
* @brief Get the service data.
- * @param [in] index The vector index of the service data requested.
+ * @param [in] index The index of the service data requested.
* @return The advertised service data or empty string if no data.
*/
std::string NimBLEAdvertisedDevice::getServiceData(uint8_t index) {
- if(index > m_serviceDataVec.size()) {
- NIMBLE_LOGW(LOG_TAG, "getServiceData: index out of range");
- return "";
+ ble_hs_adv_field *field = nullptr;
+ uint8_t bytes;
+ uint8_t data_loc = findServiceData(index, &bytes);
+
+ if(data_loc != 0xFF) {
+ field = (ble_hs_adv_field *)&m_payload[data_loc];
+ if(field->length > bytes) {
+ return std::string((char*)(field->value + bytes), field->length - bytes - 1);
+ }
}
- return m_serviceDataVec[index].second;
+
+ return "";
} //getServiceData
@@ -141,51 +284,148 @@ std::string NimBLEAdvertisedDevice::getServiceData(uint8_t index) {
* @param [in] uuid The uuid of the service data requested.
* @return The advertised service data or empty string if no data.
*/
-std::string NimBLEAdvertisedDevice::getServiceData(const NimBLEUUID &uuid) const {
- for(auto &it : m_serviceDataVec) {
- if(it.first == uuid) {
- return it.second;
+std::string NimBLEAdvertisedDevice::getServiceData(const NimBLEUUID &uuid) {
+ ble_hs_adv_field *field = nullptr;
+ uint8_t bytes;
+ uint8_t index = 0;
+ uint8_t data_loc = findServiceData(index, &bytes);
+ uint8_t uuidBytes = uuid.bitSize() / 8;
+ uint8_t plSize = m_payload.size() - 2;
+
+ while(data_loc < plSize) {
+ field = (ble_hs_adv_field *)&m_payload[data_loc];
+ if(bytes == uuidBytes && NimBLEUUID(field->value, bytes, false) == uuid) {
+ return std::string((char*)(field->value + bytes), field->length - bytes - 1);
}
+
+ index++;
+ data_loc = findServiceData(index, &bytes);
}
- NIMBLE_LOGW(LOG_TAG, "getServiceData: uuid not found");
+
+ NIMBLE_LOGI(LOG_TAG, "No service data found");
return "";
} //getServiceData
/**
- * @brief Get the advertised service UUID.
- * @param [in] index The vector index of the service data UUID requested.
- * @return The advertised service UUID or an empty UUID if not found.
+ * @brief Get the UUID of the serice data at the index.
+ * @param [in] index The index of the service data UUID requested.
+ * @return The advertised service data UUID or an empty UUID if not found.
*/
NimBLEUUID NimBLEAdvertisedDevice::getServiceDataUUID(uint8_t index) {
- if(!haveServiceData() || index > m_serviceDataVec.size()) {
- NIMBLE_LOGW(LOG_TAG, "getServiceDataUUID: index out of range");
- return NimBLEUUID("");
+ ble_hs_adv_field *field = nullptr;
+ uint8_t bytes;
+ uint8_t data_loc = findServiceData(index, &bytes);
+
+ if(data_loc != 0xFF) {
+ field = (ble_hs_adv_field *)&m_payload[data_loc];
+ if(field->length >= bytes) {
+ return NimBLEUUID(field->value, bytes, false);
+ }
}
- return m_serviceDataVec[index].first;
+
+ return NimBLEUUID("");
} // getServiceDataUUID
+/**
+ * @brief Find the service data at the index.
+ * @param [in] index The index of the service data to find.
+ * @param [in] bytes A pointer to storage for the number of the bytes in the UUID.
+ * @return The index in the vector where the data is located, 0xFF if not found.
+ */
+uint8_t NimBLEAdvertisedDevice::findServiceData(uint8_t index, uint8_t *bytes) {
+ uint8_t data_loc = 0;
+ uint8_t found = 0;
+
+ *bytes = 0;
+ index++;
+ found = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID16, index, &data_loc);
+ if(found == index) {
+ *bytes = 2;
+ return data_loc;
+ }
+
+ index -= found;
+ found = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID32, index, &data_loc);
+ if(found == index) {
+ *bytes = 4;
+ return data_loc;
+ }
+
+ index -= found;
+ found = findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID128, index, &data_loc);
+ if(found == index) {
+ *bytes = 16;
+ return data_loc;
+ }
+
+ return 0xFF;
+}
+
+
/**
* @brief Get the count of advertised service data UUIDS
* @return The number of service data UUIDS in the vector.
*/
size_t NimBLEAdvertisedDevice::getServiceDataCount() {
- return m_serviceDataVec.size();
+ uint8_t count = 0;
+
+ count += findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID16);
+ count += findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID32);
+ count += findAdvField(BLE_HS_ADV_TYPE_SVC_DATA_UUID128);
+
+ return count;
} // getServiceDataCount
/**
* @brief Get the Service UUID.
- * @param [in] index The vector index of the service UUID requested.
+ * @param [in] index The index of the service UUID requested.
* @return The Service UUID of the advertised service, or an empty UUID if not found.
*/
NimBLEUUID NimBLEAdvertisedDevice::getServiceUUID(uint8_t index) {
- if(!haveServiceUUID() || index > m_serviceUUIDs.size()) {
- NIMBLE_LOGW(LOG_TAG, "getServiceUUID: index out of range");
- return NimBLEUUID("");
+ uint8_t count = 0;
+ uint8_t data_loc = 0;
+ uint8_t uuidBytes = 0;
+ uint8_t type = BLE_HS_ADV_TYPE_INCOMP_UUIDS16;
+ ble_hs_adv_field *field = nullptr;
+
+ index++;
+
+ do {
+ count = findAdvField(type, index, &data_loc);
+ if(count >= index) {
+ if(type < BLE_HS_ADV_TYPE_INCOMP_UUIDS32) {
+ uuidBytes = 2;
+ } else if(type < BLE_HS_ADV_TYPE_INCOMP_UUIDS128) {
+ uuidBytes = 4;
+ } else {
+ uuidBytes = 16;
+ }
+ break;
+
+ } else {
+ type++;
+ index -= count;
+ }
+
+ } while(type <= BLE_HS_ADV_TYPE_COMP_UUIDS128);
+
+ if(uuidBytes > 0) {
+ field = (ble_hs_adv_field *)&m_payload[data_loc];
+ // In the case of more than one field of service uuid's we need to adjust
+ // the index to account for the uuids of the previous fields.
+ if(field->length < index * uuidBytes) {
+ index -= count - field->length / uuidBytes;
+ }
+
+ if(field->length > uuidBytes * index) {
+ return NimBLEUUID(field->value + uuidBytes * (index - 1), uuidBytes, false);
+ }
}
- return m_serviceUUIDs[index];
+
+ return NimBLEUUID("");
} // getServiceUUID
@@ -194,18 +434,32 @@ NimBLEUUID NimBLEAdvertisedDevice::getServiceUUID(uint8_t index) {
* @return The count of services in the advertising packet.
*/
size_t NimBLEAdvertisedDevice::getServiceUUIDCount() {
- return m_serviceUUIDs.size();
+ uint8_t count = 0;
+
+ count += findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS16);
+ count += findAdvField(BLE_HS_ADV_TYPE_COMP_UUIDS16);
+ count += findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS32);
+ count += findAdvField(BLE_HS_ADV_TYPE_COMP_UUIDS32);
+ count += findAdvField(BLE_HS_ADV_TYPE_INCOMP_UUIDS128);
+ count += findAdvField(BLE_HS_ADV_TYPE_COMP_UUIDS128);
+
+ return count;
} // getServiceUUIDCount
/**
* @brief Check advertised services for existance of the required UUID
+ * @param [in] uuid The service uuid to look for in the advertisement.
* @return Return true if service is advertised
*/
-bool NimBLEAdvertisedDevice::isAdvertisingService(const NimBLEUUID &uuid) const {
- for (int i = 0; i < m_serviceUUIDs.size(); i++) {
- if (m_serviceUUIDs[i].equals(uuid)) return true;
+bool NimBLEAdvertisedDevice::isAdvertisingService(const NimBLEUUID &uuid) {
+ size_t count = getServiceUUIDCount();
+ for(size_t i = 0; i < count; i++) {
+ if(uuid == getServiceUUID(i)) {
+ return true;
+ }
}
+
return false;
} // isAdvertisingService
@@ -215,16 +469,43 @@ bool NimBLEAdvertisedDevice::isAdvertisingService(const NimBLEUUID &uuid) const
* @return The TX Power of the advertised device.
*/
int8_t NimBLEAdvertisedDevice::getTXPower() {
- return m_txPower;
+ uint8_t data_loc = 0;
+
+ if(findAdvField(BLE_HS_ADV_TYPE_TX_PWR_LVL, 0, &data_loc) > 0) {
+ ble_hs_adv_field *field = (ble_hs_adv_field *)&m_payload[data_loc];
+ if(field->length == BLE_HS_ADV_TX_PWR_LVL_LEN + 1) {
+ return *(int8_t*)field->value;
+ }
+ }
+
+ return -99;
} // getTXPower
+/**
+ * @brief Does this advertisement have preferred connection parameters?
+ * @return True if connection parameters are present.
+ */
+bool NimBLEAdvertisedDevice::haveConnParams() {
+ return findAdvField(BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE) > 0;
+} // haveConnParams
+
+
+/**
+ * @brief Does this advertisement have have the advertising interval?
+ * @return True if the advertisement interval is present.
+ */
+bool NimBLEAdvertisedDevice::haveAdvInterval() {
+ return findAdvField(BLE_HS_ADV_TYPE_ADV_ITVL) > 0;
+} // haveAdvInterval
+
+
/**
* @brief Does this advertisement have an appearance value?
* @return True if there is an appearance value present.
*/
bool NimBLEAdvertisedDevice::haveAppearance() {
- return m_haveAppearance;
+ return findAdvField(BLE_HS_ADV_TYPE_APPEARANCE) > 0;
} // haveAppearance
@@ -233,16 +514,36 @@ bool NimBLEAdvertisedDevice::haveAppearance() {
* @return True if there is manufacturer data present.
*/
bool NimBLEAdvertisedDevice::haveManufacturerData() {
- return m_haveManufacturerData;
+ return findAdvField(BLE_HS_ADV_TYPE_MFG_DATA) > 0;
} // haveManufacturerData
+/**
+ * @brief Does this advertisement have a URI?
+ * @return True if there is a URI present.
+ */
+bool NimBLEAdvertisedDevice::haveURI() {
+ return findAdvField(BLE_HS_ADV_TYPE_URI) > 0;
+} // haveURI
+
+
+/**
+ * @brief Does the advertisement contain a target address?
+ * @return True if an address is present.
+ */
+bool NimBLEAdvertisedDevice::haveTargetAddress() {
+ return findAdvField(BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR) > 0 ||
+ findAdvField(BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR) > 0;
+}
+
+
/**
* @brief Does this advertisement have a name value?
* @return True if there is a name value present.
*/
bool NimBLEAdvertisedDevice::haveName() {
- return m_haveName;
+ return findAdvField(BLE_HS_ADV_TYPE_COMP_NAME) > 0 ||
+ findAdvField(BLE_HS_ADV_TYPE_INCOMP_NAME) > 0;
} // haveName
@@ -251,7 +552,7 @@ bool NimBLEAdvertisedDevice::haveName() {
* @return True if there is a signal strength value present.
*/
bool NimBLEAdvertisedDevice::haveRSSI() {
- return m_haveRSSI;
+ return m_rssi != -9999;
} // haveRSSI
@@ -260,7 +561,7 @@ bool NimBLEAdvertisedDevice::haveRSSI() {
* @return True if there is a service data value present.
*/
bool NimBLEAdvertisedDevice::haveServiceData() {
- return m_haveServiceData;
+ return getServiceDataCount() > 0;
} // haveServiceData
@@ -269,7 +570,7 @@ bool NimBLEAdvertisedDevice::haveServiceData() {
* @return True if there is a service UUID value present.
*/
bool NimBLEAdvertisedDevice::haveServiceUUID() {
- return m_haveServiceUUID;
+ return getServiceUUIDCount() > 0;
} // haveServiceUUID
@@ -278,143 +579,71 @@ bool NimBLEAdvertisedDevice::haveServiceUUID() {
* @return True if there is a transmission power value present.
*/
bool NimBLEAdvertisedDevice::haveTXPower() {
- return m_haveTXPower;
+ return findAdvField(BLE_HS_ADV_TYPE_TX_PWR_LVL) > 0;
} // haveTXPower
-/**
- * @brief Parse the advertising pay load.
- *
- * The pay load is a buffer of bytes that is either 31 bytes long or terminated by
- * a 0 length value. Each entry in the buffer has the format:
- * [length][type][data...]
- *
- * The length does not include itself but does include everything after it until the next record. A record
- * with a length value of 0 indicates a terminator.
- *
- * https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile
- */
- void NimBLEAdvertisedDevice::parseAdvertisement(uint8_t* payload, uint8_t length) {
- struct ble_hs_adv_fields fields;
- int rc = ble_hs_adv_parse_fields(&fields, payload, length);
- if (rc != 0) {
- NIMBLE_LOGE(LOG_TAG, "Gap Event Parse ERROR.");
- return;
+uint8_t NimBLEAdvertisedDevice::findAdvField(uint8_t type, uint8_t index, uint8_t *data_loc) {
+ ble_hs_adv_field *field = nullptr;
+ uint8_t data = 0;
+ uint8_t length = m_payload.size();
+ uint8_t count = 0;
+
+ if(length < 2) {
+ return count;
}
- m_payload = payload;
- m_payloadLength = length;
+ while (length > 1) {
+ field = (ble_hs_adv_field*)&m_payload[data];
-#if CONFIG_LOG_DEFAULT_LEVEL > 3 || (ARDUINO_ARCH_ESP32 && CORE_DEBUG_LEVEL >= 4)
- char* pHex = NimBLEUtils::buildHexData(nullptr, m_payload, m_payloadLength);
- NIMBLE_LOGD(LOG_TAG,"payload: %s", pHex);
- free(pHex);
-#endif
-
- if (fields.uuids16 != NULL) {
- for (int i = 0; i < fields.num_uuids16; i++) {
- setServiceUUID(NimBLEUUID(fields.uuids16[i].value));
+ if (field->length >= length) {
+ return count;
}
- }
- if (fields.uuids32 != NULL) {
- for (int i = 0; i < fields.num_uuids32; i++) {
- setServiceUUID(NimBLEUUID(fields.uuids32[i].value));
- }
- }
+ if (field->type == type) {
+ switch(type) {
+ case BLE_HS_ADV_TYPE_INCOMP_UUIDS16:
+ case BLE_HS_ADV_TYPE_COMP_UUIDS16:
+ count += field->length / 2;
+ break;
- if (fields.uuids128 != NULL) {
- for (int i = 0; i < fields.num_uuids128; i++) {
- setServiceUUID(NimBLEUUID(&fields.uuids128[i]));
- }
- }
+ case BLE_HS_ADV_TYPE_INCOMP_UUIDS32:
+ case BLE_HS_ADV_TYPE_COMP_UUIDS32:
+ count += field->length / 4;
+ break;
- if (fields.name != NULL) {
- setName(std::string(reinterpret_cast(fields.name), fields.name_len));
- }
+ case BLE_HS_ADV_TYPE_INCOMP_UUIDS128:
+ case BLE_HS_ADV_TYPE_COMP_UUIDS128:
+ count += field->length / 16;
+ break;
- if (fields.tx_pwr_lvl_is_present) {
- setTXPower(fields.tx_pwr_lvl);
- }
+ case BLE_HS_ADV_TYPE_PUBLIC_TGT_ADDR:
+ case BLE_HS_ADV_TYPE_RANDOM_TGT_ADDR:
+ count += field->length / 6;
+ break;
- if (fields.svc_data_uuid16 != NULL ||
- fields.svc_data_uuid32 != NULL ||
- fields.svc_data_uuid128 != NULL)
- {
- ble_hs_adv_field *field;
- uint8_t *data = payload;
- while(length > 1) {
- field = (ble_hs_adv_field*)data;
-
- if(field->length > length) {
- break;
+ default:
+ count++;
+ break;
}
- if(field->type == BLE_HS_ADV_TYPE_SVC_DATA_UUID16) {
- if(field->length > 2) {
- uint16_t uuid;
- memcpy(&uuid, field->value, 2);
- setServiceData(NimBLEUUID(uuid), std::string(reinterpret_cast(field->value + 2), field->length - 3));
+ if(data_loc != nullptr) {
+ if(index == 0 || count >= index) {
+ break;
}
}
-
- if(field->type == BLE_HS_ADV_TYPE_SVC_DATA_UUID32) {
- if(field->length > 4) {
- uint32_t uuid;
- memcpy(&uuid, field->value, 4);
- setServiceData(NimBLEUUID(uuid), std::string(reinterpret_cast(field->value + 4), field->length - 5));
- }
- }
-
- if(field->type == BLE_HS_ADV_TYPE_SVC_DATA_UUID128) {
- if(field->length > 16) {
- NimBLEUUID uuid(field->value, (size_t)16, false);
- setServiceData(uuid, std::string(reinterpret_cast(field->value + 16), field->length - 17));
- }
- }
-
- length -= 1 + field->length;
- data += 1 + field->length;
}
+
+ length -= 1 + field->length;
+ data += 1 + field->length;
}
- if (fields.appearance_is_present) {
- setAppearance(fields.appearance);
+ if(data_loc != nullptr && field != nullptr) {
+ *data_loc = data;
}
- if (fields.mfg_data != NULL) {
- setManufacturerData(std::string(reinterpret_cast(fields.mfg_data), fields.mfg_data_len));
- }
-
-/* TODO: create storage and fucntions for these parameters
- if (fields.public_tgt_addr != NULL) {
- NIMBLE_LOGD(LOG_TAG, " public_tgt_addr=");
- u8p = fields.public_tgt_addr;
- for (i = 0; i < fields.num_public_tgt_addrs; i++) {
- NIMBLE_LOGD(LOG_TAG, "public_tgt_addr=%s ", addr_str(u8p));
- u8p += BLE_HS_ADV_PUBLIC_TGT_ADDR_ENTRY_LEN;
- }
- NIMBLE_LOGD(LOG_TAG, "\n");
- }
-
- if (fields.slave_itvl_range != NULL) {
- NIMBLE_LOGD(LOG_TAG, " slave_itvl_range=");
- print_bytes(fields.slave_itvl_range, BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN);
- NIMBLE_LOGD(LOG_TAG, "\n");
- }
-
- if (fields.adv_itvl_is_present) {
- NIMBLE_LOGD(LOG_TAG, " adv_itvl=0x%04x\n", fields.adv_itvl);
- }
-
- if (fields.uri != NULL) {
- NIMBLE_LOGD(LOG_TAG, " uri=");
- print_bytes(fields.uri, fields.uri_len);
- NIMBLE_LOGD(LOG_TAG, "\n");
- }
-*/
-
- } //parseAdvertisement
+ return count;
+}
/**
@@ -428,106 +657,22 @@ void NimBLEAdvertisedDevice::setAddress(NimBLEAddress address) {
/**
* @brief Set the adFlag for this device.
- * @param [in] The discovered adFlag.
+ * @param [in] advType The advertisement flag data from the advertisement.
*/
void NimBLEAdvertisedDevice::setAdvType(uint8_t advType) {
m_advType = advType;
} // setAdvType
-/**
- * @brief Set the appearance for this device.
- * @param [in] The discovered appearance.
- */
-void NimBLEAdvertisedDevice::setAppearance(uint16_t appearance) {
- m_appearance = appearance;
- m_haveAppearance = true;
-} // setAppearance
-
-
-/**
- * @brief Set the manufacturer data for this device.
- * @param [in] The discovered manufacturer data.
- */
-void NimBLEAdvertisedDevice::setManufacturerData(std::string manufacturerData) {
- m_manufacturerData = manufacturerData;
- m_haveManufacturerData = true;
-} // setManufacturerData
-
-
-/**
- * @brief Set the name for this device.
- * @param [in] name The discovered name.
- */
-void NimBLEAdvertisedDevice::setName(std::string name) {
- m_name = name;
- m_haveName = true;
-} // setName
-
-
/**
* @brief Set the RSSI for this device.
- * @param [in] rssi The discovered RSSI.
+ * @param [in] rssi The RSSI of the discovered device.
*/
void NimBLEAdvertisedDevice::setRSSI(int rssi) {
- m_rssi = rssi;
- m_haveRSSI = true;
+ m_rssi = rssi;
} // setRSSI
-/**
- * @brief Set the Service UUID for this device.
- * @param [in] serviceUUID The discovered serviceUUID
- */
-
-void NimBLEAdvertisedDevice::setServiceUUID(const char* serviceUUID) {
- return setServiceUUID(NimBLEUUID(serviceUUID));
-} // setServiceUUID
-
-
-/**
- * @brief Set the Service UUID for this device.
- * @param [in] serviceUUID The discovered serviceUUID
- */
-void NimBLEAdvertisedDevice::setServiceUUID(NimBLEUUID serviceUUID) {
- // Don't add duplicates
- for (int i = 0; i < m_serviceUUIDs.size(); i++) {
- if (m_serviceUUIDs[i] == serviceUUID) {
- return;
- }
- }
- m_serviceUUIDs.push_back(serviceUUID);
- m_haveServiceUUID = true;
-} // setServiceUUID
-
-
-/**
- * @brief Set the ServiceData value.
- * @param [in] uuid The UUID that the service data belongs to.
- * @param [in] data The service data.
- */
-void NimBLEAdvertisedDevice::setServiceData(NimBLEUUID uuid, std::string data) {
- m_haveServiceData = true;
- for(auto &it : m_serviceDataVec) {
- if(it.first == uuid) {
- it.second = data;
- return;
- }
- }
- m_serviceDataVec.push_back({uuid, data});
-} //setServiceData
-
-
-/**
- * @brief Set the power level for this device.
- * @param [in] txPower The discovered power level.
- */
-void NimBLEAdvertisedDevice::setTXPower(int8_t txPower) {
- m_txPower = txPower;
- m_haveTXPower = true;
-} // setTXPower
-
-
/**
* @brief Create a string representation of this device.
* @return A string representation of this device.
@@ -579,10 +724,35 @@ std::string NimBLEAdvertisedDevice::toString() {
* @return The advertisement payload.
*/
uint8_t* NimBLEAdvertisedDevice::getPayload() {
- return m_payload;
+ return &m_payload[0];
} // getPayload
+/**
+ * @brief Stores the payload of the advertised device in a vector.
+ * @param [in] payload The advertisement payload.
+ * @param [in] length The length of the payload in bytes.
+ * @param [in] append Indicates if the the data should be appended (scan response).
+ */
+void NimBLEAdvertisedDevice::setPayload(uint8_t *payload, uint8_t length, bool append) {
+ if(!append) {
+ m_advLength = length;
+ m_payload.assign(payload, payload + length);
+ } else {
+ m_payload.insert(m_payload.end(), payload, payload + length);
+ }
+}
+
+
+/**
+ * @brief Get the length of the advertisement data in the payload.
+ * @return The number of bytes in the payload that is from the advertisment.
+ */
+uint8_t NimBLEAdvertisedDevice::getAdvLength() {
+ return m_advLength;
+}
+
+
/**
* @brief Get the advertised device address type.
* @return The device address type:
@@ -610,7 +780,7 @@ time_t NimBLEAdvertisedDevice::getTimestamp() {
* @return The size of the payload in bytes.
*/
size_t NimBLEAdvertisedDevice::getPayloadLength() {
- return m_payloadLength;
+ return m_payload.size();
} // getPayloadLength
diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertisedDevice.h b/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertisedDevice.h
index ebdb85c9e..ef354bc41 100644
--- a/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertisedDevice.h
+++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertisedDevice.h
@@ -44,7 +44,11 @@ public:
NimBLEAddress getAddress();
uint8_t getAdvType();
uint16_t getAppearance();
+ uint16_t getAdvInterval();
+ uint16_t getMinInterval();
+ uint16_t getMaxInterval();
std::string getManufacturerData();
+ std::string getURI();
/**
* @brief A template to convert the service data to .
@@ -67,7 +71,7 @@ public:
NimBLEScan* getScan();
size_t getServiceDataCount();
std::string getServiceData(uint8_t index = 0);
- std::string getServiceData(const NimBLEUUID &uuid) const;
+ std::string getServiceData(const NimBLEUUID &uuid);
/**
* @brief A template to convert the service data to .
@@ -106,12 +110,15 @@ public:
NimBLEUUID getServiceDataUUID(uint8_t index = 0);
NimBLEUUID getServiceUUID(uint8_t index = 0);
size_t getServiceUUIDCount();
+ NimBLEAddress getTargetAddress(uint8_t index = 0);
+ size_t getTargetAddressCount();
int8_t getTXPower();
uint8_t* getPayload();
+ uint8_t getAdvLength();
size_t getPayloadLength();
uint8_t getAddressType();
time_t getTimestamp();
- bool isAdvertisingService(const NimBLEUUID &uuid) const;
+ bool isAdvertisingService(const NimBLEUUID &uuid);
bool haveAppearance();
bool haveManufacturerData();
bool haveName();
@@ -119,46 +126,30 @@ public:
bool haveServiceData();
bool haveServiceUUID();
bool haveTXPower();
+ bool haveConnParams();
+ bool haveAdvInterval();
+ bool haveTargetAddress();
+ bool haveURI();
std::string toString();
private:
friend class NimBLEScan;
- void parseAdvertisement(uint8_t* payload, uint8_t length);
- void setAddress(NimBLEAddress address);
- void setAdvType(uint8_t advType);
- void setAppearance(uint16_t appearance);
- void setManufacturerData(std::string manufacturerData);
- void setName(std::string name);
- void setRSSI(int rssi);
- void setServiceData(NimBLEUUID serviceUUID, std::string data);
- void setServiceUUID(const char* serviceUUID);
- void setServiceUUID(NimBLEUUID serviceUUID);
- void setTXPower(int8_t txPower);
-
- bool m_haveAppearance;
- bool m_haveManufacturerData;
- bool m_haveName;
- bool m_haveRSSI;
- bool m_haveServiceData;
- bool m_haveServiceUUID;
- bool m_haveTXPower;
-
+ void setAddress(NimBLEAddress address);
+ void setAdvType(uint8_t advType);
+ void setPayload(uint8_t *payload, uint8_t length, bool append);
+ void setRSSI(int rssi);
+ uint8_t findAdvField(uint8_t type, uint8_t index = 0, uint8_t *data_loc = nullptr);
+ uint8_t findServiceData(uint8_t index, uint8_t* bytes);
NimBLEAddress m_address = NimBLEAddress("");
uint8_t m_advType;
- uint16_t m_appearance;
- std::string m_manufacturerData;
- std::string m_name;
int m_rssi;
- int8_t m_txPower;
- uint8_t* m_payload;
- size_t m_payloadLength;
time_t m_timestamp;
bool m_callbackSent;
+ uint8_t m_advLength;
- std::vector m_serviceUUIDs;
- std::vector>m_serviceDataVec;
+ std::vector m_payload;
};
/**
diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertising.cpp b/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertising.cpp
index a10480410..3e9ae4a64 100644
--- a/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertising.cpp
+++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertising.cpp
@@ -32,23 +32,29 @@ static const char* LOG_TAG = "NimBLEAdvertising";
/**
* @brief Construct a default advertising object.
*/
-NimBLEAdvertising::NimBLEAdvertising() : m_slaveItvl() {
+NimBLEAdvertising::NimBLEAdvertising() {
+ reset();
+} // NimBLEAdvertising
+
+
+/**
+ * @brief Stops the current advertising and resets the advertising data to the default values.
+ */
+void NimBLEAdvertising::reset() {
+ if(NimBLEDevice::getInitialized() && isAdvertising()) {
+ stop();
+ }
memset(&m_advData, 0, sizeof m_advData);
memset(&m_scanData, 0, sizeof m_scanData);
memset(&m_advParams, 0, sizeof m_advParams);
+ memset(&m_slaveItvl, 0, sizeof m_slaveItvl);
const char *name = ble_svc_gap_device_name();
m_advData.name = (uint8_t *)name;
m_advData.name_len = strlen(name);
m_advData.name_is_complete = 1;
- m_advData.tx_pwr_lvl_is_present = 1;
m_advData.tx_pwr_lvl = NimBLEDevice::getPower();
m_advData.flags = (BLE_HS_ADV_F_DISC_GEN | BLE_HS_ADV_F_BREDR_UNSUP);
- m_advData.appearance = 0;
- m_advData.appearance_is_present = 0;
- m_advData.mfg_data_len = 0;
- m_advData.mfg_data = nullptr;
- m_advData.slave_itvl_range = nullptr;
#if !defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
m_advParams.conn_mode = BLE_GAP_CONN_MODE_NON;
@@ -56,17 +62,13 @@ NimBLEAdvertising::NimBLEAdvertising() : m_slaveItvl() {
m_advParams.conn_mode = BLE_GAP_CONN_MODE_UND;
#endif
m_advParams.disc_mode = BLE_GAP_DISC_MODE_GEN;
- m_advParams.itvl_min = 0;
- m_advParams.itvl_max = 0;
-
m_customAdvData = false;
m_customScanResponseData = false;
m_scanResp = true;
m_advDataSet = false;
// Set this to non-zero to prevent auto start if host reset before started by app.
m_duration = BLE_HS_FOREVER;
-
-} // NimBLEAdvertising
+} // reset
/**
@@ -85,6 +87,7 @@ void NimBLEAdvertising::addServiceUUID(const NimBLEUUID &serviceUUID) {
*/
void NimBLEAdvertising::addServiceUUID(const char* serviceUUID) {
addServiceUUID(NimBLEUUID(serviceUUID));
+ m_advDataSet = false;
} // addServiceUUID
@@ -112,9 +115,95 @@ void NimBLEAdvertising::removeServiceUUID(const NimBLEUUID &serviceUUID) {
void NimBLEAdvertising::setAppearance(uint16_t appearance) {
m_advData.appearance = appearance;
m_advData.appearance_is_present = 1;
+ m_advDataSet = false;
} // setAppearance
+/**
+ * @brief Add the transmission power level to the advertisement packet.
+ */
+void NimBLEAdvertising::addTxPower() {
+ m_advData.tx_pwr_lvl_is_present = 1;
+ m_advDataSet = false;
+} // addTxPower
+
+
+/**
+ * @brief Set the advertised name of the device.
+ * @param [in] name The name to advertise.
+ */
+void NimBLEAdvertising::setName(const std::string &name) {
+ m_name.assign(name.begin(), name.end());
+ m_advData.name = &m_name[0];
+ m_advData.name_len = m_name.size();
+ m_advDataSet = false;
+} // setName
+
+
+/**
+ * @brief Set the advertised manufacturer data.
+ * @param [in] data The data to advertise.
+ */
+void NimBLEAdvertising::setManufacturerData(const std::string &data) {
+ m_mfgData.assign(data.begin(), data.end());
+ m_advData.mfg_data = &m_mfgData[0];
+ m_advData.mfg_data_len = m_mfgData.size();
+ m_advDataSet = false;
+} // setManufacturerData
+
+
+/**
+ * @brief Set the advertised URI.
+ * @param [in] uri The URI to advertise.
+ */
+void NimBLEAdvertising::setURI(const std::string &uri) {
+ m_uri.assign(uri.begin(), uri.end());
+ m_advData.uri = &m_uri[0];
+ m_advData.uri_len = m_uri.size();
+ m_advDataSet = false;
+} // setURI
+
+
+/**
+ * @brief Set the service data advertised for the UUID.
+ * @param [in] uuid The UUID the service data belongs to.
+ * @param [in] data The data to advertise.
+ * @note If data length is 0 the service data will not be advertised.
+ */
+void NimBLEAdvertising::setServiceData(const NimBLEUUID &uuid, const std::string &data) {
+ switch (uuid.bitSize()) {
+ case 16: {
+ m_svcData16.assign((uint8_t*)&uuid.getNative()->u16.value, (uint8_t*)&uuid.getNative()->u16.value + 2);
+ m_svcData16.insert(m_svcData16.end(), data.begin(), data.end());
+ m_advData.svc_data_uuid16 = (uint8_t*)&m_svcData16[0];
+ m_advData.svc_data_uuid16_len = (data.length() > 0) ? m_svcData16.size() : 0;
+ break;
+ }
+
+ case 32: {
+ m_svcData32.assign((uint8_t*)&uuid.getNative()->u32.value, (uint8_t*)&uuid.getNative()->u32.value + 4);
+ m_svcData32.insert(m_svcData32.end(), data.begin(), data.end());
+ m_advData.svc_data_uuid32 = (uint8_t*)&m_svcData32[0];
+ m_advData.svc_data_uuid32_len = (data.length() > 0) ? m_svcData32.size() : 0;
+ break;
+ }
+
+ case 128: {
+ m_svcData128.assign(uuid.getNative()->u128.value, uuid.getNative()->u128.value + 16);
+ m_svcData128.insert(m_svcData128.end(), data.begin(), data.end());
+ m_advData.svc_data_uuid128 = (uint8_t*)&m_svcData128[0];
+ m_advData.svc_data_uuid128_len = (data.length() > 0) ? m_svcData128.size() : 0;
+ break;
+ }
+
+ default:
+ return;
+ }
+
+ m_advDataSet = false;
+} // setServiceData
+
+
/**
* @brief Set the type of advertisment to use.
* @param [in] adv_type:
@@ -172,6 +261,8 @@ void NimBLEAdvertising::setMinPreferred(uint16_t mininterval) {
m_slaveItvl[2] = m_slaveItvl[0];
m_slaveItvl[3] = m_slaveItvl[1];
}
+
+ m_advDataSet = false;
} // setMinPreferred
@@ -200,6 +291,8 @@ void NimBLEAdvertising::setMaxPreferred(uint16_t maxinterval) {
m_slaveItvl[0] = m_slaveItvl[2];
m_slaveItvl[1] = m_slaveItvl[3];
}
+
+ m_advDataSet = false;
} // setMaxPreferred
@@ -209,6 +302,7 @@ void NimBLEAdvertising::setMaxPreferred(uint16_t maxinterval) {
*/
void NimBLEAdvertising::setScanResponse(bool set) {
m_scanResp = set;
+ m_advDataSet = false;
} // setScanResponse
@@ -344,12 +438,29 @@ bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
if (!m_customAdvData && !m_advDataSet) {
//start with 3 bytes for the flags data
uint8_t payloadLen = (2 + 1);
+ if(m_advData.mfg_data_len > 0)
+ payloadLen += (2 + m_advData.mfg_data_len);
+
+ if(m_advData.svc_data_uuid16_len > 0)
+ payloadLen += (2 + m_advData.svc_data_uuid16_len);
+
+ if(m_advData.svc_data_uuid32_len > 0)
+ payloadLen += (2 + m_advData.svc_data_uuid32_len);
+
+ if(m_advData.svc_data_uuid128_len > 0)
+ payloadLen += (2 + m_advData.svc_data_uuid128_len);
+
+ if(m_advData.uri_len > 0)
+ payloadLen += (2 + m_advData.uri_len);
+
if(m_advData.appearance_is_present)
payloadLen += (2 + BLE_HS_ADV_APPEARANCE_LEN);
+
if(m_advData.tx_pwr_lvl_is_present)
- payloadLen += (2 + 1);
+ payloadLen += (2 + BLE_HS_ADV_TX_PWR_LVL_LEN);
+
if(m_advData.slave_itvl_range != nullptr)
- payloadLen += (2 + 4);
+ payloadLen += (2 + BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN);
for(auto &it : m_serviceUUIDs) {
if(it.getNative()->u.type == BLE_UUID_TYPE_16) {
@@ -419,7 +530,7 @@ bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
// check if there is room for the name, if not put it in scan data
if((payloadLen + (2 + m_advData.name_len)) > BLE_HS_ADV_MAX_SZ) {
- if(m_scanResp){
+ if(m_scanResp && !m_customScanResponseData){
m_scanData.name = m_advData.name;
m_scanData.name_len = m_advData.name_len;
if(m_scanData.name_len > BLE_HS_ADV_MAX_SZ - 2) {
@@ -433,7 +544,6 @@ bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
m_advData.name_is_complete = 0;
} else {
if(m_advData.tx_pwr_lvl_is_present) {
- m_advData.tx_pwr_lvl = 0;
m_advData.tx_pwr_lvl_is_present = 0;
payloadLen -= (2 + 1);
}
@@ -446,7 +556,7 @@ bool NimBLEAdvertising::start(uint32_t duration, void (*advCompleteCB)(NimBLEAdv
}
}
- if(m_scanResp) {
+ if(m_scanResp && !m_customScanResponseData) {
rc = ble_gap_adv_rsp_set_fields(&m_scanData);
switch(rc) {
case 0:
@@ -581,7 +691,7 @@ void NimBLEAdvertising::advCompleteCB() {
if(m_advCompCB != nullptr) {
m_advCompCB(this);
}
-}
+} // advCompleteCB
/**
@@ -590,7 +700,7 @@ void NimBLEAdvertising::advCompleteCB() {
*/
bool NimBLEAdvertising::isAdvertising() {
return ble_gap_adv_active();
-}
+} // isAdvertising
/*
@@ -608,7 +718,7 @@ void NimBLEAdvertising::onHostSync() {
// Otherwise we should tell the app that advertising stopped.
advCompleteCB();
}
-}
+} // onHostSync
/**
@@ -646,6 +756,7 @@ int NimBLEAdvertising::handleGapEvent(struct ble_gap_event *event, void *arg) {
*/
void NimBLEAdvertisementData::addData(const std::string &data) {
if ((m_payload.length() + data.length()) > BLE_HS_ADV_MAX_SZ) {
+ NIMBLE_LOGE(LOG_TAG, "Advertisement data length exceded");
return;
}
m_payload.append(data);
@@ -657,11 +768,8 @@ void NimBLEAdvertisementData::addData(const std::string &data) {
* @param [in] data The data to be added to the payload.
* @param [in] length The size of data to be added to the payload.
*/
-void NimBLEAdvertisementData::addData(char * data, size_t length){
- if ((m_payload.length() + length) > BLE_HS_ADV_MAX_SZ) {
- return;
- }
- m_payload.append(data,length);
+void NimBLEAdvertisementData::addData(char * data, size_t length) {
+ addData(std::string(data, length));
} // addData
@@ -680,43 +788,6 @@ void NimBLEAdvertisementData::setAppearance(uint16_t appearance) {
} // setAppearance
-/**
- * @brief Set the complete services to advertise.
- * @param [in] uuid The UUID of the service.
- */
-void NimBLEAdvertisementData::setCompleteServices(const NimBLEUUID &uuid) {
- char cdata[2];
- switch (uuid.bitSize()) {
- case 16: {
- // [Len] [0x02] [LL] [HH]
- cdata[0] = 3;
- cdata[1] = BLE_HS_ADV_TYPE_COMP_UUIDS16; // 0x03
- addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->u16.value, 2));
- break;
- }
-
- case 32: {
- // [Len] [0x04] [LL] [LL] [HH] [HH]
- cdata[0] = 5;
- cdata[1] = BLE_HS_ADV_TYPE_COMP_UUIDS32; // 0x05
- addData(std::string(cdata, 2) + std::string((char*) &uuid.getNative()->u32.value, 4));
- break;
- }
-
- case 128: {
- // [Len] [0x04] [0] [1] ... [15]
- cdata[0] = 17;
- cdata[1] = BLE_HS_ADV_TYPE_COMP_UUIDS128; // 0x07
- addData(std::string(cdata, 2) + std::string((char*) uuid.getNative()->u128.value, 16));
- break;
- }
-
- default:
- return;
- }
-} // setCompleteServices
-
-
/**
* @brief Set the advertisement flags.
* @param [in] flag The flags to be set in the advertisement.
@@ -738,64 +809,141 @@ void NimBLEAdvertisementData::setFlags(uint8_t flag) {
* @param [in] data The manufacturer data to advertise.
*/
void NimBLEAdvertisementData::setManufacturerData(const std::string &data) {
- NIMBLE_LOGD("NimBLEAdvertisementData", ">> setManufacturerData");
char cdata[2];
cdata[0] = data.length() + 1;
cdata[1] = BLE_HS_ADV_TYPE_MFG_DATA ; // 0xff
addData(std::string(cdata, 2) + data);
- NIMBLE_LOGD("NimBLEAdvertisementData", "<< setManufacturerData");
} // setManufacturerData
+/**
+ * @brief Set the URI to advertise.
+ * @param [in] uri The uri to advertise.
+ */
+void NimBLEAdvertisementData::setURI(const std::string &uri) {
+ char cdata[2];
+ cdata[0] = uri.length() + 1;
+ cdata[1] = BLE_HS_ADV_TYPE_URI;
+ addData(std::string(cdata, 2) + uri);
+} // setURI
+
+
/**
* @brief Set the complete name of this device.
* @param [in] name The name to advertise.
*/
void NimBLEAdvertisementData::setName(const std::string &name) {
- NIMBLE_LOGD("NimBLEAdvertisementData", ">> setName: %s", name.c_str());
char cdata[2];
cdata[0] = name.length() + 1;
cdata[1] = BLE_HS_ADV_TYPE_COMP_NAME; // 0x09
addData(std::string(cdata, 2) + name);
- NIMBLE_LOGD("NimBLEAdvertisementData", "<< setName");
} // setName
/**
- * @brief Set the partial services to advertise.
- * @param [in] uuid The single service to advertise.
+ * @brief Set a single service to advertise as a complete list of services.
+ * @param [in] uuid The service to advertise.
+ */
+void NimBLEAdvertisementData::setCompleteServices(const NimBLEUUID &uuid) {
+ setServices(true, uuid.bitSize(), {uuid});
+} // setCompleteServices
+
+
+/**
+ * @brief Set the complete list of 16 bit services to advertise.
+ * @param [in] v_uuid A vector of 16 bit UUID's to advertise.
+ */
+void NimBLEAdvertisementData::setCompleteServices16(const std::vector& v_uuid) {
+ setServices(true, 16, v_uuid);
+} // setCompleteServices16
+
+
+/**
+ * @brief Set the complete list of 32 bit services to advertise.
+ * @param [in] v_uuid A vector of 32 bit UUID's to advertise.
+ */
+void NimBLEAdvertisementData::setCompleteServices32(const std::vector& v_uuid) {
+ setServices(true, 32, v_uuid);
+} // setCompleteServices32
+
+
+/**
+ * @brief Set a single service to advertise as a partial list of services.
+ * @param [in] uuid The service to advertise.
*/
void NimBLEAdvertisementData::setPartialServices(const NimBLEUUID &uuid) {
+ setServices(false, uuid.bitSize(), {uuid});
+} // setPartialServices
+
+
+/**
+ * @brief Set the partial list of services to advertise.
+ * @param [in] v_uuid A vector of 16 bit UUID's to advertise.
+ */
+void NimBLEAdvertisementData::setPartialServices16(const std::vector& v_uuid) {
+ setServices(false, 16, v_uuid);
+} // setPartialServices16
+
+
+/**
+ * @brief Set the partial list of services to advertise.
+ * @param [in] v_uuid A vector of 32 bit UUID's to advertise.
+ */
+void NimBLEAdvertisementData::setPartialServices32(const std::vector& v_uuid) {
+ setServices(false, 32, v_uuid);
+} // setPartialServices32
+
+
+/**
+ * @brief Utility function to create the list of service UUID's from a vector.
+ * @param [in] complete If true the vector is the complete set of services.
+ * @param [in] size The bit size of the UUID's in the vector. (16, 32, or 128).
+ * @param [in] v_uuid The vector of service UUID's to advertise.
+ */
+void NimBLEAdvertisementData::setServices(const bool complete, const uint8_t size,
+ const std::vector &v_uuid)
+{
char cdata[2];
- switch (uuid.bitSize()) {
- case 16: {
- // [Len] [0x02] [LL] [HH]
- cdata[0] = 3;
- cdata[1] = BLE_HS_ADV_TYPE_INCOMP_UUIDS16; // 0x02
- addData(std::string(cdata, 2) + std::string((char *) &uuid.getNative()->u16.value, 2));
+ cdata[0] = (size / 8) * v_uuid.size() + 1;
+ switch(size) {
+ case 16:
+ cdata[1] = complete ? BLE_HS_ADV_TYPE_COMP_UUIDS16 : BLE_HS_ADV_TYPE_INCOMP_UUIDS16;
break;
- }
-
- case 32: {
- // [Len] [0x04] [LL] [LL] [HH] [HH]
- cdata[0] = 5;
- cdata[1] = BLE_HS_ADV_TYPE_INCOMP_UUIDS32; // 0x04
- addData(std::string(cdata, 2) + std::string((char *) &uuid.getNative()->u32.value, 4));
+ case 32:
+ cdata[1] = complete ? BLE_HS_ADV_TYPE_COMP_UUIDS32 : BLE_HS_ADV_TYPE_INCOMP_UUIDS32;
break;
- }
-
- case 128: {
- // [Len] [0x04] [0] [1] ... [15]
- cdata[0] = 17;
- cdata[1] = BLE_HS_ADV_TYPE_INCOMP_UUIDS128; // 0x06
- addData(std::string(cdata, 2) + std::string((char *) &uuid.getNative()->u128.value, 16));
+ case 128:
+ cdata[1] = complete ? BLE_HS_ADV_TYPE_COMP_UUIDS128 : BLE_HS_ADV_TYPE_INCOMP_UUIDS128;
break;
- }
-
default:
return;
}
-} // setPartialServices
+
+ std::string uuids;
+
+ for(auto &it : v_uuid){
+ if(it.bitSize() != size) {
+ NIMBLE_LOGE(LOG_TAG, "Service UUID(%d) invalid", size);
+ return;
+ } else {
+ switch(size) {
+ case 16:
+ uuids += std::string((char*)&it.getNative()->u16.value, 2);
+ break;
+ case 32:
+ uuids += std::string((char*)&it.getNative()->u32.value, 4);
+ break;
+ case 128:
+ uuids += std::string((char*)&it.getNative()->u128.value, 16);
+ break;
+ default:
+ return;
+ }
+ }
+ }
+
+ addData(std::string(cdata, 2) + uuids);
+} // setServices
/**
@@ -841,15 +989,42 @@ void NimBLEAdvertisementData::setServiceData(const NimBLEUUID &uuid, const std::
* @param [in] name The short name of the device.
*/
void NimBLEAdvertisementData::setShortName(const std::string &name) {
- NIMBLE_LOGD("NimBLEAdvertisementData", ">> setShortName: %s", name.c_str());
char cdata[2];
cdata[0] = name.length() + 1;
cdata[1] = BLE_HS_ADV_TYPE_INCOMP_NAME; // 0x08
addData(std::string(cdata, 2) + name);
- NIMBLE_LOGD("NimBLEAdvertisementData", "<< setShortName");
} // setShortName
+/**
+ * @brief Adds Tx power level to the advertisement data.
+ */
+void NimBLEAdvertisementData::addTxPower() {
+ char cdata[3];
+ cdata[0] = BLE_HS_ADV_TX_PWR_LVL_LEN + 1;
+ cdata[1] = BLE_HS_ADV_TYPE_TX_PWR_LVL;
+ cdata[2] = NimBLEDevice::getPower();
+ addData(cdata, 3);
+} // addTxPower
+
+
+/**
+ * @brief Set the preferred connection interval parameters.
+ * @param [in] min The minimum interval desired.
+ * @param [in] max The maximum interval desired.
+ */
+void NimBLEAdvertisementData::setPreferredParams(uint16_t min, uint16_t max) {
+ char cdata[6];
+ cdata[0] = BLE_HS_ADV_SLAVE_ITVL_RANGE_LEN + 1;
+ cdata[1] = BLE_HS_ADV_TYPE_SLAVE_ITVL_RANGE;
+ cdata[2] = min;
+ cdata[3] = min >> 8;
+ cdata[4] = max;
+ cdata[5] = max >> 8;
+ addData(cdata, 6);
+} // setPreferredParams
+
+
/**
* @brief Retrieve the payload that is to be advertised.
* @return The payload that is to be advertised.
diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertising.h b/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertising.h
index 0d97ecbbc..17a866561 100644
--- a/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertising.h
+++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEAdvertising.h
@@ -50,18 +50,27 @@ class NimBLEAdvertisementData {
public:
void setAppearance(uint16_t appearance);
void setCompleteServices(const NimBLEUUID &uuid);
+ void setCompleteServices16(const std::vector &v_uuid);
+ void setCompleteServices32(const std::vector &v_uuid);
void setFlags(uint8_t);
void setManufacturerData(const std::string &data);
+ void setURI(const std::string &uri);
void setName(const std::string &name);
void setPartialServices(const NimBLEUUID &uuid);
+ void setPartialServices16(const std::vector &v_uuid);
+ void setPartialServices32(const std::vector &v_uuid);
void setServiceData(const NimBLEUUID &uuid, const std::string &data);
void setShortName(const std::string &name);
void addData(const std::string &data); // Add data to the payload.
void addData(char * data, size_t length);
+ void addTxPower();
+ void setPreferredParams(uint16_t min, uint16_t max);
std::string getPayload(); // Retrieve the current advert payload.
private:
friend class NimBLEAdvertising;
+ void setServices(const bool complete, const uint8_t size,
+ const std::vector &v_uuid);
std::string m_payload; // The payload of the advertisement.
}; // NimBLEAdvertisementData
@@ -80,6 +89,10 @@ public:
bool start(uint32_t duration = 0, void (*advCompleteCB)(NimBLEAdvertising *pAdv) = nullptr);
void stop();
void setAppearance(uint16_t appearance);
+ void setName(const std::string &name);
+ void setManufacturerData(const std::string &data);
+ void setURI(const std::string &uri);
+ void setServiceData(const NimBLEUUID &uuid, const std::string &data);
void setAdvertisementType(uint8_t adv_type);
void setMaxInterval(uint16_t maxinterval);
void setMinInterval(uint16_t mininterval);
@@ -89,6 +102,8 @@ public:
void setScanResponse(bool);
void setMinPreferred(uint16_t);
void setMaxPreferred(uint16_t);
+ void addTxPower();
+ void reset();
void advCompleteCB();
bool isAdvertising();
@@ -109,6 +124,12 @@ private:
void (*m_advCompCB)(NimBLEAdvertising *pAdv);
uint8_t m_slaveItvl[4];
uint32_t m_duration;
+ std::vector m_svcData16;
+ std::vector m_svcData32;
+ std::vector m_svcData128;
+ std::vector m_name;
+ std::vector m_mfgData;
+ std::vector m_uri;
};
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLECharacteristic.cpp b/lib/libesp32/NimBLE-Arduino/src/NimBLECharacteristic.cpp
index e9a5a49c9..0ffa9fb03 100644
--- a/lib/libesp32/NimBLE-Arduino/src/NimBLECharacteristic.cpp
+++ b/lib/libesp32/NimBLE-Arduino/src/NimBLECharacteristic.cpp
@@ -101,9 +101,9 @@ NimBLEDescriptor* NimBLECharacteristic::createDescriptor(const NimBLEUUID &uuid,
/**
- * @brief Return the BLE Descriptor for the given UUID if associated with this characteristic.
- * @param [in] uuid The UUID of the descriptor that we wish to retrieve.
- * @return pointer to the NimBLEDescriptor. If no such descriptor is associated with the characteristic, nullptr is returned.
+ * @brief Return the BLE Descriptor for the given UUID.
+ * @param [in] uuid The UUID of the descriptor.
+ * @return A pointer to the descriptor object or nullptr if not found.
*/
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* uuid) {
return getDescriptorByUUID(NimBLEUUID(uuid));
@@ -111,9 +111,9 @@ NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const char* uuid) {
/**
- * @brief Return the BLE Descriptor for the given UUID if associated with this characteristic.
- * @param [in] uuid The UUID of the descriptor that we wish to retrieve.
- * @return pointer to the NimBLEDescriptor. If no such descriptor is associated with the characteristic, nullptr is returned.
+ * @brief Return the BLE Descriptor for the given UUID.
+ * @param [in] uuid The UUID of the descriptor.
+ * @return A pointer to the descriptor object or nullptr if not found.
*/
NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID &uuid) {
for (auto &it : m_dscVec) {
@@ -124,6 +124,20 @@ NimBLEDescriptor* NimBLECharacteristic::getDescriptorByUUID(const NimBLEUUID &uu
return nullptr;
} // getDescriptorByUUID
+/**
+ * @brief Return the BLE Descriptor for the given handle.
+ * @param [in] handle The handle of the descriptor.
+ * @return A pointer to the descriptor object or nullptr if not found.
+ */
+NimBLEDescriptor *NimBLECharacteristic::getDescriptorByHandle(uint16_t handle) {
+ for (auto &it : m_dscVec) {
+ if (it->getHandle() == handle) {
+ return it;
+ }
+ }
+ return nullptr;
+}
+
/**
* @brief Get the handle of the characteristic.
diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLECharacteristic.h b/lib/libesp32/NimBLE-Arduino/src/NimBLECharacteristic.h
index 1c7418aef..9bb9d079b 100644
--- a/lib/libesp32/NimBLE-Arduino/src/NimBLECharacteristic.h
+++ b/lib/libesp32/NimBLE-Arduino/src/NimBLECharacteristic.h
@@ -59,6 +59,17 @@ class NimBLECharacteristicCallbacks;
*/
class NimBLECharacteristic {
public:
+
+ uint16_t getHandle();
+ NimBLEUUID getUUID();
+ std::string toString();
+
+ void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks);
+
+ void indicate();
+ void notify(bool is_notification = true);
+ size_t getSubscribedCount();
+
NimBLEDescriptor* createDescriptor(const char* uuid,
uint32_t properties =
NIMBLE_PROPERTY::READ |
@@ -72,9 +83,10 @@ public:
NimBLEDescriptor* getDescriptorByUUID(const char* uuid);
NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID &uuid);
- NimBLEUUID getUUID();
- std::string getValue(time_t *timestamp = nullptr);
+ NimBLEDescriptor* getDescriptorByHandle(uint16_t handle);
+ std::string getValue(time_t *timestamp = nullptr);
+ size_t getDataLength();
/**
* @brief A template to convert the characteristic data to .
* @tparam T The type to convert the data to.
@@ -92,25 +104,20 @@ public:
return *((T *)pData);
}
- size_t getDataLength();
- void indicate();
- void notify(bool is_notification = true);
- void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks);
void setValue(const uint8_t* data, size_t size);
void setValue(const std::string &value);
-
/**
* @brief Convenience template to set the characteristic value to val.
* @param [in] s The value to set.
*/
template
- void setValue(const T &s) {
+ void setValue(const T &s) {
setValue((uint8_t*)&s, sizeof(T));
}
- std::string toString();
- uint16_t getHandle();
- size_t getSubscribedCount();
+
+
+
private:
diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEDescriptor.cpp b/lib/libesp32/NimBLE-Arduino/src/NimBLEDescriptor.cpp
index e8f7f9f8b..95c3291f3 100644
--- a/lib/libesp32/NimBLE-Arduino/src/NimBLEDescriptor.cpp
+++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEDescriptor.cpp
@@ -122,11 +122,17 @@ uint8_t* NimBLEDescriptor::getValue() {
return m_value.attr_value;
} // getValue
+/**
+ * @brief Get the value of this descriptor as a string.
+ * @return A std::string instance containing a copy of the descriptor's value.
+ */
+std::string NimBLEDescriptor::getStringValue() {
+ return std::string((char *) m_value.attr_value, m_value.attr_len);
+}
int NimBLEDescriptor::handleGapEvent(uint16_t conn_handle, uint16_t attr_handle,
struct ble_gatt_access_ctxt *ctxt,
- void *arg)
-{
+ void *arg) {
const ble_uuid_t *uuid;
int rc;
NimBLEDescriptor* pDescriptor = (NimBLEDescriptor*)arg;
diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEDescriptor.h b/lib/libesp32/NimBLE-Arduino/src/NimBLEDescriptor.h
index 16b6edceb..76318b729 100644
--- a/lib/libesp32/NimBLE-Arduino/src/NimBLEDescriptor.h
+++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEDescriptor.h
@@ -44,20 +44,23 @@ class NimBLEDescriptorCallbacks;
class NimBLEDescriptor {
public:
uint16_t getHandle();
- size_t getLength();
NimBLEUUID getUUID();
- uint8_t* getValue();
- void setCallbacks(NimBLEDescriptorCallbacks* pCallbacks);
- void setValue(const uint8_t* data, size_t size);
- void setValue(const std::string &value);
std::string toString();
+ void setCallbacks(NimBLEDescriptorCallbacks* pCallbacks);
+
+ size_t getLength();
+ uint8_t* getValue();
+ std::string getStringValue();
+
+ void setValue(const uint8_t* data, size_t size);
+ void setValue(const std::string &value);
/**
* @brief Convenience template to set the descriptor value to val.
* @param [in] s The value to set.
*/
template
- void setValue(const T &s) {
+ void setValue(const T &s) {
setValue((uint8_t*)&s, sizeof(T));
}
diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEDevice.cpp b/lib/libesp32/NimBLE-Arduino/src/NimBLEDevice.cpp
index f34a522f7..dc9caf3d5 100644
--- a/lib/libesp32/NimBLE-Arduino/src/NimBLEDevice.cpp
+++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEDevice.cpp
@@ -62,6 +62,8 @@ std::list NimBLEDevice::m_cList;
std::list NimBLEDevice::m_ignoreList;
NimBLESecurityCallbacks* NimBLEDevice::m_securityCallbacks = nullptr;
uint8_t NimBLEDevice::m_own_addr_type = BLE_OWN_ADDR_PUBLIC;
+uint16_t NimBLEDevice::m_scanDuplicateSize = CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE;
+uint8_t NimBLEDevice::m_scanFilterMode = CONFIG_BTDM_SCAN_DUPL_TYPE;
/**
@@ -303,7 +305,7 @@ void NimBLEDevice::stopAdvertising() {
/**
- * @brief Set the transmission power.
+ * @brief Get the transmission power.
* @param [in] powerType The power level to set, can be one of:
* * ESP_BLE_PWR_TYPE_CONN_HDL0 = 0, For connection handle 0
* * ESP_BLE_PWR_TYPE_CONN_HDL1 = 1, For connection handle 1
@@ -342,7 +344,7 @@ void NimBLEDevice::stopAdvertising() {
default:
return BLE_HS_ADV_TX_PWR_LVL_AUTO;
}
-} // setPower
+} // getPower
/**
@@ -400,6 +402,53 @@ void NimBLEDevice::stopAdvertising() {
}
+/**
+ * @brief Set the duplicate filter cache size for filtering scanned devices.
+ * @param [in] cacheSize The number of advertisements filtered before the cache is reset.\n
+ * Range is 10-1000, a larger value will reduce how often the same devices are reported.
+ * @details Must only be called before calling NimBLEDevice::init.
+ */
+/*STATIC*/
+void NimBLEDevice::setScanDuplicateCacheSize(uint16_t cacheSize) {
+ if(initialized) {
+ NIMBLE_LOGE(LOG_TAG, "Cannot change scan cache size while initialized");
+ return;
+ } else if(cacheSize > 1000 || cacheSize <10) {
+ NIMBLE_LOGE(LOG_TAG, "Invalid scan cache size; min=10 max=1000");
+ return;
+ }
+
+ m_scanDuplicateSize = cacheSize;
+}
+
+
+/**
+ * @brief Set the duplicate filter mode for filtering scanned devices.
+ * @param [in] mode One of three possible options:
+ * * CONFIG_BTDM_SCAN_DUPL_TYPE_DEVICE (0) (default)\n
+ Filter by device address only, advertisements from the same address will be reported only once.
+ * * CONFIG_BTDM_SCAN_DUPL_TYPE_DATA (1)\n
+ Filter by data only, advertisements with the same data will only be reported once,\n
+ even from different addresses.
+ * * CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE (2)\n
+ Filter by address and data, advertisements from the same address will be reported only once,\n
+ except if the data in the advertisement has changed, then it will be reported again.
+ * @details Must only be called before calling NimBLEDevice::init.
+ */
+/*STATIC*/
+void NimBLEDevice::setScanFilterMode(uint8_t mode) {
+ if(initialized) {
+ NIMBLE_LOGE(LOG_TAG, "Cannot change scan duplicate type while initialized");
+ return;
+ } else if(mode > 2) {
+ NIMBLE_LOGE(LOG_TAG, "Invalid scan duplicate type");
+ return;
+ }
+
+ m_scanFilterMode = mode;
+}
+
+
/**
* @brief Host reset, we pass the message so we don't make calls until resynced.
* @param [in] reason The reason code for the reset.
@@ -499,8 +548,17 @@ void NimBLEDevice::stopAdvertising() {
ESP_ERROR_CHECK(errRc);
- ESP_ERROR_CHECK(esp_nimble_hci_and_controller_init());
+ esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
+ esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
+ bt_cfg.mode = ESP_BT_MODE_BLE;
+ bt_cfg.ble_max_conn = CONFIG_BT_NIMBLE_MAX_CONNECTIONS;
+ bt_cfg.normal_adv_size = m_scanDuplicateSize;
+ bt_cfg.scan_duplicate_type = m_scanFilterMode;
+
+ ESP_ERROR_CHECK(esp_bt_controller_init(&bt_cfg));
+ ESP_ERROR_CHECK(esp_bt_controller_enable(ESP_BT_MODE_BLE));
+ ESP_ERROR_CHECK(esp_nimble_hci_init());
nimble_port_init();
// Setup callbacks for host events
diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEDevice.h b/lib/libesp32/NimBLE-Arduino/src/NimBLEDevice.h
index 2d586bb42..27549ed60 100644
--- a/lib/libesp32/NimBLE-Arduino/src/NimBLEDevice.h
+++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEDevice.h
@@ -123,6 +123,8 @@ public:
static bool isIgnored(const NimBLEAddress &address);
static void addIgnored(const NimBLEAddress &address);
static void removeIgnored(const NimBLEAddress &address);
+ static void setScanDuplicateCacheSize(uint16_t cacheSize);
+ static void setScanFilterMode(uint8_t type);
#if defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
static NimBLEAdvertising* getAdvertising();
@@ -184,6 +186,8 @@ private:
static ble_gap_event_listener m_listener;
static gap_event_handler m_customGapHandler;
static uint8_t m_own_addr_type;
+ static uint16_t m_scanDuplicateSize;
+ static uint8_t m_scanFilterMode;
};
diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEHIDDevice.cpp b/lib/libesp32/NimBLE-Arduino/src/NimBLEHIDDevice.cpp
index a06b75360..37d0f52f5 100644
--- a/lib/libesp32/NimBLE-Arduino/src/NimBLEHIDDevice.cpp
+++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEHIDDevice.cpp
@@ -103,7 +103,7 @@ void NimBLEHIDDevice::manufacturer(std::string name) {
/**
* @brief Sets the Plug n Play characterisc value.
* @param [in] sig The vendor ID source number.
- * @param [in[ vid The vendor ID number.
+ * @param [in] vid The vendor ID number.
* @param [in] pid The product ID number.
* @param [in] version The produce version number.
*/
@@ -128,8 +128,8 @@ void NimBLEHIDDevice::hidInfo(uint8_t country, uint8_t flags) {
* @return pointer to new input report characteristic
*/
NimBLECharacteristic* NimBLEHIDDevice::inputReport(uint8_t reportID) {
- NimBLECharacteristic* inputReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY);
- NimBLEDescriptor* inputReportDescriptor = inputReportCharacteristic->createDescriptor((uint16_t) 0x2908);
+ NimBLECharacteristic* inputReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY | NIMBLE_PROPERTY::READ_ENC);
+ NimBLEDescriptor* inputReportDescriptor = inputReportCharacteristic->createDescriptor((uint16_t) 0x2908, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::READ_ENC);
uint8_t desc1_val[] = { reportID, 0x01 };
inputReportDescriptor->setValue((uint8_t*) desc1_val, 2);
@@ -144,7 +144,7 @@ NimBLECharacteristic* NimBLEHIDDevice::inputReport(uint8_t reportID) {
*/
NimBLECharacteristic* NimBLEHIDDevice::outputReport(uint8_t reportID) {
NimBLECharacteristic* outputReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::WRITE_NR | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
- NimBLEDescriptor* outputReportDescriptor = outputReportCharacteristic->createDescriptor((uint16_t) 0x2908);
+ NimBLEDescriptor* outputReportDescriptor = outputReportCharacteristic->createDescriptor((uint16_t) 0x2908, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
uint8_t desc1_val[] = { reportID, 0x02 };
outputReportDescriptor->setValue((uint8_t*) desc1_val, 2);
@@ -159,7 +159,7 @@ NimBLECharacteristic* NimBLEHIDDevice::outputReport(uint8_t reportID) {
*/
NimBLECharacteristic* NimBLEHIDDevice::featureReport(uint8_t reportID) {
NimBLECharacteristic* featureReportCharacteristic = m_hidService->createCharacteristic((uint16_t) 0x2a4d, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
- NimBLEDescriptor* featureReportDescriptor = featureReportCharacteristic->createDescriptor((uint16_t) 0x2908);
+ NimBLEDescriptor* featureReportDescriptor = featureReportCharacteristic->createDescriptor((uint16_t) 0x2908, NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE | NIMBLE_PROPERTY::READ_ENC | NIMBLE_PROPERTY::WRITE_ENC);
uint8_t desc1_val[] = { reportID, 0x03 };
featureReportDescriptor->setValue((uint8_t*) desc1_val, 2);
diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEScan.cpp b/lib/libesp32/NimBLE-Arduino/src/NimBLEScan.cpp
index 122ff3332..00aeab03c 100644
--- a/lib/libesp32/NimBLE-Arduino/src/NimBLEScan.cpp
+++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEScan.cpp
@@ -38,9 +38,9 @@ NimBLEScan::NimBLEScan() {
m_scan_params.filter_duplicates = 0; // If set, the controller ignores all but the first advertisement from each device.
m_pAdvertisedDeviceCallbacks = nullptr;
m_ignoreResults = false;
- m_wantDuplicates = false;
m_pTaskData = nullptr;
m_duration = BLE_HS_FOREVER; // make sure this is non-zero in the event of a host reset
+ m_maxResults = 0xFF;
}
@@ -64,7 +64,7 @@ NimBLEScan::~NimBLEScan() {
case BLE_GAP_EVENT_DISC: {
if(pScan->m_ignoreResults) {
- NIMBLE_LOGE(LOG_TAG, "Scan op in progress - ignoring results");
+ NIMBLE_LOGI(LOG_TAG, "Scan op in progress - ignoring results");
return 0;
}
@@ -88,34 +88,49 @@ NimBLEScan::~NimBLEScan() {
// If we haven't seen this device before; create a new instance and insert it in the vector.
// Otherwise just update the relevant parameters of the already known device.
- if(advertisedDevice == nullptr){
+ if(advertisedDevice == nullptr && event->disc.event_type != BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP){
+ // Check if we have reach the scan results limit, ignore this one if so.
+ // We still need to store each device when maxResults is 0 to be able to append the scan results
+ if(pScan->m_maxResults > 0 && pScan->m_maxResults < 0xFF &&
+ (pScan->m_scanResults.m_advertisedDevicesVector.size() >= pScan->m_maxResults))
+ {
+ return 0;
+ }
advertisedDevice = new NimBLEAdvertisedDevice();
advertisedDevice->setAddress(advertisedAddress);
advertisedDevice->setAdvType(event->disc.event_type);
pScan->m_scanResults.m_advertisedDevicesVector.push_back(advertisedDevice);
- NIMBLE_LOGI(LOG_TAG, "NEW DEVICE FOUND: %s", advertisedAddress.toString().c_str());
- }
- else{
- NIMBLE_LOGI(LOG_TAG, "UPDATING PREVIOUSLY FOUND DEVICE: %s", advertisedAddress.toString().c_str());
- }
- advertisedDevice->setRSSI(event->disc.rssi);
- if(event->disc.length_data > 0) {
- advertisedDevice->parseAdvertisement(event->disc.data, event->disc.length_data);
+ NIMBLE_LOGI(LOG_TAG, "New advertiser: %s", advertisedAddress.toString().c_str());
+ } else if(advertisedDevice != nullptr) {
+ NIMBLE_LOGI(LOG_TAG, "Updated advertiser: %s", advertisedAddress.toString().c_str());
+ } else {
+ // Scan response from unknown device
+ return 0;
}
+
advertisedDevice->m_timestamp = time(nullptr);
+ advertisedDevice->setRSSI(event->disc.rssi);
+ advertisedDevice->setPayload(event->disc.data, event->disc.length_data,
+ event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP);
if (pScan->m_pAdvertisedDeviceCallbacks) {
- if(pScan->m_wantDuplicates || !advertisedDevice->m_callbackSent) {
- // If not active scanning report the result to the listener.
- if(pScan->m_scan_params.passive || event->disc.event_type == BLE_HCI_ADV_TYPE_ADV_NONCONN_IND) {
- advertisedDevice->m_callbackSent = true;
- pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice);
+ // If not active scanning or scan response is not available
+ // report the result to the callback now.
+ if(pScan->m_scan_params.passive ||
+ (advertisedDevice->getAdvType() != BLE_HCI_ADV_TYPE_ADV_IND &&
+ advertisedDevice->getAdvType() != BLE_HCI_ADV_TYPE_ADV_SCAN_IND))
+ {
+ advertisedDevice->m_callbackSent = true;
+ pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice);
- // Otherwise wait for the scan response so we can report all of the data at once.
- } else if (event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) {
- advertisedDevice->m_callbackSent = true;
- pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice);
- }
+ // Otherwise, wait for the scan response so we can report the complete data.
+ } else if (event->disc.event_type == BLE_HCI_ADV_RPT_EVTYPE_SCAN_RSP) {
+ advertisedDevice->m_callbackSent = true;
+ pScan->m_pAdvertisedDeviceCallbacks->onResult(advertisedDevice);
+ }
+ // If not storing results and we have invoked the callback, delete the device.
+ if(pScan->m_maxResults == 0 && advertisedDevice->m_callbackSent) {
+ pScan->erase(advertisedAddress);
}
}
@@ -123,7 +138,21 @@ NimBLEScan::~NimBLEScan() {
}
case BLE_GAP_EVENT_DISC_COMPLETE: {
NIMBLE_LOGD(LOG_TAG, "discovery complete; reason=%d",
- event->disc_complete.reason);
+ event->disc_complete.reason);
+
+ // If a device advertised with scan reponse available and it was not received
+ // the callback would not have been invoked, so do it here.
+ if(pScan->m_pAdvertisedDeviceCallbacks) {
+ for(auto &it : pScan->m_scanResults.m_advertisedDevicesVector) {
+ if(!it->m_callbackSent) {
+ pScan->m_pAdvertisedDeviceCallbacks->onResult(it);
+ }
+ }
+ }
+
+ if(pScan->m_maxResults == 0) {
+ pScan->clearResults();
+ }
if (pScan->m_scanCompleteCB != nullptr) {
pScan->m_scanCompleteCB(pScan->m_scanResults);
@@ -145,15 +174,11 @@ NimBLEScan::~NimBLEScan() {
/**
* @brief Should we perform an active or passive scan?
- * The default is a passive scan. An active scan means that we will wish a scan response.
+ * The default is a passive scan. An active scan means that we will request a scan response.
* @param [in] active If true, we perform an active scan otherwise a passive scan.
*/
void NimBLEScan::setActiveScan(bool active) {
- if (active) {
- m_scan_params.passive = 0;
- } else {
- m_scan_params.passive = 1;
- }
+ m_scan_params.passive = !active;
} // setActiveScan
@@ -202,6 +227,16 @@ void NimBLEScan::setFilterPolicy(uint8_t filter) {
} // setFilterPolicy
+/**
+ * @brief Sets the max number of results to store.
+ * @param [in] maxResults The number of results to limit storage to\n
+ * 0 == none (callbacks only) 0xFF == unlimited, any other value is the limit.
+ */
+void NimBLEScan::setMaxResults(uint8_t maxResults) {
+ m_maxResults = maxResults;
+}
+
+
/**
* @brief Set the call backs to be invoked.
* @param [in] pAdvertisedDeviceCallbacks Call backs to be invoked.
@@ -209,7 +244,7 @@ void NimBLEScan::setFilterPolicy(uint8_t filter) {
*/
void NimBLEScan::setAdvertisedDeviceCallbacks(NimBLEAdvertisedDeviceCallbacks* pAdvertisedDeviceCallbacks,
bool wantDuplicates) {
- m_wantDuplicates = wantDuplicates;
+ setDuplicateFilter(!wantDuplicates);
m_pAdvertisedDeviceCallbacks = pAdvertisedDeviceCallbacks;
} // setAdvertisedDeviceCallbacks
@@ -342,10 +377,14 @@ bool NimBLEScan::stop() {
int rc = ble_gap_disc_cancel();
if (rc != 0 && rc != BLE_HS_EALREADY) {
- NIMBLE_LOGE(LOG_TAG, "Failed to cancel scan; rc=%d\n", rc);
+ NIMBLE_LOGE(LOG_TAG, "Failed to cancel scan; rc=%d", rc);
return false;
}
+ if(m_maxResults == 0) {
+ clearResults();
+ }
+
if (rc != BLE_HS_EALREADY && m_scanCompleteCB != nullptr) {
m_scanCompleteCB(m_scanResults);
}
@@ -365,7 +404,7 @@ bool NimBLEScan::stop() {
* @details After disconnecting, it may be required in the case we were connected to a device without a public address.
*/
void NimBLEScan::erase(const NimBLEAddress &address) {
- NIMBLE_LOGI(LOG_TAG, "erase device: %s", address.toString().c_str());
+ NIMBLE_LOGD(LOG_TAG, "erase device: %s", address.toString().c_str());
for(auto it = m_scanResults.m_advertisedDevicesVector.begin(); it != m_scanResults.m_advertisedDevicesVector.end(); ++it) {
if((*it)->getAddress() == address) {
diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEScan.h b/lib/libesp32/NimBLE-Arduino/src/NimBLEScan.h
index 9007a7dd8..57e743009 100644
--- a/lib/libesp32/NimBLE-Arduino/src/NimBLEScan.h
+++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEScan.h
@@ -73,6 +73,7 @@ public:
bool stop();
void clearResults();
NimBLEScanResults getResults();
+ void setMaxResults(uint8_t maxResults);
void erase(const NimBLEAddress &address);
@@ -89,10 +90,10 @@ private:
void (*m_scanCompleteCB)(NimBLEScanResults scanResults);
ble_gap_disc_params m_scan_params;
bool m_ignoreResults;
- bool m_wantDuplicates;
NimBLEScanResults m_scanResults;
uint32_t m_duration;
ble_task_data_t *m_pTaskData;
+ uint8_t m_maxResults;
};
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEServer.cpp b/lib/libesp32/NimBLE-Arduino/src/NimBLEServer.cpp
index fd5d8266b..423e87967 100644
--- a/lib/libesp32/NimBLE-Arduino/src/NimBLEServer.cpp
+++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEServer.cpp
@@ -104,28 +104,47 @@ NimBLEService* NimBLEServer::createService(const NimBLEUUID &uuid, uint32_t numH
/**
* @brief Get a %BLE Service by its UUID
- * @param [in] uuid The UUID of the new service.
- * @return A reference to the service object.
+ * @param [in] uuid The UUID of the service.
+ * @param instanceId The index of the service to return (used when multiple services have the same UUID).
+ * @return A pointer to the service object or nullptr if not found.
*/
-NimBLEService* NimBLEServer::getServiceByUUID(const char* uuid) {
- return getServiceByUUID(NimBLEUUID(uuid));
+NimBLEService* NimBLEServer::getServiceByUUID(const char* uuid, uint16_t instanceId) {
+ return getServiceByUUID(NimBLEUUID(uuid), instanceId);
} // getServiceByUUID
/**
* @brief Get a %BLE Service by its UUID
- * @param [in] uuid The UUID of the new service.
- * @return A reference to the service object.
+ * @param [in] uuid The UUID of the service.
+ * @param instanceId The index of the service to return (used when multiple services have the same UUID).
+ * @return A pointer to the service object or nullptr if not found.
*/
-NimBLEService* NimBLEServer::getServiceByUUID(const NimBLEUUID &uuid) {
+NimBLEService* NimBLEServer::getServiceByUUID(const NimBLEUUID &uuid, uint16_t instanceId) {
+ uint16_t position = 0;
for (auto &it : m_svcVec) {
if (it->getUUID() == uuid) {
- return it;
+ if (position == instanceId){
+ return it;
+ }
+ position++;
}
}
return nullptr;
} // getServiceByUUID
+/**
+ * @brief Get a %BLE Service by its handle
+ * @param handle The handle of the service.
+ * @return A pointer to the service object or nullptr if not found.
+ */
+NimBLEService *NimBLEServer::getServiceByHandle(uint16_t handle) {
+ for (auto &it : m_svcVec) {
+ if (it->getHandle() == handle) {
+ return it;
+ }
+ }
+ return nullptr;
+}
/**
* @brief Retrieve the advertising object that can be used to advertise the existence of the server.
@@ -646,7 +665,7 @@ void NimBLEServer::updateConnParams(uint16_t conn_handle,
if(rc != 0) {
NIMBLE_LOGE(LOG_TAG, "Update params error: %d, %s", rc, NimBLEUtils::returnCodeToString(rc));
}
-} // updateConnParams
+}// updateConnParams
/** Default callback handlers */
diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEServer.h b/lib/libesp32/NimBLE-Arduino/src/NimBLEServer.h
index bedf9cf58..aaaf287d2 100644
--- a/lib/libesp32/NimBLE-Arduino/src/NimBLEServer.h
+++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEServer.h
@@ -49,8 +49,9 @@ public:
void startAdvertising();
void stopAdvertising();
void start();
- NimBLEService* getServiceByUUID(const char* uuid);
- NimBLEService* getServiceByUUID(const NimBLEUUID &uuid);
+ NimBLEService* getServiceByUUID(const char* uuid, uint16_t instanceId = 0);
+ NimBLEService* getServiceByUUID(const NimBLEUUID &uuid, uint16_t instanceId = 0);
+ NimBLEService* getServiceByHandle(uint16_t handle);
int disconnect(uint16_t connID,
uint8_t reason = BLE_ERR_REM_USER_CONN_TERM);
void updateConnParams(uint16_t conn_handle,
diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEService.cpp b/lib/libesp32/NimBLE-Arduino/src/NimBLEService.cpp
index 3420da2c7..a830eec95 100644
--- a/lib/libesp32/NimBLE-Arduino/src/NimBLEService.cpp
+++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEService.cpp
@@ -233,9 +233,9 @@ NimBLECharacteristic* NimBLEService::createCharacteristic(const char* uuid, uint
*/
NimBLECharacteristic* NimBLEService::createCharacteristic(const NimBLEUUID &uuid, uint32_t properties) {
NimBLECharacteristic* pCharacteristic = new NimBLECharacteristic(uuid, properties, this);
- // Check that we don't add the same characteristic twice.
+
if (getCharacteristic(uuid) != nullptr) {
- NIMBLE_LOGW(LOG_TAG, "<< Adding a duplicate characteristic with UUID: %s",
+ NIMBLE_LOGD(LOG_TAG, "<< Adding a duplicate characteristic with UUID: %s",
std::string(uuid).c_str());
}
@@ -249,28 +249,72 @@ NimBLECharacteristic* NimBLEService::createCharacteristic(const NimBLEUUID &uuid
/**
* @brief Get a pointer to the characteristic object with the specified UUID.
* @param [in] uuid The UUID of the characteristic.
+ * @param instanceId The index of the characteristic to return (used when multiple characteristics have the same UUID).
* @return A pointer to the characteristic object or nullptr if not found.
*/
-NimBLECharacteristic* NimBLEService::getCharacteristic(const char* uuid) {
- return getCharacteristic(NimBLEUUID(uuid));
+NimBLECharacteristic* NimBLEService::getCharacteristic(const char* uuid, uint16_t instanceId) {
+ return getCharacteristic(NimBLEUUID(uuid), instanceId);
}
-
/**
* @brief Get a pointer to the characteristic object with the specified UUID.
* @param [in] uuid The UUID of the characteristic.
+ * @param instanceId The index of the characteristic to return (used when multiple characteristics have the same UUID).
* @return A pointer to the characteristic object or nullptr if not found.
*/
-NimBLECharacteristic* NimBLEService::getCharacteristic(const NimBLEUUID &uuid) {
+NimBLECharacteristic* NimBLEService::getCharacteristic(const NimBLEUUID &uuid, uint16_t instanceId) {
+ uint16_t position = 0;
for (auto &it : m_chrVec) {
if (it->getUUID() == uuid) {
- return it;
+ if (position == instanceId) {
+ return it;
+ }
+ position++;
}
}
-
return nullptr;
}
+/**
+ * @brief Get a pointer to the characteristic object with the specified handle.
+ * @param handle The handle of the characteristic.
+ * @return A pointer to the characteristic object or nullptr if not found.
+ */
+NimBLECharacteristic *NimBLEService::getCharacteristicByHandle(uint16_t handle) {
+ for (auto &it : m_chrVec) {
+ if (it->getHandle() == handle) {
+ return it;
+ }
+ }
+ return nullptr;
+}
+
+/**
+ * @return A vector containing pointers to each characteristic associated with this service.
+ */
+std::vector NimBLEService::getCharacteristics() {
+ return m_chrVec;
+}
+
+/**
+ * @return A vector containing pointers to each characteristic with the provided UUID associated with this service.
+ */
+std::vector NimBLEService::getCharacteristics(const char *uuid) {
+ return getCharacteristics(NimBLEUUID(uuid));
+}
+
+/**
+ * @return A vector containing pointers to each characteristic with the provided UUID associated with this service.
+ */
+std::vector NimBLEService::getCharacteristics(const NimBLEUUID &uuid) {
+ std::vector result;
+ for (auto &it : m_chrVec) {
+ if (it->getUUID() == uuid) {
+ result.push_back(it);
+ }
+ }
+ return result;
+}
/**
* @brief Return a string representation of this service.
@@ -295,7 +339,7 @@ std::string NimBLEService::toString() {
*/
NimBLEServer* NimBLEService::getServer() {
return m_pServer;
-} // getServer
+}// getServer
#endif // #if defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
#endif // CONFIG_BT_ENABLED
diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEService.h b/lib/libesp32/NimBLE-Arduino/src/NimBLEService.h
index 191d97fa5..1203d3e3b 100644
--- a/lib/libesp32/NimBLE-Arduino/src/NimBLEService.h
+++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEService.h
@@ -35,6 +35,16 @@ class NimBLECharacteristic;
*/
class NimBLEService {
public:
+
+ NimBLEServer* getServer();
+
+ NimBLEUUID getUUID();
+ uint16_t getHandle();
+ std::string toString();
+ void dump();
+
+ bool start();
+
NimBLECharacteristic* createCharacteristic(const char* uuid,
uint32_t properties =
NIMBLE_PROPERTY::READ |
@@ -45,14 +55,14 @@ public:
NIMBLE_PROPERTY::READ |
NIMBLE_PROPERTY::WRITE);
- void dump();
- NimBLECharacteristic* getCharacteristic(const char* uuid);
- NimBLECharacteristic* getCharacteristic(const NimBLEUUID &uuid);
- NimBLEUUID getUUID();
- NimBLEServer* getServer();
- bool start();
- std::string toString();
- uint16_t getHandle();
+ NimBLECharacteristic* getCharacteristic(const char* uuid, uint16_t instanceId = 0);
+ NimBLECharacteristic* getCharacteristic(const NimBLEUUID &uuid, uint16_t instanceId = 0);
+ NimBLECharacteristic* getCharacteristicByHandle(uint16_t handle);
+
+ std::vector getCharacteristics();
+ std::vector getCharacteristics(const char* uuid);
+ std::vector getCharacteristics(const NimBLEUUID &uuid);
+
private:
NimBLEService(const char* uuid, uint16_t numHandles, NimBLEServer* pServer);
diff --git a/lib/libesp32/NimBLE-Arduino/src/NimBLEUUID.cpp b/lib/libesp32/NimBLE-Arduino/src/NimBLEUUID.cpp
index 21ff27047..ea58ae7b2 100644
--- a/lib/libesp32/NimBLE-Arduino/src/NimBLEUUID.cpp
+++ b/lib/libesp32/NimBLE-Arduino/src/NimBLEUUID.cpp
@@ -65,29 +65,42 @@ static const char* LOG_TAG = "NimBLEUUID";
*this = NimBLEUUID(first, second, third, (uint64_t(fourth) << 48) + fifth);
}
else {
- NIMBLE_LOGE(LOG_TAG,"ERROR: UUID value not 2, 4, 16 or 36 bytes");
m_valueSet = false;
}
} // NimBLEUUID(std::string)
/**
- * @brief Create a UUID from 16 bytes of memory.
+ * @brief Create a UUID from 2, 4, 16 bytes of memory.
* @param [in] pData The pointer to the start of the UUID.
* @param [in] size The size of the data.
* @param [in] msbFirst Is the MSB first in pData memory?
*/
NimBLEUUID::NimBLEUUID(const uint8_t* pData, size_t size, bool msbFirst) {
- if (size != 16) {
- NIMBLE_LOGE(LOG_TAG,"ERROR: UUID length not 16 bytes");
- return;
- }
- m_uuid.u.type = BLE_UUID_TYPE_128;
+ uint8_t *uuidValue = nullptr;
+ switch(size) {
+ case 2:
+ uuidValue = (uint8_t*)&m_uuid.u16.value;
+ m_uuid.u.type = BLE_UUID_TYPE_16;
+ break;
+ case 4:
+ uuidValue = (uint8_t*)&m_uuid.u32.value;
+ m_uuid.u.type = BLE_UUID_TYPE_32;
+ break;
+ case 16:
+ uuidValue = m_uuid.u128.value;
+ m_uuid.u.type = BLE_UUID_TYPE_128;
+ break;
+ default:
+ m_valueSet = false;
+ NIMBLE_LOGE(LOG_TAG, "Invalid UUID size");
+ return;
+ }
if (msbFirst) {
- std::reverse_copy(pData, pData + 16, m_uuid.u128.value);
+ std::reverse_copy(pData, pData + size, uuidValue);
} else {
- memcpy(m_uuid.u128.value, pData, 16);
+ memcpy(uuidValue, pData, size);
}
m_valueSet = true;
} // NimBLEUUID
diff --git a/lib/libesp32/NimBLE-Arduino/src/esp-hci/src/esp_nimble_hci.c b/lib/libesp32/NimBLE-Arduino/src/esp-hci/src/esp_nimble_hci.c
index 98c133fa5..9af13c355 100644
--- a/lib/libesp32/NimBLE-Arduino/src/esp-hci/src/esp_nimble_hci.c
+++ b/lib/libesp32/NimBLE-Arduino/src/esp-hci/src/esp_nimble_hci.c
@@ -523,10 +523,6 @@ esp_err_t esp_nimble_hci_and_controller_init(void)
esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
- /* Added to ensure BLE only mode */
- bt_cfg.mode = ESP_BT_MODE_BLE;
- /* Added to set max connections from nimconfig */
- bt_cfg.ble_max_conn = CONFIG_BT_NIMBLE_MAX_CONNECTIONS;
if ((ret = esp_bt_controller_init(&bt_cfg)) != ESP_OK) {
return ret;
diff --git a/lib/libesp32/NimBLE-Arduino/src/nimconfig.h b/lib/libesp32/NimBLE-Arduino/src/nimconfig.h
index d90921fa1..5ad95ddb9 100644
--- a/lib/libesp32/NimBLE-Arduino/src/nimconfig.h
+++ b/lib/libesp32/NimBLE-Arduino/src/nimconfig.h
@@ -1,145 +1,156 @@
-/** @file
- *
- * IGNORE THIS FILE IF USING ESP-IDF, USE MENUCONFIG TO SET NIMBLE OPTIONS.
- *
- * The config options here are for Arduino use only.
- */
-
-#pragma once
+ #pragma once
#include "sdkconfig.h"
-
-/*
- * For ESP-IDF compatibility
- * Some versions of ESP-IDF used the config name format "CONFIG_NIMBLE_".
- * This converts them to "CONFIG_BT_NIMBLE_" format used in the latest IDF.
- */
-
-/* Detect if using ESP-IDF or Arduino (Arduino won't have these defines in sdkconfig)
- *
- * Note: We do not use #ifdef CONFIG_BT_NIMBLE_ENABLED since we cannot enable NimBLE when using
- * Arduino as a component and the esp-nimble-compnent, so we check if other config options are defined.
- * We also need to use a config parameter that must be present and not likely defined in the command line.
- */
-#if defined(CONFIG_BT_NIMBLE_GAP_DEVICE_NAME_MAX_LEN) || defined(CONFIG_NIMBLE_GAP_DEVICE_NAME_MAX_LEN)
-
-#if defined(CONFIG_NIMBLE_ENABLED) && !defined(CONFIG_BT_NIMBLE_ENABLED)
-#define CONFIG_BT_NIMBLE_ENABLED
-#endif
-
-#if defined(CONFIG_NIMBLE_ROLE_OBSERVER) && !defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
-#define CONFIG_BT_NIMBLE_ROLE_OBSERVER
-#endif
-
-#if defined(CONFIG_NIMBLE_ROLE_BROADCASTER) && !defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
-#define CONFIG_BT_NIMBLE_ROLE_BROADCASTER
-#endif
-
-#if defined(CONFIG_NIMBLE_ROLE_CENTRAL) && !defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
-#define CONFIG_BT_NIMBLE_ROLE_CENTRAL
-#endif
-
-#if defined(CONFIG_NIMBLE_ROLE_PERIPHERAL) && !defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
-#define CONFIG_BT_NIMBLE_ROLE_PERIPHERAL
-#endif
-
-#if defined(CONFIG_NIMBLE_DEBUG) && !defined(CONFIG_BT_NIMBLE_DEBUG)
-#define CONFIG_BT_NIMBLE_DEBUG
-#endif
-
-#else // Using Arduino
+#include "nimconfig_rename.h"
/***********************************************
- * Arduino config options start here
+ * Arduino user-config options start here
**********************************************/
-/** @brief Comment out if not using NimBLE Client functions \n
- * Reduces flash size by approx. 7kB.
- */
-#ifndef CONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED
-#define CONFIG_BT_NIMBLE_ROLE_CENTRAL
-#endif
+/** @brief Un-comment to change the number of simultaneous connections (esp controller max is 9) */
+// #define CONFIG_BT_NIMBLE_MAX_CONNECTIONS 3
-/** @brief Comment out if not using NimBLE Scan functions \n
- * Reduces flash size by approx. 26kB.
- */
-#ifndef CONFIG_BT_NIMBLE_ROLE_OBSERVER_DISABLED
-#define CONFIG_BT_NIMBLE_ROLE_OBSERVER
-#endif
+/** @brief Un-comment to change the default MTU size */
+// #define CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU 255
-/** @brief Comment out if not using NimBLE Server functions \n
- * Reduces flash size by approx. 16kB.
- */
-#ifndef CONFIG_BT_NIMBLE_ROLE_PERIPHERAL_DISABLED
-#define CONFIG_BT_NIMBLE_ROLE_PERIPHERAL
-#endif
+/** @brief Un-comment to change default device name */
+// #define CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME "nimble"
-/** @brief Comment out if not using NimBLE Advertising functions \n
- * Reduces flash size by approx. 5kB.
- */
-#ifndef CONFIG_BT_NIMBLE_ROLE_BROADCASTER_DISABLED
-#define CONFIG_BT_NIMBLE_ROLE_BROADCASTER
-#endif
-
-/* Uncomment to see debug log messages from the NimBLE host
+/** @brief Un-comment to see debug log messages from the NimBLE host
* Uses approx. 32kB of flash memory.
*/
// #define CONFIG_BT_NIMBLE_DEBUG
-/* Uncomment to see NimBLE host return codes as text debug log messages.
+/** @brief Un-comment to see NimBLE host return codes as text debug log messages.
* Uses approx. 7kB of flash memory.
*/
// #define CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT
-/* Uncomment to see GAP event codes as text in debug log messages.
+/** @brief Un-comment to see GAP event codes as text in debug log messages.
* Uses approx. 1kB of flash memory.
*/
// #define CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT
-/* Uncomment to see advertisment types as text while scanning in debug log messages.
+/** @brief Un-comment to see advertisment types as text while scanning in debug log messages.
* Uses approx. 250 bytes of flash memory.
*/
// #define CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT
-/** @brief Sets the core NimBLE host runs on */
+/** @brief Un-comment to change the default GAP appearance */
+// #define CONFIG_BT_NIMBLE_SVC_GAP_APPEARANCE 0x0
+
+ /** @brief Un-comment if not using NimBLE Client functions \n
+ * Reduces flash size by approx. 7kB.
+ */
+// #define CONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED
+
+/** @brief Un-comment if not using NimBLE Scan functions \n
+ * Reduces flash size by approx. 26kB.
+ */
+// #define CONFIG_BT_NIMBLE_ROLE_OBSERVER_DISABLED
+
+/** @brief Un-comment if not using NimBLE Server functions \n
+ * Reduces flash size by approx. 16kB.
+ */
+// #define CONFIG_BT_NIMBLE_ROLE_PERIPHERAL_DISABLED
+
+/** @brief Un-comment if not using NimBLE Advertising functions \n
+ * Reduces flash size by approx. 5kB.
+ */
+// #define CONFIG_BT_NIMBLE_ROLE_BROADCASTER_DISABLED
+
+/** @brief Un-comment to change the number of devices allowed to store/bond with */
+// #define CONFIG_BT_NIMBLE_MAX_BONDS 3
+
+/** @brief Un-comment to change the maximum number of CCCD subscriptions to store */
+// #define CONFIG_BT_NIMBLE_MAX_CCCDS 8
+
+/** @brief Un-comment to change the random address refresh time (in seconds) */
+// #define CONFIG_BT_NIMBLE_RPA_TIMEOUT 900
+
+/**
+ * @brief Un-comment to change the number of MSYS buffers available.
+ * @details MSYS is a system level mbuf registry. For prepare write & prepare \n
+ * responses MBUFs are allocated out of msys_1 pool. This may need to be increased if\n
+ * you are sending large blocks of data with a low MTU. E.g: 512 bytes with 23 MTU will fail.
+ */
+// #define CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT 12
+
+/** @brief Un-comment to use external PSRAM for the NimBLE host */
+// #define CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL 1
+
+/** @brief Un-comment to change the core NimBLE host runs on */
+// #define CONFIG_BT_NIMBLE_PINNED_TO_CORE 0
+
+/** @brief Un-comment to change the stack size for the NimBLE host task */
+// #define CONFIG_BT_NIMBLE_TASK_STACK_SIZE 4096
+
+/**********************************
+ End Arduino user-config
+**********************************/
+
+/* This section should not be altered */
+#ifndef CONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED
+#define CONFIG_BT_NIMBLE_ROLE_CENTRAL
+#endif
+
+#ifndef CONFIG_BT_NIMBLE_ROLE_OBSERVER_DISABLED
+#define CONFIG_BT_NIMBLE_ROLE_OBSERVER
+#endif
+
+#ifndef CONFIG_BT_NIMBLE_ROLE_PERIPHERAL_DISABLED
+#define CONFIG_BT_NIMBLE_ROLE_PERIPHERAL
+#endif
+
+#ifndef CONFIG_BT_NIMBLE_ROLE_BROADCASTER_DISABLED
+#define CONFIG_BT_NIMBLE_ROLE_BROADCASTER
+#endif
+
#ifndef CONFIG_BT_NIMBLE_PINNED_TO_CORE
#define CONFIG_BT_NIMBLE_PINNED_TO_CORE 0
#endif
-/** @brief Sets the stack size for the NimBLE host task */
#ifndef CONFIG_BT_NIMBLE_TASK_STACK_SIZE
#define CONFIG_BT_NIMBLE_TASK_STACK_SIZE 4096
#endif
-/**
- * @brief Sets the memory pool where NimBLE will be loaded
- * @details By default NimBLE is loaded in internal ram.\n
- * To use external PSRAM you must change this to `#define CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL 1`
- */
#ifndef CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_EXTERNAL
#define CONFIG_BT_NIMBLE_MEM_ALLOC_MODE_INTERNAL 1
#endif
-/** @brief Sets the number of simultaneous connections (esp controller max is 9) */
#ifndef CONFIG_BT_NIMBLE_MAX_CONNECTIONS
#define CONFIG_BT_NIMBLE_MAX_CONNECTIONS 3
#endif
-/** @brief Sets the number of devices allowed to store/bond with */
#ifndef CONFIG_BT_NIMBLE_MAX_BONDS
#define CONFIG_BT_NIMBLE_MAX_BONDS 3
#endif
-/** @brief Sets the maximum number of CCCD subscriptions to store */
#ifndef CONFIG_BT_NIMBLE_MAX_CCCDS
#define CONFIG_BT_NIMBLE_MAX_CCCDS 8
#endif
-/** @brief Default device name */
#ifndef CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME
#define CONFIG_BT_NIMBLE_SVC_GAP_DEVICE_NAME "nimble"
#endif
+#ifndef CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU
+#define CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU 255
+#endif
+
+#ifndef CONFIG_BT_NIMBLE_SVC_GAP_APPEARANCE
+#define CONFIG_BT_NIMBLE_SVC_GAP_APPEARANCE 0x0
+#endif
+
+#ifndef CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT
+#define CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT 12
+#endif
+
+#ifndef CONFIG_BT_NIMBLE_RPA_TIMEOUT
+#define CONFIG_BT_NIMBLE_RPA_TIMEOUT 900
+#endif
+
+
/** @brief Set if CCCD's and bond data should be stored in NVS */
#define CONFIG_BT_NIMBLE_NVS_PERSIST 1
@@ -152,12 +163,6 @@
/** @brief Max device name length (bytes) */
#define CONFIG_BT_NIMBLE_GAP_DEVICE_NAME_MAX_LEN 31
-/** @brief Default MTU size */
-#define CONFIG_BT_NIMBLE_ATT_PREFERRED_MTU 256
-
-/** @brief Default GAP appearance */
-#define CONFIG_BT_NIMBLE_SVC_GAP_APPEARANCE 0x0
-
/** @brief ACL Buffer count */
#define CONFIG_BT_NIMBLE_ACL_BUF_COUNT 12
@@ -173,21 +178,9 @@
/** @brief Number of low priority HCI event buffers */
#define CONFIG_BT_NIMBLE_HCI_EVT_LO_BUF_COUNT 8
-/**
- * @brief Sets the number of MSYS buffers available.
- * @details MSYS is a system level mbuf registry. For prepare write & prepare \n
- * responses MBUFs are allocated out of msys_1 pool. This may need to be increased if\n
- * you are sending large blocks of data with a low MTU. E.g: 512 bytes with 23 MTU will fail.
- */
-#define CONFIG_BT_NIMBLE_MSYS1_BLOCK_COUNT 12
-
-/** @brief Random address refresh time in seconds */
-#define CONFIG_BT_NIMBLE_RPA_TIMEOUT 900
-
/** @brief Maximum number of connection oriented channels */
#define CONFIG_BT_NIMBLE_L2CAP_COC_MAX_NUM 0
-/* These should not be altered */
#define CONFIG_BT_NIMBLE_HS_FLOW_CTRL 1
#define CONFIG_BT_NIMBLE_HS_FLOW_CTRL_ITVL 1000
#define CONFIG_BT_NIMBLE_HS_FLOW_CTRL_THRESH 2
@@ -197,14 +190,9 @@
#define CONFIG_BT_ENABLED
#endif
+#ifndef CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY
#define CONFIG_BTDM_CONTROLLER_MODE_BLE_ONLY
-
-#endif // #if defined(CONFIG_BT_NIMBLE_TASK_STACK_SIZE) || defined(CONFIG_NIMBLE_TASK_STACK_SIZE)
-
-/**********************************
- End Arduino config
-**********************************/
-
+#endif
/* Cannot use client without scan */
#if defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL) && !defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
@@ -216,26 +204,3 @@
#define CONFIG_BT_NIMBLE_ROLE_BROADCASTER
#endif
-
-
-#ifdef _DOXYGEN_
-/** @brief Uncomment to see debug log messages from the NimBLE host \n
- * Uses approx. 32kB of flash memory.
- */
-#define CONFIG_BT_NIMBLE_DEBUG
-
-/** @brief Uncomment to see NimBLE host return codes as text debug log messages. \n
- * Uses approx. 7kB of flash memory.
- */
-#define CONFIG_NIMBLE_CPP_ENABLE_RETURN_CODE_TEXT
-
-/** @brief Uncomment to see GAP event codes as text in debug log messages. \n
- * Uses approx. 1kB of flash memory.
- */
-#define CONFIG_NIMBLE_CPP_ENABLE_GAP_EVENT_CODE_TEXT
-
-/** @brief Uncomment to see advertisment types as text while scanning in debug log messages. \n
- * Uses approx. 250 bytes of flash memory.
- */
-#define CONFIG_NIMBLE_CPP_ENABLE_ADVERTISMENT_TYPE_TEXT
-#endif // _DOXYGEN_
diff --git a/lib/libesp32/NimBLE-Arduino/src/nimconfig_rename.h b/lib/libesp32/NimBLE-Arduino/src/nimconfig_rename.h
new file mode 100644
index 000000000..3b96c1fec
--- /dev/null
+++ b/lib/libesp32/NimBLE-Arduino/src/nimconfig_rename.h
@@ -0,0 +1,53 @@
+/*
+ * For ESP-IDF compatibility
+ * Some versions of ESP-IDF used the config name format "CONFIG_NIMBLE_".
+ * This converts them to "CONFIG_BT_NIMBLE_" format used in the latest IDF.
+ */
+
+#if defined(CONFIG_NIMBLE_ENABLED) && !defined(CONFIG_BT_NIMBLE_ENABLED)
+#define CONFIG_BT_NIMBLE_ENABLED
+#endif
+
+#if defined(CONFIG_NIMBLE_ROLE_OBSERVER) && !defined(CONFIG_BT_NIMBLE_ROLE_OBSERVER)
+#define CONFIG_BT_NIMBLE_ROLE_OBSERVER
+#endif
+
+#if defined(CONFIG_NIMBLE_ROLE_BROADCASTER) && !defined(CONFIG_BT_NIMBLE_ROLE_BROADCASTER)
+#define CONFIG_BT_NIMBLE_ROLE_BROADCASTER
+#endif
+
+#if defined(CONFIG_NIMBLE_ROLE_CENTRAL) && !defined(CONFIG_BT_NIMBLE_ROLE_CENTRAL)
+#define CONFIG_BT_NIMBLE_ROLE_CENTRAL
+#endif
+
+#if defined(CONFIG_NIMBLE_ROLE_PERIPHERAL) && !defined(CONFIG_BT_NIMBLE_ROLE_PERIPHERAL)
+#define CONFIG_BT_NIMBLE_ROLE_PERIPHERAL
+#endif
+
+#if defined(CONFIG_NIMBLE_DEBUG) && !defined(CONFIG_BT_NIMBLE_DEBUG)
+#define CONFIG_BT_NIMBLE_DEBUG
+#endif
+
+#if defined(CONFIG_SCAN_DUPLICATE_BY_DEVICE_ADDR) && !defined(CONFIG_BTDM_SCAN_DUPL_TYPE_DEVICE)
+#define CONFIG_BTDM_SCAN_DUPL_TYPE_DEVICE CONFIG_SCAN_DUPLICATE_BY_DEVICE_ADDR
+#endif
+
+#if defined(CONFIG_SCAN_DUPLICATE_BY_ADV_DATA ) && !defined(CONFIG_BTDM_SCAN_DUPL_TYPE_DATA)
+#define CONFIG_BTDM_SCAN_DUPL_TYPE_DATA CONFIG_SCAN_DUPLICATE_BY_ADV_DATA
+#endif
+
+#if defined(CONFIG_SCAN_DUPLICATE_BY_ADV_DATA_AND_DEVICE_ADDR) && !defined(CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE)
+#define CONFIG_BTDM_SCAN_DUPL_TYPE_DATA_DEVICE CONFIG_SCAN_DUPLICATE_BY_ADV_DATA_AND_DEVICE_ADDR
+#endif
+
+#if defined(CONFIG_SCAN_DUPLICATE_TYPE) && !defined(CONFIG_BTDM_SCAN_DUPL_TYPE)
+#define CONFIG_BTDM_SCAN_DUPL_TYPE CONFIG_SCAN_DUPLICATE_TYPE
+#endif
+
+#if defined(CONFIG_DUPLICATE_SCAN_CACHE_SIZE) && !defined(CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE)
+#define CONFIG_BTDM_SCAN_DUPL_CACHE_SIZE CONFIG_DUPLICATE_SCAN_CACHE_SIZE
+#endif
+
+#if defined(CONFIG_NIMBLE_MAX_CONNECTIONS ) && !defined(CONFIG_BT_NIMBLE_MAX_CONNECTIONS)
+#define CONFIG_BT_NIMBLE_MAX_CONNECTIONS CONFIG_NIMBLE_MAX_CONNECTIONS
+#endif
diff --git a/tasmota/xsns_62_esp32_mi_ble.ino b/tasmota/xsns_62_esp32_mi_ble.ino
index 7820d7cef..5aaf238a4 100644
--- a/tasmota/xsns_62_esp32_mi_ble.ino
+++ b/tasmota/xsns_62_esp32_mi_ble.ino
@@ -5,6 +5,7 @@
Copyright (C) 2020 Christian Baars and Theo Arends
+ Also Simon Hailes and Robert Klauco
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -23,6 +24,9 @@
--------------------------------------------------------------------------------------------
Version yyyymmdd Action Description
--------------------------------------------------------------------------------------------
+ 0.9.2.1 20210217 changed - make features alos depend on received data - i.e. 'unknown' devices will show what they send.
+ Add MI32Option6 1 to switch to tele/tasmota_ble/ style MQTT independent of HASS discovery.
+ -------
0.9.2.0 20210127 changed - Officially includes as the mi driver when using USE_BLE_ESP32.
-------
0.9.1.9 20201226 changed - All change now.
@@ -124,6 +128,7 @@ struct {
uint32_t ignoreBogusBattery:1;
uint32_t minimalSummary:1; // DEPRECATED!!
uint32_t onlyAliased:1; // only include sensors that are aliased
+ uint32_t MQTTType:1;
} option;
} MI32;
@@ -279,6 +284,8 @@ struct mi_sensor_t{
uint32_t NMT:1;
uint32_t PIR:1;
uint32_t Btn:1;
+ uint32_t events:1;
+ uint32_t pairing:1;
};
uint32_t raw;
} feature;
@@ -1409,6 +1416,7 @@ uint32_t MIBLEgetSensorSlot(const uint8_t *mac, uint16_t _type, uint8_t counter)
_newSensor.events=0x00;
_newSensor.feature.PIR=1;
_newSensor.feature.NMT=1;
+ _newSensor.feature.events=1;
break;
case MI_MJYD2S:
_newSensor.NMT=0;
@@ -1417,6 +1425,7 @@ uint32_t MIBLEgetSensorSlot(const uint8_t *mac, uint16_t _type, uint8_t counter)
_newSensor.feature.NMT=1;
_newSensor.feature.lux=1;
_newSensor.feature.bat=1;
+ _newSensor.feature.events=1;
break;
case MI_YEERC:
case MI_DOOR:
@@ -1637,15 +1646,25 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){
char tmp[20];
BLE_ESP32::dump(tmp, 20, (uint8_t*)&(parsed->payload), parsed->payload.size+3);
if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG_MORE,PSTR("M32: MI%d payload %s"), _slot, tmp);
+
+ // clear this for every payload
+ MIBLEsensors[_slot].pairing = 0;
+ MIBLEsensors[_slot].eventType.PairBtn = 0;
switch(parsed->payload.type){
case 0x01: // button press
MIBLEsensors[_slot].Btn = pld->Btn.num + (pld->Btn.longPress/2)*6;
+ MIBLEsensors[_slot].feature.Btn = 1;
MIBLEsensors[_slot].eventType.Btn = 1;
MI32.mode.shallTriggerTele = 1;
+ MIBLEsensors[_slot].shallSendMQTT = 1;
break;
- case 0x02:
- res = 0;
+ case 0x02: // related to pair button?
+ MIBLEsensors[_slot].pairing = 1;
+ MIBLEsensors[_slot].eventType.PairBtn = 1;
+ MIBLEsensors[_slot].feature.pairing = 1;
+ MI32.mode.shallTriggerTele = 1;
+ MIBLEsensors[_slot].shallSendMQTT = 1;
break;
case 0x03: {// motion? 1 byte
uint8_t motion = parsed->payload.data[0];
@@ -1655,6 +1674,7 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){
float _tempFloat=(float)(pld->temp)/10.0f;
if(_tempFloat<60){
MIBLEsensors[_slot].temp=_tempFloat;
+ MIBLEsensors[_slot].feature.temp = 1;
MIBLEsensors[_slot].eventType.temp = 1;
if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG_MORE,PSTR("M32: Mode 4: temp updated"));
} else {
@@ -1666,6 +1686,7 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){
float _tempFloat=(float)(pld->hum)/10.0f;
if(_tempFloat<101){
MIBLEsensors[_slot].hum=_tempFloat;
+ MIBLEsensors[_slot].feature.hum = 1;
MIBLEsensors[_slot].eventType.hum = 1;
if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG_MORE,PSTR("M32: Mode 6: hum updated"));
} else {
@@ -1679,17 +1700,20 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){
MIBLEsensors[_slot].eventType.noMotion = 1;
}
MIBLEsensors[_slot].eventType.lux = 1;
+ MIBLEsensors[_slot].feature.lux = 1;
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Mode 7: U24: %u Lux"), _beacon.lux & 0x00ffffff);
break;
case 0x08:
MIBLEsensors[_slot].moisture=pld->moist;
MIBLEsensors[_slot].eventType.moist = 1;
+ MIBLEsensors[_slot].feature.moist = 1;
if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG_MORE,PSTR("M32: Mode 8: moisture updated"));
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Mode 8: U8: %u Moisture"), _beacon.moist);
break;
case 0x09: // 'conductivity'
MIBLEsensors[_slot].fertility=pld->fert;
MIBLEsensors[_slot].eventType.fert = 1;
+ MIBLEsensors[_slot].feature.fert = 1;
if (BLE_ESP32::BLEDebugMode > 0) AddLog(LOG_LEVEL_DEBUG_MORE,PSTR("M32: Mode 9: fertility updated"));
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Mode 9: U16: %u Fertility"), _beacon.fert);
break;
@@ -1700,6 +1724,7 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){
break;
}
}
+ MIBLEsensors[_slot].feature.bat = 1;
if(pld->bat<101){
MIBLEsensors[_slot].bat = pld->bat;
MIBLEsensors[_slot].eventType.bat = 1;
@@ -1712,6 +1737,7 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Mode a: U8: %u %%"), _beacon.bat);
break;
case 0x0d:{
+ MIBLEsensors[_slot].feature.tempHum = 1;
float _tempFloat=(float)(pld->HT.temp)/10.0f;
if(_tempFloat < 60){
MIBLEsensors[_slot].temp = _tempFloat;
@@ -1738,6 +1764,11 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){
MIBLEsensors[_slot].eventType.lux = 1;
MIBLEsensors[_slot].NMT = 0;
MI32.mode.shallTriggerTele = 1;
+ MIBLEsensors[_slot].shallSendMQTT = 1;
+ MIBLEsensors[_slot].feature.lux = 1;
+ MIBLEsensors[_slot].feature.NMT = 1;
+ MIBLEsensors[_slot].feature.events=1;
+
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: PIR: primary"),MIBLEsensors[_slot].lux );
break;
case 0x10:{ // 'formaldehide'
@@ -1762,6 +1793,9 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){
MIBLEsensors[_slot].NMT = pld->NMT;
MIBLEsensors[_slot].eventType.NMT = 1;
MI32.mode.shallTriggerTele = 1;
+ MIBLEsensors[_slot].shallSendMQTT = 1;
+ MIBLEsensors[_slot].feature.NMT = 1;
+
// AddLog(LOG_LEVEL_DEBUG,PSTR("M32: Mode 17: NMT: %u seconds"), _beacon.NMT);
} break;
@@ -1769,6 +1803,8 @@ int MI32parseMiPayload(int _slot, struct mi_beacon_data_t *parsed){
MIBLEsensors[_slot].Btn = uint8_t(parsed->payload.data[0]); // just an 8 bit value in a union.
MIBLEsensors[_slot].eventType.Btn = 1;
MI32.mode.shallTriggerTele = 1;
+ MIBLEsensors[_slot].shallSendMQTT = 1;
+ MIBLEsensors[_slot].feature.Btn = 1;
} break;
default: {
@@ -1904,10 +1940,12 @@ void MI32EverySecond(bool restart){
// AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("M32: onesec"));
MI32TimeoutSensors();
- MI32ShowSomeSensors();
-
- MI32DiscoveryOneMISensor();
- MI32ShowOneMISensor();
+ if (MI32.option.MQTTType == 0){
+ MI32ShowSomeSensors();
+ } else {
+ MI32DiscoveryOneMISensor();
+ MI32ShowOneMISensor();
+ }
// read a battery if
// MI32.batteryreader.slot < filled and !MI32.batteryreader.active
@@ -2132,16 +2170,24 @@ void CmndMi32Option(void){
bool onOff = atoi(XdrvMailbox.data);
switch(XdrvMailbox.index) {
case 0:
- MI32.option.allwaysAggregate = onOff;
+ MI32.option.allwaysAggregate = onOff;
+ ResponseCmndNumber(onOff);
+ return;
break;
case 1:
MI32.option.noSummary = onOff;
+ ResponseCmndNumber(onOff);
+ return;
break;
case 2:
MI32.option.directBridgeMode = onOff;
+ ResponseCmndNumber(onOff);
+ return;
break;
case 4:{
MI32.option.ignoreBogusBattery = onOff;
+ ResponseCmndNumber(onOff);
+ return;
} break;
case 5:{
MI32.option.onlyAliased = onOff;
@@ -2149,7 +2195,15 @@ void CmndMi32Option(void){
// discard all sensors for a restart
MIBLEsensors.clear();
}
+ ResponseCmndNumber(onOff);
+ return;
} break;
+ case 6:{
+ MI32.option.MQTTType = onOff;
+ ResponseCmndNumber(onOff);
+ return;
+ } break;
+
}
ResponseCmndDone();
}
@@ -2249,7 +2303,7 @@ void CmndMi32Keys(void){
* Presentation
\*********************************************************************************************/
-const char HTTP_MI32[] PROGMEM = "{s}MI ESP32 v0920{m}%u%s / %u{e}";
+const char HTTP_MI32[] PROGMEM = "{s}MI ESP32 v0921{m}%u%s / %u{e}";
const char HTTP_MI32_ALIAS[] PROGMEM = "{s}%s Alias {m}%s{e}";
const char HTTP_MI32_MAC[] PROGMEM = "{s}%s %s{m}%s{e}";
const char HTTP_RSSI[] PROGMEM = "{s}%s " D_RSSI "{m}%d dBm{e}";
@@ -2527,9 +2581,13 @@ void MI32ShowSomeSensors(){
ResponseTime_P(PSTR(""));
int cnt = 0;
- for (; (MI32.mqttCurrentSlot < numsensors) && (cnt < 4); MI32.mqttCurrentSlot++, cnt++) {
+ int maxcnt = 4;
+ mi_sensor_t *p;
+ for (; (MI32.mqttCurrentSlot < numsensors) && (cnt < maxcnt); MI32.mqttCurrentSlot++, cnt++) {
ResponseAppend_P(PSTR(","));
- MI32GetOneSensorJson(MI32.mqttCurrentSlot, 0);
+ p = &MIBLEsensors[MI32.mqttCurrentSlot];
+
+ MI32GetOneSensorJson(MI32.mqttCurrentSlot, (maxcnt == 1));
int mlen = strlen(TasmotaGlobal.mqtt_data);
// if we ran out of room, leave here.
@@ -2537,6 +2595,7 @@ void MI32ShowSomeSensors(){
MI32.mqttCurrentSlot++;
break;
}
+ cnt++;
}
ResponseAppend_P(PSTR("}"));
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
@@ -2567,8 +2626,13 @@ void MI32ShowOneMISensor(){
return;
}
+ if(
#ifdef USE_HOME_ASSISTANT
- if(Settings.flag.hass_discovery){
+ Settings.flag.hass_discovery
+ ||
+#endif //USE_HOME_ASSISTANT
+ MI32.option.MQTTType == 1
+ ){
ResponseTime_P(PSTR(","));
MI32GetOneSensorJson(MI32.mqttCurrentSingleSlot, 1);
@@ -2594,7 +2658,6 @@ void MI32ShowOneMISensor(){
MqttPublish(SensorTopic);
//AddLog_P(LOG_LEVEL_DEBUG,PSTR("M32: %s: show some %d %s"),D_CMND_MI32, MI32.mqttCurrentSlot, TasmotaGlobal.mqtt_data);
}
-#endif //USE_HOME_ASSISTANT
MI32.mqttCurrentSingleSlot++;
}
@@ -2749,11 +2812,23 @@ void MI32ShowTriggeredSensors(){
int sensor = 0;
+ int maxcnt = 4;
+ if(
+#ifdef USE_HOME_ASSISTANT
+ Settings.flag.hass_discovery
+ ||
+#endif //USE_HOME_ASSISTANT
+ MI32.option.MQTTType == 1
+ ){
+ maxcnt = 1;
+ }
+
+
do {
ResponseTime_P(PSTR(""));
int cnt = 0;
- for (; (sensor < numsensors) && (cnt < 4); sensor++) {
- mi_sensor_t *p;
+ mi_sensor_t *p;
+ for (; (sensor < numsensors) && (cnt < maxcnt); sensor++) {
p = &MIBLEsensors[sensor];
if(p->eventType.raw == 0) continue;
if(p->shallSendMQTT==0) continue;
@@ -2771,7 +2846,30 @@ void MI32ShowTriggeredSensors(){
}
if (cnt){ // if we got one, then publish
ResponseAppend_P(PSTR("}"));
- MqttPublishPrefixTopic_P(STAT, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
+ if(
+ #ifdef USE_HOME_ASSISTANT
+ Settings.flag.hass_discovery
+ ||
+ #endif //USE_HOME_ASSISTANT
+ MI32.option.MQTTType == 1
+ ){
+ char SensorTopic[60];
+ char idstr[32];
+ const char *alias = BLE_ESP32::getAlias(p->MAC);
+ const char *id = idstr;
+ if (alias && *alias){
+ id = alias;
+ } else {
+ sprintf(idstr, PSTR("%s%02x%02x%02x"),
+ kMI32DeviceType[p->type-1],
+ p->MAC[3], p->MAC[4], p->MAC[5]);
+ }
+ sprintf(SensorTopic, "tele/tasmota_ble/%s",
+ id);
+ MqttPublish(SensorTopic);
+ } else {
+ MqttPublishPrefixTopic_P(STAT, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
+ }
AddLog(LOG_LEVEL_DEBUG,PSTR("M32: %s: triggered %d %s"),D_CMND_MI32, sensor, TasmotaGlobal.mqtt_data);
#ifdef USE_RULES
@@ -2887,21 +2985,25 @@ void MI32Show(bool json)
WSContentSend_PD(HTTP_NEEDKEY, typeName, _MAC, Webserver->client().localIP().toString().c_str(), tmp );
}
- if (p->type==MI_NLIGHT || p->type==MI_MJYD2S) {
-#else
- if (p->type==MI_NLIGHT) {
#endif //USE_MI_DECRYPTION
+
+ if (p->feature.events){
WSContentSend_PD(HTTP_EVENTS, typeName, p->events);
+ }
+ if (p->feature.NMT){
+ // no motion time
if(p->NMT>0) WSContentSend_PD(HTTP_NMT, typeName, p->NMT);
}
- if (p->lux!=0x00ffffff) { // this is the error code -> no valid value
- WSContentSend_PD(HTTP_SNS_ILLUMINANCE, typeName, p->lux);
+ if (p->feature.lux){
+ if (p->lux!=0x00ffffff) { // this is the error code -> no valid value
+ WSContentSend_PD(HTTP_SNS_ILLUMINANCE, typeName, p->lux);
+ }
}
if(p->bat!=0x00){
WSContentSend_PD(HTTP_BATTERY, typeName, p->bat);
}
- if (p->type==MI_YEERC || p->type==MI_DOOR){
+ if (p->feature.Btn){
WSContentSend_PD(HTTP_LASTBUTTON, typeName, p->Btn);
}
if (p->pairing){