* Fix issue #3833, data parsing of Eddystone TLM data frame Add Beacon scanner example to show usage of BLEEddystoneTLM class and BLEEddystoneURL class Add EddystoneTLM beacon example Add EddystoneURL beacon example * Fix buffer size for .toString()
This commit is contained in:
parent
9856f0cc28
commit
ef2b54547e
153
libraries/BLE/examples/BLE_Beacon_Scanner/BLE_Beacon_Scanner.ino
Normal file
153
libraries/BLE/examples/BLE_Beacon_Scanner/BLE_Beacon_Scanner.ino
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp
|
||||||
|
Ported to Arduino ESP32 by Evandro Copercini
|
||||||
|
Changed to a beacon scanner to report iBeacon, EddystoneURL and EddystoneTLM beacons by beegee-tokyo
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include <BLEDevice.h>
|
||||||
|
#include <BLEUtils.h>
|
||||||
|
#include <BLEScan.h>
|
||||||
|
#include <BLEAdvertisedDevice.h>
|
||||||
|
#include <BLEEddystoneURL.h>
|
||||||
|
#include <BLEEddystoneTLM.h>
|
||||||
|
#include <BLEBeacon.h>
|
||||||
|
|
||||||
|
#define ENDIAN_CHANGE_U16(x) ((((x)&0xFF00) >> 8) + (((x)&0xFF) << 8))
|
||||||
|
|
||||||
|
int scanTime = 5; //In seconds
|
||||||
|
BLEScan *pBLEScan;
|
||||||
|
|
||||||
|
class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
|
||||||
|
{
|
||||||
|
void onResult(BLEAdvertisedDevice advertisedDevice)
|
||||||
|
{
|
||||||
|
if (advertisedDevice.haveName())
|
||||||
|
{
|
||||||
|
Serial.print("Device name: ");
|
||||||
|
Serial.println(advertisedDevice.getName().c_str());
|
||||||
|
Serial.println("");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (advertisedDevice.haveServiceUUID())
|
||||||
|
{
|
||||||
|
BLEUUID devUUID = advertisedDevice.getServiceUUID();
|
||||||
|
Serial.print("Found ServiceUUID: ");
|
||||||
|
Serial.println(devUUID.toString().c_str());
|
||||||
|
Serial.println("");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (advertisedDevice.haveManufacturerData() == true)
|
||||||
|
{
|
||||||
|
std::string strManufacturerData = advertisedDevice.getManufacturerData();
|
||||||
|
|
||||||
|
uint8_t cManufacturerData[100];
|
||||||
|
strManufacturerData.copy((char *)cManufacturerData, strManufacturerData.length(), 0);
|
||||||
|
|
||||||
|
if (strManufacturerData.length() == 25 && cManufacturerData[0] == 0x4C && cManufacturerData[1] == 0x00)
|
||||||
|
{
|
||||||
|
Serial.println("Found an iBeacon!");
|
||||||
|
BLEBeacon oBeacon = BLEBeacon();
|
||||||
|
oBeacon.setData(strManufacturerData);
|
||||||
|
Serial.printf("iBeacon Frame\n");
|
||||||
|
Serial.printf("ID: %04X Major: %d Minor: %d UUID: %s Power: %d\n", oBeacon.getManufacturerId(), ENDIAN_CHANGE_U16(oBeacon.getMajor()), ENDIAN_CHANGE_U16(oBeacon.getMinor()), oBeacon.getProximityUUID().toString().c_str(), oBeacon.getSignalPower());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Serial.println("Found another manufacturers beacon!");
|
||||||
|
Serial.printf("strManufacturerData: %d ", strManufacturerData.length());
|
||||||
|
for (int i = 0; i < strManufacturerData.length(); i++)
|
||||||
|
{
|
||||||
|
Serial.printf("[%X]", cManufacturerData[i]);
|
||||||
|
}
|
||||||
|
Serial.printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *payLoad = advertisedDevice.getPayload();
|
||||||
|
|
||||||
|
BLEUUID checkUrlUUID = (uint16_t)0xfeaa;
|
||||||
|
|
||||||
|
if (advertisedDevice.getServiceUUID().equals(checkUrlUUID))
|
||||||
|
{
|
||||||
|
if (payLoad[11] == 0x10)
|
||||||
|
{
|
||||||
|
Serial.println("Found an EddystoneURL beacon!");
|
||||||
|
BLEEddystoneURL foundEddyURL = BLEEddystoneURL();
|
||||||
|
std::string eddyContent((char *)&payLoad[11]); // incomplete EddystoneURL struct!
|
||||||
|
|
||||||
|
foundEddyURL.setData(eddyContent);
|
||||||
|
std::string bareURL = foundEddyURL.getURL();
|
||||||
|
if (bareURL[0] == 0x00)
|
||||||
|
{
|
||||||
|
size_t payLoadLen = advertisedDevice.getPayloadLength();
|
||||||
|
Serial.println("DATA-->");
|
||||||
|
for (int idx = 0; idx < payLoadLen; idx++)
|
||||||
|
{
|
||||||
|
Serial.printf("0x%08X ", payLoad[idx]);
|
||||||
|
}
|
||||||
|
Serial.println("\nInvalid Data");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Serial.printf("Found URL: %s\n", foundEddyURL.getURL().c_str());
|
||||||
|
Serial.printf("Decoded URL: %s\n", foundEddyURL.getDecodedURL().c_str());
|
||||||
|
Serial.printf("TX power %d\n", foundEddyURL.getPower());
|
||||||
|
Serial.println("\n");
|
||||||
|
}
|
||||||
|
else if (payLoad[11] == 0x20)
|
||||||
|
{
|
||||||
|
Serial.println("Found an EddystoneTLM beacon!");
|
||||||
|
BLEEddystoneTLM foundEddyURL = BLEEddystoneTLM();
|
||||||
|
std::string eddyContent((char *)&payLoad[11]); // incomplete EddystoneURL struct!
|
||||||
|
|
||||||
|
eddyContent = "01234567890123";
|
||||||
|
|
||||||
|
for (int idx = 0; idx < 14; idx++)
|
||||||
|
{
|
||||||
|
eddyContent[idx] = payLoad[idx + 11];
|
||||||
|
}
|
||||||
|
|
||||||
|
foundEddyURL.setData(eddyContent);
|
||||||
|
Serial.printf("Reported battery voltage: %dmV\n", foundEddyURL.getVolt());
|
||||||
|
Serial.printf("Reported temperature from TLM class: %.2fC\n", (double)foundEddyURL.getTemp());
|
||||||
|
int temp = (int)payLoad[16] + (int)(payLoad[15] << 8);
|
||||||
|
float calcTemp = temp / 256.0f;
|
||||||
|
Serial.printf("Reported temperature from data: %.2fC\n", calcTemp);
|
||||||
|
Serial.printf("Reported advertise count: %d\n", foundEddyURL.getCount());
|
||||||
|
Serial.printf("Reported time since last reboot: %ds\n", foundEddyURL.getTime());
|
||||||
|
Serial.println("\n");
|
||||||
|
Serial.print(foundEddyURL.toString().c_str());
|
||||||
|
Serial.println("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println("Scanning...");
|
||||||
|
|
||||||
|
BLEDevice::init("");
|
||||||
|
pBLEScan = BLEDevice::getScan(); //create new scan
|
||||||
|
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
|
||||||
|
pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
|
||||||
|
pBLEScan->setInterval(100);
|
||||||
|
pBLEScan->setWindow(99); // less or equal setInterval value
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
// put your main code here, to run repeatedly:
|
||||||
|
BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
|
||||||
|
Serial.print("Devices found: ");
|
||||||
|
Serial.println(foundDevices.getCount());
|
||||||
|
Serial.println("Scan done!");
|
||||||
|
pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory
|
||||||
|
delay(2000);
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
## BLE Beacon Scanner
|
||||||
|
|
||||||
|
Initiates a BLE device scan.
|
||||||
|
Checks if the discovered devices are
|
||||||
|
- an iBeacon
|
||||||
|
- an Eddystone TLM beacon
|
||||||
|
- an Eddystone URL beacon
|
||||||
|
|
||||||
|
and sends the decoded beacon information over Serial log
|
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
EddystoneTLM beacon by BeeGee based on https://github.com/pcbreflux/espressif/blob/master/esp32/arduino/sketchbook/ESP32_Eddystone_TLM_deepsleep/ESP32_Eddystone_TLM_deepsleep.ino
|
||||||
|
EddystoneTLM frame specification https://github.com/google/eddystone/blob/master/eddystone-tlm/tlm-plain.md
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create a BLE server that will send periodic Eddystone URL frames.
|
||||||
|
The design of creating the BLE server is:
|
||||||
|
1. Create a BLE Server
|
||||||
|
2. Create advertising data
|
||||||
|
3. Start advertising.
|
||||||
|
4. wait
|
||||||
|
5. Stop advertising.
|
||||||
|
6. deep sleep
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include "sys/time.h"
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include "BLEDevice.h"
|
||||||
|
#include "BLEUtils.h"
|
||||||
|
#include "BLEBeacon.h"
|
||||||
|
#include "BLEAdvertising.h"
|
||||||
|
#include "BLEEddystoneURL.h"
|
||||||
|
|
||||||
|
#include "esp_sleep.h"
|
||||||
|
|
||||||
|
#define GPIO_DEEP_SLEEP_DURATION 10 // sleep x seconds and then wake up
|
||||||
|
RTC_DATA_ATTR static time_t last; // remember last boot in RTC Memory
|
||||||
|
RTC_DATA_ATTR static uint32_t bootcount; // remember number of boots in RTC Memory
|
||||||
|
|
||||||
|
// See the following for generating UUIDs:
|
||||||
|
// https://www.uuidgenerator.net/
|
||||||
|
BLEAdvertising *pAdvertising;
|
||||||
|
struct timeval nowTimeStruct;
|
||||||
|
|
||||||
|
time_t lastTenth;
|
||||||
|
|
||||||
|
#define BEACON_UUID "8ec76ea3-6668-48da-9866-75be8bc86f4d" // UUID 1 128-Bit (may use linux tool uuidgen or random numbers via https://www.uuidgenerator.net/)
|
||||||
|
|
||||||
|
// Check
|
||||||
|
// https://github.com/google/eddystone/blob/master/eddystone-tlm/tlm-plain.md
|
||||||
|
// and http://www.hugi.scene.org/online/coding/hugi%2015%20-%20cmtadfix.htm
|
||||||
|
// for the temperature value. It is a 8.8 fixed-point notation
|
||||||
|
void setBeacon()
|
||||||
|
{
|
||||||
|
char beacon_data[25];
|
||||||
|
uint16_t beconUUID = 0xFEAA;
|
||||||
|
uint16_t volt = random(2800, 3700); // 3300mV = 3.3V
|
||||||
|
float tempFloat = random(2000, 3100) / 100.0f;
|
||||||
|
Serial.printf("Random temperature is %.2fC\n", tempFloat);
|
||||||
|
int temp = (int)(tempFloat * 256); //(uint16_t)((float)23.00);
|
||||||
|
Serial.printf("Converted to 8.8 format %0X%0X\n", (temp >> 8), (temp & 0xFF));
|
||||||
|
|
||||||
|
BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
|
||||||
|
BLEAdvertisementData oScanResponseData = BLEAdvertisementData();
|
||||||
|
|
||||||
|
oScanResponseData.setFlags(0x06); // GENERAL_DISC_MODE 0x02 | BR_EDR_NOT_SUPPORTED 0x04
|
||||||
|
oScanResponseData.setCompleteServices(BLEUUID(beconUUID));
|
||||||
|
|
||||||
|
beacon_data[0] = 0x20; // Eddystone Frame Type (Unencrypted Eddystone-TLM)
|
||||||
|
beacon_data[1] = 0x00; // TLM version
|
||||||
|
beacon_data[2] = (volt >> 8); // Battery voltage, 1 mV/bit i.e. 0xCE4 = 3300mV = 3.3V
|
||||||
|
beacon_data[3] = (volt & 0xFF); //
|
||||||
|
beacon_data[4] = (temp >> 8); // Beacon temperature
|
||||||
|
beacon_data[5] = (temp & 0xFF); //
|
||||||
|
beacon_data[6] = ((bootcount & 0xFF000000) >> 24); // Advertising PDU count
|
||||||
|
beacon_data[7] = ((bootcount & 0xFF0000) >> 16); //
|
||||||
|
beacon_data[8] = ((bootcount & 0xFF00) >> 8); //
|
||||||
|
beacon_data[9] = (bootcount & 0xFF); //
|
||||||
|
beacon_data[10] = ((lastTenth & 0xFF000000) >> 24); // Time since power-on or reboot as 0.1 second resolution counter
|
||||||
|
beacon_data[11] = ((lastTenth & 0xFF0000) >> 16); //
|
||||||
|
beacon_data[12] = ((lastTenth & 0xFF00) >> 8); //
|
||||||
|
beacon_data[13] = (lastTenth & 0xFF); //
|
||||||
|
|
||||||
|
oScanResponseData.setServiceData(BLEUUID(beconUUID), std::string(beacon_data, 14));
|
||||||
|
oAdvertisementData.setName("TLMBeacon");
|
||||||
|
pAdvertising->setAdvertisementData(oAdvertisementData);
|
||||||
|
pAdvertising->setScanResponseData(oScanResponseData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
gettimeofday(&nowTimeStruct, NULL);
|
||||||
|
|
||||||
|
Serial.printf("start ESP32 %d\n", bootcount++);
|
||||||
|
|
||||||
|
Serial.printf("deep sleep (%lds since last reset, %lds since last boot)\n", nowTimeStruct.tv_sec, nowTimeStruct.tv_sec - last);
|
||||||
|
|
||||||
|
last = nowTimeStruct.tv_sec;
|
||||||
|
lastTenth = nowTimeStruct.tv_sec * 10; // Time since last reset as 0.1 second resolution counter
|
||||||
|
|
||||||
|
// Create the BLE Device
|
||||||
|
BLEDevice::init("TLMBeacon");
|
||||||
|
|
||||||
|
BLEDevice::setPower(ESP_PWR_LVL_N12);
|
||||||
|
|
||||||
|
pAdvertising = BLEDevice::getAdvertising();
|
||||||
|
|
||||||
|
setBeacon();
|
||||||
|
// Start advertising
|
||||||
|
pAdvertising->start();
|
||||||
|
Serial.println("Advertizing started for 10s ...");
|
||||||
|
delay(10000);
|
||||||
|
pAdvertising->stop();
|
||||||
|
Serial.printf("enter deep sleep for 10s\n");
|
||||||
|
esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION);
|
||||||
|
Serial.printf("in deep sleep\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
## Eddystone TLM beacon
|
||||||
|
EddystoneTLM beacon by BeeGee based on
|
||||||
|
[pcbreflux ESP32 Eddystone TLM deepsleep](https://github.com/pcbreflux/espressif/blob/master/esp32/arduino/sketchbook/ESP32_Eddystone_TLM_deepsleep/ESP32_Eddystone_TLM_deepsleep.ino)
|
||||||
|
|
||||||
|
[EddystoneTLM frame specification](https://github.com/google/eddystone/blob/master/eddystone-tlm/tlm-plain.md)
|
||||||
|
|
||||||
|
Create a BLE server that will send periodic Eddystone TLM frames.
|
||||||
|
The design of creating the BLE server is:
|
||||||
|
1. Create a BLE Server
|
||||||
|
2. Create advertising data
|
||||||
|
3. Start advertising.
|
||||||
|
4. wait
|
||||||
|
5. Stop advertising.
|
||||||
|
6. deep sleep
|
@ -0,0 +1,192 @@
|
|||||||
|
/*
|
||||||
|
EddystoneURL beacon by BeeGee
|
||||||
|
EddystoneURL frame specification https://github.com/google/eddystone/blob/master/eddystone-url/README.md
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create a BLE server that will send periodic Eddystone URL frames.
|
||||||
|
The design of creating the BLE server is:
|
||||||
|
1. Create a BLE Server
|
||||||
|
2. Create advertising data
|
||||||
|
3. Start advertising.
|
||||||
|
4. wait
|
||||||
|
5. Stop advertising.
|
||||||
|
6. deep sleep
|
||||||
|
|
||||||
|
*/
|
||||||
|
#include "sys/time.h"
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
#include "BLEDevice.h"
|
||||||
|
#include "BLEUtils.h"
|
||||||
|
#include "BLEBeacon.h"
|
||||||
|
#include "BLEAdvertising.h"
|
||||||
|
#include "BLEEddystoneURL.h"
|
||||||
|
|
||||||
|
#include "esp_sleep.h"
|
||||||
|
|
||||||
|
#define GPIO_DEEP_SLEEP_DURATION 10 // sleep x seconds and then wake up
|
||||||
|
RTC_DATA_ATTR static time_t last; // remember last boot in RTC Memory
|
||||||
|
RTC_DATA_ATTR static uint32_t bootcount; // remember number of boots in RTC Memory
|
||||||
|
|
||||||
|
// See the following for generating UUIDs:
|
||||||
|
// https://www.uuidgenerator.net/
|
||||||
|
BLEAdvertising *pAdvertising;
|
||||||
|
struct timeval now;
|
||||||
|
|
||||||
|
#define BEACON_UUID "8ec76ea3-6668-48da-9866-75be8bc86f4d" // UUID 1 128-Bit (may use linux tool uuidgen or random numbers via https://www.uuidgenerator.net/)
|
||||||
|
|
||||||
|
static const char *eddystone_url_prefix_subs[] = {
|
||||||
|
"http://www.",
|
||||||
|
"https://www.",
|
||||||
|
"http://",
|
||||||
|
"https://",
|
||||||
|
"urn:uuid:",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *eddystone_url_suffix_subs[] = {
|
||||||
|
".com/",
|
||||||
|
".org/",
|
||||||
|
".edu/",
|
||||||
|
".net/",
|
||||||
|
".info/",
|
||||||
|
".biz/",
|
||||||
|
".gov/",
|
||||||
|
".com",
|
||||||
|
".org",
|
||||||
|
".edu",
|
||||||
|
".net",
|
||||||
|
".info",
|
||||||
|
".biz",
|
||||||
|
".gov",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
static int string_begin_with(const char *str, const char *prefix)
|
||||||
|
{
|
||||||
|
int prefix_len = strlen(prefix);
|
||||||
|
if (strncmp(prefix, str, prefix_len) == 0)
|
||||||
|
{
|
||||||
|
return prefix_len;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setBeacon()
|
||||||
|
{
|
||||||
|
BLEAdvertisementData oAdvertisementData = BLEAdvertisementData();
|
||||||
|
BLEAdvertisementData oScanResponseData = BLEAdvertisementData();
|
||||||
|
|
||||||
|
const char url[] = "https://d.giesecke.tk";
|
||||||
|
|
||||||
|
int scheme_len, ext_len = 1, i, idx, url_idx;
|
||||||
|
char *ret_data;
|
||||||
|
int url_len = strlen(url);
|
||||||
|
|
||||||
|
ret_data = (char *)calloc(1, url_len + 13);
|
||||||
|
|
||||||
|
ret_data[0] = 2; // Len
|
||||||
|
ret_data[1] = 0x01; // Type Flags
|
||||||
|
ret_data[2] = 0x06; // GENERAL_DISC_MODE 0x02 | BR_EDR_NOT_SUPPORTED 0x04
|
||||||
|
ret_data[3] = 3; // Len
|
||||||
|
ret_data[4] = 0x03; // Type 16-Bit UUID
|
||||||
|
ret_data[5] = 0xAA; // Eddystone UUID 2 -> 0xFEAA LSB
|
||||||
|
ret_data[6] = 0xFE; // Eddystone UUID 1 MSB
|
||||||
|
ret_data[7] = 19; // Length of Beacon Data
|
||||||
|
ret_data[8] = 0x16; // Type Service Data
|
||||||
|
ret_data[9] = 0xAA; // Eddystone UUID 2 -> 0xFEAA LSB
|
||||||
|
ret_data[10] = 0xFE; // Eddystone UUID 1 MSB
|
||||||
|
ret_data[11] = 0x10; // Eddystone Frame Type
|
||||||
|
ret_data[12] = 0xF4; // Beacons TX power at 0m
|
||||||
|
|
||||||
|
i = 0, idx = 13, url_idx = 0;
|
||||||
|
|
||||||
|
//replace prefix
|
||||||
|
scheme_len = 0;
|
||||||
|
while (eddystone_url_prefix_subs[i] != NULL)
|
||||||
|
{
|
||||||
|
if ((scheme_len = string_begin_with(url, eddystone_url_prefix_subs[i])) > 0)
|
||||||
|
{
|
||||||
|
ret_data[idx] = i;
|
||||||
|
idx++;
|
||||||
|
url_idx += scheme_len;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
while (url_idx < url_len)
|
||||||
|
{
|
||||||
|
i = 0;
|
||||||
|
ret_data[idx] = url[url_idx];
|
||||||
|
ext_len = 1;
|
||||||
|
while (eddystone_url_suffix_subs[i] != NULL)
|
||||||
|
{
|
||||||
|
if ((ext_len = string_begin_with(&url[url_idx], eddystone_url_suffix_subs[i])) > 0)
|
||||||
|
{
|
||||||
|
ret_data[idx] = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ext_len = 1; //inc 1
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
url_idx += ext_len;
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
ret_data[7] = idx - 8;
|
||||||
|
|
||||||
|
Serial.printf("struct size %d url size %d reported len %d\n",
|
||||||
|
url_len + 13,
|
||||||
|
url_len, ret_data[7]);
|
||||||
|
|
||||||
|
Serial.printf("URL in data %s\n", &ret_data[13]);
|
||||||
|
|
||||||
|
std::string eddyStoneData(ret_data);
|
||||||
|
|
||||||
|
oAdvertisementData.addData(eddyStoneData);
|
||||||
|
oScanResponseData.setName("URLBeacon");
|
||||||
|
pAdvertising->setAdvertisementData(oAdvertisementData);
|
||||||
|
pAdvertising->setScanResponseData(oScanResponseData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
|
||||||
|
Serial.printf("start ESP32 %d\n", bootcount++);
|
||||||
|
|
||||||
|
Serial.printf("deep sleep (%lds since last reset, %lds since last boot)\n", now.tv_sec, now.tv_sec - last);
|
||||||
|
|
||||||
|
last = now.tv_sec;
|
||||||
|
|
||||||
|
// Create the BLE Device
|
||||||
|
BLEDevice::init("URLBeacon");
|
||||||
|
|
||||||
|
BLEDevice::setPower(ESP_PWR_LVL_N12);
|
||||||
|
|
||||||
|
// Create the BLE Server
|
||||||
|
// BLEServer *pServer = BLEDevice::createServer(); // <-- no longer required to instantiate BLEServer, less flash and ram usage
|
||||||
|
|
||||||
|
pAdvertising = BLEDevice::getAdvertising();
|
||||||
|
|
||||||
|
setBeacon();
|
||||||
|
// Start advertising
|
||||||
|
pAdvertising->start();
|
||||||
|
Serial.println("Advertizing started...");
|
||||||
|
delay(10000);
|
||||||
|
pAdvertising->stop();
|
||||||
|
Serial.printf("enter deep sleep\n");
|
||||||
|
esp_deep_sleep(1000000LL * GPIO_DEEP_SLEEP_DURATION);
|
||||||
|
Serial.printf("in deep sleep\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
## Eddystone URL beacon
|
||||||
|
EddystoneURL beacon by BeeGee based on
|
||||||
|
[pcbreflux ESP32 Eddystone URL deepsleep](https://github.com/pcbreflux/espressif/tree/master/esp32/arduino/sketchbook/ESP32_Eddystone_URL_deepsleep)
|
||||||
|
|
||||||
|
[EddystoneURL frame specification](https://github.com/google/eddystone/blob/master/eddystone-url/README.md)
|
||||||
|
|
||||||
|
Create a BLE server that will send periodic Eddystone URL frames.
|
||||||
|
The design of creating the BLE server is:
|
||||||
|
1. Create a BLE Server
|
||||||
|
2. Create advertising data
|
||||||
|
3. Start advertising.
|
||||||
|
4. wait
|
||||||
|
5. Stop advertising.
|
||||||
|
6. deep sleep
|
@ -3,6 +3,11 @@
|
|||||||
*
|
*
|
||||||
* Created on: Mar 12, 2018
|
* Created on: Mar 12, 2018
|
||||||
* Author: pcbreflux
|
* Author: pcbreflux
|
||||||
|
* Edited on: Mar 20, 2020 by beegee-tokyo
|
||||||
|
* Fix temperature value (8.8 fixed format)
|
||||||
|
* Fix time stamp (0.1 second resolution)
|
||||||
|
* Fixes based on EddystoneTLM frame specification https://github.com/google/eddystone/blob/master/eddystone-tlm/tlm-plain.md
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
#if defined(CONFIG_BT_ENABLED)
|
#if defined(CONFIG_BT_ENABLED)
|
||||||
@ -20,7 +25,7 @@ BLEEddystoneTLM::BLEEddystoneTLM() {
|
|||||||
m_eddystoneData.frameType = EDDYSTONE_TLM_FRAME_TYPE;
|
m_eddystoneData.frameType = EDDYSTONE_TLM_FRAME_TYPE;
|
||||||
m_eddystoneData.version = 0;
|
m_eddystoneData.version = 0;
|
||||||
m_eddystoneData.volt = 3300; // 3300mV = 3.3V
|
m_eddystoneData.volt = 3300; // 3300mV = 3.3V
|
||||||
m_eddystoneData.temp = (uint16_t) ((float) 23.00);
|
m_eddystoneData.temp = (uint16_t) ((float) 23.00)/256;
|
||||||
m_eddystoneData.advCount = 0;
|
m_eddystoneData.advCount = 0;
|
||||||
m_eddystoneData.tmil = 0;
|
m_eddystoneData.tmil = 0;
|
||||||
} // BLEEddystoneTLM
|
} // BLEEddystoneTLM
|
||||||
@ -38,41 +43,50 @@ uint8_t BLEEddystoneTLM::getVersion() {
|
|||||||
} // getVersion
|
} // getVersion
|
||||||
|
|
||||||
uint16_t BLEEddystoneTLM::getVolt() {
|
uint16_t BLEEddystoneTLM::getVolt() {
|
||||||
return m_eddystoneData.volt;
|
return ENDIAN_CHANGE_U16(m_eddystoneData.volt);
|
||||||
} // getVolt
|
} // getVolt
|
||||||
|
|
||||||
float BLEEddystoneTLM::getTemp() {
|
float BLEEddystoneTLM::getTemp() {
|
||||||
return (float)m_eddystoneData.temp;
|
return ENDIAN_CHANGE_U16(m_eddystoneData.temp) / 256.0f;
|
||||||
} // getTemp
|
} // getTemp
|
||||||
|
|
||||||
uint32_t BLEEddystoneTLM::getCount() {
|
uint32_t BLEEddystoneTLM::getCount() {
|
||||||
return m_eddystoneData.advCount;
|
return ENDIAN_CHANGE_U32(m_eddystoneData.advCount);
|
||||||
} // getCount
|
} // getCount
|
||||||
|
|
||||||
uint32_t BLEEddystoneTLM::getTime() {
|
uint32_t BLEEddystoneTLM::getTime() {
|
||||||
return m_eddystoneData.tmil;
|
return (ENDIAN_CHANGE_U32(m_eddystoneData.tmil)) / 10;
|
||||||
} // getTime
|
} // getTime
|
||||||
|
|
||||||
std::string BLEEddystoneTLM::toString() {
|
std::string BLEEddystoneTLM::toString() {
|
||||||
std::string out = "";
|
std::string out = "";
|
||||||
uint32_t rawsec = ENDIAN_CHANGE_U32(m_eddystoneData.tmil);
|
uint32_t rawsec = ENDIAN_CHANGE_U32(m_eddystoneData.tmil);
|
||||||
char val[6];
|
char val[12];
|
||||||
|
|
||||||
out += "Version " + m_eddystoneData.version;
|
out += "Version "; // + std::string(m_eddystoneData.version);
|
||||||
|
snprintf(val, sizeof(val), "%d", m_eddystoneData.version);
|
||||||
|
out += val;
|
||||||
out += "\n";
|
out += "\n";
|
||||||
out += "Battery Voltage " + ENDIAN_CHANGE_U16(m_eddystoneData.volt);
|
out += "Battery Voltage "; // + ENDIAN_CHANGE_U16(m_eddystoneData.volt);
|
||||||
|
snprintf(val, sizeof(val), "%d", ENDIAN_CHANGE_U16(m_eddystoneData.volt));
|
||||||
|
out += val;
|
||||||
out += " mV\n";
|
out += " mV\n";
|
||||||
|
|
||||||
out += "Temperature ";
|
out += "Temperature ";
|
||||||
snprintf(val, sizeof(val), "%d", m_eddystoneData.temp);
|
snprintf(val, sizeof(val), "%.2f", ENDIAN_CHANGE_U16(m_eddystoneData.temp) / 256.0f);
|
||||||
out += val;
|
out += val;
|
||||||
out += ".0 °C\n";
|
out += " C\n";
|
||||||
|
|
||||||
out += "Adv. Count ";
|
out += "Adv. Count ";
|
||||||
snprintf(val, sizeof(val), "%d", ENDIAN_CHANGE_U32(m_eddystoneData.advCount));
|
snprintf(val, sizeof(val), "%d", ENDIAN_CHANGE_U32(m_eddystoneData.advCount));
|
||||||
out += val;
|
out += val;
|
||||||
out += "\n";
|
out += "\n";
|
||||||
|
|
||||||
|
out += "Time in seconds ";
|
||||||
|
snprintf(val, sizeof(val), "%d", rawsec/10);
|
||||||
|
out += val;
|
||||||
|
out += "\n";
|
||||||
|
|
||||||
out += "Time ";
|
out += "Time ";
|
||||||
|
|
||||||
snprintf(val, sizeof(val), "%04d", rawsec / 864000);
|
snprintf(val, sizeof(val), "%04d", rawsec / 864000);
|
||||||
|
Loading…
Reference in New Issue
Block a user