Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c77404f
Initial steps to enabling bluetooth
Joseph-Jacobson May 7, 2025
8a055f2
Merge pull request #326 from EmotiBit/master
Joseph-Jacobson May 7, 2025
2f41662
Next bluetooth build before creating test software
Joseph-Jacobson May 12, 2025
2244162
Adding multiple characteristics
Joseph-Jacobson Jul 15, 2025
80d7099
added read control- untested
Joseph-Jacobson Jul 15, 2025
01990cd
Merge branch 'feat-SplitterRefactor' into 1.12.1.feat-blePrototype-Ex…
Joseph-Jacobson Jul 16, 2025
9d4ba9c
Changes to parseIncomingControlPackets to enable bluetooth control pa…
Joseph-Jacobson Jul 17, 2025
d7acd3b
Initial Wireless Off Testing
Joseph-Jacobson Jul 22, 2025
0a735a5
removed gitIgnore
Joseph-Jacobson Jul 30, 2025
e58e169
Code cleanup
Joseph-Jacobson Jul 31, 2025
a70b0c9
tab fixes
Joseph-Jacobson Jul 31, 2025
3339bf0
removed sync code
Joseph-Jacobson Jul 31, 2025
5687d78
More tab changes
Joseph-Jacobson Jul 31, 2025
2db7d38
Code cleanup
Joseph-Jacobson Jul 31, 2025
a473162
Deleted workspace
Joseph-Jacobson Jul 31, 2025
2849d46
Merge branch 'feat-SplitterRefactor' into feat-blePrototype-Example
Joseph-Jacobson Jul 31, 2025
bbfd66b
enabled the ability to run debug mode + bluetooth at the same time
Joseph-Jacobson Jul 31, 2025
38f7c97
More cleanup
Joseph-Jacobson Jul 31, 2025
69bf798
Updated versioning
Joseph-Jacobson Aug 4, 2025
6e919d3
Bumped library
Joseph-Jacobson Aug 6, 2025
0ed979a
Spacing
Joseph-Jacobson Aug 6, 2025
1450c29
Merge branch 'master' into feat-blePrototype-Example
Joseph-Jacobson Sep 13, 2025
176cb58
Removed nameSdCardFile()
Joseph-Jacobson Oct 17, 2025
7d6574e
Minor fixes
Joseph-Jacobson Nov 7, 2025
c1e58c1
feat: adds documentation on github workflows and scripts
nitin710 Nov 8, 2025
47f981c
main readme update
nitin710 Nov 8, 2025
8300982
Fixed setPowerMode() to handle BT mode changes
produceconsumerobot Nov 12, 2025
b270aee
PR review changes
Joseph-Jacobson Nov 18, 2025
eab8f6f
Merge remote-tracking branch 'origin/master' into feat-blePrototype-E…
Joseph-Jacobson Apr 7, 2026
e25f04c
Fix for issue 345
Joseph-Jacobson Apr 7, 2026
dab6c44
Update EmotiBit.cpp
Joseph-Jacobson Apr 7, 2026
ce42cd5
Fixed relevant minor code rabbit concerns
Joseph-Jacobson Apr 18, 2026
abdec15
Added startTimer to "Exiting Sending Test Data Mode" for m0 to resume…
Joseph-Jacobson Apr 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
343 changes: 239 additions & 104 deletions EmotiBit.cpp

Large diffs are not rendered by default.

13 changes: 10 additions & 3 deletions EmotiBit.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
#ifdef ARDUINO_FEATHER_ESP32
#include <SD.h>
#include "driver/adc.h"
#include <esp_bt.h>
#else
#include <SdFat.h>
#include <ArduinoLowPower.h>
Expand All @@ -39,6 +38,9 @@
#include "FileTransferManager.h"
#endif
#include "EmotiBitConfigManager.h"
#ifdef ARDUINO_FEATHER_ESP32
#include "EmotiBitBluetooth.h"
#endif

