@@ -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 Beer Gravity Monitor
A sleep-interval of less than 300s will reduce battery life, consider using 900s
When using the gyro temperature use a sleep-interval that is greater than 300s for accurate readings
(C) Copyright 2021-22 Magnus Persson
\ No newline at end of file
+
Beer Gravity Monitor Beer Gravity Monitor
A sleep-interval of less than 300s will reduce battery life, consider using 900s
When using the gyro temperature use a sleep-interval that is greater than 300s for accurate readings
(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...
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 Beer Gravity Monitor
Current version:
Loading...
Average runtime:
Loading...
(C) Copyright 2021-22 Magnus Persson
\ No newline at end of file
+
Beer Gravity Monitor Beer Gravity Monitor
Current version:
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