Skip to content

Commit

Permalink
Merge pull request #125 from thorrak:async_ws
Browse files Browse the repository at this point in the history
- Convert to use an asynchronous web server
- Cache room sensor temperature value
  • Loading branch information
thorrak authored Mar 1, 2025
2 parents 6b91a9a + 1f409f7 commit dd185d3
Show file tree
Hide file tree
Showing 10 changed files with 342 additions and 380 deletions.
Binary file modified data/index.js.gz
Binary file not shown.
19 changes: 14 additions & 5 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,19 @@ framework = arduino
; The default platform & platform package only applies to ESP32 derivatives
platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.13/platform-espressif32.zip
lib_deps =
bblanchon/ArduinoJson @ ^7.2.1
https://github.com/thorrak/Arduino-Log.git ; // Need this until ArduinoLog merges https://github.com/thijse/Arduino-Log/pull/21
https://github.com/tzapu/WiFiManager.git#0d84861270c3cd64f72a4eaf34443ee580d2547e ; Anchor to latest commit as of 8/7/24
pstolarz/OneWireNg@^0.13.1
https://github.com/pstolarz/Arduino-Temperature-Control-Library.git#475f390038fe6828f0403960b8634a5227e54b34 ; Anchor to latest commit as of 12/15/24
bblanchon/ArduinoJson @ ^7.2.1
bblanchon/StreamUtils @ ^1.9.0
; https://github.com/thorrak/AsyncTCP
; https://github.com/thorrak/ESPAsyncWebServer.git
https://github.com/thorrak/Arduino-Log.git ; // Need this until ArduinoLog merges https://github.com/thijse/Arduino-Log/pull/21
ESP32Async/ESPAsyncWebServer @ 3.7.1 ; https://github.com/ESP32Async/ESPAsyncWebServer.git
lib_deps_bluetooth =
h2zero/NimBLE-Arduino @ ^2.2.1 ; https://github.com/h2zero/NimBLE-Arduino.git
h2zero/NimBLE-Arduino @ ^2.2.3 ; https://github.com/h2zero/NimBLE-Arduino.git
lib_deps_esp32 =
ESP32Async/AsyncTCP @ ^3.3.2 ; https://github.com/ESP32Async/AsyncTCP.git
lib_deps_esp8266 =
ESP32Async/ESPAsyncTCP @ ^2.0.0 ; https://github.com/ESP32Async/ESPAsyncTCP.git

; Let's also include some other common build flags for ease-of-use
build_flags =
Expand Down Expand Up @@ -70,6 +73,7 @@ build_flags =
lib_deps =
${common.lib_deps}
${common.lib_deps_bluetooth}
${common.lib_deps_esp32}
https://github.com/PaulStoffregen/XPT2046_Touchscreen
adafruit/Adafruit GFX Library@^1.11.5
adafruit/Adafruit ILI9341@^1.5.12
Expand Down Expand Up @@ -104,6 +108,7 @@ build_flags =
lib_deps =
${common.lib_deps}
${common.lib_deps_bluetooth}
${common.lib_deps_esp32}
upload_speed = ${common.upload_speed}
monitor_speed = ${common.monitor_speed}
board_build.partitions = 4mb_no_ota.csv
Expand All @@ -128,6 +133,7 @@ build_flags =
-DPIO_FRAMEWORK_ARDUINO_ESPRESSIF_SDK221
lib_deps =
${common.lib_deps}
${common.lib_deps_esp8266}

