From 21fba0481c7ec3c816013b25e8c1992a740ee911 Mon Sep 17 00:00:00 2001 From: Magnus Persson Date: Thu, 10 Mar 2022 11:10:54 +0100 Subject: [PATCH] Added BLE on ESP32 target. --- html/config.htm | 25 +++++++++++- html/config.min.htm | 2 +- html/device.htm | 5 +++ html/device.min.htm | 2 +- src/ble.cpp | 99 +++++++++++++++++++++++++++++++++++++++++++++ src/ble.hpp | 48 ++++++++++++++++++++++ src/config.cpp | 2 + src/config.hpp | 13 ++++++ src/main.cpp | 9 +++++ src/resources.hpp | 2 + src/webserver.cpp | 34 +++++++++++++++- test/config.json | 4 +- test/device.json | 1 + 13 files changed, 241 insertions(+), 5 deletions(-) create mode 100644 src/ble.cpp create mode 100644 src/ble.hpp diff --git a/html/config.htm b/html/config.htm index aae1526..0371175 100644 --- a/html/config.htm +++ b/html/config.htm @@ -374,7 +374,23 @@ -
+
+ +
+ +
+
+
@@ -537,6 +553,13 @@ function checkHeader(input) { $('#spinner').show(); $.getJSON(url, function (cfg) { console.log( cfg ); + + if(cfg["platform"]=="esp32") { + $('#esp32-tilt').removeClass('d-none'); + $('#esp32-ota').addClass('d-none'); + $("#ble").val(cfg["ble"]); + } + $("#id1").val(cfg["id"]); $("#id2").val(cfg["id"]); $("#id3").val(cfg["id"]); diff --git a/html/config.min.htm b/html/config.min.htm index 8d0efd3..acbb4bc 100644 --- a/html/config.min.htm +++ b/html/config.min.htm @@ -1 +1 @@ -Beer Gravity Monitor

Temperature Format:





Gravity Format:


(C) Copyright 2021-22 Magnus Persson
\ No newline at end of file +Beer Gravity Monitor

Temperature Format:





Gravity Format:


(C) Copyright 2021-22 Magnus Persson
\ No newline at end of file diff --git a/html/device.htm b/html/device.htm index d777056..46d84eb 100644 --- a/html/device.htm +++ b/html/device.htm @@ -88,6 +88,10 @@
Device ID:
Loading...
+
+
Platform:
+
Loading...
+
Average runtime:
Loading...
@@ -135,6 +139,7 @@ $("#app-ver").text(cfg["app-ver"] + " (html 0.8.0)"); $("#mdns").text(cfg["mdns"]); $("#id").text(cfg["id"]); + $("#platform").text(cfg["platform"]); $("#runtime").text(cfg["runtime-average"] + " seconds"); }) .fail(function () { diff --git a/html/device.min.htm b/html/device.min.htm index 1f5a4d9..66a338c 100644 --- a/html/device.min.htm +++ b/html/device.min.htm @@ -1 +1 @@ -Beer Gravity Monitor

Current version:
Loading...
Host name:
Loading...
Device ID:
Loading...
Average runtime:
Loading...

(C) Copyright 2021-22 Magnus Persson
\ No newline at end of file +Beer Gravity Monitor

Current version:
Loading...
Host name:
Loading...
Device ID:
Loading...
Platform:
Loading...
Average runtime:
Loading...

(C) Copyright 2021-22 Magnus Persson
\ No newline at end of file diff --git a/src/ble.cpp b/src/ble.cpp new file mode 100644 index 0000000..2af4bfc --- /dev/null +++ b/src/ble.cpp @@ -0,0 +1,99 @@ +/* +MIT License + +Copyright (c) 2021-22 Magnus + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +#if defined(ESP32) + +#include + +// Tilt UUID variants and data format, based on tilt-sim +// +// https://github.com/spouliot/tilt-sim +// +// Tilt data format is described here. Only SG and Temp is transmitted over BLE. +// https://kvurd.com/blog/tilt-hydrometer-ibeacon-data-format/ + +// +// Create ble sender +// +BleSender::BleSender(const char* color) { + BLEDevice::init(""); + + // boost power to maximum, these might be changed once battery life using BLE has been tested. + esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_DEFAULT, ESP_PWR_LVL_P9); + esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_ADV, ESP_PWR_LVL_P9); + esp_ble_tx_power_set(ESP_BLE_PWR_TYPE_SCAN ,ESP_PWR_LVL_P9); + + _advertising = BLEDevice::getAdvertising(); + _color = color; + + if (!_color.compareTo("red")) + _uuid = BLEUUID::fromString("A495BB10-C5B1-4B44-B512-1370F02D74DE"); + else if (!_color.compareTo("green")) + _uuid = BLEUUID::fromString("A495BB20-C5B1-4B44-B512-1370F02D74DE"); + else if (!_color.compareTo("black")) + _uuid = BLEUUID::fromString("A495BB30-C5B1-4B44-B512-1370F02D74DE"); + else if (!_color.compareTo("purple")) + _uuid = BLEUUID::fromString("A495BB40-C5B1-4B44-B512-1370F02D74DE"); + else if (!_color.compareTo("orange")) + _uuid = BLEUUID::fromString("A495BB50-C5B1-4B44-B512-1370F02D74DE"); + else if (!_color.compareTo("blue")) + _uuid = BLEUUID::fromString("A495BB60-C5B1-4B44-B512-1370F02D74DE"); + else if (!_color.compareTo("yellow")) + _uuid = BLEUUID::fromString("A495BB70-C5B1-4B44-B512-1370F02D74DE"); + else // if (_color.compareTo("pink")) + _uuid = BLEUUID::fromString("A495BB80-C5B1-4B44-B512-1370F02D74DE"); +} + +// +// Send temp and gravity via BLE +// +void BleSender::sendData(float tempF, float gravSG) { + uint16_t gravity = gravSG*1000; // SG * 1000 or SG * 10000 for Tilt Pro/HD + uint16_t temperature = tempF; // Deg F _or_ Deg F * 10 for Tilt Pro/HD + + BLEBeacon oBeacon = BLEBeacon(); + oBeacon.setManufacturerId(0x4C00); // fake Apple 0x004C LSB (ENDIAN_CHANGE_U16!) + oBeacon.setProximityUUID(_uuid); + oBeacon.setMajor(temperature); + oBeacon.setMinor(gravity); + std::string strServiceData = ""; + strServiceData += (char)26; // Len + strServiceData += (char)0xFF; // Type + strServiceData += oBeacon.getData(); + + BLEAdvertisementData oAdvertisementData = BLEAdvertisementData(); + oAdvertisementData.setFlags(0x04); // BR_EDR_NOT_SUPPORTED 0x04 + oAdvertisementData.addData(strServiceData); + + BLEAdvertisementData oScanResponseData = BLEAdvertisementData(); + _advertising->setAdvertisementData(oAdvertisementData); + _advertising->setScanResponseData(oScanResponseData); + _advertising->setAdvertisementType(BLE_GAP_CONN_MODE_NON); + + _advertising->start(); + delay(100); + _advertising->stop(); + delay(100); +} + +#endif // ESP32 \ No newline at end of file diff --git a/src/ble.hpp b/src/ble.hpp new file mode 100644 index 0000000..599f118 --- /dev/null +++ b/src/ble.hpp @@ -0,0 +1,48 @@ +/* +MIT License + +Copyright (c) 2021-22 Magnus + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +#ifndef SRC_BLE_HPP_ +#define SRC_BLE_HPP_ + +#if defined (ESP32) + +#include +#include +#include "NimBLEDevice.h" +#include "NimBLEBeacon.h" + +class BleSender { + private: + BLEAdvertising *_advertising; + String _color; + BLEUUID _uuid; + + public: + BleSender(const char* color); + void sendData(float tempF, float gravSG); +}; + +#endif // ESP32 +#endif // SRC_BLE_HPP_ + +// EOF \ No newline at end of file diff --git a/src/config.cpp b/src/config.cpp index c87c3bc..48fbcd2 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -70,6 +70,7 @@ void Config::createJson(DynamicJsonDocument& doc) { doc[PARAM_OTA] = getOtaURL(); doc[PARAM_SSID] = getWifiSSID(); doc[PARAM_PASS] = getWifiPass(); + doc[PARAM_BLE] = getColorBLE(); doc[PARAM_TEMPFORMAT] = String(getTempFormat()); doc[PARAM_PUSH_BREWFATHER] = getBrewfatherPushUrl(); doc[PARAM_TOKEN] = getToken(); @@ -203,6 +204,7 @@ bool Config::loadFile() { if (!doc[PARAM_MDNS].isNull()) setMDNS(doc[PARAM_MDNS]); if (!doc[PARAM_SSID].isNull()) setWifiSSID(doc[PARAM_SSID]); if (!doc[PARAM_PASS].isNull()) setWifiPass(doc[PARAM_PASS]); + if (!doc[PARAM_BLE].isNull()) setColorBLE(doc[PARAM_BLE]); if (!doc[PARAM_TEMPFORMAT].isNull()) { String s = doc[PARAM_TEMPFORMAT]; diff --git a/src/config.hpp b/src/config.hpp index 0dd27fd..48cd427 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -130,6 +130,9 @@ class Config { bool _gravityTempAdj = false; char _gravityFormat = 'G'; + // BLE (ESP32 only) + String _colorBLE; + // Gyro calibration and formula calculation data RawGyroData _gyroCalibration = {0, 0, 0, 0, 0, 0}; RawFormulaData _formulaData = {{0, 0, 0, 0, 0}, {1, 1, 1, 1, 1}}; @@ -335,6 +338,16 @@ class Config { bool isGravitySG() { return _gravityFormat == 'G'; } bool isGravityPlato() { return _gravityFormat == 'P'; } + const char* getColorBLE() { return _colorBLE.c_str(); } + void setColorBLE(String c) { + _colorBLE = c; + _saveNeeded = true; + } + bool isBLEActive() { return _colorBLE.length() ? true : false; } + bool isWifiPushActive() { + return (isHttpActive() || isHttp2Active() || isBrewfatherActive() || isInfluxDb2Active() || isMqttActive()) ? true : false; + } + const RawGyroData& getGyroCalibration() { return _gyroCalibration; } void setGyroCalibration(const RawGyroData& r) { _gyroCalibration = r; diff --git a/src/main.cpp b/src/main.cpp index 2d1bb93..35ede1c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -30,6 +30,7 @@ SOFTWARE. #include #include #include +#include // Define constats for this program #ifdef DEACTIVATE_SLEEPMODE @@ -248,6 +249,14 @@ bool loopReadGravity() { angle, tempC, gravity, corrGravity); #endif +#if defined (ESP32) + if (myConfig.isBLEActive()) { + BleSender ble(myConfig.getColorBLE()); + ble.sendData( convertCtoF(tempC), gravitySG); + Log.notice(F("MAIN: Broadcast data over bluetooth." CR)); + } +#endif + bool pushExpired = (abs((int32_t)(millis() - pushMillis)) > (myConfig.getSleepInterval() * 1000)); diff --git a/src/resources.hpp b/src/resources.hpp index 3f62a42..6e86bd7 100644 --- a/src/resources.hpp +++ b/src/resources.hpp @@ -71,6 +71,8 @@ SOFTWARE. #define PARAM_SLEEP_MODE "sleep-mode" #define PARAM_RSSI "rssi" #define PARAM_ERROR "error" +#define PARAM_PLATFORM "platform" +#define PARAM_BLE "ble" #define PARAM_HW_GYRO_READ_COUNT "gyro-read-count" #define PARAM_HW_GYRO_READ_DELAY "gyro-read-delay" #define PARAM_HW_GYRO_MOVING_THREASHOLD "gyro-moving-threashold" diff --git a/src/webserver.cpp b/src/webserver.cpp index a20674c..b2656dd 100644 --- a/src/webserver.cpp +++ b/src/webserver.cpp @@ -55,6 +55,12 @@ void WebServerHandler::webHandleDevice() { doc[PARAM_RUNTIME_AVERAGE] = reduceFloatPrecision( runLog.getAverage() ? runLog.getAverage() / 1000 : 0, 1); +#if defined(ESP8266) + doc[PARAM_PLATFORM] = "esp8266"; +#else + doc[PARAM_PLATFORM] = "esp32"; +#endif + #if LOG_LEVEL == 6 serializeJson(doc, Serial); Serial.print(CR); @@ -106,6 +112,12 @@ void WebServerHandler::webHandleConfig() { doc[PARAM_RUNTIME_AVERAGE] = reduceFloatPrecision( runLog.getAverage() ? runLog.getAverage() / 1000 : 0, 1); +#if defined(ESP8266) + doc[PARAM_PLATFORM] = "esp8266"; +#else + doc[PARAM_PLATFORM] = "esp32"; +#endif + #if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING) serializeJson(doc, Serial); Serial.print(CR); @@ -146,7 +158,25 @@ void WebServerHandler::webHandleUpload() { obj[PARAM_FILE_SIZE] = dir.fileSize(); } #else // defined(ESP32) -#warning "TODO: Implement file listing for ESP32" + JsonArray files = doc.createNestedArray(PARAM_FILES); + + File dir = LittleFS.open("/"); + + while (true) { + File entry = dir.openNextFile(); + if (!entry) { + // no more files + break; + } + + if (!entry.isDirectory()) { + JsonObject obj = files.createNestedObject(); + obj[PARAM_FILE_NAME] = entry.name(); + obj[PARAM_FILE_SIZE] = entry.size(); + } + entry.close(); + } + dir.close(); #endif #if LOG_LEVEL == 6 && !defined(WEB_DISABLE_LOGGING) @@ -521,6 +551,8 @@ void WebServerHandler::webHandleConfigHardware() { myConfig.setTempSensorAdjF(_server->arg(PARAM_TEMP_ADJ)); } } + if (_server->hasArg(PARAM_BLE)) + myConfig.setColorBLE(_server->arg(PARAM_BLE).c_str()); if (_server->hasArg(PARAM_OTA)) myConfig.setOtaURL(_server->arg(PARAM_OTA).c_str()); if (_server->hasArg(PARAM_GYRO_TEMP)) diff --git a/test/config.json b/test/config.json index b0cf88d..11c5f6b 100644 --- a/test/config.json +++ b/test/config.json @@ -37,5 +37,7 @@ "angle": 90.93, "gravity": 1.105, "battery": 0.04, - "runtime-average": 2.0 + "runtime-average": 2.0, + "ble": "pink", + "platform": "esp32" } \ No newline at end of file diff --git a/test/device.json b/test/device.json index 57f3db7..f083ca9 100644 --- a/test/device.json +++ b/test/device.json @@ -3,5 +3,6 @@ "app-ver": "0.0.0", "id": "7376ef", "mdns": "gravmon", + "platform": "esp32", "runtime-average": 3.12 } \ No newline at end of file