From f3b2531a033e2190114eda1edac1e7d91e404ce6 Mon Sep 17 00:00:00 2001 From: mjardiEnz Date: Mon, 11 Dec 2023 14:36:09 +0100 Subject: [PATCH 01/28] Weeks on Battery through MQTT - Add Weeks on Battery that comes from Tilt readings through MQTT. --- src/sendData.cpp | 31 +++++++++++++++++++++++++------ src/tilt/tiltHydrometer.cpp | 6 ++++++ src/tilt/tiltHydrometer.h | 1 + 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/sendData.cpp b/src/sendData.cpp index 04c2b09..a59d5d1 100644 --- a/src/sendData.cpp +++ b/src/sendData.cpp @@ -716,7 +716,7 @@ bool dataSendHandler::send_to_mqtt() // Function sends three payloads with the first two designed to // support autodiscovery and configuration on Home Assistant. // General payload formatted as json when sent to mqTT: - //{"Color":"Black","SG":"1.0180","Temp":"73.0","fermunits":"SG","tempunits":"F","timeStamp":1608745710} + //{"Color":"Black","SG":"1.0180","Temp":"73.0","fermunits":"SG","tempunits":"F","WoB":"90","timeStamp":1608745710} // // Loop through each of the tilt colors cached by tilt_scanner, // sending data for each of the active tilts @@ -729,7 +729,7 @@ bool dataSendHandler::send_to_mqtt() config.mqttTopic, tilt_color_names[i]); - for (uint8_t j = 0; j < 3; j++) + for (uint8_t j = 0; j < 4; j++) { char m_topic[90] = {'\0'}; char tilt_name[15] = {'\0'}; @@ -741,7 +741,7 @@ bool dataSendHandler::send_to_mqtt() strcat(tilt_name, "Tilt "); strcat(tilt_name, tilt_color_names[i]); - if (j < 2 ) + if (j < 3 ) { JsonObject device = payload.createNestedObject("device"); device["identifiers"] = tilt_color_names[i]; @@ -773,9 +773,9 @@ bool dataSendHandler::send_to_mqtt() sprintf(m_topic, "homeassistant/sensor/%s_tilt_%sG/sp_gravity/config", config.mqttTopic, tilt_color_names[i]); - //payload["dev_cla"] = "None"; +//payload["dev_cla"] = "None"; payload["unit_of_meas"] = "SG"; - //payload["ic"] = ""; +//payload["ic"] = ""; payload["stat_t"] = tilt_topic; strcat(tilt_sensor_name, "Tilt Specific Gravity - "); strcat(tilt_sensor_name, tilt_color_names[i]); @@ -786,18 +786,37 @@ bool dataSendHandler::send_to_mqtt() payload["uniq_id"] = uniq_id; retain = true; break; - case 2: //General payload with sensor data + case 2: //Home Assistant Config Topic for Weeks On Battery + sprintf(m_topic, "homeassistant/sensor/%s_tilt_%sWoB/weeks_on_battery/config", + config.mqttTopic, + tilt_color_names[i]); + payload["unit_of_meas"] = "weeks"; + payload["ic"] = "mdi:battery"; + payload["stat_t"] = tilt_topic; + strcat(tilt_sensor_name, "Tilt Weeks On Battery - "); + strcat(tilt_sensor_name, tilt_color_names[i]); + payload["name"] = tilt_sensor_name; + payload["val_tpl"] = "{{value_json.WoB}}"; + snprintf(uniq_id, 30, "tiltbridge_tilt%sWoB", + tilt_color_names[i]); + payload["uniq_id"] = uniq_id; + retain = true; + break; + case 3: //General payload with sensor data strcat(m_topic, tilt_topic); char current_grav[8] = {'\0'}; char current_temp[5] = {'\0'}; + char current_wob[8] = {'\0'}; strcpy(current_grav, tilt_scanner.tilt(i)->converted_gravity(false).c_str()); strcpy(current_temp, tilt_scanner.tilt(i)->converted_temp(false).c_str()); + strcpy(current_wob, tilt_scanner.tilt(i)->get_weeks_battery().c_str()); payload["Color"] = tilt_color_names[i]; payload["timeStamp"] = (int)std::time(0); payload["fermunits"] = "SG"; payload["SG"] = current_grav; payload["Temp"] = current_temp; payload["tempunits"] = config.tempUnit; + payload["WoB"] = current_wob; retain = false; break; } diff --git a/src/tilt/tiltHydrometer.cpp b/src/tilt/tiltHydrometer.cpp index 0c4ac98..88dc879 100644 --- a/src/tilt/tiltHydrometer.cpp +++ b/src/tilt/tiltHydrometer.cpp @@ -253,6 +253,12 @@ std::string tiltHydrometer::converted_temp(bool fahrenheit_only) return output; } +std::string tiltHydrometer::get_weeks_battery() +{ + std::string stdString = std::to_string(weeks_since_last_battery_change); + return stdString; +} + bool tiltHydrometer::is_celsius() const { return strcmp(config.tempUnit, "C") == 0; diff --git a/src/tilt/tiltHydrometer.h b/src/tilt/tiltHydrometer.h index ee60a23..e1499cd 100644 --- a/src/tilt/tiltHydrometer.h +++ b/src/tilt/tiltHydrometer.h @@ -45,6 +45,7 @@ class tiltHydrometer std::string converted_gravity(bool use_raw_gravity); void to_json_string(char *json_string, bool use_raw_gravity); std::string converted_temp(bool fahrenheit_only); + std::string get_weeks_battery(); bool is_celsius() const; bool is_loaded(); From de26a52039f75f553c49e4e9823703874ef241a1 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 4 Feb 2024 09:49:15 -0500 Subject: [PATCH 02/28] Update to latest ArduinoJson and LCBUrl --- platformio.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index df75bb2..f0dc4a9 100644 --- a/platformio.ini +++ b/platformio.ini @@ -53,7 +53,7 @@ build_flags = ; Do not use spaces around the "=" here, ;-D FSEDIT=1 ; Use a filesystem editor extra_scripts = tools/get_port.py ; Pick up port information based on OS lib_deps = - bblanchon/ArduinoJson @ 6.21.2 ; https://github.com/bblanchon/ArduinoJson + bblanchon/ArduinoJson @ 6.21.5 ; https://github.com/bblanchon/ArduinoJson ; thijse/ArduinoLog @ 1.1.1 ; https://github.com/thijse/Arduino-Log.git https://github.com/thorrak/Arduino-Log.git ; // Need this until ArduinoLog merges https://github.com/thijse/Arduino-Log/pull/23 https://github.com/lbussy/esptelnet.git @@ -61,7 +61,7 @@ lib_deps = https://github.com/thorrak/WiFiManager.git#feature_asyncwebserver h2zero/NimBLE-Arduino @ 1.4.1 ; https://github.com/h2zero/NimBLE-Arduino 256dpi/MQTT @ 2.5.1 ; https://github.com/256dpi/arduino-mqtt - lbussy/LCBUrl @ ^1.1.7 + lbussy/LCBUrl @ ^1.1.9 https://github.com/lbussy/Parse-SDK-Arduino.git#fix_warnings espi_lib_deps = bodmer/TFT_eSPI @ 2.4.79 ; https://github.com/Bodmer/TFT_eSPI.git From 5d469611e4a050375a55f38841ff400a97d93dda Mon Sep 17 00:00:00 2001 From: John Date: Sun, 4 Feb 2024 14:15:55 -0500 Subject: [PATCH 03/28] Explicitly break out NimBLE log level --- platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/platformio.ini b/platformio.ini index f0dc4a9..fc0095f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -40,6 +40,7 @@ build_flags = ; Do not use spaces around the "=" here, -D PRINT_GRAV_UPDATES=0 ; Turn on and off gravity printing to serial log -D CORE_DEBUG_LEVEL=0 ; Set core Arduino log level (5 = high) -D ARDUINO_LOG_LEVEL=0 ; Set Serial log level (6 = high) + -D CONFIG_NIMBLE_CPP_LOG_LEVEL=0 ; Set NimBLE log level (4 = high) ;-D PARSE_DEBUG ; Turn main Parse debug logging on ;-D PARSE_DEBUG_RESPONSE ; Turn Parse response debugging on -D DISABLE_LOGGING ; This will remove log lib from sketch From 62d65ed443f1044c08de49e5c7ea0cc9be843b51 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 4 Feb 2024 14:16:47 -0500 Subject: [PATCH 04/28] Adjust memory logging level --- src/main.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 0fd85a8..ec12a1e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,7 +16,7 @@ void printMem() { const uint32_t free = ESP.getFreeHeap(); const uint32_t max = ESP.getMaxAllocHeap(); const uint8_t frag = 100 - (max * 100) / free; - Log.verbose(F("Free Heap: %d, Largest contiguous block: %d, Frag: %d%%\r\n"), free, max, frag); + Log.info(F("Free Heap: %d, Largest contiguous block: %d, Frag: %d%%\r\n"), free, max, frag); } void reboot() @@ -52,7 +52,8 @@ void setup() { initButtons(); // Initialize buttons // Start independent timers -#if (ARDUINO_LOG_LEVEL >= 5) && !defined(DISABLE_LOGGING) + // ARDUINO_LOG_LOG_LEVEL_INFO is 4 +#if (ARDUINO_LOG_LEVEL >= ARDUINO_LOG_LOG_LEVEL_INFO) && !defined(DISABLE_LOGGING) memCheck.attach(30, printMem); // Memory debug print on timer #endif From f06c12f2b5219d24516c3009fc5fcaf9d481ab39 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 4 Feb 2024 14:20:35 -0500 Subject: [PATCH 05/28] Rebuild send_to_url Leverages HTTPClient, and adds support for both http and https --- src/sendData.cpp | 167 +++++++++++++++++------------------------------ src/sendData.h | 6 +- 2 files changed, 60 insertions(+), 113 deletions(-) diff --git a/src/sendData.cpp b/src/sendData.cpp index 04c2b09..cee462f 100644 --- a/src/sendData.cpp +++ b/src/sendData.cpp @@ -77,7 +77,7 @@ bool dataSendHandler::send_to_localTarget() serializeJson(doc, tilt_data); - if (send_to_url(config.localTargetURL, "", tilt_data, "application/json")) + if (send_to_url(config.localTargetURL, tilt_data, "application/json")) { Log.notice(F("Completed send to Local Target.\r\n")); } @@ -241,7 +241,7 @@ bool dataSendHandler::send_to_bf_and_bf(const uint8_t which_bf) char payload_string[BF_SIZE]; serializeJson(j, payload_string); - if (!send_to_url(url, "", payload_string, "application/json")) + if (!send_to_url(url, payload_string, "application/json")) result = false; // There was an error with the previous send } } @@ -327,7 +327,7 @@ bool dataSendHandler::send_to_brewstatus() tilt_scanner.tilt(i)->converted_temp(true).c_str(), // Only sending Fahrenheit numbers since we don't send units tilt_color_names[i], ((double)std::time(0) + (config.TZoffset * 3600.0)) / 86400.0 + 25569.0); - if (send_to_url(config.brewstatusURL, "", payload, "application/x-www-form-urlencoded")) + if (send_to_url(config.brewstatusURL, payload, "application/x-www-form-urlencoded")) { Log.notice(F("Completed send to Brew Status.\r\n")); } @@ -422,6 +422,9 @@ bool dataSendHandler::send_to_google() serializeJson(payload, payload_string); payload.clear(); + HTTPClient http; + WiFiClientSecure secureClient; + http.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS); // Follow the 301 http.setConnectTimeout(6000); // Set 6 second timeout http.setReuse(false); @@ -547,7 +550,7 @@ String lcburl_getAfterPath(LCBUrl url) // Get anything after the path return afterpath; } -bool dataSendHandler::send_to_url(const char *url, const char *apiKey, const char *dataToSend, const char *contentType, bool checkBody, const char* bodyCheck) +bool dataSendHandler::send_to_url(const char *url, const char *dataToSend, const char *contentType, bool checkBody, const char* bodyCheck) { // This handles the generic act of sending data to an endpoint bool retVal = false; @@ -558,6 +561,8 @@ bool dataSendHandler::send_to_url(const char *url, const char *apiKey, const cha lcburl.setUrl(url); bool validTarget = false; + // There is an issue where the built-in HTTP client for some reason won't resolve mDNS addresses. Instead, we'll + // resolve the address first, and then pass that to the client if needed. if (lcburl.isMDNS(lcburl.getHost().c_str())) { // Make sure we can resolve the address @@ -570,12 +575,11 @@ bool dataSendHandler::send_to_url(const char *url, const char *apiKey, const cha else { // If it's not mDNS all we care about is that it's http - if (lcburl.getScheme() == "http") + // if (lcburl.getScheme() == "http") validTarget = true; } - if (validTarget) - { + if (validTarget) { if (lcburl.isMDNS(lcburl.getHost().c_str())) // Use the IP address we resolved (necessary for mDNS) Log.verbose(F("Connecting to: %s at %s on port %l\r\n"), @@ -587,115 +591,62 @@ bool dataSendHandler::send_to_url(const char *url, const char *apiKey, const cha lcburl.getHost().c_str(), lcburl.getPort()); - if (client.connect(lcburl.getIP(lcburl.getHost().c_str()), lcburl.getPort())) - { - Log.verbose(F("Connected to: %s.\r\n"), lcburl.getHost().c_str()); - // Open POST connection - if (lcburl_getAfterPath(lcburl).length() > 0) - { - Log.verbose(F("POST /%s%s HTTP/1.1\r\n"), - lcburl.getPath().c_str(), - lcburl_getAfterPath(lcburl).c_str()); - } - else - { - Log.verbose(F("POST /%s HTTP/1.1\r\n"), lcburl.getPath().c_str()); - } - client.print(F("POST /")); - client.print(lcburl.getPath().c_str()); - if (lcburl_getAfterPath(lcburl).length() > 0) - { - client.print(lcburl_getAfterPath(lcburl).c_str()); - } - client.println(F(" HTTP/1.1")); - - // Begin headers - // - // Host - Log.verbose(F("Host: %s:%l\r\n"), lcburl.getHost().c_str(), lcburl.getPort()); - client.print(F("Host: ")); - client.print(lcburl.getHost().c_str()); - client.print(F(":")); - client.println(lcburl.getPort()); - // - Log.verbose(F("Connection: close\r\n")); - client.println(F("Connection: close")); - // Content - Log.verbose(F("Content-Length: %l\r\n"), strlen(dataToSend)); - client.print(F("Content-Length: ")); - client.println(strlen(dataToSend)); - // Content Type - Log.verbose(F("Content-Type: %s\r\n"), contentType); - client.print(F("Content-Type: ")); - client.println(contentType); - // API Key - if (strlen(apiKey) > 2) - { - Log.verbose(F("X-API-KEY: %s\r\n"), apiKey); - client.print(F("X-API-KEY: ")); - client.println(apiKey); - } - // Terminate headers with a blank line - Log.verbose(F("End headers.\r\n")); - client.println(); - // - // End Headers - - // Post JSON - client.println(dataToSend); - // Check the HTTP status (should be "HTTP/1.1 200 OK") - char status[32] = {0}; - client.readBytesUntil('\r', status, sizeof(status)); - client.stop(); - Log.verbose(F("Status: %s\r\n"), status); - if (strcmp(status + 9, "200 OK") == 0) - { - if (checkBody == true) // We can do additional checks here - { - // Check body - String response = String(status); - if (response.indexOf(bodyCheck) >= 0) - { - Log.verbose(F("Response body ok.\r\n")); - retVal = true; - } - else - { - Log.error(F("Unexpected body content: %s\r\n"), response.c_str()); - retVal = false; - } - } - else - { - Log.verbose(F("Post to %s was successful.\r\n"), lcburl.getHost().c_str()); - retVal = true; + // This may crash if we're allocating too much memory on the heap, but if I can get away with this + // it's the easiest solution. + HTTPClient http; + WiFiClientSecure secureClient; + secureClient.setInsecure(); // Don't perform certificate validation. This opens up MITM attacks, but I don't have memory otherwise. + + // Determine if the URL is HTTP or HTTPS and initialize HTTPClient + if (lcburl.getScheme() == "https") { + http.begin(secureClient, url); // HTTPS + } else { + http.begin(url); // HTTP + } + + // Set headers + http.addHeader("Content-Type", contentType); + http.addHeader("Accept", "application/json"); + + // Send the request + int httpResponseCode; + httpResponseCode = http.POST(dataToSend); + + // Optionally check the response + bool result = false; + if (httpResponseCode > 0) { + // HTTP header has been sent and Server response header has been handled + Log.verbose(F("HTTP Response code: %d\r\n"), httpResponseCode); + + if (checkBody) { + String response = http.getString(); + if (response.indexOf(bodyCheck) >= 0) { + result = true; + } else { + Log.error(F("Body check failed. Body: %s\r\n"), response.c_str()); } + } else { + result = (httpResponseCode == HTTP_CODE_OK); } - else - { - Log.error(F("Unexpected status: %s\r\n"), status); - retVal = false; - } - } - else - { - Log.warning(F("Connection failed, Host: %s, Port: %l (Err: %d)\r\n"), - lcburl.getHost().c_str(), lcburl.getPort(), client.connected()); - retVal = false; + } else { + Log.error(F("Error on sending POST: %s\r\n"), http.errorToString(httpResponseCode).c_str()); + Log.error(F("Connection failed, Host: %s, Port: %l\r\n"), lcburl.getHost().c_str(), lcburl.getPort()); } - } - else - { + + // Close connection + http.end(); + delay(100); // Give garbage collection time to run + return result; + + } else { Log.error(F("Invalid target: %s.\r\n"), url); } - } - else - { + } else { Log.notice(F("No URL provided, or no data to send.\r\n")); - retVal = false; } - return retVal; + // If we reached here, the send was unsuccessful + return false; } bool dataSendHandler::send_to_mqtt() diff --git a/src/sendData.h b/src/sendData.h index 66ee709..1cdec0a 100644 --- a/src/sendData.h +++ b/src/sendData.h @@ -69,12 +69,8 @@ class dataSendHandler private: void connect_mqtt(); - bool send_to_url(const char *url, const char *apiKey, const char *dataToSend, const char *contentType, bool checkBody = false, const char *bodyCheck = ""); - bool http_send_json(const char *url, const char * payload); - HTTPClient http; - WiFiClient client; + bool send_to_url(const char *url, const char *dataToSend, const char *contentType, bool checkBody = false, const char *bodyCheck = ""); WiFiClient mqClient; - WiFiClientSecure secureClient; }; bool send_to_bf_and_bf(); From e4aac9109674d2c35c39fd884f14cdcd8020aef2 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 4 Feb 2024 14:21:48 -0500 Subject: [PATCH 06/28] Refactor Grainfather support to use send_to_url (Fixes #241) --- src/sendData.cpp | 36 ++---------------------------------- 1 file changed, 2 insertions(+), 34 deletions(-) diff --git a/src/sendData.cpp b/src/sendData.cpp index cee462f..585a8bc 100644 --- a/src/sendData.cpp +++ b/src/sendData.cpp @@ -251,7 +251,6 @@ bool dataSendHandler::send_to_bf_and_bf(const uint8_t which_bf) bool dataSendHandler::send_to_grainfather() { bool result = true; - StaticJsonDocument j; if (send_grainfather && ! send_lock) { @@ -272,6 +271,7 @@ bool dataSendHandler::send_to_grainfather() if (tilt_scanner.tilt(i)->is_loaded()) { + StaticJsonDocument j; Log.verbose(F("Tilt loaded with color name: %s\r\n"), tilt_color_names[i]); j["Temp"] = tilt_scanner.tilt(i)->converted_temp(true); // Always in Fahrenheit j["Unit"] = "F"; @@ -280,7 +280,7 @@ bool dataSendHandler::send_to_grainfather() char payload_string[GF_SIZE]; serializeJson(j, payload_string); - if (!http_send_json(config.grainfatherURL[i].link, payload_string)) + if (!send_to_url(config.grainfatherURL[i].link, payload_string, "application/json")) { result = false; // There was an error with the previous send } @@ -345,38 +345,6 @@ bool dataSendHandler::send_to_brewstatus() return result; } -bool dataSendHandler::http_send_json(const char * url, const char * payload) -{ - int httpResponseCode; - StaticJsonDocument retval; - http.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS); - http.setConnectTimeout(6000); - http.setReuse(false); - - secureClient.setInsecure(); - - http.addHeader(F("Content-Type"), F("application/json")); - http.addHeader(F("Accept"), F("application/json")); - httpResponseCode = http.POST(payload); - - if (httpResponseCode >= 400) { - Log.error(F("HTTP error %d: %s, %s.\r\n"), httpResponseCode, http.errorToString(httpResponseCode).c_str(), http.getString().c_str()); - return false; - } - - if (!http.begin(secureClient, url)) { - Log.error(F("Unable to create secure connection to %s.\r\n"), url); - return false; - } - - deserializeJson(retval, http.getString().c_str()); - - http.end(); - retval.clear(); - - return true; -} - bool dataSendHandler::send_to_google() { From effc284783ea8fc262f4f30177557ce3b91e4de7 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 4 Feb 2024 14:25:01 -0500 Subject: [PATCH 07/28] Update GitHub build action --- .github/workflows/build.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index fc0ebae..5d48fe5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,6 +4,7 @@ on: push: branches: - master + - new_sender # tags: # - "v*" # pull_request: @@ -21,11 +22,11 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3.3.0 + - uses: actions/checkout@v4.1.1 - run: git fetch --prune --unshallow - name: Cache pip - uses: actions/cache@v3.2.2 + uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} @@ -33,13 +34,13 @@ jobs: ${{ runner.os }}-pip- - name: Cache PlatformIO - uses: actions/cache@v3.2.2 + uses: actions/cache@v4 with: path: ~/.platformio key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }} - name: Set up Python - uses: actions/setup-python@v4.4.0 + uses: actions/setup-python@v5 - name: Install PlatformIO run: | From c4b11d4fa298a5b7c4e3c2f62f185bbf685b6bec Mon Sep 17 00:00:00 2001 From: John Date: Sun, 4 Feb 2024 14:55:25 -0500 Subject: [PATCH 08/28] Clean up includes --- src/jsonconfig.cpp | 5 +- src/main.cpp | 4 +- src/main.h | 15 ------ src/sendData.cpp | 19 +++++++ src/sendData.h | 18 +------ src/send_targets/taplistio.cpp | 92 +--------------------------------- src/serialhandler.h | 2 - 7 files changed, 26 insertions(+), 129 deletions(-) diff --git a/src/jsonconfig.cpp b/src/jsonconfig.cpp index 25758e5..7465ffe 100644 --- a/src/jsonconfig.cpp +++ b/src/jsonconfig.cpp @@ -6,13 +6,10 @@ #include #endif - -#include "main.h" +#include "getGuid.h" #include "serialhandler.h" - #include "jsonconfig.h" -#include "bridge_lcd.h" #define MAX_FILENAME_LENGTH 32 diff --git a/src/main.cpp b/src/main.cpp index ec12a1e..5ca0637 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,9 +2,11 @@ // Please note - This source code (along with other files) are provided under license. // More details (including license details) can be found in the files accompanying this source code. - +#include "watchButtons.h" #include "main.h" #include "tilt/tiltScanner.h" +#include "http_server.h" + #if (ARDUINO_LOG_LEVEL >= 5) Ticker memCheck; diff --git a/src/main.h b/src/main.h index a614c56..1ec4c85 100644 --- a/src/main.h +++ b/src/main.h @@ -1,21 +1,6 @@ #ifndef _MAIN_H #define _MAIN_H -#include "watchButtons.h" -#include "http_server.h" -#include "sendData.h" -#include "bridge_lcd.h" -#include "wifi_setup.h" -#include "serialhandler.h" -#include "jsonconfig.h" -#include "parseTarget.h" -#include -#include -#include - -#ifdef LOG_LOCAL_LEVEL -#include -#endif void printMem(); void setup(); diff --git a/src/sendData.cpp b/src/sendData.cpp index 585a8bc..4c27ddb 100644 --- a/src/sendData.cpp +++ b/src/sendData.cpp @@ -1,5 +1,24 @@ +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include #include "sendData.h" #include "tilt/tiltScanner.h" +#include "jsonconfig.h" +#include "version.h" +#include "parseTarget.h" +#include "http_server.h" +#include "main.h" // for printMem() dataSendHandler data_sender; // Global data sender diff --git a/src/sendData.h b/src/sendData.h index 1cdec0a..0052c47 100644 --- a/src/sendData.h +++ b/src/sendData.h @@ -1,24 +1,8 @@ #ifndef TILTBRIDGE_SENDDATA_H #define TILTBRIDGE_SENDDATA_H -#include "serialhandler.h" -#include "wifi_setup.h" -#include "jsonconfig.h" -#include "main.h" // DEBUG - -#include -#include -#include - -#include -#include -#include #include -#include -#include -#include -#include -#include +#include #define GSCRIPTS_DELAY (10 * 60) // 10 minute delay between pushes to Google Sheets directly #define BREWERS_FRIEND_DELAY (15 * 60) // 15 minute delay between pushes to Brewer's Friend diff --git a/src/send_targets/taplistio.cpp b/src/send_targets/taplistio.cpp index 0b4be43..83d13c1 100644 --- a/src/send_targets/taplistio.cpp +++ b/src/send_targets/taplistio.cpp @@ -1,101 +1,13 @@ -#include #include -#include "Ticker.h" #include - #include -// #include -#include -#include -#include + +#include #include "jsonconfig.h" #include "tilt/tiltScanner.h" #include "sendData.h" -extern bool send_lock; // TODO - Move this to dataSendHandler - - -// bool dataSendHandler::send_to_taplistio() -// { -// StaticJsonDocument<192> j; -// char payload_string[192]; -// int httpResponseCode; -// bool result = true; - -// // See if it's our time to send. -// if (!send_taplistio) { -// return false; -// } else if (send_lock) { -// return false; -// } - -// // Attempt to send. -// send_taplistio = false; -// send_lock = true; - -// if (WiFiClass::status() != WL_CONNECTED) { -// Log.verbose(F("taplist.io: Wifi not connected, skipping send.\r\n")); -// taplistioTicker.once(config.taplistioPushEvery, [](){data_sender.send_taplistio = true;}); -// send_lock = false; -// return false; -// } - -// char userAgent[128]; -// snprintf(userAgent, sizeof(userAgent), -// "tiltbridge/%s (branch %s; build %s)", -// version(), -// branch(), -// build() -// ); - -// for (uint8_t i = 0; i < TILT_COLORS; i++) { - -// if (!tilt_scanner.tilt(i)->is_loaded()) { -// continue; -// } - -// j["Color"] = tilt_color_names[i]; -// j["Temp"] = tilt_scanner.tilt(i)->converted_temp(false); -// j["SG"] = tilt_scanner.tilt(i)->converted_gravity(false); -// j["temperature_unit"] = "F"; -// j["gravity_unit"] = "G"; - -// serializeJson(j, payload_string); - -// http.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS); -// http.setConnectTimeout(6000); -// http.setReuse(false); -// secureClient.setInsecure(); - -// Log.verbose(F("taplist.io: Sending %s Tilt to %s\r\n"), tilt_color_names[i], config.taplistioURL); - -// if (!http.begin(secureClient, config.taplistioURL)) { -// Log.error(F("taplist.io: Unable to create secure connection to %s\r\n"), config.taplistioURL); -// result = false; -// break; -// } - -// http.addHeader(F("Content-Type"), F("application/json")); -// http.setUserAgent(userAgent); -// httpResponseCode = http.POST(payload_string); - -// if (httpResponseCode < HTTP_CODE_OK || httpResponseCode > HTTP_CODE_NO_CONTENT) { -// Log.error(F("taplist.io: send %s Tilt failed (%d): %s. Response:\r\n%s\r\n"), -// tilt_color_names[i], -// httpResponseCode, -// http.errorToString(httpResponseCode).c_str(), -// http.getString().c_str()); -// result = false; -// } else { -// Log.verbose(F("taplist.io: %s Tilt: success!\r\n"), tilt_color_names[i]); -// } -// } - -// taplistioTicker.once(config.taplistioPushEvery, [](){send_taplistio = true;}); -// send_lock = false; -// return result; -// } bool dataSendHandler::send_to_taplistio() diff --git a/src/serialhandler.h b/src/serialhandler.h index 59234be..3c5ad05 100644 --- a/src/serialhandler.h +++ b/src/serialhandler.h @@ -1,8 +1,6 @@ #ifndef _SERIALLOG_H #define _SERIALLOG_H -#include - #if DOTELNET == true #include #include From 68998f206abc07947036b34fdaa0907d9fa0c4e0 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 4 Feb 2024 14:56:15 -0500 Subject: [PATCH 09/28] Use send_to_url for taplistio --- src/sendData.h | 1 + src/send_targets/taplistio.cpp | 54 +++------------------------------- 2 files changed, 5 insertions(+), 50 deletions(-) diff --git a/src/sendData.h b/src/sendData.h index 0052c47..b7731e6 100644 --- a/src/sendData.h +++ b/src/sendData.h @@ -61,5 +61,6 @@ bool send_to_bf_and_bf(); void send_to_cloud(); extern dataSendHandler data_sender; +extern bool send_lock; #endif //TILTBRIDGE_SENDDATA_H diff --git a/src/send_targets/taplistio.cpp b/src/send_targets/taplistio.cpp index 83d13c1..af708f0 100644 --- a/src/send_targets/taplistio.cpp +++ b/src/send_targets/taplistio.cpp @@ -12,11 +12,6 @@ bool dataSendHandler::send_to_taplistio() { - StaticJsonDocument<192> j; - char payload_string[192]; - char taplistio_url[768]; - char auth_header[64]; - int httpResponseCode; bool result = true; // See if it's our time to send. @@ -42,16 +37,10 @@ bool dataSendHandler::send_to_taplistio() return false; } - char userAgent[128]; - snprintf(userAgent, sizeof(userAgent), - "tiltbridge/%s (branch %s; build %s)", - version(), - branch(), - build() - ); - - for (uint8_t i = 0; i < TILT_COLORS; i++) { + StaticJsonDocument<192> j; + char payload_string[192]; + if (!tilt_scanner.tilt(i)->is_loaded()) { continue; @@ -67,42 +56,7 @@ bool dataSendHandler::send_to_taplistio() Log.verbose(F("taplist.io: Sending %s Tilt to %s\r\n"), tilt_color_names[i], config.taplistioURL); - yield(); // Yield before we lock up the radio - - WiFiClientSecure *client = new WiFiClientSecure; - if(client) { - client->setInsecure(); - { - // Add a scoping block for HTTPClient https to make sure it is destroyed before WiFiClientSecure *client is - HTTPClient http; - - http.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS); - http.setConnectTimeout(6000); - http.setReuse(false); - - if (http.begin(*client, config.taplistioURL)) { - http.addHeader(F("Content-Type"), F("application/json")); - http.setUserAgent(userAgent); - httpResponseCode = http.POST(payload_string); - - if (httpResponseCode < HTTP_CODE_OK || httpResponseCode > HTTP_CODE_NO_CONTENT) { - Log.error(F("taplist.io: send %s Tilt failed (%d): %s. Response:\r\n%s\r\n"), - tilt_color_names[i], - httpResponseCode, - http.errorToString(httpResponseCode).c_str(), - http.getString().c_str()); - result = false; - } else { - Log.verbose(F("taplist.io: %s Tilt: success!\r\n"), tilt_color_names[i]); - } - http.end(); - } else { - Log.error(F("taplist.io: Unable to create connection\r\n")); - result = false; - } - } - delete client; - } + result = send_to_url(config.taplistioURL, payload_string, "application/json"); } taplistioTicker.once(config.taplistioPushEvery, [](){data_sender.send_taplistio = true;}); From b75a8e4a4aae3343038e8d3d37298092bbb86d1d Mon Sep 17 00:00:00 2001 From: John Date: Sun, 4 Feb 2024 15:10:21 -0500 Subject: [PATCH 10/28] Consolidate send handling --- src/http_server.cpp | 28 ++++-------- src/main.cpp | 9 +--- src/parseTarget.cpp | 5 +- src/sendData.cpp | 108 ++++++++++++++++++++++---------------------- src/sendData.h | 27 +++++++++-- 5 files changed, 89 insertions(+), 88 deletions(-) diff --git a/src/http_server.cpp b/src/http_server.cpp index d57ffed..654bb10 100644 --- a/src/http_server.cpp +++ b/src/http_server.cpp @@ -18,16 +18,6 @@ httpServer http_server; Ticker sendNowTicker; -extern bool send_cloudTarget; -extern bool send_brewersFriend; -extern bool send_brewfather; -extern bool send_userTarget; -extern bool send_grainfather; -extern bool send_localTarget; -extern bool send_brewStatus; -extern bool send_gSheets; -extern bool send_mqtt; - AsyncWebServer server(WEBPORT); // This is to simplify the redirects in processCalibration @@ -220,7 +210,7 @@ bool processCloudTargetSettings(AsyncWebServerRequest *request) { if (!config.cloudEnabled) { config.cloudEnabled = true; // Trigger a send to Cloud in 5 seconds - sendNowTicker.once(5, [](){send_cloudTarget = true;}); + sendNowTicker.once(5, [](){data_sender.send_cloudTarget = true;}); } Log.notice(F("Settings update, [%s]:(%s) applied.\r\n"), name, value); } else if (strcmp(value, "false") == 0) { @@ -269,7 +259,7 @@ bool processLocalTargetSettings(AsyncWebServerRequest *request) { Log.notice(F("Settings update, [%s]:(%s) applied.\r\n"), name, value); strlcpy(config.localTargetURL, value, 256); // Trigger a send to Fermentrack/BPR in 5 seconds using the updated URL - sendNowTicker.once(5, [](){send_localTarget = true;}); + sendNowTicker.once(5, [](){data_sender.send_localTarget = true;}); } else if (strcmp(value, "") == 0 || strlen(value) == 0) { Log.notice(F("Settings update, [%s]:(%s) cleared.\r\n"), name, value); strlcpy(config.localTargetURL, value, 256); @@ -324,7 +314,7 @@ bool processGoogleSheetsSettings(AsyncWebServerRequest *request) { strlcpy(config.scriptsURL, value, 256); Log.notice(F("Settings update, [%s]:(%s) applied.\r\n"), name, value); // Trigger a send in 5 seconds using the updated GSheets URL - sendNowTicker.once(5, [](){send_gSheets = true;}); + sendNowTicker.once(5, [](){data_sender.send_gSheets = true;}); } else if (strcmp(value, "") == 0 || strlen(value) == 0) { strlcpy(config.scriptsURL, value, 256); Log.notice(F("Settings update, [%s]:(%s) cleared.\r\n"), name, value); @@ -412,7 +402,7 @@ bool processBrewersFriendSettings(AsyncWebServerRequest *request) { strlcpy(config.brewersFriendKey, value, 65); Log.notice(F("Settings update, [%s]:(%s) applied.\r\n"), name, value); // Trigger a send to Brewers Friend in 5 seconds using the updated key - sendNowTicker.once(5, [](){send_brewersFriend = true;}); + sendNowTicker.once(5, [](){data_sender.send_brewersFriend = true;}); } else if (strcmp(value, "") == 0 || strlen(value) == 0) { strlcpy(config.brewersFriendKey, value, 65); Log.notice(F("Settings update, [%s]:(%s) cleared.\r\n"), name, value); @@ -457,7 +447,7 @@ bool processBrewfatherSettings(AsyncWebServerRequest *request) strlcpy(config.brewfatherKey, value, 65); Log.notice(F("Settings update, [%s]:(%s) applied.\r\n"), name, value); // Trigger a send to Brewfather in 5 seconds using the updated key - sendNowTicker.once(5, [](){send_brewfather = true;}); + sendNowTicker.once(5, [](){data_sender.send_brewfather = true;}); } else if (strcmp(value, "") == 0 || strlen(value) == 0) { strlcpy(config.brewfatherKey, value, 65); Log.notice(F("Settings update, [%s]:(%s) cleared.\r\n"), name, value); @@ -502,7 +492,7 @@ bool processUserTargetSettings(AsyncWebServerRequest *request) strlcpy(config.userTargetURL, value, 65); Log.notice(F("Settings update, [%s]:(%s) applied.\r\n"), name, value); // Trigger a send to the user target in 5 seconds using the updated key - sendNowTicker.once(5, [](){send_userTarget = true;}); + sendNowTicker.once(5, [](){data_sender.send_userTarget = true;}); } else if (strcmp(value, "") == 0 || strlen(value) == 0) { strlcpy(config.userTargetURL, value, 128); Log.notice(F("Settings update, [%s]:(%s) cleared.\r\n"), name, value); @@ -557,7 +547,7 @@ bool processGrainfatherSettings(AsyncWebServerRequest *request) if (GRAINFATHER_MIN_URL_LENGTH < strlen(value) && strlen(value) < 64) { strlcpy(config.grainfatherURL[to_color].link, value, 64); Log.notice(F("Settings update, [%s]:(%s) applied.\r\n"), name, value); - sendNowTicker.once(5, [](){send_grainfather = true;}); + sendNowTicker.once(5, [](){data_sender.send_grainfather = true;}); } else if (strcmp(value, "") == 0 || strlen(value) == 0) { strlcpy(config.grainfatherURL[to_color].link, value, 64); Log.notice(F("Settings update, [%s]:(%s) cleared.\r\n"), name, value); @@ -601,7 +591,7 @@ bool processBrewstatusSettings(AsyncWebServerRequest *request) { strlcpy(config.brewstatusURL, value, 256); Log.notice(F("Settings update, [%s]:(%s) applied.\r\n"), name, value); // Trigger a send to Brewstatus in 5 seconds using the updated key - sendNowTicker.once(5, [](){send_brewStatus = true;}); + sendNowTicker.once(5, [](){data_sender.send_brewStatus = true;}); } else if (strcmp(value, "") == 0 || strlen(value) == 0) { strlcpy(config.brewstatusURL, value, 256); Log.notice(F("Settings update, [%s]:(%s) cleared.\r\n"), name, value); @@ -794,7 +784,7 @@ bool processMqttSettings(AsyncWebServerRequest *request) { } else { if (config.save()) { // Trigger a send via MQTT in 5 seconds using the updated data - sendNowTicker.once(5, [](){send_mqtt = true;}); + sendNowTicker.once(5, [](){data_sender.send_mqtt = true;}); return true; } else { Log.error(F("Error: Unable to save MQTT configuration data.\r\n")); diff --git a/src/main.cpp b/src/main.cpp index 5ca0637..8b619a7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -71,14 +71,7 @@ void loop() { serialLoop(); // Service telnet and console commands checkButtons(); // Check for reset calls - send_to_cloud(); - data_sender.send_to_localTarget(); - send_to_bf_and_bf(); - data_sender.send_to_brewstatus(); - data_sender.send_to_grainfather(); - data_sender.send_to_taplistio(); - data_sender.send_to_google(); - data_sender.send_to_mqtt(); + data_sender.process(); if (tilt_scanner.scan()) { // The scans are done asynchronously, so we'll poke the scanner to see if diff --git a/src/parseTarget.cpp b/src/parseTarget.cpp index 280f9a1..1d679b7 100644 --- a/src/parseTarget.cpp +++ b/src/parseTarget.cpp @@ -1,4 +1,5 @@ #include "parseTarget.h" +#include "sendData.h" #include "tilt/tiltScanner.h" #define SERVER_URL "http://tiltbridge.com/cloudkeys/keys.json" @@ -6,8 +7,6 @@ static bool parseHasKeys = false; static bool parseIsSetup = false; -extern bool send_cloudTarget; - void doParsePoll() // Get Parse data from git repo { if (!parseHasKeys) @@ -177,6 +176,6 @@ void addTiltToParse() // Dispatch data to Parse else { doParseSetup(); - send_cloudTarget = true; + data_sender.send_cloudTarget = true; } } diff --git a/src/sendData.cpp b/src/sendData.cpp index 4c27ddb..986a734 100644 --- a/src/sendData.cpp +++ b/src/sendData.cpp @@ -25,31 +25,6 @@ dataSendHandler data_sender; // Global data sender MQTTClient mqttClient(512); -// POST Timers -Ticker cloudTargetTicker; -Ticker localTargetTicker; -Ticker brewersFriendTicker; -Ticker brewfatherTicker; -Ticker userTargetTicker; -Ticker grainfatherTicker; -Ticker brewStatusTicker; -//Ticker taplistioTicker; // Now inside dataSendHandler object -Ticker gSheetsTicker; -Ticker mqttTicker; - -// POST Semaphores -bool send_cloudTarget = false; -bool send_localTarget = false; -bool send_brewersFriend = false; -bool send_brewfather = false; -bool send_userTarget = false; -bool send_grainfather = false; -bool send_brewStatus = false; -//bool send_taplistio = false; // Now inside dataSendHandler object -bool send_gSheets = false; -bool send_mqtt = false; -bool send_lock = false; - dataSendHandler::dataSendHandler() {} void dataSendHandler::init() @@ -58,25 +33,37 @@ void dataSendHandler::init() // Set up timers // DEBUG: - cloudTargetTicker.once(10, [](){send_cloudTarget = true;}); // Schedule first send to Cloud Target - localTargetTicker.once(20, [](){send_localTarget = true;}); // Schedule first send to Local Target -// localTargetTicker.once(5, [](){send_localTarget = true;}); // Schedule first send to Local Target + cloudTargetTicker.once(10, [](){data_sender.send_cloudTarget = true;}); // Schedule first send to Cloud Target + localTargetTicker.once(20, [](){data_sender.send_localTarget = true;}); // Schedule first send to Local Target +// localTargetTicker.once(5, [](){data_sender.send_localTarget = true;}); // Schedule first send to Local Target // DEBUG^ - brewStatusTicker.once(30, [](){send_brewStatus = true;}); // Schedule first send to Brew Status - brewfatherTicker.once(40, [](){send_brewfather = true;}); // Schedule first send to Brewfather - brewersFriendTicker.once(50, [](){send_brewersFriend = true;}); // Schedule first send to Brewer's Friend - userTargetTicker.once(60, [](){send_userTarget = true;}); // Schedule first send to User-defined JSON target - mqttTicker.once(65, [](){send_mqtt = true;}); // Schedule first send to MQTT - gSheetsTicker.once(70, [](){send_gSheets = true;}); // Schedule first send to Google Sheets - grainfatherTicker.once(80, [](){send_grainfather = true;}); // Schedule first send to Grainfather + brewStatusTicker.once(30, [](){data_sender.send_brewStatus = true;}); // Schedule first send to Brew Status + brewfatherTicker.once(40, [](){data_sender.send_brewfather = true;}); // Schedule first send to Brewfather + brewersFriendTicker.once(50, [](){data_sender.send_brewersFriend = true;}); // Schedule first send to Brewer's Friend + userTargetTicker.once(60, [](){data_sender.send_userTarget = true;}); // Schedule first send to User-defined JSON target + mqttTicker.once(65, [](){data_sender.send_mqtt = true;}); // Schedule first send to MQTT + gSheetsTicker.once(70, [](){data_sender.send_gSheets = true;}); // Schedule first send to Google Sheets + grainfatherTicker.once(80, [](){data_sender.send_grainfather = true;}); // Schedule first send to Grainfather taplistioTicker.once(90, [](){data_sender.send_taplistio = true;}); // Schedule first send to Taplist.io } +void dataSendHandler::process() +{ + send_to_cloud(); + send_to_localTarget(); + send_to_bf_and_bf(); + send_to_grainfather(); + send_to_brewstatus(); + send_to_taplistio(); + send_to_google(); + send_to_mqtt(); +} + bool dataSendHandler::send_to_localTarget() { bool result = true; - if (send_localTarget && ! send_lock) + if (data_sender.send_localTarget && !send_lock) { // Local Target send_localTarget = false; @@ -106,21 +93,21 @@ bool dataSendHandler::send_to_localTarget() Log.verbose(F("Error sending to Local Target.\r\n")); } } - localTargetTicker.once(config.localTargetPushEvery, [](){send_localTarget = true;}); // Set up subsequent send to localTarget + localTargetTicker.once(config.localTargetPushEvery, [](){data_sender.send_localTarget = true;}); // Set up subsequent send to localTarget // tilt_scanner.init(); send_lock = false; } return result; } -bool send_to_bf_and_bf() +bool dataSendHandler::send_to_bf_and_bf() { bool retval = false; - if (send_brewersFriend && ! send_lock) + if (data_sender.send_brewersFriend && !send_lock) { send_lock = true; // Brewer's Friend - send_brewersFriend = false; + data_sender.send_brewersFriend = false; if (WiFiClass::status() == WL_CONNECTED && strlen(config.brewersFriendKey) > BREWERS_FRIEND_MIN_KEY_LENGTH) { Log.verbose(F("Calling send to Brewer's Friend.\r\n")); @@ -134,15 +121,15 @@ bool send_to_bf_and_bf() Log.verbose(F("Error sending to Brewer's Friend.\r\n")); } } - brewersFriendTicker.once(BREWERS_FRIEND_DELAY, [](){send_brewersFriend = true;}); // Set up subsequent send to Brewer's Friend + brewersFriendTicker.once(BREWERS_FRIEND_DELAY, [](){data_sender.send_brewersFriend = true;}); // Set up subsequent send to Brewer's Friend send_lock = false; } - if (send_brewfather && ! send_lock) + if (data_sender.send_brewfather && !send_lock) { send_lock = true; // Brewfather - send_brewfather = false; + data_sender.send_brewfather = false; if (WiFiClass::status() == WL_CONNECTED && strlen(config.brewfatherKey) > BREWFATHER_MIN_KEY_LENGTH) { Log.verbose(F("Calling send to Brewfather.\r\n")); @@ -156,16 +143,16 @@ bool send_to_bf_and_bf() Log.verbose(F("Error sending to Brewfather.\r\n")); } } - brewfatherTicker.once(BREWFATHER_DELAY, [](){send_brewfather = true;}); // Set up subsequent send to Brewfather + brewfatherTicker.once(BREWFATHER_DELAY, [](){data_sender.send_brewfather = true;}); // Set up subsequent send to Brewfather send_lock = false; } - if (send_userTarget && ! send_lock) + if (data_sender.send_userTarget && !send_lock) { send_lock = true; // User Target - send_userTarget = false; + data_sender.send_userTarget = false; if (WiFiClass::status() == WL_CONNECTED && strlen(config.userTargetURL) > USER_TARGET_MIN_URL_LENGTH) { Log.verbose(F("Calling send to User Target.\r\n")); @@ -179,19 +166,19 @@ bool send_to_bf_and_bf() Log.verbose(F("Error sending to User Target.\r\n")); } } - userTargetTicker.once(USER_TARGET_DELAY, [](){send_userTarget = true;}); // Set up subsequent send to User Target + userTargetTicker.once(USER_TARGET_DELAY, [](){data_sender.send_userTarget = true;}); // Set up subsequent send to User Target send_lock = false; } return retval; } -void send_to_cloud() +void dataSendHandler::send_to_cloud() { - if (send_cloudTarget && ! send_lock) { + if (data_sender.send_cloudTarget && !send_lock) { send_lock = true; send_cloudTarget = false; addTiltToParse(); - cloudTargetTicker.once(CLOUD_DELAY, [](){send_cloudTarget = true;}); // Set up subsequent send to localTarget + cloudTargetTicker.once(CLOUD_DELAY, [](){data_sender.send_cloudTarget = true;}); // Set up subsequent send to localTarget } send_lock = false; } @@ -271,7 +258,7 @@ bool dataSendHandler::send_to_grainfather() { bool result = true; - if (send_grainfather && ! send_lock) + if (send_grainfather && !send_lock) { // Brew Status send_grainfather = false; @@ -306,7 +293,7 @@ bool dataSendHandler::send_to_grainfather() } } } - grainfatherTicker.once(GRAINFATHER_DELAY, [](){send_grainfather = true;}); // Set up subsequent send to Grainfather + grainfatherTicker.once(GRAINFATHER_DELAY, [](){data_sender.send_grainfather = true;}); // Set up subsequent send to Grainfather send_lock = false; } return result; @@ -358,7 +345,7 @@ bool dataSendHandler::send_to_brewstatus() } } } - brewStatusTicker.once(config.brewstatusPushEvery, [](){send_brewStatus = true;}); // Set up subsequent send to Brew Status + brewStatusTicker.once(config.brewstatusPushEvery, [](){data_sender.send_brewStatus = true;}); // Set up subsequent send to Brew Status send_lock = false; } return result; @@ -465,7 +452,7 @@ bool dataSendHandler::send_to_google() Log.notice(F("Submitted %l sheet%s to Google.\r\n"), numSent, (numSent== 1) ? "" : "s"); } - gSheetsTicker.once(GSCRIPTS_DELAY, [](){send_gSheets = true;}); // Set up subsequent send to Google Sheets + gSheetsTicker.once(GSCRIPTS_DELAY, [](){data_sender.send_gSheets = true;}); // Set up subsequent send to Google Sheets //tilt_scanner.init(); send_lock = false; @@ -596,6 +583,17 @@ bool dataSendHandler::send_to_url(const char *url, const char *dataToSend, const http.addHeader("Content-Type", contentType); http.addHeader("Accept", "application/json"); + char userAgent[128]; + snprintf(userAgent, sizeof(userAgent), + "tiltbridge/%s (branch %s; build %s)", + version(), + branch(), + build() + ); + http.setUserAgent(userAgent); + + yield(); // Yield before we lock up the radio + // Send the request int httpResponseCode; httpResponseCode = http.POST(dataToSend); @@ -765,7 +763,7 @@ bool dataSendHandler::send_to_mqtt() Log.verbose(F("Error publishing to MQTT Broker.\r\n")); } } - mqttTicker.once(config.mqttPushEvery, [](){send_mqtt = true;}); // Set up subsequent send to MQTT + mqttTicker.once(config.mqttPushEvery, [](){data_sender.send_mqtt = true;}); // Set up subsequent send to MQTT send_lock = false; } diff --git a/src/sendData.h b/src/sendData.h index b7731e6..102058e 100644 --- a/src/sendData.h +++ b/src/sendData.h @@ -45,22 +45,43 @@ class dataSendHandler bool send_to_mqtt(); bool send_to_bf_and_bf(uint8_t which_bf); // Handler for both Brewer's Friend and Brewfather bool send_to_grainfather(); + bool send_to_bf_and_bf(); + void send_to_cloud(); + // Send Timers + Ticker cloudTargetTicker; + Ticker localTargetTicker; + Ticker brewersFriendTicker; + Ticker brewfatherTicker; + Ticker userTargetTicker; + Ticker grainfatherTicker; + Ticker brewStatusTicker; Ticker taplistioTicker; + Ticker gSheetsTicker; + Ticker mqttTicker; + // Send Semaphores + bool send_cloudTarget = false; + bool send_localTarget = false; + bool send_brewersFriend = false; + bool send_brewfather = false; + bool send_userTarget = false; + bool send_grainfather = false; + bool send_brewStatus = false; bool send_taplistio = false; + bool send_gSheets = false; + bool send_mqtt = false; private: + bool send_lock = false; + void connect_mqtt(); bool send_to_url(const char *url, const char *dataToSend, const char *contentType, bool checkBody = false, const char *bodyCheck = ""); WiFiClient mqClient; }; -bool send_to_bf_and_bf(); -void send_to_cloud(); extern dataSendHandler data_sender; -extern bool send_lock; #endif //TILTBRIDGE_SENDDATA_H From 2e719e97b932e2f684bfb4b1415036bf5edff9eb Mon Sep 17 00:00:00 2001 From: John Date: Sun, 4 Feb 2024 15:20:03 -0500 Subject: [PATCH 11/28] Move parseTarget.cpp/.h --- src/http_server.cpp | 1 + src/http_server.h | 2 +- src/parseTarget.h | 21 --------------------- src/sendData.cpp | 2 +- src/{ => send_targets}/parseTarget.cpp | 7 +++++++ src/send_targets/parseTarget.h | 10 ++++++++++ 6 files changed, 20 insertions(+), 23 deletions(-) delete mode 100644 src/parseTarget.h rename src/{ => send_targets}/parseTarget.cpp (98%) create mode 100644 src/send_targets/parseTarget.h diff --git a/src/http_server.cpp b/src/http_server.cpp index 654bb10..eb7bdf7 100644 --- a/src/http_server.cpp +++ b/src/http_server.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "resetreasons.h" #include "uptime.h" diff --git a/src/http_server.h b/src/http_server.h index 8c9c67e..56c2ba3 100644 --- a/src/http_server.h +++ b/src/http_server.h @@ -5,7 +5,7 @@ #include "OTAUpdate.h" #include "sendData.h" #include "jsonconfig.h" -#include "parseTarget.h" +#include "send_targets/parseTarget.h" #ifdef FSEDIT #include diff --git a/src/parseTarget.h b/src/parseTarget.h deleted file mode 100644 index 0a25995..0000000 --- a/src/parseTarget.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _PARSE_TARGET_H -#define _PARSE_TARGET_H - -#include "version.h" -#include "getGuid.h" -#include "jsonconfig.h" -#include "tilt/tiltHydrometer.h" -#include -#include -#include -#include -#include -#include - -void doParsePoll(); -void doParseSetup(); -void addTiltToParse(); - -extern const char* tilt_color_names[]; - -#endif // _PARSE_TARGET_H diff --git a/src/sendData.cpp b/src/sendData.cpp index 986a734..c7304e2 100644 --- a/src/sendData.cpp +++ b/src/sendData.cpp @@ -16,7 +16,7 @@ #include "tilt/tiltScanner.h" #include "jsonconfig.h" #include "version.h" -#include "parseTarget.h" +#include "send_targets/parseTarget.h" #include "http_server.h" #include "main.h" // for printMem() diff --git a/src/parseTarget.cpp b/src/send_targets/parseTarget.cpp similarity index 98% rename from src/parseTarget.cpp rename to src/send_targets/parseTarget.cpp index 1d679b7..5a26054 100644 --- a/src/parseTarget.cpp +++ b/src/send_targets/parseTarget.cpp @@ -1,4 +1,11 @@ +#include +#include +#include + #include "parseTarget.h" + +#include "jsonconfig.h" +#include "version.h" #include "sendData.h" #include "tilt/tiltScanner.h" diff --git a/src/send_targets/parseTarget.h b/src/send_targets/parseTarget.h new file mode 100644 index 0000000..ecd8ae8 --- /dev/null +++ b/src/send_targets/parseTarget.h @@ -0,0 +1,10 @@ +#ifndef _PARSE_TARGET_H +#define _PARSE_TARGET_H + +void doParsePoll(); +void doParseSetup(); +void addTiltToParse(); + +extern const char* tilt_color_names[]; + +#endif // _PARSE_TARGET_H From 02ed27908de6389d8e9a4ea4ac3d2a8fc72d9721 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 4 Feb 2024 15:49:12 -0500 Subject: [PATCH 12/28] Clean up includes --- src/OTAUpdate.h | 3 --- src/bridge_lcd.cpp | 9 +++++---- src/getGuid.cpp | 1 + src/getGuid.h | 2 -- src/http_server.cpp | 10 ++++------ src/http_server.h | 6 ------ src/main.cpp | 11 ++++++++++- src/sendData.cpp | 8 ++++---- src/serialhandler.cpp | 1 - src/tilt/tiltHydrometer.h | 2 -- src/tilt/tiltScanner.cpp | 6 +++++- src/tilt/tiltScanner.h | 10 ++-------- src/uptime.cpp | 2 ++ src/uptime.h | 2 +- src/watchButtons.cpp | 1 + src/watchButtons.h | 4 ---- src/wifi_setup.cpp | 6 ++---- src/wifi_setup.h | 10 ---------- 18 files changed, 37 insertions(+), 57 deletions(-) diff --git a/src/OTAUpdate.h b/src/OTAUpdate.h index 743cbbb..9125a18 100644 --- a/src/OTAUpdate.h +++ b/src/OTAUpdate.h @@ -1,9 +1,6 @@ #ifndef TILTBRIDGE_OTAUPDATE_H #define TILTBRIDGE_OTAUPDATE_H -#include -#include - // Although this should be automatically done with build flags, OTA updates // are explicitly not supported on the "legacy" OLED screen version due to // flash constraints. TFT + 16MB flash only! diff --git a/src/bridge_lcd.cpp b/src/bridge_lcd.cpp index ba53876..dbe9894 100644 --- a/src/bridge_lcd.cpp +++ b/src/bridge_lcd.cpp @@ -1,13 +1,14 @@ -#include "bridge_lcd.h" -#include "jsonconfig.h" -#include "tilt/tiltScanner.h" -#include #include +#include #ifdef LCD_SSD1306 #include #endif +#include "jsonconfig.h" +#include "tilt/tiltScanner.h" +#include "bridge_lcd.h" + bridge_lcd lcd; #if defined(LCD_SSD1306) || defined(LCD_TFT_ESPI) diff --git a/src/getGuid.cpp b/src/getGuid.cpp index 4d1415e..5207c9c 100644 --- a/src/getGuid.cpp +++ b/src/getGuid.cpp @@ -1,4 +1,5 @@ #include + #include "getGuid.h" void getGuid(char *str) diff --git a/src/getGuid.h b/src/getGuid.h index eed68a1..a1c78b9 100644 --- a/src/getGuid.h +++ b/src/getGuid.h @@ -1,8 +1,6 @@ #ifndef _GET_GUID_H #define _GET_GUID_H -#include - void getGuid(char *str); #endif // _GET_GUID_H diff --git a/src/http_server.cpp b/src/http_server.cpp index eb7bdf7..5cd891e 100644 --- a/src/http_server.cpp +++ b/src/http_server.cpp @@ -1,19 +1,17 @@ #include -#include -#include -#include -#include #include -#include #include +#include #include "resetreasons.h" #include "uptime.h" #include "version.h" -#include "http_server.h" #include "jsonconfig.h" #include "tilt/tiltScanner.h" +#include "sendData.h" + +#include "http_server.h" httpServer http_server; diff --git a/src/http_server.h b/src/http_server.h index 56c2ba3..8a379fe 100644 --- a/src/http_server.h +++ b/src/http_server.h @@ -1,12 +1,6 @@ #ifndef TILTBRIDGE_HTTP_SERVER_H #define TILTBRIDGE_HTTP_SERVER_H -#include "wifi_setup.h" -#include "OTAUpdate.h" -#include "sendData.h" -#include "jsonconfig.h" -#include "send_targets/parseTarget.h" - #ifdef FSEDIT #include #endif diff --git a/src/main.cpp b/src/main.cpp index 8b619a7..71b535c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,10 +2,19 @@ // Please note - This source code (along with other files) are provided under license. // More details (including license details) can be found in the files accompanying this source code. +#include + #include "watchButtons.h" -#include "main.h" #include "tilt/tiltScanner.h" #include "http_server.h" +#include "wifi_setup.h" +#include "sendData.h" +#include "send_targets/parseTarget.h" +#include "jsonconfig.h" +#include "bridge_lcd.h" +#include "serialhandler.h" +#include "main.h" + #if (ARDUINO_LOG_LEVEL >= 5) diff --git a/src/sendData.cpp b/src/sendData.cpp index c7304e2..d3e14db 100644 --- a/src/sendData.cpp +++ b/src/sendData.cpp @@ -4,15 +4,13 @@ #include #include -#include #include #include - #include -#include +#include #include -#include "sendData.h" + #include "tilt/tiltScanner.h" #include "jsonconfig.h" #include "version.h" @@ -20,6 +18,8 @@ #include "http_server.h" #include "main.h" // for printMem() +#include "sendData.h" + dataSendHandler data_sender; // Global data sender diff --git a/src/serialhandler.cpp b/src/serialhandler.cpp index 1d2a388..1e2cfc2 100644 --- a/src/serialhandler.cpp +++ b/src/serialhandler.cpp @@ -1,4 +1,3 @@ -#include #include #include "serialhandler.h" diff --git a/src/tilt/tiltHydrometer.h b/src/tilt/tiltHydrometer.h index ee60a23..e1d874a 100644 --- a/src/tilt/tiltHydrometer.h +++ b/src/tilt/tiltHydrometer.h @@ -1,8 +1,6 @@ #ifndef TILTBRIDGE_TILTHYDROMETER_H #define TILTBRIDGE_TILTHYDROMETER_H -//#include "jsonconfig.h" -#include #include #define TILT_DATA_SIZE 477 // JSON size of a Tilt diff --git a/src/tilt/tiltScanner.cpp b/src/tilt/tiltScanner.cpp index 47a9c26..d693803 100644 --- a/src/tilt/tiltScanner.cpp +++ b/src/tilt/tiltScanner.cpp @@ -2,8 +2,12 @@ // Created by John Beeler on 5/12/18. // -#include "tiltScanner.h" #include +#include +#include + +#include "tiltScanner.h" + // Create the scanner BLEScan *pBLEScan; diff --git a/src/tilt/tiltScanner.h b/src/tilt/tiltScanner.h index 6ef4aaa..f5b1877 100644 --- a/src/tilt/tiltScanner.h +++ b/src/tilt/tiltScanner.h @@ -5,16 +5,10 @@ #ifndef TILTBRIDGE_TILTSCANNER_H #define TILTBRIDGE_TILTSCANNER_H -#include "tiltHydrometer.h" -#include "serialhandler.h" +#include + #include "tiltHydrometer.h" -#include -#include -#include -#include -#include -#include #define BLE_SCAN_TIME 3 // Seconds to scan diff --git a/src/uptime.cpp b/src/uptime.cpp index b161206..9135ca4 100644 --- a/src/uptime.cpp +++ b/src/uptime.cpp @@ -2,6 +2,8 @@ // Created by Lee Bussy on 12/31/20 // +#include + #include "uptime.h" static int refresh = UPTIME_REFRESH * 1000; diff --git a/src/uptime.h b/src/uptime.h index a81d63f..d31115e 100644 --- a/src/uptime.h +++ b/src/uptime.h @@ -5,7 +5,7 @@ #ifndef _UPTIME_H #define _UPTIME_H -#include +// #include #define UPTIME_REFRESH 1 diff --git a/src/watchButtons.cpp b/src/watchButtons.cpp index d26fb61..3e0b994 100644 --- a/src/watchButtons.cpp +++ b/src/watchButtons.cpp @@ -1,3 +1,4 @@ +#include "bridge_lcd.h" #include "watchButtons.h" static unsigned long wifiButtonTime = 0; // Button press timer diff --git a/src/watchButtons.h b/src/watchButtons.h index b87b850..022d748 100644 --- a/src/watchButtons.h +++ b/src/watchButtons.h @@ -1,10 +1,6 @@ #ifndef _WATCHBUTTONS_H #define _WATCHBUTTONS_H -#include "bridge_lcd.h" -#include -#include - // We use these for LCD_TFT_ESPI or LCD_SSD1306 #define BOARD_RESET_BUTTON_GPIO 35 // (Soft) Reset button #define WIFI_RESET_BUTTON_GPIO 0 // Boot button diff --git a/src/wifi_setup.cpp b/src/wifi_setup.cpp index 5d295d8..191f793 100644 --- a/src/wifi_setup.cpp +++ b/src/wifi_setup.cpp @@ -1,13 +1,11 @@ -#include #include #include -#include #include #include + #include "bridge_lcd.h" #include "jsonconfig.h" -#include "http_server.h" // Make sure this include is after WiFiManager -#include "serialhandler.h" +#include "http_server.h" #include "wifi_setup.h" diff --git a/src/wifi_setup.h b/src/wifi_setup.h index 98e1bc3..099fba7 100644 --- a/src/wifi_setup.h +++ b/src/wifi_setup.h @@ -4,16 +4,6 @@ #define WIFI_SETUP_AP_NAME "TiltBridgeAP" #define WIFI_SETUP_AP_PASS "tiltbridge" // Must be 8-63 chars -//#include "bridge_lcd.h" -//#include "serialhandler.h" -//#include "jsonconfig.h" -//#include - -//#include -//#include -//#include -//#include "http_server.h" // Make sure this include is after AsyncWiFiManager - #define WEB_SERVER_PORT 80 From a4d1a42adf0b717b3945a0ef943e30f92c8156a0 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 4 Feb 2024 16:06:12 -0500 Subject: [PATCH 13/28] Reorganize senders --- src/main.cpp | 2 +- src/{send_targets => }/parseTarget.cpp | 0 src/{send_targets => }/parseTarget.h | 0 src/sendData.cpp | 71 +++++++++++++++++++++++--- src/sendData.h | 3 ++ src/send_targets/taplistio.cpp | 65 ----------------------- 6 files changed, 67 insertions(+), 74 deletions(-) rename src/{send_targets => }/parseTarget.cpp (100%) rename src/{send_targets => }/parseTarget.h (100%) delete mode 100644 src/send_targets/taplistio.cpp diff --git a/src/main.cpp b/src/main.cpp index 71b535c..3beba85 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,7 +9,7 @@ #include "http_server.h" #include "wifi_setup.h" #include "sendData.h" -#include "send_targets/parseTarget.h" +#include "parseTarget.h" #include "jsonconfig.h" #include "bridge_lcd.h" #include "serialhandler.h" diff --git a/src/send_targets/parseTarget.cpp b/src/parseTarget.cpp similarity index 100% rename from src/send_targets/parseTarget.cpp rename to src/parseTarget.cpp diff --git a/src/send_targets/parseTarget.h b/src/parseTarget.h similarity index 100% rename from src/send_targets/parseTarget.h rename to src/parseTarget.h diff --git a/src/sendData.cpp b/src/sendData.cpp index d3e14db..a7b0fd0 100644 --- a/src/sendData.cpp +++ b/src/sendData.cpp @@ -14,7 +14,7 @@ #include "tilt/tiltScanner.h" #include "jsonconfig.h" #include "version.h" -#include "send_targets/parseTarget.h" +#include "parseTarget.h" #include "http_server.h" #include "main.h" // for printMem() @@ -83,7 +83,7 @@ bool dataSendHandler::send_to_localTarget() serializeJson(doc, tilt_data); - if (send_to_url(config.localTargetURL, tilt_data, "application/json")) + if (send_to_url(config.localTargetURL, tilt_data, content_json)) { Log.notice(F("Completed send to Local Target.\r\n")); } @@ -247,7 +247,7 @@ bool dataSendHandler::send_to_bf_and_bf(const uint8_t which_bf) char payload_string[BF_SIZE]; serializeJson(j, payload_string); - if (!send_to_url(url, payload_string, "application/json")) + if (!send_to_url(url, payload_string, content_json)) result = false; // There was an error with the previous send } } @@ -286,7 +286,7 @@ bool dataSendHandler::send_to_grainfather() char payload_string[GF_SIZE]; serializeJson(j, payload_string); - if (!send_to_url(config.grainfatherURL[i].link, payload_string, "application/json")) + if (!send_to_url(config.grainfatherURL[i].link, payload_string, content_json)) { result = false; // There was an error with the previous send } @@ -299,6 +299,61 @@ bool dataSendHandler::send_to_grainfather() return result; } +bool dataSendHandler::send_to_taplistio() +{ + bool result = true; + + // See if it's our time to send. + if (!send_taplistio) { + return false; + } else if (send_lock) { + Log.verbose(F("taplist.io: send lock set.\r\n")); + return false; + } + + + // Since we're only using .once timers, we can just detach/recreate every time and be fine + taplistioTicker.detach(); + + // Attempt to send. + send_taplistio = false; + send_lock = true; + + if (WiFiClass::status() != WL_CONNECTED) { + Log.verbose(F("taplist.io: Wifi not connected, skipping send.\r\n")); + taplistioTicker.once(config.taplistioPushEvery, [](){data_sender.send_taplistio = true;}); + send_lock = false; + return false; + } + + for (uint8_t i = 0; i < TILT_COLORS; i++) { + StaticJsonDocument<192> j; + char payload_string[192]; + + + if (!tilt_scanner.tilt(i)->is_loaded()) { + continue; + } + + j["Color"] = tilt_color_names[i]; + j["Temp"] = tilt_scanner.tilt(i)->converted_temp(false); + j["SG"] = tilt_scanner.tilt(i)->converted_gravity(false); + j["temperature_unit"] = "F"; + j["gravity_unit"] = "G"; + + serializeJson(j, payload_string); + + Log.verbose(F("taplist.io: Sending %s Tilt to %s\r\n"), tilt_color_names[i], config.taplistioURL); + + result = send_to_url(config.taplistioURL, payload_string, content_json); + } + + taplistioTicker.once(config.taplistioPushEvery, [](){data_sender.send_taplistio = true;}); + send_lock = false; + return result; +} + + bool dataSendHandler::send_to_brewstatus() { bool result = true; @@ -333,7 +388,7 @@ bool dataSendHandler::send_to_brewstatus() tilt_scanner.tilt(i)->converted_temp(true).c_str(), // Only sending Fahrenheit numbers since we don't send units tilt_color_names[i], ((double)std::time(0) + (config.TZoffset * 3600.0)) / 86400.0 + 25569.0); - if (send_to_url(config.brewstatusURL, payload, "application/x-www-form-urlencoded")) + if (send_to_url(config.brewstatusURL, payload, content_x_www_form_urlencoded)) { Log.notice(F("Completed send to Brew Status.\r\n")); } @@ -412,7 +467,7 @@ bool dataSendHandler::send_to_google() Log.verbose(F("Created secure connection to %s.\r\n"), config.scriptsURL); Log.verbose(F("Sending the following payload to Google Sheets (%s):\r\n\t\t%s\r\n"), tilt_color_names[i], payload_string); - http.addHeader(F("Content-Type"), F("application/json")); // Specify content-type header + http.addHeader(F("Content-Type"), content_json); // Specify content-type header httpResponseCode = http.POST(payload_string); // Send the payload if (httpResponseCode == HTTP_CODE_OK) { // HTTP_CODE_OK = 200 @@ -580,8 +635,8 @@ bool dataSendHandler::send_to_url(const char *url, const char *dataToSend, const } // Set headers - http.addHeader("Content-Type", contentType); - http.addHeader("Accept", "application/json"); + http.addHeader(F("Content-Type"), contentType); + http.addHeader(F("Accept"), content_json); char userAgent[128]; snprintf(userAgent, sizeof(userAgent), diff --git a/src/sendData.h b/src/sendData.h index 102058e..205a28e 100644 --- a/src/sendData.h +++ b/src/sendData.h @@ -84,4 +84,7 @@ class dataSendHandler extern dataSendHandler data_sender; +constexpr auto content_json = "application/json"; +constexpr auto content_x_www_form_urlencoded = "application/x-www-form-urlencoded"; + #endif //TILTBRIDGE_SENDDATA_H diff --git a/src/send_targets/taplistio.cpp b/src/send_targets/taplistio.cpp deleted file mode 100644 index af708f0..0000000 --- a/src/send_targets/taplistio.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include -#include -#include - -#include - -#include "jsonconfig.h" -#include "tilt/tiltScanner.h" -#include "sendData.h" - - - -bool dataSendHandler::send_to_taplistio() -{ - bool result = true; - - // See if it's our time to send. - if (!send_taplistio) { - return false; - } else if (send_lock) { - Log.verbose(F("taplist.io: send lock set.\r\n")); - return false; - } - - - // Since we're only using .once timers, we can just detach/recreate every time and be fine - taplistioTicker.detach(); - - // Attempt to send. - send_taplistio = false; - send_lock = true; - - if (WiFiClass::status() != WL_CONNECTED) { - Log.verbose(F("taplist.io: Wifi not connected, skipping send.\r\n")); - taplistioTicker.once(config.taplistioPushEvery, [](){data_sender.send_taplistio = true;}); - send_lock = false; - return false; - } - - for (uint8_t i = 0; i < TILT_COLORS; i++) { - StaticJsonDocument<192> j; - char payload_string[192]; - - - if (!tilt_scanner.tilt(i)->is_loaded()) { - continue; - } - - j["Color"] = tilt_color_names[i]; - j["Temp"] = tilt_scanner.tilt(i)->converted_temp(false); - j["SG"] = tilt_scanner.tilt(i)->converted_gravity(false); - j["temperature_unit"] = "F"; - j["gravity_unit"] = "G"; - - serializeJson(j, payload_string); - - Log.verbose(F("taplist.io: Sending %s Tilt to %s\r\n"), tilt_color_names[i], config.taplistioURL); - - result = send_to_url(config.taplistioURL, payload_string, "application/json"); - } - - taplistioTicker.once(config.taplistioPushEvery, [](){data_sender.send_taplistio = true;}); - send_lock = false; - return result; -} From 0dcd6327b36eaf2f397fe63a446c403202d837b2 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 4 Feb 2024 18:20:48 -0500 Subject: [PATCH 14/28] Increment version number --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index fc0095f..13bc37f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -27,7 +27,7 @@ monitor_rts = 1 build_flags = ; Do not use spaces around the "=" here, will give you a builder not found error !python tools/git_rev.py ; Pick up git information for version (disabled), branch, and commit (in version.cpp) - -D PIO_SRC_TAG=1.2.1 ; Increment versions shown in about.htm page (from version.cpp) + -D PIO_SRC_TAG=1.2.2 ; Increment versions shown in about.htm page (from version.cpp) ; Async TCP Settings: -D CONFIG_ASYNC_TCP_RUNNING_CORE=1 ; per: https://github.com/me-no-dev/ESPAsyncWebServer/issues/731#issuecomment-628163515 -D CONFIG_ASYNC_TCP_USE_WDT=1 From 70fea8ee27f59ced1d1defcc318cfb7c6cc8589b Mon Sep 17 00:00:00 2001 From: John Date: Sun, 18 Feb 2024 08:56:36 -0500 Subject: [PATCH 15/28] Update MQTT library --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 13bc37f..9a8933d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -61,7 +61,7 @@ lib_deps = https://github.com/me-no-dev/ESPAsyncWebServer.git https://github.com/thorrak/WiFiManager.git#feature_asyncwebserver h2zero/NimBLE-Arduino @ 1.4.1 ; https://github.com/h2zero/NimBLE-Arduino - 256dpi/MQTT @ 2.5.1 ; https://github.com/256dpi/arduino-mqtt + 256dpi/MQTT @ 2.5.2 ; https://github.com/256dpi/arduino-mqtt lbussy/LCBUrl @ ^1.1.9 https://github.com/lbussy/Parse-SDK-Arduino.git#fix_warnings espi_lib_deps = From 2b3b95d69fd23582a9af432f94a3c7821e842262 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 18 Feb 2024 11:08:53 -0500 Subject: [PATCH 16/28] Rewrite MQTT sender --- src/sendData.cpp | 292 +++++++++++++++++++++++++---------------------- src/sendData.h | 15 ++- 2 files changed, 166 insertions(+), 141 deletions(-) diff --git a/src/sendData.cpp b/src/sendData.cpp index 5f56628..5eab5ed 100644 --- a/src/sendData.cpp +++ b/src/sendData.cpp @@ -689,157 +689,171 @@ bool dataSendHandler::send_to_url(const char *url, const char *dataToSend, const return false; } -bool dataSendHandler::send_to_mqtt() -{ - // TODO: (JSON) Come back and tighten this up + +bool dataSendHandler::send_to_mqtt() { bool result = false; - StaticJsonDocument<512> payload; mqttClient.loop(); - if (send_mqtt && ! send_lock) - { - // MQTT + if (send_mqtt && !send_lock) { send_mqtt = false; send_lock = true; - if (strcmp(config.mqttBrokerHost, "") != 0 || strlen(config.mqttBrokerHost) != 0) - { + + if (strcmp(config.mqttBrokerHost, "") != 0 || strlen(config.mqttBrokerHost) != 0) { Log.verbose(F("Publishing available results to MQTT Broker.\r\n")); - // Function sends three payloads with the first two designed to - // support autodiscovery and configuration on Home Assistant. - // General payload formatted as json when sent to mqTT: - //{"Color":"Black","SG":"1.0180","Temp":"73.0","fermunits":"SG","tempunits":"F","WoB":"90","timeStamp":1608745710} - // - // Loop through each of the tilt colors cached by tilt_scanner, - // sending data for each of the active tilts - for (uint8_t i = 0; i < TILT_COLORS; i++) - { - if (tilt_scanner.tilt(i)->is_loaded()) - { - char tilt_topic[50] = {'\0'}; - snprintf(tilt_topic, 50, "%s/tilt_%s", - config.mqttTopic, - tilt_color_names[i]); - for (uint8_t j = 0; j < 4; j++) - { - char m_topic[90] = {'\0'}; - char tilt_name[15] = {'\0'}; - char tilt_sensor_name[35] = {'\0'}; - char uniq_id[30] = {'\0'}; - char unit[10] = {'\0'}; - bool retain = false; - - strcat(tilt_name, "Tilt "); - strcat(tilt_name, tilt_color_names[i]); - - if (j < 3 ) - { - JsonObject device = payload.createNestedObject("device"); - device["identifiers"] = tilt_color_names[i]; - device["name"] = tilt_name; - } - - switch (j) - { - case 0: //Home Assistant Config Topic for Temperature - sprintf(m_topic, "homeassistant/sensor/%s_tilt_%s/temperature/config", - config.mqttTopic, - tilt_color_names[i]); - payload["dev_cla"] = "temperature"; - strcat(unit, "\u00b0"); - strcat(unit, config.tempUnit); - payload["unit_of_meas"] = unit; - payload["ic"] = "mdi:thermometer"; - payload["stat_t"] = tilt_topic; - strcat(tilt_sensor_name, "Tilt Temperature - "); - strcat(tilt_sensor_name, tilt_color_names[i]); - payload["name"] = tilt_sensor_name; - payload["val_tpl"] = "{{value_json.Temp}}"; - snprintf(uniq_id, 30, "tiltbridge_tilt%sT", - tilt_color_names[i]); - payload["uniq_id"] = uniq_id; - retain = true; - break; - case 1: //Home Assistant Config Topic for Sp Gravity - sprintf(m_topic, "homeassistant/sensor/%s_tilt_%sG/sp_gravity/config", - config.mqttTopic, - tilt_color_names[i]); -//payload["dev_cla"] = "None"; - payload["unit_of_meas"] = "SG"; -//payload["ic"] = ""; - payload["stat_t"] = tilt_topic; - strcat(tilt_sensor_name, "Tilt Specific Gravity - "); - strcat(tilt_sensor_name, tilt_color_names[i]); - payload["name"] = tilt_sensor_name; - payload["val_tpl"] = "{{value_json.SG}}"; - snprintf(uniq_id, 30, "tiltbridge_tilt%sG", - tilt_color_names[i]); - payload["uniq_id"] = uniq_id; - retain = true; - break; - case 2: //Home Assistant Config Topic for Weeks On Battery - sprintf(m_topic, "homeassistant/sensor/%s_tilt_%sWoB/weeks_on_battery/config", - config.mqttTopic, - tilt_color_names[i]); - payload["unit_of_meas"] = "weeks"; - payload["ic"] = "mdi:battery"; - payload["stat_t"] = tilt_topic; - strcat(tilt_sensor_name, "Tilt Weeks On Battery - "); - strcat(tilt_sensor_name, tilt_color_names[i]); - payload["name"] = tilt_sensor_name; - payload["val_tpl"] = "{{value_json.WoB}}"; - snprintf(uniq_id, 30, "tiltbridge_tilt%sWoB", - tilt_color_names[i]); - payload["uniq_id"] = uniq_id; - retain = true; - break; - case 3: //General payload with sensor data - strcat(m_topic, tilt_topic); - char current_grav[8] = {'\0'}; - char current_temp[5] = {'\0'}; - char current_wob[8] = {'\0'}; - strcpy(current_grav, tilt_scanner.tilt(i)->converted_gravity(false).c_str()); - strcpy(current_temp, tilt_scanner.tilt(i)->converted_temp(false).c_str()); - strcpy(current_wob, tilt_scanner.tilt(i)->get_weeks_battery().c_str()); - payload["Color"] = tilt_color_names[i]; - payload["timeStamp"] = (int)std::time(0); - payload["fermunits"] = "SG"; - payload["SG"] = current_grav; - payload["Temp"] = current_temp; - payload["tempunits"] = config.tempUnit; - payload["WoB"] = current_wob; - retain = false; - break; - } - char payload_string[320] = {'\0'}; - serializeJson(payload, payload_string); + for (uint8_t i = 0; i < TILT_COLORS; i++) { + if (tilt_scanner.tilt(i)->is_loaded()) { + prepare_and_send_payloads(i); + } + } - Log.verbose(F("Topic: %s\r\n"), m_topic); - Log.verbose(F("Message: %s\r\n"), payload_string); + mqttTicker.once(config.mqttPushEvery, [](){ data_sender.send_mqtt = true; }); + send_lock = false; + } + } - if (!mqttClient.connected() && j == 0) - { - Log.warning(F("MQTT disconnected. Attempting to reconnect to MQTT Broker\r\n")); - connect_mqtt(); - } + return result; +} - result = mqttClient.publish(m_topic, payload_string, retain, 0); - delay(10); +void dataSendHandler::prepare_and_send_payloads(uint8_t tilt_index) { + char tilt_topic[50] = {'\0'}; + snprintf(tilt_topic, 50, "%s/tilt_%s", config.mqttTopic, tilt_color_names[tilt_index]); - payload.clear(); - } - } - } - if (result) { - Log.notice(F("Completed publish to MQTT Broker.\r\n")); - } else { - result = false; // There was an error with the previous send - Log.verbose(F("Error publishing to MQTT Broker.\r\n")); - } - } - mqttTicker.once(config.mqttPushEvery, [](){data_sender.send_mqtt = true;}); // Set up subsequent send to MQTT - send_lock = false; + // Prepare and send each of the four payloads + prepare_temperature_payload(tilt_color_names[tilt_index], tilt_topic); + prepare_gravity_payload(tilt_color_names[tilt_index], tilt_topic); + prepare_battery_payload(tilt_color_names[tilt_index], tilt_topic); + prepare_general_payload(tilt_index, tilt_topic); +} + +void dataSendHandler::prepare_temperature_payload(const char* tilt_color, const char* tilt_topic) { + //Home Assistant Config Topic for Temperature + char m_topic[90]; + char tilt_sensor_name[35]; + char uniq_id[30]; + char unit[10] = "\u00b0"; // Unicode for degree symbol + StaticJsonDocument<512> payload; + + // Construct the MQTT topic string for temperature + sprintf(m_topic, "homeassistant/sensor/%s_tilt_%s/temperature/config", config.mqttTopic, tilt_color); + + // Set up payload fields + strcat(unit, config.tempUnit); // Append temperature unit after degree symbol + payload["dev_cla"] = "temperature"; + payload["unit_of_meas"] = unit; + payload["ic"] = "mdi:thermometer"; + payload["stat_t"] = tilt_topic; + + // Construct sensor name + snprintf(tilt_sensor_name, sizeof(tilt_sensor_name), "Tilt Temperature - %s", tilt_color); + payload["name"] = tilt_sensor_name; + + // Value template + payload["val_tpl"] = "{{value_json.Temp}}"; + + // Unique ID + snprintf(uniq_id, sizeof(uniq_id), "tiltbridge_tilt%sT", tilt_color); + payload["uniq_id"] = uniq_id; + + // Serialize and publish + publish_to_mqtt(m_topic, payload, true); // Retain flag set to true +} + + +void dataSendHandler::prepare_gravity_payload(const char* tilt_color, const char* tilt_topic) { + //Home Assistant Config Topic for Sp Gravity + char m_topic[90]; + char tilt_sensor_name[35]; + char uniq_id[30]; + StaticJsonDocument<512> payload; + + // Construct the MQTT topic string for specific gravity + sprintf(m_topic, "homeassistant/sensor/%s_tilt_%sG/sp_gravity/config", config.mqttTopic, tilt_color); + + // Set up payload fields + payload["unit_of_meas"] = "SG"; + payload["stat_t"] = tilt_topic; + + // Construct sensor name + snprintf(tilt_sensor_name, sizeof(tilt_sensor_name), "Tilt Specific Gravity - %s", tilt_color); + payload["name"] = tilt_sensor_name; + + // Value template + payload["val_tpl"] = "{{value_json.SG}}"; + + // Unique ID + snprintf(uniq_id, sizeof(uniq_id), "tiltbridge_tilt%sG", tilt_color); + payload["uniq_id"] = uniq_id; + + // Serialize and publish + publish_to_mqtt(m_topic, payload, true); // Retain flag set to true +} + +void dataSendHandler::prepare_battery_payload(const char* tilt_color, const char* tilt_topic) { + //Home Assistant Config Topic for Weeks On Battery + char m_topic[90]; + char tilt_sensor_name[35]; + char uniq_id[30]; + StaticJsonDocument<512> payload; + + // Construct the MQTT topic string for weeks on battery + sprintf(m_topic, "homeassistant/sensor/%s_tilt_%sWoB/weeks_on_battery/config", config.mqttTopic, tilt_color); + + // Set up payload fields + payload["unit_of_meas"] = "weeks"; + payload["ic"] = "mdi:battery"; + payload["stat_t"] = tilt_topic; + + // Construct sensor name + snprintf(tilt_sensor_name, sizeof(tilt_sensor_name), "Tilt Weeks On Battery - %s", tilt_color); + payload["name"] = tilt_sensor_name; + + // Value template + payload["val_tpl"] = "{{value_json.WoB}}"; + + // Unique ID + snprintf(uniq_id, sizeof(uniq_id), "tiltbridge_tilt%sWoB", tilt_color); + payload["uniq_id"] = uniq_id; + + // Serialize and publish + publish_to_mqtt(m_topic, payload, true); // Retain flag set to true +} + +void dataSendHandler::prepare_general_payload(uint8_t tilt_index, const char* tilt_topic) { + //General payload with sensor data + char m_topic[90]; + StaticJsonDocument<512> payload; + tiltHydrometer* current_tilt = tilt_scanner.tilt(tilt_index); + + // Construct the MQTT topic string for general sensor data + strcpy(m_topic, tilt_topic); + + // Populate payload with sensor data + payload["Color"] = tilt_color_names[tilt_index]; + payload["timeStamp"] = (int)std::time(0); + payload["fermunits"] = "SG"; + payload["SG"] = current_tilt->converted_gravity(false).c_str(); + payload["Temp"] = current_tilt->converted_temp(false).c_str(); + payload["tempunits"] = config.tempUnit; + payload["WoB"] = current_tilt->get_weeks_battery().c_str(); + + // Serialize and publish + publish_to_mqtt(m_topic, payload, false); // Retain flag set to false for general data +} + + +bool dataSendHandler::publish_to_mqtt(const char* topic, StaticJsonDocument<512>& payload, bool retain) { + char payload_string[512]; + serializeJson(payload, payload_string); + + if (!mqttClient.connected()) { + Log.warning(F("MQTT disconnected. Attempting to reconnect to MQTT Broker\r\n")); + connect_mqtt(); } + bool result = mqttClient.publish(topic, payload_string, retain, 0); + Log.verbose(F("Published to MQTT\r\n")); + delay(10); return result; } + diff --git a/src/sendData.h b/src/sendData.h index 205a28e..5491ae2 100644 --- a/src/sendData.h +++ b/src/sendData.h @@ -3,6 +3,7 @@ #include #include +#include #define GSCRIPTS_DELAY (10 * 60) // 10 minute delay between pushes to Google Sheets directly #define BREWERS_FRIEND_DELAY (15 * 60) // 15 minute delay between pushes to Brewer's Friend @@ -36,7 +37,6 @@ class dataSendHandler void init(); void init_mqtt(); void process(); - bool mqtt_alreadyinit = false; bool send_to_google(); bool send_to_localTarget(); @@ -76,9 +76,20 @@ class dataSendHandler private: bool send_lock = false; - void connect_mqtt(); bool send_to_url(const char *url, const char *dataToSend, const char *contentType, bool checkBody = false, const char *bodyCheck = ""); + + // MQTT Stuff WiFiClient mqClient; + bool mqtt_alreadyinit = false; + + void connect_mqtt(); + bool publish_to_mqtt(const char* topic, StaticJsonDocument<512>& payload, bool retain); + void prepare_and_send_payloads(uint8_t tilt_index); + void prepare_temperature_payload(const char* tilt_color, const char* tilt_topic); + void prepare_gravity_payload(const char* tilt_color, const char* tilt_topic); + void prepare_battery_payload(const char* tilt_color, const char* tilt_topic); + void prepare_general_payload(uint8_t tilt_index, const char* tilt_topic); + }; From 788490629924cbb53cd19357b4d0deea49516569 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 18 Feb 2024 11:35:06 -0500 Subject: [PATCH 17/28] Update build.yml --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5d48fe5..6eb3e35 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,7 +4,7 @@ on: push: branches: - master - - new_sender + - devel # tags: # - "v*" # pull_request: @@ -83,4 +83,4 @@ jobs: LICENSE bin/*.bin env: - GITHUB_REPOSITORY: thorrak/tiltbridge \ No newline at end of file + GITHUB_REPOSITORY: thorrak/tiltbridge From 99c45628112b544da4cb45c10e725426d2b109f3 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 18 Feb 2024 12:11:59 -0500 Subject: [PATCH 18/28] Add additional information to the Home Assistant MQTT Auto Discovery messages --- src/sendData.cpp | 39 +++++++++++++++++++++++++++++++++++---- src/sendData.h | 1 + 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/sendData.cpp b/src/sendData.cpp index 5eab5ed..8c1c2cb 100644 --- a/src/sendData.cpp +++ b/src/sendData.cpp @@ -726,6 +726,36 @@ void dataSendHandler::prepare_and_send_payloads(uint8_t tilt_index) { prepare_general_payload(tilt_index, tilt_topic); } +void dataSendHandler::enrich_announcement(const char* topic, const char* tilt_color, StaticJsonDocument<512>& payload) { + payload["stat_t"] = topic; + + payload["dev"]["name"] = "Tilt Red"; + payload["dev"]["ids"] = tilt_color; + payload["dev"]["mdl"] = "Tilt Hydrometer"; + payload["dev"]["mf"] = "Baron Brew Equipment LLC"; + payload["dev"]["sw"] = version(); + payload["dev"]["sa"] = "Brewery"; // Suggested Area + + char ip_address_url[25] = "http://"; + { + char ip[16]; + sprintf(ip, "%d.%d.%d.%d", WiFi.localIP()[0], WiFi.localIP()[1], WiFi.localIP()[2], WiFi.localIP()[3]); + strncat(ip_address_url, ip, 16); + strcat(ip_address_url, "/"); + } + + + payload["dev"]["cu"] = ip_address_url; + // model and hw_version could be added, but it would require the Tilt object to determine Tilt vs. Tilt Pro + + + payload["json_attr_t"] = topic; + payload["json_attr_tpl"] = "{ \"Uptime\": \"{{ value_json.timeStamp }}\" }\n"; + + +} + + void dataSendHandler::prepare_temperature_payload(const char* tilt_color, const char* tilt_topic) { //Home Assistant Config Topic for Temperature char m_topic[90]; @@ -741,8 +771,7 @@ void dataSendHandler::prepare_temperature_payload(const char* tilt_color, const strcat(unit, config.tempUnit); // Append temperature unit after degree symbol payload["dev_cla"] = "temperature"; payload["unit_of_meas"] = unit; - payload["ic"] = "mdi:thermometer"; - payload["stat_t"] = tilt_topic; + payload["ic"] = "mdi:thermometer-water"; // Construct sensor name snprintf(tilt_sensor_name, sizeof(tilt_sensor_name), "Tilt Temperature - %s", tilt_color); @@ -755,6 +784,7 @@ void dataSendHandler::prepare_temperature_payload(const char* tilt_color, const snprintf(uniq_id, sizeof(uniq_id), "tiltbridge_tilt%sT", tilt_color); payload["uniq_id"] = uniq_id; + enrich_announcement(tilt_topic, tilt_color, payload); // Serialize and publish publish_to_mqtt(m_topic, payload, true); // Retain flag set to true } @@ -772,7 +802,7 @@ void dataSendHandler::prepare_gravity_payload(const char* tilt_color, const char // Set up payload fields payload["unit_of_meas"] = "SG"; - payload["stat_t"] = tilt_topic; + payload["ic"] = "mdi:slope-downhill"; // Construct sensor name snprintf(tilt_sensor_name, sizeof(tilt_sensor_name), "Tilt Specific Gravity - %s", tilt_color); @@ -785,6 +815,7 @@ void dataSendHandler::prepare_gravity_payload(const char* tilt_color, const char snprintf(uniq_id, sizeof(uniq_id), "tiltbridge_tilt%sG", tilt_color); payload["uniq_id"] = uniq_id; + enrich_announcement(tilt_topic, tilt_color, payload); // Serialize and publish publish_to_mqtt(m_topic, payload, true); // Retain flag set to true } @@ -802,7 +833,6 @@ void dataSendHandler::prepare_battery_payload(const char* tilt_color, const char // Set up payload fields payload["unit_of_meas"] = "weeks"; payload["ic"] = "mdi:battery"; - payload["stat_t"] = tilt_topic; // Construct sensor name snprintf(tilt_sensor_name, sizeof(tilt_sensor_name), "Tilt Weeks On Battery - %s", tilt_color); @@ -815,6 +845,7 @@ void dataSendHandler::prepare_battery_payload(const char* tilt_color, const char snprintf(uniq_id, sizeof(uniq_id), "tiltbridge_tilt%sWoB", tilt_color); payload["uniq_id"] = uniq_id; + enrich_announcement(tilt_topic, tilt_color, payload); // Serialize and publish publish_to_mqtt(m_topic, payload, true); // Retain flag set to true } diff --git a/src/sendData.h b/src/sendData.h index 5491ae2..34177db 100644 --- a/src/sendData.h +++ b/src/sendData.h @@ -89,6 +89,7 @@ class dataSendHandler void prepare_gravity_payload(const char* tilt_color, const char* tilt_topic); void prepare_battery_payload(const char* tilt_color, const char* tilt_topic); void prepare_general_payload(uint8_t tilt_index, const char* tilt_topic); + void enrich_announcement(const char* topic, const char* tilt_color, StaticJsonDocument<512>& payload); }; From bd74d56b3f6d115dfeb0d2822e9d5bb610f53691 Mon Sep 17 00:00:00 2001 From: John Date: Mon, 19 Feb 2024 09:50:39 -0500 Subject: [PATCH 19/28] Reorder data send handlers Moves MQTT earlier - see discussion in #247 --- src/sendData.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/sendData.cpp b/src/sendData.cpp index 8c1c2cb..fb2509d 100644 --- a/src/sendData.cpp +++ b/src/sendData.cpp @@ -32,19 +32,17 @@ void dataSendHandler::init() init_mqtt(); // Set up timers - // DEBUG: - cloudTargetTicker.once(10, [](){data_sender.send_cloudTarget = true;}); // Schedule first send to Cloud Target - localTargetTicker.once(20, [](){data_sender.send_localTarget = true;}); // Schedule first send to Local Target // localTargetTicker.once(5, [](){data_sender.send_localTarget = true;}); // Schedule first send to Local Target - // DEBUG^ + localTargetTicker.once(10, [](){data_sender.send_localTarget = true;}); // Schedule first send to Local Target + mqttTicker.once(20, [](){data_sender.send_mqtt = true;}); // Schedule first send to MQTT brewStatusTicker.once(30, [](){data_sender.send_brewStatus = true;}); // Schedule first send to Brew Status brewfatherTicker.once(40, [](){data_sender.send_brewfather = true;}); // Schedule first send to Brewfather brewersFriendTicker.once(50, [](){data_sender.send_brewersFriend = true;}); // Schedule first send to Brewer's Friend userTargetTicker.once(60, [](){data_sender.send_userTarget = true;}); // Schedule first send to User-defined JSON target - mqttTicker.once(65, [](){data_sender.send_mqtt = true;}); // Schedule first send to MQTT gSheetsTicker.once(70, [](){data_sender.send_gSheets = true;}); // Schedule first send to Google Sheets grainfatherTicker.once(80, [](){data_sender.send_grainfather = true;}); // Schedule first send to Grainfather taplistioTicker.once(90, [](){data_sender.send_taplistio = true;}); // Schedule first send to Taplist.io + cloudTargetTicker.once(100, [](){data_sender.send_cloudTarget = true;}); // Schedule first send to Cloud Target } void dataSendHandler::process() From c16151566499f96582c816dcdbd87f53e87f910a Mon Sep 17 00:00:00 2001 From: John Date: Mon, 19 Feb 2024 09:51:12 -0500 Subject: [PATCH 20/28] Change icons for HAST See discussion in #248 --- src/sendData.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sendData.cpp b/src/sendData.cpp index fb2509d..f117ceb 100644 --- a/src/sendData.cpp +++ b/src/sendData.cpp @@ -769,7 +769,7 @@ void dataSendHandler::prepare_temperature_payload(const char* tilt_color, const strcat(unit, config.tempUnit); // Append temperature unit after degree symbol payload["dev_cla"] = "temperature"; payload["unit_of_meas"] = unit; - payload["ic"] = "mdi:thermometer-water"; + payload["ic"] = "mdi:thermometer-lines"; // Construct sensor name snprintf(tilt_sensor_name, sizeof(tilt_sensor_name), "Tilt Temperature - %s", tilt_color); @@ -800,7 +800,7 @@ void dataSendHandler::prepare_gravity_payload(const char* tilt_color, const char // Set up payload fields payload["unit_of_meas"] = "SG"; - payload["ic"] = "mdi:slope-downhill"; + payload["ic"] = "mdi:trending-down"; // Construct sensor name snprintf(tilt_sensor_name, sizeof(tilt_sensor_name), "Tilt Specific Gravity - %s", tilt_color); From 0e05c6c8739279fcb88b1a02e8da753c4758ae0c Mon Sep 17 00:00:00 2001 From: John Date: Mon, 19 Feb 2024 16:01:52 -0500 Subject: [PATCH 21/28] Get rid of as many std::strings as possible Lower code side, less complexity, and hopefully better implementation overall --- .github/workflows/build.yml | 2 +- src/bridge_lcd.cpp | 7 +-- src/sendData.cpp | 63 ++++++++++++++++-------- src/tilt/tiltHydrometer.cpp | 96 +++++++++++++++++++------------------ src/tilt/tiltHydrometer.h | 8 ++-- src/tilt/tiltScanner.cpp | 4 +- 6 files changed, 102 insertions(+), 78 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6eb3e35..5bcac4f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,7 +4,7 @@ on: push: branches: - master - - devel + - no_std_strings # tags: # - "v*" # pull_request: diff --git a/src/bridge_lcd.cpp b/src/bridge_lcd.cpp index dbe9894..5a3d51d 100644 --- a/src/bridge_lcd.cpp +++ b/src/bridge_lcd.cpp @@ -499,9 +499,10 @@ void bridge_lcd::display_wifi_reconnect_failed() { } void bridge_lcd::print_tilt_to_line(tiltHydrometer *tilt, uint8_t line) { - char gravity[11], temp[8]; - sprintf(gravity, "%s", tilt->converted_gravity(false).c_str()); - sprintf(temp, "%s %s", tilt->converted_temp(false).c_str(), tilt->is_celsius() ? "C" : "F"); + char gravity[11], temp[9], temp_str[6]; + tilt->converted_gravity(gravity, 11, false); + tilt->converted_temp(temp_str, 6, false); + snprintf(temp, sizeof(temp), "%s %s", temp_str, tilt->is_celsius() ? "C" : "F"); #if defined(LCD_TFT_ESPI) tft->setTextColor(tilt_text_colors[tilt->m_color]); diff --git a/src/sendData.cpp b/src/sendData.cpp index f117ceb..746b86b 100644 --- a/src/sendData.cpp +++ b/src/sendData.cpp @@ -234,11 +234,16 @@ bool dataSendHandler::send_to_bf_and_bf(const uint8_t which_bf) { if (tilt_scanner.tilt(i)->is_loaded()) { + char gravity[10]; + char temp[6]; + Log.verbose(F("Tilt loaded with color name: %s\r\n"), tilt_color_names[i]); j["name"] = tilt_color_names[i]; - j["temp"] = tilt_scanner.tilt(i)->converted_temp(true); // Always in Fahrenheit + tilt_scanner.tilt(i)->converted_temp(temp, sizeof(temp), true); // Always in Fahrenheit + j["temp"] = temp; j["temp_unit"] = "F"; - j["gravity"] = tilt_scanner.tilt(i)->converted_gravity(false); + tilt_scanner.tilt(i)->converted_gravity(gravity, sizeof(gravity), false); + j["gravity"] = gravity; j["gravity_unit"] = "G"; j["device_source"] = "TiltBridge"; @@ -275,11 +280,15 @@ bool dataSendHandler::send_to_grainfather() if (tilt_scanner.tilt(i)->is_loaded()) { + char gravity[10]; + char temp[6]; StaticJsonDocument j; Log.verbose(F("Tilt loaded with color name: %s\r\n"), tilt_color_names[i]); - j["Temp"] = tilt_scanner.tilt(i)->converted_temp(true); // Always in Fahrenheit + tilt_scanner.tilt(i)->converted_temp(temp, sizeof(temp), true); // Always in Fahrenheit + j["Temp"] = temp; j["Unit"] = "F"; - j["SG"] = tilt_scanner.tilt(i)->converted_gravity(false); + tilt_scanner.tilt(i)->converted_gravity(gravity, sizeof(gravity), false); + j["SG"] = gravity; char payload_string[GF_SIZE]; serializeJson(j, payload_string); @@ -327,6 +336,8 @@ bool dataSendHandler::send_to_taplistio() for (uint8_t i = 0; i < TILT_COLORS; i++) { StaticJsonDocument<192> j; char payload_string[192]; + char gravity[10]; + char temp[6]; if (!tilt_scanner.tilt(i)->is_loaded()) { @@ -334,8 +345,10 @@ bool dataSendHandler::send_to_taplistio() } j["Color"] = tilt_color_names[i]; - j["Temp"] = tilt_scanner.tilt(i)->converted_temp(false); - j["SG"] = tilt_scanner.tilt(i)->converted_gravity(false); + tilt_scanner.tilt(i)->converted_temp(temp, sizeof(temp), false); // Always in Fahrenheit + j["Temp"] = temp; + tilt_scanner.tilt(i)->converted_gravity(gravity, sizeof(gravity), false); + j["SG"] = gravity; j["temperature_unit"] = "F"; j["gravity_unit"] = "G"; @@ -381,17 +394,16 @@ bool dataSendHandler::send_to_brewstatus() { if (tilt_scanner.tilt(i)->is_loaded()) { + char gravity[10]; + char temp[6]; + tilt_scanner.tilt(i)->converted_gravity(gravity, sizeof(gravity), false); + tilt_scanner.tilt(i)->converted_temp(temp, sizeof(temp), true); // Always in Fahrenheit since we don't send units snprintf(payload, payload_size, "SG=%s&Temp=%s&Color=%s&Timepoint=%.11f&Beer=Undefined&Comment=", - tilt_scanner.tilt(i)->converted_gravity(false).c_str(), - tilt_scanner.tilt(i)->converted_temp(true).c_str(), // Only sending Fahrenheit numbers since we don't send units - tilt_color_names[i], - ((double)std::time(0) + (config.TZoffset * 3600.0)) / 86400.0 + 25569.0); - if (send_to_url(config.brewstatusURL, payload, content_x_www_form_urlencoded)) - { + gravity, temp, tilt_color_names[i], ((double)std::time(0) + (config.TZoffset * 3600.0)) / 86400.0 + 25569.0); + + if (send_to_url(config.brewstatusURL, payload, content_x_www_form_urlencoded)) { Log.notice(F("Completed send to Brew Status.\r\n")); - } - else - { + } else { result = false; Log.verbose(F("Error sending to Brew Status.\r\n")); } @@ -435,12 +447,17 @@ bool dataSendHandler::send_to_google() if (tilt_scanner.tilt(i)->is_loaded()) { // Check if there is a google sheet name associated with the specific Tilt if (strlen(config.gsheets_config[i].name) > 0) { + char gravity[10]; + char temp[6]; + // If there's a sheet name saved, then we should send the data if (numSent == 0) Log.notice(F("Beginning GSheets check-in.\r\n")); payload["Beer"] = config.gsheets_config[i].name; - payload["Temp"] = tilt_scanner.tilt(i)->converted_temp(true); // Always send in Fahrenheit - payload["SG"] = tilt_scanner.tilt(i)->converted_gravity(false); + tilt_scanner.tilt(i)->converted_temp(temp, sizeof(temp), true); // Always in Fahrenheit + payload["Temp"] = temp; + tilt_scanner.tilt(i)->converted_gravity(gravity, sizeof(gravity), false); + payload["SG"] = gravity; payload["Color"] = tilt_color_names[i]; payload["Comment"] = ""; payload["Email"] = config.scriptsEmail; // The gmail email address associated with the script on google @@ -851,6 +868,9 @@ void dataSendHandler::prepare_battery_payload(const char* tilt_color, const char void dataSendHandler::prepare_general_payload(uint8_t tilt_index, const char* tilt_topic) { //General payload with sensor data char m_topic[90]; + char gravity[10]; + char temp[6]; + char battery_str[4]; // large enough for 0-255 and the null terminator StaticJsonDocument<512> payload; tiltHydrometer* current_tilt = tilt_scanner.tilt(tilt_index); @@ -861,10 +881,13 @@ void dataSendHandler::prepare_general_payload(uint8_t tilt_index, const char* ti payload["Color"] = tilt_color_names[tilt_index]; payload["timeStamp"] = (int)std::time(0); payload["fermunits"] = "SG"; - payload["SG"] = current_tilt->converted_gravity(false).c_str(); - payload["Temp"] = current_tilt->converted_temp(false).c_str(); + current_tilt->converted_gravity(gravity, 10, false); + payload["SG"] = gravity; + current_tilt->converted_temp(temp, 6, false); + payload["Temp"] = temp; payload["tempunits"] = config.tempUnit; - payload["WoB"] = current_tilt->get_weeks_battery().c_str(); + current_tilt->get_weeks_battery(battery_str, 4); + payload["WoB"] = battery_str; // Serialize and publish publish_to_mqtt(m_topic, payload, false); // Retain flag set to false for general data diff --git a/src/tilt/tiltHydrometer.cpp b/src/tilt/tiltHydrometer.cpp index 88dc879..d6ea67a 100644 --- a/src/tilt/tiltHydrometer.cpp +++ b/src/tilt/tiltHydrometer.cpp @@ -45,48 +45,35 @@ tiltHydrometer::tiltHydrometer(uint8_t color) } // tiltHydrometer -uint8_t tiltHydrometer::uuid_to_color_no(std::string uuid) +uint8_t tiltHydrometer::uuid_to_color_no(const char* uuid) { + if (uuid == nullptr) { + return TILT_NONE; + } - if (uuid == TILT_COLOR_RED_UUID) - { + if (strcmp(uuid, TILT_COLOR_RED_UUID) == 0) return TILT_COLOR_RED; - } - else if (uuid == TILT_COLOR_GREEN_UUID) - { + else if (strcmp(uuid, TILT_COLOR_GREEN_UUID) == 0) return TILT_COLOR_GREEN; - } - else if (uuid == TILT_COLOR_BLACK_UUID) - { + else if (strcmp(uuid, TILT_COLOR_BLACK_UUID) == 0) return TILT_COLOR_BLACK; - } - else if (uuid == TILT_COLOR_PURPLE_UUID) - { + else if (strcmp(uuid, TILT_COLOR_PURPLE_UUID) == 0) return TILT_COLOR_PURPLE; - } - else if (uuid == TILT_COLOR_ORANGE_UUID) - { + else if (strcmp(uuid, TILT_COLOR_ORANGE_UUID) == 0) return TILT_COLOR_ORANGE; - } - else if (uuid == TILT_COLOR_BLUE_UUID) - { + else if (strcmp(uuid, TILT_COLOR_BLUE_UUID) == 0) return TILT_COLOR_BLUE; - } - else if (uuid == TILT_COLOR_YELLOW_UUID) - { + else if (strcmp(uuid, TILT_COLOR_YELLOW_UUID) == 0) return TILT_COLOR_YELLOW; - } - else if (uuid == TILT_COLOR_PINK_UUID) - { + else if (strcmp(uuid, TILT_COLOR_PINK_UUID) == 0) return TILT_COLOR_PINK; - } else - { return TILT_NONE; - } + } + bool tiltHydrometer::set_values(uint16_t i_temp, uint16_t i_grav, uint8_t i_tx_pwr, int8_t current_rssi) { double d_temp; @@ -203,27 +190,33 @@ bool tiltHydrometer::set_values(uint16_t i_temp, uint16_t i_grav, uint8_t i_tx_p return true; } -std::string tiltHydrometer::converted_gravity(bool use_raw_gravity) +void tiltHydrometer::converted_gravity(char* output, size_t output_size, bool use_raw_gravity) { - char rnd_gravity[7]; + if (output == nullptr || output_size < 7) { + // Handle error: output is null or not large enough + return; + } + const uint16_t grav_scalar = (tilt_pro) ? 10000 : 1000; + float gravity_value = use_raw_gravity ? gravity : gravity_smoothed; + float converted_value = static_cast(gravity_value) / grav_scalar; - if (use_raw_gravity) - snprintf(rnd_gravity, 7, "%.4f", (float)gravity / grav_scalar); - else - snprintf(rnd_gravity, 7, "%.4f", (float)gravity_smoothed / grav_scalar); - std::string output = rnd_gravity; - return output; + // Using snprintf to format the string and handle buffer overflow + snprintf(output, output_size, "%.4f", converted_value); } void tiltHydrometer::to_json_string(char *json_string, bool use_raw_gravity) { StaticJsonDocument j; + char gravity_str[10]; + char temp_str[6]; j["color"] = tilt_color_names[m_color]; - j["temp"] = converted_temp(false); + converted_temp(temp_str, sizeof(temp_str), false); + j["temp"] = temp_str; j["tempUnit"] = is_celsius() ? "C" : "F"; - j["gravity"] = converted_gravity(use_raw_gravity); + converted_gravity(gravity_str, sizeof(gravity_str), use_raw_gravity); + j["gravity"] = gravity_str; j["weeks_on_battery"] = weeks_since_last_battery_change; j["sends_battery"] = receives_battery; j["high_resolution"] = tilt_pro; @@ -239,26 +232,35 @@ void tiltHydrometer::to_json_string(char *json_string, bool use_raw_gravity) serializeJson(j, json_string, TILT_DATA_SIZE); } -std::string tiltHydrometer::converted_temp(bool fahrenheit_only) +void tiltHydrometer::converted_temp(char* output, size_t output_size, bool fahrenheit_only) { - char rnd_temp[5]; + if (output == nullptr || output_size < 6) { // 6 to accommodate '-0.0\0' or similar + // Handle error: output is null or not large enough + return; + } + const float temp_scalar = (tilt_pro) ? 10.0f : 1.0f; - double d_temp = (double)temp / temp_scalar; + double d_temp = static_cast(temp) / temp_scalar; - if (is_celsius() && !fahrenheit_only) + if (is_celsius() && !fahrenheit_only) { d_temp = (d_temp - 32) * 5 / 9; + } - snprintf(rnd_temp, 5, "%.1f", d_temp); - std::string output = rnd_temp; - return output; + snprintf(output, output_size, "%.1f", d_temp); } -std::string tiltHydrometer::get_weeks_battery() +void tiltHydrometer::get_weeks_battery(char* output, size_t output_size) { - std::string stdString = std::to_string(weeks_since_last_battery_change); - return stdString; + if (output == nullptr || output_size == 0) { + // Handle error: output is null or size is zero + return; + } + + // Using snprintf to safely convert weeks_since_last_battery_change to a string + snprintf(output, output_size, "%u", static_cast(weeks_since_last_battery_change)); } + bool tiltHydrometer::is_celsius() const { return strcmp(config.tempUnit, "C") == 0; diff --git a/src/tilt/tiltHydrometer.h b/src/tilt/tiltHydrometer.h index 148cf46..fc8bf83 100644 --- a/src/tilt/tiltHydrometer.h +++ b/src/tilt/tiltHydrometer.h @@ -40,14 +40,14 @@ class tiltHydrometer explicit tiltHydrometer(uint8_t color); bool set_values(uint16_t i_temp, uint16_t i_grav, uint8_t i_tx_pwr, int8_t current_rssi); - std::string converted_gravity(bool use_raw_gravity); + void converted_gravity(char* output, size_t output_size, bool use_raw_gravity); void to_json_string(char *json_string, bool use_raw_gravity); - std::string converted_temp(bool fahrenheit_only); - std::string get_weeks_battery(); + void converted_temp(char* output, size_t output_size, bool fahrenheit_only); + void get_weeks_battery(char* output, size_t output_size); bool is_celsius() const; bool is_loaded(); - static uint8_t uuid_to_color_no(std::string data); + static uint8_t uuid_to_color_no(const char* uuid); uint16_t temp; uint16_t gravity; diff --git a/src/tilt/tiltScanner.cpp b/src/tilt/tiltScanner.cpp index d693803..4669674 100644 --- a/src/tilt/tiltScanner.cpp +++ b/src/tilt/tiltScanner.cpp @@ -140,10 +140,8 @@ uint8_t tiltScanner::load_tilt_from_advert_hex(const std::string &advert_string_ } m_color = tiltHydrometer::uuid_to_color_no(m_color_arr); - if (m_color == TILT_NONE) - { // We didn't match the uuid to a color (should only happen if new colors are released) + if (m_color == TILT_NONE) // We didn't match the uuid to a color (should only happen if new colors are released) return TILT_NONE; - } uint16_t temp = std::strtoul(temp_arr, nullptr, 16); uint16_t gravity = std::strtoul(grav_arr, nullptr, 16); From a823477c7c27312a42bf8c41cf4dda47fcfff8b4 Mon Sep 17 00:00:00 2001 From: John Date: Mon, 19 Feb 2024 16:02:34 -0500 Subject: [PATCH 22/28] Actually always send taplistio in F --- src/sendData.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sendData.cpp b/src/sendData.cpp index 746b86b..fa71fd6 100644 --- a/src/sendData.cpp +++ b/src/sendData.cpp @@ -345,7 +345,7 @@ bool dataSendHandler::send_to_taplistio() } j["Color"] = tilt_color_names[i]; - tilt_scanner.tilt(i)->converted_temp(temp, sizeof(temp), false); // Always in Fahrenheit + tilt_scanner.tilt(i)->converted_temp(temp, sizeof(temp), true); // Always in Fahrenheit j["Temp"] = temp; tilt_scanner.tilt(i)->converted_gravity(gravity, sizeof(gravity), false); j["SG"] = gravity; From c44f049fdacf7bc1b10e21546385255455ee5586 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 20 Feb 2024 08:03:56 -0500 Subject: [PATCH 23/28] Use tilt color properly in name --- src/sendData.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sendData.cpp b/src/sendData.cpp index fa71fd6..d59842f 100644 --- a/src/sendData.cpp +++ b/src/sendData.cpp @@ -743,8 +743,9 @@ void dataSendHandler::prepare_and_send_payloads(uint8_t tilt_index) { void dataSendHandler::enrich_announcement(const char* topic, const char* tilt_color, StaticJsonDocument<512>& payload) { payload["stat_t"] = topic; - - payload["dev"]["name"] = "Tilt Red"; + char deviceName[20]; + snprintf(deviceName, sizeof(deviceName), "Tilt %s", tilt_color); + payload["dev"]["name"] = deviceName; payload["dev"]["ids"] = tilt_color; payload["dev"]["mdl"] = "Tilt Hydrometer"; payload["dev"]["mf"] = "Baron Brew Equipment LLC"; From 3fd669731a5f8e3f3cb89952d2e124f65ffaf918 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 25 Feb 2024 11:05:27 -0500 Subject: [PATCH 24/28] Don't attempt send to unconfigured taplist.io --- src/sendData.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sendData.cpp b/src/sendData.cpp index d59842f..b4ac568 100644 --- a/src/sendData.cpp +++ b/src/sendData.cpp @@ -310,6 +310,11 @@ bool dataSendHandler::send_to_taplistio() { bool result = true; + // Check if config.taplistioURL is set, and return if it's not + if (strlen(config.taplistioURL) <= 10) { + return false; + } + // See if it's our time to send. if (!send_taplistio) { return false; From 4944d10d5afbe24a4fd5ae6c1709e5bacf25cb4b Mon Sep 17 00:00:00 2001 From: John Date: Sun, 25 Feb 2024 11:05:55 -0500 Subject: [PATCH 25/28] Reconnect to MQTT on loop --- src/sendData.cpp | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/src/sendData.cpp b/src/sendData.cpp index b4ac568..8018c36 100644 --- a/src/sendData.cpp +++ b/src/sendData.cpp @@ -574,6 +574,10 @@ void dataSendHandler::init_mqtt() void dataSendHandler::connect_mqtt() { + if(!mqtt_alreadyinit) { + Log.error("Call to connect_mqtt without init_mqtt being called first. This is a bug.\r\n"); + return; + } if (strlen(config.mqttUsername) > 1) { mqttClient.connect(config.mdnsID, config.mqttUsername, config.mqttPassword); @@ -712,24 +716,33 @@ bool dataSendHandler::send_to_url(const char *url, const char *dataToSend, const bool dataSendHandler::send_to_mqtt() { bool result = false; - mqttClient.loop(); + + if (strcmp(config.mqttBrokerHost, "") == 0 || strlen(config.mqttBrokerHost) == 0) { + // No MQTT broker configured + return false; + } + + if (!mqttClient.connected()) { + Log.warning(F("MQTT disconnected. Attempting to reconnect to MQTT Broker in loop\r\n")); + connect_mqtt(); + } else { + mqttClient.loop(); + } if (send_mqtt && !send_lock) { send_mqtt = false; send_lock = true; - if (strcmp(config.mqttBrokerHost, "") != 0 || strlen(config.mqttBrokerHost) != 0) { - Log.verbose(F("Publishing available results to MQTT Broker.\r\n")); + Log.verbose(F("Publishing available results to MQTT Broker.\r\n")); - for (uint8_t i = 0; i < TILT_COLORS; i++) { - if (tilt_scanner.tilt(i)->is_loaded()) { - prepare_and_send_payloads(i); - } + for (uint8_t i = 0; i < TILT_COLORS; i++) { + if (tilt_scanner.tilt(i)->is_loaded()) { + prepare_and_send_payloads(i); } - - mqttTicker.once(config.mqttPushEvery, [](){ data_sender.send_mqtt = true; }); - send_lock = false; } + + mqttTicker.once(config.mqttPushEvery, [](){ data_sender.send_mqtt = true; }); + send_lock = false; } return result; @@ -910,7 +923,11 @@ bool dataSendHandler::publish_to_mqtt(const char* topic, StaticJsonDocument<512> } bool result = mqttClient.publish(topic, payload_string, retain, 0); - Log.verbose(F("Published to MQTT\r\n")); + if(result) { + Log.verbose(F("Published to MQTT\r\n")); + } else { + Log.error(F("Failed to publish to MQTT\r\n")); + } delay(10); return result; } From 2050220f56728d215705c42be52977247ff4d0e5 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 25 Feb 2024 11:40:53 -0500 Subject: [PATCH 26/28] Clean up MQTT (re)initialization --- src/sendData.cpp | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/sendData.cpp b/src/sendData.cpp index 8018c36..1ac4589 100644 --- a/src/sendData.cpp +++ b/src/sendData.cpp @@ -539,35 +539,37 @@ void dataSendHandler::init_mqtt() { LCBUrl url; - if (strcmp(config.mqttBrokerHost, "") != 0 || strlen(config.mqttBrokerHost) != 0) - { + if(mqtt_alreadyinit) { + Log.verbose(F("MQTT already initialized. Disconnecting.\r\n")); + mqttClient.disconnect(); + delay(250); + } + + if (strcmp(config.mqttBrokerHost, "") != 0 || strlen(config.mqttBrokerHost) != 0) { if (url.isMDNS(config.mqttBrokerHost)) { Log.verbose(F("Initializing connection to MQTTBroker: %s (%s) on port: %d\r\n"), - config.mqttBrokerHost, - url.getIP(config.mqttBrokerHost).toString().c_str(), - config.mqttBrokerPort); + config.mqttBrokerHost, url.getIP(config.mqttBrokerHost).toString().c_str(), config.mqttBrokerPort); } else { Log.verbose(F("Initializing connection to MQTTBroker: %s on port: %d\r\n"), - config.mqttBrokerHost, - config.mqttBrokerPort); + config.mqttBrokerHost, config.mqttBrokerPort); } if (mqtt_alreadyinit) { - mqttClient.disconnect(); - delay(250); + // If we've already initialized, just reset the host/port & reconnect if (url.isMDNS(config.mqttBrokerHost)) { mqttClient.setHost(url.getIP(config.mqttBrokerHost), config.mqttBrokerPort); } else { mqttClient.setHost(config.mqttBrokerHost, config.mqttBrokerPort); } + mqttClient.connect(config.mdnsID); } else { if (url.isMDNS(config.mqttBrokerHost)) { mqttClient.begin(url.getIP(config.mqttBrokerHost), config.mqttBrokerPort, mqClient); } else { mqttClient.begin(config.mqttBrokerHost, config.mqttBrokerPort, mqClient); } + mqtt_alreadyinit = true; } - mqtt_alreadyinit = true; mqttClient.setKeepAlive(config.mqttPushEvery); } } @@ -575,7 +577,8 @@ void dataSendHandler::init_mqtt() void dataSendHandler::connect_mqtt() { if(!mqtt_alreadyinit) { - Log.error("Call to connect_mqtt without init_mqtt being called first. This is a bug.\r\n"); + // Since init is not called synchronously with the settings update when the user sets the MQTT broker, we need to + // wait until the MQTT client is initialized if it hasn't been done already. return; } if (strlen(config.mqttUsername) > 1) From 61c6ee63e520b6ece74eb682421b77bfb7c1f605 Mon Sep 17 00:00:00 2001 From: John Date: Thu, 29 Feb 2024 08:35:37 -0500 Subject: [PATCH 27/28] Check for WiFi status in data send loop --- src/sendData.cpp | 170 +++++++++++++++++++++++------------------------ 1 file changed, 85 insertions(+), 85 deletions(-) diff --git a/src/sendData.cpp b/src/sendData.cpp index 1ac4589..471c9cc 100644 --- a/src/sendData.cpp +++ b/src/sendData.cpp @@ -47,14 +47,16 @@ void dataSendHandler::init() void dataSendHandler::process() { - send_to_cloud(); - send_to_localTarget(); - send_to_bf_and_bf(); - send_to_grainfather(); - send_to_brewstatus(); - send_to_taplistio(); - send_to_google(); - send_to_mqtt(); + if (WiFiClass::status() == WL_CONNECTED) { + send_to_cloud(); + send_to_localTarget(); + send_to_bf_and_bf(); + send_to_grainfather(); + send_to_brewstatus(); + send_to_taplistio(); + send_to_google(); + send_to_mqtt(); + } } bool dataSendHandler::send_to_localTarget() @@ -68,8 +70,7 @@ bool dataSendHandler::send_to_localTarget() send_lock = true; // tilt_scanner.deinit(); - if (WiFiClass::status() == WL_CONNECTED && strlen(config.localTargetURL) >= LOCALTARGET_MIN_URL_LENGTH) - { + if (strlen(config.localTargetURL) >= LOCALTARGET_MIN_URL_LENGTH) { Log.verbose(F("Calling send to Local Target.\r\n")); DynamicJsonDocument doc(TILT_ALL_DATA_SIZE + 128); char tilt_data[TILT_ALL_DATA_SIZE + 128]; @@ -106,8 +107,7 @@ bool dataSendHandler::send_to_bf_and_bf() send_lock = true; // Brewer's Friend data_sender.send_brewersFriend = false; - if (WiFiClass::status() == WL_CONNECTED && strlen(config.brewersFriendKey) > BREWERS_FRIEND_MIN_KEY_LENGTH) - { + if (strlen(config.brewersFriendKey) > BREWERS_FRIEND_MIN_KEY_LENGTH) { Log.verbose(F("Calling send to Brewer's Friend.\r\n")); retval = data_sender.send_to_bf_and_bf(BF_MEANS_BREWERS_FRIEND); if (retval) @@ -128,8 +128,7 @@ bool dataSendHandler::send_to_bf_and_bf() send_lock = true; // Brewfather data_sender.send_brewfather = false; - if (WiFiClass::status() == WL_CONNECTED && strlen(config.brewfatherKey) > BREWFATHER_MIN_KEY_LENGTH) - { + if (strlen(config.brewfatherKey) > BREWFATHER_MIN_KEY_LENGTH) { Log.verbose(F("Calling send to Brewfather.\r\n")); retval = data_sender.send_to_bf_and_bf(BF_MEANS_BREWFATHER); if (retval) @@ -151,7 +150,7 @@ bool dataSendHandler::send_to_bf_and_bf() send_lock = true; // User Target data_sender.send_userTarget = false; - if (WiFiClass::status() == WL_CONNECTED && strlen(config.userTargetURL) > USER_TARGET_MIN_URL_LENGTH) + if (strlen(config.userTargetURL) > USER_TARGET_MIN_URL_LENGTH) { Log.verbose(F("Calling send to User Target.\r\n")); retval = data_sender.send_to_bf_and_bf(BF_MEANS_USER_TARGET); @@ -266,37 +265,35 @@ bool dataSendHandler::send_to_grainfather() // Brew Status send_grainfather = false; send_lock = true; - if (WiFiClass::status() == WL_CONNECTED) + + Log.verbose(F("Calling send to Grainfather.\r\n")); + + // Loop through each of the tilt colors cached by tilt_scanner, sending + // data for each of the active tilts + for (uint8_t i = 0; i < TILT_COLORS; i++) { - Log.verbose(F("Calling send to Grainfather.\r\n")); + if (strlen(config.grainfatherURL[i].link) == 0) { + continue; + } - // Loop through each of the tilt colors cached by tilt_scanner, sending - // data for each of the active tilts - for (uint8_t i = 0; i < TILT_COLORS; i++) + if (tilt_scanner.tilt(i)->is_loaded()) { - if (strlen(config.grainfatherURL[i].link) == 0) { - continue; - } - - if (tilt_scanner.tilt(i)->is_loaded()) + char gravity[10]; + char temp[6]; + StaticJsonDocument j; + Log.verbose(F("Tilt loaded with color name: %s\r\n"), tilt_color_names[i]); + tilt_scanner.tilt(i)->converted_temp(temp, sizeof(temp), true); // Always in Fahrenheit + j["Temp"] = temp; + j["Unit"] = "F"; + tilt_scanner.tilt(i)->converted_gravity(gravity, sizeof(gravity), false); + j["SG"] = gravity; + + char payload_string[GF_SIZE]; + serializeJson(j, payload_string); + + if (!send_to_url(config.grainfatherURL[i].link, payload_string, content_json)) { - char gravity[10]; - char temp[6]; - StaticJsonDocument j; - Log.verbose(F("Tilt loaded with color name: %s\r\n"), tilt_color_names[i]); - tilt_scanner.tilt(i)->converted_temp(temp, sizeof(temp), true); // Always in Fahrenheit - j["Temp"] = temp; - j["Unit"] = "F"; - tilt_scanner.tilt(i)->converted_gravity(gravity, sizeof(gravity), false); - j["SG"] = gravity; - - char payload_string[GF_SIZE]; - serializeJson(j, payload_string); - - if (!send_to_url(config.grainfatherURL[i].link, payload_string, content_json)) - { - result = false; // There was an error with the previous send - } + result = false; // There was an error with the previous send } } } @@ -331,12 +328,13 @@ bool dataSendHandler::send_to_taplistio() send_taplistio = false; send_lock = true; - if (WiFiClass::status() != WL_CONNECTED) { - Log.verbose(F("taplist.io: Wifi not connected, skipping send.\r\n")); - taplistioTicker.once(config.taplistioPushEvery, [](){data_sender.send_taplistio = true;}); - send_lock = false; - return false; - } + // This is now checked in the data sending loop + // if (WiFiClass::status() != WL_CONNECTED) { + // Log.verbose(F("taplist.io: Wifi not connected, skipping send.\r\n")); + // taplistioTicker.once(config.taplistioPushEvery, [](){data_sender.send_taplistio = true;}); + // send_lock = false; + // return false; + // } for (uint8_t i = 0; i < TILT_COLORS; i++) { StaticJsonDocument<192> j; @@ -381,8 +379,7 @@ bool dataSendHandler::send_to_brewstatus() // Brew Status send_brewStatus = false; send_lock = true; - if (WiFiClass::status() == WL_CONNECTED && strlen(config.brewstatusURL) > BREWSTATUS_MIN_URL_LENGTH) - { + if (strlen(config.brewstatusURL) > BREWSTATUS_MIN_URL_LENGTH) { Log.verbose(F("Calling send to Brew Status.\r\n")); // The payload should look like this when sent to Brewstatus: @@ -539,55 +536,58 @@ void dataSendHandler::init_mqtt() { LCBUrl url; - if(mqtt_alreadyinit) { - Log.verbose(F("MQTT already initialized. Disconnecting.\r\n")); - mqttClient.disconnect(); - delay(250); - } - - if (strcmp(config.mqttBrokerHost, "") != 0 || strlen(config.mqttBrokerHost) != 0) { - if (url.isMDNS(config.mqttBrokerHost)) { - Log.verbose(F("Initializing connection to MQTTBroker: %s (%s) on port: %d\r\n"), - config.mqttBrokerHost, url.getIP(config.mqttBrokerHost).toString().c_str(), config.mqttBrokerPort); - } else { - Log.verbose(F("Initializing connection to MQTTBroker: %s on port: %d\r\n"), - config.mqttBrokerHost, config.mqttBrokerPort); + // Checking for the WiFi Status is done in the data sending loop, but we also need to be sure we are connected to WiFi when we initialize the MQTT client + if (WiFiClass::status() == WL_CONNECTED) { + if(mqtt_alreadyinit) { + Log.verbose(F("MQTT already initialized. Disconnecting.\r\n")); + mqttClient.disconnect(); + delay(250); } - if (mqtt_alreadyinit) { - // If we've already initialized, just reset the host/port & reconnect + if (strcmp(config.mqttBrokerHost, "") != 0 || strlen(config.mqttBrokerHost) != 0) { if (url.isMDNS(config.mqttBrokerHost)) { - mqttClient.setHost(url.getIP(config.mqttBrokerHost), config.mqttBrokerPort); + Log.verbose(F("Initializing connection to MQTTBroker: %s (%s) on port: %d\r\n"), + config.mqttBrokerHost, url.getIP(config.mqttBrokerHost).toString().c_str(), config.mqttBrokerPort); } else { - mqttClient.setHost(config.mqttBrokerHost, config.mqttBrokerPort); + Log.verbose(F("Initializing connection to MQTTBroker: %s on port: %d\r\n"), + config.mqttBrokerHost, config.mqttBrokerPort); } - mqttClient.connect(config.mdnsID); - } else { - if (url.isMDNS(config.mqttBrokerHost)) { - mqttClient.begin(url.getIP(config.mqttBrokerHost), config.mqttBrokerPort, mqClient); + + if (mqtt_alreadyinit) { + mqttClient.disconnect(); + delay(250); + if (url.isMDNS(config.mqttBrokerHost)) { + mqttClient.setHost(url.getIP(config.mqttBrokerHost), config.mqttBrokerPort); + } else { + mqttClient.setHost(config.mqttBrokerHost, config.mqttBrokerPort); + } } else { - mqttClient.begin(config.mqttBrokerHost, config.mqttBrokerPort, mqClient); + if (url.isMDNS(config.mqttBrokerHost)) { + mqttClient.begin(url.getIP(config.mqttBrokerHost), config.mqttBrokerPort, mqClient); + } else { + mqttClient.begin(config.mqttBrokerHost, config.mqttBrokerPort, mqClient); + } } mqtt_alreadyinit = true; + mqttClient.setKeepAlive(config.mqttPushEvery); } - mqttClient.setKeepAlive(config.mqttPushEvery); } } void dataSendHandler::connect_mqtt() { - if(!mqtt_alreadyinit) { - // Since init is not called synchronously with the settings update when the user sets the MQTT broker, we need to - // wait until the MQTT client is initialized if it hasn't been done already. - return; - } - if (strlen(config.mqttUsername) > 1) - { - mqttClient.connect(config.mdnsID, config.mqttUsername, config.mqttPassword); - } - else - { - mqttClient.connect(config.mdnsID); + // Checking for the WiFi Status is done in the data sending loop, but we also need to be sure we are connected to WiFi when we connect to the MQTT broker + if (WiFiClass::status() == WL_CONNECTED) { + if(!mqtt_alreadyinit) { + // Since init is not called synchronously with the settings update when the user sets the MQTT broker, we need to + // wait until the MQTT client is initialized if it hasn't been done already. + return; + } + if (strlen(config.mqttUsername) > 1) { + mqttClient.connect(config.mdnsID, config.mqttUsername, config.mqttPassword); + } else { + mqttClient.connect(config.mdnsID); + } } } From 85421879fa469a82db7b7c44731016b4e2184c01 Mon Sep 17 00:00:00 2001 From: John Date: Fri, 1 Mar 2024 20:31:32 -0500 Subject: [PATCH 28/28] Add additional case design (Closes #257) --- docs/source/hardware.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/hardware.rst b/docs/source/hardware.rst index 354dc06..b586a89 100644 --- a/docs/source/hardware.rst +++ b/docs/source/hardware.rst @@ -82,6 +82,7 @@ OLED Cases - `TiltBridge Heltec/TTGO ESP32 OLED Enclosure by Thorrak `_ - `Generic "OLED" Enclosure by Thorrak `_ - `HiLetGo Wifi 32 Tiltbridge Case by calandryll `_ +- `Ideaspark OLED 0.96" ESP32 case `_