From b96129a6e65cfbf41fe7230087ad410ef39bd267 Mon Sep 17 00:00:00 2001 From: rbaron Date: Fri, 12 Feb 2021 18:21:11 +0100 Subject: [PATCH] Quick and dirty ble advetiment --- code/parasite/lib/parasite/ble.cpp | 5 -- code/parasite/lib/parasite/parasite/ble.cpp | 1 + .../lib/parasite/{ => parasite}/ble.h | 2 +- .../lib/parasite/{ => parasite}/pwm.cpp | 0 .../lib/parasite/{ => parasite}/pwm.h | 0 code/parasite/platformio.ini | 4 +- code/parasite/src/main.cpp | 49 ++++++++++++------- resources.md | 47 +++++++++++++++++- 8 files changed, 80 insertions(+), 28 deletions(-) delete mode 100644 code/parasite/lib/parasite/ble.cpp create mode 100644 code/parasite/lib/parasite/parasite/ble.cpp rename code/parasite/lib/parasite/{ => parasite}/ble.h (98%) rename code/parasite/lib/parasite/{ => parasite}/pwm.cpp (100%) rename code/parasite/lib/parasite/{ => parasite}/pwm.h (100%) diff --git a/code/parasite/lib/parasite/ble.cpp b/code/parasite/lib/parasite/ble.cpp deleted file mode 100644 index 460a88f..0000000 --- a/code/parasite/lib/parasite/ble.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "ble.h" - -#include "ble_advdata.h" -#include "nrf_sdh.h" -#include "nrf_sdh_ble.h" \ No newline at end of file diff --git a/code/parasite/lib/parasite/parasite/ble.cpp b/code/parasite/lib/parasite/parasite/ble.cpp new file mode 100644 index 0000000..8ef29e1 --- /dev/null +++ b/code/parasite/lib/parasite/parasite/ble.cpp @@ -0,0 +1 @@ +#include "ble.h" \ No newline at end of file diff --git a/code/parasite/lib/parasite/ble.h b/code/parasite/lib/parasite/parasite/ble.h similarity index 98% rename from code/parasite/lib/parasite/ble.h rename to code/parasite/lib/parasite/parasite/ble.h index 128561b..2c51365 100644 --- a/code/parasite/lib/parasite/ble.h +++ b/code/parasite/lib/parasite/parasite/ble.h @@ -8,7 +8,7 @@ namespace parasite { class BLEAdvertiser { public: void Advertise(std::string name, double moisture) {} -} +}; } // namespace parasite #endif // _PARASITE_BLE_H_ \ No newline at end of file diff --git a/code/parasite/lib/parasite/pwm.cpp b/code/parasite/lib/parasite/parasite/pwm.cpp similarity index 100% rename from code/parasite/lib/parasite/pwm.cpp rename to code/parasite/lib/parasite/parasite/pwm.cpp diff --git a/code/parasite/lib/parasite/pwm.h b/code/parasite/lib/parasite/parasite/pwm.h similarity index 100% rename from code/parasite/lib/parasite/pwm.h rename to code/parasite/lib/parasite/parasite/pwm.h diff --git a/code/parasite/platformio.ini b/code/parasite/platformio.ini index 3082ed1..04dbfa3 100644 --- a/code/parasite/platformio.ini +++ b/code/parasite/platformio.ini @@ -8,14 +8,12 @@ ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html -[common] -lib_deps = sandeepmistry/BLEPeripheral@^0.4.0 [env:e73-tbb] platform = nordicnrf52 board = adafruit_feather_nrf52832 framework = arduino -build_flags = -DNRF52 -DS132 -DNRF51_S132 +; build_flags = -DNRF52 -DS132 -DNRF51_S132 -DNRF5 ; Let's keep it simple for now and just use adafruit_feather_nrf52832. ; board = e73-tbb diff --git a/code/parasite/src/main.cpp b/code/parasite/src/main.cpp index 3f7d37a..901c87e 100644 --- a/code/parasite/src/main.cpp +++ b/code/parasite/src/main.cpp @@ -1,9 +1,9 @@ #include -// #include "ble.h" -#include "pwm.h" +#include "parasite/pwm.h" +#include "parasite/ble.h" -#include "nrf_sdh_ble.h" +#include constexpr int kLED1Pin = 17; constexpr int kLED2Pin = 18; @@ -12,22 +12,30 @@ constexpr int kSensAnalogPin = 4; // AIN2 constexpr int kDischargeEnablePin = 16; constexpr double kPWMFrequency = 500000; -// static void ble_stack_init(void) { -// ret_code_t err_code; +char manufacturer_data[] = { + 0x01, + 0x02, + 0x03, +}; -// err_code = nrf_sdh_enable_request(); -// APP_ERROR_CHECK(err_code); +constexpr int kManufacturerDataLen = 3; -// // Configure the BLE stack using the default settings. -// // Fetch the start address of the application RAM. -// uint32_t ram_start = 0; -// err_code = nrf_sdh_ble_default_cfg_set(APP_BLE_CONN_CFG_TAG, &ram_start); -// APP_ERROR_CHECK(err_code); +void setupAdvertising() { + Bluefruit.begin(1, 1); + Bluefruit.setName("Parasite"); +} -// // Enable BLE stack. -// err_code = nrf_sdh_ble_enable(&ram_start); -// APP_ERROR_CHECK(err_code); -// } +void updateAdvertisingData(int moisture_level) { + manufacturer_data[2] = moisture_level & 0xff; + manufacturer_data[1] = 0xff; + Bluefruit.Advertising.stop(); + Bluefruit.Advertising.clearData(); + Bluefruit.Advertising.addName(); + Bluefruit.Advertising.addManufacturerData(manufacturer_data, kManufacturerDataLen); + Bluefruit.Advertising.setInterval(32, 244); // in unit of 0.625 ms + Bluefruit.Advertising.setFastTimeout(30); // number of seconds in fast mode + Bluefruit.Advertising.start(0); // 0 = Don't stop advertising after n seconds +} void setup() { Serial.begin(9600); @@ -37,11 +45,18 @@ void setup() { digitalWrite(kDischargeEnablePin, HIGH); analogReference(AR_VDD4); + + setupAdvertising(); + // Bluefruit.Advertising.start(); + + // ble.setConnectable(false); + // ble.addLocalAttribute(); } void loop() { int sens_val = analogRead(kSensAnalogPin); Serial.printf("Val: %d\n", sens_val); digitalToggle(kLED1Pin); + updateAdvertisingData(sens_val); delay(500); -} \ No newline at end of file +} diff --git a/resources.md b/resources.md index 7770e8f..e506a34 100644 --- a/resources.md +++ b/resources.md @@ -142,7 +142,50 @@ I'm getting ~680 when in the air; ~65 while holding the sensor. The default reso # BLE * BLE examples for platformio with nordicnrf52 platform: [link](https://github.com/platformio/platform-nordicnrf52/tree/master/examples) -* [BLEPeripheral](https://github.com/sandeepmistry/arduino-BLEPeripheral) seems to be a popular library choice * [nrf5 BLE examples](https://devzone.nordicsemi.com/nordic/short-range-guides/b/bluetooth-low-energy/posts/ble-advertising-a-beginners-tutorial) are way more complicated than I need for now +* How the alternative firmware for the xiaomi temp sensor works: [link](https://github.com/atc1441/ATC_MiThermometer) + * The MCU is a [Telink TLSR8251](http://wiki.telink-semi.cn/doc/ds/DS_TLSR8251-E_Datasheet%20for%20Telink%20BLE+IEEE802.15.4%20Multi-Standard%20Wireless%20SoC%20TLSR8251.pdf) + * Deep sleep current is 1-2uA + * It sends an _advertisement packet_ every 1 minute with the MAC, temperature, humidity and battery level + * [main](https://github.com/atc1441/ATC_MiThermometer/blob/master/ATC_Thermometer/main.c) + * [main_loop](https://github.com/atc1441/ATC_MiThermometer/blob/916cef7db24977ec187e68ab6e718b7b7a4988e6/ATC_Thermometer/app.c#L76) + * [advertisement_data](https://github.com/atc1441/ATC_MiThermometer/blob/master/ATC_Thermometer/ble.c#L39) definition + * [set_adv_data](https://github.com/atc1441/ATC_MiThermometer/blob/master/ATC_Thermometer/ble.c#L178) - where the temp, humidity and batt levels are encoded into the advertisement data +* How the xiaomi BLE temp sensor works in ESPHome: [link](https://github.com/esphome/esphome/blob/5c86f332b269fd3e4bffcbdf3359a021419effdd/esphome/components/xiaomi_lywsd03mmc/xiaomi_lywsd03mmc.cpp) +* [How advertisement works YouTube video](https://www.youtube.com/watch?v=CJcLabp42b4) by nordic + * In your case: + * GAP role: broadcaster + * Advertisement type: legacy ADV_NONCONN_IND (non-connectable broadcast) + * Advertising data starts at 22:17 + * The payload might contain 37 bytes in the classic/legacy protocol: + * addr (6 bytes) (either public or random) + * Public has privacy concerns + * Random can be static or private (resolvable or non-resolvable) + * data (31 bytes) + * The 31 bytes of advertisement data can be split into structures + * Each structure has a length (1 byte), a type (n bytes) and data (remaining bytes) + * Examples of structures are service UUID, local name, manufacturer specific data + * Manufacturer specific data is usually the way to transmit data in the advertisement packet + * Requires a company id. Check out the [list](https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers). Adafruit has the 0x0822. +* [BLEPeripheral](https://github.com/sandeepmistry/arduino-BLEPeripheral) seems to be a popular library choice + * [setManufacturerData](https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/161a4163f565be3cd5b62bbc59f0c2b522d82b02/src/BLEPeripheral.h#L72) is probably what we want + * It seems to be highly geared towards nrf51 SOCs, although it mentions support for some nrf52 ones +* [Adafruit_nRF52_Arduino](https://github.com/adafruit/Adafruit_nRF52_Arduino) + * [BLEAdvertising guide](https://learn.adafruit.com/bluefruit-nrf52-feather-learning-guide/bleadvertising) + * [BLEAdvertising.h](https://github.com/adafruit/Adafruit_nRF52_Arduino/blob/master/libraries/Bluefruit52Lib/src/BLEAdvertising.h#L87) +* Can we update the manufaturer advertising data dynamically? + * [Hint on devzone.nordicsemi.com](https://devzone.nordicsemi.com/f/nordic-q-a/11217/adc-values-in-advertising-data-dynamically-changing) -# OTA \ No newline at end of file +# Central BLE +The "central" BLE will be responsible for listening to parasite's BLE broadcasts and parsing its manufacturer's data. +One idea is to use ESPHome for this, for example like the xiaomi sensor does: +* [Xiaomi component's parse_device](https://github.com/esphome/esphome/blob/dev/esphome/components/xiaomi_lywsd03mmc/xiaomi_lywsd03mmc.cpp#L19) +* [esp32_ble_tracker calls all registered parse_devices()](https://github.com/esphome/esphome/blob/dev/esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp#L68) +* [Setting up the development environment for ESPHome](https://esphome.io/guides/contributing.html#setting-up-development-environment) + +Question: parasite will advertise a _lot_ of packets in short bursts. How is this data "deduplicated"? I imagine ESPHome won't parse all the packets and forward them to MQTT. + +# OTA + +# Measuring current consumption +* Good [issue](https://github.com/atc1441/ATC_MiThermometer/issues/134) on the xiaomi sensor tracker \ No newline at end of file