upload_speed = ${common.upload_speed}
monitor_speed = ${common.monitor_speed}
Expand Down Expand Up @@ -174,6 +180,7 @@ monitor_filters = esp8266_exception_decoder, default
; -DESP32C3
; lib_deps =
; ${common.lib_deps}
; ${common.lib_deps_esp32}
; upload_speed = ${common.upload_speed}
; monitor_speed = ${common.monitor_speed}
; board_build.partitions = 4mb_inc_ota.csv
Expand Down Expand Up @@ -204,6 +211,7 @@ build_flags =
-DESP32S2
lib_deps =
${common.lib_deps}
${common.lib_deps_esp32}
upload_speed = ${common.upload_speed}
monitor_speed = ${common.monitor_speed}
board_build.partitions = 4mb_inc_ota.csv
Expand Down Expand Up @@ -279,6 +287,7 @@ build_flags =
lib_deps =
${common.lib_deps}
${common.lib_deps_bluetooth}
${common.lib_deps_esp32}
; bodmer/TFT_eSPI @ 2.5.43 ; https://github.com/Bodmer/TFT_eSPI.git
https://github.com/Bodmer/TFT_eSPI.git#5793878d24161c1ed23ccb136f8564f332506d53 ; master as of 7/6/24
upload_speed = 1500000
Expand Down
2 changes: 1 addition & 1 deletion src/Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@



#define FIRMWARE_REVISION "v16-alpha4"
#define FIRMWARE_REVISION "v16-alpha5"

#ifdef ESP8266_WiFi
#define WIFI_SETUP_AP_NAME "BrewPiAP"
Expand Down
18 changes: 16 additions & 2 deletions src/TempControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ extern DisconnectedTempSensor defaultTempSensor;
TempSensor* TempControl::beerSensor;
TempSensor* TempControl::fridgeSensor;
BasicTempSensor* TempControl::ambientSensor = &defaultTempSensor;
temperature ambientTemp = TEMP_SENSOR_DISCONNECTED; // Updated in the updateTemperatures() function to prevent reading from the sensor in an async web response


Actuator* TempControl::heater = &defaultActuator;
Expand Down Expand Up @@ -141,6 +142,17 @@ void updateSensor(TempSensor* sensor) {
}
}


/**
* Get the current cached room temperature.
*
* @return Current cached room temperature
*/
temperature TempControl::getRoomTemp() {
return ambientTemp;
}


/**
* Update all installed temp sensors.
*
Expand All @@ -150,10 +162,12 @@ void TempControl::updateTemperatures(){

updateSensor(beerSensor);
updateSensor(fridgeSensor);

ambientTemp = ambientSensor->read(); // Update ambient sensor here rather to prevent being updated as part of an async web response

// Read ambient sensor to keep the value up to date. If no sensor is connected, this does nothing.
// If no sensor is connected, this does nothing.
// This prevents a delay in serial response because the value is not up to date.
if(ambientSensor->read() == TEMP_SENSOR_DISCONNECTED){
if(ambientTemp == TEMP_SENSOR_DISCONNECTED){
ambientSensor->init(); // try to reconnect a disconnected, but installed sensor
}
}
Expand Down
7 changes: 1 addition & 6 deletions src/TempControl.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,12 +216,7 @@ class TempControl{
TEMP_CONTROL_METHOD temperature getFridgeSetting();
TEMP_CONTROL_METHOD void setFridgeTemp(temperature newTemp);

/**
* Get the current temperature of the room probe.
*/
TEMP_CONTROL_METHOD temperature getRoomTemp() {
return ambientSensor->read();
}
TEMP_CONTROL_METHOD temperature getRoomTemp();

TEMP_CONTROL_METHOD void setMode(char newMode, bool force=false);

