Skip to content

Instantly share code, notes, and snippets.

@kholia
Last active April 7, 2020 09:08
Show Gist options
  • Save kholia/9d74960b7dd39be23a080031f5101bcf to your computer and use it in GitHub Desktop.
Save kholia/9d74960b7dd39be23a080031f5101bcf to your computer and use it in GitHub Desktop.
ESP32 + UT353-BT Mini Sound Level Meter. NO SUPPORT IS PROVIDED.
/**
* A BLE client example that is rich in capabilities.
* There is a lot new capabilities implemented.
* author unknown
* updated by chegewara
*/
// QnD support for "UT353-BT Mini Sound Level Meter" by Dhiru Kholia (March 2020)
// - Publishes sensor data to a Redis server on LAN
// https://raw.githubusercontent.com/RuiSantosdotme/ESP32-Course/master/code/Dual_Core/Dual_Core_Blinking_LEDs/Dual_Core_Blinking_LEDs.ino
#include <WiFi.h>
#include <WiFiMulti.h>
#include <HTTPClient.h>
#include "variables.h"
#include "BLEDevice.h"
//#include "BLEScan.h"
#include <ArduinoJson.h>
TaskHandle_t Task1;
TaskHandle_t Task2;
QueueHandle_t queue;
int capacity = 1024;
// The remote service we wish to connect to - WX_SERVICE_UUID
static BLEUUID serviceUUID("0000FF12-0000-1000-8000-00805f9b34fb");
// The characteristic of the remote service we are interested in - WX_CHAR_UUID
static BLEUUID charUUID("0000FF01-0000-1000-8000-00805f9b34fb");
static BLEUUID WX_NOTIFICATION_UUID("0000FF02-0000-1000-8000-00805f9b34fb");
static boolean doConnect = false;
static boolean connected = false;
static boolean doScan = false;
static BLERemoteCharacteristic *pRemoteCharacteristic,
*pRemoteCharacteristicNotify;
static BLEAdvertisedDevice *myDevice;
static void notifyCallback(BLERemoteCharacteristic *pBLERemoteCharacteristic,
uint8_t *pData, size_t length, bool isNotify) {
static int counter = 0;
counter++;
if (counter % 32 == 0) {
Serial.println("+");
// Serial.println(ESP.getFreeHeap());
counter = 0;
}
/* Serial.print("Notify callback for characteristic ");
Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str());
Serial.print(" of data length ");
Serial.println(length); */
// Serial.print("data: ");
String buf = (char *)pData + 6; // offset to data
float value = buf.toFloat();
// Serial.println(value); // with offset to data
xQueueSend(queue, &value, portMAX_DELAY);
}
class MyClientCallback : public BLEClientCallbacks {
void onConnect(BLEClient *pclient) {}
void onDisconnect(BLEClient *pclient) {
connected = false;
Serial.println("onDisconnect");
}
};
bool connectToServer() {
Serial.print("Forming a connection to ");
Serial.println(myDevice->getAddress().toString().c_str());
BLEClient *pClient = BLEDevice::createClient();
Serial.println(" - Created client");
pClient->setClientCallbacks(new MyClientCallback());
// Connect to the remove BLE Server.
pClient->connect(myDevice); // if you pass BLEAdvertisedDevice instead of
// address, it will be recognized type of peer
// device address (public or private)
Serial.println(" - Connected to server");
// Obtain a reference to the service we are after in the remote BLE server.
BLERemoteService *pRemoteService = pClient->getService(serviceUUID);
if (pRemoteService == nullptr) {
Serial.print("Failed to find our service UUID: ");
Serial.println(serviceUUID.toString().c_str());
pClient->disconnect();
return false;
}
Serial.println(" - Found our service");
// Obtain a reference to the characteristic in the service of the remote BLE
// server.
pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
if (pRemoteCharacteristic == nullptr) {
Serial.print("Failed to find our characteristic UUID: ");
Serial.println(charUUID.toString().c_str());
pClient->disconnect();
return false;
}
Serial.println(" - Found our characteristic");
// notify hack
pRemoteCharacteristicNotify =
pRemoteService->getCharacteristic(WX_NOTIFICATION_UUID);
if (pRemoteCharacteristicNotify == nullptr) {
Serial.print("Failed to find our characteristic UUID: ");
Serial.println(charUUID.toString().c_str());
pClient->disconnect();
return false;
}
Serial.println(" - Found our notify characteristic");
// Read the value of the characteristic.
if (pRemoteCharacteristicNotify->canRead()) {
std::string value = pRemoteCharacteristic->readValue();
Serial.print("The characteristic value was: ");
Serial.println(value.c_str());
}
const uint8_t notificationOn[] = {0x1, 0x0};
pRemoteCharacteristicNotify->getDescriptor(BLEUUID((uint16_t)0x2902))
->writeValue((uint8_t *)notificationOn, 2, true);
if (pRemoteCharacteristic->canNotify())
pRemoteCharacteristic->registerForNotify(notifyCallback);
if (pRemoteCharacteristicNotify->canNotify())
pRemoteCharacteristicNotify->registerForNotify(notifyCallback);
else
Serial.println("Failed to setup notify!");
connected = true;
return true;
}
/**
* Scan for BLE servers and find the first one that advertises the service we
* are looking for.
*/
class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
/**
* Called for each advertising BLE server.
*/
void onResult(BLEAdvertisedDevice advertisedDevice) {
Serial.print("BLE Advertised Device found: ");
Serial.println(advertisedDevice.toString().c_str());
// We have found a device, let us now see if it contains the service we are
// looking for.
if (advertisedDevice.haveServiceUUID() &&
advertisedDevice.isAdvertisingService(serviceUUID)) {
BLEDevice::getScan()->stop();
myDevice = new BLEAdvertisedDevice(advertisedDevice);
doConnect = true;
doScan = true;
} // Found our server
} // onResult
}; // MyAdvertisedDeviceCallbacks
// Not sure if WiFiClientSecure checks the validity date of the certificate.
// Setting clock just to be sure...
void setClock() {
configTime(0, 0, "pool.ntp.org", "time.nist.gov");
Serial.print(F("Waiting for NTP time sync: "));
time_t nowSecs = time(nullptr);
while (nowSecs < 8 * 3600 * 2) {
delay(500);
Serial.print(F("."));
yield();
nowSecs = time(nullptr);
}
Serial.println();
struct tm timeinfo;
gmtime_r(&nowSecs, &timeinfo);
Serial.print(F("Current time: "));
Serial.print(asctime(&timeinfo));
}
WiFiMulti WiFiMulti;
void setup() {
Serial.begin(115200);
Serial.println("Starting Arduino BLE Client application...");
BLEDevice::init("");
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFiMulti.addAP(ssid, password);
// wait for WiFi connection
Serial.print("Waiting for WiFi to connect...");
while ((WiFiMulti.run() != WL_CONNECTED)) {
Serial.print(".");
delay(500);
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
// Retrieve a Scanner and set the callback we want to use to be informed when
// we have detected a new device. Specify that we want active scanning and
// start the scan to run for 5 seconds.
BLEScan *pBLEScan = BLEDevice::getScan();
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setInterval(1349);
pBLEScan->setWindow(449);
pBLEScan->setActiveScan(true);
pBLEScan->start(5, false);
// create a task that will be executed in the Task1Sensor() function, with
// priority 1 and executed on core 0
xTaskCreatePinnedToCore(
Task1Sensor, /* Task function. */
"Task1", /* name of task. */
10000, /* Stack size of task */
NULL, /* parameter of the task */
7, /* priority of the task */
&Task1, /* Task handle to keep track of created task */
0); /* pin task to core 0 */
delay(500);
// create a task that will be executed in the Task2Publish() function, with
// priority 1 and executed on core 1
xTaskCreatePinnedToCore(
Task2Publish,
"Task2",
10000,
NULL,
1,
&Task2,
1);
queue = xQueueCreate(capacity, sizeof(float));
if (queue == NULL) {
Serial.println("Error creating the queue");
}
} // End of setup.
// Task1Sensor: blinks an LED every 1000 ms
void Task1Sensor(void *pvParameters) {
Serial.print("Task1 running on core ");
Serial.println(xPortGetCoreID());
for (;;) {
/* digitalWrite(led1, HIGH);
delay(1000);
digitalWrite(led1, LOW);
delay(1000); */
// If the flag "doConnect" is true then we have scanned for and found the
// desired BLE Server with which we wish to connect. Now we connect to it.
// Once we are connected we set the connected flag to be true.
if (doConnect == true) {
if (connectToServer()) {
Serial.println("We are now connected to the BLE Server.");
} else {
Serial.println("We have failed to connect to the server; there is "
"nothing more we will do.");
}
doConnect = false;
}
// If we are connected to a peer BLE Server, update the characteristic each
// time we are reached with the current time since boot.
if (connected) {
// String newValue = "Time since boot: " + String(millis() / 1000);
// Serial.println("Setting new characteristic value to \"" + newValue +
// "\"");
// Set the characteristic's value to be the array of bytes that is
// actually a string. pRemoteCharacteristic->writeValue(newValue.c_str(),
// newValue.length());
// BluetoothLeService.this.writeRXCharacteristic("0x5e");
pRemoteCharacteristic->writeValue(0x5e, 1);
} else if (doScan) {
BLEDevice::getScan()->start(
0); // this is just eample to start scan after disconnect, most likely
// there is better way to do it in arduino
}
delay(10);
}
}
void Task2Publish(void *pvParameters) {
Serial.print("Task2 running on core ");
Serial.println(xPortGetCoreID());
char buf[1024];
WiFiClient redis;
IPAddress gateway;
float element;
for (;;) {
if ((WiFiMulti.run() == WL_CONNECTED)) {
gateway = WiFi.gatewayIP();
// Serial.println(gateway);
// Serial.println("-");
int qlen = uxQueueMessagesWaiting(queue);
Serial.println(qlen);
for (int i = 0; i < 64; i++) {
redis.connect(gateway, 6379);
xQueueReceive(queue, &element, portMAX_DELAY);
String szValue = String(element);
sprintf(buf, "*3\r\n$5\r\nLPUSH\r\n$4\r\ndata\r\n$%d\r\n%s\r\n", szValue.length(), szValue.c_str());
redis.write(buf);
/* if (redis.available()) {
redis.read();
} */
redis.stop();
}
}
// With delay(10) in sensor loop, we produce < 24 data points every second,
// and we have storage for 1024 such points.
delay(1000);
}
}
void loop() {} // End of loop
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment