Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
23 changes: 21 additions & 2 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ lib_extra_dirs = ~/Documents/Arduino/libraries
upload_speed = 921600
monitor_speed = 115200
board_build.partitions = custom32c3sm.csv
build_flags =
-D LED_ON=LOW
build_flags =
-D LED_ON=LOW
-D ESP32_C3
lib_deps =
https://github.com/Links2004/arduinoWebSockets.git
bblanchon/ArduinoJson@^7.4.1
Expand All @@ -32,6 +33,24 @@ framework = arduino
lib_extra_dirs = ~/Documents/Arduino/libraries
monitor_speed = 115200
upload_speed = 115200
build_flags =
-D NODEMCU_V2
lib_deps =
https://github.com/Links2004/arduinoWebSockets.git
bblanchon/ArduinoJson@^7.4.1
adafruit/Adafruit SSD1306@^2.5.13
yuriisalimov/MAX6675_Thermocouple@^2.0.2
tzapu/WiFiManager@^2.0.17

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
board_build.partitions = custom32c3sm.csv
build_flags =
-D LED_ON=LOW
-D ESP32_DEV
lib_deps =
https://github.com/Links2004/arduinoWebSockets.git
bblanchon/ArduinoJson@^7.4.1
Expand Down
4 changes: 2 additions & 2 deletions src/BleManager.cpp
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

I think this is comment is not necessary. Since debugln(x) is macro Serial.println(x), it will not shown while not monitor it.

Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,8 @@ void BleManager::broadcastData()

sendData(jsonData);

debugln("# [BLE-JSON] " + jsonData);
debugln("");
// debugln("# [BLE-JSON] " + jsonData);
// debugln("");
}
}

Expand Down
6 changes: 6 additions & 0 deletions src/CommandHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ CommandHandler::CommandHandler(CroasterCore &core, DisplayManager &display)

void CommandHandler::begin()
{
#ifdef LED_BUILTIN
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LED_OFF);
#endif
}

void CommandHandler::loop()
Expand All @@ -24,15 +26,19 @@ void CommandHandler::loop()
if (blinking && now - lastBlinkTime >= blinkDelay)
{
ledState = !ledState;
#ifdef LED_BUILTIN
digitalWrite(LED_BUILTIN, ledState ? LED_ON : LED_OFF);
#endif
displayManager.blinkIndicator(ledState);
lastBlinkTime = now;
blinkCount++;

if (blinkCount >= blinkTotal)
{
blinking = false;
#ifdef LED_BUILTIN
digitalWrite(LED_BUILTIN, LED_OFF); // turn off when done
#endif
displayManager.blinkIndicator(false); // turn off when done
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/Constants.h
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This is great. I was forgot to move this value into Constant.h. But the value was presented as second in int. Also the value was passed into ICRM App. change data type will need changes to the app too.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Maybe it would be best to store it as int in milliseconds, because the usage is always in miliseconds. Currently it is converted every time the BLE stack sends new data. I was also thinking if it would be good to have to separate values for Websockets and BLE.

Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,7 @@ const double version = 0.44;
// Dummy mode
const bool dummyMode = false;

static constexpr double INITIAL_INTERVAL_SEND_S = .05;

// Smoothing factor of a temperature value
#define SMOOTHING_FACTOR 5
2 changes: 1 addition & 1 deletion src/CroasterCore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,7 @@ String CroasterCore::ssidName()
return getDeviceName("[", "] Croaster V" + String(version));
}

String CroasterCore::getJsonData(const String &message, const bool &skipCroaster, int id)
String CroasterCore::getJsonData(const String &message, const bool skipCroaster, int id)
{
String ipAddress = getIpAddress();

Expand Down
4 changes: 2 additions & 2 deletions src/CroasterCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class CroasterCore

String tempUnit = "C";

unsigned long intervalSend = 3;
unsigned long intervalSend = INITIAL_INTERVAL_SEND_S;

bool useDummyData;

Expand Down Expand Up @@ -128,7 +128,7 @@ class CroasterCore
* @param id Identifier used to fetch specific JSON data. Defaults to 0.
* @return A String containing the JSON data.
*/
String getJsonData(const String &message = "", const bool &skipCroaster = false, int id = 0);
String getJsonData(const String &message = "", const bool skipCroaster = true, int id = 0);

/**
* @brief Retrieves the SSID name for the device.
Expand Down
9 changes: 7 additions & 2 deletions src/PinConfig.h
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
#pragma once

// Thermocouple pin assignments
#if defined(ESP8266)
#if defined(NODEMCU_V2)
#define SCK_PIN D5
#define SO_PIN D7
#define CS_PIN_BT D8
#define CS_PIN_ET D6
#elif defined(ESP32)
#elif defined(ESP32_C3)
#define SCK_PIN 4
#define SO_PIN 5
#define CS_PIN_BT 7
#define CS_PIN_ET 6
#elif defined(ESP32_DEV)
#define SCK_PIN SCK
#define SO_PIN MISO
#define CS_PIN_BT SS
#define CS_PIN_ET MOSI
#endif
30 changes: 21 additions & 9 deletions src/main.cpp
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

i'll move USE_WEBSOCKET and USE_BLE to Constants.h like this :

// Check is BLE connection supported
// Change to `false` if you do not wish to use
#define USE_BLE defined(ESP32) and true

// Change to `false` if you do not wish to use
#define USE_WEBSOCKET true

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Currently, we have #define, const bool, and static constexpr in Constants.h. The best C++ way and to have it type safe would be only using static constexpr, it is type safe and is evaluated during compile time.

Original file line number Diff line number Diff line change
Expand Up @@ -6,59 +6,71 @@
#error "This ain't a ESP8266 or ESP32!"
#endif

#define USE_WEBSOCKET false
#define USE_BLE true

#include <Arduino.h>
#include "Constants.h"
#if USE_BLE
#include "BleManager.h"
#endif
#if USE_WEBSOCKET
#include "WiFiManagerUtil.h"
#include "WebSocketManager.h"
#endif
#include "CroasterCore.h"
#include "DisplayManager.h"
#include "CommandHandler.h"


// === Global Instances ===
CroasterCore croaster(dummyMode);

DisplayManager displayManager(croaster);

CommandHandler commandHandler(croaster, displayManager);

#if defined(ESP32)
#if defined(ESP32) and USE_BLE
BleManager bleManager(croaster, commandHandler);
#endif

#if USE_WEBSOCKET
WebSocketManager wsManager(croaster, commandHandler);
#endif

// === Arduino Setup ===
void setup()
{
Serial.begin(115200);

#if USE_WEBSOCKET
// Initialize managers
setupWiFiManager(croaster.ssidName());
#endif

commandHandler.begin();

#if defined(ESP32)
#if defined(ESP32) and USE_BLE
bleManager.begin();
#endif

#if USE_WEBSOCKET
wsManager.begin();

#endif
displayManager.begin();
}

// === Arduino Loop ===
void loop()
{
processWiFiManager();

croaster.loop();


#if USE_WEBSOCKET
processWiFiManager();
wsManager.loop();

#endif
displayManager.loop();

#if defined(ESP32)
#if defined(ESP32) and USE_BLE
bleManager.loop();
#endif

Expand Down
95 changes: 95 additions & 0 deletions tools/CroasterBLEtoWebsocketsBridge.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@

import asyncio
import json
import logging
import time

from websockets.asyncio.server import serve
from websockets.exceptions import ConnectionClosedOK
from bleak import BleakScanner, BleakClient

DATA_UUID = "d56d0059-ad65-43f3-b971-431d48f89a69"

logger = logging.getLogger("BLEtoWebsocketsBridge")
logging.basicConfig(level=logging.INFO, format="%(asctime)s\t%(levelname)s\t%(message)s")
ble_queue = asyncio.Queue()
first_time = True

# see https://github.com/hbldh/bleak/issues/801
async def ble_callback(sender, data: bytearray):
global ble_queue
while not ble_queue.empty():
await ble_queue.get()
ble_data = json.loads(data)
rec_time = time.time()
await ble_queue.put((rec_time, ble_data))


# Find the Croaster by name, return None if not found
async def find_croaster():
devices = await BleakScanner.discover()
for d in devices:
logging.debug(str(d))
if d.name is not None and "[C4C4]" in d.name:
logging.info("Found device " + d.name )
return d
return None

async def request_handler(websocket):
global ble_queue, first_time
try:
while True:
message = await websocket.recv()
decoded_message = json.loads(message)
if decoded_message["command"] == "getArtisanData":
# something like: {"command":"getArtisanData","id":6120,"roasterID":0}
response_id = decoded_message["id"]
# data = { "BT": 137, "ET": 117}
# response = {"id": response_id, "data": data }
# if first_time:
# first_time = False
# # discard first sample for better syncroniization.
# rec_time, ble_data = await ble_queue.get()

start_time = time.time()
rec_time, ble_data = await ble_queue.get()

stop_time = time.time()
artisan_response = ble_data
artisan_response["id"] = response_id
response_json = json.dumps(artisan_response)
et = artisan_response["data"]["ET"]
bt = artisan_response["data"]["BT"]
elapsed_time_ms = (stop_time - start_time) * 1000
data_age_ms = (stop_time - rec_time) * 1000
logging.info(f"Response for {response_id}: ET: {et:.2f}C, BT {bt:.2f}C (delay: {elapsed_time_ms:.0f}ms, age: {data_age_ms:.0f}ms)")
await websocket.send(response_json)
else:
logging.warning(f"Unknown command {decoded_message['command']}")
except ConnectionClosedOK:
logging.info("Artisan disconnected")



async def main():
logging.info("Bridge started")
global croaster_client
croaster_adress = await find_croaster()
if croaster_adress is None:
logging.error("Croaster not found")
exit()
croaster_client = BleakClient(croaster_adress)
await croaster_client.connect()
if not croaster_client.is_connected:
exit()
await croaster_client.start_notify(DATA_UUID, ble_callback)

async with serve(request_handler, "localhost", 8765) as server:
await server.serve_forever()


if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
logger.info("Shutting down")
2 changes: 2 additions & 0 deletions tools/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bleak
websockets