Expand Down
3 changes: 2 additions & 1 deletion src/brewpi-esp8266.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,8 @@ if(bt_scanner.scanning_failed()) {
#endif

#ifdef ENABLE_HTTP_INTERFACE
http_server.web_server->handleClient();
// The webserver is now handled asynchronously, so we don't need to call handleClient() here
http_server.processQueuedDeviceDefinition(); // Do this in the main loop to avoid issues with blocking to read DS18b20s
rest_handler.process();
#endif

Expand Down
136 changes: 136 additions & 0 deletions src/extended_async_json_handler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/**
* @file extended_async_json_handler.h
* @brief A class for handling JSON requests in AsyncWebServer with a custom handler function.
*/

#ifndef EXTENDED_ASYNC_JSON_HANDLER_H_
#define EXTENDED_ASYNC_JSON_HANDLER_H_

#include <AsyncJson.h>

#if ASYNC_JSON_SUPPORT == 1

/**
* @class PutAsyncCallbackJsonWebHandler
* @brief Extends AsyncCallbackJsonWebHandler to support custom JSON request handling for HTTP PUT.
*
* This class provides the ability to process incoming PUT requests in an `AsyncWebServer`
* using a user-defined handler function. The handler processes the JSON payload and returns
* a success or failure response based on its logic.
*/
class PutAsyncCallbackJsonWebHandler : public AsyncCallbackJsonWebHandler {
protected:
/**
* @brief Pointer to the custom handler function.
*
* The custom handler function processes the JSON payload and determines whether the
* request should be considered successful or not.
*/
bool (*_customHandler)(const JsonDocument&, bool);

public:
/**
* @brief Constructor for PutAsyncCallbackJsonWebHandler.
*
* @param uri The URI to handle.
* @param maxJsonBufferSize Maximum size of the JSON buffer (defaults to DYNAMIC_JSON_DOCUMENT_SIZE).
* @param customHandler A pointer to the custom handler function. The function must accept
* a `JsonDocument` and a `bool`, and return a `bool` indicating success.
*
* The custom handler function will be invoked for each request to the specified URI. If
* the handler is not provided or fails, an appropriate HTTP response will be sent to the client.
*/
PutAsyncCallbackJsonWebHandler(
const char* uri,
bool (*customHandler)(const JsonDocument&, bool) = nullptr)
: AsyncCallbackJsonWebHandler(
uri,
[customHandler](AsyncWebServerRequest* request, JsonVariant& json) {
if (!customHandler) {
request->send(500, "application/json", "{\"error\":\"No handler provided\"}");
return;
}

// Parse the JSON payload
JsonDocument doc;
doc = json.as<JsonObject>();

// Call the handler
if (customHandler(doc, true)) {
request->send(200, "application/json", "{\"status\":\"ok\"}");
} else {
request->send(400, "application/json", "{\"status\":\"error\"}");
}
}),
_customHandler(customHandler) {
setMethod(HTTP_PUT);
}
};


/**
* @class GetAsyncCallbackJsonWebHandler
* @brief Extends AsyncCallbackJsonWebHandler to support custom JSON response handling for HTTP GET.
*
* This class provides the ability to process incoming GET requests in an `AsyncWebServer`
* using a user-defined handler function that generates and returns JSON data.
*/
class GetAsyncCallbackJsonWebHandler : public AsyncCallbackJsonWebHandler {
protected:
/**
* @brief Pointer to the custom handler function.
*
* The custom handler function generates JSON data to be sent in the response.
* It accepts a `JsonDocument` reference which it populates with the response data.
*/
void (*_customHandler)(JsonDocument&);

public:
/**
* @brief Constructor for GetAsyncCallbackJsonWebHandler.
*
* @param uri The URI to handle.
* @param customHandler A pointer to the custom handler function. The function must accept
* a `JsonDocument` reference and populate it with the response data.
*
* The custom handler function will be invoked for each GET request to the specified URI.
* If the handler is not provided, an appropriate HTTP response will be sent to the client.
*/
GetAsyncCallbackJsonWebHandler(
const char* uri,
void (*customHandler)(JsonDocument&) = nullptr)
: AsyncCallbackJsonWebHandler(
uri,
[customHandler](AsyncWebServerRequest* request, JsonVariant& json) {
if (!customHandler) {
request->send(500, "application/json", "{\"error\":\"No handler provided\"}");
return;
}

AsyncJsonResponse *response = new AsyncJsonResponse();
{
JsonDocument doc;
customHandler(doc);

// // Print the contents of doc to the serial console
// Serial.println(F("Generated JSON:"));
// serializeJsonPretty(doc, Serial); // Pretty print for easier reading
// Serial.println(); // Add a newline for better formatting

response->getRoot().set(doc);
}

response->setLength();
request->send(response);

}),
_customHandler(customHandler) {
setMethod(HTTP_GET);
}

};

#endif // ASYNC_JSON_SUPPORT == 1

#endif // EXTENDED_ASYNC_JSON_HANDLER_H_

Loading

0 comments on commit dd185d3

Please sign in to comment.