class EmotiBit {

Expand Down Expand Up @@ -266,6 +268,7 @@ class EmotiBit {
MAX_LOW_POWER, // data not sent, time-syncing accuracy low
LOW_POWER, // data not sent, time-syncing accuracy high
NORMAL_POWER, // data sending, time-syncing accuracy high
BLUETOOTH,
length
};

Expand All @@ -280,6 +283,9 @@ class EmotiBit {
EmotiBitEda emotibitEda;
EmotiBitNvmController _emotibitNvmController;
#ifdef ARDUINO_FEATHER_ESP32
EmotiBitBluetooth _emotiBitBluetooth;
#endif //ARDUINO_FEATHER_ESP32
#ifdef ARDUINO_FEATHER_ESP32
FileTransferManager _fileTransferManager;
#endif
EmotiBitConfigManager _emotibitConfigManager;
Comment on lines +286 to 291

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Encapsulation: avoid exposing transport internals publicly.

Exposing EmotiBitBluetooth _emotiBitBluetooth publicly couples callers to the transport and makes invariants harder to preserve. Prefer private with minimal accessors or friend usage within EmotiBit.

🤖 Prompt for AI Agents
In EmotiBit.h around lines 287 to 292, the EmotiBitBluetooth _emotiBitBluetooth
member is declared publicly which exposes transport internals; change its
visibility to private (or protected) and remove public exposure, and if external
access is required provide a minimal, controlled accessor (e.g., a
const/reference getter or specific methods that expose only necessary
operations) or declare only internal classes as friends so callers cannot
manipulate transport internals directly; ensure conditional
ARDUINO_FEATHER_ESP32 guards are preserved and update any callsites to use the
new accessor or friend interface.

Expand Down Expand Up @@ -429,6 +435,7 @@ class EmotiBit {
DataType _serialData = DataType::length;
volatile bool buttonPressed = false;
bool startBufferOverflowTest = false;
bool _bluetoothEnabled = false;

void setupFailed(const String failureMode, int buttonPin = -1, bool configFileError = false);
bool setupSdCard(bool loadConfig = true);
Expand All @@ -444,7 +451,8 @@ class EmotiBit {
void attachShortButtonPress(void(*shortButtonPressFunction)(void));
void attachLongButtonPress(void(*longButtonPressFunction)(void));
PowerMode getPowerMode();
void setPowerMode(PowerMode mode);
//void setPowerMode(PowerMode mode);
bool setPowerMode(PowerMode mode);
Comment on lines +454 to +455

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Remove the stale commented-out signature.

The old void setPowerMode(...) declaration can be dropped now that the public API is bool setPowerMode(...); leaving both in the header makes the intended contract less clear.

bool writeSdCardMessage(const String &s);
int freeMemory();
bool loadConfigFile(const String &filename);
Expand All @@ -459,7 +467,6 @@ class EmotiBit {
bool processThermopileData(); // placeholder until separate EmotiBitThermopile controller is implemented
void writeSerialData(EmotiBit::DataType t);
void printEmotiBitInfo();


/**
* Copies data buffer of the specified DataType into the passed array
Expand Down
234 changes: 234 additions & 0 deletions EmotiBitBluetooth.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
#ifdef ARDUINO_FEATHER_ESP32
#include "EmotiBitBluetooth.h"
#include <esp_bt.h>

uint8_t EmotiBitBluetooth::begin(const String& emotibitDeviceId)
{
if (pServer)
{
EmotiBitBluetooth::reconnect();
Serial.println("Bluetooth already initialized, reconnecting...");
return 0; // Success
}

_emotibitDeviceId = emotibitDeviceId;

Serial.println("Bluetooth tag detected, turning on bluetooth.");
BLEDevice::init(("EmotiBit: " + _emotibitDeviceId).c_str());

pServer = BLEDevice::createServer();

if (!pServer)
{
Serial.println("ERROR: Failed to create BLE server");
return 1;
}

pServer->setCallbacks(new MyServerCallbacks(this));
BLEService* pService = pServer->createService(EMOTIBIT_SERVICE_UUID);

pDataTxCharacteristic = pService->createCharacteristic(EMOTIBIT_DATA_TX_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_NOTIFY);
if (!pDataTxCharacteristic)
{
Serial.println("ERROR: Failed to create TX characteristic");
return 1;
}
pDataTxCharacteristic->addDescriptor(new BLE2902());

pDataRxCharacteristic = pService->createCharacteristic(EMOTIBIT_DATA_RX_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_WRITE);
if (!pDataRxCharacteristic)
{
Serial.println("ERROR: Failed to create RX characteristic");
return 1;
}
pDataRxCharacteristic->setCallbacks(new MyCallbacks());

pService->start();

EmotiBitBluetooth::startAdvertising();
_bluetoothReconnect = true; // Allow reconnection after disconnection

return 0;
Comment thread
Joseph-Jacobson marked this conversation as resolved.
}

void EmotiBitBluetooth::MyServerCallbacks::onConnect(BLEServer* pServer)
{
server->deviceConnected = true;
server->_connId = pServer->getConnId();
Serial.println("BLE client connected");
}

void EmotiBitBluetooth::MyServerCallbacks::onDisconnect(BLEServer* pServer)
{
server->deviceConnected = false;
Serial.println("BLE client disconnected");
//need to restart advertising to allow new connections after disconnection if accidentally disconnected
if (server->_bluetoothReconnect)
{
server->reconnect();
Serial.println("Restarted BLE advertising");
}
}

//ToDO: Current polling aproach can drop back to back writes since the characteristic only holds the last value.
void EmotiBitBluetooth::MyCallbacks::onWrite(BLECharacteristic *pCharacteristic)
{
std::string rxValue = pCharacteristic->getValue();
if (rxValue.length() > 0) {
//Serial.print("Received: ");
//Serial.println(rxValue.c_str());
}
Comment thread
Joseph-Jacobson marked this conversation as resolved.
}

void EmotiBitBluetooth::setDeviceId(const String& emotibitDeviceId)
{
_emotibitDeviceId = emotibitDeviceId;
}

void EmotiBitBluetooth::sendData(const String &message)
{
if (deviceConnected)
{
//TODO: consider truncating via MTU if message is too long
if (pDataTxCharacteristic == nullptr)
{
//Serial.println("ERROR: pDataTxCharacteristic is NULL!");
return;
}

//Serial.print("BLE TX: Message length=");
//Serial.print(message.length());

// Set the value
pDataTxCharacteristic->setValue(message.c_str());

// Call notify - note: doesn't return success/failure status
pDataTxCharacteristic->notify();

// Check descriptor status
BLEDescriptor* p2902 = pDataTxCharacteristic->getDescriptorByUUID(BLEUUID((uint16_t)0x2902));
if (p2902)
{
const uint8_t* val = p2902->getValue();
if (val)
{
//Serial.print(" | Notifications enabled=");
//Serial.print((val[0] & 0x01) ? "YES" : "NO");
}
}

//Serial.print(" | Char ptr=0x");
//Serial.print((uint32_t)pDataTxCharacteristic, HEX);
//Serial.print(" | Message: ");
//Serial.println(message.c_str());
}
else
{
//ToDO: consider gating behind a debug flag
Serial.println("unable to send data: deviceConnected=false");
}
}

uint8_t EmotiBitBluetooth::readControl(String& packet)
{
uint8_t numPackets = 0;
packet = "";
if (deviceConnected)
{
std::string rxValue = pDataRxCharacteristic->getValue();
if (!rxValue.empty())
{
//Serial.print("Received: ");
//Serial.println(rxValue.c_str());
_receivedControlMessage += String(rxValue.c_str());

//CLEAR THE CHAR VALUE SO WE DON’T REUSE IT
pDataRxCharacteristic->setValue("");
}

String tempPacket = "";
while (_receivedControlMessage.length() > 0)
{
int c = _receivedControlMessage[0];
_receivedControlMessage.remove(0, 1);

if (c == (int)EmotiBitPacket::PACKET_DELIMITER_CSV)
{
numPackets++;
packet = tempPacket;
tempPacket = "";
_receivedControlMessage = "";
return numPackets;
}
else
{
if (c == 0) {
// Throw out null term
}
else
{
tempPacket += (char)c;
}
}
}
}
return numPackets;
}
Comment thread
Joseph-Jacobson marked this conversation as resolved.

bool EmotiBitBluetooth::isOff()
{
return _bluetoothOff;
}

void EmotiBitBluetooth::end()
{
if (pServer && deviceConnected)
{
//tear down the old connection
pServer->disconnect(_connId);
Serial.println("BLE client disconnected by end()");
}
Comment thread
Joseph-Jacobson marked this conversation as resolved.
if (pServer)
{
pServer->getAdvertising()->stop();
Serial.println("BLE advertising stopped");
}
_bluetoothOff = true;
_bluetoothReconnect = false;
}

void EmotiBitBluetooth::reconnect()
{
if (pServer)
{
EmotiBitBluetooth::startAdvertising();
Serial.println("BLE advertising restarted after reconnect");
_bluetoothOff = false;
_bluetoothReconnect = true;
}
else
{
Serial.println("ERROR: pServer is NULL, cannot reconnect");
}
}

void EmotiBitBluetooth::startAdvertising()
{
if (pServer)
{
pServer->getAdvertising()->start();
_bluetoothOff = false;
Serial.println("BLE advertising started");
}
Comment thread
Joseph-Jacobson marked this conversation as resolved.
else
{
Serial.println("ERROR: pServer is NULL, cannot start advertising");
}
}
Comment thread
Joseph-Jacobson marked this conversation as resolved.

void EmotiBitBluetooth::disableBluetooth()
{
esp_bt_controller_disable();
}

#endif //ARDUINO_FEATHER_ESP32
Loading
Loading